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