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