blob: 361509c549dd610b091df364b711e48c10bb0fd3 [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
39static char *bond_input_error_strings[] = {
40#define _(n,s) s,
41 foreach_bond_input_error
42#undef _
43};
44
45static u8 *
46format_bond_input_trace (u8 * s, va_list * args)
47{
48 CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
49 CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
50 bond_packet_trace_t *t = va_arg (*args, bond_packet_trace_t *);
Steven9cd2d7a2017-12-20 12:43:01 -080051
Steven70488ab2018-03-28 17:59:00 -070052 s = format (s, "src %U, dst %U, %U -> %U",
Steven9cd2d7a2017-12-20 12:43:01 -080053 format_ethernet_address, t->ethernet.src_address,
54 format_ethernet_address, t->ethernet.dst_address,
Steven70488ab2018-03-28 17:59:00 -070055 format_vnet_sw_if_index_name, vnet_get_main (),
56 t->sw_if_index,
57 format_vnet_sw_if_index_name, vnet_get_main (),
58 t->bond_sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -080059
60 return s;
61}
Damjan Marion5e5adb32018-05-26 00:50:39 +020062
63typedef enum
64{
65 BOND_INPUT_NEXT_DROP,
66 BOND_INPUT_N_NEXT,
Steven9f781d82018-06-05 11:09:32 -070067} bond_output_next_t;
Steven9cd2d7a2017-12-20 12:43:01 -080068
69static_always_inline u8
70packet_is_cdp (ethernet_header_t * eth)
71{
72 llc_header_t *llc;
73 snap_header_t *snap;
74
75 llc = (llc_header_t *) (eth + 1);
76 snap = (snap_header_t *) (llc + 1);
77
78 return ((eth->type == htons (ETHERNET_TYPE_CDP)) ||
79 ((llc->src_sap == 0xAA) && (llc->control == 0x03) &&
80 (snap->protocol == htons (0x2000)) &&
81 (snap->oui[0] == 0) && (snap->oui[1] == 0) &&
82 (snap->oui[2] == 0x0C)));
83}
84
Damjan Marion5e5adb32018-05-26 00:50:39 +020085static inline u32
86bond_sw_if_idx_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node,
87 vlib_buffer_t * b, u32 bond_sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080088{
Steven9cd2d7a2017-12-20 12:43:01 -080089 u16 *ethertype_p, ethertype;
90 ethernet_vlan_header_t *vlan;
Damjan Marion5e5adb32018-05-26 00:50:39 +020091 ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b);
Steven9cd2d7a2017-12-20 12:43:01 -080092
Damjan Marion5e5adb32018-05-26 00:50:39 +020093 ethertype = clib_mem_unaligned (&eth->type, u16);
94 if (!ethernet_frame_is_tagged (ntohs (ethertype)))
Steven9cd2d7a2017-12-20 12:43:01 -080095 {
Damjan Marion5e5adb32018-05-26 00:50:39 +020096 // Let some layer2 packets pass through.
97 if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
98 && !packet_is_cdp (eth)
99 && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
Steven9cd2d7a2017-12-20 12:43:01 -0800100 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200101 /* Change the physical interface to bond interface */
102 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
103 return 1;
Steven9cd2d7a2017-12-20 12:43:01 -0800104 }
105 }
106 else
107 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200108 vlan = (void *) (eth + 1);
109 ethertype_p = &vlan->type;
110 ethertype = clib_mem_unaligned (ethertype_p, u16);
111 if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
112 {
113 vlan++;
114 ethertype_p = &vlan->type;
115 }
116 ethertype = clib_mem_unaligned (ethertype_p, u16);
117 if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
118 && (ethertype != htons (ETHERNET_TYPE_CDP))
119 && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
120 {
121 /* Change the physical interface to bond interface */
122 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
123 return 1;
124 }
Steven9cd2d7a2017-12-20 12:43:01 -0800125 }
126
Damjan Marion5e5adb32018-05-26 00:50:39 +0200127 vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
128 return 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800129}
130
Damjan Marion5e5adb32018-05-26 00:50:39 +0200131static inline void
132bond_update_next (vlib_main_t * vm, vlib_node_runtime_t * node,
133 u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
134 u32 packet_count,
135 u32 * bond_sw_if_index, vlib_buffer_t * b,
136 u32 * next_index, vlib_error_t * error)
Steven9cd2d7a2017-12-20 12:43:01 -0800137{
Damjan Marion067cd622018-07-11 12:47:43 +0200138 u16 thread_index = vm->thread_index;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200139 slave_if_t *sif;
140 bond_if_t *bif;
141
142 if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
143 return;
144
145 if (packet_count)
146 vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
147 VNET_INTERFACE_COUNTER_RX, thread_index,
148 *last_slave_sw_if_index, packet_count);
149
150 *last_slave_sw_if_index = slave_sw_if_index;
151 *next_index = BOND_INPUT_NEXT_DROP;
152
153 sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
154 ASSERT (sif);
155
156 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
157
158 ASSERT (bif);
159 ASSERT (vec_len (bif->slaves));
160
161 if (PREDICT_TRUE (bif->admin_up == 0))
162 {
163 *bond_sw_if_index = slave_sw_if_index;
164 *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
165 }
166
167 *bond_sw_if_index = bif->sw_if_index;
168 *error = 0;
Damjan Marion7d98a122018-07-19 20:42:08 +0200169 vnet_feature_next (next_index, b);
Damjan Marion5e5adb32018-05-26 00:50:39 +0200170}
171
Damjan Marion812b32d2018-05-28 21:26:47 +0200172VLIB_NODE_FN (bond_input_node) (vlib_main_t * vm,
173 vlib_node_runtime_t * node,
174 vlib_frame_t * frame)
Damjan Marion5e5adb32018-05-26 00:50:39 +0200175{
Damjan Marion067cd622018-07-11 12:47:43 +0200176 u16 thread_index = vm->thread_index;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200177 u32 *from, n_left;
178 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
179 u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
180 u16 nexts[VLIB_FRAME_SIZE], *next;
181 u32 last_slave_sw_if_index = ~0;
182 u32 bond_sw_if_index = 0;
183 vlib_error_t error = 0;
184 u32 next_index = 0;
185 u32 cnt = 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800186
187 /* Vector of buffer / pkt indices we're supposed to process */
188 from = vlib_frame_vector_args (frame);
189
190 /* Number of buffers / pkts */
Damjan Marion5e5adb32018-05-26 00:50:39 +0200191 n_left = frame->n_vectors;
Steven9cd2d7a2017-12-20 12:43:01 -0800192
Damjan Marion5e5adb32018-05-26 00:50:39 +0200193 vlib_get_buffers (vm, from, bufs, n_left);
Steven9cd2d7a2017-12-20 12:43:01 -0800194
Damjan Marion5e5adb32018-05-26 00:50:39 +0200195 b = bufs;
196 next = nexts;
197 sw_if_index = sw_if_indices;
198
199 while (n_left >= 4)
Steven9cd2d7a2017-12-20 12:43:01 -0800200 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200201 u32 x = 0;
202 /* Prefetch next iteration */
203 if (PREDICT_TRUE (n_left >= 16))
Steven9cd2d7a2017-12-20 12:43:01 -0800204 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200205 CLIB_PREFETCH (vlib_buffer_get_current (b[8]),
206 CLIB_CACHE_LINE_BYTES, LOAD);
207 CLIB_PREFETCH (vlib_buffer_get_current (b[9]),
208 CLIB_CACHE_LINE_BYTES, LOAD);
209 CLIB_PREFETCH (vlib_buffer_get_current (b[10]),
210 CLIB_CACHE_LINE_BYTES, LOAD);
211 CLIB_PREFETCH (vlib_buffer_get_current (b[11]),
212 CLIB_CACHE_LINE_BYTES, LOAD);
Steven9cd2d7a2017-12-20 12:43:01 -0800213
Damjan Marion5e5adb32018-05-26 00:50:39 +0200214 vlib_prefetch_buffer_header (b[12], LOAD);
215 vlib_prefetch_buffer_header (b[13], LOAD);
216 vlib_prefetch_buffer_header (b[14], LOAD);
217 vlib_prefetch_buffer_header (b[15], LOAD);
Steven9cd2d7a2017-12-20 12:43:01 -0800218 }
219
Damjan Marion5e5adb32018-05-26 00:50:39 +0200220 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
221 sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
222 sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
223 sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
224
225 x |= sw_if_index[0] ^ last_slave_sw_if_index;
226 x |= sw_if_index[1] ^ last_slave_sw_if_index;
227 x |= sw_if_index[2] ^ last_slave_sw_if_index;
228 x |= sw_if_index[3] ^ last_slave_sw_if_index;
229
230 if (PREDICT_TRUE (x == 0))
Steven9cd2d7a2017-12-20 12:43:01 -0800231 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200232 next[0] = next[1] = next[2] = next[3] = next_index;
233 if (next_index == BOND_INPUT_NEXT_DROP)
Steven9cd2d7a2017-12-20 12:43:01 -0800234 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200235 b[0]->error = error;
236 b[1]->error = error;
237 b[2]->error = error;
238 b[3]->error = error;
Steven9cd2d7a2017-12-20 12:43:01 -0800239 }
Damjan Marion5e5adb32018-05-26 00:50:39 +0200240 else
Steven70488ab2018-03-28 17:59:00 -0700241 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200242 cnt +=
243 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
244 cnt +=
245 bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
246 cnt +=
247 bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
248 cnt +=
249 bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
Steven70488ab2018-03-28 17:59:00 -0700250 }
Steven9cd2d7a2017-12-20 12:43:01 -0800251 }
Damjan Marion5e5adb32018-05-26 00:50:39 +0200252 else
253 {
254
255 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
256 cnt, &bond_sw_if_index, b[0], &next_index,
257 &error);
258 next[0] = next_index;
259 if (next_index == BOND_INPUT_NEXT_DROP)
260 b[0]->error = error;
261 else
262 cnt += bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
263
264 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
265 cnt, &bond_sw_if_index, b[1], &next_index,
266 &error);
267 next[1] = next_index;
268 if (next_index == BOND_INPUT_NEXT_DROP)
269 b[1]->error = error;
270 else
271 cnt += bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
272
273 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
274 cnt, &bond_sw_if_index, b[2], &next_index,
275 &error);
276 next[2] = next_index;
277 if (next_index == BOND_INPUT_NEXT_DROP)
278 b[2]->error = error;
279 else
280 cnt += bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
281
282 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
283 cnt, &bond_sw_if_index, b[3], &next_index,
284 &error);
285 next[3] = next_index;
286 if (next_index == BOND_INPUT_NEXT_DROP)
287 b[3]->error = error;
288 else
289 cnt += bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
290 }
291
292 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
293 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
294 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
295 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
296
297 /* next */
298 n_left -= 4;
299 b += 4;
300 sw_if_index += 4;
301 next += 4;
Steven9cd2d7a2017-12-20 12:43:01 -0800302 }
303
Damjan Marion5e5adb32018-05-26 00:50:39 +0200304 while (n_left)
305 {
306 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
307 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
308 cnt, &bond_sw_if_index, b[0], &next_index, &error);
309 next[0] = next_index;
310 if (next_index == BOND_INPUT_NEXT_DROP)
311 b[0]->error = error;
312 else
313 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
314
315 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
316
317 /* next */
318 n_left -= 1;
319 b += 1;
320 sw_if_index += 1;
321 next += 1;
322 }
323
324 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
325 {
326 n_left = frame->n_vectors; /* number of packets to process */
327 b = bufs;
328 sw_if_index = sw_if_indices;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200329 bond_packet_trace_t *t0;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200330
Damjan Marionf264f082018-05-30 00:03:34 +0200331 while (n_left)
Damjan Marion5e5adb32018-05-26 00:50:39 +0200332 {
333 if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
334 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200335 t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
336 t0->sw_if_index = sw_if_index[0];
337 clib_memcpy (&t0->ethernet, vlib_buffer_get_current (b[0]),
338 sizeof (ethernet_header_t));
339 t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
340 }
341 /* next */
342 n_left--;
343 b++;
344 sw_if_index++;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200345 }
346 }
347
348 /* increase rx counters */
349 vlib_increment_simple_counter
350 (vnet_main.interface_main.sw_if_counters +
351 VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, cnt);
352
353 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Steven9cd2d7a2017-12-20 12:43:01 -0800354 vlib_node_increment_counter (vm, bond_input_node.index,
355 BOND_INPUT_ERROR_NONE, frame->n_vectors);
356
Steven9cd2d7a2017-12-20 12:43:01 -0800357 return frame->n_vectors;
358}
359
360static clib_error_t *
361bond_input_init (vlib_main_t * vm)
362{
363 return 0;
364}
365
366/* *INDENT-OFF* */
367VLIB_REGISTER_NODE (bond_input_node) = {
Steven9cd2d7a2017-12-20 12:43:01 -0800368 .name = "bond-input",
369 .vector_size = sizeof (u32),
370 .format_buffer = format_ethernet_header_with_length,
371 .format_trace = format_bond_input_trace,
372 .type = VLIB_NODE_TYPE_INTERNAL,
373 .n_errors = BOND_INPUT_N_ERROR,
374 .error_strings = bond_input_error_strings,
Damjan Marion5e5adb32018-05-26 00:50:39 +0200375 .n_next_nodes = BOND_INPUT_N_NEXT,
Steven9cd2d7a2017-12-20 12:43:01 -0800376 .next_nodes =
377 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200378 [BOND_INPUT_NEXT_DROP] = "error-drop"
Steven9cd2d7a2017-12-20 12:43:01 -0800379 }
380};
381
382VLIB_INIT_FUNCTION (bond_input_init);
383
384VNET_FEATURE_INIT (bond_input, static) =
385{
386 .arc_name = "device-input",
387 .node_name = "bond-input",
388 .runs_before = VNET_FEATURES ("ethernet-input"),
389};
Steven9cd2d7a2017-12-20 12:43:01 -0800390/* *INDENT-ON* */
391
392static clib_error_t *
393bond_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
394{
395 bond_main_t *bm = &bond_main;
396 slave_if_t *sif;
397 vlib_main_t *vm = bm->vlib_main;
398
399 sif = bond_get_slave_by_sw_if_index (sw_if_index);
400 if (sif)
401 {
402 sif->port_enabled = flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
403 if (sif->port_enabled == 0)
404 {
405 if (sif->lacp_enabled == 0)
406 {
407 bond_disable_collecting_distributing (vm, sif);
408 }
409 }
410 else
411 {
412 if (sif->lacp_enabled == 0)
413 {
414 bond_enable_collecting_distributing (vm, sif);
415 }
416 }
417 }
418
419 return 0;
420}
421
422VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bond_sw_interface_up_down);
423
424static clib_error_t *
425bond_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;
Steven9cd2d7a2017-12-20 12:43:01 -0800431
Stevence2db6a2018-04-23 17:06:24 -0700432 sw = vnet_get_hw_sw_interface (vnm, hw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -0800433 sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
434 if (sif)
435 {
436 if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
437 {
438 if (sif->lacp_enabled == 0)
439 {
440 bond_disable_collecting_distributing (vm, sif);
441 }
442 }
443 else
444 {
445 if (sif->lacp_enabled == 0)
446 {
447 bond_enable_collecting_distributing (vm, sif);
448 }
449 }
450 }
451
452 return 0;
453}
454
455VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
Steven9cd2d7a2017-12-20 12:43:01 -0800456
457/*
458 * fd.io coding-style-patch-verification: ON
459 *
460 * Local Variables:
461 * eval: (c-set-style "gnu")
462 * End:
463 */