dev: startup.conf handling improvements
[vpp.git] / src / vnet / dev / config.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright (c) 2023 Cisco Systems, Inc.
3  */
4
5 #include "vppinfra/error.h"
6 #include "vppinfra/pool.h"
7 #include <vnet/vnet.h>
8 #include <vnet/ethernet/ethernet.h>
9 #include <vnet/dev/dev.h>
10 #include <vnet/dev/api.h>
11 #include <vnet/dev/log.h>
12
13 VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
14   .class_name = "dev",
15   .subclass_name = "config",
16 };
17
18 static clib_error_t *
19 vnet_dev_config_one_interface (vlib_main_t *vm, unformat_input_t *input,
20                                vnet_dev_api_create_port_if_args_t *args)
21 {
22   clib_error_t *err = 0;
23
24   log_debug (0, "port %u %U", args->port_id, format_unformat_input, input);
25
26   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
27     {
28       u32 n;
29
30       if (unformat (input, "name %U", unformat_c_string_array, args->intf_name,
31                     sizeof (args->intf_name)))
32         ;
33       else if (unformat (input, "num-rx-queues %u", &n))
34         args->num_rx_queues = n;
35       else if (unformat (input, "num-tx-queues %u", &n))
36         args->num_tx_queues = n;
37       else if (unformat (input, "rx-queue-size %u", &n))
38         args->rx_queue_size = n;
39       else if (unformat (input, "tx-queue-size %u", &n))
40         args->tx_queue_size = n;
41       else if (unformat (input, "flags %U", unformat_vnet_dev_port_flags,
42                          &args->flags))
43         ;
44       else if (unformat (input, "args %U", unformat_single_quoted_string,
45                          &args->args))
46         ;
47       else
48         {
49           err = clib_error_return (0, "unknown input '%U'",
50                                    format_unformat_error, input);
51           break;
52         }
53     }
54   return err;
55 }
56 static clib_error_t *
57 vnet_dev_config_one_device (vlib_main_t *vm, unformat_input_t *input,
58                             char *device_id)
59 {
60   log_debug (0, "device %s %U", device_id, format_unformat_input, input);
61   clib_error_t *err = 0;
62   vnet_dev_api_attach_args_t args = {};
63   vnet_dev_api_create_port_if_args_t *if_args_vec = 0, *if_args;
64
65   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
66     {
67       unformat_input_t sub_input;
68       u32 n;
69
70       if (unformat (input, "driver %U", unformat_c_string_array,
71                     args.driver_name, sizeof (args.driver_name)))
72         ;
73       else if (unformat (input, "flags %U", unformat_vnet_dev_flags,
74                          &args.flags))
75         ;
76       else if (unformat (input, "args %U", unformat_single_quoted_string,
77                          &args.args))
78         ;
79       else if (unformat (input, "port %u %U", &n, unformat_vlib_cli_sub_input,
80                          &sub_input))
81         {
82           vnet_dev_api_create_port_if_args_t *if_args;
83           vec_add2 (if_args_vec, if_args, 1);
84           if_args->port_id = n;
85           err = vnet_dev_config_one_interface (vm, &sub_input, if_args);
86           unformat_free (&sub_input);
87           if (err)
88             break;
89         }
90       else
91         {
92           err = clib_error_return (0, "unknown input '%U'",
93                                    format_unformat_error, input);
94           break;
95         }
96     }
97
98   if (err == 0)
99     {
100       vnet_dev_rv_t rv;
101
102       clib_memcpy (args.device_id, device_id, sizeof (args.device_id));
103       rv = vnet_dev_api_attach (vm, &args);
104       vec_free (args.args);
105
106       if (rv == VNET_DEV_OK)
107         {
108           vec_foreach (if_args, if_args_vec)
109             {
110               clib_memcpy (if_args->device_id, device_id,
111                            sizeof (if_args->device_id));
112               rv = vnet_dev_api_create_port_if (vm, if_args);
113               if (rv != VNET_DEV_OK)
114                 break;
115             }
116         }
117
118       if (rv != VNET_DEV_OK)
119         err = clib_error_return (0, "error: %U for device '%s'",
120                                  format_vnet_dev_rv, rv, device_id);
121     }
122
123   vec_free (if_args_vec);
124   return err;
125 }
126
127 uword
128 dev_config_process_node_fn (vlib_main_t *vm, vlib_node_runtime_t *rt,
129                             vlib_frame_t *f)
130 {
131   vnet_dev_main_t *dm = &vnet_dev_main;
132   unformat_input_t input;
133   clib_error_t *err = 0;
134
135   if (dm->startup_config == 0)
136     return 0;
137
138   unformat_init_vector (&input, dm->startup_config);
139   dm->startup_config = 0;
140
141   while (!err && unformat_check_input (&input) != UNFORMAT_END_OF_INPUT)
142     {
143       unformat_input_t sub_input;
144       vnet_dev_device_id_t device_id;
145       if (unformat (&input, "dev %U %U", unformat_c_string_array, device_id,
146                     sizeof (device_id), unformat_vlib_cli_sub_input,
147                     &sub_input))
148         {
149           err = vnet_dev_config_one_device (vm, &sub_input, device_id);
150           unformat_free (&sub_input);
151         }
152       else if (unformat (&input, "dev %U", unformat_c_string_array, device_id,
153                          sizeof (device_id)))
154         {
155           unformat_input_t no_input = {};
156           unformat_init_vector (&no_input, 0);
157           err = vnet_dev_config_one_device (vm, &no_input, device_id);
158           unformat_free (&no_input);
159         }
160       else
161         err = clib_error_return (0, "unknown input '%U'",
162                                  format_unformat_error, &input);
163     }
164
165   unformat_free (&input);
166
167   if (err)
168     {
169       log_err (0, "%U", format_clib_error, err);
170       clib_error_free (err);
171     }
172
173   vlib_node_set_state (vm, rt->node_index, VLIB_NODE_STATE_DISABLED);
174   vlib_node_rename (vm, rt->node_index, "deleted-%u", rt->node_index);
175   vec_add1 (dm->free_process_node_indices, rt->node_index);
176   return 0;
177 }
178
179 VLIB_REGISTER_NODE (dev_config_process_node) = {
180   .function = dev_config_process_node_fn,
181   .type = VLIB_NODE_TYPE_PROCESS,
182   .name = "dev-config",
183 };
184
185 static clib_error_t *
186 devices_config (vlib_main_t *vm, unformat_input_t *input)
187 {
188   vnet_dev_main_t *dm = &vnet_dev_main;
189   uword c;
190
191   while ((c = unformat_get_input (input)) != UNFORMAT_END_OF_INPUT)
192     vec_add1 (dm->startup_config, c);
193
194   return 0;
195 }
196
197 VLIB_CONFIG_FUNCTION (devices_config, "devices");