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