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 #ifndef CLIB_MARCH_VARIANT
25 bond_main_t bond_main;
26 #endif /* CLIB_MARCH_VARIANT */
28 #define foreach_bond_input_error \
30 _(IF_DOWN, "interface down") \
31 _(PASSIVE_IF, "traffic received on passive interface") \
32 _(PASS_THRU, "pass through (CDP, LLDP, slow protocols)")
36 #define _(f,s) BOND_INPUT_ERROR_##f,
37 foreach_bond_input_error
42 static char *bond_input_error_strings[] = {
44 foreach_bond_input_error
49 format_bond_input_trace (u8 * s, va_list * args)
51 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
52 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
53 bond_packet_trace_t *t = va_arg (*args, bond_packet_trace_t *);
55 s = format (s, "src %U, dst %U, %U -> %U",
56 format_ethernet_address, t->ethernet.src_address,
57 format_ethernet_address, t->ethernet.dst_address,
58 format_vnet_sw_if_index_name, vnet_get_main (),
60 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,
91 u32 * n_rx_packets, u32 * n_rx_bytes)
93 u16 *ethertype_p, ethertype;
94 ethernet_vlan_header_t *vlan;
95 ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b);
98 *n_rx_bytes += b->current_length;
99 ethertype = clib_mem_unaligned (ð->type, u16);
100 if (!ethernet_frame_is_tagged (ntohs (ethertype)))
102 // Let some layer2 packets pass through.
103 if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
104 && !packet_is_cdp (eth)
105 && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
107 /* Change the physical interface to bond interface */
108 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
114 vlan = (void *) (eth + 1);
115 ethertype_p = &vlan->type;
116 ethertype = clib_mem_unaligned (ethertype_p, u16);
117 if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
120 ethertype_p = &vlan->type;
122 ethertype = clib_mem_unaligned (ethertype_p, u16);
123 if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
124 && (ethertype != htons (ETHERNET_TYPE_CDP))
125 && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
127 /* Change the physical interface to bond interface */
128 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
133 vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
138 bond_update_next (vlib_main_t * vm, vlib_node_runtime_t * node,
139 u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
140 u32 * bond_sw_if_index, vlib_buffer_t * b,
141 u32 * next_index, vlib_error_t * error)
146 *next_index = BOND_INPUT_NEXT_DROP;
149 if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
152 *last_slave_sw_if_index = slave_sw_if_index;
154 sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
157 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
160 ASSERT (vec_len (bif->slaves));
162 if (PREDICT_FALSE (bif->admin_up == 0))
164 *bond_sw_if_index = slave_sw_if_index;
165 *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
169 if (PREDICT_FALSE ((bif->mode == BOND_MODE_ACTIVE_BACKUP) &&
170 vec_len (bif->active_slaves) &&
171 (slave_sw_if_index != bif->active_slaves[0])))
173 *bond_sw_if_index = slave_sw_if_index;
174 *error = node->errors[BOND_INPUT_ERROR_PASSIVE_IF];
178 *bond_sw_if_index = bif->sw_if_index;
181 vnet_feature_next (next_index, b);
184 static_always_inline void
185 bond_update_next_x4 (vlib_buffer_t * b0, vlib_buffer_t * b1,
186 vlib_buffer_t * b2, vlib_buffer_t * b3)
188 u32 tmp0, tmp1, tmp2, tmp3;
190 tmp0 = tmp1 = tmp2 = tmp3 = BOND_INPUT_NEXT_DROP;
191 vnet_feature_next (&tmp0, b0);
192 vnet_feature_next (&tmp1, b1);
193 vnet_feature_next (&tmp2, b2);
194 vnet_feature_next (&tmp3, b3);
197 VLIB_NODE_FN (bond_input_node) (vlib_main_t * vm,
198 vlib_node_runtime_t * node,
199 vlib_frame_t * frame)
201 u16 thread_index = vm->thread_index;
203 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
204 u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
205 u16 nexts[VLIB_FRAME_SIZE], *next;
206 u32 last_slave_sw_if_index = ~0;
207 u32 bond_sw_if_index = 0;
208 vlib_error_t error = 0;
210 u32 n_rx_bytes = 0, n_rx_packets = 0;
212 /* Vector of buffer / pkt indices we're supposed to process */
213 from = vlib_frame_vector_args (frame);
215 /* Number of buffers / pkts */
216 n_left = frame->n_vectors;
218 vlib_get_buffers (vm, from, bufs, n_left);
222 sw_if_index = sw_if_indices;
227 /* Prefetch next iteration */
228 if (PREDICT_TRUE (n_left >= 16))
230 vlib_prefetch_buffer_data (b[8], LOAD);
231 vlib_prefetch_buffer_data (b[9], LOAD);
232 vlib_prefetch_buffer_data (b[10], LOAD);
233 vlib_prefetch_buffer_data (b[11], LOAD);
235 vlib_prefetch_buffer_header (b[12], LOAD);
236 vlib_prefetch_buffer_header (b[13], LOAD);
237 vlib_prefetch_buffer_header (b[14], LOAD);
238 vlib_prefetch_buffer_header (b[15], LOAD);
241 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
242 sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
243 sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
244 sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
246 x |= sw_if_index[0] ^ last_slave_sw_if_index;
247 x |= sw_if_index[1] ^ last_slave_sw_if_index;
248 x |= sw_if_index[2] ^ last_slave_sw_if_index;
249 x |= sw_if_index[3] ^ last_slave_sw_if_index;
251 if (PREDICT_TRUE (x == 0))
254 * Optimize to call update_next only if there is a feature arc
255 * after bond-input. Test feature count greater than 1 because
256 * bond-input itself is a feature arc for this slave interface.
258 ASSERT ((vnet_buffer (b[0])->feature_arc_index ==
259 vnet_buffer (b[1])->feature_arc_index) &&
260 (vnet_buffer (b[0])->feature_arc_index ==
261 vnet_buffer (b[2])->feature_arc_index) &&
262 (vnet_buffer (b[0])->feature_arc_index ==
263 vnet_buffer (b[3])->feature_arc_index));
264 if (PREDICT_FALSE (vnet_get_feature_count
265 (vnet_buffer (b[0])->feature_arc_index,
266 last_slave_sw_if_index) > 1))
267 bond_update_next_x4 (b[0], b[1], b[2], b[3]);
269 next[0] = next[1] = next[2] = next[3] = next_index;
270 if (next_index == BOND_INPUT_NEXT_DROP)
279 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
280 &n_rx_packets, &n_rx_bytes);
281 bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index,
282 &n_rx_packets, &n_rx_bytes);
283 bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index,
284 &n_rx_packets, &n_rx_bytes);
285 bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index,
286 &n_rx_packets, &n_rx_bytes);
291 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
292 &bond_sw_if_index, b[0], &next_index, &error);
293 next[0] = next_index;
294 if (next_index == BOND_INPUT_NEXT_DROP)
297 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
298 &n_rx_packets, &n_rx_bytes);
300 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
301 &bond_sw_if_index, b[1], &next_index, &error);
302 next[1] = next_index;
303 if (next_index == BOND_INPUT_NEXT_DROP)
306 bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index,
307 &n_rx_packets, &n_rx_bytes);
309 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
310 &bond_sw_if_index, b[2], &next_index, &error);
311 next[2] = next_index;
312 if (next_index == BOND_INPUT_NEXT_DROP)
315 bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index,
316 &n_rx_packets, &n_rx_bytes);
318 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
319 &bond_sw_if_index, b[3], &next_index, &error);
320 next[3] = next_index;
321 if (next_index == BOND_INPUT_NEXT_DROP)
324 bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index,
325 &n_rx_packets, &n_rx_bytes);
328 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
329 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
330 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
331 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
342 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
343 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
344 &bond_sw_if_index, b[0], &next_index, &error);
345 next[0] = next_index;
346 if (next_index == BOND_INPUT_NEXT_DROP)
349 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index,
350 &n_rx_packets, &n_rx_bytes);
352 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
361 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
363 n_left = frame->n_vectors; /* number of packets to process */
365 sw_if_index = sw_if_indices;
366 bond_packet_trace_t *t0;
370 if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
372 t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
373 t0->sw_if_index = sw_if_index[0];
374 clib_memcpy_fast (&t0->ethernet, vlib_buffer_get_current (b[0]),
375 sizeof (ethernet_header_t));
376 t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
385 /* increase rx counters */
386 vlib_increment_combined_counter
387 (vnet_main.interface_main.combined_sw_if_counters +
388 VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, n_rx_packets,
391 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
392 vlib_node_increment_counter (vm, bond_input_node.index,
393 BOND_INPUT_ERROR_NONE, frame->n_vectors);
395 return frame->n_vectors;
398 static clib_error_t *
399 bond_input_init (vlib_main_t * vm)
405 VLIB_REGISTER_NODE (bond_input_node) = {
406 .name = "bond-input",
407 .vector_size = sizeof (u32),
408 .format_buffer = format_ethernet_header_with_length,
409 .format_trace = format_bond_input_trace,
410 .type = VLIB_NODE_TYPE_INTERNAL,
411 .n_errors = BOND_INPUT_N_ERROR,
412 .error_strings = bond_input_error_strings,
413 .n_next_nodes = BOND_INPUT_N_NEXT,
416 [BOND_INPUT_NEXT_DROP] = "error-drop"
420 VLIB_INIT_FUNCTION (bond_input_init);
422 VNET_FEATURE_INIT (bond_input, static) =
424 .arc_name = "device-input",
425 .node_name = "bond-input",
426 .runs_before = VNET_FEATURES ("ethernet-input"),
430 static clib_error_t *
431 bond_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
433 bond_main_t *bm = &bond_main;
435 vlib_main_t *vm = bm->vlib_main;
437 sif = bond_get_slave_by_sw_if_index (sw_if_index);
440 if (sif->lacp_enabled)
443 /* port_enabled is both admin up and hw link up */
444 sif->port_enabled = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
445 vnet_sw_interface_is_link_up (vnm, sw_if_index));
446 if (sif->port_enabled == 0)
447 bond_disable_collecting_distributing (vm, sif);
449 bond_enable_collecting_distributing (vm, sif);
455 VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bond_sw_interface_up_down);
457 static clib_error_t *
458 bond_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
460 bond_main_t *bm = &bond_main;
462 vnet_sw_interface_t *sw;
463 vlib_main_t *vm = bm->vlib_main;
465 sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
466 sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
469 if (sif->lacp_enabled)
472 /* port_enabled is both admin up and hw link up */
473 sif->port_enabled = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) &&
474 vnet_sw_interface_is_admin_up (vnm,
476 if (sif->port_enabled == 0)
477 bond_disable_collecting_distributing (vm, sif);
479 bond_enable_collecting_distributing (vm, sif);
485 VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
488 * fd.io coding-style-patch-verification: ON
491 * eval: (c-set-style "gnu")