blob: b831d40540e1a4092659229509f92ded9d8328db [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") \
29 _(NO_SLAVE, "no slave") \
30 _(NO_BOND, "no bond interface")\
31 _(PASS_THRU, "pass through")
32
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}
64
65static_always_inline u8
66packet_is_cdp (ethernet_header_t * eth)
67{
68 llc_header_t *llc;
69 snap_header_t *snap;
70
71 llc = (llc_header_t *) (eth + 1);
72 snap = (snap_header_t *) (llc + 1);
73
74 return ((eth->type == htons (ETHERNET_TYPE_CDP)) ||
75 ((llc->src_sap == 0xAA) && (llc->control == 0x03) &&
76 (snap->protocol == htons (0x2000)) &&
77 (snap->oui[0] == 0) && (snap->oui[1] == 0) &&
78 (snap->oui[2] == 0x0C)));
79}
80
81static inline void
82bond_sw_if_index_rewrite (vlib_main_t * vm, vlib_node_runtime_t * node,
83 slave_if_t * sif, ethernet_header_t * eth,
84 vlib_buffer_t * b0)
85{
86 bond_if_t *bif;
87 u16 thread_index = vlib_get_thread_index ();
88 u16 *ethertype_p, ethertype;
89 ethernet_vlan_header_t *vlan;
90
91 if (PREDICT_TRUE (sif != 0))
92 {
93 bif = bond_get_master_by_sw_if_index (sif->group);
94 if (PREDICT_TRUE (bif != 0))
95 {
96 if (PREDICT_TRUE (vec_len (bif->slaves) >= 1))
97 {
98 if (PREDICT_TRUE (bif->admin_up == 1))
99 {
100 if (!ethernet_frame_is_tagged (ntohs (eth->type)))
101 {
102 // Let some layer2 packets pass through.
103 if (PREDICT_TRUE ((eth->type !=
104 htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
105 && !packet_is_cdp (eth)
106 && (eth->type !=
107 htons
108 (ETHERNET_TYPE_802_1_LLDP))))
109 {
110 // Change the physical interface to
111 // bond interface
112 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
113 bif->sw_if_index;
114
115 /* increase rx counters */
116 vlib_increment_simple_counter
117 (vnet_main.interface_main.sw_if_counters +
118 VNET_INTERFACE_COUNTER_RX, thread_index,
119 bif->sw_if_index, 1);
120 }
121 else
122 {
123 vlib_error_count (vm, node->node_index,
124 BOND_INPUT_ERROR_PASS_THRU, 1);
125 }
126 }
127 else
128 {
129 vlan = (void *) (eth + 1);
130 ethertype_p = &vlan->type;
131 if (*ethertype_p == ntohs (ETHERNET_TYPE_VLAN))
132 {
133 vlan++;
134 ethertype_p = &vlan->type;
135 }
136 ethertype = *ethertype_p;
137 if (PREDICT_TRUE ((ethertype !=
138 htons (ETHERNET_TYPE_SLOW_PROTOCOLS))
139 && (ethertype !=
140 htons (ETHERNET_TYPE_CDP))
141 && (ethertype !=
142 htons
143 (ETHERNET_TYPE_802_1_LLDP))))
144 {
145 // Change the physical interface to
146 // bond interface
147 vnet_buffer (b0)->sw_if_index[VLIB_RX] =
148 bif->sw_if_index;
149
150 /* increase rx counters */
151 vlib_increment_simple_counter
152 (vnet_main.interface_main.sw_if_counters +
153 VNET_INTERFACE_COUNTER_RX, thread_index,
154 bif->sw_if_index, 1);
155 }
156 else
157 {
158 vlib_error_count (vm, node->node_index,
159 BOND_INPUT_ERROR_PASS_THRU, 1);
160 }
161 }
162 }
163 else
164 {
165 vlib_error_count (vm, node->node_index,
166 BOND_INPUT_ERROR_IF_DOWN, 1);
167 }
168 }
169 else
170 {
171 vlib_error_count (vm, node->node_index,
172 BOND_INPUT_ERROR_NO_SLAVE, 1);
173 }
174 }
175 else
176 {
177 vlib_error_count (vm, node->node_index,
178 BOND_INPUT_ERROR_NO_BOND, 1);
179 }
180 }
181 else
182 {
183 vlib_error_count (vm, node->node_index, BOND_INPUT_ERROR_NO_SLAVE, 1);
184 }
185
186}
187
188static uword
189bond_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
190 vlib_frame_t * frame)
191{
192 u32 bi0, bi1, bi2, bi3;
193 vlib_buffer_t *b0, *b1, *b2, *b3;
194 u32 next_index;
195 u32 *from, *to_next, n_left_from, n_left_to_next;
196 ethernet_header_t *eth, *eth1, *eth2, *eth3;
197 u32 next0, next1, next2, next3;
198 bond_packet_trace_t *t0;
199 uword n_trace = vlib_get_trace_count (vm, node);
200 u32 sw_if_index, sw_if_index1, sw_if_index2, sw_if_index3;
201 slave_if_t *sif, *sif1, *sif2, *sif3;
202 u16 thread_index = vlib_get_thread_index ();
203
204 /* Vector of buffer / pkt indices we're supposed to process */
205 from = vlib_frame_vector_args (frame);
206
207 /* Number of buffers / pkts */
208 n_left_from = frame->n_vectors;
209
210 /* Speculatively send the first buffer to the last disposition we used */
211 next_index = node->cached_next_index;
212
213 while (n_left_from > 0)
214 {
215 /* set up to enqueue to our disposition with index = next_index */
216 vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
217
218 while (n_left_from >= 12 && n_left_to_next >= 4)
219 {
220 // Prefetch next iteration
221 {
222 vlib_buffer_t *b4, *b5, *b6, *b7;
223
224 b4 = vlib_get_buffer (vm, from[4]);
225 b5 = vlib_get_buffer (vm, from[5]);
226 b6 = vlib_get_buffer (vm, from[6]);
227 b7 = vlib_get_buffer (vm, from[7]);
228
229 vlib_prefetch_buffer_header (b4, STORE);
230 vlib_prefetch_buffer_header (b5, STORE);
231 vlib_prefetch_buffer_header (b6, STORE);
232 vlib_prefetch_buffer_header (b7, STORE);
233
234 CLIB_PREFETCH (b4->data, CLIB_CACHE_LINE_BYTES, LOAD);
235 CLIB_PREFETCH (b5->data, CLIB_CACHE_LINE_BYTES, LOAD);
236 CLIB_PREFETCH (b6->data, CLIB_CACHE_LINE_BYTES, LOAD);
237 CLIB_PREFETCH (b7->data, CLIB_CACHE_LINE_BYTES, LOAD);
238 }
239
240 next0 = 0;
241 next1 = 0;
242 next2 = 0;
243 next3 = 0;
244
245 bi0 = from[0];
246 bi1 = from[1];
247 bi2 = from[2];
248 bi3 = from[3];
249
250 to_next[0] = bi0;
251 to_next[1] = bi1;
252 to_next[2] = bi2;
253 to_next[3] = bi3;
254
255 from += 4;
256 to_next += 4;
257 n_left_from -= 4;
258 n_left_to_next -= 4;
259
260 b0 = vlib_get_buffer (vm, bi0);
261 b1 = vlib_get_buffer (vm, bi1);
262 b2 = vlib_get_buffer (vm, bi2);
263 b3 = vlib_get_buffer (vm, bi3);
264
265 vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0,
266 b0);
267 vnet_feature_next (vnet_buffer (b1)->sw_if_index[VLIB_RX], &next1,
268 b1);
269 vnet_feature_next (vnet_buffer (b2)->sw_if_index[VLIB_RX], &next2,
270 b2);
271 vnet_feature_next (vnet_buffer (b3)->sw_if_index[VLIB_RX], &next3,
272 b3);
273
274 eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
275 eth1 = (ethernet_header_t *) vlib_buffer_get_current (b1);
276 eth2 = (ethernet_header_t *) vlib_buffer_get_current (b2);
277 eth3 = (ethernet_header_t *) vlib_buffer_get_current (b3);
278
279 sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
280 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_RX];
281 sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_RX];
282 sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_RX];
283
284 // sw_if_index points to the physical interface
285 sif = bond_get_slave_by_sw_if_index (sw_if_index);
286 sif1 = bond_get_slave_by_sw_if_index (sw_if_index1);
287 sif2 = bond_get_slave_by_sw_if_index (sw_if_index2);
288 sif3 = bond_get_slave_by_sw_if_index (sw_if_index3);
289
290 bond_sw_if_index_rewrite (vm, node, sif, eth, b0);
291 bond_sw_if_index_rewrite (vm, node, sif1, eth1, b1);
292 bond_sw_if_index_rewrite (vm, node, sif2, eth2, b2);
293 bond_sw_if_index_rewrite (vm, node, sif3, eth3, b3);
294
295 if (PREDICT_FALSE (n_trace > 0))
296 {
297 vlib_trace_buffer (vm, node, next0, b0, 0 /* follow_chain */ );
298 vlib_set_trace_count (vm, node, --n_trace);
299 t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
300 t0->ethernet = *eth;
301 t0->sw_if_index = sw_if_index;
302 t0->bond_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
303
304 if (PREDICT_TRUE (n_trace > 0))
305 {
306 vlib_trace_buffer (vm, node, next1, b1,
307 0 /* follow_chain */ );
308 vlib_set_trace_count (vm, node, --n_trace);
309 t0 = vlib_add_trace (vm, node, b1, sizeof (*t0));
310 t0->ethernet = *eth1;
311 t0->sw_if_index = sw_if_index1;
312 t0->bond_sw_if_index =
313 vnet_buffer (b1)->sw_if_index[VLIB_RX];
314
315 if (PREDICT_TRUE (n_trace > 0))
316 {
317 vlib_trace_buffer (vm, node, next1, b2,
318 0 /* follow_chain */ );
319 vlib_set_trace_count (vm, node, --n_trace);
320 t0 = vlib_add_trace (vm, node, b2, sizeof (*t0));
321 t0->ethernet = *eth2;
322 t0->sw_if_index = sw_if_index2;
323 t0->bond_sw_if_index =
324 vnet_buffer (b2)->sw_if_index[VLIB_RX];
325
326 if (PREDICT_TRUE (n_trace > 0))
327 {
328 vlib_trace_buffer (vm, node, next1, b2,
329 0 /* follow_chain */ );
330 vlib_set_trace_count (vm, node, --n_trace);
331 t0 = vlib_add_trace (vm, node, b3, sizeof (*t0));
332 t0->ethernet = *eth3;
333 t0->sw_if_index = sw_if_index3;
334 t0->bond_sw_if_index =
335 vnet_buffer (b3)->sw_if_index[VLIB_RX];
336 }
337 }
338 }
339 }
340
341 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
342 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b1);
343 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b2);
344 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b3);
345
346 /* verify speculative enqueue, maybe switch current next frame */
347 vlib_validate_buffer_enqueue_x4 (vm, node, next_index,
348 to_next, n_left_to_next,
349 bi0, bi1, bi2, bi3, next0, next1,
350 next2, next3);
351 }
352
353 while (n_left_from > 0 && n_left_to_next > 0)
354 {
355 // Prefetch next iteration
356 if (n_left_from > 1)
357 {
358 vlib_buffer_t *p2;
359
360 p2 = vlib_get_buffer (vm, from[1]);
361 vlib_prefetch_buffer_header (p2, STORE);
362 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
363 }
364
365 next0 = 0;
366 bi0 = from[0];
367 to_next[0] = bi0;
368 from += 1;
369 to_next += 1;
370 n_left_from -= 1;
371 n_left_to_next -= 1;
372
373 b0 = vlib_get_buffer (vm, bi0);
374 vnet_feature_next (vnet_buffer (b0)->sw_if_index[VLIB_RX], &next0,
375 b0);
376
377 eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
378
379 sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
380 // sw_if_index points to the physical interface
381 sif = bond_get_slave_by_sw_if_index (sw_if_index);
382 bond_sw_if_index_rewrite (vm, node, sif, eth, b0);
383
Steven70488ab2018-03-28 17:59:00 -0700384 if (PREDICT_FALSE (n_trace > 0))
385 {
386 vlib_trace_buffer (vm, node, next0, b0, 0 /* follow_chain */ );
387 vlib_set_trace_count (vm, node, --n_trace);
388 t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
389 t0->ethernet = *eth;
390 t0->sw_if_index = sw_if_index;
391 t0->bond_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_RX];
392
393 }
394
Steven9cd2d7a2017-12-20 12:43:01 -0800395 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
396
397 /* verify speculative enqueue, maybe switch current next frame */
398 vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
399 to_next, n_left_to_next,
400 bi0, next0);
401 }
402 vlib_put_next_frame (vm, node, next_index, n_left_to_next);
403 }
404
405 vlib_node_increment_counter (vm, bond_input_node.index,
406 BOND_INPUT_ERROR_NONE, frame->n_vectors);
407
408 vnet_device_increment_rx_packets (thread_index, frame->n_vectors);
409
410 return frame->n_vectors;
411}
412
413static clib_error_t *
414bond_input_init (vlib_main_t * vm)
415{
416 return 0;
417}
418
419/* *INDENT-OFF* */
420VLIB_REGISTER_NODE (bond_input_node) = {
421 .function = bond_input_fn,
422 .name = "bond-input",
423 .vector_size = sizeof (u32),
424 .format_buffer = format_ethernet_header_with_length,
425 .format_trace = format_bond_input_trace,
426 .type = VLIB_NODE_TYPE_INTERNAL,
427 .n_errors = BOND_INPUT_N_ERROR,
428 .error_strings = bond_input_error_strings,
429 .n_next_nodes = 0,
430 .next_nodes =
431 {
432 [0] = "error-drop"
433 }
434};
435
436VLIB_INIT_FUNCTION (bond_input_init);
437
438VNET_FEATURE_INIT (bond_input, static) =
439{
440 .arc_name = "device-input",
441 .node_name = "bond-input",
442 .runs_before = VNET_FEATURES ("ethernet-input"),
443};
444VLIB_NODE_FUNCTION_MULTIARCH (bond_input_node, bond_input_fn)
445/* *INDENT-ON* */
446
447static clib_error_t *
448bond_sw_interface_up_down (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
449{
450 bond_main_t *bm = &bond_main;
451 slave_if_t *sif;
452 vlib_main_t *vm = bm->vlib_main;
453
454 sif = bond_get_slave_by_sw_if_index (sw_if_index);
455 if (sif)
456 {
457 sif->port_enabled = flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP;
458 if (sif->port_enabled == 0)
459 {
460 if (sif->lacp_enabled == 0)
461 {
462 bond_disable_collecting_distributing (vm, sif);
463 }
464 }
465 else
466 {
467 if (sif->lacp_enabled == 0)
468 {
469 bond_enable_collecting_distributing (vm, sif);
470 }
471 }
472 }
473
474 return 0;
475}
476
477VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (bond_sw_interface_up_down);
478
479static clib_error_t *
480bond_hw_interface_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
481{
482 bond_main_t *bm = &bond_main;
483 slave_if_t *sif;
484 vnet_sw_interface_t *sw;
485 vlib_main_t *vm = bm->vlib_main;
486 vnet_interface_main_t *im = &vnm->interface_main;
487
488 sw = pool_elt_at_index (im->sw_interfaces, hw_if_index);
489 sif = bond_get_slave_by_sw_if_index (sw->sw_if_index);
490 if (sif)
491 {
492 if (!(flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
493 {
494 if (sif->lacp_enabled == 0)
495 {
496 bond_disable_collecting_distributing (vm, sif);
497 }
498 }
499 else
500 {
501 if (sif->lacp_enabled == 0)
502 {
503 bond_enable_collecting_distributing (vm, sif);
504 }
505 }
506 }
507
508 return 0;
509}
510
511VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (bond_hw_interface_up_down);
512
513/*
514 * fd.io coding-style-patch-verification: ON
515 *
516 * Local Variables:
517 * eval: (c-set-style "gnu")
518 * End:
519 */