bond: send gratuitous arp when the active slave went down in active-backup mode
[vpp.git] / src / vnet / bonding / device.c
1 /*
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>
25 #include <vppinfra/lb_hash_hash.h>
26 #include <vnet/ip/ip.h>
27 #include <vnet/ethernet/arp_packet.h>
28
29 #define foreach_bond_tx_error     \
30   _(NONE, "no error")             \
31   _(IF_DOWN, "interface down")    \
32   _(NO_SLAVE, "no slave")
33
34 typedef 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
42 static char *bond_tx_error_strings[] = {
43 #define _(n,s) s,
44   foreach_bond_tx_error
45 #undef _
46 };
47
48 static u8 *
49 format_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
67 u8 *
68 format_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
79 static __clib_unused clib_error_t *
80 bond_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     }
105
106   return 0;
107 }
108
109 static __clib_unused clib_error_t *
110 bond_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
117 static clib_error_t *
118 bond_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
132 static_always_inline u32
133 bond_load_balance_broadcast (vlib_main_t * vm, vlib_node_runtime_t * node,
134                              bond_if_t * bif, vlib_buffer_t * b0,
135                              uword slave_count)
136 {
137   vnet_main_t *vnm = vnet_get_main ();
138   vlib_buffer_t *c0;
139   int port;
140   u32 *to_next = 0;
141   u32 sw_if_index;
142   vlib_frame_t *f;
143   u16 thread_index = vlib_get_thread_index ();
144
145   for (port = 1; port < slave_count; port++)
146     {
147       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];
152       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++;
160         }
161     }
162
163   return 0;
164 }
165
166 static_always_inline u32
167 bond_load_balance_l2 (vlib_main_t * vm, vlib_node_runtime_t * node,
168                       bond_if_t * bif, vlib_buffer_t * b0, uword slave_count)
169 {
170   ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
171   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);
176
177   c = lb_hash_hash_2_tuples (a, b);
178
179   if (BOND_MODULO_SHORTCUT (slave_count))
180     return (c & (slave_count - 1));
181   else
182     return c % slave_count;
183 }
184
185 static_always_inline u16 *
186 bond_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
208 static_always_inline u32
209 bond_load_balance_l23 (vlib_main_t * vm, vlib_node_runtime_t * node,
210                        bond_if_t * bif, vlib_buffer_t * b0, uword slave_count)
211 {
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;
216   u32 *mac1, *mac2, *mac3;
217
218   ethertype_p = bond_locate_ethertype (eth);
219   ethertype = clib_mem_unaligned (ethertype_p, u16);
220
221   if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
222       (ethertype != htons (ETHERNET_TYPE_IP6)))
223     return (bond_load_balance_l2 (vm, node, bif, b0, slave_count));
224
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     {
230       u32 a, c;
231
232       mac1 = (u32 *) & eth->dst_address[0];
233       mac2 = (u32 *) & eth->dst_address[4];
234       mac3 = (u32 *) & eth->src_address[2];
235
236       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;
245     }
246   else if (ip_version == 0x6)
247     {
248       u64 a;
249       u32 c;
250       ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
251
252       mac1 = (u32 *) & eth->dst_address[0];
253       mac2 = (u32 *) & eth->dst_address[4];
254       mac3 = (u32 *) & eth->src_address[2];
255
256       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;
271     }
272   return (bond_load_balance_l2 (vm, node, bif, b0, slave_count));
273 }
274
275 static_always_inline u32
276 bond_load_balance_l34 (vlib_main_t * vm, vlib_node_runtime_t * node,
277                        bond_if_t * bif, vlib_buffer_t * b0, uword slave_count)
278 {
279   ethernet_header_t *eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
280   u8 ip_version;
281   uword is_tcp_udp;
282   ip4_header_t *ip4;
283   u16 ethertype, *ethertype_p;
284
285   ethertype_p = bond_locate_ethertype (eth);
286   ethertype = clib_mem_unaligned (ethertype_p, u16);
287
288   if ((ethertype != htons (ETHERNET_TYPE_IP4)) &&
289       (ethertype != htons (ETHERNET_TYPE_IP6)))
290     return (bond_load_balance_l2 (vm, node, bif, b0, slave_count));
291
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     {
297       u32 a, c, t1, t2;
298       tcp_header_t *tcp = (void *) (ip4 + 1);
299
300       is_tcp_udp = (ip4->protocol == IP_PROTOCOL_TCP) ||
301         (ip4->protocol == IP_PROTOCOL_UDP);
302       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;
312     }
313   else if (ip_version == 0x6)
314     {
315       u64 a;
316       u32 c, t1, t2;
317       ip6_header_t *ip6 = (ip6_header_t *) (eth + 1);
318       tcp_header_t *tcp = (void *) (ip6 + 1);
319
320       is_tcp_udp = 0;
321       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         }
338       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;
354     }
355
356   return (bond_load_balance_l2 (vm, node, bif, b0, slave_count));
357 }
358
359 static_always_inline u32
360 bond_load_balance_round_robin (vlib_main_t * vm,
361                                vlib_node_runtime_t * node,
362                                bond_if_t * bif, vlib_buffer_t * b0,
363                                uword slave_count)
364 {
365   bif->lb_rr_last_index++;
366   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;
370
371   return bif->lb_rr_last_index;
372 }
373
374 static_always_inline u32
375 bond_load_balance_active_backup (vlib_main_t * vm,
376                                  vlib_node_runtime_t * node,
377                                  bond_if_t * bif, vlib_buffer_t * b0,
378                                  uword slave_count)
379 {
380   /* First interface is the active, the rest is backup */
381   return 0;
382 }
383
384 static 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
390 static uword
391 bond_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;
402   u32 port;
403   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 ();
408   u32 *to_next;
409   u32 sif_if_index, sif_if_index1, sif_if_index2, sif_if_index3;
410   vlib_frame_t *f;
411   uword slave_count;
412
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
425   clib_spinlock_lock_if_init (&bif->lockp);
426   slave_count = vec_len (bif->active_slaves);
427   if (PREDICT_FALSE (slave_count == 0))
428     {
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);
443       clib_spinlock_unlock_if_init (&bif->lockp);
444       return frame->n_vectors;
445     }
446
447   vec_validate_aligned (bif->per_thread_info[thread_index].frame, slave_count,
448                         CLIB_CACHE_LINE_BYTES);
449
450   /* Number of buffers / pkts */
451   n_left_from = frame->n_vectors;
452
453   while (n_left_from > 0)
454     {
455       while (n_left_from >= 4)
456         {
457           u32 next0 = 0, next1 = 0, next2 = 0, next3 = 0;
458           u32 port0 = 0, port1 = 0, port2 = 0, port3 = 0;
459
460           // Prefetch next iteration
461           if (n_left_from >= 8)
462             {
463               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
470               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);
474
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
501           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             }
520
521           sif_if_index = *vec_elt_at_index (bif->active_slaves, port0);
522           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
531           if (PREDICT_FALSE ((bif->per_thread_info[thread_index].frame[port0]
532                               == 0)))
533             bif->per_thread_info[thread_index].frame[port0] =
534               vnet_get_frame_to_sw_interface (vnm, sif_if_index);
535
536           if (PREDICT_FALSE ((bif->per_thread_info[thread_index].frame[port1]
537                               == 0)))
538             bif->per_thread_info[thread_index].frame[port1] =
539               vnet_get_frame_to_sw_interface (vnm, sif_if_index1);
540
541           if (PREDICT_FALSE ((bif->per_thread_info[thread_index].frame[port2]
542                               == 0)))
543             bif->per_thread_info[thread_index].frame[port2] =
544               vnet_get_frame_to_sw_interface (vnm, sif_if_index2);
545
546           if (PREDICT_FALSE ((bif->per_thread_info[thread_index].frame[port3]
547                               == 0)))
548             bif->per_thread_info[thread_index].frame[port3] =
549               vnet_get_frame_to_sw_interface (vnm, sif_if_index3);
550
551           f = bif->per_thread_info[thread_index].frame[port0];
552           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 */ );
578               vlib_set_trace_count (vm, node, --n_trace);
579               t0 = vlib_add_trace (vm, node, b0, sizeof (*t0));
580               eth = (ethernet_header_t *) vlib_buffer_get_current (b0);
581               t0->ethernet = *eth;
582               t0->sw_if_index = sw_if_index;
583               t0->bond_sw_if_index = vnet_buffer (b0)->sw_if_index[VLIB_TX];
584
585               if (PREDICT_TRUE (n_trace > 0))
586                 {
587                   vlib_trace_buffer (vm, node, next1, b1,
588                                      0 /* follow_chain */ );
589                   vlib_set_trace_count (vm, node, --n_trace);
590                   t0 = vlib_add_trace (vm, node, b1, sizeof (*t0));
591                   eth = (ethernet_header_t *) vlib_buffer_get_current (b1);
592                   t0->ethernet = *eth;
593                   t0->sw_if_index = sw_if_index1;
594                   t0->bond_sw_if_index =
595                     vnet_buffer (b1)->sw_if_index[VLIB_TX];
596
597                   if (PREDICT_TRUE (n_trace > 0))
598                     {
599                       vlib_trace_buffer (vm, node, next2, b2,
600                                          0 /* follow_chain */ );
601                       vlib_set_trace_count (vm, node, --n_trace);
602                       t0 = vlib_add_trace (vm, node, b2, sizeof (*t0));
603                       eth =
604                         (ethernet_header_t *) vlib_buffer_get_current (b2);
605                       t0->ethernet = *eth;
606                       t0->sw_if_index = sw_if_index2;
607                       t0->bond_sw_if_index =
608                         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                         }
624                     }
625                 }
626             }
627           from += 4;
628           n_left_from -= 4;
629         }
630
631       while (n_left_from > 0)
632         {
633           u32 next0 = 0;
634           u32 port0 = 0;
635
636           // Prefetch next iteration
637           if (n_left_from > 1)
638             {
639               vlib_buffer_t *p2;
640
641               p2 = vlib_get_buffer (vm, from[1]);
642               vlib_prefetch_buffer_header (p2, LOAD);
643               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
653           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);
659           vnet_buffer (b0)->sw_if_index[VLIB_TX] = sif_if_index;
660           if (PREDICT_FALSE
661               ((bif->per_thread_info[thread_index].frame[port0] == 0)))
662             bif->per_thread_info[thread_index].frame[port0] =
663               vnet_get_frame_to_sw_interface (vnm, sif_if_index);
664           f = bif->per_thread_info[thread_index].frame[port0];
665           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         }
684     }
685
686   for (port = 0; port < slave_count; port++)
687     {
688       f = bif->per_thread_info[thread_index].frame[port];
689       if (f == 0)
690         continue;
691
692       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;
695     }
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
701   clib_spinlock_unlock_if_init (&bif->lockp);
702   return frame->n_vectors;
703 }
704
705 static walk_rc_t
706 bond_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
717 static uword
718 bond_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* */
744 VLIB_REGISTER_NODE (bond_process_node) = {
745   .function = bond_process,
746   .type = VLIB_NODE_TYPE_PROCESS,
747   .name = "bond-process",
748 };
749 /* *INDENT-ON* */
750
751 /* *INDENT-OFF* */
752 VNET_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,
758   .set_l2_mode_function = bond_set_l2_mode_function,
759   .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
764 VLIB_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  */