blob: 1ade1c290a133e8b352dd6bcd0610626b8a643f0 [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/ethernet/ethernet.h>
21#include <vnet/ip/ip4_packet.h>
22#include <vnet/ip/ip6_packet.h>
23#include <vnet/ip/ip6_hop_by_hop_packet.h>
24#include <vnet/bonding/node.h>
Steven0d883012018-05-11 11:06:23 -070025#include <vppinfra/lb_hash_hash.h>
Steven9f781d82018-06-05 11:09:32 -070026#include <vnet/ip/ip.h>
27#include <vnet/ethernet/arp_packet.h>
Steven9cd2d7a2017-12-20 12:43:01 -080028
29#define foreach_bond_tx_error \
30 _(NONE, "no error") \
31 _(IF_DOWN, "interface down") \
32 _(NO_SLAVE, "no slave")
33
34typedef enum
35{
36#define _(f,s) BOND_TX_ERROR_##f,
37 foreach_bond_tx_error
38#undef _
39 BOND_TX_N_ERROR,
40} bond_tx_error_t;
41
42static char *bond_tx_error_strings[] = {
43#define _(n,s) s,
44 foreach_bond_tx_error
45#undef _
46};
47
48static u8 *
49format_bond_tx_trace (u8 * s, va_list * args)
50{
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 *);
54 vnet_hw_interface_t *hw, *hw1;
55 vnet_main_t *vnm = vnet_get_main ();
56
57 hw = vnet_get_sup_hw_interface (vnm, t->sw_if_index);
58 hw1 = vnet_get_sup_hw_interface (vnm, t->bond_sw_if_index);
59 s = format (s, "src %U, dst %U, %s -> %s",
60 format_ethernet_address, t->ethernet.src_address,
61 format_ethernet_address, t->ethernet.dst_address,
62 hw->name, hw1->name);
63
64 return s;
65}
66
67u8 *
68format_bond_interface_name (u8 * s, va_list * args)
69{
70 u32 dev_instance = va_arg (*args, u32);
71 bond_main_t *bm = &bond_main;
72 bond_if_t *bif = pool_elt_at_index (bm->interfaces, dev_instance);
73
74 s = format (s, "BondEthernet%lu", bif->dev_instance);
75
76 return s;
77}
78
79static __clib_unused clib_error_t *
Steven4f8863b2018-04-12 19:36:19 -070080bond_set_l2_mode_function (vnet_main_t * vnm,
81 struct vnet_hw_interface_t *bif_hw,
82 i32 l2_if_adjust)
83{
84 bond_if_t *bif;
85 u32 *sw_if_index;
86 struct vnet_hw_interface_t *sif_hw;
87
88 bif = bond_get_master_by_sw_if_index (bif_hw->sw_if_index);
89 if (!bif)
90 return 0;
91
92 if ((bif_hw->l2_if_count == 1) && (l2_if_adjust == 1))
93 {
94 /* Just added first L2 interface on this port */
95 vec_foreach (sw_if_index, bif->slaves)
96 {
97 sif_hw = vnet_get_sup_hw_interface (vnm, *sw_if_index);
98 ethernet_set_flags (vnm, sif_hw->hw_if_index,
99 ETHERNET_INTERFACE_FLAG_ACCEPT_ALL);
100
101 /* ensure all packets go to ethernet-input */
102 ethernet_set_rx_redirect (vnm, sif_hw, 1);
103 }
104 }
Steven4f8863b2018-04-12 19:36:19 -0700105
106 return 0;
107}
108
109static __clib_unused clib_error_t *
Steven9cd2d7a2017-12-20 12:43:01 -0800110bond_subif_add_del_function (vnet_main_t * vnm, u32 hw_if_index,
111 struct vnet_sw_interface_t *st, int is_add)
112{
113 /* Nothing for now */
114 return 0;
115}
116
117static clib_error_t *
118bond_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
119{
120 vnet_hw_interface_t *hif = vnet_get_hw_interface (vnm, hw_if_index);
121 uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
122 bond_main_t *bm = &bond_main;
123 bond_if_t *bif = pool_elt_at_index (bm->interfaces, hif->dev_instance);
124
125 bif->admin_up = is_up;
126 if (is_up && vec_len (bif->active_slaves))
127 vnet_hw_interface_set_flags (vnm, bif->hw_if_index,
128 VNET_HW_INTERFACE_FLAG_LINK_UP);
129 return 0;
130}
131
Steven0d883012018-05-11 11:06:23 -0700132static_always_inline u32
Steven9cd2d7a2017-12-20 12:43:01 -0800133bond_load_balance_broadcast (vlib_main_t * vm, vlib_node_runtime_t * node,
Steven18c0f222018-03-26 21:52:11 -0700134 bond_if_t * bif, vlib_buffer_t * b0,
135 uword slave_count)
Steven9cd2d7a2017-12-20 12:43:01 -0800136{
137 vnet_main_t *vnm = vnet_get_main ();
138 vlib_buffer_t *c0;
Steven22b5be02018-04-11 15:32:15 -0700139 int port;
Steven9cd2d7a2017-12-20 12:43:01 -0800140 u32 *to_next = 0;
141 u32 sw_if_index;
142 vlib_frame_t *f;
Steven22b5be02018-04-11 15:32:15 -0700143 u16 thread_index = vlib_get_thread_index ();
Steven9cd2d7a2017-12-20 12:43:01 -0800144
Steven22b5be02018-04-11 15:32:15 -0700145 for (port = 1; port < slave_count; port++)
Steven9cd2d7a2017-12-20 12:43:01 -0800146 {
Steven22b5be02018-04-11 15:32:15 -0700147 sw_if_index = *vec_elt_at_index (bif->active_slaves, port);
148 if (bif->per_thread_info[thread_index].frame[port] == 0)
149 bif->per_thread_info[thread_index].frame[port] =
150 vnet_get_frame_to_sw_interface (vnm, sw_if_index);
151 f = bif->per_thread_info[thread_index].frame[port];
Steven9cd2d7a2017-12-20 12:43:01 -0800152 to_next = vlib_frame_vector_args (f);
153 to_next += f->n_vectors;
154 c0 = vlib_buffer_copy (vm, b0);
155 if (PREDICT_TRUE (c0 != 0))
156 {
157 vnet_buffer (c0)->sw_if_index[VLIB_TX] = sw_if_index;
158 to_next[0] = vlib_get_buffer_index (vm, c0);
159 f->n_vectors++;
Steven9cd2d7a2017-12-20 12:43:01 -0800160 }
161 }
162
163 return 0;
164}
165
Steven0d883012018-05-11 11:06:23 -0700166static_always_inline u32
Steven9cd2d7a2017-12-20 12:43:01 -0800167bond_load_balance_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
Steven18c0f222018-03-26 21:52:11 -0700168 bond_if_t * bif, vlib_buffer_t * b0, uword slave_count)
Steven9cd2d7a2017-12-20 12:43:01 -0800169{
170 ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
Steven0d883012018-05-11 11:06:23 -0700171 u32 c;
172 u64 *dst = (u64 *) & eth->dst_address[0];
173 u64 a = clib_mem_unaligned (dst, u64);
174 u32 *src = (u32 *) & eth->src_address[2];
175 u32 b = clib_mem_unaligned (src, u32);
Steven9cd2d7a2017-12-20 12:43:01 -0800176
Steven0d883012018-05-11 11:06:23 -0700177 c = lb_hash_hash_2_tuples (a, b);
Steven9cd2d7a2017-12-20 12:43:01 -0800178
Steven0d883012018-05-11 11:06:23 -0700179 if (BOND_MODULO_SHORTCUT (slave_count))
180 return (c & (slave_count - 1));
181 else
182 return c % slave_count;
Steven9cd2d7a2017-12-20 12:43:01 -0800183}
184
Steven0d883012018-05-11 11:06:23 -0700185static_always_inline u16 *
Steven9cd2d7a2017-12-20 12:43:01 -0800186bond_locate_ethertype (ethernet_header_t * eth)
187{
188 u16 *ethertype_p;
189 ethernet_vlan_header_t *vlan;
190
191 if (!ethernet_frame_is_tagged (clib_net_to_host_u16 (eth->type)))
192 {
193 ethertype_p = &eth->type;
194 }
195 else
196 {
197 vlan = (void *) (eth + 1);
198 ethertype_p = &vlan->type;
199 if (*ethertype_p == ntohs (ETHERNET_TYPE_VLAN))
200 {
201 vlan++;
202 ethertype_p = &vlan->type;
203 }
204 }
205 return ethertype_p;
206}
207
Steven0d883012018-05-11 11:06:23 -0700208static_always_inline u32
Steven9cd2d7a2017-12-20 12:43:01 -0800209bond_load_balance_l23 (vlib_main_t * vm, vlib_node_runtime_t * node,
Steven18c0f222018-03-26 21:52:11 -0700210 bond_if_t * bif, vlib_buffer_t * b0, uword slave_count)
Steven9cd2d7a2017-12-20 12:43:01 -0800211{
212 ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
213 u8 ip_version;
214 ip4_header_t *ip4;
215 u16 ethertype, *ethertype_p;
Steven0d883012018-05-11 11:06:23 -0700216 u32 *mac1, *mac2, *mac3;
Steven9cd2d7a2017-12-20 12:43:01 -0800217
218 ethertype_p = bond_locate_ethertype (eth);
Steven0d883012018-05-11 11:06:23 -0700219 ethertype = clib_mem_unaligned (ethertype_p, u16);
Steven9cd2d7a2017-12-20 12:43:01 -0800220
221 if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
222 (ethertype != htons (ETHERNET_TYPE_IP6)))
Steven18c0f222018-03-26 21:52:11 -0700223 return (bond_load_balance_l2 (vm, node, bif, b0, slave_count));
Steven9cd2d7a2017-12-20 12:43:01 -0800224
225 ip4 = (ip4_header_t *) (ethertype_p + 1);
226 ip_version = (ip4->ip_version_and_header_length >> 4);
227
228 if (ip_version == 0x4)
229 {
Steven0d883012018-05-11 11:06:23 -0700230 u32 a, c;
Steven9cd2d7a2017-12-20 12:43:01 -0800231
Steven0d883012018-05-11 11:06:23 -0700232 mac1 = (u32 *) & eth->dst_address[0];
233 mac2 = (u32 *) & eth->dst_address[4];
234 mac3 = (u32 *) & eth->src_address[2];
Steven9cd2d7a2017-12-20 12:43:01 -0800235
Steven0d883012018-05-11 11:06:23 -0700236 a = clib_mem_unaligned (mac1, u32) ^ clib_mem_unaligned (mac2, u32) ^
237 clib_mem_unaligned (mac3, u32);
238 c =
239 lb_hash_hash_2_tuples (clib_mem_unaligned (&ip4->address_pair, u64),
240 a);
241 if (BOND_MODULO_SHORTCUT (slave_count))
242 return (c & (slave_count - 1));
243 else
244 return c % slave_count;
Steven9cd2d7a2017-12-20 12:43:01 -0800245 }
246 else if (ip_version == 0x6)
247 {
Steven0d883012018-05-11 11:06:23 -0700248 u64 a;
249 u32 c;
Steven9cd2d7a2017-12-20 12:43:01 -0800250 ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
251
Steven0d883012018-05-11 11:06:23 -0700252 mac1 = (u32 *) & eth->dst_address[0];
253 mac2 = (u32 *) & eth->dst_address[4];
254 mac3 = (u32 *) & eth->src_address[2];
Steven9cd2d7a2017-12-20 12:43:01 -0800255
Steven0d883012018-05-11 11:06:23 -0700256 a = clib_mem_unaligned (mac1, u32) ^ clib_mem_unaligned (mac2, u32) ^
257 clib_mem_unaligned (mac3, u32);
258 c =
259 lb_hash_hash (clib_mem_unaligned
260 (&ip6->src_address.as_uword[0], uword),
261 clib_mem_unaligned (&ip6->src_address.as_uword[1],
262 uword),
263 clib_mem_unaligned (&ip6->dst_address.as_uword[0],
264 uword),
265 clib_mem_unaligned (&ip6->dst_address.as_uword[1],
266 uword), a);
267 if (BOND_MODULO_SHORTCUT (slave_count))
268 return (c & (slave_count - 1));
269 else
270 return c % slave_count;
Steven9cd2d7a2017-12-20 12:43:01 -0800271 }
Steven18c0f222018-03-26 21:52:11 -0700272 return (bond_load_balance_l2 (vm, node, bif, b0, slave_count));
Steven9cd2d7a2017-12-20 12:43:01 -0800273}
274
Steven0d883012018-05-11 11:06:23 -0700275static_always_inline u32
Steven9cd2d7a2017-12-20 12:43:01 -0800276bond_load_balance_l34 (vlib_main_t * vm, vlib_node_runtime_t * node,
Steven18c0f222018-03-26 21:52:11 -0700277 bond_if_t * bif, vlib_buffer_t * b0, uword slave_count)
Steven9cd2d7a2017-12-20 12:43:01 -0800278{
279 ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
280 u8 ip_version;
Steven0d883012018-05-11 11:06:23 -0700281 uword is_tcp_udp;
Steven9cd2d7a2017-12-20 12:43:01 -0800282 ip4_header_t *ip4;
283 u16 ethertype, *ethertype_p;
284
285 ethertype_p = bond_locate_ethertype (eth);
Steven0d883012018-05-11 11:06:23 -0700286 ethertype = clib_mem_unaligned (ethertype_p, u16);
Steven9cd2d7a2017-12-20 12:43:01 -0800287
288 if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
289 (ethertype != htons (ETHERNET_TYPE_IP6)))
Steven18c0f222018-03-26 21:52:11 -0700290 return (bond_load_balance_l2 (vm, node, bif, b0, slave_count));
Steven9cd2d7a2017-12-20 12:43:01 -0800291
292 ip4 = (ip4_header_t *) (ethertype_p + 1);
293 ip_version = (ip4->ip_version_and_header_length >> 4);
294
295 if (ip_version == 0x4)
296 {
Steven0d883012018-05-11 11:06:23 -0700297 u32 a, c, t1, t2;
Steven9cd2d7a2017-12-20 12:43:01 -0800298 tcp_header_t *tcp = (void *) (ip4 + 1);
Steven0d883012018-05-11 11:06:23 -0700299
Steven9cd2d7a2017-12-20 12:43:01 -0800300 is_tcp_udp = (ip4->protocol == IP_PROTOCOL_TCP) ||
301 (ip4->protocol == IP_PROTOCOL_UDP);
Steven0d883012018-05-11 11:06:23 -0700302 t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
303 t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
304 a = t1 ^ t2;
305 c =
306 lb_hash_hash_2_tuples (clib_mem_unaligned (&ip4->address_pair, u64),
307 a);
308 if (BOND_MODULO_SHORTCUT (slave_count))
309 return (c & (slave_count - 1));
310 else
311 return c % slave_count;
Steven9cd2d7a2017-12-20 12:43:01 -0800312 }
313 else if (ip_version == 0x6)
314 {
Steven0d883012018-05-11 11:06:23 -0700315 u64 a;
316 u32 c, t1, t2;
Steven9cd2d7a2017-12-20 12:43:01 -0800317 ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
318 tcp_header_t *tcp = (void *) (ip6 + 1);
319
Steven0d883012018-05-11 11:06:23 -0700320 is_tcp_udp = 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800321 if (PREDICT_TRUE ((ip6->protocol == IP_PROTOCOL_TCP) ||
322 (ip6->protocol == IP_PROTOCOL_UDP)))
323 {
324 is_tcp_udp = 1;
325 tcp = (void *) (ip6 + 1);
326 }
327 else if (ip6->protocol == IP_PROTOCOL_IP6_HOP_BY_HOP_OPTIONS)
328 {
329 ip6_hop_by_hop_header_t *hbh =
330 (ip6_hop_by_hop_header_t *) (ip6 + 1);
331 if ((hbh->protocol == IP_PROTOCOL_TCP)
332 || (hbh->protocol == IP_PROTOCOL_UDP))
333 {
334 is_tcp_udp = 1;
335 tcp = (tcp_header_t *) ((u8 *) hbh + ((hbh->length + 1) << 3));
336 }
337 }
Steven0d883012018-05-11 11:06:23 -0700338 t1 = is_tcp_udp ? clib_mem_unaligned (&tcp->src, u16) : 0;
339 t2 = is_tcp_udp ? clib_mem_unaligned (&tcp->dst, u16) : 0;
340 a = t1 ^ t2;
341 c =
342 lb_hash_hash (clib_mem_unaligned
343 (&ip6->src_address.as_uword[0], uword),
344 clib_mem_unaligned (&ip6->src_address.as_uword[1],
345 uword),
346 clib_mem_unaligned (&ip6->dst_address.as_uword[0],
347 uword),
348 clib_mem_unaligned (&ip6->dst_address.as_uword[1],
349 uword), a);
350 if (BOND_MODULO_SHORTCUT (slave_count))
351 return (c & (slave_count - 1));
352 else
353 return c % slave_count;
Steven9cd2d7a2017-12-20 12:43:01 -0800354 }
355
Steven18c0f222018-03-26 21:52:11 -0700356 return (bond_load_balance_l2 (vm, node, bif, b0, slave_count));
Steven9cd2d7a2017-12-20 12:43:01 -0800357}
358
Steven0d883012018-05-11 11:06:23 -0700359static_always_inline u32
Steven9cd2d7a2017-12-20 12:43:01 -0800360bond_load_balance_round_robin (vlib_main_t * vm,
361 vlib_node_runtime_t * node,
Steven18c0f222018-03-26 21:52:11 -0700362 bond_if_t * bif, vlib_buffer_t * b0,
363 uword slave_count)
Steven9cd2d7a2017-12-20 12:43:01 -0800364{
365 bif->lb_rr_last_index++;
Steven0d883012018-05-11 11:06:23 -0700366 if (BOND_MODULO_SHORTCUT (slave_count))
367 bif->lb_rr_last_index &= slave_count - 1;
368 else
369 bif->lb_rr_last_index %= slave_count;
Steven9cd2d7a2017-12-20 12:43:01 -0800370
371 return bif->lb_rr_last_index;
372}
373
Steven0d883012018-05-11 11:06:23 -0700374static_always_inline u32
Steven9cd2d7a2017-12-20 12:43:01 -0800375bond_load_balance_active_backup (vlib_main_t * vm,
376 vlib_node_runtime_t * node,
Steven18c0f222018-03-26 21:52:11 -0700377 bond_if_t * bif, vlib_buffer_t * b0,
378 uword slave_count)
Steven9cd2d7a2017-12-20 12:43:01 -0800379{
380 /* First interface is the active, the rest is backup */
381 return 0;
382}
383
384static bond_load_balance_func_t bond_load_balance_table[] = {
385#define _(v,f,s, p) { bond_load_balance_##p },
386 foreach_bond_lb_algo
387#undef _
388};
389
390static uword
391bond_tx_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
392 vlib_frame_t * frame)
393{
394 vnet_interface_output_runtime_t *rund = (void *) node->runtime_data;
395 bond_main_t *bm = &bond_main;
396 bond_if_t *bif = pool_elt_at_index (bm->interfaces, rund->dev_instance);
397 u32 bi0, bi1, bi2, bi3;
398 vlib_buffer_t *b0, *b1, *b2, *b3;
399 u32 *from = vlib_frame_vector_args (frame);
400 u32 n_left_from;
401 ethernet_header_t *eth;
Steven0d883012018-05-11 11:06:23 -0700402 u32 port;
Steven9cd2d7a2017-12-20 12:43:01 -0800403 u32 sw_if_index, sw_if_index1, sw_if_index2, sw_if_index3;
404 bond_packet_trace_t *t0;
405 uword n_trace = vlib_get_trace_count (vm, node);
406 u16 thread_index = vlib_get_thread_index ();
407 vnet_main_t *vnm = vnet_get_main ();
Stevena005e7f2018-03-22 17:46:58 -0700408 u32 *to_next;
Steven9cd2d7a2017-12-20 12:43:01 -0800409 u32 sif_if_index, sif_if_index1, sif_if_index2, sif_if_index3;
Stevena005e7f2018-03-22 17:46:58 -0700410 vlib_frame_t *f;
Steven18c0f222018-03-26 21:52:11 -0700411 uword slave_count;
Steven9cd2d7a2017-12-20 12:43:01 -0800412
413 if (PREDICT_FALSE (bif->admin_up == 0))
414 {
415 vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
416 vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
417 VNET_INTERFACE_COUNTER_DROP,
418 thread_index, bif->sw_if_index,
419 frame->n_vectors);
420 vlib_error_count (vm, node->node_index, BOND_TX_ERROR_IF_DOWN,
421 frame->n_vectors);
422 return frame->n_vectors;
423 }
424
Stevena005e7f2018-03-22 17:46:58 -0700425 clib_spinlock_lock_if_init (&bif->lockp);
Steven18c0f222018-03-26 21:52:11 -0700426 slave_count = vec_len (bif->active_slaves);
427 if (PREDICT_FALSE (slave_count == 0))
Steven9cd2d7a2017-12-20 12:43:01 -0800428 {
429 bi0 = from[0];
430 b0 = vlib_get_buffer (vm, bi0);
431 vlib_increment_combined_counter
432 (vnet_main.interface_main.combined_sw_if_counters
433 + VNET_INTERFACE_COUNTER_TX, thread_index, bif->sw_if_index,
434 frame->n_vectors, b0->current_length);
435
436 vlib_buffer_free (vm, vlib_frame_args (frame), frame->n_vectors);
437 vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters +
438 VNET_INTERFACE_COUNTER_DROP,
439 thread_index, bif->sw_if_index,
440 frame->n_vectors);
441 vlib_error_count (vm, node->node_index, BOND_TX_ERROR_NO_SLAVE,
442 frame->n_vectors);
Stevena005e7f2018-03-22 17:46:58 -0700443 clib_spinlock_unlock_if_init (&bif->lockp);
Steven9cd2d7a2017-12-20 12:43:01 -0800444 return frame->n_vectors;
445 }
446
Steven18c0f222018-03-26 21:52:11 -0700447 vec_validate_aligned (bif->per_thread_info[thread_index].frame, slave_count,
448 CLIB_CACHE_LINE_BYTES);
Stevena005e7f2018-03-22 17:46:58 -0700449
Steven9cd2d7a2017-12-20 12:43:01 -0800450 /* Number of buffers / pkts */
451 n_left_from = frame->n_vectors;
452
Stevena005e7f2018-03-22 17:46:58 -0700453 while (n_left_from > 0)
Steven9cd2d7a2017-12-20 12:43:01 -0800454 {
Stevena005e7f2018-03-22 17:46:58 -0700455 while (n_left_from >= 4)
Steven9cd2d7a2017-12-20 12:43:01 -0800456 {
Steven0d883012018-05-11 11:06:23 -0700457 u32 next0 = 0, next1 = 0, next2 = 0, next3 = 0;
458 u32 port0 = 0, port1 = 0, port2 = 0, port3 = 0;
459
Stevena005e7f2018-03-22 17:46:58 -0700460 // Prefetch next iteration
461 if (n_left_from >= 8)
Steven9cd2d7a2017-12-20 12:43:01 -0800462 {
Stevena005e7f2018-03-22 17:46:58 -0700463 vlib_buffer_t *p4, *p5, *p6, *p7;
464
465 p4 = vlib_get_buffer (vm, from[4]);
466 p5 = vlib_get_buffer (vm, from[5]);
467 p6 = vlib_get_buffer (vm, from[6]);
468 p7 = vlib_get_buffer (vm, from[7]);
469
Steven0d883012018-05-11 11:06:23 -0700470 vlib_prefetch_buffer_header (p4, LOAD);
471 vlib_prefetch_buffer_header (p5, LOAD);
472 vlib_prefetch_buffer_header (p6, LOAD);
473 vlib_prefetch_buffer_header (p7, LOAD);
Stevena005e7f2018-03-22 17:46:58 -0700474
475 CLIB_PREFETCH (p4->data, CLIB_CACHE_LINE_BYTES, LOAD);
476 CLIB_PREFETCH (p5->data, CLIB_CACHE_LINE_BYTES, LOAD);
477 CLIB_PREFETCH (p6->data, CLIB_CACHE_LINE_BYTES, LOAD);
478 CLIB_PREFETCH (p7->data, CLIB_CACHE_LINE_BYTES, LOAD);
479 }
480
481 bi0 = from[0];
482 bi1 = from[1];
483 bi2 = from[2];
484 bi3 = from[3];
485
486 b0 = vlib_get_buffer (vm, bi0);
487 b1 = vlib_get_buffer (vm, bi1);
488 b2 = vlib_get_buffer (vm, bi2);
489 b3 = vlib_get_buffer (vm, bi3);
490
491 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
492 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b1);
493 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b2);
494 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b3);
495
496 sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
497 sw_if_index1 = vnet_buffer (b1)->sw_if_index[VLIB_TX];
498 sw_if_index2 = vnet_buffer (b2)->sw_if_index[VLIB_TX];
499 sw_if_index3 = vnet_buffer (b3)->sw_if_index[VLIB_TX];
500
Steven0d883012018-05-11 11:06:23 -0700501 if (PREDICT_TRUE (slave_count != 1))
502 {
503 port0 =
504 (bond_load_balance_table[bif->lb]).load_balance (vm, node,
505 bif, b0,
506 slave_count);
507 port1 =
508 (bond_load_balance_table[bif->lb]).load_balance (vm, node,
509 bif, b1,
510 slave_count);
511 port2 =
512 (bond_load_balance_table[bif->lb]).load_balance (vm, node,
513 bif, b2,
514 slave_count);
515 port3 =
516 (bond_load_balance_table[bif->lb]).load_balance (vm, node,
517 bif, b3,
518 slave_count);
519 }
Stevena005e7f2018-03-22 17:46:58 -0700520
Steven0d883012018-05-11 11:06:23 -0700521 sif_if_index = *vec_elt_at_index (bif->active_slaves, port0);
Stevena005e7f2018-03-22 17:46:58 -0700522 sif_if_index1 = *vec_elt_at_index (bif->active_slaves, port1);
523 sif_if_index2 = *vec_elt_at_index (bif->active_slaves, port2);
524 sif_if_index3 = *vec_elt_at_index (bif->active_slaves, port3);
525
526 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sif_if_index;
527 vnet_buffer (b1)->sw_if_index[VLIB_TX] = sif_if_index1;
528 vnet_buffer (b2)->sw_if_index[VLIB_TX] = sif_if_index2;
529 vnet_buffer (b3)->sw_if_index[VLIB_TX] = sif_if_index3;
530
Steven0d883012018-05-11 11:06:23 -0700531 if (PREDICT_FALSE ((bif->per_thread_info[thread_index].frame[port0]
532 == 0)))
533 bif->per_thread_info[thread_index].frame[port0] =
Stevena005e7f2018-03-22 17:46:58 -0700534 vnet_get_frame_to_sw_interface (vnm, sif_if_index);
535
Steven0d883012018-05-11 11:06:23 -0700536 if (PREDICT_FALSE ((bif->per_thread_info[thread_index].frame[port1]
537 == 0)))
Stevena005e7f2018-03-22 17:46:58 -0700538 bif->per_thread_info[thread_index].frame[port1] =
539 vnet_get_frame_to_sw_interface (vnm, sif_if_index1);
540
Steven0d883012018-05-11 11:06:23 -0700541 if (PREDICT_FALSE ((bif->per_thread_info[thread_index].frame[port2]
542 == 0)))
Stevena005e7f2018-03-22 17:46:58 -0700543 bif->per_thread_info[thread_index].frame[port2] =
544 vnet_get_frame_to_sw_interface (vnm, sif_if_index2);
545
Steven0d883012018-05-11 11:06:23 -0700546 if (PREDICT_FALSE ((bif->per_thread_info[thread_index].frame[port3]
547 == 0)))
Stevena005e7f2018-03-22 17:46:58 -0700548 bif->per_thread_info[thread_index].frame[port3] =
549 vnet_get_frame_to_sw_interface (vnm, sif_if_index3);
550
Steven0d883012018-05-11 11:06:23 -0700551 f = bif->per_thread_info[thread_index].frame[port0];
Stevena005e7f2018-03-22 17:46:58 -0700552 to_next = vlib_frame_vector_args (f);
553 to_next += f->n_vectors;
554 to_next[0] = vlib_get_buffer_index (vm, b0);
555 f->n_vectors++;
556
557 f = bif->per_thread_info[thread_index].frame[port1];
558 to_next = vlib_frame_vector_args (f);
559 to_next += f->n_vectors;
560 to_next[0] = vlib_get_buffer_index (vm, b1);
561 f->n_vectors++;
562
563 f = bif->per_thread_info[thread_index].frame[port2];
564 to_next = vlib_frame_vector_args (f);
565 to_next += f->n_vectors;
566 to_next[0] = vlib_get_buffer_index (vm, b2);
567 f->n_vectors++;
568
569 f = bif->per_thread_info[thread_index].frame[port3];
570 to_next = vlib_frame_vector_args (f);
571 to_next += f->n_vectors;
572 to_next[0] = vlib_get_buffer_index (vm, b3);
573 f->n_vectors++;
574
575 if (PREDICT_FALSE (n_trace > 0))
576 {
577 vlib_trace_buffer (vm, node, next0, b0, 0 /* follow_chain */ );
Steven9cd2d7a2017-12-20 12:43:01 -0800578 vlib_set_trace_count (vm, node, --n_trace);
Stevena005e7f2018-03-22 17:46:58 -0700579 t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
580 eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
Steven9cd2d7a2017-12-20 12:43:01 -0800581 t0->ethernet = *eth;
Stevena005e7f2018-03-22 17:46:58 -0700582 t0->sw_if_index = sw_if_index;
583 t0->bond_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
Steven9cd2d7a2017-12-20 12:43:01 -0800584
585 if (PREDICT_TRUE (n_trace > 0))
586 {
Stevena005e7f2018-03-22 17:46:58 -0700587 vlib_trace_buffer (vm, node, next1, b1,
Steven9cd2d7a2017-12-20 12:43:01 -0800588 0 /* follow_chain */ );
589 vlib_set_trace_count (vm, node, --n_trace);
Stevena005e7f2018-03-22 17:46:58 -0700590 t0 = vlib_add_trace (vm, node, b1, sizeof (*t0));
591 eth = (ethernet_header_t *) vlib_buffer_get_current (b1);
Steven9cd2d7a2017-12-20 12:43:01 -0800592 t0->ethernet = *eth;
Stevena005e7f2018-03-22 17:46:58 -0700593 t0->sw_if_index = sw_if_index1;
Steven9cd2d7a2017-12-20 12:43:01 -0800594 t0->bond_sw_if_index =
Stevena005e7f2018-03-22 17:46:58 -0700595 vnet_buffer (b1)->sw_if_index[VLIB_TX];
Steven9cd2d7a2017-12-20 12:43:01 -0800596
597 if (PREDICT_TRUE (n_trace > 0))
598 {
Stevena005e7f2018-03-22 17:46:58 -0700599 vlib_trace_buffer (vm, node, next2, b2,
Steven9cd2d7a2017-12-20 12:43:01 -0800600 0 /* follow_chain */ );
601 vlib_set_trace_count (vm, node, --n_trace);
Stevena005e7f2018-03-22 17:46:58 -0700602 t0 = vlib_add_trace (vm, node, b2, sizeof (*t0));
Steven9cd2d7a2017-12-20 12:43:01 -0800603 eth =
Stevena005e7f2018-03-22 17:46:58 -0700604 (ethernet_header_t *) vlib_buffer_get_current (b2);
Steven9cd2d7a2017-12-20 12:43:01 -0800605 t0->ethernet = *eth;
Stevena005e7f2018-03-22 17:46:58 -0700606 t0->sw_if_index = sw_if_index2;
Steven9cd2d7a2017-12-20 12:43:01 -0800607 t0->bond_sw_if_index =
Stevena005e7f2018-03-22 17:46:58 -0700608 vnet_buffer (b2)->sw_if_index[VLIB_TX];
609
610 if (PREDICT_TRUE (n_trace > 0))
611 {
612 vlib_trace_buffer (vm, node, next3, b3,
613 0 /* follow_chain */ );
614 vlib_set_trace_count (vm, node, --n_trace);
615 t0 = vlib_add_trace (vm, node, b3, sizeof (*t0));
616 eth =
617 (ethernet_header_t *)
618 vlib_buffer_get_current (b3);
619 t0->ethernet = *eth;
620 t0->sw_if_index = sw_if_index3;
621 t0->bond_sw_if_index =
622 vnet_buffer (b3)->sw_if_index[VLIB_TX];
623 }
Steven9cd2d7a2017-12-20 12:43:01 -0800624 }
625 }
626 }
Stevena005e7f2018-03-22 17:46:58 -0700627 from += 4;
628 n_left_from -= 4;
Steven9cd2d7a2017-12-20 12:43:01 -0800629 }
630
Stevena005e7f2018-03-22 17:46:58 -0700631 while (n_left_from > 0)
632 {
Steven0d883012018-05-11 11:06:23 -0700633 u32 next0 = 0;
634 u32 port0 = 0;
635
Stevena005e7f2018-03-22 17:46:58 -0700636 // Prefetch next iteration
637 if (n_left_from > 1)
638 {
639 vlib_buffer_t *p2;
640
641 p2 = vlib_get_buffer (vm, from[1]);
Steven0d883012018-05-11 11:06:23 -0700642 vlib_prefetch_buffer_header (p2, LOAD);
Stevena005e7f2018-03-22 17:46:58 -0700643 CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, LOAD);
644 }
645
646 bi0 = from[0];
647 b0 = vlib_get_buffer (vm, bi0);
648
649 VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b0);
650
651 sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
652
Steven0d883012018-05-11 11:06:23 -0700653 if (PREDICT_TRUE (slave_count != 1))
654 port0 =
655 (bond_load_balance_table[bif->lb]).load_balance (vm, node, bif,
656 b0,
657 slave_count);
658 sif_if_index = *vec_elt_at_index (bif->active_slaves, port0);
Stevena005e7f2018-03-22 17:46:58 -0700659 vnet_buffer (b0)->sw_if_index[VLIB_TX] = sif_if_index;
Steven0d883012018-05-11 11:06:23 -0700660 if (PREDICT_FALSE
661 ((bif->per_thread_info[thread_index].frame[port0] == 0)))
662 bif->per_thread_info[thread_index].frame[port0] =
Stevena005e7f2018-03-22 17:46:58 -0700663 vnet_get_frame_to_sw_interface (vnm, sif_if_index);
Steven0d883012018-05-11 11:06:23 -0700664 f = bif->per_thread_info[thread_index].frame[port0];
Stevena005e7f2018-03-22 17:46:58 -0700665 to_next = vlib_frame_vector_args (f);
666 to_next += f->n_vectors;
667 to_next[0] = vlib_get_buffer_index (vm, b0);
668 f->n_vectors++;
669
670 if (PREDICT_FALSE (n_trace > 0))
671 {
672 vlib_trace_buffer (vm, node, next0, b0, 0 /* follow_chain */ );
673 vlib_set_trace_count (vm, node, --n_trace);
674 t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
675 eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
676 t0->ethernet = *eth;
677 t0->sw_if_index = sw_if_index;
678 t0->bond_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
679 }
680
681 from += 1;
682 n_left_from -= 1;
683 }
Steven9cd2d7a2017-12-20 12:43:01 -0800684 }
685
Steven18c0f222018-03-26 21:52:11 -0700686 for (port = 0; port < slave_count; port++)
Steven9cd2d7a2017-12-20 12:43:01 -0800687 {
Stevena005e7f2018-03-22 17:46:58 -0700688 f = bif->per_thread_info[thread_index].frame[port];
689 if (f == 0)
690 continue;
Steven9cd2d7a2017-12-20 12:43:01 -0800691
Stevena005e7f2018-03-22 17:46:58 -0700692 sw_if_index = *vec_elt_at_index (bif->active_slaves, port);
693 vnet_put_frame_to_sw_interface (vnm, sw_if_index, f);
694 bif->per_thread_info[thread_index].frame[port] = 0;
Steven9cd2d7a2017-12-20 12:43:01 -0800695 }
696
697 vlib_increment_simple_counter (vnet_main.interface_main.sw_if_counters
698 + VNET_INTERFACE_COUNTER_TX, thread_index,
699 bif->sw_if_index, frame->n_vectors);
700
Stevena005e7f2018-03-22 17:46:58 -0700701 clib_spinlock_unlock_if_init (&bif->lockp);
Steven9cd2d7a2017-12-20 12:43:01 -0800702 return frame->n_vectors;
703}
704
Steven9f781d82018-06-05 11:09:32 -0700705static walk_rc_t
706bond_active_interface_switch_cb (vnet_main_t * vnm, u32 sw_if_index,
707 void *arg)
708{
709 bond_main_t *bm = &bond_main;
710
711 send_ip4_garp (bm->vlib_main, sw_if_index);
712 send_ip6_na (bm->vlib_main, sw_if_index);
713
714 return (WALK_CONTINUE);
715}
716
717static uword
718bond_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
719{
720 vnet_main_t *vnm = vnet_get_main ();
721 uword event_type, *event_data = 0;
722
723 while (1)
724 {
725 u32 i;
726 u32 hw_if_index;
727
728 vlib_process_wait_for_event (vm);
729 event_type = vlib_process_get_events (vm, &event_data);
730 ASSERT (event_type == BOND_SEND_GARP_NA);
731 for (i = 0; i < vec_len (event_data); i++)
732 {
733 hw_if_index = event_data[i];
734 /* walk hw interface to process all subinterfaces */
735 vnet_hw_interface_walk_sw (vnm, hw_if_index,
736 bond_active_interface_switch_cb, 0);
737 }
738 vec_reset_length (event_data);
739 }
740 return 0;
741}
742
743/* *INDENT-OFF* */
744VLIB_REGISTER_NODE (bond_process_node) = {
745 .function = bond_process,
746 .type = VLIB_NODE_TYPE_PROCESS,
747 .name = "bond-process",
748};
749/* *INDENT-ON* */
750
Steven9cd2d7a2017-12-20 12:43:01 -0800751/* *INDENT-OFF* */
752VNET_DEVICE_CLASS (bond_dev_class) = {
753 .name = "bond",
754 .tx_function = bond_tx_fn,
755 .tx_function_n_errors = BOND_TX_N_ERROR,
756 .tx_function_error_strings = bond_tx_error_strings,
757 .format_device_name = format_bond_interface_name,
Steven4f8863b2018-04-12 19:36:19 -0700758 .set_l2_mode_function = bond_set_l2_mode_function,
Steven9cd2d7a2017-12-20 12:43:01 -0800759 .admin_up_down_function = bond_interface_admin_up_down,
760 .subif_add_del_function = bond_subif_add_del_function,
761 .format_tx_trace = format_bond_tx_trace,
762};
763
764VLIB_DEVICE_TX_FUNCTION_MULTIARCH (bond_dev_class, bond_tx_fn)
765/* *INDENT-ON* */
766
767/*
768 * fd.io coding-style-patch-verification: ON
769 *
770 * Local Variables:
771 * eval: (c-set-style "gnu")
772 * End:
773 */