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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
20 #include <vnet/llc/llc.h>
21 #include <vnet/snap/snap.h>
22 #include <vnet/bonding/node.h>
24 bond_main_t bond_main;
26 #define foreach_bond_input_error \
28 _(IF_DOWN, "interface down") \
29 _(NO_SLAVE, "no slave") \
30 _(NO_BOND, "no bond interface")\
31 _(PASS_THRU, "pass through")
35 #define _(f,s) BOND_INPUT_ERROR_##f,
36 foreach_bond_input_error
41 static char *bond_input_error_strings[] = {
43 foreach_bond_input_error
48 format_bond_input_trace (u8 * s, va_list * args)
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 *);
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 (),
59 format_vnet_sw_if_index_name, vnet_get_main (),
65 static_always_inline u8
66 packet_is_cdp (ethernet_header_t * eth)
71 llc = (llc_header_t *) (eth + 1);
72 snap = (snap_header_t *) (llc + 1);
74 return ((eth->type == htons (ETHERNET_TYPE_CDP)) ||
75 ((llc->src_sap == 0xAA) && (llc->control == 0x03) &&
76 (snap->protocol == htons (0x2000)) &&
77 (snap->oui[0] == 0) && (snap->oui[1] == 0) &&
78 (snap->oui[2] == 0x0C)));
82 bond_sw_if_index_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node,
83 slave_if_t * sif, ethernet_header_t * eth,
87 u16 thread_index = vlib_get_thread_index ();
88 u16 *ethertype_p, ethertype;
89 ethernet_vlan_header_t *vlan;
91 if (PREDICT_TRUE (sif != 0))
93 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
94 if (PREDICT_TRUE (bif != 0))
96 if (PREDICT_TRUE (vec_len (bif->slaves) >= 1))
98 if (PREDICT_TRUE (bif->admin_up == 1))
100 ethertype = clib_mem_unaligned (ð->type, u16);
101 if (!ethernet_frame_is_tagged (ntohs (ethertype)))
103 // Let some layer2 packets pass through.
104 if (PREDICT_TRUE ((ethertype !=
105 htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
106 && !packet_is_cdp (eth)
109 (ETHERNET_TYPE_802_1_LLDP))))
111 // Change the physical interface to
113 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
116 /* increase rx counters */
117 vlib_increment_simple_counter
118 (vnet_main.interface_main.sw_if_counters +
119 VNET_INTERFACE_COUNTER_RX, thread_index,
120 bif->sw_if_index, 1);
124 vlib_error_count (vm, node->node_index,
125 BOND_INPUT_ERROR_PASS_THRU, 1);
130 vlan = (void *) (eth + 1);
131 ethertype_p = &vlan->type;
132 ethertype = clib_mem_unaligned (ethertype_p, u16);
133 if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
136 ethertype_p = &vlan->type;
138 ethertype = clib_mem_unaligned (ethertype_p, u16);
139 if (PREDICT_TRUE ((ethertype !=
140 htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
142 htons (ETHERNET_TYPE_CDP))
145 (ETHERNET_TYPE_802_1_LLDP))))
147 // Change the physical interface to
149 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
152 /* increase rx counters */
153 vlib_increment_simple_counter
154 (vnet_main.interface_main.sw_if_counters +
155 VNET_INTERFACE_COUNTER_RX, thread_index,
156 bif->sw_if_index, 1);
160 vlib_error_count (vm, node->node_index,
161 BOND_INPUT_ERROR_PASS_THRU, 1);
167 vlib_error_count (vm, node->node_index,
168 BOND_INPUT_ERROR_IF_DOWN, 1);
173 vlib_error_count (vm, node->node_index,
174 BOND_INPUT_ERROR_NO_SLAVE, 1);
179 vlib_error_count (vm, node->node_index,
180 BOND_INPUT_ERROR_NO_BOND, 1);
185 vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_NO_SLAVE, 1);
191 bond_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
192 vlib_frame_t * frame)
194 u32 bi0, bi1, bi2, bi3;
195 vlib_buffer_t *b0, *b1, *b2, *b3;
197 u32 *from, *to_next, n_left_from, n_left_to_next;
198 ethernet_header_t *eth, *eth1, *eth2, *eth3;
199 u32 next0, next1, next2, next3;
200 bond_packet_trace_t *t0;
201 uword n_trace = vlib_get_trace_count (vm, node);
202 u32 sw_if_index, sw_if_index1, sw_if_index2, sw_if_index3;
203 slave_if_t *sif, *sif1, *sif2, *sif3;
204 u16 thread_index = vlib_get_thread_index ();
206 /* Vector of buffer / pkt indices we're supposed to process */
207 from = vlib_frame_vector_args (frame);
209 /* Number of buffers / pkts */
210 n_left_from = frame->n_vectors;
212 /* Speculatively send the first buffer to the last disposition we used */
213 next_index = node->cached_next_index;
215 while (n_left_from > 0)
217 /* set up to enqueue to our disposition with index = next_index */
218 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
220 while (n_left_from >= 12 && n_left_to_next >= 4)
222 // Prefetch next iteration
224 vlib_buffer_t *b4, *b5, *b6, *b7;
226 b4 = vlib_get_buffer (vm, from[4]);
227 b5 = vlib_get_buffer (vm, from[5]);
228 b6 = vlib_get_buffer (vm, from[6]);
229 b7 = vlib_get_buffer (vm, from[7]);
231 vlib_prefetch_buffer_header (b4, LOAD);
232 vlib_prefetch_buffer_header (b5, LOAD);
233 vlib_prefetch_buffer_header (b6, LOAD);
234 vlib_prefetch_buffer_header (b7, LOAD);
236 CLIB_PREFETCH (b4->data, CLIB_CACHE_LINE_BYTES, LOAD);
237 CLIB_PREFETCH (b5->data, CLIB_CACHE_LINE_BYTES, LOAD);
238 CLIB_PREFETCH (b6->data, CLIB_CACHE_LINE_BYTES, LOAD);
239 CLIB_PREFETCH (b7->data, CLIB_CACHE_LINE_BYTES, LOAD);
262 b0 = vlib_get_buffer (vm, bi0);
263 b1 = vlib_get_buffer (vm, bi1);
264 b2 = vlib_get_buffer (vm, bi2);
265 b3 = vlib_get_buffer (vm, bi3);
267 vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0,
269 vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_RX], &next1,
271 vnet_feature_next (vnet_buffer (b2)->sw_if_index[VLIB_RX], &next2,
273 vnet_feature_next (vnet_buffer (b3)->sw_if_index[VLIB_RX], &next3,
276 eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
277 eth1 = (ethernet_header_t *) vlib_buffer_get_current (b1);
278 eth2 = (ethernet_header_t *) vlib_buffer_get_current (b2);
279 eth3 = (ethernet_header_t *) vlib_buffer_get_current (b3);
281 sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
282 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
283 sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_RX];
284 sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_RX];
286 // sw_if_index points to the physical interface
287 sif = bond_get_slave_by_sw_if_index (sw_if_index);
288 sif1 = bond_get_slave_by_sw_if_index (sw_if_index1);
289 sif2 = bond_get_slave_by_sw_if_index (sw_if_index2);
290 sif3 = bond_get_slave_by_sw_if_index (sw_if_index3);
292 bond_sw_if_index_rewrite (vm, node, sif, eth, b0);
293 bond_sw_if_index_rewrite (vm, node, sif1, eth1, b1);
294 bond_sw_if_index_rewrite (vm, node, sif2, eth2, b2);
295 bond_sw_if_index_rewrite (vm, node, sif3, eth3, b3);
297 if (PREDICT_FALSE (n_trace > 0))
299 vlib_trace_buffer (vm, node, next0, b0, 0 /* follow_chain */ );
300 vlib_set_trace_count (vm, node, --n_trace);
301 t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
303 t0->sw_if_index = sw_if_index;
304 t0->bond_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
306 if (PREDICT_TRUE (n_trace > 0))
308 vlib_trace_buffer (vm, node, next1, b1,
309 0 /* follow_chain */ );
310 vlib_set_trace_count (vm, node, --n_trace);
311 t0 = vlib_add_trace (vm, node, b1, sizeof (*t0));
312 t0->ethernet = *eth1;
313 t0->sw_if_index = sw_if_index1;
314 t0->bond_sw_if_index =
315 vnet_buffer (b1)->sw_if_index[VLIB_RX];
317 if (PREDICT_TRUE (n_trace > 0))
319 vlib_trace_buffer (vm, node, next2, b2,
320 0 /* follow_chain */ );
321 vlib_set_trace_count (vm, node, --n_trace);
322 t0 = vlib_add_trace (vm, node, b2, sizeof (*t0));
323 t0->ethernet = *eth2;
324 t0->sw_if_index = sw_if_index2;
325 t0->bond_sw_if_index =
326 vnet_buffer (b2)->sw_if_index[VLIB_RX];
328 if (PREDICT_TRUE (n_trace > 0))
330 vlib_trace_buffer (vm, node, next3, b3,
331 0 /* follow_chain */ );
332 vlib_set_trace_count (vm, node, --n_trace);
333 t0 = vlib_add_trace (vm, node, b3, sizeof (*t0));
334 t0->ethernet = *eth3;
335 t0->sw_if_index = sw_if_index3;
336 t0->bond_sw_if_index =
337 vnet_buffer (b3)->sw_if_index[VLIB_RX];
343 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
344 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b1);
345 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b2);
346 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b3);
348 /* verify speculative enqueue, maybe switch current next frame */
349 vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
350 to_next, n_left_to_next,
351 bi0, bi1, bi2, bi3, next0, next1,
355 while (n_left_from > 0 && n_left_to_next > 0)
357 // Prefetch next iteration
362 p2 = vlib_get_buffer (vm, from[1]);
363 vlib_prefetch_buffer_header (p2, LOAD);
364 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
375 b0 = vlib_get_buffer (vm, bi0);
376 vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0,
379 eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
381 sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
382 // sw_if_index points to the physical interface
383 sif = bond_get_slave_by_sw_if_index (sw_if_index);
384 bond_sw_if_index_rewrite (vm, node, sif, eth, b0);
386 if (PREDICT_FALSE (n_trace > 0))
388 vlib_trace_buffer (vm, node, next0, b0, 0 /* follow_chain */ );
389 vlib_set_trace_count (vm, node, --n_trace);
390 t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
392 t0->sw_if_index = sw_if_index;
393 t0->bond_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
397 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
399 /* verify speculative enqueue, maybe switch current next frame */
400 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
401 to_next, n_left_to_next,
404 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
407 vlib_node_increment_counter (vm, bond_input_node.index,
408 BOND_INPUT_ERROR_NONE, frame->n_vectors);
410 vnet_device_increment_rx_packets (thread_index, frame->n_vectors);
412 return frame->n_vectors;
415 static clib_error_t *
416 bond_input_init (vlib_main_t * vm)
422 VLIB_REGISTER_NODE (bond_input_node) = {
423 .function = bond_input_fn,
424 .name = "bond-input",
425 .vector_size = sizeof (u32),
426 .format_buffer = format_ethernet_header_with_length,
427 .format_trace = format_bond_input_trace,
428 .type = VLIB_NODE_TYPE_INTERNAL,
429 .n_errors = BOND_INPUT_N_ERROR,
430 .error_strings = bond_input_error_strings,
438 VLIB_INIT_FUNCTION (bond_input_init);
440 VNET_FEATURE_INIT (bond_input, static) =
442 .arc_name = "device-input",
443 .node_name = "bond-input",
444 .runs_before = VNET_FEATURES ("ethernet-input"),
446 VLIB_NODE_FUNCTION_MULTIARCH (bond_input_node, bond_input_fn)
449 static clib_error_t *
450 bond_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
452 bond_main_t *bm = &bond_main;
454 vlib_main_t *vm = bm->vlib_main;
456 sif = bond_get_slave_by_sw_if_index (sw_if_index);
459 sif->port_enabled = flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
460 if (sif->port_enabled == 0)
462 if (sif->lacp_enabled == 0)
464 bond_disable_collecting_distributing (vm, sif);
469 if (sif->lacp_enabled == 0)
471 bond_enable_collecting_distributing (vm, sif);
479 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bond_sw_interface_up_down);
481 static clib_error_t *
482 bond_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
484 bond_main_t *bm = &bond_main;
486 vnet_sw_interface_t *sw;
487 vlib_main_t *vm = bm->vlib_main;
489 sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
490 sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
493 if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
495 if (sif->lacp_enabled == 0)
497 bond_disable_collecting_distributing (vm, sif);
502 if (sif->lacp_enabled == 0)
504 bond_enable_collecting_distributing (vm, sif);
512 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
515 * fd.io coding-style-patch-verification: ON
518 * eval: (c-set-style "gnu")