vnet: store hw interface speed in kbps instead of using flags
[vpp.git] / src / vnet / interface.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * interface.c: VNET interfaces/sub-interfaces
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vnet/vnet.h>
41 #include <vnet/plugin/plugin.h>
42 #include <vnet/fib/ip6_fib.h>
43 #include <vnet/adj/adj.h>
44 #include <vnet/adj/adj_mcast.h>
45 #include <vnet/l2/l2_input.h>
46
47 typedef enum vnet_interface_helper_flags_t_
48 {
49   VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE = (1 << 0),
50   VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE = (1 << 1),
51 } vnet_interface_helper_flags_t;
52
53 static clib_error_t *vnet_hw_interface_set_flags_helper (vnet_main_t * vnm,
54                                                          u32 hw_if_index,
55                                                          vnet_hw_interface_flags_t
56                                                          flags,
57                                                          vnet_interface_helper_flags_t
58                                                          helper_flags);
59
60 static clib_error_t *vnet_sw_interface_set_flags_helper (vnet_main_t * vnm,
61                                                          u32 sw_if_index,
62                                                          vnet_sw_interface_flags_t
63                                                          flags,
64                                                          vnet_interface_helper_flags_t
65                                                          helper_flags);
66
67 static clib_error_t *vnet_hw_interface_set_class_helper (vnet_main_t * vnm,
68                                                          u32 hw_if_index,
69                                                          u32 hw_class_index,
70                                                          u32 redistribute);
71
72 typedef struct
73 {
74   /* Either sw or hw interface index. */
75   u32 sw_hw_if_index;
76
77   /* Flags. */
78   u32 flags;
79 } vnet_sw_hw_interface_state_t;
80
81 static void
82 serialize_vec_vnet_sw_hw_interface_state (serialize_main_t * m, va_list * va)
83 {
84   vnet_sw_hw_interface_state_t *s =
85     va_arg (*va, vnet_sw_hw_interface_state_t *);
86   u32 n = va_arg (*va, u32);
87   u32 i;
88   for (i = 0; i < n; i++)
89     {
90       serialize_integer (m, s[i].sw_hw_if_index,
91                          sizeof (s[i].sw_hw_if_index));
92       serialize_integer (m, s[i].flags, sizeof (s[i].flags));
93     }
94 }
95
96 static void
97 unserialize_vec_vnet_sw_hw_interface_state (serialize_main_t * m,
98                                             va_list * va)
99 {
100   vnet_sw_hw_interface_state_t *s =
101     va_arg (*va, vnet_sw_hw_interface_state_t *);
102   u32 n = va_arg (*va, u32);
103   u32 i;
104   for (i = 0; i < n; i++)
105     {
106       unserialize_integer (m, &s[i].sw_hw_if_index,
107                            sizeof (s[i].sw_hw_if_index));
108       unserialize_integer (m, &s[i].flags, sizeof (s[i].flags));
109     }
110 }
111
112 static vnet_sw_interface_flags_t
113 vnet_hw_interface_flags_to_sw (vnet_hw_interface_flags_t hwf)
114 {
115   vnet_sw_interface_flags_t swf = VNET_SW_INTERFACE_FLAG_NONE;
116
117   if (hwf & VNET_HW_INTERFACE_FLAG_LINK_UP)
118     swf |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
119
120   return (swf);
121 }
122
123 void
124 serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
125 {
126   vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
127   vnet_sw_hw_interface_state_t *sts = 0, *st;
128   vnet_sw_interface_t *sif;
129   vnet_hw_interface_t *hif;
130   vnet_interface_main_t *im = &vnm->interface_main;
131
132   /* Serialize hardware interface classes since they may have changed.
133      Must do this before sending up/down flags. */
134   /* *INDENT-OFF* */
135   pool_foreach (hif, im->hw_interfaces, ({
136     vnet_hw_interface_class_t * hw_class = vnet_get_hw_interface_class (vnm, hif->hw_class_index);
137     serialize_cstring (m, hw_class->name);
138   }));
139   /* *INDENT-ON* */
140
141   /* Send sw/hw interface state when non-zero. */
142   /* *INDENT-OFF* */
143   pool_foreach (sif, im->sw_interfaces, ({
144     if (sif->flags != 0)
145       {
146         vec_add2 (sts, st, 1);
147         st->sw_hw_if_index = sif->sw_if_index;
148         st->flags = sif->flags;
149       }
150   }));
151   /* *INDENT-ON* */
152
153   vec_serialize (m, sts, serialize_vec_vnet_sw_hw_interface_state);
154
155   if (sts)
156     _vec_len (sts) = 0;
157
158   /* *INDENT-OFF* */
159   pool_foreach (hif, im->hw_interfaces, ({
160     if (hif->flags != 0)
161       {
162         vec_add2 (sts, st, 1);
163         st->sw_hw_if_index = hif->hw_if_index;
164         st->flags = vnet_hw_interface_flags_to_sw(hif->flags);
165       }
166   }));
167   /* *INDENT-ON* */
168
169   vec_serialize (m, sts, serialize_vec_vnet_sw_hw_interface_state);
170
171   vec_free (sts);
172 }
173
174 static vnet_hw_interface_flags_t
175 vnet_sw_interface_flags_to_hw (vnet_sw_interface_flags_t swf)
176 {
177   vnet_hw_interface_flags_t hwf = VNET_HW_INTERFACE_FLAG_NONE;
178
179   if (swf & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
180     hwf |= VNET_HW_INTERFACE_FLAG_LINK_UP;
181
182   return (hwf);
183 }
184
185 void
186 unserialize_vnet_interface_state (serialize_main_t * m, va_list * va)
187 {
188   vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
189   vnet_sw_hw_interface_state_t *sts = 0, *st;
190
191   /* First set interface hardware class. */
192   {
193     vnet_interface_main_t *im = &vnm->interface_main;
194     vnet_hw_interface_t *hif;
195     char *class_name;
196     uword *p;
197     clib_error_t *error;
198
199     /* *INDENT-OFF* */
200     pool_foreach (hif, im->hw_interfaces, ({
201       unserialize_cstring (m, &class_name);
202       p = hash_get_mem (im->hw_interface_class_by_name, class_name);
203       ASSERT (p != 0);
204       error = vnet_hw_interface_set_class_helper (vnm, hif->hw_if_index, p[0], /* redistribute */ 0);
205       if (error)
206         clib_error_report (error);
207       vec_free (class_name);
208     }));
209     /* *INDENT-ON* */
210   }
211
212   vec_unserialize (m, &sts, unserialize_vec_vnet_sw_hw_interface_state);
213   vec_foreach (st, sts)
214     vnet_sw_interface_set_flags_helper (vnm, st->sw_hw_if_index, st->flags,
215                                         /* no distribute */ 0);
216   vec_free (sts);
217
218   vec_unserialize (m, &sts, unserialize_vec_vnet_sw_hw_interface_state);
219   vec_foreach (st, sts)
220   {
221     vnet_hw_interface_set_flags_helper
222       (vnm, st->sw_hw_if_index, vnet_sw_interface_flags_to_hw (st->flags),
223        /* no distribute */ 0);
224   }
225   vec_free (sts);
226 }
227
228 static clib_error_t *
229 call_elf_section_interface_callbacks (vnet_main_t * vnm, u32 if_index,
230                                       u32 flags,
231                                       _vnet_interface_function_list_elt_t **
232                                       elts)
233 {
234   _vnet_interface_function_list_elt_t *elt;
235   vnet_interface_function_priority_t prio;
236   clib_error_t *error = 0;
237
238   for (prio = VNET_ITF_FUNC_PRIORITY_LOW;
239        prio <= VNET_ITF_FUNC_PRIORITY_HIGH; prio++)
240     {
241       elt = elts[prio];
242
243       while (elt)
244         {
245           error = elt->fp (vnm, if_index, flags);
246           if (error)
247             return error;
248           elt = elt->next_interface_function;
249         }
250     }
251   return error;
252 }
253
254 static clib_error_t *
255 call_hw_interface_add_del_callbacks (vnet_main_t * vnm, u32 hw_if_index,
256                                      u32 is_create)
257 {
258   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
259   vnet_hw_interface_class_t *hw_class =
260     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
261   vnet_device_class_t *dev_class =
262     vnet_get_device_class (vnm, hi->dev_class_index);
263   clib_error_t *error = 0;
264
265   if (hw_class->interface_add_del_function
266       && (error =
267           hw_class->interface_add_del_function (vnm, hw_if_index, is_create)))
268     return error;
269
270   if (dev_class->interface_add_del_function
271       && (error =
272           dev_class->interface_add_del_function (vnm, hw_if_index,
273                                                  is_create)))
274     return error;
275
276   error = call_elf_section_interface_callbacks
277     (vnm, hw_if_index, is_create, vnm->hw_interface_add_del_functions);
278
279   return error;
280 }
281
282 static clib_error_t *
283 call_sw_interface_add_del_callbacks (vnet_main_t * vnm, u32 sw_if_index,
284                                      u32 is_create)
285 {
286   return call_elf_section_interface_callbacks
287     (vnm, sw_if_index, is_create, vnm->sw_interface_add_del_functions);
288 }
289
290 #define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
291 #define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
292
293 static clib_error_t *
294 vnet_hw_interface_set_flags_helper (vnet_main_t * vnm, u32 hw_if_index,
295                                     vnet_hw_interface_flags_t flags,
296                                     vnet_interface_helper_flags_t
297                                     helper_flags)
298 {
299   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
300   vnet_hw_interface_class_t *hw_class =
301     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
302   u32 mask;
303   clib_error_t *error = 0;
304   u32 is_create =
305     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
306
307   mask =
308     (VNET_HW_INTERFACE_FLAG_LINK_UP | VNET_HW_INTERFACE_FLAG_DUPLEX_MASK);
309   flags &= mask;
310
311   /* Call hardware interface add/del callbacks. */
312   if (is_create)
313     call_hw_interface_add_del_callbacks (vnm, hw_if_index, is_create);
314
315   /* Already in the desired state? */
316   if (!is_create && (hi->flags & mask) == flags)
317     goto done;
318
319   if ((hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) !=
320       (flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
321     {
322       /* Do hardware class (e.g. ethernet). */
323       if (hw_class->link_up_down_function
324           && (error = hw_class->link_up_down_function (vnm, hw_if_index,
325                                                        flags)))
326         goto done;
327
328       error = call_elf_section_interface_callbacks
329         (vnm, hw_if_index, flags, vnm->hw_interface_link_up_down_functions);
330
331       if (error)
332         goto done;
333     }
334
335   hi->flags &= ~mask;
336   hi->flags |= flags;
337
338 done:
339   return error;
340 }
341
342 static clib_error_t *
343 vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
344                                     vnet_sw_interface_flags_t flags,
345                                     vnet_interface_helper_flags_t
346                                     helper_flags)
347 {
348   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
349   u32 mask;
350   clib_error_t *error = 0;
351   u32 is_create =
352     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
353   u32 old_flags;
354
355   mask = VNET_SW_INTERFACE_FLAG_ADMIN_UP | VNET_SW_INTERFACE_FLAG_PUNT;
356   flags &= mask;
357
358   if (is_create)
359     {
360       error =
361         call_sw_interface_add_del_callbacks (vnm, sw_if_index, is_create);
362       if (error)
363         goto done;
364
365       if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
366         {
367           /* Notify everyone when the interface is created as admin up */
368           error = call_elf_section_interface_callbacks (vnm, sw_if_index,
369                                                         flags,
370                                                         vnm->
371                                                         sw_interface_admin_up_down_functions);
372           if (error)
373             goto done;
374         }
375     }
376   else
377     {
378       vnet_sw_interface_t *si_sup = si;
379
380       /* Check that super interface is in correct state. */
381       if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
382         {
383           si_sup = vnet_get_sw_interface (vnm, si->sup_sw_if_index);
384
385           /* Check to see if we're bringing down the soft interface and if it's parent is up */
386           if ((flags != (si_sup->flags & mask)) &&
387               (!((flags == 0)
388                  && ((si_sup->flags & mask) ==
389                      VNET_SW_INTERFACE_FLAG_ADMIN_UP))))
390             {
391               error = clib_error_return (0, "super-interface %U must be %U",
392                                          format_vnet_sw_interface_name, vnm,
393                                          si_sup,
394                                          format_vnet_sw_interface_flags,
395                                          flags);
396               goto done;
397             }
398         }
399
400       /* Do not change state for slave link of bonded interfaces */
401       if (si->flags & VNET_SW_INTERFACE_FLAG_BOND_SLAVE)
402         {
403           error = clib_error_return
404             (0, "not allowed as %U belong to a BondEthernet interface",
405              format_vnet_sw_interface_name, vnm, si);
406           goto done;
407         }
408
409       /* Already in the desired state? */
410       if ((si->flags & mask) == flags)
411         goto done;
412
413       /* Sub-interfaces of hardware interfaces that do no redistribute,
414          do not redistribute themselves. */
415       if (si_sup->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
416         {
417           vnet_hw_interface_t *hi =
418             vnet_get_hw_interface (vnm, si_sup->hw_if_index);
419           vnet_device_class_t *dev_class =
420             vnet_get_device_class (vnm, hi->dev_class_index);
421           if (!dev_class->redistribute)
422             helper_flags &=
423               ~VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE;
424         }
425
426       /* set the flags now before invoking the registered clients
427        * so that the state they query is consistent with the state here notified */
428       old_flags = si->flags;
429       si->flags &= ~mask;
430       si->flags |= flags;
431       if ((flags | old_flags) & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
432         error = call_elf_section_interface_callbacks
433           (vnm, sw_if_index, flags,
434            vnm->sw_interface_admin_up_down_functions);
435
436       if (error)
437         {
438           /* restore flags on error */
439           si->flags = old_flags;
440           goto done;
441         }
442
443       if (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
444         {
445           vnet_hw_interface_t *hi =
446             vnet_get_hw_interface (vnm, si->hw_if_index);
447           vnet_hw_interface_class_t *hw_class =
448             vnet_get_hw_interface_class (vnm, hi->hw_class_index);
449           vnet_device_class_t *dev_class =
450             vnet_get_device_class (vnm, hi->dev_class_index);
451
452           if ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) &&
453               (si->flags & VNET_SW_INTERFACE_FLAG_ERROR))
454             {
455               error = clib_error_return (0, "Interface in the error state");
456               goto done;
457             }
458
459           /* save the si admin up flag */
460           old_flags = si->flags;
461
462           /* update si admin up flag in advance if we are going admin down */
463           if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
464             si->flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
465
466           if (dev_class->admin_up_down_function
467               && (error = dev_class->admin_up_down_function (vnm,
468                                                              si->hw_if_index,
469                                                              flags)))
470             {
471               /* restore si admin up flag to it's original state on errors */
472               si->flags = old_flags;
473               goto done;
474             }
475
476           if (hw_class->admin_up_down_function
477               && (error = hw_class->admin_up_down_function (vnm,
478                                                             si->hw_if_index,
479                                                             flags)))
480             {
481               /* restore si admin up flag to it's original state on errors */
482               si->flags = old_flags;
483               goto done;
484             }
485
486           /* Admin down implies link down. */
487           if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
488               && (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
489             vnet_hw_interface_set_flags_helper (vnm, si->hw_if_index,
490                                                 hi->flags &
491                                                 ~VNET_HW_INTERFACE_FLAG_LINK_UP,
492                                                 helper_flags);
493         }
494     }
495
496   si->flags &= ~mask;
497   si->flags |= flags;
498
499 done:
500   return error;
501 }
502
503 clib_error_t *
504 vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index,
505                              vnet_hw_interface_flags_t flags)
506 {
507   return vnet_hw_interface_set_flags_helper
508     (vnm, hw_if_index, flags,
509      VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
510 }
511
512 clib_error_t *
513 vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index,
514                              vnet_sw_interface_flags_t flags)
515 {
516   return vnet_sw_interface_set_flags_helper
517     (vnm, sw_if_index, flags,
518      VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
519 }
520
521 static u32
522 vnet_create_sw_interface_no_callbacks (vnet_main_t * vnm,
523                                        vnet_sw_interface_t * template)
524 {
525   vnet_interface_main_t *im = &vnm->interface_main;
526   vnet_sw_interface_t *sw;
527   u32 sw_if_index;
528
529   pool_get (im->sw_interfaces, sw);
530   sw_if_index = sw - im->sw_interfaces;
531
532   sw[0] = template[0];
533
534   sw->flags = 0;
535   sw->sw_if_index = sw_if_index;
536   if (sw->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
537     sw->sup_sw_if_index = sw->sw_if_index;
538
539   /* Allocate counters for this interface. */
540   {
541     u32 i;
542
543     vnet_interface_counter_lock (im);
544
545     for (i = 0; i < vec_len (im->sw_if_counters); i++)
546       {
547         vlib_validate_simple_counter (&im->sw_if_counters[i], sw_if_index);
548         vlib_zero_simple_counter (&im->sw_if_counters[i], sw_if_index);
549       }
550
551     for (i = 0; i < vec_len (im->combined_sw_if_counters); i++)
552       {
553         vlib_validate_combined_counter (&im->combined_sw_if_counters[i],
554                                         sw_if_index);
555         vlib_zero_combined_counter (&im->combined_sw_if_counters[i],
556                                     sw_if_index);
557       }
558
559     vnet_interface_counter_unlock (im);
560   }
561
562   return sw_if_index;
563 }
564
565 clib_error_t *
566 vnet_create_sw_interface (vnet_main_t * vnm, vnet_sw_interface_t * template,
567                           u32 * sw_if_index)
568 {
569   clib_error_t *error;
570   vnet_hw_interface_t *hi;
571   vnet_device_class_t *dev_class;
572
573   hi = vnet_get_sup_hw_interface (vnm, template->sup_sw_if_index);
574   dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
575
576   if (template->type == VNET_SW_INTERFACE_TYPE_SUB &&
577       dev_class->subif_add_del_function)
578     {
579       error = dev_class->subif_add_del_function (vnm, hi->hw_if_index,
580                                                  (struct vnet_sw_interface_t
581                                                   *) template, 1);
582       if (error)
583         return error;
584     }
585
586   *sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, template);
587   error = vnet_sw_interface_set_flags_helper
588     (vnm, *sw_if_index, template->flags,
589      VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
590
591   if (error)
592     {
593       /* undo the work done by vnet_create_sw_interface_no_callbacks() */
594       vnet_interface_main_t *im = &vnm->interface_main;
595       vnet_sw_interface_t *sw =
596         pool_elt_at_index (im->sw_interfaces, *sw_if_index);
597       pool_put (im->sw_interfaces, sw);
598     }
599
600   return error;
601 }
602
603 void
604 vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
605 {
606   vnet_interface_main_t *im = &vnm->interface_main;
607   vnet_sw_interface_t *sw =
608     pool_elt_at_index (im->sw_interfaces, sw_if_index);
609
610   /* Check if the interface has config and is removed from L2 BD or XConnect */
611   vlib_main_t *vm = vlib_get_main ();
612   l2_input_config_t *config;
613   if (sw_if_index < vec_len (l2input_main.configs))
614     {
615       config = vec_elt_at_index (l2input_main.configs, sw_if_index);
616       if (config->xconnect)
617         set_int_l2_mode (vm, vnm, MODE_L3, config->output_sw_if_index, 0,
618                          L2_BD_PORT_TYPE_NORMAL, 0, 0);
619       if (config->xconnect || config->bridge)
620         set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0,
621                          L2_BD_PORT_TYPE_NORMAL, 0, 0);
622     }
623   vnet_clear_sw_interface_tag (vnm, sw_if_index);
624
625   /* Bring down interface in case it is up. */
626   if (sw->flags != 0)
627     vnet_sw_interface_set_flags (vnm, sw_if_index, /* flags */ 0);
628
629   call_sw_interface_add_del_callbacks (vnm, sw_if_index, /* is_create */ 0);
630
631   pool_put (im->sw_interfaces, sw);
632 }
633
634 static clib_error_t *
635 call_sw_interface_mtu_change_callbacks (vnet_main_t * vnm, u32 sw_if_index)
636 {
637   return call_elf_section_interface_callbacks
638     (vnm, sw_if_index, 0, vnm->sw_interface_mtu_change_functions);
639 }
640
641 void
642 vnet_sw_interface_set_mtu (vnet_main_t * vnm, u32 sw_if_index, u32 mtu)
643 {
644   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
645
646   if (si->mtu[VNET_MTU_L3] != mtu)
647     {
648       si->mtu[VNET_MTU_L3] = mtu;
649       call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
650     }
651 }
652
653 void
654 vnet_sw_interface_set_protocol_mtu (vnet_main_t * vnm, u32 sw_if_index,
655                                     u32 mtu[])
656 {
657   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
658   bool changed = false;
659   int i;
660
661   for (i = 0; i < VNET_N_MTU; i++)
662     {
663       if (si->mtu[i] != mtu[i])
664         {
665           si->mtu[i] = mtu[i];
666           changed = true;
667         }
668     }
669   /* Notify interested parties */
670   if (changed)
671     call_sw_interface_mtu_change_callbacks (vnm, sw_if_index);
672 }
673
674 void
675 vnet_sw_interface_ip_directed_broadcast (vnet_main_t * vnm,
676                                          u32 sw_if_index, u8 enable)
677 {
678   vnet_sw_interface_t *si;
679
680   si = vnet_get_sw_interface (vnm, sw_if_index);
681
682   if (enable)
683     si->flags |= VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST;
684   else
685     si->flags &= ~VNET_SW_INTERFACE_FLAG_DIRECTED_BCAST;
686
687   ip4_directed_broadcast (sw_if_index, enable);
688 }
689
690 /*
691  * Reflect a change in hardware MTU on protocol MTUs
692  */
693 static walk_rc_t
694 sw_interface_walk_callback (vnet_main_t * vnm, u32 sw_if_index, void *ctx)
695 {
696   u32 *link_mtu = ctx;
697   vnet_sw_interface_set_mtu (vnm, sw_if_index, *link_mtu);
698   return WALK_CONTINUE;
699 }
700
701 void
702 vnet_hw_interface_set_mtu (vnet_main_t * vnm, u32 hw_if_index, u32 mtu)
703 {
704   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
705
706   if (hi->max_packet_bytes != mtu)
707     {
708       hi->max_packet_bytes = mtu;
709       ethernet_set_flags (vnm, hw_if_index, ETHERNET_INTERFACE_FLAG_MTU);
710       vnet_hw_interface_walk_sw (vnm, hw_if_index, sw_interface_walk_callback,
711                                  &mtu);
712     }
713 }
714
715 static void
716 setup_tx_node (vlib_main_t * vm,
717                u32 node_index, vnet_device_class_t * dev_class)
718 {
719   vlib_node_t *n = vlib_get_node (vm, node_index);
720
721   n->function = dev_class->tx_function;
722   n->format_trace = dev_class->format_tx_trace;
723
724   vlib_register_errors (vm, node_index,
725                         dev_class->tx_function_n_errors,
726                         dev_class->tx_function_error_strings);
727 }
728
729 static void
730 setup_output_node (vlib_main_t * vm,
731                    u32 node_index, vnet_hw_interface_class_t * hw_class)
732 {
733   vlib_node_t *n = vlib_get_node (vm, node_index);
734   n->format_buffer = hw_class->format_header;
735   n->unformat_buffer = hw_class->unformat_header;
736 }
737
738 /* Register an interface instance. */
739 u32
740 vnet_register_interface (vnet_main_t * vnm,
741                          u32 dev_class_index,
742                          u32 dev_instance,
743                          u32 hw_class_index, u32 hw_instance)
744 {
745   vnet_interface_main_t *im = &vnm->interface_main;
746   vnet_hw_interface_t *hw;
747   vnet_device_class_t *dev_class =
748     vnet_get_device_class (vnm, dev_class_index);
749   vnet_hw_interface_class_t *hw_class =
750     vnet_get_hw_interface_class (vnm, hw_class_index);
751   vlib_main_t *vm = vnm->vlib_main;
752   vnet_feature_config_main_t *fcm;
753   vnet_config_main_t *cm;
754   u32 hw_index, i;
755   char *tx_node_name = NULL, *output_node_name = NULL;
756
757   pool_get (im->hw_interfaces, hw);
758   clib_memset (hw, 0, sizeof (*hw));
759
760   hw_index = hw - im->hw_interfaces;
761   hw->hw_if_index = hw_index;
762   hw->default_rx_mode = VNET_HW_INTERFACE_RX_MODE_POLLING;
763
764   if (dev_class->format_device_name)
765     hw->name = format (0, "%U", dev_class->format_device_name, dev_instance);
766   else if (hw_class->format_interface_name)
767     hw->name = format (0, "%U", hw_class->format_interface_name,
768                        dev_instance);
769   else
770     hw->name = format (0, "%s%x", hw_class->name, dev_instance);
771
772   if (!im->hw_interface_by_name)
773     im->hw_interface_by_name = hash_create_vec ( /* size */ 0,
774                                                 sizeof (hw->name[0]),
775                                                 sizeof (uword));
776
777   hash_set_mem (im->hw_interface_by_name, hw->name, hw_index);
778
779   /* Make hardware interface point to software interface. */
780   {
781     vnet_sw_interface_t sw = {
782       .type = VNET_SW_INTERFACE_TYPE_HARDWARE,
783       .flood_class = VNET_FLOOD_CLASS_NORMAL,
784       .hw_if_index = hw_index
785     };
786     hw->sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, &sw);
787   }
788
789   hw->dev_class_index = dev_class_index;
790   hw->dev_instance = dev_instance;
791   hw->hw_class_index = hw_class_index;
792   hw->hw_instance = hw_instance;
793
794   hw->max_rate_bits_per_sec = 0;
795   hw->min_packet_bytes = 0;
796   vnet_sw_interface_set_mtu (vnm, hw->sw_if_index, 0);
797
798   if (dev_class->tx_function == 0)
799     goto no_output_nodes;       /* No output/tx nodes to create */
800
801   tx_node_name = (char *) format (0, "%v-tx", hw->name);
802   output_node_name = (char *) format (0, "%v-output", hw->name);
803
804   /* If we have previously deleted interface nodes, re-use them. */
805   if (vec_len (im->deleted_hw_interface_nodes) > 0)
806     {
807       vnet_hw_interface_nodes_t *hn;
808       vlib_node_t *node;
809       vlib_node_runtime_t *nrt;
810
811       hn = vec_end (im->deleted_hw_interface_nodes) - 1;
812
813       hw->tx_node_index = hn->tx_node_index;
814       hw->output_node_index = hn->output_node_index;
815
816       vlib_node_rename (vm, hw->tx_node_index, "%v", tx_node_name);
817       vlib_node_rename (vm, hw->output_node_index, "%v", output_node_name);
818
819       /* *INDENT-OFF* */
820       foreach_vlib_main ({
821         vnet_interface_output_runtime_t *rt;
822
823         rt = vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
824         ASSERT (rt->is_deleted == 1);
825         rt->is_deleted = 0;
826         rt->hw_if_index = hw_index;
827         rt->sw_if_index = hw->sw_if_index;
828         rt->dev_instance = hw->dev_instance;
829
830         rt = vlib_node_get_runtime_data (this_vlib_main, hw->tx_node_index);
831         rt->hw_if_index = hw_index;
832         rt->sw_if_index = hw->sw_if_index;
833         rt->dev_instance = hw->dev_instance;
834       });
835       /* *INDENT-ON* */
836
837       /* The new class may differ from the old one.
838        * Functions have to be updated. */
839       node = vlib_get_node (vm, hw->output_node_index);
840       node->function = vnet_interface_output_node_multiarch_select ();
841       node->format_trace = format_vnet_interface_output_trace;
842       /* *INDENT-OFF* */
843       foreach_vlib_main ({
844         nrt = vlib_node_get_runtime (this_vlib_main, hw->output_node_index);
845         nrt->function = node->function;
846       });
847       /* *INDENT-ON* */
848
849       node = vlib_get_node (vm, hw->tx_node_index);
850       node->function = dev_class->tx_function;
851       node->format_trace = dev_class->format_tx_trace;
852       /* *INDENT-OFF* */
853       foreach_vlib_main ({
854         nrt = vlib_node_get_runtime (this_vlib_main, hw->tx_node_index);
855         nrt->function = node->function;
856       });
857       /* *INDENT-ON* */
858
859       _vec_len (im->deleted_hw_interface_nodes) -= 1;
860     }
861   else
862     {
863       vlib_node_registration_t r;
864       vnet_interface_output_runtime_t rt = {
865         .hw_if_index = hw_index,
866         .sw_if_index = hw->sw_if_index,
867         .dev_instance = hw->dev_instance,
868         .is_deleted = 0,
869       };
870
871       clib_memset (&r, 0, sizeof (r));
872       r.type = VLIB_NODE_TYPE_INTERNAL;
873       r.runtime_data = &rt;
874       r.runtime_data_bytes = sizeof (rt);
875       r.scalar_size = 0;
876       r.vector_size = sizeof (u32);
877
878       r.flags = VLIB_NODE_FLAG_IS_OUTPUT;
879       r.name = tx_node_name;
880       r.function = dev_class->tx_function;
881
882       hw->tx_node_index = vlib_register_node (vm, &r);
883
884       vlib_node_add_named_next_with_slot (vm, hw->tx_node_index,
885                                           "error-drop",
886                                           VNET_INTERFACE_TX_NEXT_DROP);
887
888       r.flags = 0;
889       r.name = output_node_name;
890       r.function = vnet_interface_output_node_multiarch_select ();
891       r.format_trace = format_vnet_interface_output_trace;
892
893       {
894         static char *e[] = {
895           "interface is down",
896           "interface is deleted",
897         };
898
899         r.n_errors = ARRAY_LEN (e);
900         r.error_strings = e;
901       }
902       hw->output_node_index = vlib_register_node (vm, &r);
903
904       vlib_node_add_named_next_with_slot (vm, hw->output_node_index,
905                                           "error-drop",
906                                           VNET_INTERFACE_OUTPUT_NEXT_DROP);
907       vlib_node_add_next_with_slot (vm, hw->output_node_index,
908                                     hw->tx_node_index,
909                                     VNET_INTERFACE_OUTPUT_NEXT_TX);
910
911       /* add interface to the list of "output-interface" feature arc start nodes
912          and clone nexts from 1st interface if it exists */
913       fcm = vnet_feature_get_config_main (im->output_feature_arc_index);
914       cm = &fcm->config_main;
915       i = vec_len (cm->start_node_indices);
916       vec_validate (cm->start_node_indices, i);
917       cm->start_node_indices[i] = hw->output_node_index;
918       if (hw_index)
919         {
920           /* copy nexts from 1st interface */
921           vnet_hw_interface_t *first_hw;
922           vlib_node_t *first_node;
923
924           first_hw = vnet_get_hw_interface (vnm, /* hw_if_index */ 0);
925           first_node = vlib_get_node (vm, first_hw->output_node_index);
926
927           /* 1st 2 nexts are already added above */
928           for (i = 2; i < vec_len (first_node->next_nodes); i++)
929             vlib_node_add_next_with_slot (vm, hw->output_node_index,
930                                           first_node->next_nodes[i], i);
931         }
932     }
933
934   setup_output_node (vm, hw->output_node_index, hw_class);
935   setup_tx_node (vm, hw->tx_node_index, dev_class);
936
937 no_output_nodes:
938   /* Call all up/down callbacks with zero flags when interface is created. */
939   vnet_sw_interface_set_flags_helper (vnm, hw->sw_if_index, /* flags */ 0,
940                                       VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
941   vnet_hw_interface_set_flags_helper (vnm, hw_index, /* flags */ 0,
942                                       VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
943   vec_free (tx_node_name);
944   vec_free (output_node_name);
945
946   return hw_index;
947 }
948
949 void
950 vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
951 {
952   vnet_interface_main_t *im = &vnm->interface_main;
953   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
954   vlib_main_t *vm = vnm->vlib_main;
955   vnet_device_class_t *dev_class = vnet_get_device_class (vnm,
956                                                           hw->dev_class_index);
957   /* If it is up, mark it down. */
958   if (hw->flags != 0)
959     vnet_hw_interface_set_flags (vnm, hw_if_index, /* flags */ 0);
960
961   /* Call delete callbacks. */
962   call_hw_interface_add_del_callbacks (vnm, hw_if_index, /* is_create */ 0);
963
964   /* Delete any sub-interfaces. */
965   {
966     u32 id, sw_if_index;
967     /* *INDENT-OFF* */
968     hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id,
969     ({
970       vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
971       u64 sup_and_sub_key =
972         ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
973       hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
974       vnet_delete_sw_interface (vnm, sw_if_index);
975     }));
976     hash_free (hw->sub_interface_sw_if_index_by_id);
977     /* *INDENT-ON* */
978   }
979
980   /* Delete software interface corresponding to hardware interface. */
981   vnet_delete_sw_interface (vnm, hw->sw_if_index);
982
983   if (dev_class->tx_function)
984     {
985       /* Put output/tx nodes into recycle pool */
986       vnet_hw_interface_nodes_t *dn;
987
988       /* *INDENT-OFF* */
989       foreach_vlib_main
990         ({
991           vnet_interface_output_runtime_t *rt =
992             vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
993
994           /* Mark node runtime as deleted so output node (if called)
995            * will drop packets. */
996           rt->is_deleted = 1;
997         });
998       /* *INDENT-ON* */
999
1000       vlib_node_rename (vm, hw->output_node_index,
1001                         "interface-%d-output-deleted", hw_if_index);
1002       vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted",
1003                         hw_if_index);
1004       vec_add2 (im->deleted_hw_interface_nodes, dn, 1);
1005       dn->tx_node_index = hw->tx_node_index;
1006       dn->output_node_index = hw->output_node_index;
1007     }
1008
1009   hash_unset_mem (im->hw_interface_by_name, hw->name);
1010   vec_free (hw->name);
1011   vec_free (hw->hw_address);
1012   vec_free (hw->input_node_thread_index_by_queue);
1013   vec_free (hw->dq_runtime_index_by_queue);
1014
1015   pool_put (im->hw_interfaces, hw);
1016 }
1017
1018 void
1019 vnet_hw_interface_walk_sw (vnet_main_t * vnm,
1020                            u32 hw_if_index,
1021                            vnet_hw_sw_interface_walk_t fn, void *ctx)
1022 {
1023   vnet_hw_interface_t *hi;
1024   u32 id, sw_if_index;
1025
1026   hi = vnet_get_hw_interface (vnm, hw_if_index);
1027   /* the super first, then the sub interfaces */
1028   if (WALK_STOP == fn (vnm, hi->sw_if_index, ctx))
1029     return;
1030
1031   /* *INDENT-OFF* */
1032   hash_foreach (id, sw_if_index,
1033                 hi->sub_interface_sw_if_index_by_id,
1034   ({
1035     if (WALK_STOP == fn (vnm, sw_if_index, ctx))
1036       break;
1037   }));
1038   /* *INDENT-ON* */
1039 }
1040
1041 void
1042 vnet_hw_interface_walk (vnet_main_t * vnm,
1043                         vnet_hw_interface_walk_t fn, void *ctx)
1044 {
1045   vnet_interface_main_t *im;
1046   vnet_hw_interface_t *hi;
1047
1048   im = &vnm->interface_main;
1049
1050   /* *INDENT-OFF* */
1051   pool_foreach (hi, im->hw_interfaces,
1052   ({
1053     if (WALK_STOP == fn(vnm, hi->hw_if_index, ctx))
1054       break;
1055   }));
1056   /* *INDENT-ON* */
1057 }
1058
1059 void
1060 vnet_sw_interface_walk (vnet_main_t * vnm,
1061                         vnet_sw_interface_walk_t fn, void *ctx)
1062 {
1063   vnet_interface_main_t *im;
1064   vnet_sw_interface_t *si;
1065
1066   im = &vnm->interface_main;
1067
1068   /* *INDENT-OFF* */
1069   pool_foreach (si, im->sw_interfaces,
1070   {
1071     if (WALK_STOP == fn (vnm, si, ctx))
1072       break;
1073   });
1074   /* *INDENT-ON* */
1075 }
1076
1077 void
1078 vnet_hw_interface_init_for_class (vnet_main_t * vnm, u32 hw_if_index,
1079                                   u32 hw_class_index, u32 hw_instance)
1080 {
1081   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1082   vnet_hw_interface_class_t *hc =
1083     vnet_get_hw_interface_class (vnm, hw_class_index);
1084
1085   hi->hw_class_index = hw_class_index;
1086   hi->hw_instance = hw_instance;
1087   setup_output_node (vnm->vlib_main, hi->output_node_index, hc);
1088 }
1089
1090 static clib_error_t *
1091 vnet_hw_interface_set_class_helper (vnet_main_t * vnm, u32 hw_if_index,
1092                                     u32 hw_class_index, u32 redistribute)
1093 {
1094   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1095   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, hi->sw_if_index);
1096   vnet_hw_interface_class_t *old_class =
1097     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
1098   vnet_hw_interface_class_t *new_class =
1099     vnet_get_hw_interface_class (vnm, hw_class_index);
1100   vnet_device_class_t *dev_class =
1101     vnet_get_device_class (vnm, hi->dev_class_index);
1102   clib_error_t *error = 0;
1103
1104   /* New class equals old class?  Nothing to do. */
1105   if (hi->hw_class_index == hw_class_index)
1106     return 0;
1107
1108   /* No need (and incorrect since admin up flag may be set) to do error checking when
1109      receiving unserialize message. */
1110   if (redistribute)
1111     {
1112       if (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1113         return clib_error_return (0,
1114                                   "%v must be admin down to change class from %s to %s",
1115                                   hi->name, old_class->name, new_class->name);
1116
1117       /* Make sure interface supports given class. */
1118       if ((new_class->is_valid_class_for_interface
1119            && !new_class->is_valid_class_for_interface (vnm, hw_if_index,
1120                                                         hw_class_index))
1121           || (dev_class->is_valid_class_for_interface
1122               && !dev_class->is_valid_class_for_interface (vnm, hw_if_index,
1123                                                            hw_class_index)))
1124         return clib_error_return (0,
1125                                   "%v class cannot be changed from %s to %s",
1126                                   hi->name, old_class->name, new_class->name);
1127
1128     }
1129
1130   if (old_class->hw_class_change)
1131     old_class->hw_class_change (vnm, hw_if_index, old_class->index,
1132                                 new_class->index);
1133
1134   vnet_hw_interface_init_for_class (vnm, hw_if_index, new_class->index,
1135                                     /* instance */ ~0);
1136
1137   if (new_class->hw_class_change)
1138     new_class->hw_class_change (vnm, hw_if_index, old_class->index,
1139                                 new_class->index);
1140
1141   if (dev_class->hw_class_change)
1142     dev_class->hw_class_change (vnm, hw_if_index, new_class->index);
1143
1144   return error;
1145 }
1146
1147 clib_error_t *
1148 vnet_hw_interface_set_class (vnet_main_t * vnm, u32 hw_if_index,
1149                              u32 hw_class_index)
1150 {
1151   return vnet_hw_interface_set_class_helper (vnm, hw_if_index, hw_class_index,
1152                                              /* redistribute */ 1);
1153 }
1154
1155 static int
1156 vnet_hw_interface_rx_redirect_to_node_helper (vnet_main_t * vnm,
1157                                               u32 hw_if_index,
1158                                               u32 node_index,
1159                                               u32 redistribute)
1160 {
1161   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1162   vnet_device_class_t *dev_class = vnet_get_device_class
1163     (vnm, hi->dev_class_index);
1164
1165   if (dev_class->rx_redirect_to_node)
1166     {
1167       dev_class->rx_redirect_to_node (vnm, hw_if_index, node_index);
1168       return 0;
1169     }
1170
1171   return VNET_API_ERROR_UNIMPLEMENTED;
1172 }
1173
1174 int
1175 vnet_hw_interface_rx_redirect_to_node (vnet_main_t * vnm, u32 hw_if_index,
1176                                        u32 node_index)
1177 {
1178   return vnet_hw_interface_rx_redirect_to_node_helper (vnm, hw_if_index,
1179                                                        node_index,
1180                                                        1 /* redistribute */ );
1181 }
1182
1183 word
1184 vnet_sw_interface_compare (vnet_main_t * vnm,
1185                            uword sw_if_index0, uword sw_if_index1)
1186 {
1187   vnet_sw_interface_t *sup0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1188   vnet_sw_interface_t *sup1 = vnet_get_sup_sw_interface (vnm, sw_if_index1);
1189   vnet_hw_interface_t *h0 = vnet_get_hw_interface (vnm, sup0->hw_if_index);
1190   vnet_hw_interface_t *h1 = vnet_get_hw_interface (vnm, sup1->hw_if_index);
1191
1192   if (h0 != h1)
1193     return vec_cmp (h0->name, h1->name);
1194   return (word) h0->hw_instance - (word) h1->hw_instance;
1195 }
1196
1197 word
1198 vnet_hw_interface_compare (vnet_main_t * vnm,
1199                            uword hw_if_index0, uword hw_if_index1)
1200 {
1201   vnet_hw_interface_t *h0 = vnet_get_hw_interface (vnm, hw_if_index0);
1202   vnet_hw_interface_t *h1 = vnet_get_hw_interface (vnm, hw_if_index1);
1203
1204   if (h0 != h1)
1205     return vec_cmp (h0->name, h1->name);
1206   return (word) h0->hw_instance - (word) h1->hw_instance;
1207 }
1208
1209 int
1210 vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index)
1211 {
1212   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
1213   if ((si->type == VNET_SW_INTERFACE_TYPE_P2P) ||
1214       (si->type == VNET_SW_INTERFACE_TYPE_PIPE))
1215     return 1;
1216
1217   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
1218   vnet_hw_interface_class_t *hc =
1219     vnet_get_hw_interface_class (vnm, hw->hw_class_index);
1220
1221   return (hc->flags & VNET_HW_INTERFACE_CLASS_FLAG_P2P);
1222 }
1223
1224 clib_error_t *
1225 vnet_interface_init (vlib_main_t * vm)
1226 {
1227   vnet_main_t *vnm = vnet_get_main ();
1228   vnet_interface_main_t *im = &vnm->interface_main;
1229   vlib_buffer_t *b = 0;
1230   vnet_buffer_opaque_t *o = 0;
1231   clib_error_t *error;
1232
1233   /*
1234    * Keep people from shooting themselves in the foot.
1235    */
1236   if (sizeof (b->opaque) != sizeof (vnet_buffer_opaque_t))
1237     {
1238 #define _(a) if (sizeof(o->a) > sizeof (o->unused))                     \
1239       clib_warning                                                      \
1240         ("FATAL: size of opaque union subtype %s is %d (max %d)",       \
1241          #a, sizeof(o->a), sizeof (o->unused));
1242       foreach_buffer_opaque_union_subtype;
1243 #undef _
1244
1245       return clib_error_return
1246         (0, "FATAL: size of vlib buffer opaque %d, size of vnet opaque %d",
1247          sizeof (b->opaque), sizeof (vnet_buffer_opaque_t));
1248     }
1249
1250   im->sw_if_counter_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
1251                                                    CLIB_CACHE_LINE_BYTES);
1252   im->sw_if_counter_lock[0] = 1;        /* should be no need */
1253
1254   vec_validate (im->sw_if_counters, VNET_N_SIMPLE_INTERFACE_COUNTER - 1);
1255 #define _(E,n,p)                                                        \
1256   im->sw_if_counters[VNET_INTERFACE_COUNTER_##E].name = #n;             \
1257   im->sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
1258   foreach_simple_interface_counter_name
1259 #undef _
1260     vec_validate (im->combined_sw_if_counters,
1261                   VNET_N_COMBINED_INTERFACE_COUNTER - 1);
1262 #define _(E,n,p)                                                        \
1263   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].name = #n;    \
1264   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
1265   foreach_combined_interface_counter_name
1266 #undef _
1267     im->sw_if_counter_lock[0] = 0;
1268
1269   im->device_class_by_name = hash_create_string ( /* size */ 0,
1270                                                  sizeof (uword));
1271   {
1272     vnet_device_class_t *c;
1273
1274     c = vnm->device_class_registrations;
1275
1276     while (c)
1277       {
1278         c->index = vec_len (im->device_classes);
1279         hash_set_mem (im->device_class_by_name, c->name, c->index);
1280
1281         if (c->tx_fn_registrations)
1282           {
1283             vlib_node_fn_registration_t *fnr = c->tx_fn_registrations;
1284             int priority = -1;
1285
1286             /* to avoid confusion, please remove ".tx_function" statement
1287                from VNET_DEVICE_CLASS() if using function candidates */
1288             ASSERT (c->tx_function == 0);
1289
1290             while (fnr)
1291               {
1292                 if (fnr->priority > priority)
1293                   {
1294                     priority = fnr->priority;
1295                     c->tx_function = fnr->function;
1296                   }
1297                 fnr = fnr->next_registration;
1298               }
1299           }
1300
1301         vec_add1 (im->device_classes, c[0]);
1302         c = c->next_class_registration;
1303       }
1304   }
1305
1306   im->hw_interface_class_by_name = hash_create_string ( /* size */ 0,
1307                                                        sizeof (uword));
1308
1309   im->sw_if_index_by_sup_and_sub = hash_create_mem (0, sizeof (u64),
1310                                                     sizeof (uword));
1311   {
1312     vnet_hw_interface_class_t *c;
1313
1314     c = vnm->hw_interface_class_registrations;
1315
1316     while (c)
1317       {
1318         c->index = vec_len (im->hw_interface_classes);
1319         hash_set_mem (im->hw_interface_class_by_name, c->name, c->index);
1320
1321         if (NULL == c->build_rewrite)
1322           c->build_rewrite = default_build_rewrite;
1323         if (NULL == c->update_adjacency)
1324           c->update_adjacency = default_update_adjacency;
1325
1326         vec_add1 (im->hw_interface_classes, c[0]);
1327         c = c->next_class_registration;
1328       }
1329   }
1330
1331   if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
1332     return error;
1333
1334   vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
1335
1336 #if VLIB_BUFFER_TRACE_TRAJECTORY > 0
1337   if ((error = vlib_call_init_function (vm, trajectory_trace_init)))
1338     return error;
1339 #endif
1340
1341   return 0;
1342 }
1343
1344 VLIB_INIT_FUNCTION (vnet_interface_init);
1345
1346 /* Kludge to renumber interface names [only!] */
1347 int
1348 vnet_interface_name_renumber (u32 sw_if_index, u32 new_show_dev_instance)
1349 {
1350   int rv;
1351   vnet_main_t *vnm = vnet_get_main ();
1352   vnet_interface_main_t *im = &vnm->interface_main;
1353   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1354
1355   vnet_device_class_t *dev_class = vnet_get_device_class
1356     (vnm, hi->dev_class_index);
1357
1358   if (dev_class->name_renumber == 0 || dev_class->format_device_name == 0)
1359     return VNET_API_ERROR_UNIMPLEMENTED;
1360
1361   rv = dev_class->name_renumber (hi, new_show_dev_instance);
1362
1363   if (rv)
1364     return rv;
1365
1366   hash_unset_mem (im->hw_interface_by_name, hi->name);
1367   vec_free (hi->name);
1368   /* Use the mapping we set up to call it Ishmael */
1369   hi->name = format (0, "%U", dev_class->format_device_name,
1370                      hi->dev_instance);
1371
1372   hash_set_mem (im->hw_interface_by_name, hi->name, hi->hw_if_index);
1373   return rv;
1374 }
1375
1376 clib_error_t *
1377 vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
1378 {
1379   vnet_interface_main_t *im = &vnm->interface_main;
1380   vlib_main_t *vm = vnm->vlib_main;
1381   vnet_hw_interface_t *hw;
1382   u8 *old_name;
1383   clib_error_t *error = 0;
1384
1385   hw = vnet_get_hw_interface (vnm, hw_if_index);
1386   if (!hw)
1387     {
1388       return clib_error_return (0,
1389                                 "unable to find hw interface for index %u",
1390                                 hw_if_index);
1391     }
1392
1393   old_name = hw->name;
1394
1395   /* set new hw->name */
1396   hw->name = format (0, "%s", new_name);
1397
1398   /* remove the old name to hw_if_index mapping and install the new one */
1399   hash_unset_mem (im->hw_interface_by_name, old_name);
1400   hash_set_mem (im->hw_interface_by_name, hw->name, hw_if_index);
1401
1402   /* rename tx/output nodes */
1403   vlib_node_rename (vm, hw->tx_node_index, "%v-tx", hw->name);
1404   vlib_node_rename (vm, hw->output_node_index, "%v-output", hw->name);
1405
1406   /* free the old name vector */
1407   vec_free (old_name);
1408
1409   return error;
1410 }
1411
1412 static clib_error_t *
1413 vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
1414                                              u32 hw_if_index,
1415                                              const u8 * mac_address)
1416 {
1417   clib_error_t *error = 0;
1418   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
1419
1420   if (hi->hw_address)
1421     {
1422       u8 *old_address = vec_dup (hi->hw_address);
1423       vnet_device_class_t *dev_class =
1424         vnet_get_device_class (vnm, hi->dev_class_index);
1425       if (dev_class->mac_addr_change_function)
1426         {
1427           error =
1428             dev_class->mac_addr_change_function (hi, old_address,
1429                                                  mac_address);
1430         }
1431       if (!error)
1432         {
1433           vnet_hw_interface_class_t *hw_class;
1434
1435           hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
1436
1437           if (NULL != hw_class->mac_addr_change_function)
1438             hw_class->mac_addr_change_function (hi, old_address, mac_address);
1439         }
1440       else
1441         {
1442           error =
1443             clib_error_return (0,
1444                                "MAC Address Change is not supported on this interface");
1445         }
1446       vec_free (old_address);
1447     }
1448   else
1449     {
1450       error =
1451         clib_error_return (0,
1452                            "mac address change is not supported for interface index %u",
1453                            hw_if_index);
1454     }
1455   return error;
1456 }
1457
1458 clib_error_t *
1459 vnet_hw_interface_change_mac_address (vnet_main_t * vnm, u32 hw_if_index,
1460                                       const u8 * mac_address)
1461 {
1462   return vnet_hw_interface_change_mac_address_helper
1463     (vnm, hw_if_index, mac_address);
1464 }
1465
1466 /* update the unnumbered state of an interface*/
1467 void
1468 vnet_sw_interface_update_unnumbered (u32 unnumbered_sw_if_index,
1469                                      u32 ip_sw_if_index, u8 enable)
1470 {
1471   vnet_main_t *vnm = vnet_get_main ();
1472   vnet_sw_interface_t *si;
1473   u32 was_unnum;
1474
1475   si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
1476   was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED);
1477
1478   if (enable)
1479     {
1480       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
1481       si->unnumbered_sw_if_index = ip_sw_if_index;
1482
1483       ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
1484         [unnumbered_sw_if_index] =
1485         ip4_main.
1486         lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
1487       ip6_main.
1488         lookup_main.if_address_pool_index_by_sw_if_index
1489         [unnumbered_sw_if_index] =
1490         ip6_main.
1491         lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
1492     }
1493   else
1494     {
1495       si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
1496       si->unnumbered_sw_if_index = (u32) ~ 0;
1497
1498       ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
1499         [unnumbered_sw_if_index] = ~0;
1500       ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
1501         [unnumbered_sw_if_index] = ~0;
1502     }
1503
1504   if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
1505     {
1506       ip4_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
1507       ip6_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
1508     }
1509 }
1510
1511 vnet_l3_packet_type_t
1512 vnet_link_to_l3_proto (vnet_link_t link)
1513 {
1514   switch (link)
1515     {
1516     case VNET_LINK_IP4:
1517       return (VNET_L3_PACKET_TYPE_IP4);
1518     case VNET_LINK_IP6:
1519       return (VNET_L3_PACKET_TYPE_IP6);
1520     case VNET_LINK_MPLS:
1521       return (VNET_L3_PACKET_TYPE_MPLS);
1522     case VNET_LINK_ARP:
1523       return (VNET_L3_PACKET_TYPE_ARP);
1524     case VNET_LINK_ETHERNET:
1525     case VNET_LINK_NSH:
1526       ASSERT (0);
1527       break;
1528     }
1529   ASSERT (0);
1530   return (0);
1531 }
1532
1533 vnet_mtu_t
1534 vnet_link_to_mtu (vnet_link_t link)
1535 {
1536   switch (link)
1537     {
1538     case VNET_LINK_IP4:
1539       return (VNET_MTU_IP4);
1540     case VNET_LINK_IP6:
1541       return (VNET_MTU_IP6);
1542     case VNET_LINK_MPLS:
1543       return (VNET_MTU_MPLS);
1544     default:
1545       return (VNET_MTU_L3);
1546     }
1547 }
1548
1549 u8 *
1550 default_build_rewrite (vnet_main_t * vnm,
1551                        u32 sw_if_index,
1552                        vnet_link_t link_type, const void *dst_address)
1553 {
1554   return (NULL);
1555 }
1556
1557 void
1558 default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
1559 {
1560   ip_adjacency_t *adj;
1561
1562   adj = adj_get (ai);
1563
1564   switch (adj->lookup_next_index)
1565     {
1566     case IP_LOOKUP_NEXT_GLEAN:
1567       adj_glean_update_rewrite (ai);
1568       break;
1569     case IP_LOOKUP_NEXT_ARP:
1570     case IP_LOOKUP_NEXT_BCAST:
1571       /*
1572        * default rewrite in neighbour adj
1573        */
1574       adj_nbr_update_rewrite
1575         (ai,
1576          ADJ_NBR_REWRITE_FLAG_COMPLETE,
1577          vnet_build_rewrite_for_sw_interface (vnm,
1578                                               sw_if_index,
1579                                               adj_get_link_type (ai), NULL));
1580       break;
1581     case IP_LOOKUP_NEXT_MCAST:
1582       /*
1583        * mcast traffic also uses default rewrite string with no mcast
1584        * switch time updates.
1585        */
1586       adj_mcast_update_rewrite
1587         (ai,
1588          vnet_build_rewrite_for_sw_interface (vnm,
1589                                               sw_if_index,
1590                                               adj_get_link_type (ai),
1591                                               NULL), 0);
1592       break;
1593     case IP_LOOKUP_NEXT_DROP:
1594     case IP_LOOKUP_NEXT_PUNT:
1595     case IP_LOOKUP_NEXT_LOCAL:
1596     case IP_LOOKUP_NEXT_REWRITE:
1597     case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
1598     case IP_LOOKUP_NEXT_MIDCHAIN:
1599     case IP_LOOKUP_NEXT_ICMP_ERROR:
1600     case IP_LOOKUP_N_NEXT:
1601       ASSERT (0);
1602       break;
1603     }
1604 }
1605
1606 int collect_detailed_interface_stats_flag = 0;
1607
1608 void
1609 collect_detailed_interface_stats_flag_set (void)
1610 {
1611   collect_detailed_interface_stats_flag = 1;
1612 }
1613
1614 void
1615 collect_detailed_interface_stats_flag_clear (void)
1616 {
1617   collect_detailed_interface_stats_flag = 0;
1618 }
1619
1620 static clib_error_t *
1621 collect_detailed_interface_stats_cli (vlib_main_t * vm,
1622                                       unformat_input_t * input,
1623                                       vlib_cli_command_t * cmd)
1624 {
1625   unformat_input_t _line_input, *line_input = &_line_input;
1626   clib_error_t *error = NULL;
1627
1628   /* Get a line of input. */
1629   if (!unformat_user (input, unformat_line_input, line_input))
1630     return clib_error_return (0, "expected enable | disable");
1631
1632   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1633     {
1634       if (unformat (line_input, "enable") || unformat (line_input, "on"))
1635         collect_detailed_interface_stats_flag_set ();
1636       else if (unformat (line_input, "disable")
1637                || unformat (line_input, "off"))
1638         collect_detailed_interface_stats_flag_clear ();
1639       else
1640         {
1641           error = clib_error_return (0, "unknown input `%U'",
1642                                      format_unformat_error, line_input);
1643           goto done;
1644         }
1645     }
1646
1647 done:
1648   unformat_free (line_input);
1649   return error;
1650 }
1651
1652 /* *INDENT-OFF* */
1653 VLIB_CLI_COMMAND (collect_detailed_interface_stats_command, static) = {
1654   .path = "interface collect detailed-stats",
1655   .short_help = "interface collect detailed-stats <enable|disable>",
1656   .function = collect_detailed_interface_stats_cli,
1657 };
1658 /* *INDENT-ON* */
1659
1660 /*
1661  * fd.io coding-style-patch-verification: ON
1662  *
1663  * Local Variables:
1664  * eval: (c-set-style "gnu")
1665  * End:
1666  */