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 _(PASS_THRU, "pass through (CDP, LLDP, slow protocols)")
33 #define _(f,s) BOND_INPUT_ERROR_##f,
34 foreach_bond_input_error
39 #ifndef CLIB_MULTIARCH_VARIANT
40 static char *bond_input_error_strings[] = {
42 foreach_bond_input_error
47 format_bond_input_trace (u8 * s, va_list * args)
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 *);
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 (),
58 format_vnet_sw_if_index_name, vnet_get_main (),
72 static_always_inline u8
73 packet_is_cdp (ethernet_header_t * eth)
78 llc = (llc_header_t *) (eth + 1);
79 snap = (snap_header_t *) (llc + 1);
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)));
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)
92 u16 *ethertype_p, ethertype;
93 ethernet_vlan_header_t *vlan;
94 ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b);
96 ethertype = clib_mem_unaligned (ð->type, u16);
97 if (!ethernet_frame_is_tagged (ntohs (ethertype)))
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))))
104 /* Change the physical interface to bond interface */
105 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
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))
117 ethertype_p = &vlan->type;
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))))
124 /* Change the physical interface to bond interface */
125 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
130 vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
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,
138 u32 * bond_sw_if_index, vlib_buffer_t * b,
139 u32 * next_index, vlib_error_t * error)
141 u16 thread_index = vlib_get_thread_index ();
145 if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
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);
153 *last_slave_sw_if_index = slave_sw_if_index;
154 *next_index = BOND_INPUT_NEXT_DROP;
156 sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
159 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
162 ASSERT (vec_len (bif->slaves));
164 if (PREDICT_TRUE (bif->admin_up == 0))
166 *bond_sw_if_index = slave_sw_if_index;
167 *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
170 *bond_sw_if_index = bif->sw_if_index;
172 vnet_feature_next ( /* not used */ 0, next_index, b);
175 uword CLIB_CPU_OPTIMIZED
176 CLIB_MULTIARCH_FN (bond_input_fn) (vlib_main_t * vm,
177 vlib_node_runtime_t * node,
178 vlib_frame_t * frame)
180 u16 thread_index = vlib_get_thread_index ();
182 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
183 u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
184 u16 nexts[VLIB_FRAME_SIZE], *next;
185 u32 last_slave_sw_if_index = ~0;
186 u32 bond_sw_if_index = 0;
187 vlib_error_t error = 0;
191 /* Vector of buffer / pkt indices we're supposed to process */
192 from = vlib_frame_vector_args (frame);
194 /* Number of buffers / pkts */
195 n_left = frame->n_vectors;
197 vlib_get_buffers (vm, from, bufs, n_left);
201 sw_if_index = sw_if_indices;
206 /* Prefetch next iteration */
207 if (PREDICT_TRUE (n_left >= 16))
209 CLIB_PREFETCH (vlib_buffer_get_current (b[8]),
210 CLIB_CACHE_LINE_BYTES, LOAD);
211 CLIB_PREFETCH (vlib_buffer_get_current (b[9]),
212 CLIB_CACHE_LINE_BYTES, LOAD);
213 CLIB_PREFETCH (vlib_buffer_get_current (b[10]),
214 CLIB_CACHE_LINE_BYTES, LOAD);
215 CLIB_PREFETCH (vlib_buffer_get_current (b[11]),
216 CLIB_CACHE_LINE_BYTES, LOAD);
218 vlib_prefetch_buffer_header (b[12], LOAD);
219 vlib_prefetch_buffer_header (b[13], LOAD);
220 vlib_prefetch_buffer_header (b[14], LOAD);
221 vlib_prefetch_buffer_header (b[15], LOAD);
224 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
225 sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
226 sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
227 sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
229 x |= sw_if_index[0] ^ last_slave_sw_if_index;
230 x |= sw_if_index[1] ^ last_slave_sw_if_index;
231 x |= sw_if_index[2] ^ last_slave_sw_if_index;
232 x |= sw_if_index[3] ^ last_slave_sw_if_index;
234 if (PREDICT_TRUE (x == 0))
236 next[0] = next[1] = next[2] = next[3] = next_index;
237 if (next_index == BOND_INPUT_NEXT_DROP)
247 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
249 bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
251 bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
253 bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
259 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
260 cnt, &bond_sw_if_index, b[0], &next_index,
262 next[0] = next_index;
263 if (next_index == BOND_INPUT_NEXT_DROP)
266 cnt += bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
268 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
269 cnt, &bond_sw_if_index, b[1], &next_index,
271 next[1] = next_index;
272 if (next_index == BOND_INPUT_NEXT_DROP)
275 cnt += bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
277 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
278 cnt, &bond_sw_if_index, b[2], &next_index,
280 next[2] = next_index;
281 if (next_index == BOND_INPUT_NEXT_DROP)
284 cnt += bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
286 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
287 cnt, &bond_sw_if_index, b[3], &next_index,
289 next[3] = next_index;
290 if (next_index == BOND_INPUT_NEXT_DROP)
293 cnt += bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
296 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
297 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
298 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
299 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
310 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
311 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
312 cnt, &bond_sw_if_index, b[0], &next_index, &error);
313 next[0] = next_index;
314 if (next_index == BOND_INPUT_NEXT_DROP)
317 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
319 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
328 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
330 n_left = frame->n_vectors; /* number of packets to process */
332 sw_if_index = sw_if_indices;
334 bond_packet_trace_t *t0;
335 uword n_trace = vlib_get_trace_count (vm, node);
337 while (n_left && n_trace)
339 if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
341 vlib_trace_buffer (vm, node, next[0], b[0],
342 0 /* follow_chain */ );
343 vlib_set_trace_count (vm, node, --n_trace);
344 t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
345 t0->sw_if_index = sw_if_index[0];
346 clib_memcpy (&t0->ethernet, vlib_buffer_get_current (b[0]),
347 sizeof (ethernet_header_t));
348 t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
358 /* increase rx counters */
359 vlib_increment_simple_counter
360 (vnet_main.interface_main.sw_if_counters +
361 VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, cnt);
363 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
364 vlib_node_increment_counter (vm, bond_input_node.index,
365 BOND_INPUT_ERROR_NONE, frame->n_vectors);
367 return frame->n_vectors;
370 #ifndef CLIB_MULTIARCH_VARIANT
371 static clib_error_t *
372 bond_input_init (vlib_main_t * vm)
378 VLIB_REGISTER_NODE (bond_input_node) = {
379 .function = bond_input_fn,
380 .name = "bond-input",
381 .vector_size = sizeof (u32),
382 .format_buffer = format_ethernet_header_with_length,
383 .format_trace = format_bond_input_trace,
384 .type = VLIB_NODE_TYPE_INTERNAL,
385 .n_errors = BOND_INPUT_N_ERROR,
386 .error_strings = bond_input_error_strings,
387 .n_next_nodes = BOND_INPUT_N_NEXT,
390 [BOND_INPUT_NEXT_DROP] = "error-drop"
395 vlib_node_function_t __clib_weak bond_input_fn_avx512;
396 vlib_node_function_t __clib_weak bond_input_fn_avx2;
397 static void __clib_constructor
398 bond_input_multiarch_select (void)
400 if (bond_input_fn_avx512 && clib_cpu_supports_avx512f ())
401 bond_input_node.function = bond_input_fn_avx512;
402 else if (bond_input_fn_avx2 && clib_cpu_supports_avx2 ())
403 bond_input_node.function = bond_input_fn_avx2;
408 VLIB_INIT_FUNCTION (bond_input_init);
410 VNET_FEATURE_INIT (bond_input, static) =
412 .arc_name = "device-input",
413 .node_name = "bond-input",
414 .runs_before = VNET_FEATURES ("ethernet-input"),
418 static clib_error_t *
419 bond_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
421 bond_main_t *bm = &bond_main;
423 vlib_main_t *vm = bm->vlib_main;
425 sif = bond_get_slave_by_sw_if_index (sw_if_index);
428 sif->port_enabled = flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
429 if (sif->port_enabled == 0)
431 if (sif->lacp_enabled == 0)
433 bond_disable_collecting_distributing (vm, sif);
438 if (sif->lacp_enabled == 0)
440 bond_enable_collecting_distributing (vm, sif);
448 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bond_sw_interface_up_down);
450 static clib_error_t *
451 bond_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
453 bond_main_t *bm = &bond_main;
455 vnet_sw_interface_t *sw;
456 vlib_main_t *vm = bm->vlib_main;
458 sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
459 sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
462 if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
464 if (sif->lacp_enabled == 0)
466 bond_disable_collecting_distributing (vm, sif);
471 if (sif->lacp_enabled == 0)
473 bond_enable_collecting_distributing (vm, sif);
481 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
485 * fd.io coding-style-patch-verification: ON
488 * eval: (c-set-style "gnu")