session: fix workers race to allocate lookup table
[vpp.git] / src / vnet / dev / handlers.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 #include <vnet/flow/flow.h>
11
12 VLIB_REGISTER_LOG_CLASS (dev_log, static) = {
13   .class_name = "dev",
14   .subclass_name = "handler",
15 };
16
17 clib_error_t *
18 vnet_dev_port_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hw,
19                                   u32 frame_size)
20 {
21   vlib_main_t *vm = vlib_get_main ();
22   vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hw->dev_instance);
23   vnet_dev_rv_t rv;
24
25   vnet_dev_port_cfg_change_req_t req = {
26     .type = VNET_DEV_PORT_CFG_MAX_RX_FRAME_SIZE,
27     .max_rx_frame_size = frame_size,
28   };
29
30   log_debug (p->dev, "size %u", frame_size);
31
32   rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req);
33   if (rv == VNET_DEV_ERR_NO_CHANGE)
34     return 0;
35
36   if (rv != VNET_DEV_OK)
37     return vnet_dev_port_err (vm, p, rv,
38                               "new max frame size is not valid for port");
39
40   if ((rv = vnet_dev_process_port_cfg_change_req (vm, p, &req)) != VNET_DEV_OK)
41     return vnet_dev_port_err (vm, p, rv,
42                               "device failed to change max frame size");
43
44   return 0;
45 }
46
47 u32
48 vnet_dev_port_eth_flag_change (vnet_main_t *vnm, vnet_hw_interface_t *hw,
49                                u32 flags)
50 {
51   vlib_main_t *vm = vlib_get_main ();
52   vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hw->dev_instance);
53   vnet_dev_rv_t rv;
54
55   vnet_dev_port_cfg_change_req_t req = {
56     .type = VNET_DEV_PORT_CFG_PROMISC_MODE,
57   };
58
59   switch (flags)
60     {
61     case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
62       log_debug (p->dev, "promisc off");
63       break;
64     case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
65       log_debug (p->dev, "promisc on");
66       req.promisc = 1;
67       break;
68     default:
69       return ~0;
70     }
71
72   rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req);
73   if (rv == VNET_DEV_ERR_NO_CHANGE)
74     return 0;
75
76   if (rv != VNET_DEV_OK)
77     return ~0;
78
79   rv = vnet_dev_process_port_cfg_change_req (vm, p, &req);
80   if (rv == VNET_DEV_OK || rv == VNET_DEV_ERR_NO_CHANGE)
81     return 0;
82   return ~0;
83 }
84
85 clib_error_t *
86 vnet_dev_port_mac_change (vnet_hw_interface_t *hi, const u8 *old,
87                           const u8 *new)
88 {
89   vlib_main_t *vm = vlib_get_main ();
90   vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance);
91   vnet_dev_rv_t rv;
92
93   vnet_dev_port_cfg_change_req_t req = {
94     .type = VNET_DEV_PORT_CFG_CHANGE_PRIMARY_HW_ADDR,
95   };
96
97   vnet_dev_set_hw_addr_eth_mac (&req.addr, new);
98
99   log_debug (p->dev, "new mac  %U", format_vnet_dev_hw_addr, &req.addr);
100
101   rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req);
102   if (rv == VNET_DEV_ERR_NO_CHANGE)
103     return 0;
104
105   if (rv != VNET_DEV_OK)
106     return vnet_dev_port_err (vm, p, rv, "hw address is not valid for port");
107
108   if ((rv = vnet_dev_process_port_cfg_change_req (vm, p, &req)) != VNET_DEV_OK)
109     return vnet_dev_port_err (vm, p, rv, "device failed to change hw address");
110
111   return 0;
112 }
113
114 clib_error_t *
115 vnet_dev_add_del_mac_address (vnet_hw_interface_t *hi, const u8 *address,
116                               u8 is_add)
117 {
118   vlib_main_t *vm = vlib_get_main ();
119   vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance);
120   vnet_dev_rv_t rv;
121
122   vnet_dev_port_cfg_change_req_t req = {
123     .type = is_add ? VNET_DEV_PORT_CFG_ADD_SECONDARY_HW_ADDR :
124                            VNET_DEV_PORT_CFG_REMOVE_SECONDARY_HW_ADDR,
125   };
126
127   vnet_dev_set_hw_addr_eth_mac (&req.addr, address);
128
129   log_debug (p->dev, "received (addr %U is_add %u", format_vnet_dev_hw_addr,
130              &req.addr, is_add);
131
132   rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req);
133   if (rv != VNET_DEV_OK)
134     return vnet_dev_port_err (vm, p, rv,
135                               "provided secondary hw addresses cannot "
136                               "be added/removed");
137
138   if ((rv = vnet_dev_process_port_cfg_change_req (vm, p, &req)) != VNET_DEV_OK)
139     return vnet_dev_port_err (
140       vm, p, rv, "device failed to add/remove secondary hw address");
141
142   return 0;
143 }
144
145 int
146 vnet_dev_flow_ops_fn (vnet_main_t *vnm, vnet_flow_dev_op_t op,
147                       u32 dev_instance, u32 flow_index, uword *private_data)
148 {
149   vlib_main_t *vm = vlib_get_main ();
150   vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (dev_instance);
151   vnet_dev_port_cfg_change_req_t req;
152   vnet_dev_rv_t rv;
153
154   switch (op)
155     {
156     case VNET_FLOW_DEV_OP_ADD_FLOW:
157       req.type = VNET_DEV_PORT_CFG_ADD_RX_FLOW;
158       break;
159     case VNET_FLOW_DEV_OP_DEL_FLOW:
160       req.type = VNET_DEV_PORT_CFG_DEL_RX_FLOW;
161       break;
162     case VNET_FLOW_DEV_OP_GET_COUNTER:
163       req.type = VNET_DEV_PORT_CFG_GET_RX_FLOW_COUNTER;
164       break;
165     case VNET_FLOW_DEV_OP_RESET_COUNTER:
166       req.type = VNET_DEV_PORT_CFG_RESET_RX_FLOW_COUNTER;
167       break;
168     default:
169       log_warn (p->dev, "unsupported request for flow_ops received");
170       return VNET_FLOW_ERROR_NOT_SUPPORTED;
171     }
172
173   req.flow_index = flow_index;
174   req.private_data = private_data;
175
176   rv = vnet_dev_port_cfg_change_req_validate (vm, p, &req);
177   if (rv != VNET_DEV_OK)
178     {
179       log_err (p->dev, "validation failed for flow_ops");
180       return VNET_FLOW_ERROR_NOT_SUPPORTED;
181     }
182
183   if ((rv = vnet_dev_process_port_cfg_change_req (vm, p, &req)) != VNET_DEV_OK)
184     {
185       log_err (p->dev, "request for flow_ops failed");
186       return vnet_dev_flow_err (vm, rv);
187     }
188
189   return 0;
190 }
191
192 clib_error_t *
193 vnet_dev_interface_set_rss_queues (vnet_main_t *vnm, vnet_hw_interface_t *hi,
194                                    clib_bitmap_t *bitmap)
195 {
196   vnet_dev_port_t *p = vnet_dev_get_port_from_dev_instance (hi->dev_instance);
197   log_warn (p->dev, "unsupported request for flow_ops received");
198   return vnet_error (VNET_ERR_UNSUPPORTED, "not implemented");
199 }
200
201 void
202 vnet_dev_clear_hw_interface_counters (u32 instance)
203 {
204   vnet_dev_port_t *port = vnet_dev_get_port_from_dev_instance (instance);
205   vlib_main_t *vm = vlib_get_main ();
206
207   vnet_dev_process_call_port_op_no_rv (vm, port, vnet_dev_port_clear_counters);
208 }
209
210 void
211 vnet_dev_set_interface_next_node (vnet_main_t *vnm, u32 hw_if_index,
212                                   u32 node_index)
213 {
214   vlib_main_t *vm = vlib_get_main ();
215   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
216   vnet_dev_port_t *port =
217     vnet_dev_get_port_from_dev_instance (hw->dev_instance);
218   int runtime_update = 0;
219
220   if (node_index == ~0)
221     {
222       port->intf.redirect_to_node_next_index = 0;
223       if (port->intf.feature_arc == 0)
224         {
225           port->intf.rx_next_index =
226             vnet_dev_default_next_index_by_port_type[port->attr.type];
227           runtime_update = 1;
228         }
229       port->intf.redirect_to_node = 0;
230     }
231   else
232     {
233       u16 next_index = vlib_node_add_next (vlib_get_main (),
234                                            port_rx_eth_node.index, node_index);
235       port->intf.redirect_to_node_next_index = next_index;
236       if (port->intf.feature_arc == 0)
237         {
238           port->intf.rx_next_index = next_index;
239           runtime_update = 1;
240         }
241       port->intf.redirect_to_node = 1;
242     }
243   port->intf.rx_next_index =
244     node_index == ~0 ?
245             vnet_dev_default_next_index_by_port_type[port->attr.type] :
246             node_index;
247
248   if (runtime_update)
249     {
250       foreach_vnet_dev_port_rx_queue (rxq, port)
251         vnet_dev_rx_queue_rt_request (
252           vm, rxq, (vnet_dev_rx_queue_rt_req_t){ .update_next_index = 1 });
253       log_debug (port->dev, "runtime update requested due to chgange in "
254                             "reditect-to-next configuration");
255     }
256 }