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