dev: add change_max_rx_frame_size capability
[vpp.git] / src / vnet / dev / port.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright (c) 2023 Cisco Systems, Inc.
3  */
4
5 #include <vnet/vnet.h>
6 #include <vnet/ethernet/ethernet.h>
7 #include <vnet/dev/dev.h>
8 #include <vnet/dev/counters.h>
9 #include <vnet/dev/log.h>
10
11 VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
12   .class_name = "dev",
13   .subclass_name = "port",
14 };
15
16 static uword
17 dummy_input_fn (vlib_main_t *vm, vlib_node_runtime_t *node,
18                 vlib_frame_t *frame)
19 {
20   ASSERT (0);
21   return 0;
22 }
23
24 VLIB_REGISTER_NODE (port_rx_eth_node) = {
25   .function = dummy_input_fn,
26   .name = "port-rx-eth",
27   .runtime_data_bytes = sizeof (vnet_dev_rx_node_runtime_t),
28   .type = VLIB_NODE_TYPE_INPUT,
29   .state = VLIB_NODE_STATE_DISABLED,
30   .n_next_nodes = VNET_DEV_ETH_RX_PORT_N_NEXTS,
31   .next_nodes = {
32 #define _(n, s) [VNET_DEV_ETH_RX_PORT_NEXT_##n] = s,
33   foreach_vnet_dev_port_rx_next
34 #undef _
35   },
36 };
37
38 u16 vnet_dev_default_next_index_by_port_type[] = {
39   [VNET_DEV_PORT_TYPE_ETHERNET] = VNET_DEV_ETH_RX_PORT_NEXT_ETH_INPUT,
40 };
41
42 VNET_FEATURE_ARC_INIT (eth_port_rx, static) = {
43   .arc_name = "port-rx-eth",
44   .start_nodes = VNET_FEATURES ("port-rx-eth"),
45   .last_in_arc = "ethernet-input",
46   .arc_index_ptr = &vnet_dev_main.eth_port_rx_feature_arc_index,
47 };
48
49 VNET_FEATURE_INIT (l2_patch, static) = {
50   .arc_name = "port-rx-eth",
51   .node_name = "l2-patch",
52   .runs_before = VNET_FEATURES ("ethernet-input"),
53 };
54
55 VNET_FEATURE_INIT (worker_handoff, static) = {
56   .arc_name = "port-rx-eth",
57   .node_name = "worker-handoff",
58   .runs_before = VNET_FEATURES ("ethernet-input"),
59 };
60
61 VNET_FEATURE_INIT (span_input, static) = {
62   .arc_name = "port-rx-eth",
63   .node_name = "span-input",
64   .runs_before = VNET_FEATURES ("ethernet-input"),
65 };
66
67 VNET_FEATURE_INIT (p2p_ethernet_node, static) = {
68   .arc_name = "port-rx-eth",
69   .node_name = "p2p-ethernet-input",
70   .runs_before = VNET_FEATURES ("ethernet-input"),
71 };
72
73 VNET_FEATURE_INIT (ethernet_input, static) = {
74   .arc_name = "port-rx-eth",
75   .node_name = "ethernet-input",
76   .runs_before = 0, /* not before any other features */
77 };
78
79 void
80 vnet_dev_port_free (vlib_main_t *vm, vnet_dev_port_t *port)
81 {
82   vnet_dev_t *dev = port->dev;
83
84   vnet_dev_port_validate (vm, port);
85
86   ASSERT (port->started == 0);
87
88   log_debug (dev, "port %u", port->port_id);
89
90   if (port->port_ops.free)
91     port->port_ops.free (vm, port);
92
93   pool_free (port->secondary_hw_addr);
94   pool_free (port->rx_queues);
95   pool_free (port->tx_queues);
96   pool_put_index (dev->ports, port->index);
97   clib_mem_free (port);
98 }
99
100 void
101 vnet_dev_port_update_tx_node_runtime (vlib_main_t *vm, vnet_dev_port_t *port)
102 {
103   vnet_dev_port_validate (vm, port);
104
105   foreach_vnet_dev_port_tx_queue (q, port)
106     {
107       u32 ti;
108       clib_bitmap_foreach (ti, q->assigned_threads)
109         {
110           vlib_main_t *tvm = vlib_get_main_by_index (ti);
111           vlib_node_runtime_t *nr =
112             vlib_node_get_runtime (tvm, port->intf.tx_node_index);
113           vnet_dev_tx_node_runtime_t *tnr = vnet_dev_get_tx_node_runtime (nr);
114           tnr->hw_if_index = port->intf.hw_if_index;
115           tnr->tx_queue = q;
116         }
117     }
118 }
119
120 void
121 vnet_dev_port_stop (vlib_main_t *vm, vnet_dev_port_t *port)
122 {
123   vnet_dev_t *dev = port->dev;
124   vnet_dev_rt_op_t *ops = 0;
125   u16 n_threads = vlib_get_n_threads ();
126
127   log_debug (dev, "stopping port %u", port->port_id);
128
129   for (u16 i = 0; i < n_threads; i++)
130     {
131       vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
132       vec_add1 (ops, op);
133     }
134
135   vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
136   vec_free (ops);
137
138   port->port_ops.stop (vm, port);
139
140   foreach_vnet_dev_port_rx_queue (q, port)
141     {
142       q->started = 0;
143       log_debug (dev, "port %u rx queue %u stopped", port->port_id,
144                  q->queue_id);
145     }
146
147   foreach_vnet_dev_port_tx_queue (q, port)
148     {
149       q->started = 0;
150       log_debug (dev, "port %u tx queue %u stopped", port->port_id,
151                  q->queue_id);
152     }
153
154   log_debug (dev, "port %u stopped", port->port_id);
155   port->started = 0;
156 }
157
158 vnet_dev_rv_t
159 vnet_dev_port_start_all_rx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
160 {
161   vnet_dev_rv_t rv = VNET_DEV_OK;
162
163   vnet_dev_port_validate (vm, port);
164
165   foreach_vnet_dev_port_rx_queue (q, port)
166     {
167       rv = vnet_dev_rx_queue_start (vm, q);
168       if (rv != VNET_DEV_OK)
169         return rv;
170     }
171   return rv;
172 }
173
174 vnet_dev_rv_t
175 vnet_dev_port_start_all_tx_queues (vlib_main_t *vm, vnet_dev_port_t *port)
176 {
177   vnet_dev_rv_t rv = VNET_DEV_OK;
178
179   vnet_dev_port_validate (vm, port);
180
181   foreach_vnet_dev_port_tx_queue (q, port)
182     {
183       rv = vnet_dev_tx_queue_start (vm, q);
184       if (rv != VNET_DEV_OK)
185         return rv;
186     }
187   return rv;
188 }
189
190 vnet_dev_rv_t
191 vnet_dev_port_start (vlib_main_t *vm, vnet_dev_port_t *port)
192 {
193   u16 n_threads = vlib_get_n_threads ();
194   vnet_dev_t *dev = port->dev;
195   vnet_dev_rt_op_t *ops = 0;
196   vnet_dev_rv_t rv;
197
198   vnet_dev_port_validate (vm, port);
199
200   log_debug (dev, "starting port %u", port->port_id);
201
202   vnet_dev_port_update_tx_node_runtime (vm, port);
203
204   if ((rv = port->port_ops.start (vm, port)) != VNET_DEV_OK)
205     {
206       vnet_dev_port_stop (vm, port);
207       return rv;
208     }
209
210   for (u16 i = 0; i < n_threads; i++)
211     {
212       vnet_dev_rt_op_t op = { .thread_index = i, .port = port };
213       vec_add1 (ops, op);
214     }
215
216   vnet_dev_rt_exec_ops (vm, dev, ops, vec_len (ops));
217   vec_free (ops);
218
219   foreach_vnet_dev_port_rx_queue (q, port)
220     if (q->enabled)
221       {
222         log_debug (dev, "port %u rx queue %u started", port->port_id,
223                    q->queue_id);
224         q->started = 1;
225       }
226
227   foreach_vnet_dev_port_tx_queue (q, port)
228     if (q->enabled)
229       {
230         log_debug (dev, "port %u tx queue %u started", port->port_id,
231                    q->queue_id);
232         q->started = 1;
233       }
234
235   port->started = 1;
236   log_debug (dev, "port %u started", port->port_id);
237
238   return VNET_DEV_OK;
239 }
240
241 vnet_dev_rv_t
242 vnet_dev_port_add (vlib_main_t *vm, vnet_dev_t *dev, vnet_dev_port_id_t id,
243                    vnet_dev_port_add_args_t *args)
244 {
245   vnet_dev_port_t **pp, *port;
246   vnet_dev_rv_t rv = VNET_DEV_OK;
247
248   ASSERT (args->port.attr.type != VNET_DEV_PORT_TYPE_UNKNOWN);
249   ASSERT (args->port.attr.max_supported_rx_frame_size);
250
251   port =
252     vnet_dev_alloc_with_data (sizeof (vnet_dev_port_t), args->port.data_size);
253   pool_get (dev->ports, pp);
254   pp[0] = port;
255   clib_memcpy (vnet_dev_get_port_data (port), args->port.initial_data,
256                args->port.data_size);
257   port->port_id = id;
258   port->index = pp - dev->ports;
259   port->dev = dev;
260   port->attr = args->port.attr;
261   port->rx_queue_config = args->rx_queue.config;
262   port->tx_queue_config = args->tx_queue.config;
263   port->rx_queue_ops = args->rx_queue.ops;
264   port->tx_queue_ops = args->tx_queue.ops;
265   port->port_ops = args->port.ops;
266   port->rx_node = *args->rx_node;
267   port->tx_node = *args->tx_node;
268
269   /* defaults out of port attributes */
270   port->max_rx_frame_size = args->port.attr.max_supported_rx_frame_size;
271   port->primary_hw_addr = args->port.attr.hw_addr;
272
273   if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
274     {
275       if (port->max_rx_frame_size > 1514 &&
276           port->attr.caps.change_max_rx_frame_size)
277         port->max_rx_frame_size = 1514;
278     }
279
280   if (port->port_ops.alloc)
281     rv = port->port_ops.alloc (vm, port);
282
283   if (rv == VNET_DEV_OK)
284     port->initialized = 1;
285
286   return rv;
287 }
288
289 vnet_dev_rv_t
290 vnet_dev_port_cfg_change_req_validate (vlib_main_t *vm, vnet_dev_port_t *port,
291                                        vnet_dev_port_cfg_change_req_t *req)
292 {
293   vnet_dev_rv_t rv;
294   vnet_dev_hw_addr_t *addr;
295   int found;
296
297   if (req->validated)
298     return VNET_DEV_OK;
299
300   switch (req->type)
301     {
302     case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
303       if (req->max_rx_frame_size > port->attr.max_supported_rx_frame_size)
304         return VNET_DEV_ERR_INVALID_VALUE;
305       if (req->max_rx_frame_size == port->max_rx_frame_size)
306         return VNET_DEV_ERR_NO_CHANGE;
307       break;
308
309     case VNET_DEV_PORT_CFG_PROMISC_MODE:
310       if (req->promisc == port->promisc)
311         return VNET_DEV_ERR_NO_CHANGE;
312       break;
313
314     case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
315       if (clib_memcmp (&req->addr, &port->primary_hw_addr,
316                        sizeof (vnet_dev_hw_addr_t)) == 0)
317         return VNET_DEV_ERR_NO_CHANGE;
318       break;
319
320     case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
321       pool_foreach (addr, port->secondary_hw_addr)
322         if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
323           return VNET_DEV_ERR_ALREADY_EXISTS;
324       break;
325
326     case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
327       found = 0;
328       pool_foreach (addr, port->secondary_hw_addr)
329         if (clib_memcmp (addr, &req->addr, sizeof (*addr)) == 0)
330           found = 1;
331       if (!found)
332         return VNET_DEV_ERR_NO_SUCH_ENTRY;
333       break;
334
335     default:
336       break;
337     }
338
339   if (port->port_ops.config_change_validate)
340     {
341       rv = port->port_ops.config_change_validate (vm, port, req);
342       if (rv != VNET_DEV_OK)
343         return rv;
344     }
345   else
346     return VNET_DEV_ERR_NOT_SUPPORTED;
347
348   req->validated = 1;
349   return VNET_DEV_OK;
350 }
351
352 vnet_dev_rv_t
353 vnet_dev_port_cfg_change (vlib_main_t *vm, vnet_dev_port_t *port,
354                           vnet_dev_port_cfg_change_req_t *req)
355 {
356   vnet_dev_rv_t rv = VNET_DEV_OK;
357   vnet_dev_hw_addr_t *a;
358   vnet_dev_rx_queue_t *rxq = 0;
359   u8 enable = 0;
360
361   vnet_dev_port_validate (vm, port);
362
363   if (req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE ||
364       req->type == VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE)
365     {
366       if (req->all_queues == 0)
367         {
368           rxq = vnet_dev_port_get_rx_queue_by_id (port, req->queue_id);
369           if (rxq == 0)
370             return VNET_DEV_ERR_BUG;
371         }
372     }
373
374   if ((rv = vnet_dev_port_cfg_change_req_validate (vm, port, req)))
375     return rv;
376
377   if (port->port_ops.config_change)
378     rv = port->port_ops.config_change (vm, port, req);
379   else
380     return VNET_DEV_ERR_NOT_SUPPORTED;
381
382   if (rv != VNET_DEV_OK)
383     return rv;
384
385   switch (req->type)
386     {
387     case VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE:
388       port->max_rx_frame_size = req->max_rx_frame_size;
389       break;
390
391     case VNET_DEV_PORT_CFG_PROMISC_MODE:
392       port->promisc = req->promisc;
393       break;
394
395     case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_ENABLE:
396       enable = 1;
397     case VNET_DEV_PORT_CFG_RXQ_INTR_MODE_DISABLE:
398       if (req->all_queues)
399         {
400           clib_bitmap_t *bmp = 0;
401           vnet_dev_rt_op_t *ops = 0;
402           u32 i;
403
404           foreach_vnet_dev_port_rx_queue (q, port)
405             {
406               q->interrupt_mode = enable;
407               bmp = clib_bitmap_set (bmp, q->rx_thread_index, 1);
408             }
409
410           clib_bitmap_foreach (i, bmp)
411             {
412               vnet_dev_rt_op_t op = { .port = port, .thread_index = i };
413               vec_add1 (ops, op);
414             }
415
416           vnet_dev_rt_exec_ops (vm, port->dev, ops, vec_len (ops));
417           clib_bitmap_free (bmp);
418           vec_free (ops);
419         }
420       else
421         {
422           rxq->interrupt_mode = enable;
423           vnet_dev_rt_exec_ops (vm, port->dev,
424                                 &(vnet_dev_rt_op_t){
425                                   .port = port,
426                                   .thread_index = rxq->rx_thread_index,
427                                 },
428                                 1);
429         }
430       break;
431
432     case VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR:
433       clib_memcpy (&port->primary_hw_addr, &req->addr,
434                    sizeof (vnet_dev_hw_addr_t));
435       break;
436
437     case VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR:
438       pool_get (port->secondary_hw_addr, a);
439       clib_memcpy (a, &req->addr, sizeof (vnet_dev_hw_addr_t));
440       break;
441
442     case VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR:
443       pool_foreach (a, port->secondary_hw_addr)
444         if (clib_memcmp (a, &req->addr, sizeof (vnet_dev_hw_addr_t)) == 0)
445           {
446             pool_put (port->secondary_hw_addr, a);
447             break;
448           }
449       break;
450
451     default:
452       break;
453     }
454
455   return VNET_DEV_OK;
456 }
457
458 void
459 vnet_dev_port_state_change (vlib_main_t *vm, vnet_dev_port_t *port,
460                             vnet_dev_port_state_changes_t changes)
461 {
462   vnet_main_t *vnm = vnet_get_main ();
463
464   vnet_dev_port_validate (vm, port);
465
466   if (changes.change.link_speed)
467     {
468       port->speed = changes.link_speed;
469       if (port->interface_created)
470         vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
471                                           changes.link_speed);
472       log_debug (port->dev, "port speed changed to %u", changes.link_speed);
473     }
474
475   if (changes.change.link_state)
476     {
477       port->link_up = changes.link_state;
478       if (port->interface_created)
479         vnet_hw_interface_set_flags (
480           vnm, port->intf.hw_if_index,
481           changes.link_state ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
482       log_debug (port->dev, "port link state changed to %s",
483                  changes.link_state ? "up" : "down");
484     }
485 }
486
487 void
488 vnet_dev_port_add_counters (vlib_main_t *vm, vnet_dev_port_t *port,
489                             vnet_dev_counter_t *counters, u16 n_counters)
490 {
491   vnet_dev_port_validate (vm, port);
492
493   port->counter_main =
494     vnet_dev_counters_alloc (vm, counters, n_counters, "%s port %u counters",
495                              port->dev->device_id, port->port_id);
496 }
497
498 void
499 vnet_dev_port_free_counters (vlib_main_t *vm, vnet_dev_port_t *port)
500 {
501   vnet_dev_port_validate (vm, port);
502
503   if (port->counter_main)
504     vnet_dev_counters_free (vm, port->counter_main);
505 }
506
507 vnet_dev_rv_t
508 vnet_dev_port_if_create (vlib_main_t *vm, vnet_dev_port_t *port)
509 {
510   vnet_main_t *vnm = vnet_get_main ();
511   u16 n_threads = vlib_get_n_threads ();
512   vnet_dev_main_t *dm = &vnet_dev_main;
513   vnet_dev_t *dev = port->dev;
514   vnet_dev_port_t **pp;
515   vnet_dev_rv_t rv;
516   u16 ti = 0;
517
518   if (port->intf.name[0] == 0)
519     {
520       u8 *s;
521       s = format (0, "%s%u/%u",
522                   dm->drivers[port->dev->driver_index].registration->name,
523                   port->dev->index, port->index);
524       u32 n = vec_len (s);
525
526       if (n >= sizeof (port->intf.name))
527         {
528           vec_free (s);
529           return VNET_DEV_ERR_BUG;
530         }
531       clib_memcpy (port->intf.name, s, n);
532       port->intf.name[n] = 0;
533       vec_free (s);
534     }
535
536   log_debug (
537     dev, "allocating %u rx queues with size %u and %u tx queues with size %u",
538     port->intf.num_rx_queues, port->intf.rxq_sz, port->intf.num_tx_queues,
539     port->intf.txq_sz);
540
541   for (int i = 0; i < port->intf.num_rx_queues; i++)
542     if ((rv = vnet_dev_rx_queue_alloc (vm, port, port->intf.rxq_sz)) !=
543         VNET_DEV_OK)
544       goto error;
545
546   for (u32 i = 0; i < port->intf.num_tx_queues; i++)
547     if ((rv = vnet_dev_tx_queue_alloc (vm, port, port->intf.txq_sz)) !=
548         VNET_DEV_OK)
549       goto error;
550
551   foreach_vnet_dev_port_tx_queue (q, port)
552     {
553       q->assigned_threads = clib_bitmap_set (q->assigned_threads, ti, 1);
554       log_debug (dev, "port %u tx queue %u assigned to thread %u",
555                  port->port_id, q->queue_id, ti);
556       if (++ti >= n_threads)
557         break;
558     }
559
560   /* pool of port pointers helps us to assign unique dev_instance */
561   pool_get (dm->ports_by_dev_instance, pp);
562   port->intf.dev_instance = pp - dm->ports_by_dev_instance;
563   pp[0] = port;
564
565   if (port->attr.type == VNET_DEV_PORT_TYPE_ETHERNET)
566     {
567       vnet_device_class_t *dev_class;
568       vnet_dev_driver_t *driver;
569       vnet_sw_interface_t *sw;
570       vnet_hw_interface_t *hw;
571       u32 rx_node_index;
572
573       driver = pool_elt_at_index (dm->drivers, dev->driver_index);
574
575       /* hack to provide per-port tx node function */
576       dev_class = vnet_get_device_class (vnm, driver->dev_class_index);
577       dev_class->tx_fn_registrations = port->tx_node.registrations;
578       dev_class->format_tx_trace = port->tx_node.format_trace;
579       dev_class->tx_function_error_counters = port->tx_node.error_counters;
580       dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
581
582       /* create new interface including tx and output nodes */
583       port->intf.hw_if_index = vnet_eth_register_interface (
584         vnm, &(vnet_eth_interface_registration_t){
585                .address = port->primary_hw_addr.eth_mac,
586                .max_frame_size = port->max_rx_frame_size,
587                .dev_class_index = driver->dev_class_index,
588                .dev_instance = port->intf.dev_instance,
589                .cb.set_max_frame_size = vnet_dev_port_set_max_frame_size,
590                .cb.flag_change = vnet_dev_port_eth_flag_change,
591              });
592
593       sw = vnet_get_hw_sw_interface (vnm, port->intf.hw_if_index);
594       hw = vnet_get_hw_interface (vnm, port->intf.hw_if_index);
595       port->intf.sw_if_index = sw->sw_if_index;
596       vnet_hw_interface_set_flags (
597         vnm, port->intf.hw_if_index,
598         port->link_up ? VNET_HW_INTERFACE_FLAG_LINK_UP : 0);
599       if (port->speed)
600         vnet_hw_interface_set_link_speed (vnm, port->intf.hw_if_index,
601                                           port->speed);
602
603       port->intf.tx_node_index = hw->tx_node_index;
604
605       /* create / reuse rx node */
606       if (vec_len (dm->free_rx_node_indices))
607         {
608           vlib_node_t *n;
609           rx_node_index = vec_pop (dm->free_rx_node_indices);
610           vlib_node_rename (vm, rx_node_index, "%s-rx", port->intf.name);
611           n = vlib_get_node (vm, rx_node_index);
612           n->function = vlib_node_get_preferred_node_fn_variant (
613             vm, port->rx_node.registrations);
614           n->format_trace = port->rx_node.format_trace;
615           vlib_register_errors (vm, rx_node_index,
616                                 port->rx_node.n_error_counters, 0,
617                                 port->rx_node.error_counters);
618         }
619       else
620         {
621           dev_class->format_tx_trace = port->tx_node.format_trace;
622           dev_class->tx_function_error_counters = port->tx_node.error_counters;
623           dev_class->tx_function_n_errors = port->tx_node.n_error_counters;
624           vlib_node_registration_t rx_node_reg = {
625             .sibling_of = "port-rx-eth",
626             .type = VLIB_NODE_TYPE_INPUT,
627             .state = VLIB_NODE_STATE_DISABLED,
628             .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
629             .node_fn_registrations = port->rx_node.registrations,
630             .format_trace = port->rx_node.format_trace,
631             .error_counters = port->rx_node.error_counters,
632             .n_errors = port->rx_node.n_error_counters,
633           };
634           rx_node_index =
635             vlib_register_node (vm, &rx_node_reg, "%s-rx", port->intf.name);
636         }
637       port->rx_node_assigned = 1;
638       port->intf.rx_node_index = rx_node_index;
639       port->intf.rx_next_index =
640         vnet_dev_default_next_index_by_port_type[port->attr.type];
641
642       vlib_worker_thread_node_runtime_update ();
643       log_debug (dev,
644                  "ethernet interface created, hw_if_index %u sw_if_index %u "
645                  "rx_node_index %u tx_node_index %u",
646                  port->intf.hw_if_index, port->intf.sw_if_index,
647                  port->intf.rx_node_index, port->intf.tx_node_index);
648     }
649
650   port->interface_created = 1;
651   foreach_vnet_dev_port_rx_queue (q, port)
652     {
653       vnet_buffer (&q->buffer_template)->sw_if_index[VLIB_RX] =
654         port->intf.sw_if_index;
655       /* poison to catch node not calling runtime update function */
656       q->next_index = ~0;
657       q->interrupt_mode = port->intf.default_is_intr_mode;
658       vnet_dev_rx_queue_rt_request (
659         vm, q, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
660     }
661
662   vnet_dev_port_update_tx_node_runtime (vm, port);
663
664   if (port->port_ops.init)
665     rv = port->port_ops.init (vm, port);
666
667 error:
668   if (rv != VNET_DEV_OK)
669     vnet_dev_port_if_remove (vm, port);
670   return rv;
671 }
672
673 vnet_dev_rv_t
674 vnet_dev_port_if_remove (vlib_main_t *vm, vnet_dev_port_t *port)
675 {
676   vnet_dev_main_t *dm = &vnet_dev_main;
677   vnet_main_t *vnm = vnet_get_main ();
678
679   vnet_dev_port_validate (vm, port);
680
681   if (port->started)
682     vnet_dev_port_stop (vm, port);
683
684   if (port->rx_node_assigned)
685     {
686       vlib_node_rename (vm, port->intf.rx_node_index, "deleted-%u",
687                         port->intf.rx_node_index);
688       vec_add1 (dm->free_rx_node_indices, port->intf.rx_node_index);
689       port->rx_node_assigned = 0;
690     }
691
692   if (port->interface_created)
693     {
694       vlib_worker_thread_barrier_sync (vm);
695       vnet_delete_hw_interface (vnm, port->intf.hw_if_index);
696       vlib_worker_thread_barrier_release (vm);
697       pool_put_index (dm->ports_by_dev_instance, port->intf.dev_instance);
698       port->interface_created = 0;
699     }
700
701   port->intf = (typeof (port->intf)){};
702
703   if (port->port_ops.deinit)
704     port->port_ops.deinit (vm, port);
705
706   foreach_vnet_dev_port_tx_queue (q, port)
707     vnet_dev_tx_queue_free (vm, q);
708
709   foreach_vnet_dev_port_rx_queue (q, port)
710     vnet_dev_rx_queue_free (vm, q);
711
712   vnet_dev_port_free_counters (vm, port);
713
714   return VNET_DEV_OK;
715 }
716 void
717 vnet_dev_port_clear_counters (vlib_main_t *vm, vnet_dev_port_t *port)
718 {
719   if (port->counter_main)
720     vnet_dev_counters_clear (vm, port->counter_main);
721
722   foreach_vnet_dev_port_rx_queue (q, port)
723     if (q->counter_main)
724       vnet_dev_counters_clear (vm, q->counter_main);
725
726   foreach_vnet_dev_port_tx_queue (q, port)
727     if (q->counter_main)
728       vnet_dev_counters_clear (vm, q->counter_main);
729
730   log_notice (port->dev, "counters cleared on port %u", port->port_id);
731 }