blob: 7abd7b0de32e34382065894f6cc1e54ab925d0bb [file] [log] [blame]
Steven9cd2d7a2017-12-20 12:43:01 -08001/*
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
24bond_main_t bond_main;
25
26#define foreach_bond_input_error \
27 _(NONE, "no error") \
28 _(IF_DOWN, "interface down") \
Damjan Marion5e5adb32018-05-26 00:50:39 +020029 _(PASS_THRU, "pass through (CDP, LLDP, slow protocols)")
Steven9cd2d7a2017-12-20 12:43:01 -080030
31typedef 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
Damjan Marion812b32d2018-05-28 21:26:47 +020039#ifndef CLIB_MARCH_VARIANT
Steven9cd2d7a2017-12-20 12:43:01 -080040static char *bond_input_error_strings[] = {
41#define _(n,s) s,
42 foreach_bond_input_error
43#undef _
44};
45
46static u8 *
47format_bond_input_trace (u8 * s, va_list * args)
48{
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 *);
Steven9cd2d7a2017-12-20 12:43:01 -080052
Steven70488ab2018-03-28 17:59:00 -070053 s = format (s, "src %U, dst %U, %U -> %U",
Steven9cd2d7a2017-12-20 12:43:01 -080054 format_ethernet_address, t->ethernet.src_address,
55 format_ethernet_address, t->ethernet.dst_address,
Steven70488ab2018-03-28 17:59:00 -070056 format_vnet_sw_if_index_name, vnet_get_main (),
57 t->sw_if_index,
58 format_vnet_sw_if_index_name, vnet_get_main (),
59 t->bond_sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -080060
61 return s;
62}
Damjan Marion5e5adb32018-05-26 00:50:39 +020063#endif
64
65
66typedef enum
67{
68 BOND_INPUT_NEXT_DROP,
69 BOND_INPUT_N_NEXT,
Steven9f781d82018-06-05 11:09:32 -070070} bond_output_next_t;
Steven9cd2d7a2017-12-20 12:43:01 -080071
72static_always_inline u8
73packet_is_cdp (ethernet_header_t * eth)
74{
75 llc_header_t *llc;
76 snap_header_t *snap;
77
78 llc = (llc_header_t *) (eth + 1);
79 snap = (snap_header_t *) (llc + 1);
80
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)));
86}
87
Damjan Marion5e5adb32018-05-26 00:50:39 +020088static inline u32
89bond_sw_if_idx_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node,
90 vlib_buffer_t * b, u32 bond_sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080091{
Steven9cd2d7a2017-12-20 12:43:01 -080092 u16 *ethertype_p, ethertype;
93 ethernet_vlan_header_t *vlan;
Damjan Marion5e5adb32018-05-26 00:50:39 +020094 ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b);
Steven9cd2d7a2017-12-20 12:43:01 -080095
Damjan Marion5e5adb32018-05-26 00:50:39 +020096 ethertype = clib_mem_unaligned (&eth->type, u16);
97 if (!ethernet_frame_is_tagged (ntohs (ethertype)))
Steven9cd2d7a2017-12-20 12:43:01 -080098 {
Damjan Marion5e5adb32018-05-26 00:50:39 +020099 // 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))))
Steven9cd2d7a2017-12-20 12:43:01 -0800103 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200104 /* Change the physical interface to bond interface */
105 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
106 return 1;
Steven9cd2d7a2017-12-20 12:43:01 -0800107 }
108 }
109 else
110 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200111 vlan = (void *) (eth + 1);
112 ethertype_p = &vlan->type;
113 ethertype = clib_mem_unaligned (ethertype_p, u16);
114 if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
115 {
116 vlan++;
117 ethertype_p = &vlan->type;
118 }
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))))
123 {
124 /* Change the physical interface to bond interface */
125 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
126 return 1;
127 }
Steven9cd2d7a2017-12-20 12:43:01 -0800128 }
129
Damjan Marion5e5adb32018-05-26 00:50:39 +0200130 vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
131 return 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800132}
133
Damjan Marion5e5adb32018-05-26 00:50:39 +0200134static inline void
135bond_update_next (vlib_main_t * vm, vlib_node_runtime_t * node,
136 u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
137 u32 packet_count,
138 u32 * bond_sw_if_index, vlib_buffer_t * b,
139 u32 * next_index, vlib_error_t * error)
Steven9cd2d7a2017-12-20 12:43:01 -0800140{
Damjan Marion067cd622018-07-11 12:47:43 +0200141 u16 thread_index = vm->thread_index;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200142 slave_if_t *sif;
143 bond_if_t *bif;
144
145 if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
146 return;
147
148 if (packet_count)
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);
152
153 *last_slave_sw_if_index = slave_sw_if_index;
154 *next_index = BOND_INPUT_NEXT_DROP;
155
156 sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
157 ASSERT (sif);
158
159 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
160
161 ASSERT (bif);
162 ASSERT (vec_len (bif->slaves));
163
164 if (PREDICT_TRUE (bif->admin_up == 0))
165 {
166 *bond_sw_if_index = slave_sw_if_index;
167 *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
168 }
169
170 *bond_sw_if_index = bif->sw_if_index;
171 *error = 0;
172 vnet_feature_next ( /* not used */ 0, next_index, b);
173}
174
Damjan Marion812b32d2018-05-28 21:26:47 +0200175VLIB_NODE_FN (bond_input_node) (vlib_main_t * vm,
176 vlib_node_runtime_t * node,
177 vlib_frame_t * frame)
Damjan Marion5e5adb32018-05-26 00:50:39 +0200178{
Damjan Marion067cd622018-07-11 12:47:43 +0200179 u16 thread_index = vm->thread_index;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200180 u32 *from, n_left;
181 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
182 u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
183 u16 nexts[VLIB_FRAME_SIZE], *next;
184 u32 last_slave_sw_if_index = ~0;
185 u32 bond_sw_if_index = 0;
186 vlib_error_t error = 0;
187 u32 next_index = 0;
188 u32 cnt = 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800189
190 /* Vector of buffer / pkt indices we're supposed to process */
191 from = vlib_frame_vector_args (frame);
192
193 /* Number of buffers / pkts */
Damjan Marion5e5adb32018-05-26 00:50:39 +0200194 n_left = frame->n_vectors;
Steven9cd2d7a2017-12-20 12:43:01 -0800195
Damjan Marion5e5adb32018-05-26 00:50:39 +0200196 vlib_get_buffers (vm, from, bufs, n_left);
Steven9cd2d7a2017-12-20 12:43:01 -0800197
Damjan Marion5e5adb32018-05-26 00:50:39 +0200198 b = bufs;
199 next = nexts;
200 sw_if_index = sw_if_indices;
201
202 while (n_left >= 4)
Steven9cd2d7a2017-12-20 12:43:01 -0800203 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200204 u32 x = 0;
205 /* Prefetch next iteration */
206 if (PREDICT_TRUE (n_left >= 16))
Steven9cd2d7a2017-12-20 12:43:01 -0800207 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200208 CLIB_PREFETCH (vlib_buffer_get_current (b[8]),
209 CLIB_CACHE_LINE_BYTES, LOAD);
210 CLIB_PREFETCH (vlib_buffer_get_current (b[9]),
211 CLIB_CACHE_LINE_BYTES, LOAD);
212 CLIB_PREFETCH (vlib_buffer_get_current (b[10]),
213 CLIB_CACHE_LINE_BYTES, LOAD);
214 CLIB_PREFETCH (vlib_buffer_get_current (b[11]),
215 CLIB_CACHE_LINE_BYTES, LOAD);
Steven9cd2d7a2017-12-20 12:43:01 -0800216
Damjan Marion5e5adb32018-05-26 00:50:39 +0200217 vlib_prefetch_buffer_header (b[12], LOAD);
218 vlib_prefetch_buffer_header (b[13], LOAD);
219 vlib_prefetch_buffer_header (b[14], LOAD);
220 vlib_prefetch_buffer_header (b[15], LOAD);
Steven9cd2d7a2017-12-20 12:43:01 -0800221 }
222
Damjan Marion5e5adb32018-05-26 00:50:39 +0200223 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
224 sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
225 sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
226 sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
227
228 x |= sw_if_index[0] ^ last_slave_sw_if_index;
229 x |= sw_if_index[1] ^ last_slave_sw_if_index;
230 x |= sw_if_index[2] ^ last_slave_sw_if_index;
231 x |= sw_if_index[3] ^ last_slave_sw_if_index;
232
233 if (PREDICT_TRUE (x == 0))
Steven9cd2d7a2017-12-20 12:43:01 -0800234 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200235 next[0] = next[1] = next[2] = next[3] = next_index;
236 if (next_index == BOND_INPUT_NEXT_DROP)
Steven9cd2d7a2017-12-20 12:43:01 -0800237 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200238 b[0]->error = error;
239 b[1]->error = error;
240 b[2]->error = error;
241 b[3]->error = error;
Steven9cd2d7a2017-12-20 12:43:01 -0800242 }
Damjan Marion5e5adb32018-05-26 00:50:39 +0200243 else
Steven70488ab2018-03-28 17:59:00 -0700244 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200245 cnt +=
246 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
247 cnt +=
248 bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
249 cnt +=
250 bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
251 cnt +=
252 bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
Steven70488ab2018-03-28 17:59:00 -0700253 }
Steven9cd2d7a2017-12-20 12:43:01 -0800254 }
Damjan Marion5e5adb32018-05-26 00:50:39 +0200255 else
256 {
257
258 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
259 cnt, &bond_sw_if_index, b[0], &next_index,
260 &error);
261 next[0] = next_index;
262 if (next_index == BOND_INPUT_NEXT_DROP)
263 b[0]->error = error;
264 else
265 cnt += bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
266
267 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
268 cnt, &bond_sw_if_index, b[1], &next_index,
269 &error);
270 next[1] = next_index;
271 if (next_index == BOND_INPUT_NEXT_DROP)
272 b[1]->error = error;
273 else
274 cnt += bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
275
276 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
277 cnt, &bond_sw_if_index, b[2], &next_index,
278 &error);
279 next[2] = next_index;
280 if (next_index == BOND_INPUT_NEXT_DROP)
281 b[2]->error = error;
282 else
283 cnt += bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
284
285 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
286 cnt, &bond_sw_if_index, b[3], &next_index,
287 &error);
288 next[3] = next_index;
289 if (next_index == BOND_INPUT_NEXT_DROP)
290 b[3]->error = error;
291 else
292 cnt += bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
293 }
294
295 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
296 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
297 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
298 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
299
300 /* next */
301 n_left -= 4;
302 b += 4;
303 sw_if_index += 4;
304 next += 4;
Steven9cd2d7a2017-12-20 12:43:01 -0800305 }
306
Damjan Marion5e5adb32018-05-26 00:50:39 +0200307 while (n_left)
308 {
309 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
310 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
311 cnt, &bond_sw_if_index, b[0], &next_index, &error);
312 next[0] = next_index;
313 if (next_index == BOND_INPUT_NEXT_DROP)
314 b[0]->error = error;
315 else
316 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
317
318 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
319
320 /* next */
321 n_left -= 1;
322 b += 1;
323 sw_if_index += 1;
324 next += 1;
325 }
326
327 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
328 {
329 n_left = frame->n_vectors; /* number of packets to process */
330 b = bufs;
331 sw_if_index = sw_if_indices;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200332 bond_packet_trace_t *t0;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200333
Damjan Marionf264f082018-05-30 00:03:34 +0200334 while (n_left)
Damjan Marion5e5adb32018-05-26 00:50:39 +0200335 {
336 if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
337 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200338 t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
339 t0->sw_if_index = sw_if_index[0];
340 clib_memcpy (&t0->ethernet, vlib_buffer_get_current (b[0]),
341 sizeof (ethernet_header_t));
342 t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
343 }
344 /* next */
345 n_left--;
346 b++;
347 sw_if_index++;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200348 }
349 }
350
351 /* increase rx counters */
352 vlib_increment_simple_counter
353 (vnet_main.interface_main.sw_if_counters +
354 VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, cnt);
355
356 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Steven9cd2d7a2017-12-20 12:43:01 -0800357 vlib_node_increment_counter (vm, bond_input_node.index,
358 BOND_INPUT_ERROR_NONE, frame->n_vectors);
359
Steven9cd2d7a2017-12-20 12:43:01 -0800360 return frame->n_vectors;
361}
362
Damjan Marion812b32d2018-05-28 21:26:47 +0200363#ifndef CLIB_MARCH_VARIANT
Steven9cd2d7a2017-12-20 12:43:01 -0800364static clib_error_t *
365bond_input_init (vlib_main_t * vm)
366{
367 return 0;
368}
369
370/* *INDENT-OFF* */
371VLIB_REGISTER_NODE (bond_input_node) = {
Steven9cd2d7a2017-12-20 12:43:01 -0800372 .name = "bond-input",
373 .vector_size = sizeof (u32),
374 .format_buffer = format_ethernet_header_with_length,
375 .format_trace = format_bond_input_trace,
376 .type = VLIB_NODE_TYPE_INTERNAL,
377 .n_errors = BOND_INPUT_N_ERROR,
378 .error_strings = bond_input_error_strings,
Damjan Marion5e5adb32018-05-26 00:50:39 +0200379 .n_next_nodes = BOND_INPUT_N_NEXT,
Steven9cd2d7a2017-12-20 12:43:01 -0800380 .next_nodes =
381 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200382 [BOND_INPUT_NEXT_DROP] = "error-drop"
Steven9cd2d7a2017-12-20 12:43:01 -0800383 }
384};
385
386VLIB_INIT_FUNCTION (bond_input_init);
387
388VNET_FEATURE_INIT (bond_input, static) =
389{
390 .arc_name = "device-input",
391 .node_name = "bond-input",
392 .runs_before = VNET_FEATURES ("ethernet-input"),
393};
Steven9cd2d7a2017-12-20 12:43:01 -0800394/* *INDENT-ON* */
395
396static clib_error_t *
397bond_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
398{
399 bond_main_t *bm = &bond_main;
400 slave_if_t *sif;
401 vlib_main_t *vm = bm->vlib_main;
402
403 sif = bond_get_slave_by_sw_if_index (sw_if_index);
404 if (sif)
405 {
406 sif->port_enabled = flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
407 if (sif->port_enabled == 0)
408 {
409 if (sif->lacp_enabled == 0)
410 {
411 bond_disable_collecting_distributing (vm, sif);
412 }
413 }
414 else
415 {
416 if (sif->lacp_enabled == 0)
417 {
418 bond_enable_collecting_distributing (vm, sif);
419 }
420 }
421 }
422
423 return 0;
424}
425
426VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bond_sw_interface_up_down);
427
428static clib_error_t *
429bond_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
430{
431 bond_main_t *bm = &bond_main;
432 slave_if_t *sif;
433 vnet_sw_interface_t *sw;
434 vlib_main_t *vm = bm->vlib_main;
Steven9cd2d7a2017-12-20 12:43:01 -0800435
Stevence2db6a2018-04-23 17:06:24 -0700436 sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -0800437 sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
438 if (sif)
439 {
440 if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
441 {
442 if (sif->lacp_enabled == 0)
443 {
444 bond_disable_collecting_distributing (vm, sif);
445 }
446 }
447 else
448 {
449 if (sif->lacp_enabled == 0)
450 {
451 bond_enable_collecting_distributing (vm, sif);
452 }
453 }
454 }
455
456 return 0;
457}
458
459VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
Damjan Marion5e5adb32018-05-26 00:50:39 +0200460#endif
Steven9cd2d7a2017-12-20 12:43:01 -0800461
462/*
463 * fd.io coding-style-patch-verification: ON
464 *
465 * Local Variables:
466 * eval: (c-set-style "gnu")
467 * End:
468 */