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