1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <rte_devargs.h>
6 #include <rte_pci.h>
7 #include <rte_bus_pci.h>
8 #include <rte_kvargs.h>
9 
10 #include "rte_eth_bond.h"
11 #include "eth_bond_private.h"
12 
13 const char *pmd_bond_init_valid_arguments[] = {
14 	PMD_BOND_SLAVE_PORT_KVARG,
15 	PMD_BOND_PRIMARY_SLAVE_KVARG,
16 	PMD_BOND_MODE_KVARG,
17 	PMD_BOND_XMIT_POLICY_KVARG,
18 	PMD_BOND_SOCKET_ID_KVARG,
19 	PMD_BOND_MAC_ADDR_KVARG,
20 	PMD_BOND_AGG_MODE_KVARG,
21 	"driver",
22 	NULL
23 };
24 
25 static inline int
find_port_id_by_pci_addr(const struct rte_pci_addr * pci_addr)26 find_port_id_by_pci_addr(const struct rte_pci_addr *pci_addr)
27 {
28 	struct rte_pci_device *pci_dev;
29 	struct rte_pci_addr *eth_pci_addr;
30 	unsigned i;
31 
32 	RTE_ETH_FOREACH_DEV(i) {
33 		pci_dev = RTE_ETH_DEV_TO_PCI(&rte_eth_devices[i]);
34 		eth_pci_addr = &pci_dev->addr;
35 
36 		if (pci_addr->bus == eth_pci_addr->bus &&
37 			pci_addr->devid == eth_pci_addr->devid &&
38 			pci_addr->domain == eth_pci_addr->domain &&
39 			pci_addr->function == eth_pci_addr->function)
40 			return i;
41 	}
42 	return -1;
43 }
44 
45 static inline int
find_port_id_by_dev_name(const char * name)46 find_port_id_by_dev_name(const char *name)
47 {
48 	unsigned i;
49 
50 	RTE_ETH_FOREACH_DEV(i) {
51 		if (rte_eth_devices[i].data == NULL)
52 			continue;
53 
54 		if (strcmp(rte_eth_devices[i].device->name, name) == 0)
55 			return i;
56 	}
57 	return -1;
58 }
59 
60 static inline int
bond_pci_addr_cmp(const struct rte_device * dev,const void * _pci_addr)61 bond_pci_addr_cmp(const struct rte_device *dev, const void *_pci_addr)
62 {
63 	const struct rte_pci_device *pdev = RTE_DEV_TO_PCI_CONST(dev);
64 	const struct rte_pci_addr *paddr = _pci_addr;
65 
66 	return rte_pci_addr_cmp(&pdev->addr, paddr);
67 }
68 
69 /**
70  * Parses a port identifier string to a port id by pci address, then by name,
71  * and finally port id.
72  */
73 static inline int
parse_port_id(const char * port_str)74 parse_port_id(const char *port_str)
75 {
76 	struct rte_pci_addr dev_addr;
77 	struct rte_bus *pci_bus;
78 	struct rte_device *dev;
79 	int port_id;
80 
81 	pci_bus = rte_bus_find_by_name("pci");
82 	if (pci_bus == NULL) {
83 		RTE_BOND_LOG(ERR, "unable to find PCI bus\n");
84 		return -1;
85 	}
86 
87 	/* try parsing as pci address, physical devices */
88 	if (pci_bus->parse(port_str, &dev_addr) == 0) {
89 		dev = pci_bus->find_device(NULL, bond_pci_addr_cmp, &dev_addr);
90 		if (dev == NULL) {
91 			RTE_BOND_LOG(ERR, "unable to find PCI device");
92 			return -1;
93 		}
94 		port_id = find_port_id_by_pci_addr(&dev_addr);
95 		if (port_id < 0)
96 			return -1;
97 	} else {
98 		/* try parsing as device name, virtual devices */
99 		port_id = find_port_id_by_dev_name(port_str);
100 		if (port_id < 0) {
101 			char *end;
102 			errno = 0;
103 
104 			/* try parsing as port id */
105 			port_id = strtol(port_str, &end, 10);
106 			if (*end != 0 || errno != 0)
107 				return -1;
108 		}
109 	}
110 
111 	if (port_id < 0 || port_id > RTE_MAX_ETHPORTS) {
112 		RTE_BOND_LOG(ERR, "Slave port specified (%s) outside expected range",
113 				port_str);
114 		return -1;
115 	}
116 	return port_id;
117 }
118 
119 int
bond_ethdev_parse_slave_port_kvarg(const char * key,const char * value,void * extra_args)120 bond_ethdev_parse_slave_port_kvarg(const char *key,
121 		const char *value, void *extra_args)
122 {
123 	struct bond_ethdev_slave_ports *slave_ports;
124 
125 	if (value == NULL || extra_args == NULL)
126 		return -1;
127 
128 	slave_ports = extra_args;
129 
130 	if (strcmp(key, PMD_BOND_SLAVE_PORT_KVARG) == 0) {
131 		int port_id = parse_port_id(value);
132 		if (port_id < 0) {
133 			RTE_BOND_LOG(ERR, "Invalid slave port value (%s) specified",
134 				     value);
135 			return -1;
136 		} else
137 			slave_ports->slaves[slave_ports->slave_count++] =
138 					port_id;
139 	}
140 	return 0;
141 }
142 
143 int
bond_ethdev_parse_slave_mode_kvarg(const char * key __rte_unused,const char * value,void * extra_args)144 bond_ethdev_parse_slave_mode_kvarg(const char *key __rte_unused,
145 		const char *value, void *extra_args)
146 {
147 	uint8_t *mode;
148 	char *endptr;
149 
150 	if (value == NULL || extra_args == NULL)
151 		return -1;
152 
153 	mode = extra_args;
154 
155 	errno = 0;
156 	*mode = strtol(value, &endptr, 10);
157 	if (*endptr != 0 || errno != 0)
158 		return -1;
159 
160 	/* validate mode value */
161 	switch (*mode) {
162 	case BONDING_MODE_ROUND_ROBIN:
163 	case BONDING_MODE_ACTIVE_BACKUP:
164 	case BONDING_MODE_BALANCE:
165 	case BONDING_MODE_BROADCAST:
166 	case BONDING_MODE_8023AD:
167 	case BONDING_MODE_TLB:
168 	case BONDING_MODE_ALB:
169 		return 0;
170 	default:
171 		RTE_BOND_LOG(ERR, "Invalid slave mode value (%s) specified", value);
172 		return -1;
173 	}
174 }
175 
176 int
bond_ethdev_parse_slave_agg_mode_kvarg(const char * key __rte_unused,const char * value,void * extra_args)177 bond_ethdev_parse_slave_agg_mode_kvarg(const char *key __rte_unused,
178 		const char *value, void *extra_args)
179 {
180 	uint8_t *agg_mode;
181 
182 	if (value == NULL || extra_args == NULL)
183 		return -1;
184 
185 	agg_mode = extra_args;
186 
187 	errno = 0;
188 	if (strncmp(value, "stable", 6) == 0)
189 		*agg_mode = AGG_STABLE;
190 
191 	if (strncmp(value, "bandwidth", 9) == 0)
192 		*agg_mode = AGG_BANDWIDTH;
193 
194 	if (strncmp(value, "count", 5) == 0)
195 		*agg_mode = AGG_COUNT;
196 
197 	switch (*agg_mode) {
198 	case AGG_STABLE:
199 	case AGG_BANDWIDTH:
200 	case AGG_COUNT:
201 		return 0;
202 	default:
203 		RTE_BOND_LOG(ERR, "Invalid agg mode value stable/bandwidth/count");
204 		return -1;
205 	}
206 }
207 
208 int
bond_ethdev_parse_socket_id_kvarg(const char * key __rte_unused,const char * value,void * extra_args)209 bond_ethdev_parse_socket_id_kvarg(const char *key __rte_unused,
210 		const char *value, void *extra_args)
211 {
212 	int socket_id;
213 	char *endptr;
214 
215 	if (value == NULL || extra_args == NULL)
216 		return -1;
217 
218 	errno = 0;
219 	socket_id = (uint8_t)strtol(value, &endptr, 10);
220 	if (*endptr != 0 || errno != 0)
221 		return -1;
222 
223 	/* validate socket id value */
224 	if (socket_id >= 0) {
225 		*(uint8_t *)extra_args = (uint8_t)socket_id;
226 		return 0;
227 	}
228 	return -1;
229 }
230 
231 int
bond_ethdev_parse_primary_slave_port_id_kvarg(const char * key __rte_unused,const char * value,void * extra_args)232 bond_ethdev_parse_primary_slave_port_id_kvarg(const char *key __rte_unused,
233 		const char *value, void *extra_args)
234 {
235 	int primary_slave_port_id;
236 
237 	if (value == NULL || extra_args == NULL)
238 		return -1;
239 
240 	primary_slave_port_id = parse_port_id(value);
241 	if (primary_slave_port_id < 0)
242 		return -1;
243 
244 	*(uint16_t *)extra_args = (uint16_t)primary_slave_port_id;
245 
246 	return 0;
247 }
248 
249 int
bond_ethdev_parse_balance_xmit_policy_kvarg(const char * key __rte_unused,const char * value,void * extra_args)250 bond_ethdev_parse_balance_xmit_policy_kvarg(const char *key __rte_unused,
251 		const char *value, void *extra_args)
252 {
253 	uint8_t *xmit_policy;
254 
255 	if (value == NULL || extra_args == NULL)
256 		return -1;
257 
258 	xmit_policy = extra_args;
259 
260 	if (strcmp(PMD_BOND_XMIT_POLICY_LAYER2_KVARG, value) == 0)
261 		*xmit_policy = BALANCE_XMIT_POLICY_LAYER2;
262 	else if (strcmp(PMD_BOND_XMIT_POLICY_LAYER23_KVARG, value) == 0)
263 		*xmit_policy = BALANCE_XMIT_POLICY_LAYER23;
264 	else if (strcmp(PMD_BOND_XMIT_POLICY_LAYER34_KVARG, value) == 0)
265 		*xmit_policy = BALANCE_XMIT_POLICY_LAYER34;
266 	else
267 		return -1;
268 
269 	return 0;
270 }
271 
272 int
bond_ethdev_parse_bond_mac_addr_kvarg(const char * key __rte_unused,const char * value,void * extra_args)273 bond_ethdev_parse_bond_mac_addr_kvarg(const char *key __rte_unused,
274 		const char *value, void *extra_args)
275 {
276 	if (value == NULL || extra_args == NULL)
277 		return -1;
278 
279 	/* Parse MAC */
280 	return rte_ether_unformat_addr(value, extra_args);
281 }
282 
283 int
bond_ethdev_parse_time_ms_kvarg(const char * key __rte_unused,const char * value,void * extra_args)284 bond_ethdev_parse_time_ms_kvarg(const char *key __rte_unused,
285 		const char *value, void *extra_args)
286 {
287 	uint32_t time_ms;
288 	char *endptr;
289 
290 	if (value == NULL || extra_args == NULL)
291 		return -1;
292 
293 	errno = 0;
294 	time_ms = (uint32_t)strtol(value, &endptr, 10);
295 	if (*endptr != 0 || errno != 0)
296 		return -1;
297 
298 	*(uint32_t *)extra_args = time_ms;
299 
300 	return 0;
301 }
302