Remove unused argument to vlib_feature_next
[vpp.git] / src / vnet / bonding / node.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #define _GNU_SOURCE
19 #include <stdint.h>
20 #include <vnet/llc/llc.h>
21 #include <vnet/snap/snap.h>
22 #include <vnet/bonding/node.h>
23
24 bond_main_t bond_main;
25
26 #define foreach_bond_input_error \
27   _(NONE, "no error")            \
28   _(IF_DOWN, "interface down")   \
29   _(PASS_THRU, "pass through (CDP, LLDP, slow protocols)")
30
31 typedef enum
32 {
33 #define _(f,s) BOND_INPUT_ERROR_##f,
34   foreach_bond_input_error
35 #undef _
36     BOND_INPUT_N_ERROR,
37 } bond_input_error_t;
38
39 #ifndef CLIB_MARCH_VARIANT
40 static char *bond_input_error_strings[] = {
41 #define _(n,s) s,
42   foreach_bond_input_error
43 #undef _
44 };
45
46 static u8 *
47 format_bond_input_trace (u8 * s, va_list * args)
48 {
49   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
50   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
51   bond_packet_trace_t *t = va_arg (*args, bond_packet_trace_t *);
52
53   s = format (s, "src %U, dst %U, %U -> %U",
54               format_ethernet_address, t->ethernet.src_address,
55               format_ethernet_address, t->ethernet.dst_address,
56               format_vnet_sw_if_index_name, vnet_get_main (),
57               t->sw_if_index,
58               format_vnet_sw_if_index_name, vnet_get_main (),
59               t->bond_sw_if_index);
60
61   return s;
62 }
63 #endif
64
65
66 typedef enum
67 {
68   BOND_INPUT_NEXT_DROP,
69   BOND_INPUT_N_NEXT,
70 } bond_output_next_t;
71
72 static_always_inline u8
73 packet_is_cdp (ethernet_header_t * eth)
74 {
75   llc_header_t *llc;
76   snap_header_t *snap;
77
78   llc = (llc_header_t *) (eth + 1);
79   snap = (snap_header_t *) (llc + 1);
80
81   return ((eth->type == htons (ETHERNET_TYPE_CDP)) ||
82           ((llc->src_sap == 0xAA) && (llc->control == 0x03) &&
83            (snap->protocol == htons (0x2000)) &&
84            (snap->oui[0] == 0) && (snap->oui[1] == 0) &&
85            (snap->oui[2] == 0x0C)));
86 }
87
88 static inline u32
89 bond_sw_if_idx_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node,
90                         vlib_buffer_t * b, u32 bond_sw_if_index)
91 {
92   u16 *ethertype_p, ethertype;
93   ethernet_vlan_header_t *vlan;
94   ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b);
95
96   ethertype = clib_mem_unaligned (&eth->type, u16);
97   if (!ethernet_frame_is_tagged (ntohs (ethertype)))
98     {
99       // Let some layer2 packets pass through.
100       if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
101                         && !packet_is_cdp (eth)
102                         && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
103         {
104           /* Change the physical interface to bond interface */
105           vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
106           return 1;
107         }
108     }
109   else
110     {
111       vlan = (void *) (eth + 1);
112       ethertype_p = &vlan->type;
113       ethertype = clib_mem_unaligned (ethertype_p, u16);
114       if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
115         {
116           vlan++;
117           ethertype_p = &vlan->type;
118         }
119       ethertype = clib_mem_unaligned (ethertype_p, u16);
120       if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
121                         && (ethertype != htons (ETHERNET_TYPE_CDP))
122                         && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
123         {
124           /* Change the physical interface to bond interface */
125           vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
126           return 1;
127         }
128     }
129
130   vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
131   return 0;
132 }
133
134 static inline void
135 bond_update_next (vlib_main_t * vm, vlib_node_runtime_t * node,
136                   u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
137                   u32 packet_count,
138                   u32 * bond_sw_if_index, vlib_buffer_t * b,
139                   u32 * next_index, vlib_error_t * error)
140 {
141   u16 thread_index = vm->thread_index;
142   slave_if_t *sif;
143   bond_if_t *bif;
144
145   if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
146     return;
147
148   if (packet_count)
149     vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
150                                    VNET_INTERFACE_COUNTER_RX, thread_index,
151                                    *last_slave_sw_if_index, packet_count);
152
153   *last_slave_sw_if_index = slave_sw_if_index;
154   *next_index = BOND_INPUT_NEXT_DROP;
155
156   sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
157   ASSERT (sif);
158
159   bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
160
161   ASSERT (bif);
162   ASSERT (vec_len (bif->slaves));
163
164   if (PREDICT_TRUE (bif->admin_up == 0))
165     {
166       *bond_sw_if_index = slave_sw_if_index;
167       *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
168     }
169
170   *bond_sw_if_index = bif->sw_if_index;
171   *error = 0;
172   vnet_feature_next (next_index, b);
173 }
174
175 VLIB_NODE_FN (bond_input_node) (vlib_main_t * vm,
176                                 vlib_node_runtime_t * node,
177                                 vlib_frame_t * frame)
178 {
179   u16 thread_index = vm->thread_index;
180   u32 *from, n_left;
181   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
182   u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
183   u16 nexts[VLIB_FRAME_SIZE], *next;
184   u32 last_slave_sw_if_index = ~0;
185   u32 bond_sw_if_index = 0;
186   vlib_error_t error = 0;
187   u32 next_index = 0;
188   u32 cnt = 0;
189
190   /* Vector of buffer / pkt indices we're supposed to process */
191   from = vlib_frame_vector_args (frame);
192
193   /* Number of buffers / pkts */
194   n_left = frame->n_vectors;
195
196   vlib_get_buffers (vm, from, bufs, n_left);
197
198   b = bufs;
199   next = nexts;
200   sw_if_index = sw_if_indices;
201
202   while (n_left >= 4)
203     {
204       u32 x = 0;
205       /* Prefetch next iteration */
206       if (PREDICT_TRUE (n_left >= 16))
207         {
208           CLIB_PREFETCH (vlib_buffer_get_current (b[8]),
209                          CLIB_CACHE_LINE_BYTES, LOAD);
210           CLIB_PREFETCH (vlib_buffer_get_current (b[9]),
211                          CLIB_CACHE_LINE_BYTES, LOAD);
212           CLIB_PREFETCH (vlib_buffer_get_current (b[10]),
213                          CLIB_CACHE_LINE_BYTES, LOAD);
214           CLIB_PREFETCH (vlib_buffer_get_current (b[11]),
215                          CLIB_CACHE_LINE_BYTES, LOAD);
216
217           vlib_prefetch_buffer_header (b[12], LOAD);
218           vlib_prefetch_buffer_header (b[13], LOAD);
219           vlib_prefetch_buffer_header (b[14], LOAD);
220           vlib_prefetch_buffer_header (b[15], LOAD);
221         }
222
223       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
224       sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
225       sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
226       sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
227
228       x |= sw_if_index[0] ^ last_slave_sw_if_index;
229       x |= sw_if_index[1] ^ last_slave_sw_if_index;
230       x |= sw_if_index[2] ^ last_slave_sw_if_index;
231       x |= sw_if_index[3] ^ last_slave_sw_if_index;
232
233       if (PREDICT_TRUE (x == 0))
234         {
235           next[0] = next[1] = next[2] = next[3] = next_index;
236           if (next_index == BOND_INPUT_NEXT_DROP)
237             {
238               b[0]->error = error;
239               b[1]->error = error;
240               b[2]->error = error;
241               b[3]->error = error;
242             }
243           else
244             {
245               cnt +=
246                 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
247               cnt +=
248                 bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
249               cnt +=
250                 bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
251               cnt +=
252                 bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
253             }
254         }
255       else
256         {
257
258           bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
259                             cnt, &bond_sw_if_index, b[0], &next_index,
260                             &error);
261           next[0] = next_index;
262           if (next_index == BOND_INPUT_NEXT_DROP)
263             b[0]->error = error;
264           else
265             cnt += bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
266
267           bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
268                             cnt, &bond_sw_if_index, b[1], &next_index,
269                             &error);
270           next[1] = next_index;
271           if (next_index == BOND_INPUT_NEXT_DROP)
272             b[1]->error = error;
273           else
274             cnt += bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
275
276           bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
277                             cnt, &bond_sw_if_index, b[2], &next_index,
278                             &error);
279           next[2] = next_index;
280           if (next_index == BOND_INPUT_NEXT_DROP)
281             b[2]->error = error;
282           else
283             cnt += bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
284
285           bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
286                             cnt, &bond_sw_if_index, b[3], &next_index,
287                             &error);
288           next[3] = next_index;
289           if (next_index == BOND_INPUT_NEXT_DROP)
290             b[3]->error = error;
291           else
292             cnt += bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
293         }
294
295       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
296       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
297       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
298       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
299
300       /* next */
301       n_left -= 4;
302       b += 4;
303       sw_if_index += 4;
304       next += 4;
305     }
306
307   while (n_left)
308     {
309       sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
310       bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
311                         cnt, &bond_sw_if_index, b[0], &next_index, &error);
312       next[0] = next_index;
313       if (next_index == BOND_INPUT_NEXT_DROP)
314         b[0]->error = error;
315       else
316         bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
317
318       VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
319
320       /* next */
321       n_left -= 1;
322       b += 1;
323       sw_if_index += 1;
324       next += 1;
325     }
326
327   if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
328     {
329       n_left = frame->n_vectors;        /* number of packets to process */
330       b = bufs;
331       sw_if_index = sw_if_indices;
332       bond_packet_trace_t *t0;
333
334       while (n_left)
335         {
336           if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
337             {
338               t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
339               t0->sw_if_index = sw_if_index[0];
340               clib_memcpy (&t0->ethernet, vlib_buffer_get_current (b[0]),
341                            sizeof (ethernet_header_t));
342               t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
343             }
344           /* next */
345           n_left--;
346           b++;
347           sw_if_index++;
348         }
349     }
350
351   /* increase rx counters */
352   vlib_increment_simple_counter
353     (vnet_main.interface_main.sw_if_counters +
354      VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, cnt);
355
356   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
357   vlib_node_increment_counter (vm, bond_input_node.index,
358                                BOND_INPUT_ERROR_NONE, frame->n_vectors);
359
360   return frame->n_vectors;
361 }
362
363 #ifndef CLIB_MARCH_VARIANT
364 static clib_error_t *
365 bond_input_init (vlib_main_t * vm)
366 {
367   return 0;
368 }
369
370 /* *INDENT-OFF* */
371 VLIB_REGISTER_NODE (bond_input_node) = {
372   .name = "bond-input",
373   .vector_size = sizeof (u32),
374   .format_buffer = format_ethernet_header_with_length,
375   .format_trace = format_bond_input_trace,
376   .type = VLIB_NODE_TYPE_INTERNAL,
377   .n_errors = BOND_INPUT_N_ERROR,
378   .error_strings = bond_input_error_strings,
379   .n_next_nodes = BOND_INPUT_N_NEXT,
380   .next_nodes =
381   {
382     [BOND_INPUT_NEXT_DROP] = "error-drop"
383   }
384 };
385
386 VLIB_INIT_FUNCTION (bond_input_init);
387
388 VNET_FEATURE_INIT (bond_input, static) =
389 {
390   .arc_name = "device-input",
391   .node_name = "bond-input",
392   .runs_before = VNET_FEATURES ("ethernet-input"),
393 };
394 /* *INDENT-ON* */
395
396 static clib_error_t *
397 bond_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
398 {
399   bond_main_t *bm = &bond_main;
400   slave_if_t *sif;
401   vlib_main_t *vm = bm->vlib_main;
402
403   sif = bond_get_slave_by_sw_if_index (sw_if_index);
404   if (sif)
405     {
406       sif->port_enabled = flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
407       if (sif->port_enabled == 0)
408         {
409           if (sif->lacp_enabled == 0)
410             {
411               bond_disable_collecting_distributing (vm, sif);
412             }
413         }
414       else
415         {
416           if (sif->lacp_enabled == 0)
417             {
418               bond_enable_collecting_distributing (vm, sif);
419             }
420         }
421     }
422
423   return 0;
424 }
425
426 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bond_sw_interface_up_down);
427
428 static clib_error_t *
429 bond_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
430 {
431   bond_main_t *bm = &bond_main;
432   slave_if_t *sif;
433   vnet_sw_interface_t *sw;
434   vlib_main_t *vm = bm->vlib_main;
435
436   sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
437   sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
438   if (sif)
439     {
440       if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
441         {
442           if (sif->lacp_enabled == 0)
443             {
444               bond_disable_collecting_distributing (vm, sif);
445             }
446         }
447       else
448         {
449           if (sif->lacp_enabled == 0)
450             {
451               bond_enable_collecting_distributing (vm, sif);
452             }
453         }
454     }
455
456   return 0;
457 }
458
459 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
460 #endif
461
462 /*
463  * fd.io coding-style-patch-verification: ON
464  *
465  * Local Variables:
466  * eval: (c-set-style "gnu")
467  * End:
468  */