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