blob: 636146f84492b46d6bba71747ebfca9eb221571a [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
Benoît Ganne47727c02019-02-12 13:35:08 +010024#ifndef CLIB_MARCH_VARIANT
Steven9cd2d7a2017-12-20 12:43:01 -080025bond_main_t bond_main;
Benoît Ganne47727c02019-02-12 13:35:08 +010026#endif /* CLIB_MARCH_VARIANT */
Steven9cd2d7a2017-12-20 12:43:01 -080027
28#define foreach_bond_input_error \
29 _(NONE, "no error") \
30 _(IF_DOWN, "interface down") \
Damjan Marion5e5adb32018-05-26 00:50:39 +020031 _(PASS_THRU, "pass through (CDP, LLDP, slow protocols)")
Steven9cd2d7a2017-12-20 12:43:01 -080032
33typedef enum
34{
35#define _(f,s) BOND_INPUT_ERROR_##f,
36 foreach_bond_input_error
37#undef _
38 BOND_INPUT_N_ERROR,
39} bond_input_error_t;
40
41static char *bond_input_error_strings[] = {
42#define _(n,s) s,
43 foreach_bond_input_error
44#undef _
45};
46
47static u8 *
48format_bond_input_trace (u8 * s, va_list * args)
49{
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 *);
Steven9cd2d7a2017-12-20 12:43:01 -080053
Steven70488ab2018-03-28 17:59:00 -070054 s = format (s, "src %U, dst %U, %U -> %U",
Steven9cd2d7a2017-12-20 12:43:01 -080055 format_ethernet_address, t->ethernet.src_address,
56 format_ethernet_address, t->ethernet.dst_address,
Steven70488ab2018-03-28 17:59:00 -070057 format_vnet_sw_if_index_name, vnet_get_main (),
58 t->sw_if_index,
59 format_vnet_sw_if_index_name, vnet_get_main (),
60 t->bond_sw_if_index);
Steven9cd2d7a2017-12-20 12:43:01 -080061
62 return s;
63}
Damjan Marion5e5adb32018-05-26 00:50:39 +020064
65typedef enum
66{
67 BOND_INPUT_NEXT_DROP,
68 BOND_INPUT_N_NEXT,
Steven9f781d82018-06-05 11:09:32 -070069} bond_output_next_t;
Steven9cd2d7a2017-12-20 12:43:01 -080070
71static_always_inline u8
72packet_is_cdp (ethernet_header_t * eth)
73{
74 llc_header_t *llc;
75 snap_header_t *snap;
76
77 llc = (llc_header_t *) (eth + 1);
78 snap = (snap_header_t *) (llc + 1);
79
80 return ((eth->type == htons (ETHERNET_TYPE_CDP)) ||
81 ((llc->src_sap == 0xAA) && (llc->control == 0x03) &&
82 (snap->protocol == htons (0x2000)) &&
83 (snap->oui[0] == 0) && (snap->oui[1] == 0) &&
84 (snap->oui[2] == 0x0C)));
85}
86
Damjan Marion5e5adb32018-05-26 00:50:39 +020087static inline u32
88bond_sw_if_idx_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node,
89 vlib_buffer_t * b, u32 bond_sw_if_index)
Steven9cd2d7a2017-12-20 12:43:01 -080090{
Steven9cd2d7a2017-12-20 12:43:01 -080091 u16 *ethertype_p, ethertype;
92 ethernet_vlan_header_t *vlan;
Damjan Marion5e5adb32018-05-26 00:50:39 +020093 ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b);
Steven9cd2d7a2017-12-20 12:43:01 -080094
Damjan Marion5e5adb32018-05-26 00:50:39 +020095 ethertype = clib_mem_unaligned (&eth->type, u16);
96 if (!ethernet_frame_is_tagged (ntohs (ethertype)))
Steven9cd2d7a2017-12-20 12:43:01 -080097 {
Damjan Marion5e5adb32018-05-26 00:50:39 +020098 // Let some layer2 packets pass through.
99 if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
100 && !packet_is_cdp (eth)
101 && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
Steven9cd2d7a2017-12-20 12:43:01 -0800102 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200103 /* Change the physical interface to bond interface */
104 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
105 return 1;
Steven9cd2d7a2017-12-20 12:43:01 -0800106 }
107 }
108 else
109 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200110 vlan = (void *) (eth + 1);
111 ethertype_p = &vlan->type;
112 ethertype = clib_mem_unaligned (ethertype_p, u16);
113 if (ethertype == ntohs (ETHERNET_TYPE_VLAN))
114 {
115 vlan++;
116 ethertype_p = &vlan->type;
117 }
118 ethertype = clib_mem_unaligned (ethertype_p, u16);
119 if (PREDICT_TRUE ((ethertype != htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
120 && (ethertype != htons (ETHERNET_TYPE_CDP))
121 && (ethertype != htons (ETHERNET_TYPE_802_1_LLDP))))
122 {
123 /* Change the physical interface to bond interface */
124 vnet_buffer (b)->sw_if_index[VLIB_RX] = bond_sw_if_index;
125 return 1;
126 }
Steven9cd2d7a2017-12-20 12:43:01 -0800127 }
128
Damjan Marion5e5adb32018-05-26 00:50:39 +0200129 vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_PASS_THRU, 1);
130 return 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800131}
132
Damjan Marion5e5adb32018-05-26 00:50:39 +0200133static inline void
134bond_update_next (vlib_main_t * vm, vlib_node_runtime_t * node,
135 u32 * last_slave_sw_if_index, u32 slave_sw_if_index,
136 u32 packet_count,
137 u32 * bond_sw_if_index, vlib_buffer_t * b,
138 u32 * next_index, vlib_error_t * error)
Steven9cd2d7a2017-12-20 12:43:01 -0800139{
Damjan Marion067cd622018-07-11 12:47:43 +0200140 u16 thread_index = vm->thread_index;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200141 slave_if_t *sif;
142 bond_if_t *bif;
143
144 if (PREDICT_TRUE (*last_slave_sw_if_index == slave_sw_if_index))
145 return;
146
147 if (packet_count)
148 vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
149 VNET_INTERFACE_COUNTER_RX, thread_index,
150 *last_slave_sw_if_index, packet_count);
151
152 *last_slave_sw_if_index = slave_sw_if_index;
153 *next_index = BOND_INPUT_NEXT_DROP;
154
155 sif = bond_get_slave_by_sw_if_index (slave_sw_if_index);
156 ASSERT (sif);
157
158 bif = bond_get_master_by_dev_instance (sif->bif_dev_instance);
159
160 ASSERT (bif);
161 ASSERT (vec_len (bif->slaves));
162
163 if (PREDICT_TRUE (bif->admin_up == 0))
164 {
165 *bond_sw_if_index = slave_sw_if_index;
166 *error = node->errors[BOND_INPUT_ERROR_IF_DOWN];
167 }
168
169 *bond_sw_if_index = bif->sw_if_index;
170 *error = 0;
Damjan Marion7d98a122018-07-19 20:42:08 +0200171 vnet_feature_next (next_index, b);
Damjan Marion5e5adb32018-05-26 00:50:39 +0200172}
173
Damjan Marion812b32d2018-05-28 21:26:47 +0200174VLIB_NODE_FN (bond_input_node) (vlib_main_t * vm,
175 vlib_node_runtime_t * node,
176 vlib_frame_t * frame)
Damjan Marion5e5adb32018-05-26 00:50:39 +0200177{
Damjan Marion067cd622018-07-11 12:47:43 +0200178 u16 thread_index = vm->thread_index;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200179 u32 *from, n_left;
180 vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
181 u32 sw_if_indices[VLIB_FRAME_SIZE], *sw_if_index;
182 u16 nexts[VLIB_FRAME_SIZE], *next;
183 u32 last_slave_sw_if_index = ~0;
184 u32 bond_sw_if_index = 0;
185 vlib_error_t error = 0;
186 u32 next_index = 0;
187 u32 cnt = 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800188
189 /* Vector of buffer / pkt indices we're supposed to process */
190 from = vlib_frame_vector_args (frame);
191
192 /* Number of buffers / pkts */
Damjan Marion5e5adb32018-05-26 00:50:39 +0200193 n_left = frame->n_vectors;
Steven9cd2d7a2017-12-20 12:43:01 -0800194
Damjan Marion5e5adb32018-05-26 00:50:39 +0200195 vlib_get_buffers (vm, from, bufs, n_left);
Steven9cd2d7a2017-12-20 12:43:01 -0800196
Damjan Marion5e5adb32018-05-26 00:50:39 +0200197 b = bufs;
198 next = nexts;
199 sw_if_index = sw_if_indices;
200
201 while (n_left >= 4)
Steven9cd2d7a2017-12-20 12:43:01 -0800202 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200203 u32 x = 0;
204 /* Prefetch next iteration */
205 if (PREDICT_TRUE (n_left >= 16))
Steven9cd2d7a2017-12-20 12:43:01 -0800206 {
Damjan Mariond30bf012018-11-18 23:48:43 +0100207 vlib_prefetch_buffer_data (b[8], LOAD);
208 vlib_prefetch_buffer_data (b[9], LOAD);
209 vlib_prefetch_buffer_data (b[10], LOAD);
210 vlib_prefetch_buffer_data (b[11], LOAD);
Steven9cd2d7a2017-12-20 12:43:01 -0800211
Damjan Marion5e5adb32018-05-26 00:50:39 +0200212 vlib_prefetch_buffer_header (b[12], LOAD);
213 vlib_prefetch_buffer_header (b[13], LOAD);
214 vlib_prefetch_buffer_header (b[14], LOAD);
215 vlib_prefetch_buffer_header (b[15], LOAD);
Steven9cd2d7a2017-12-20 12:43:01 -0800216 }
217
Damjan Marion5e5adb32018-05-26 00:50:39 +0200218 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
219 sw_if_index[1] = vnet_buffer (b[1])->sw_if_index[VLIB_RX];
220 sw_if_index[2] = vnet_buffer (b[2])->sw_if_index[VLIB_RX];
221 sw_if_index[3] = vnet_buffer (b[3])->sw_if_index[VLIB_RX];
222
223 x |= sw_if_index[0] ^ last_slave_sw_if_index;
224 x |= sw_if_index[1] ^ last_slave_sw_if_index;
225 x |= sw_if_index[2] ^ last_slave_sw_if_index;
226 x |= sw_if_index[3] ^ last_slave_sw_if_index;
227
228 if (PREDICT_TRUE (x == 0))
Steven9cd2d7a2017-12-20 12:43:01 -0800229 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200230 next[0] = next[1] = next[2] = next[3] = next_index;
231 if (next_index == BOND_INPUT_NEXT_DROP)
Steven9cd2d7a2017-12-20 12:43:01 -0800232 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200233 b[0]->error = error;
234 b[1]->error = error;
235 b[2]->error = error;
236 b[3]->error = error;
Steven9cd2d7a2017-12-20 12:43:01 -0800237 }
Damjan Marion5e5adb32018-05-26 00:50:39 +0200238 else
Steven70488ab2018-03-28 17:59:00 -0700239 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200240 cnt +=
241 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
242 cnt +=
243 bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
244 cnt +=
245 bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
246 cnt +=
247 bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
Steven70488ab2018-03-28 17:59:00 -0700248 }
Steven9cd2d7a2017-12-20 12:43:01 -0800249 }
Damjan Marion5e5adb32018-05-26 00:50:39 +0200250 else
251 {
252
253 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
254 cnt, &bond_sw_if_index, b[0], &next_index,
255 &error);
256 next[0] = next_index;
257 if (next_index == BOND_INPUT_NEXT_DROP)
258 b[0]->error = error;
259 else
260 cnt += bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
261
262 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[1],
263 cnt, &bond_sw_if_index, b[1], &next_index,
264 &error);
265 next[1] = next_index;
266 if (next_index == BOND_INPUT_NEXT_DROP)
267 b[1]->error = error;
268 else
269 cnt += bond_sw_if_idx_rewrite (vm, node, b[1], bond_sw_if_index);
270
271 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[2],
272 cnt, &bond_sw_if_index, b[2], &next_index,
273 &error);
274 next[2] = next_index;
275 if (next_index == BOND_INPUT_NEXT_DROP)
276 b[2]->error = error;
277 else
278 cnt += bond_sw_if_idx_rewrite (vm, node, b[2], bond_sw_if_index);
279
280 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[3],
281 cnt, &bond_sw_if_index, b[3], &next_index,
282 &error);
283 next[3] = next_index;
284 if (next_index == BOND_INPUT_NEXT_DROP)
285 b[3]->error = error;
286 else
287 cnt += bond_sw_if_idx_rewrite (vm, node, b[3], bond_sw_if_index);
288 }
289
290 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
291 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
292 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
293 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
294
295 /* next */
296 n_left -= 4;
297 b += 4;
298 sw_if_index += 4;
299 next += 4;
Steven9cd2d7a2017-12-20 12:43:01 -0800300 }
301
Damjan Marion5e5adb32018-05-26 00:50:39 +0200302 while (n_left)
303 {
304 sw_if_index[0] = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
305 bond_update_next (vm, node, &last_slave_sw_if_index, sw_if_index[0],
306 cnt, &bond_sw_if_index, b[0], &next_index, &error);
307 next[0] = next_index;
308 if (next_index == BOND_INPUT_NEXT_DROP)
309 b[0]->error = error;
310 else
311 bond_sw_if_idx_rewrite (vm, node, b[0], bond_sw_if_index);
312
313 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
314
315 /* next */
316 n_left -= 1;
317 b += 1;
318 sw_if_index += 1;
319 next += 1;
320 }
321
322 if (PREDICT_FALSE ((node->flags & VLIB_NODE_FLAG_TRACE)))
323 {
324 n_left = frame->n_vectors; /* number of packets to process */
325 b = bufs;
326 sw_if_index = sw_if_indices;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200327 bond_packet_trace_t *t0;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200328
Damjan Marionf264f082018-05-30 00:03:34 +0200329 while (n_left)
Damjan Marion5e5adb32018-05-26 00:50:39 +0200330 {
331 if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED))
332 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200333 t0 = vlib_add_trace (vm, node, b[0], sizeof (*t0));
334 t0->sw_if_index = sw_if_index[0];
Dave Barach178cf492018-11-13 16:34:13 -0500335 clib_memcpy_fast (&t0->ethernet, vlib_buffer_get_current (b[0]),
336 sizeof (ethernet_header_t));
Damjan Marion5e5adb32018-05-26 00:50:39 +0200337 t0->bond_sw_if_index = vnet_buffer (b[0])->sw_if_index[VLIB_RX];
338 }
339 /* next */
340 n_left--;
341 b++;
342 sw_if_index++;
Damjan Marion5e5adb32018-05-26 00:50:39 +0200343 }
344 }
345
346 /* increase rx counters */
347 vlib_increment_simple_counter
348 (vnet_main.interface_main.sw_if_counters +
349 VNET_INTERFACE_COUNTER_RX, thread_index, bond_sw_if_index, cnt);
350
351 vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
Steven9cd2d7a2017-12-20 12:43:01 -0800352 vlib_node_increment_counter (vm, bond_input_node.index,
353 BOND_INPUT_ERROR_NONE, frame->n_vectors);
354
Steven9cd2d7a2017-12-20 12:43:01 -0800355 return frame->n_vectors;
356}
357
358static clib_error_t *
359bond_input_init (vlib_main_t * vm)
360{
361 return 0;
362}
363
364/* *INDENT-OFF* */
365VLIB_REGISTER_NODE (bond_input_node) = {
Steven9cd2d7a2017-12-20 12:43:01 -0800366 .name = "bond-input",
367 .vector_size = sizeof (u32),
368 .format_buffer = format_ethernet_header_with_length,
369 .format_trace = format_bond_input_trace,
370 .type = VLIB_NODE_TYPE_INTERNAL,
371 .n_errors = BOND_INPUT_N_ERROR,
372 .error_strings = bond_input_error_strings,
Damjan Marion5e5adb32018-05-26 00:50:39 +0200373 .n_next_nodes = BOND_INPUT_N_NEXT,
Steven9cd2d7a2017-12-20 12:43:01 -0800374 .next_nodes =
375 {
Damjan Marion5e5adb32018-05-26 00:50:39 +0200376 [BOND_INPUT_NEXT_DROP] = "error-drop"
Steven9cd2d7a2017-12-20 12:43:01 -0800377 }
378};
379
380VLIB_INIT_FUNCTION (bond_input_init);
381
382VNET_FEATURE_INIT (bond_input, static) =
383{
384 .arc_name = "device-input",
385 .node_name = "bond-input",
386 .runs_before = VNET_FEATURES ("ethernet-input"),
387};
Steven9cd2d7a2017-12-20 12:43:01 -0800388/* *INDENT-ON* */
389
390static clib_error_t *
391bond_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
392{
393 bond_main_t *bm = &bond_main;
394 slave_if_t *sif;
395 vlib_main_t *vm = bm->vlib_main;
396
397 sif = bond_get_slave_by_sw_if_index (sw_if_index);
398 if (sif)
399 {
400 sif->port_enabled = flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
Stevene43278f2019-01-17 15:11:29 -0800401 if (sif->lacp_enabled)
402 return 0;
403
Steven9cd2d7a2017-12-20 12:43:01 -0800404 if (sif->port_enabled == 0)
405 {
Stevene43278f2019-01-17 15:11:29 -0800406 bond_disable_collecting_distributing (vm, sif);
Steven9cd2d7a2017-12-20 12:43:01 -0800407 }
408 else
409 {
Stevene43278f2019-01-17 15:11:29 -0800410 vnet_main_t *vnm = vnet_get_main ();
411 vnet_hw_interface_t *hw =
412 vnet_get_sup_hw_interface (vnm, sw_if_index);
413
414 if (hw->flags & VNET_HW_INTERFACE_FLAG_LINK_UP)
415 bond_enable_collecting_distributing (vm, sif);
Steven9cd2d7a2017-12-20 12:43:01 -0800416 }
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 {
Stevene43278f2019-01-17 15:11:29 -0800436 if (sif->lacp_enabled)
437 return 0;
438
Steven9cd2d7a2017-12-20 12:43:01 -0800439 if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
440 {
Stevene43278f2019-01-17 15:11:29 -0800441 bond_disable_collecting_distributing (vm, sif);
Steven9cd2d7a2017-12-20 12:43:01 -0800442 }
Stevene43278f2019-01-17 15:11:29 -0800443 else if (sif->port_enabled)
Steven9cd2d7a2017-12-20 12:43:01 -0800444 {
Stevene43278f2019-01-17 15:11:29 -0800445 bond_enable_collecting_distributing (vm, sif);
Steven9cd2d7a2017-12-20 12:43:01 -0800446 }
447 }
448
449 return 0;
450}
451
452VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
Steven9cd2d7a2017-12-20 12:43:01 -0800453
454/*
455 * fd.io coding-style-patch-verification: ON
456 *
457 * Local Variables:
458 * eval: (c-set-style "gnu")
459 * End:
460 */