595ed1432bc7b364d695a2111fd7f23b6510f70b
[vpp.git] / vnet / 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
43 #define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
44 #define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
45
46 static clib_error_t *vnet_hw_interface_set_flags_helper (vnet_main_t * vnm,
47                                                          u32 hw_if_index,
48                                                          u32 flags,
49                                                          u32 helper_flags);
50
51 static clib_error_t *vnet_sw_interface_set_flags_helper (vnet_main_t * vnm,
52                                                          u32 sw_if_index,
53                                                          u32 flags,
54                                                          u32 helper_flags);
55
56 static clib_error_t *vnet_hw_interface_set_class_helper (vnet_main_t * vnm,
57                                                          u32 hw_if_index,
58                                                          u32 hw_class_index,
59                                                          u32 redistribute);
60
61 typedef struct
62 {
63   /* Either sw or hw interface index. */
64   u32 sw_hw_if_index;
65
66   /* Flags. */
67   u32 flags;
68 } vnet_sw_hw_interface_state_t;
69
70 static void
71 serialize_vec_vnet_sw_hw_interface_state (serialize_main_t * m, va_list * va)
72 {
73   vnet_sw_hw_interface_state_t *s =
74     va_arg (*va, vnet_sw_hw_interface_state_t *);
75   u32 n = va_arg (*va, u32);
76   u32 i;
77   for (i = 0; i < n; i++)
78     {
79       serialize_integer (m, s[i].sw_hw_if_index,
80                          sizeof (s[i].sw_hw_if_index));
81       serialize_integer (m, s[i].flags, sizeof (s[i].flags));
82     }
83 }
84
85 static void
86 unserialize_vec_vnet_sw_hw_interface_state (serialize_main_t * m,
87                                             va_list * va)
88 {
89   vnet_sw_hw_interface_state_t *s =
90     va_arg (*va, vnet_sw_hw_interface_state_t *);
91   u32 n = va_arg (*va, u32);
92   u32 i;
93   for (i = 0; i < n; i++)
94     {
95       unserialize_integer (m, &s[i].sw_hw_if_index,
96                            sizeof (s[i].sw_hw_if_index));
97       unserialize_integer (m, &s[i].flags, sizeof (s[i].flags));
98     }
99 }
100
101 static void
102 serialize_vnet_sw_hw_interface_set_flags (serialize_main_t * m, va_list * va)
103 {
104   vnet_sw_hw_interface_state_t *s =
105     va_arg (*va, vnet_sw_hw_interface_state_t *);
106   serialize (m, serialize_vec_vnet_sw_hw_interface_state, s, 1);
107 }
108
109 static void
110 unserialize_vnet_sw_interface_set_flags (serialize_main_t * m, va_list * va)
111 {
112   CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
113   vnet_sw_hw_interface_state_t s;
114
115   unserialize (m, unserialize_vec_vnet_sw_hw_interface_state, &s, 1);
116
117   vnet_sw_interface_set_flags_helper
118     (vnet_get_main (), s.sw_hw_if_index, s.flags,
119      /* helper_flags no redistribution */ 0);
120 }
121
122 static void
123 unserialize_vnet_hw_interface_set_flags (serialize_main_t * m, va_list * va)
124 {
125   CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
126   vnet_sw_hw_interface_state_t s;
127
128   unserialize (m, unserialize_vec_vnet_sw_hw_interface_state, &s, 1);
129
130   vnet_hw_interface_set_flags_helper
131     (vnet_get_main (), s.sw_hw_if_index, s.flags,
132      /* helper_flags no redistribution */ 0);
133 }
134
135 MC_SERIALIZE_MSG (vnet_sw_interface_set_flags_msg, static) =
136 {
137 .name = "vnet_sw_interface_set_flags",.serialize =
138     serialize_vnet_sw_hw_interface_set_flags,.unserialize =
139     unserialize_vnet_sw_interface_set_flags,};
140
141 MC_SERIALIZE_MSG (vnet_hw_interface_set_flags_msg, static) =
142 {
143 .name = "vnet_hw_interface_set_flags",.serialize =
144     serialize_vnet_sw_hw_interface_set_flags,.unserialize =
145     unserialize_vnet_hw_interface_set_flags,};
146
147 void
148 serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
149 {
150   vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
151   vnet_sw_hw_interface_state_t *sts = 0, *st;
152   vnet_sw_interface_t *sif;
153   vnet_hw_interface_t *hif;
154   vnet_interface_main_t *im = &vnm->interface_main;
155
156   /* Serialize hardware interface classes since they may have changed.
157      Must do this before sending up/down flags. */
158   /* *INDENT-OFF* */
159   pool_foreach (hif, im->hw_interfaces, ({
160     vnet_hw_interface_class_t * hw_class = vnet_get_hw_interface_class (vnm, hif->hw_class_index);
161     serialize_cstring (m, hw_class->name);
162   }));
163   /* *INDENT-ON* */
164
165   /* Send sw/hw interface state when non-zero. */
166   /* *INDENT-OFF* */
167   pool_foreach (sif, im->sw_interfaces, ({
168     if (sif->flags != 0)
169       {
170         vec_add2 (sts, st, 1);
171         st->sw_hw_if_index = sif->sw_if_index;
172         st->flags = sif->flags;
173       }
174   }));
175   /* *INDENT-ON* */
176
177   vec_serialize (m, sts, serialize_vec_vnet_sw_hw_interface_state);
178
179   if (sts)
180     _vec_len (sts) = 0;
181
182   /* *INDENT-OFF* */
183   pool_foreach (hif, im->hw_interfaces, ({
184     if (hif->flags != 0)
185       {
186         vec_add2 (sts, st, 1);
187         st->sw_hw_if_index = hif->hw_if_index;
188         st->flags = hif->flags;
189       }
190   }));
191   /* *INDENT-ON* */
192
193   vec_serialize (m, sts, serialize_vec_vnet_sw_hw_interface_state);
194
195   vec_free (sts);
196 }
197
198 void
199 unserialize_vnet_interface_state (serialize_main_t * m, va_list * va)
200 {
201   vnet_main_t *vnm = va_arg (*va, vnet_main_t *);
202   vnet_sw_hw_interface_state_t *sts = 0, *st;
203
204   /* First set interface hardware class. */
205   {
206     vnet_interface_main_t *im = &vnm->interface_main;
207     vnet_hw_interface_t *hif;
208     char *class_name;
209     uword *p;
210     clib_error_t *error;
211
212     /* *INDENT-OFF* */
213     pool_foreach (hif, im->hw_interfaces, ({
214       unserialize_cstring (m, &class_name);
215       p = hash_get_mem (im->hw_interface_class_by_name, class_name);
216       ASSERT (p != 0);
217       error = vnet_hw_interface_set_class_helper (vnm, hif->hw_if_index, p[0], /* redistribute */ 0);
218       if (error)
219         clib_error_report (error);
220       vec_free (class_name);
221     }));
222     /* *INDENT-ON* */
223   }
224
225   vec_unserialize (m, &sts, unserialize_vec_vnet_sw_hw_interface_state);
226   vec_foreach (st, sts)
227     vnet_sw_interface_set_flags_helper (vnm, st->sw_hw_if_index, st->flags,
228                                         /* no distribute */ 0);
229   vec_free (sts);
230
231   vec_unserialize (m, &sts, unserialize_vec_vnet_sw_hw_interface_state);
232   vec_foreach (st, sts)
233     vnet_hw_interface_set_flags_helper (vnm, st->sw_hw_if_index, st->flags,
234                                         /* no distribute */ 0);
235   vec_free (sts);
236 }
237
238 static clib_error_t *
239 call_elf_section_interface_callbacks (vnet_main_t * vnm, u32 if_index,
240                                       u32 flags,
241                                       _vnet_interface_function_list_elt_t *
242                                       elt)
243 {
244   clib_error_t *error = 0;
245
246   while (elt)
247     {
248       error = elt->fp (vnm, if_index, flags);
249       if (error)
250         return error;
251       elt = elt->next_interface_function;
252     }
253   return error;
254 }
255
256 static clib_error_t *
257 call_hw_interface_add_del_callbacks (vnet_main_t * vnm, u32 hw_if_index,
258                                      u32 is_create)
259 {
260   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
261   vnet_hw_interface_class_t *hw_class =
262     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
263   vnet_device_class_t *dev_class =
264     vnet_get_device_class (vnm, hi->dev_class_index);
265   clib_error_t *error = 0;
266
267   if (hw_class->interface_add_del_function
268       && (error =
269           hw_class->interface_add_del_function (vnm, hw_if_index, is_create)))
270     return error;
271
272   if (dev_class->interface_add_del_function
273       && (error =
274           dev_class->interface_add_del_function (vnm, hw_if_index,
275                                                  is_create)))
276     return error;
277
278   error = call_elf_section_interface_callbacks
279     (vnm, hw_if_index, is_create, vnm->hw_interface_add_del_functions);
280
281   return error;
282 }
283
284 static clib_error_t *
285 call_sw_interface_add_del_callbacks (vnet_main_t * vnm, u32 sw_if_index,
286                                      u32 is_create)
287 {
288   return call_elf_section_interface_callbacks
289     (vnm, sw_if_index, is_create, vnm->sw_interface_add_del_functions);
290 }
291
292 #define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
293 #define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
294
295 static clib_error_t *
296 vnet_hw_interface_set_flags_helper (vnet_main_t * vnm, u32 hw_if_index,
297                                     u32 flags, u32 helper_flags)
298 {
299   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
300   vnet_hw_interface_class_t *hw_class =
301     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
302   vnet_device_class_t *dev_class =
303     vnet_get_device_class (vnm, hi->dev_class_index);
304   vlib_main_t *vm = vnm->vlib_main;
305   u32 mask;
306   clib_error_t *error = 0;
307   u32 is_create =
308     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
309
310   mask =
311     (VNET_HW_INTERFACE_FLAG_LINK_UP | VNET_HW_INTERFACE_FLAG_DUPLEX_MASK |
312      VNET_HW_INTERFACE_FLAG_SPEED_MASK);
313   flags &= mask;
314
315   /* Call hardware interface add/del callbacks. */
316   if (is_create)
317     call_hw_interface_add_del_callbacks (vnm, hw_if_index, is_create);
318
319   /* Already in the desired state? */
320   if (!is_create && (hi->flags & mask) == flags)
321     goto done;
322
323   /* Some interface classes do not redistribute (e.g. are local). */
324   if (!dev_class->redistribute)
325     helper_flags &= ~VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE;
326
327   if (vm->mc_main
328       && (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE))
329     {
330       vnet_sw_hw_interface_state_t s;
331       s.sw_hw_if_index = hw_if_index;
332       s.flags = flags;
333       mc_serialize (vm->mc_main, &vnet_hw_interface_set_flags_msg, &s);
334     }
335
336   if ((hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) !=
337       (flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
338     {
339       /* Do hardware class (e.g. ethernet). */
340       if (hw_class->link_up_down_function
341           && (error = hw_class->link_up_down_function (vnm, hw_if_index,
342                                                        flags)))
343         goto done;
344
345       error = call_elf_section_interface_callbacks
346         (vnm, hw_if_index, flags, vnm->hw_interface_link_up_down_functions);
347
348       if (error)
349         goto done;
350     }
351
352   hi->flags &= ~mask;
353   hi->flags |= flags;
354
355 done:
356   return error;
357 }
358
359 static clib_error_t *
360 vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
361                                     u32 flags, u32 helper_flags)
362 {
363   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
364   vlib_main_t *vm = vnm->vlib_main;
365   u32 mask;
366   clib_error_t *error = 0;
367   u32 is_create =
368     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
369   u32 old_flags;
370
371   mask = VNET_SW_INTERFACE_FLAG_ADMIN_UP | VNET_SW_INTERFACE_FLAG_PUNT;
372   flags &= mask;
373
374   if (is_create)
375     {
376       error =
377         call_sw_interface_add_del_callbacks (vnm, sw_if_index, is_create);
378       if (error)
379         goto done;
380
381       if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
382         {
383           /* Notify everyone when the interface is created as admin up */
384           error = call_elf_section_interface_callbacks (vnm, sw_if_index,
385                                                         flags,
386                                                         vnm->
387                                                         sw_interface_admin_up_down_functions);
388           if (error)
389             goto done;
390         }
391     }
392   else
393     {
394       vnet_sw_interface_t *si_sup = si;
395
396       /* Check that super interface is in correct state. */
397       if (si->type == VNET_SW_INTERFACE_TYPE_SUB)
398         {
399           si_sup = vnet_get_sw_interface (vnm, si->sup_sw_if_index);
400
401           /* Check to see if we're bringing down the soft interface and if it's parent is up */
402           if ((flags != (si_sup->flags & mask)) &&
403               (!((flags == 0)
404                  && ((si_sup->flags & mask) ==
405                      VNET_SW_INTERFACE_FLAG_ADMIN_UP))))
406             {
407               error = clib_error_return (0, "super-interface %U must be %U",
408                                          format_vnet_sw_interface_name, vnm,
409                                          si_sup,
410                                          format_vnet_sw_interface_flags,
411                                          flags);
412               goto done;
413             }
414         }
415
416       /* Donot change state for slave link of bonded interfaces */
417       if (si->flags & VNET_SW_INTERFACE_FLAG_BOND_SLAVE)
418         {
419           error = clib_error_return
420             (0, "not allowed as %U belong to a BondEthernet interface",
421              format_vnet_sw_interface_name, vnm, si);
422           goto done;
423         }
424
425       /* Already in the desired state? */
426       if ((si->flags & mask) == flags)
427         goto done;
428
429       /* Sub-interfaces of hardware interfaces that do no redistribute,
430          do not redistribute themselves. */
431       if (si_sup->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
432         {
433           vnet_hw_interface_t *hi =
434             vnet_get_hw_interface (vnm, si_sup->hw_if_index);
435           vnet_device_class_t *dev_class =
436             vnet_get_device_class (vnm, hi->dev_class_index);
437           if (!dev_class->redistribute)
438             helper_flags &=
439               ~VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE;
440         }
441
442       if (vm->mc_main
443           && (helper_flags &
444               VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE))
445         {
446           vnet_sw_hw_interface_state_t s;
447           s.sw_hw_if_index = sw_if_index;
448           s.flags = flags;
449           mc_serialize (vm->mc_main, &vnet_sw_interface_set_flags_msg, &s);
450         }
451
452       /* set the flags now before invoking the registered clients
453        * so that the state they query is consistent with the state here notified */
454       old_flags = si->flags;
455       si->flags &= ~mask;
456       si->flags |= flags;
457       if ((flags | old_flags) & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
458         error = call_elf_section_interface_callbacks
459           (vnm, sw_if_index, flags,
460            vnm->sw_interface_admin_up_down_functions);
461       si->flags = old_flags;
462
463       if (error)
464         goto done;
465
466       if (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
467         {
468           vnet_hw_interface_t *hi =
469             vnet_get_hw_interface (vnm, si->hw_if_index);
470           vnet_hw_interface_class_t *hw_class =
471             vnet_get_hw_interface_class (vnm, hi->hw_class_index);
472           vnet_device_class_t *dev_class =
473             vnet_get_device_class (vnm, hi->dev_class_index);
474
475           /* save the si admin up flag */
476           old_flags = si->flags;
477
478           /* update si admin up flag in advance if we are going admin down */
479           if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
480             si->flags &= ~VNET_SW_INTERFACE_FLAG_ADMIN_UP;
481
482           if (dev_class->admin_up_down_function
483               && (error = dev_class->admin_up_down_function (vnm,
484                                                              si->hw_if_index,
485                                                              flags)))
486             {
487               /* restore si admin up flag to it's original state on errors */
488               si->flags = old_flags;
489               goto done;
490             }
491
492           if (hw_class->admin_up_down_function
493               && (error = hw_class->admin_up_down_function (vnm,
494                                                             si->hw_if_index,
495                                                             flags)))
496             {
497               /* restore si admin up flag to it's original state on errors */
498               si->flags = old_flags;
499               goto done;
500             }
501
502           /* Admin down implies link down. */
503           if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
504               && (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
505             vnet_hw_interface_set_flags_helper (vnm, si->hw_if_index,
506                                                 hi->flags &
507                                                 ~VNET_HW_INTERFACE_FLAG_LINK_UP,
508                                                 helper_flags);
509         }
510     }
511
512   si->flags &= ~mask;
513   si->flags |= flags;
514
515 done:
516   return error;
517 }
518
519 clib_error_t *
520 vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
521 {
522   return vnet_hw_interface_set_flags_helper
523     (vnm, hw_if_index, flags,
524      VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
525 }
526
527 clib_error_t *
528 vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
529 {
530   return vnet_sw_interface_set_flags_helper
531     (vnm, sw_if_index, flags,
532      VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
533 }
534
535 static u32
536 vnet_create_sw_interface_no_callbacks (vnet_main_t * vnm,
537                                        vnet_sw_interface_t * template)
538 {
539   vnet_interface_main_t *im = &vnm->interface_main;
540   vnet_sw_interface_t *sw;
541   u32 sw_if_index;
542
543   pool_get (im->sw_interfaces, sw);
544   sw_if_index = sw - im->sw_interfaces;
545
546   sw[0] = template[0];
547
548   sw->flags = 0;
549   sw->sw_if_index = sw_if_index;
550   if (sw->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
551     sw->sup_sw_if_index = sw->sw_if_index;
552
553   /* Allocate counters for this interface. */
554   {
555     u32 i;
556
557     vnet_interface_counter_lock (im);
558
559     for (i = 0; i < vec_len (im->sw_if_counters); i++)
560       {
561         vlib_validate_simple_counter (&im->sw_if_counters[i], sw_if_index);
562         vlib_zero_simple_counter (&im->sw_if_counters[i], sw_if_index);
563       }
564
565     for (i = 0; i < vec_len (im->combined_sw_if_counters); i++)
566       {
567         vlib_validate_combined_counter (&im->combined_sw_if_counters[i],
568                                         sw_if_index);
569         vlib_zero_combined_counter (&im->combined_sw_if_counters[i],
570                                     sw_if_index);
571       }
572
573     vnet_interface_counter_unlock (im);
574   }
575
576   return sw_if_index;
577 }
578
579 clib_error_t *
580 vnet_create_sw_interface (vnet_main_t * vnm, vnet_sw_interface_t * template,
581                           u32 * sw_if_index)
582 {
583   clib_error_t *error;
584   vnet_hw_interface_t *hi;
585   vnet_device_class_t *dev_class;
586
587   hi = vnet_get_sup_hw_interface (vnm, template->sup_sw_if_index);
588   dev_class = vnet_get_device_class (vnm, hi->dev_class_index);
589
590   if (template->type == VNET_SW_INTERFACE_TYPE_SUB &&
591       dev_class->subif_add_del_function)
592     {
593       error = dev_class->subif_add_del_function (vnm, hi->hw_if_index,
594                                                  (struct vnet_sw_interface_t
595                                                   *) template, 1);
596       if (error)
597         return error;
598     }
599
600   *sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, template);
601   error = vnet_sw_interface_set_flags_helper
602     (vnm, *sw_if_index, template->flags,
603      VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
604
605   if (error)
606     {
607       /* undo the work done by vnet_create_sw_interface_no_callbacks() */
608       vnet_interface_main_t *im = &vnm->interface_main;
609       vnet_sw_interface_t *sw =
610         pool_elt_at_index (im->sw_interfaces, *sw_if_index);
611       pool_put (im->sw_interfaces, sw);
612     }
613
614   return error;
615 }
616
617 void
618 vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
619 {
620   vnet_interface_main_t *im = &vnm->interface_main;
621   vnet_sw_interface_t *sw =
622     pool_elt_at_index (im->sw_interfaces, sw_if_index);
623
624   /* Bring down interface in case it is up. */
625   if (sw->flags != 0)
626     vnet_sw_interface_set_flags (vnm, sw_if_index, /* flags */ 0);
627
628   call_sw_interface_add_del_callbacks (vnm, sw_if_index, /* is_create */ 0);
629
630   pool_put (im->sw_interfaces, sw);
631 }
632
633 static void
634 setup_tx_node (vlib_main_t * vm,
635                u32 node_index, vnet_device_class_t * dev_class)
636 {
637   vlib_node_t *n = vlib_get_node (vm, node_index);
638
639   n->function = dev_class->tx_function;
640   n->format_trace = dev_class->format_tx_trace;
641   vlib_register_errors (vm, node_index,
642                         dev_class->tx_function_n_errors,
643                         dev_class->tx_function_error_strings);
644 }
645
646 static void
647 setup_output_node (vlib_main_t * vm,
648                    u32 node_index, vnet_hw_interface_class_t * hw_class)
649 {
650   vlib_node_t *n = vlib_get_node (vm, node_index);
651   n->format_buffer = hw_class->format_header;
652   n->unformat_buffer = hw_class->unformat_header;
653 }
654
655 /* Register an interface instance. */
656 u32
657 vnet_register_interface (vnet_main_t * vnm,
658                          u32 dev_class_index,
659                          u32 dev_instance,
660                          u32 hw_class_index, u32 hw_instance)
661 {
662   vnet_interface_main_t *im = &vnm->interface_main;
663   vnet_hw_interface_t *hw;
664   vnet_device_class_t *dev_class =
665     vnet_get_device_class (vnm, dev_class_index);
666   vnet_hw_interface_class_t *hw_class =
667     vnet_get_hw_interface_class (vnm, hw_class_index);
668   vlib_main_t *vm = vnm->vlib_main;
669   u32 hw_index;
670   char *tx_node_name, *output_node_name;
671
672   pool_get (im->hw_interfaces, hw);
673
674   hw_index = hw - im->hw_interfaces;
675   hw->hw_if_index = hw_index;
676
677   if (dev_class->format_device_name)
678     hw->name = format (0, "%U", dev_class->format_device_name, dev_instance);
679   else if (hw_class->format_interface_name)
680     hw->name = format (0, "%U", hw_class->format_interface_name,
681                        dev_instance);
682   else
683     hw->name = format (0, "%s%x", hw_class->name, dev_instance);
684
685   if (!im->hw_interface_by_name)
686     im->hw_interface_by_name = hash_create_vec ( /* size */ 0,
687                                                 sizeof (hw->name[0]),
688                                                 sizeof (uword));
689
690   hash_set_mem (im->hw_interface_by_name, hw->name, hw_index);
691
692   /* Make hardware interface point to software interface. */
693   {
694     vnet_sw_interface_t sw;
695
696     memset (&sw, 0, sizeof (sw));
697     sw.type = VNET_SW_INTERFACE_TYPE_HARDWARE;
698     sw.hw_if_index = hw_index;
699     hw->sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, &sw);
700   }
701
702   hw->dev_class_index = dev_class_index;
703   hw->dev_instance = dev_instance;
704   hw->hw_class_index = hw_class_index;
705   hw->hw_instance = hw_instance;
706
707   hw->max_rate_bits_per_sec = 0;
708   hw->min_packet_bytes = 0;
709   hw->per_packet_overhead_bytes = 0;
710   hw->max_l3_packet_bytes[VLIB_RX] = ~0;
711   hw->max_l3_packet_bytes[VLIB_TX] = ~0;
712
713   tx_node_name = (char *) format (0, "%v-tx", hw->name);
714   output_node_name = (char *) format (0, "%v-output", hw->name);
715
716   /* If we have previously deleted interface nodes, re-use them. */
717   if (vec_len (im->deleted_hw_interface_nodes) > 0)
718     {
719       vnet_hw_interface_nodes_t *hn;
720       vnet_interface_output_runtime_t *rt;
721
722       hn = vec_end (im->deleted_hw_interface_nodes) - 1;
723
724       hw->tx_node_index = hn->tx_node_index;
725       hw->output_node_index = hn->output_node_index;
726
727       vlib_node_rename (vm, hw->tx_node_index, "%v", tx_node_name);
728       vlib_node_rename (vm, hw->output_node_index, "%v", output_node_name);
729
730       rt = vlib_node_get_runtime_data (vm, hw->output_node_index);
731       ASSERT (rt->is_deleted == 1);
732       rt->is_deleted = 0;
733       rt->hw_if_index = hw_index;
734       rt->sw_if_index = hw->sw_if_index;
735       rt->dev_instance = hw->dev_instance;
736
737       rt = vlib_node_get_runtime_data (vm, hw->tx_node_index);
738       rt->hw_if_index = hw_index;
739       rt->sw_if_index = hw->sw_if_index;
740       rt->dev_instance = hw->dev_instance;
741
742       vlib_worker_thread_node_runtime_update ();
743       _vec_len (im->deleted_hw_interface_nodes) -= 1;
744     }
745   else
746     {
747       vlib_node_registration_t r;
748       vnet_interface_output_runtime_t rt = {
749         .hw_if_index = hw_index,
750         .sw_if_index = hw->sw_if_index,
751         .dev_instance = hw->dev_instance,
752         .is_deleted = 0,
753       };
754
755       memset (&r, 0, sizeof (r));
756       r.type = VLIB_NODE_TYPE_INTERNAL;
757       r.runtime_data = &rt;
758       r.runtime_data_bytes = sizeof (rt);
759       r.scalar_size = 0;
760       r.vector_size = sizeof (u32);
761
762       r.flags = VLIB_NODE_FLAG_IS_OUTPUT;
763       r.name = tx_node_name;
764       r.function = dev_class->tx_function;
765
766       hw->tx_node_index = vlib_register_node (vm, &r);
767
768       vlib_node_add_named_next_with_slot (vm, hw->tx_node_index,
769                                           "error-drop",
770                                           VNET_INTERFACE_TX_NEXT_DROP);
771
772       r.flags = 0;
773       r.name = output_node_name;
774       r.function = dev_class->no_flatten_output_chains ?
775         vnet_interface_output_node_no_flatten_multiarch_select () :
776         vnet_interface_output_node_multiarch_select ();
777       r.format_trace = format_vnet_interface_output_trace;
778
779       {
780         static char *e[] = {
781           "interface is down",
782           "interface is deleted",
783         };
784
785         r.n_errors = ARRAY_LEN (e);
786         r.error_strings = e;
787       }
788       hw->output_node_index = vlib_register_node (vm, &r);
789
790 #define _(sym,str) vlib_node_add_named_next_with_slot (vm, \
791                      hw->output_node_index, str,           \
792                      VNET_INTERFACE_OUTPUT_NEXT_##sym);
793       foreach_intf_output_feat
794 #undef _
795         vlib_node_add_named_next_with_slot (vm, hw->output_node_index,
796                                             "error-drop",
797                                             VNET_INTERFACE_OUTPUT_NEXT_DROP);
798       vlib_node_add_next_with_slot (vm, hw->output_node_index,
799                                     hw->tx_node_index,
800                                     VNET_INTERFACE_OUTPUT_NEXT_TX);
801     }
802
803   setup_output_node (vm, hw->output_node_index, hw_class);
804   setup_tx_node (vm, hw->tx_node_index, dev_class);
805
806   /* Call all up/down callbacks with zero flags when interface is created. */
807   vnet_sw_interface_set_flags_helper (vnm, hw->sw_if_index, /* flags */ 0,
808                                       VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
809   vnet_hw_interface_set_flags_helper (vnm, hw_index, /* flags */ 0,
810                                       VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
811
812   return hw_index;
813 }
814
815 void
816 vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
817 {
818   vnet_interface_main_t *im = &vnm->interface_main;
819   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
820   vlib_main_t *vm = vnm->vlib_main;
821
822   /* If it is up, mark it down. */
823   if (hw->flags != 0)
824     vnet_hw_interface_set_flags (vnm, hw_if_index, /* flags */ 0);
825
826   /* Call delete callbacks. */
827   call_hw_interface_add_del_callbacks (vnm, hw_if_index, /* is_create */ 0);
828
829   /* Delete software interface corresponding to hardware interface. */
830   vnet_delete_sw_interface (vnm, hw->sw_if_index);
831
832   /* Delete any sub-interfaces. */
833   {
834     u32 id, sw_if_index;
835     /* *INDENT-OFF* */
836     hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id, ({
837       vnet_delete_sw_interface (vnm, sw_if_index);
838     }));
839     /* *INDENT-ON* */
840   }
841
842   {
843     vnet_hw_interface_nodes_t *dn;
844     vnet_interface_output_runtime_t *rt =
845       vlib_node_get_runtime_data (vm, hw->output_node_index);
846
847     /* Mark node runtime as deleted so output node (if called) will drop packets. */
848     rt->is_deleted = 1;
849
850     vlib_node_rename (vm, hw->output_node_index,
851                       "interface-%d-output-deleted", hw_if_index);
852     vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted",
853                       hw_if_index);
854     vec_add2 (im->deleted_hw_interface_nodes, dn, 1);
855     dn->tx_node_index = hw->tx_node_index;
856     dn->output_node_index = hw->output_node_index;
857   }
858
859   hash_unset_mem (im->hw_interface_by_name, hw->name);
860   vec_free (hw->name);
861
862   pool_put (im->hw_interfaces, hw);
863 }
864
865 static void
866 serialize_vnet_hw_interface_set_class (serialize_main_t * m, va_list * va)
867 {
868   u32 hw_if_index = va_arg (*va, u32);
869   char *hw_class_name = va_arg (*va, char *);
870   serialize_integer (m, hw_if_index, sizeof (hw_if_index));
871   serialize_cstring (m, hw_class_name);
872 }
873
874 static void
875 unserialize_vnet_hw_interface_set_class (serialize_main_t * m, va_list * va)
876 {
877   CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
878   vnet_main_t *vnm = vnet_get_main ();
879   u32 hw_if_index;
880   char *hw_class_name;
881   uword *p;
882   clib_error_t *error;
883
884   unserialize_integer (m, &hw_if_index, sizeof (hw_if_index));
885   unserialize_cstring (m, &hw_class_name);
886   p =
887     hash_get (vnm->interface_main.hw_interface_class_by_name, hw_class_name);
888   ASSERT (p != 0);
889   error = vnet_hw_interface_set_class_helper (vnm, hw_if_index, p[0],
890                                               /* redistribute */ 0);
891   if (error)
892     clib_error_report (error);
893 }
894
895 MC_SERIALIZE_MSG (vnet_hw_interface_set_class_msg, static) =
896 {
897 .name = "vnet_hw_interface_set_class",.serialize =
898     serialize_vnet_hw_interface_set_class,.unserialize =
899     unserialize_vnet_hw_interface_set_class,};
900
901 void
902 vnet_hw_interface_init_for_class (vnet_main_t * vnm, u32 hw_if_index,
903                                   u32 hw_class_index, u32 hw_instance)
904 {
905   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
906   vnet_hw_interface_class_t *hc =
907     vnet_get_hw_interface_class (vnm, hw_class_index);
908
909   hi->hw_class_index = hw_class_index;
910   hi->hw_instance = hw_instance;
911   setup_output_node (vnm->vlib_main, hi->output_node_index, hc);
912 }
913
914 static clib_error_t *
915 vnet_hw_interface_set_class_helper (vnet_main_t * vnm, u32 hw_if_index,
916                                     u32 hw_class_index, u32 redistribute)
917 {
918   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
919   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, hi->sw_if_index);
920   vnet_hw_interface_class_t *old_class =
921     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
922   vnet_hw_interface_class_t *new_class =
923     vnet_get_hw_interface_class (vnm, hw_class_index);
924   vnet_device_class_t *dev_class =
925     vnet_get_device_class (vnm, hi->dev_class_index);
926   clib_error_t *error = 0;
927
928   /* New class equals old class?  Nothing to do. */
929   if (hi->hw_class_index == hw_class_index)
930     return 0;
931
932   /* No need (and incorrect since admin up flag may be set) to do error checking when
933      receiving unserialize message. */
934   if (redistribute)
935     {
936       if (si->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
937         return clib_error_return (0,
938                                   "%v must be admin down to change class from %s to %s",
939                                   hi->name, old_class->name, new_class->name);
940
941       /* Make sure interface supports given class. */
942       if ((new_class->is_valid_class_for_interface
943            && !new_class->is_valid_class_for_interface (vnm, hw_if_index,
944                                                         hw_class_index))
945           || (dev_class->is_valid_class_for_interface
946               && !dev_class->is_valid_class_for_interface (vnm, hw_if_index,
947                                                            hw_class_index)))
948         return clib_error_return (0,
949                                   "%v class cannot be changed from %s to %s",
950                                   hi->name, old_class->name, new_class->name);
951
952       if (vnm->vlib_main->mc_main)
953         {
954           mc_serialize (vnm->vlib_main->mc_main,
955                         &vnet_hw_interface_set_class_msg, hw_if_index,
956                         new_class->name);
957           return 0;
958         }
959     }
960
961   if (old_class->hw_class_change)
962     old_class->hw_class_change (vnm, hw_if_index, old_class->index,
963                                 new_class->index);
964
965   vnet_hw_interface_init_for_class (vnm, hw_if_index, new_class->index,
966                                     /* instance */ ~0);
967
968   if (new_class->hw_class_change)
969     new_class->hw_class_change (vnm, hw_if_index, old_class->index,
970                                 new_class->index);
971
972   if (dev_class->hw_class_change)
973     dev_class->hw_class_change (vnm, hw_if_index, new_class->index);
974
975   return error;
976 }
977
978 clib_error_t *
979 vnet_hw_interface_set_class (vnet_main_t * vnm, u32 hw_if_index,
980                              u32 hw_class_index)
981 {
982   return vnet_hw_interface_set_class_helper (vnm, hw_if_index, hw_class_index,
983                                              /* redistribute */ 1);
984 }
985
986 static int
987 vnet_hw_interface_rx_redirect_to_node_helper (vnet_main_t * vnm,
988                                               u32 hw_if_index,
989                                               u32 node_index,
990                                               u32 redistribute)
991 {
992   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
993   vnet_device_class_t *dev_class = vnet_get_device_class
994     (vnm, hi->dev_class_index);
995
996   if (redistribute)
997     {
998       /* $$$$ fixme someday maybe */
999       ASSERT (vnm->vlib_main->mc_main == 0);
1000     }
1001   if (dev_class->rx_redirect_to_node)
1002     {
1003       dev_class->rx_redirect_to_node (vnm, hw_if_index, node_index);
1004       return 0;
1005     }
1006
1007   return VNET_API_ERROR_UNIMPLEMENTED;
1008 }
1009
1010 int
1011 vnet_hw_interface_rx_redirect_to_node (vnet_main_t * vnm, u32 hw_if_index,
1012                                        u32 node_index)
1013 {
1014   return vnet_hw_interface_rx_redirect_to_node_helper (vnm, hw_if_index,
1015                                                        node_index,
1016                                                        1 /* redistribute */ );
1017 }
1018
1019 word
1020 vnet_sw_interface_compare (vnet_main_t * vnm,
1021                            uword sw_if_index0, uword sw_if_index1)
1022 {
1023   vnet_sw_interface_t *sup0 = vnet_get_sup_sw_interface (vnm, sw_if_index0);
1024   vnet_sw_interface_t *sup1 = vnet_get_sup_sw_interface (vnm, sw_if_index1);
1025   vnet_hw_interface_t *h0 = vnet_get_hw_interface (vnm, sup0->hw_if_index);
1026   vnet_hw_interface_t *h1 = vnet_get_hw_interface (vnm, sup1->hw_if_index);
1027
1028   if (h0 != h1)
1029     return vec_cmp (h0->name, h1->name);
1030   return (word) h0->hw_instance - (word) h1->hw_instance;
1031 }
1032
1033 word
1034 vnet_hw_interface_compare (vnet_main_t * vnm,
1035                            uword hw_if_index0, uword hw_if_index1)
1036 {
1037   vnet_hw_interface_t *h0 = vnet_get_hw_interface (vnm, hw_if_index0);
1038   vnet_hw_interface_t *h1 = vnet_get_hw_interface (vnm, hw_if_index1);
1039
1040   if (h0 != h1)
1041     return vec_cmp (h0->name, h1->name);
1042   return (word) h0->hw_instance - (word) h1->hw_instance;
1043 }
1044
1045 clib_error_t *
1046 vnet_interface_init (vlib_main_t * vm)
1047 {
1048   vnet_main_t *vnm = vnet_get_main ();
1049   vnet_interface_main_t *im = &vnm->interface_main;
1050   vlib_buffer_t *b = 0;
1051   vnet_buffer_opaque_t *o = 0;
1052
1053   /*
1054    * Keep people from shooting themselves in the foot.
1055    */
1056   if (sizeof (b->opaque) != sizeof (vnet_buffer_opaque_t))
1057     {
1058 #define _(a) if (sizeof(o->a) > sizeof (o->unused))                     \
1059       clib_warning                                                      \
1060         ("FATAL: size of opaque union subtype %s is %d (max %d)",       \
1061          #a, sizeof(o->a), sizeof (o->unused));
1062       foreach_buffer_opaque_union_subtype;
1063 #undef _
1064
1065       return clib_error_return
1066         (0, "FATAL: size of vlib buffer opaque %d, size of vnet opaque %d",
1067          sizeof (b->opaque), sizeof (vnet_buffer_opaque_t));
1068     }
1069
1070   im->sw_if_counter_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
1071                                                    CLIB_CACHE_LINE_BYTES);
1072   im->sw_if_counter_lock[0] = 1;        /* should be no need */
1073
1074   vec_validate (im->sw_if_counters, VNET_N_SIMPLE_INTERFACE_COUNTER - 1);
1075   im->sw_if_counters[VNET_INTERFACE_COUNTER_DROP].name = "drops";
1076   im->sw_if_counters[VNET_INTERFACE_COUNTER_PUNT].name = "punts";
1077   im->sw_if_counters[VNET_INTERFACE_COUNTER_IP4].name = "ip4";
1078   im->sw_if_counters[VNET_INTERFACE_COUNTER_IP6].name = "ip6";
1079   im->sw_if_counters[VNET_INTERFACE_COUNTER_RX_NO_BUF].name = "rx-no-buf";
1080   im->sw_if_counters[VNET_INTERFACE_COUNTER_RX_MISS].name = "rx-miss";
1081   im->sw_if_counters[VNET_INTERFACE_COUNTER_RX_ERROR].name = "rx-error";
1082   im->sw_if_counters[VNET_INTERFACE_COUNTER_TX_ERROR].name = "tx-error";
1083
1084   vec_validate (im->combined_sw_if_counters,
1085                 VNET_N_COMBINED_INTERFACE_COUNTER - 1);
1086   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX].name = "rx";
1087   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX].name = "tx";
1088
1089   im->sw_if_counter_lock[0] = 0;
1090
1091   im->device_class_by_name = hash_create_string ( /* size */ 0,
1092                                                  sizeof (uword));
1093   {
1094     vnet_device_class_t *c;
1095
1096     c = vnm->device_class_registrations;
1097
1098     while (c)
1099       {
1100         c->index = vec_len (im->device_classes);
1101         hash_set_mem (im->device_class_by_name, c->name, c->index);
1102         vec_add1 (im->device_classes, c[0]);
1103         c = c->next_class_registration;
1104       }
1105   }
1106
1107   im->hw_interface_class_by_name = hash_create_string ( /* size */ 0,
1108                                                        sizeof (uword));
1109
1110   im->sw_if_index_by_sup_and_sub = hash_create_mem (0, sizeof (u64),
1111                                                     sizeof (uword));
1112   {
1113     vnet_hw_interface_class_t *c;
1114
1115     c = vnm->hw_interface_class_registrations;
1116
1117     while (c)
1118       {
1119         c->index = vec_len (im->hw_interface_classes);
1120         hash_set_mem (im->hw_interface_class_by_name, c->name, c->index);
1121         vec_add1 (im->hw_interface_classes, c[0]);
1122         c = c->next_class_registration;
1123       }
1124   }
1125
1126   {
1127     clib_error_t *error;
1128
1129     if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
1130       return error;
1131
1132     return error;
1133   }
1134 }
1135
1136 VLIB_INIT_FUNCTION (vnet_interface_init);
1137
1138 /* Kludge to renumber interface names [only!] */
1139 int
1140 vnet_interface_name_renumber (u32 sw_if_index, u32 new_show_dev_instance)
1141 {
1142   int rv;
1143   vnet_main_t *vnm = vnet_get_main ();
1144   vnet_interface_main_t *im = &vnm->interface_main;
1145   vnet_hw_interface_t *hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
1146
1147   vnet_device_class_t *dev_class = vnet_get_device_class
1148     (vnm, hi->dev_class_index);
1149
1150   if (dev_class->name_renumber == 0 || dev_class->format_device_name == 0)
1151     return VNET_API_ERROR_UNIMPLEMENTED;
1152
1153   rv = dev_class->name_renumber (hi, new_show_dev_instance);
1154
1155   if (rv)
1156     return rv;
1157
1158   hash_unset_mem (im->hw_interface_by_name, hi->name);
1159   vec_free (hi->name);
1160   /* Use the mapping we set up to call it Ishmael */
1161   hi->name = format (0, "%U", dev_class->format_device_name,
1162                      hi->dev_instance);
1163
1164   hash_set_mem (im->hw_interface_by_name, hi->name, hi->hw_if_index);
1165   return rv;
1166 }
1167
1168 int
1169 vnet_interface_add_del_feature (vnet_main_t * vnm,
1170                                 vlib_main_t * vm,
1171                                 u32 sw_if_index,
1172                                 intf_output_feat_t feature, int is_add)
1173 {
1174   vnet_sw_interface_t *sw;
1175
1176   sw = vnet_get_sw_interface (vnm, sw_if_index);
1177
1178   if (is_add)
1179     {
1180
1181       sw->output_feature_bitmap |= (1 << feature);
1182       sw->output_feature_bitmap |= (1 << INTF_OUTPUT_FEAT_DONE);
1183
1184     }
1185   else
1186     {                           /* delete */
1187
1188       sw->output_feature_bitmap &= ~(1 << feature);
1189       if (sw->output_feature_bitmap == (1 << INTF_OUTPUT_FEAT_DONE))
1190         sw->output_feature_bitmap = 0;
1191
1192     }
1193   return 0;
1194 }
1195
1196 clib_error_t *
1197 vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
1198 {
1199   vnet_interface_main_t *im = &vnm->interface_main;
1200   vlib_main_t *vm = vnm->vlib_main;
1201   vnet_hw_interface_t *hw;
1202   u8 *old_name;
1203   clib_error_t *error = 0;
1204
1205   hw = vnet_get_hw_interface (vnm, hw_if_index);
1206   if (!hw)
1207     {
1208       return clib_error_return (0,
1209                                 "unable to find hw interface for index %u",
1210                                 hw_if_index);
1211     }
1212
1213   old_name = hw->name;
1214
1215   /* set new hw->name */
1216   hw->name = format (0, "%s", new_name);
1217
1218   /* remove the old name to hw_if_index mapping and install the new one */
1219   hash_unset_mem (im->hw_interface_by_name, old_name);
1220   hash_set_mem (im->hw_interface_by_name, hw->name, hw_if_index);
1221
1222   /* rename tx/output nodes */
1223   vlib_node_rename (vm, hw->tx_node_index, "%v-tx", hw->name);
1224   vlib_node_rename (vm, hw->output_node_index, "%v-output", hw->name);
1225
1226   /* free the old name vector */
1227   vec_free (old_name);
1228
1229   return error;
1230 }
1231
1232 /*
1233  * fd.io coding-style-patch-verification: ON
1234  *
1235  * Local Variables:
1236  * eval: (c-set-style "gnu")
1237  * End:
1238  */