xref: /aosp_15_r20/external/libnl/lib/route/link/sriov.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2016 Intel Corp. All rights reserved.
4  * Copyright (c) 2016 Jef Oliver <[email protected]>
5  */
6 
7 /**
8  * @ingroup link
9  * @defgroup sriov SRIOV
10  * SR-IOV VF link module
11  *
12  * @details
13  * SR-IOV (Single Root Input/Output Virtualization) is a network interface
14  * that allows for the isolation of the PCI Express resources. In a virtual
15  * environment, SR-IOV allows multiple virtual machines can share a single
16  * PCI Express hardware interface. This is done via VFs (Virtual Functions),
17  * virtual hardware devices with their own PCI address.
18  *
19  * @{
20  */
21 
22 #include "nl-default.h"
23 
24 #include <linux/if_ether.h>
25 #include <linux/if_link.h>
26 
27 #include <netlink/netlink.h>
28 #include <netlink/route/link.h>
29 #include <netlink/route/link/sriov.h>
30 
31 #include "nl-route.h"
32 #include "link-sriov.h"
33 #include "link-api.h"
34 
35 /** @cond SKIP */
36 struct rtnl_link_vf {
37 	struct nl_list_head vf_list;
38 	int ce_refcnt;
39 	uint32_t ce_mask;
40 	uint32_t vf_index;
41 	uint64_t vf_guid_node;
42 	uint64_t vf_guid_port;
43 	uint32_t vf_linkstate;
44 	struct nl_addr *vf_lladdr;
45 	uint32_t vf_max_tx_rate;
46 	uint32_t vf_min_tx_rate;
47 	uint32_t vf_rate;
48 	uint32_t vf_rss_query_en;
49 	uint32_t vf_spoofchk;
50 	uint64_t vf_stats[RTNL_LINK_VF_STATS_MAX + 1];
51 	uint32_t vf_trust;
52 	struct nl_vf_vlans *vf_vlans;
53 };
54 
55 #define SRIOVON "on"
56 #define SRIOVOFF "off"
57 
58 #define SET_VF_STAT(link, vf_num, stb, stat, attr) \
59 	vf_data->vf_stats[stat] = nla_get_u64(stb[attr])
60 
61 /* SRIOV-VF Attributes */
62 #define SRIOV_ATTR_INDEX 		(1 <<  0)
63 #define SRIOV_ATTR_ADDR 		(1 <<  1)
64 #define SRIOV_ATTR_VLAN 		(1 <<  2)
65 #define SRIOV_ATTR_TX_RATE 		(1 <<  3)
66 #define SRIOV_ATTR_SPOOFCHK 		(1 <<  4)
67 #define SRIOV_ATTR_RATE_MAX 		(1 <<  5)
68 #define SRIOV_ATTR_RATE_MIN 		(1 <<  6)
69 #define SRIOV_ATTR_LINK_STATE 		(1 <<  7)
70 #define SRIOV_ATTR_RSS_QUERY_EN 	(1 <<  8)
71 #define SRIOV_ATTR_STATS 		(1 <<  9)
72 #define SRIOV_ATTR_TRUST 		(1 << 10)
73 #define SRIOV_ATTR_IB_NODE_GUID 	(1 << 11)
74 #define SRIOV_ATTR_IB_PORT_GUID 	(1 << 12)
75 
76 static struct nla_policy sriov_info_policy[IFLA_VF_MAX+1] = {
77 	[IFLA_VF_MAC]		= { .minlen = sizeof(struct ifla_vf_mac) },
78 	[IFLA_VF_VLAN]		= { .minlen = sizeof(struct ifla_vf_vlan) },
79 	[IFLA_VF_VLAN_LIST]     = { .type = NLA_NESTED },
80 	[IFLA_VF_TX_RATE]	= { .minlen = sizeof(struct ifla_vf_tx_rate) },
81 	[IFLA_VF_SPOOFCHK]	= { .minlen = sizeof(struct ifla_vf_spoofchk) },
82 	[IFLA_VF_RATE]		= { .minlen = sizeof(struct ifla_vf_rate) },
83 	[IFLA_VF_LINK_STATE]	= { .minlen = sizeof(struct ifla_vf_link_state) },
84 	[IFLA_VF_RSS_QUERY_EN]	= { .minlen = sizeof(struct ifla_vf_rss_query_en) },
85 	[IFLA_VF_STATS]		= { .type = NLA_NESTED },
86 	[IFLA_VF_TRUST]		= { .minlen = sizeof(struct ifla_vf_trust) },
87 	[IFLA_VF_IB_NODE_GUID]	= { .minlen = sizeof(struct ifla_vf_guid) },
88 	[IFLA_VF_IB_PORT_GUID]	= { .minlen = sizeof(struct ifla_vf_guid) },
89 };
90 
91 static struct nla_policy sriov_stats_policy[IFLA_VF_STATS_MAX+1] = {
92 	[IFLA_VF_STATS_RX_PACKETS]	= { .type = NLA_U64 },
93 	[IFLA_VF_STATS_TX_PACKETS]	= { .type = NLA_U64 },
94 	[IFLA_VF_STATS_RX_BYTES]	= { .type = NLA_U64 },
95 	[IFLA_VF_STATS_TX_BYTES]	= { .type = NLA_U64 },
96 	[IFLA_VF_STATS_BROADCAST]	= { .type = NLA_U64 },
97 	[IFLA_VF_STATS_MULTICAST]	= { .type = NLA_U64 },
98 };
99 
100 /** @endcond */
101 
102 /* Clone SRIOV VF list in link object */
rtnl_link_sriov_clone(struct rtnl_link * dst,struct rtnl_link * src)103 int rtnl_link_sriov_clone(struct rtnl_link *dst, struct rtnl_link *src) {
104 	int err = 0;
105 	struct nl_addr *vf_addr;
106 	struct rtnl_link_vf *s_list, *d_vf, *s_vf, *next, *dest_h = NULL;
107 	nl_vf_vlans_t *src_vlans = NULL, *dst_vlans = NULL;
108 	nl_vf_vlan_info_t *src_vlan_info = NULL, *dst_vlan_info = NULL;
109 
110 	if (!rtnl_link_has_vf_list(src))
111 		return 0;
112 
113 	dst->l_vf_list = rtnl_link_vf_alloc();
114 	if (!dst->l_vf_list)
115 		return -NLE_NOMEM;
116 	dest_h = dst->l_vf_list;
117 	s_list = src->l_vf_list;
118 
119 	nl_list_for_each_entry_safe(s_vf, next, &s_list->vf_list, vf_list) {
120 		if (!(d_vf = rtnl_link_vf_alloc()))
121 			return -NLE_NOMEM;
122 
123 		memcpy(d_vf, s_vf, sizeof(*s_vf));
124 
125 		if (s_vf->ce_mask & SRIOV_ATTR_ADDR) {
126 			vf_addr = nl_addr_clone(s_vf->vf_lladdr);
127 			if (!vf_addr) {
128 				rtnl_link_vf_put(d_vf);
129 				return -NLE_NOMEM;
130 			}
131 			d_vf->vf_lladdr = vf_addr;
132 		}
133 
134 		if (s_vf->ce_mask & SRIOV_ATTR_VLAN) {
135 			src_vlans = s_vf->vf_vlans;
136 			src_vlan_info = src_vlans->vlans;
137 
138 			err = rtnl_link_vf_vlan_alloc(&dst_vlans,
139 						      src_vlans->size);
140 			if (err < 0) {
141 				rtnl_link_vf_put(d_vf);
142 				return err;
143 			}
144 			dst_vlan_info = dst_vlans->vlans;
145 			memcpy(dst_vlans, src_vlans, sizeof(nl_vf_vlans_t));
146 			memcpy(dst_vlan_info, src_vlan_info,
147 			       dst_vlans->size * sizeof(*dst_vlan_info));
148 			d_vf->vf_vlans = dst_vlans;
149 		}
150 
151 		nl_list_add_head(&d_vf->vf_list, &dest_h->vf_list);
152 		dest_h = d_vf;
153 	}
154 
155 	return 0;
156 }
157 
158 /* Dump VLAN details for each SRIOV VF */
dump_sriov_vlans(nl_vf_vlans_t * vlans,struct nl_dump_params * p)159 static void dump_sriov_vlans(nl_vf_vlans_t *vlans,
160 			     struct nl_dump_params *p) {
161 	char buf[64];
162 	int cur = 0;
163 	nl_vf_vlan_info_t *vlan_data;
164 	uint16_t prot;
165 
166 	vlan_data = vlans->vlans;
167 	nl_dump(p, "\t      VLANS:\n");
168 	while (cur < vlans->size) {
169 		nl_dump(p, "\t      vlan %u", vlan_data[cur].vf_vlan);
170 		if (vlan_data[cur].vf_vlan_qos)
171 			nl_dump(p, " qos %u", vlan_data[cur].vf_vlan_qos);
172 		if (vlan_data[cur].vf_vlan_proto) {
173 			prot = vlan_data[cur].vf_vlan_proto;
174 			nl_dump(p, " proto %s",
175 				rtnl_link_vf_vlanproto2str(prot, buf,
176 							   sizeof(buf)));
177 		}
178 		nl_dump(p, "\n");
179 		cur++;
180 	}
181 
182 	return;
183 }
184 
185 /* Dump details for each SRIOV VF */
dump_vf_details(struct rtnl_link_vf * vf_data,struct nl_dump_params * p)186 static void dump_vf_details(struct rtnl_link_vf *vf_data,
187 			    struct nl_dump_params *p) {
188 	char buf[64];
189 	int err = 0;
190 	struct nl_vf_rate vf_rate;
191 	uint32_t v = 0;
192 
193 	nl_dump(p, "\tvf %u: ", vf_data->vf_index);
194 	if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE) {
195 		v = vf_data->vf_linkstate;
196 		nl_dump(p, "state %s ",
197 			rtnl_link_vf_linkstate2str(v, buf, sizeof(buf)));
198 	}
199 	if (vf_data->ce_mask & SRIOV_ATTR_ADDR) {
200 		nl_dump(p, "addr %s ",
201 			nl_addr2str(vf_data->vf_lladdr, buf, sizeof(buf)));
202 	}
203 	nl_dump(p, "\n");
204 
205 	v = vf_data->vf_spoofchk;
206 	nl_dump(p, "\t      spoofchk %s ", v ? SRIOVON : SRIOVOFF);
207 	v = vf_data->vf_trust;
208 	nl_dump(p, "trust %s ", v ? SRIOVON : SRIOVOFF);
209 	v = vf_data->vf_rss_query_en;
210 	nl_dump(p, "rss_query %s\n", v ? SRIOVON : SRIOVOFF);
211 
212 	err = rtnl_link_vf_get_rate(vf_data, &vf_rate);
213 	if (!err) {
214 		if (vf_rate.api == RTNL_LINK_VF_RATE_API_OLD)
215 			nl_dump(p, "\t      rate_api old rate %u\n",
216 				vf_rate.rate);
217 		else if (vf_rate.api == RTNL_LINK_VF_RATE_API_NEW)
218 			nl_dump(p, "\t      rate_api new min_rate %u "
219 					"max_rate %u\n", vf_rate.min_tx_rate,
220 				vf_rate.max_tx_rate);
221 	}
222 	if (vf_data->ce_mask & SRIOV_ATTR_VLAN)
223 		dump_sriov_vlans(vf_data->vf_vlans, p);
224 
225 	return;
226 }
227 
228 /* Loop through SRIOV VF list dump details */
rtnl_link_sriov_dump_details(struct rtnl_link * link,struct nl_dump_params * p)229 void rtnl_link_sriov_dump_details(struct rtnl_link *link,
230 				  struct nl_dump_params *p) {
231 	struct rtnl_link_vf *vf_data, *list, *next;
232 
233 	if (!rtnl_link_has_vf_list(link))
234 		BUG();
235 
236 	nl_dump(p, "    SRIOV VF List\n");
237 	list = link->l_vf_list;
238 	nl_list_for_each_entry_safe(vf_data, next, &list->vf_list, vf_list) {
239 		if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
240 			dump_vf_details(vf_data, p);
241 	}
242 
243 	return;
244 }
245 
246 /* Dump stats for each SRIOV VF */
dump_vf_stats(struct rtnl_link_vf * vf_data,struct nl_dump_params * p)247 static void dump_vf_stats(struct rtnl_link_vf *vf_data,
248 			  struct nl_dump_params *p) {
249 	char *unit;
250 	float res;
251 
252 	nl_dump(p, "    VF %u Stats:\n", vf_data->vf_index);
253 	nl_dump_line(p, "\tRX:    %-14s %-10s   %-10s %-10s\n",
254 		     "bytes", "packets", "multicast", "broadcast");
255 
256 	res = nl_cancel_down_bytes(vf_data->vf_stats[RTNL_LINK_VF_STATS_RX_BYTES],
257 				   &unit);
258 
259 	nl_dump_line(p,
260 		"\t%10.2f %3s   %10" PRIu64 "   %10" PRIu64 " %10" PRIu64 "\n",
261 		res, unit,
262 		vf_data->vf_stats[RTNL_LINK_VF_STATS_RX_PACKETS],
263 		vf_data->vf_stats[RTNL_LINK_VF_STATS_MULTICAST],
264 		vf_data->vf_stats[RTNL_LINK_VF_STATS_BROADCAST]);
265 
266 	nl_dump_line(p, "\tTX:    %-14s %-10s\n", "bytes", "packets");
267 
268 	res = nl_cancel_down_bytes(vf_data->vf_stats[RTNL_LINK_VF_STATS_TX_BYTES],
269 				   &unit);
270 
271 	nl_dump_line(p, "\t%10.2f %3s   %10" PRIu64 "\n", res, unit,
272 		vf_data->vf_stats[RTNL_LINK_VF_STATS_TX_PACKETS]);
273 
274 	return;
275 }
276 
277 /* Loop through SRIOV VF list dump stats */
rtnl_link_sriov_dump_stats(struct rtnl_link * link,struct nl_dump_params * p)278 void rtnl_link_sriov_dump_stats(struct rtnl_link *link,
279 				struct nl_dump_params *p) {
280 	struct rtnl_link_vf *vf_data, *list, *next;
281 
282 	list = link->l_vf_list;
283 	nl_list_for_each_entry_safe(vf_data, next, &list->vf_list, vf_list) {
284 		if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
285 			dump_vf_stats(vf_data, p);
286 	}
287 	nl_dump(p, "\n");
288 
289 	return;
290 }
291 
292 /* Free stored SRIOV VF data */
rtnl_link_sriov_free_data(struct rtnl_link * link)293 void rtnl_link_sriov_free_data(struct rtnl_link *link) {
294 	struct rtnl_link_vf *list, *vf, *next;
295 
296 	if (!rtnl_link_has_vf_list(link))
297 		return;
298 
299 	list = link->l_vf_list;
300 	nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
301 		nl_list_del(&vf->vf_list);
302 		rtnl_link_vf_put(vf);
303 	}
304 
305 	rtnl_link_vf_put(link->l_vf_list);
306 
307 	return;
308 }
309 
310 /* Fill VLAN info array */
rtnl_link_vf_vlan_info(int len,struct ifla_vf_vlan_info ** vi,nl_vf_vlans_t ** nvi)311 static int rtnl_link_vf_vlan_info(int len, struct ifla_vf_vlan_info **vi,
312 				  nl_vf_vlans_t **nvi) {
313 	int cur = 0, err;
314 	nl_vf_vlans_t *vlans;
315 
316 	if (len <= 0)
317 		return 0;
318 
319 	if ((err = rtnl_link_vf_vlan_alloc(&vlans, len)) < 0)
320 		return err;
321 
322 	cur = 0;
323 	while (cur < len) {
324 		vlans->vlans[cur].vf_vlan = vi[cur]->vlan ? vi[cur]->vlan : 0;
325 		vlans->vlans[cur].vf_vlan_qos = vi[cur]->qos ? vi[cur]->qos : 0;
326 		if (vi[cur]->vlan_proto) {
327 			vlans->vlans[cur].vf_vlan_proto = ntohs(vi[cur]->vlan_proto);
328 		} else {
329 			vlans->vlans[cur].vf_vlan_proto = ETH_P_8021Q;
330 		}
331 		cur++;
332 	}
333 
334 	*nvi = vlans;
335 	return 0;
336 }
337 
338 /* Fill the IFLA_VF_VLAN attribute */
sriov_fill_vf_vlan(struct nl_msg * msg,nl_vf_vlan_info_t * vinfo,uint32_t index)339 static void sriov_fill_vf_vlan(struct nl_msg *msg, nl_vf_vlan_info_t *vinfo,
340 			       uint32_t index) {
341 	struct ifla_vf_vlan vlan;
342 
343 	vlan.vf = index;
344 	vlan.vlan = vinfo[0].vf_vlan;
345 	vlan.qos = vinfo[0].vf_vlan_qos;
346 	NLA_PUT(msg, IFLA_VF_VLAN, sizeof(vlan), &vlan);
347 
348 nla_put_failure:
349 	return;
350 }
351 
352 /* Fill the IFLA_VF_VLAN_LIST attribute */
sriov_fill_vf_vlan_list(struct nl_msg * msg,nl_vf_vlans_t * vlans,uint32_t index)353 static int sriov_fill_vf_vlan_list(struct nl_msg *msg, nl_vf_vlans_t *vlans,
354 				   uint32_t index) {
355 	int cur = 0;
356 	nl_vf_vlan_info_t *vlan_info = vlans->vlans;
357 	struct ifla_vf_vlan_info vlan;
358 	struct nlattr *list;
359 
360 	if (!(list = nla_nest_start(msg, IFLA_VF_VLAN_LIST)))
361 		return -NLE_MSGSIZE;
362 
363 	vlan.vf = index;
364 	while (cur < vlans->size) {
365 		vlan.vlan = vlan_info[cur].vf_vlan;
366 		vlan.qos = vlan_info[cur].vf_vlan_qos;
367 		vlan.vlan_proto = vlan_info[cur].vf_vlan_proto;
368 
369 		NLA_PUT(msg, IFLA_VF_VLAN_INFO, sizeof(vlan), &vlan);
370 
371 		cur++;
372 	}
373 
374 nla_put_failure:
375 	nla_nest_end(msg, list);
376 
377 	return 0;
378 }
379 
380 /* Fill individual IFLA_VF_INFO attributes */
sriov_fill_vfinfo(struct nl_msg * msg,struct rtnl_link_vf * vf_data)381 static int sriov_fill_vfinfo(struct nl_msg *msg,
382 			     struct rtnl_link_vf *vf_data) {
383 	int err = 0, new_rate = 0;
384 	nl_vf_vlans_t *vlan_list;
385 	nl_vf_vlan_info_t *vlan_info;
386 	struct ifla_vf_guid vf_node_guid;
387 	struct ifla_vf_guid vf_port_guid;
388 	struct ifla_vf_link_state vf_link_state;
389 	struct ifla_vf_mac vf_mac;
390 	struct ifla_vf_rate new_vf_rate;
391 	struct ifla_vf_rss_query_en vf_rss_query_en;
392 	struct ifla_vf_spoofchk vf_spoofchk;
393 	struct ifla_vf_trust vf_trust;
394 	struct ifla_vf_tx_rate vf_rate;
395 	struct nlattr *list;
396 	uint16_t proto;
397 
398 	if (!(vf_data->ce_mask & SRIOV_ATTR_INDEX))
399 		return -NLE_MISSING_ATTR;
400 
401 	if (!(list = nla_nest_start(msg, IFLA_VF_INFO)))
402 		return -NLE_MSGSIZE;
403 
404 	/* IFLA_VF_MAC */
405 	if (vf_data->ce_mask & SRIOV_ATTR_ADDR) {
406 		vf_mac.vf = vf_data->vf_index;
407 		memset(vf_mac.mac, 0, sizeof(vf_mac.mac));
408 		memcpy(vf_mac.mac, nl_addr_get_binary_addr(vf_data->vf_lladdr),
409 		       nl_addr_get_len(vf_data->vf_lladdr));
410 		NLA_PUT(msg, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac);
411 	}
412 
413 	/* IFLA_VF_VLAN IFLA_VF_VLAN_LIST */
414 	if (vf_data->ce_mask & SRIOV_ATTR_VLAN) {
415 		vlan_list = vf_data->vf_vlans;
416 		vlan_info = vlan_list->vlans;
417 		proto = vlan_info[0].vf_vlan_proto;
418 		if (!proto)
419 			proto = ETH_P_8021Q;
420 
421 		if ((vlan_list->size == 1) && (proto == ETH_P_8021Q))
422 			sriov_fill_vf_vlan(msg, vlan_info, vf_data->vf_index);
423 		else
424 			err = sriov_fill_vf_vlan_list(msg, vlan_list,
425 						      vf_data->vf_index);
426 	}
427 
428 	/* IFLA_VF_TX_RATE */
429 	if (vf_data->ce_mask & SRIOV_ATTR_TX_RATE) {
430 		vf_rate.vf = vf_data->vf_index;
431 		vf_rate.rate = vf_data->vf_rate;
432 
433 		NLA_PUT(msg, IFLA_VF_TX_RATE, sizeof(vf_rate), &vf_rate);
434 	}
435 
436 	/* IFLA_VF_RATE */
437 	new_vf_rate.min_tx_rate = 0;
438 	new_vf_rate.max_tx_rate = 0;
439 	new_vf_rate.vf = vf_data->vf_index;
440 	if (vf_data->ce_mask & SRIOV_ATTR_RATE_MIN) {
441 		new_vf_rate.min_tx_rate = vf_data->vf_min_tx_rate;
442 		new_rate = 1;
443 	}
444 	if (vf_data->ce_mask & SRIOV_ATTR_RATE_MAX) {
445 		new_vf_rate.max_tx_rate = vf_data->vf_max_tx_rate;
446 		new_rate = 1;
447 	}
448 	if (new_rate)
449 		NLA_PUT(msg, IFLA_VF_RATE, sizeof(new_vf_rate), &new_vf_rate);
450 
451 	/* IFLA_VF_SPOOFCHK */
452 	if (vf_data->ce_mask & SRIOV_ATTR_SPOOFCHK) {
453 		vf_spoofchk.vf = vf_data->vf_index;
454 		vf_spoofchk.setting = vf_data->vf_spoofchk;
455 
456 		NLA_PUT(msg, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
457 			&vf_spoofchk);
458 	}
459 
460 	/* IFLA_VF_LINK_STATE */
461 	if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE) {
462 		vf_link_state.vf = vf_data->vf_index;
463 		vf_link_state.link_state = vf_data->vf_linkstate;
464 
465 		NLA_PUT(msg, IFLA_VF_LINK_STATE, sizeof(vf_link_state),
466 			&vf_link_state);
467 	}
468 
469 	/* IFLA_VF_RSS_QUERY_EN */
470 	if (vf_data->ce_mask & SRIOV_ATTR_RSS_QUERY_EN) {
471 		vf_rss_query_en.vf = vf_data->vf_index;
472 		vf_rss_query_en.setting = vf_data->vf_rss_query_en;
473 
474 		NLA_PUT(msg, IFLA_VF_RSS_QUERY_EN, sizeof(vf_rss_query_en),
475 			&vf_rss_query_en);
476 	}
477 
478 	/* IFLA_VF_TRUST */
479 	if (vf_data->ce_mask & SRIOV_ATTR_TRUST) {
480 		vf_trust.vf = vf_data->vf_index;
481 		vf_trust.setting = vf_data->vf_trust;
482 
483 		NLA_PUT(msg, IFLA_VF_TRUST, sizeof(vf_trust), &vf_trust);
484 	}
485 
486 	/* IFLA_VF_IB_NODE_GUID */
487 	if (vf_data->ce_mask & SRIOV_ATTR_IB_NODE_GUID) {
488 		vf_node_guid.vf = vf_data->vf_index;
489 		vf_node_guid.guid = vf_data->vf_guid_node;
490 
491 		NLA_PUT(msg, IFLA_VF_IB_NODE_GUID, sizeof(vf_node_guid),
492 			&vf_node_guid);
493 	}
494 
495 	/* IFLA_VF_IB_PORT_GUID */
496 	if (vf_data->ce_mask & SRIOV_ATTR_IB_PORT_GUID) {
497 		vf_port_guid.vf = vf_data->vf_index;
498 		vf_port_guid.guid = vf_data->vf_guid_port;
499 
500 		NLA_PUT(msg, IFLA_VF_IB_PORT_GUID, sizeof(vf_port_guid),
501 			&vf_port_guid);
502 	}
503 
504 nla_put_failure:
505 	nla_nest_end(msg, list);
506 
507 	return err;
508 }
509 
510 /* Fill the IFLA_VFINFO_LIST attribute */
rtnl_link_sriov_fill_vflist(struct nl_msg * msg,struct rtnl_link * link)511 int rtnl_link_sriov_fill_vflist(struct nl_msg *msg, struct rtnl_link *link) {
512 	int err = 0;
513 	struct nlattr *data;
514 	struct rtnl_link_vf *list, *vf, *next;
515 
516 	if (!(err = rtnl_link_has_vf_list(link)))
517 		return 0;
518 
519 	if (!(data = nla_nest_start(msg, IFLA_VFINFO_LIST)))
520 		return -NLE_MSGSIZE;
521 
522 	list = link->l_vf_list;
523 	nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
524 		if (vf->ce_mask & SRIOV_ATTR_INDEX) {
525 			if ((err = sriov_fill_vfinfo(msg, vf)) < 0)
526 				goto nla_nest_list_failure;
527 		}
528 	}
529 
530 nla_nest_list_failure:
531 	nla_nest_end(msg, data);
532 
533 	return err;
534 }
535 
536 /* Parse IFLA_VFINFO_LIST and IFLA_VF_INFO attributes */
rtnl_link_sriov_parse_vflist(struct rtnl_link * link,struct nlattr ** tb)537 int rtnl_link_sriov_parse_vflist(struct rtnl_link *link, struct nlattr **tb) {
538 	int err, len, list_len, list_rem;
539 	struct ifla_vf_mac *vf_lladdr;
540 	struct ifla_vf_vlan *vf_vlan;
541 	struct ifla_vf_vlan_info *vf_vlan_info[MAX_VLAN_LIST_LEN];
542 	struct ifla_vf_tx_rate *vf_tx_rate;
543 	struct ifla_vf_spoofchk *vf_spoofchk;
544 	struct ifla_vf_link_state *vf_linkstate;
545 	struct ifla_vf_rate *vf_rate;
546 	struct ifla_vf_rss_query_en *vf_rss_query;
547 	struct ifla_vf_trust *vf_trust;
548 	struct nlattr *nla, *nla_list, *t[IFLA_VF_MAX+1],
549 		*stb[RTNL_LINK_VF_STATS_MAX+1];
550 	nl_vf_vlans_t *vf_vlans = NULL;
551 	struct rtnl_link_vf *vf_data, *vf_head = NULL;
552 
553 	len = nla_len(tb[IFLA_VFINFO_LIST]);
554 	link->l_vf_list = rtnl_link_vf_alloc();
555 	if (!link->l_vf_list)
556 		return -NLE_NOMEM;
557 	vf_head = link->l_vf_list;
558 
559 	for (nla = nla_data(tb[IFLA_VFINFO_LIST]); nla_ok(nla, len);
560 	     nla = nla_next(nla, &len)) {
561 		err = nla_parse(t, IFLA_VF_MAX, nla_data(nla), nla_len(nla),
562 				sriov_info_policy);
563 		if (err < 0)
564 			return err;
565 
566 		vf_data = rtnl_link_vf_alloc();
567 		if (!vf_data)
568 			return -NLE_NOMEM;
569 
570 		if (t[IFLA_VF_MAC]) {
571 			vf_lladdr = nla_data(t[IFLA_VF_MAC]);
572 
573 			vf_data->vf_index = vf_lladdr->vf;
574 			vf_data->ce_mask |= SRIOV_ATTR_INDEX;
575 
576 			vf_data->vf_lladdr = nl_addr_build(AF_LLC,
577 							   vf_lladdr->mac, 6);
578 			if (vf_data->vf_lladdr == NULL) {
579 				rtnl_link_vf_put(vf_data);
580 				return -NLE_NOMEM;
581 			}
582 			nl_addr_set_family(vf_data->vf_lladdr, AF_LLC);
583 			vf_data->ce_mask |= SRIOV_ATTR_ADDR;
584 		}
585 
586 		if (t[IFLA_VF_VLAN_LIST]) {
587 			list_len = 0;
588 			nla_for_each_nested(nla_list, t[IFLA_VF_VLAN_LIST],
589 					    list_rem) {
590 				if (list_len >= MAX_VLAN_LIST_LEN)
591 					break;
592 				vf_vlan_info[list_len] = nla_data(nla_list);
593 				list_len++;
594 			}
595 
596 			err = rtnl_link_vf_vlan_info(list_len, vf_vlan_info,
597 						     &vf_vlans);
598 			if (err < 0) {
599 				rtnl_link_vf_put(vf_data);
600 				return err;
601 			}
602 
603 			vf_data->vf_vlans = vf_vlans;
604 			vf_data->ce_mask |= SRIOV_ATTR_VLAN;
605 		} else if (t[IFLA_VF_VLAN]) {
606 			vf_vlan = nla_data(t[IFLA_VF_VLAN]);
607 
608 			if (vf_vlan->vlan) {
609 				err = rtnl_link_vf_vlan_alloc(&vf_vlans, 1);
610 				if (err < 0) {
611 					rtnl_link_vf_put(vf_data);
612 					return err;
613 				}
614 
615 				vf_vlans->vlans[0].vf_vlan = vf_vlan->vlan;
616 				vf_vlans->vlans[0].vf_vlan_qos = vf_vlan->qos;
617 				vf_vlans->vlans[0].vf_vlan_proto = ETH_P_8021Q;
618 
619 				vf_data->vf_vlans = vf_vlans;
620 				vf_data->ce_mask |= SRIOV_ATTR_VLAN;
621 			}
622 		}
623 
624 		if (t[IFLA_VF_TX_RATE]) {
625 			vf_tx_rate = nla_data(t[IFLA_VF_TX_RATE]);
626 
627 			if (vf_tx_rate->rate) {
628 				vf_data->vf_rate = vf_tx_rate->rate;
629 				vf_data->ce_mask |= SRIOV_ATTR_TX_RATE;
630 			}
631 		}
632 
633 		if (t[IFLA_VF_SPOOFCHK]) {
634 			vf_spoofchk = nla_data(t[IFLA_VF_SPOOFCHK]);
635 
636 			if (vf_spoofchk->setting != ((uint32_t)-1)) {
637 				vf_data->vf_spoofchk = vf_spoofchk->setting ? 1 : 0;
638 				vf_data->ce_mask |= SRIOV_ATTR_SPOOFCHK;
639 			}
640 		}
641 
642 		if (t[IFLA_VF_LINK_STATE]) {
643 			vf_linkstate = nla_data(t[IFLA_VF_LINK_STATE]);
644 
645 			vf_data->vf_linkstate = vf_linkstate->link_state;
646 			vf_data->ce_mask |= SRIOV_ATTR_LINK_STATE;
647 		}
648 
649 		if (t[IFLA_VF_RATE]) {
650 			vf_rate = nla_data(t[IFLA_VF_RATE]);
651 
652 			if (vf_rate->max_tx_rate) {
653 				vf_data->vf_max_tx_rate = vf_rate->max_tx_rate;
654 				vf_data->ce_mask |= SRIOV_ATTR_RATE_MAX;
655 			}
656 			if (vf_rate->min_tx_rate) {
657 				vf_data->vf_min_tx_rate = vf_rate->min_tx_rate;
658 				vf_data->ce_mask |= SRIOV_ATTR_RATE_MIN;
659 			}
660 		}
661 
662 		if (t[IFLA_VF_RSS_QUERY_EN]) {
663 			vf_rss_query = nla_data(t[IFLA_VF_RSS_QUERY_EN]);
664 
665 			if (vf_rss_query->setting != ((uint32_t)-1)) {
666 				vf_data->vf_rss_query_en = vf_rss_query->setting ? 1 : 0;
667 				vf_data->ce_mask |= SRIOV_ATTR_RSS_QUERY_EN;
668 			}
669 		}
670 
671 		if (t[IFLA_VF_STATS]) {
672 			err = nla_parse_nested(stb, RTNL_LINK_VF_STATS_MAX,
673 					       t[IFLA_VF_STATS],
674 					       sriov_stats_policy);
675 			if (err < 0) {
676 				rtnl_link_vf_put(vf_data);
677 				return err;
678 			}
679 
680 			SET_VF_STAT(link, cur, stb,
681 				    RTNL_LINK_VF_STATS_RX_PACKETS,
682 				    IFLA_VF_STATS_RX_PACKETS);
683 			SET_VF_STAT(link, cur, stb,
684 				    RTNL_LINK_VF_STATS_TX_PACKETS,
685 				    IFLA_VF_STATS_TX_PACKETS);
686 			SET_VF_STAT(link, cur, stb,
687 				    RTNL_LINK_VF_STATS_RX_BYTES,
688 				    IFLA_VF_STATS_RX_BYTES);
689 			SET_VF_STAT(link, cur, stb,
690 				    RTNL_LINK_VF_STATS_TX_BYTES,
691 				    IFLA_VF_STATS_TX_BYTES);
692 			SET_VF_STAT(link, cur, stb,
693 				    RTNL_LINK_VF_STATS_BROADCAST,
694 				    IFLA_VF_STATS_BROADCAST);
695 			SET_VF_STAT(link, cur, stb,
696 				    RTNL_LINK_VF_STATS_MULTICAST,
697 				    IFLA_VF_STATS_MULTICAST);
698 
699 			vf_data->ce_mask |= SRIOV_ATTR_STATS;
700 		}
701 
702 		if (t[IFLA_VF_TRUST]) {
703 			vf_trust = nla_data(t[IFLA_VF_TRUST]);
704 
705 			if (vf_trust->setting != ((uint32_t)-1)) {
706 				vf_data->vf_trust = vf_trust->setting ? 1 : 0;
707 				vf_data->ce_mask |= SRIOV_ATTR_TRUST;
708 			}
709 		}
710 
711 		nl_list_add_head(&vf_data->vf_list, &vf_head->vf_list);
712 		vf_head = vf_data;
713 	}
714 
715 	return 0;
716 }
717 
718 /**
719  * @name SR-IOV Sub-Object
720  * @{
721  */
722 
723 /**
724  * Add a SRIOV VF object to a link object
725  * @param link  	Link object to add to
726  * @param vf_data 	SRIOV VF object to add
727  *
728  * @return 0 if SRIOV VF object added successfully
729  * @return -NLE_OBJ_NOTFOUND if \p link or \p vf_data not provided
730  * @return -NLE_NOMEM if out of memory
731  */
rtnl_link_vf_add(struct rtnl_link * link,struct rtnl_link_vf * vf_data)732 int rtnl_link_vf_add(struct rtnl_link *link, struct rtnl_link_vf *vf_data) {
733 	struct rtnl_link_vf *vf_head = NULL;
734 
735 	if (!link||!vf_data)
736 		return -NLE_OBJ_NOTFOUND;
737 
738 	if (!link->l_vf_list) {
739 		link->l_vf_list = rtnl_link_vf_alloc();
740 		if (!link->l_vf_list)
741 			return -NLE_NOMEM;
742 	}
743 
744 	vf_head = vf_data;
745 	vf_head->ce_refcnt++;
746 
747 	vf_head = link->l_vf_list;
748 	nl_list_add_head(&vf_data->vf_list, &vf_head->vf_list);
749 	link->l_vf_list = vf_head;
750 
751 	rtnl_link_set_vf_list(link);
752 
753 	return 0;
754 }
755 
756 /**
757  * Allocate a new SRIOV VF object
758  *
759  * @return NULL if out of memory
760  * @return New VF Object
761  *
762  * @see rtnl_link_vf_put()
763  *
764  * The SRIOV VF object must be returned to the link object with
765  * rtnl_link_vf_put() when operations are done to prevent memory leaks.
766  */
rtnl_link_vf_alloc(void)767 struct rtnl_link_vf *rtnl_link_vf_alloc(void) {
768 	struct rtnl_link_vf *vf;
769 
770 	if (!(vf = calloc(1, sizeof(*vf))))
771 		return NULL;
772 
773 	NL_INIT_LIST_HEAD(&vf->vf_list);
774 	vf->ce_refcnt = 1;
775 
776 	NL_DBG(4, "Allocated new SRIOV VF object %p\n", vf);
777 
778 	return vf;
779 }
780 
781 /**
782  * Free SRIOV VF object.
783  * @arg vf_data 	SRIOV VF data object
784  */
rtnl_link_vf_free(struct rtnl_link_vf * vf_data)785 void rtnl_link_vf_free(struct rtnl_link_vf *vf_data) {
786 	if (!vf_data)
787 		return;
788 
789 	if (vf_data->ce_refcnt > 0)
790 		NL_DBG(1, "Warning: Freeing SRIOV VF object in use...\n");
791 
792 	if (vf_data->ce_mask & SRIOV_ATTR_ADDR)
793 		nl_addr_put(vf_data->vf_lladdr);
794 	if (vf_data->ce_mask & SRIOV_ATTR_VLAN)
795 		rtnl_link_vf_vlan_put(vf_data->vf_vlans);
796 
797 	NL_DBG(4, "Freed SRIOV VF object %p\n", vf_data);
798 	free(vf_data);
799 
800 	return;
801 }
802 
803 /**
804  * Lookup SRIOV VF in link object by VF index.
805  *
806  * @return NULL if VF not found
807  * @return VF Object
808  *
809  * @see rtnl_link_vf_put()
810  *
811  * The SRIOV VF object must be returned to the link object with
812  * rtnl_link_vf_put() when operations are done to prevent memory leaks.
813  */
rtnl_link_vf_get(struct rtnl_link * link,uint32_t vf_num)814 struct rtnl_link_vf *rtnl_link_vf_get(struct rtnl_link *link, uint32_t vf_num) {
815 	struct rtnl_link_vf *list, *vf, *next, *ret = NULL;
816 
817 	list = link->l_vf_list;
818 	nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
819 		if (vf->vf_index == vf_num) {
820 			ret = vf;
821 			break;
822 		}
823 	}
824 
825 	if (ret) {
826 		ret->ce_refcnt++;
827 		NL_DBG(4, "New reference to SRIOV VF object %p, total %i\n",
828 		       ret, ret->ce_refcnt);
829 	}
830 
831 	return ret;
832 }
833 
834 /**
835  * Return SRIOV VF object to the owning link object.
836  * @arg vf_data 	SRIOV VF data object
837  *
838  * @see rtnl_link_vf_alloc()
839  * @see rtnl_link_vf_get()
840  */
rtnl_link_vf_put(struct rtnl_link_vf * vf_data)841 void rtnl_link_vf_put(struct rtnl_link_vf *vf_data) {
842 	if (!vf_data)
843 		return;
844 
845 	vf_data->ce_refcnt--;
846 	NL_DBG(4, "Returned SRIOV VF object reference %p, %i remaining\n",
847 	       vf_data, vf_data->ce_refcnt);
848 
849 	if (vf_data->ce_refcnt < 0)
850 		BUG();
851 
852 	if (vf_data->ce_refcnt <= 0)
853 		rtnl_link_vf_free(vf_data);
854 
855 	return;
856 }
857 
858 /**
859  * Get link layer address of SRIOV Virtual Function
860  * @arg vf_data 	SRIOV VF object
861  * @arg addr 		Pointer to store Link Layer address
862  *
863  * @see rtnl_link_get_num_vf()
864  * @see rtnl_link_vf_set_addr()
865  *
866  * @copydoc pointer_lifetime_warning
867  * @return 0 if addr is present and addr is set to pointer containing address
868  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
869  * @return -NLE_NOATTR if the link layer address is not set
870  */
rtnl_link_vf_get_addr(struct rtnl_link_vf * vf_data,struct nl_addr ** addr)871 int rtnl_link_vf_get_addr(struct rtnl_link_vf *vf_data, struct nl_addr **addr)
872 {
873 	if (!vf_data)
874 		return -NLE_OBJ_NOTFOUND;
875 
876 	if (vf_data->ce_mask & SRIOV_ATTR_ADDR)
877 		*addr = vf_data->vf_lladdr;
878 	else
879 		return -NLE_NOATTR;
880 
881 	return 0;
882 }
883 
884 /**
885  * Set link layer address of SRIOV Virtual Function object
886  * @param vf_data 	SRIOV VF object
887  * @param addr 		New link layer address
888  *
889  * This function increments the reference counter of the address object
890  * and overwrites any existing link layer address previously assigned.
891  *
892  * @see rtnl_link_vf_get_addr()
893  */
rtnl_link_vf_set_addr(struct rtnl_link_vf * vf_data,struct nl_addr * addr)894 void rtnl_link_vf_set_addr(struct rtnl_link_vf *vf_data, struct nl_addr *addr) {
895 	if (vf_data->vf_lladdr)
896 		nl_addr_put(vf_data->vf_lladdr);
897 
898 	nl_addr_get(addr);
899 	vf_data->vf_lladdr = addr;
900 	vf_data->ce_mask |= SRIOV_ATTR_ADDR;
901 
902 	return;
903 }
904 
905 /**
906  * Set the Infiniband node GUID for the SRIOV Virtual Function object
907  * @param vf_data 	SRIOV VF object
908  * @param guid  	node GUID
909  */
rtnl_link_vf_set_ib_node_guid(struct rtnl_link_vf * vf_data,uint64_t guid)910 void rtnl_link_vf_set_ib_node_guid(struct rtnl_link_vf *vf_data,
911 				   uint64_t guid) {
912 	vf_data->vf_guid_node = guid;
913 	vf_data->ce_mask |= SRIOV_ATTR_IB_NODE_GUID;
914 
915 	return;
916 }
917 
918 /**
919  * Set the Infiniband port GUID for the SRIOV Virtual Function object
920  * @param vf_data 	SRIOV VF object
921  * @param guid  	port GUID
922  */
rtnl_link_vf_set_ib_port_guid(struct rtnl_link_vf * vf_data,uint64_t guid)923 void rtnl_link_vf_set_ib_port_guid(struct rtnl_link_vf *vf_data,
924 				   uint64_t guid) {
925 	vf_data->vf_guid_port = guid;
926 	vf_data->ce_mask |= SRIOV_ATTR_IB_PORT_GUID;
927 
928 	return;
929 }
930 
931 /**
932  * Get index of SRIOV Virtual Function
933  * @arg vf_data 	SRIOV VF object
934  * @arg vf_index 	Pointer to store VF index
935  *
936  * @see rtnl_link_get_num_vf()
937  *
938  * @return 0 if index is present and vf_index is set
939  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
940  * @return -NLE_NOATTR if the VF index is not set
941  */
rtnl_link_vf_get_index(struct rtnl_link_vf * vf_data,uint32_t * vf_index)942 int rtnl_link_vf_get_index(struct rtnl_link_vf *vf_data, uint32_t *vf_index)
943 {
944 	if (!vf_data)
945 		return -NLE_OBJ_NOTFOUND;
946 
947 	if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
948 		*vf_index = vf_data->vf_index;
949 	else
950 		return -NLE_NOATTR;
951 
952 	return 0;
953 }
954 
955 /**
956  * Set index of SRIOV Virtual Function object
957  * @param vf_data 	SRIOV VF object
958  * @param vf_index 	Index value
959  *
960  * @see rtnl_link_vf_get_index()
961  */
rtnl_link_vf_set_index(struct rtnl_link_vf * vf_data,uint32_t vf_index)962 void rtnl_link_vf_set_index(struct rtnl_link_vf *vf_data, uint32_t vf_index)
963 {
964 	vf_data->vf_index = vf_index;
965 	vf_data->ce_mask |= SRIOV_ATTR_INDEX;
966 
967 	return;
968 }
969 
970 /**
971  * Get link state of SRIOV Virtual Function
972  * @arg vf_data  	SRIOV VF object
973  * @arg vf_linkstate 	Pointer to store VF link state
974  *
975  * @see rtnl_link_get_num_vf()
976  * @see rtnl_link_set_linkstate()
977  *
978  * @return 0 if link state is present and vf_linkstate is set
979  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
980  * @return -NLE_NOATTR if the VF link state is not set
981  */
rtnl_link_vf_get_linkstate(struct rtnl_link_vf * vf_data,uint32_t * vf_linkstate)982 int rtnl_link_vf_get_linkstate(struct rtnl_link_vf *vf_data,
983 			       uint32_t *vf_linkstate)
984 {
985 	if (!vf_data)
986 		return -NLE_OBJ_NOTFOUND;
987 
988 	if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE)
989 		*vf_linkstate = vf_data->vf_linkstate;
990 	else
991 		return -NLE_NOATTR;
992 
993 	return 0;
994 }
995 
996 /**
997  * Set link state of SRIOV Virtual Function object
998  * @param vf_data 	SRIOV VF object
999  * @param vf_linkstate Link state value
1000  *
1001  * @see rtnl_link_get_linkstate()
1002  *
1003  * Not all hardware supports setting link state. If the feature is unsupported,
1004  * the link change request will fail with -NLE_OPNOTSUPP
1005  */
rtnl_link_vf_set_linkstate(struct rtnl_link_vf * vf_data,uint32_t vf_linkstate)1006 void rtnl_link_vf_set_linkstate(struct rtnl_link_vf *vf_data,
1007 				uint32_t vf_linkstate) {
1008 	vf_data->vf_linkstate = vf_linkstate;
1009 	vf_data->ce_mask |= SRIOV_ATTR_LINK_STATE;
1010 
1011 	return;
1012 }
1013 
1014 /**
1015  * Get TX Rate Limit of SRIOV Virtual Function
1016  * @arg vf_data 	SRIOV VF object
1017  * @arg vf_rate 	Pointer to store VF rate limiting data
1018  *
1019  * @see rtnl_link_get_num_vf()
1020  * @see rtnl_link_set_rate()
1021  *
1022  * When the older rate API has been implemented, the rate member of the struct
1023  * will be set, and the api member will be set to RTNL_LINK_VF_API_OLD.
1024  * When the newer rate API has been implemented, the max_tx_rate
1025  * and/or the minx_tx_rate will be set, and the api member will be set to
1026  * RTNL_LINK_VF_API_NEW.
1027  *
1028  * Old rate API supports only a maximum TX rate.
1029  *   ip link set dev vf 0 rate
1030  * New rate API supports minumum and maximum TX rates.
1031  *   ip link set dev vf 0 min_tx_rate
1032  *   ip link set dev vf 0 max_tx_rate
1033  *
1034  * @return 0 if rate is present and vf_rate is set
1035  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
1036  * @return -NLE_NOATTR if the VF rate is not set
1037  */
rtnl_link_vf_get_rate(struct rtnl_link_vf * vf_data,struct nl_vf_rate * vf_rate)1038 int rtnl_link_vf_get_rate(struct rtnl_link_vf *vf_data,
1039 			  struct nl_vf_rate *vf_rate)
1040 {
1041 	int set = 0;
1042 
1043 	if (!vf_data)
1044 		return -NLE_OBJ_NOTFOUND;
1045 
1046 	vf_rate->api = RTNL_LINK_VF_RATE_API_UNSPEC;
1047 	vf_rate->rate = 0;
1048 	vf_rate->max_tx_rate = 0;
1049 	vf_rate->min_tx_rate = 0;
1050 
1051 	if (vf_data->ce_mask & SRIOV_ATTR_RATE_MAX) {
1052 		if (vf_data->vf_max_tx_rate) {
1053 			vf_rate->api = RTNL_LINK_VF_RATE_API_NEW;
1054 			vf_rate->max_tx_rate = vf_data->vf_max_tx_rate;
1055 			set = 1;
1056 		}
1057 	}
1058 	if (vf_data->ce_mask & SRIOV_ATTR_RATE_MIN) {
1059 		if (vf_data->vf_min_tx_rate) {
1060 			vf_rate->api = RTNL_LINK_VF_RATE_API_NEW;
1061 			vf_rate->min_tx_rate = vf_data->vf_min_tx_rate;
1062 			set = 1;
1063 		}
1064 	}
1065 	if ((!set) && (vf_data->ce_mask & SRIOV_ATTR_TX_RATE)) {
1066 		if (vf_data->vf_rate) {
1067 			vf_rate->api = RTNL_LINK_VF_RATE_API_OLD;
1068 			vf_rate->rate = vf_data->vf_rate;
1069 			set = 1;
1070 		}
1071 	}
1072 
1073 	if (!set)
1074 		return -NLE_NOATTR;
1075 
1076 	return 0;
1077 }
1078 
1079 /**
1080  * Set TX Rate Limit of SRIOV Virtual Function object
1081  * @param vf_data 	SRIOV VF object
1082  * @param vf_rate 	Rate limiting structure
1083  *
1084  * @see rtnl_link_vf_get_rate()
1085  *
1086  * When setting the rate, the API level must be specificed.
1087  * Valid API levels:
1088  *   RTNL_LINK_VF_RATE_API_NEW
1089  *   RTNL_LINK_VF_RATE_API_OLD
1090  *
1091  * When using the new API, if either the min_tx_rate or
1092  * max_tx_rate has been set, and the other is being changed,
1093  * you must specify the currently set values to preserve
1094  * them. If this is not done, that setting will be disabled.
1095  *
1096  * Old rate API supports only a maximum TX rate.
1097  *   ip link set dev vf 0 rate
1098  * New rate API supports minumum and maximum TX rates.
1099  *   ip link set dev vf 0 min_tx_rate
1100  *   ip link set dev vf 0 max_tx_rate
1101  *
1102  * Not all hardware supports min_tx_rate.
1103  */
rtnl_link_vf_set_rate(struct rtnl_link_vf * vf_data,struct nl_vf_rate * vf_rate)1104 void rtnl_link_vf_set_rate(struct rtnl_link_vf *vf_data,
1105 			   struct nl_vf_rate *vf_rate) {
1106 	if (vf_rate->api == RTNL_LINK_VF_RATE_API_OLD) {
1107 		vf_data->vf_rate = vf_rate->rate;
1108 		vf_data->ce_mask |= SRIOV_ATTR_TX_RATE;
1109 	} else if (vf_rate->api == RTNL_LINK_VF_RATE_API_NEW) {
1110 		vf_data->vf_max_tx_rate = vf_rate->max_tx_rate;
1111 		vf_data->ce_mask |= SRIOV_ATTR_RATE_MAX;
1112 
1113 		vf_data->vf_min_tx_rate = vf_rate->min_tx_rate;
1114 		vf_data->ce_mask |= SRIOV_ATTR_RATE_MIN;
1115 	}
1116 
1117 	return;
1118 }
1119 
1120 /**
1121  * Get RSS Query EN value of SRIOV Virtual Function
1122  * @arg vf_data 	SRIOV VF object
1123  * @arg vf_rss_query_en	Pointer to store VF RSS Query value
1124  *
1125  * @see rtnl_link_get_num_vf()
1126  * @see rtnl_link_vf_set_rss_query_en()
1127  *
1128  * @return 0 if rss_query_en is present and vf_rss_query_en is set
1129  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
1130  * @return -NLE_NOATTR if the VF RSS Query EN value is not set
1131  */
rtnl_link_vf_get_rss_query_en(struct rtnl_link_vf * vf_data,uint32_t * vf_rss_query_en)1132 int rtnl_link_vf_get_rss_query_en(struct rtnl_link_vf *vf_data,
1133 				  uint32_t *vf_rss_query_en)
1134 {
1135 	if (!vf_data)
1136 		return -NLE_OBJ_NOTFOUND;
1137 
1138 	if (vf_data->ce_mask & SRIOV_ATTR_RSS_QUERY_EN)
1139 		*vf_rss_query_en = vf_data->vf_rss_query_en;
1140 	else
1141 		return -NLE_NOATTR;
1142 
1143 	return 0;
1144 }
1145 
1146 /**
1147  * Set RSS configuration querying of SRIOV Virtual Function Object
1148  * @arg vf_data 	SRIOV VF object
1149  * @arg vf_rss_query_en	RSS Query value
1150  *
1151  * @see rtnl_link_vf_get_rss_query_en()
1152  */
rtnl_link_vf_set_rss_query_en(struct rtnl_link_vf * vf_data,uint32_t vf_rss_query_en)1153 void rtnl_link_vf_set_rss_query_en(struct rtnl_link_vf *vf_data,
1154 				  uint32_t vf_rss_query_en) {
1155 	vf_data->vf_rss_query_en = vf_rss_query_en;
1156 	vf_data->ce_mask |= SRIOV_ATTR_RSS_QUERY_EN;
1157 
1158 	return;
1159 }
1160 
1161 /**
1162  * Get spoof checking value of SRIOV Virtual Function
1163  * @arg vf_data 	SRIOV VF object
1164  * @arg vf_spoofchk 	Pointer to store VF spoofchk value
1165  *
1166  * @see rtnl_link_get_num_vf()
1167  * @see rtnl_link_set_spoofchk()
1168  *
1169  * @return 0 if spoofchk is present and vf_spoofchk is set
1170  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
1171  * @return -NLE_NOATTR if the VF spoofcheck is not set
1172  */
rtnl_link_vf_get_spoofchk(struct rtnl_link_vf * vf_data,uint32_t * vf_spoofchk)1173 int rtnl_link_vf_get_spoofchk(struct rtnl_link_vf *vf_data,
1174 			      uint32_t *vf_spoofchk)
1175 {
1176 	if (!vf_data)
1177 		return -NLE_OBJ_NOTFOUND;
1178 
1179 	if (vf_data->ce_mask & SRIOV_ATTR_SPOOFCHK)
1180 		*vf_spoofchk = vf_data->vf_spoofchk;
1181 	else
1182 		return -NLE_NOATTR;
1183 
1184 	return 0;
1185 }
1186 
1187 /**
1188  * Set spoof checking value of SRIOV Virtual Function Object
1189  * @param vf_data
1190  * @param vf_spoofchk
1191  *
1192  * @see rtnl_link_vf_get_spoofchk()
1193  */
rtnl_link_vf_set_spoofchk(struct rtnl_link_vf * vf_data,uint32_t vf_spoofchk)1194 void rtnl_link_vf_set_spoofchk(struct rtnl_link_vf *vf_data,
1195 			       uint32_t vf_spoofchk) {
1196 	vf_data->vf_spoofchk = vf_spoofchk;
1197 	vf_data->ce_mask |= SRIOV_ATTR_SPOOFCHK;
1198 
1199 	return;
1200 }
1201 
1202 /**
1203  * Get value of stat counter for SRIOV Virtual Function
1204  * @arg vf_data 	SRIOV VF object
1205  * @arg stat 		Identifier of statistical counter
1206  * @arg vf_stat 	Pointer to store VF stat value in
1207  *
1208  * @see rtnl_link_get_num_vf()
1209  *
1210  * @return 0 if stat is present and vf_stat is set
1211  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
1212  * @return -NLE_NOATTR if the VF stat is not set
1213  */
rtnl_link_vf_get_stat(struct rtnl_link_vf * vf_data,rtnl_link_vf_stats_t stat,uint64_t * vf_stat)1214 int rtnl_link_vf_get_stat(struct rtnl_link_vf *vf_data,
1215 			  rtnl_link_vf_stats_t stat, uint64_t *vf_stat)
1216 {
1217 	if (!vf_data)
1218 		return -NLE_OBJ_NOTFOUND;
1219 
1220 	if (vf_data->ce_mask & SRIOV_ATTR_STATS)
1221 		*vf_stat = vf_data->vf_stats[stat];
1222 	else
1223 		return -NLE_NOATTR;
1224 
1225 	return 0;
1226 }
1227 
1228 /**
1229  * Get trust setting of SRIOV Virtual Function
1230  * @arg vf_data 	SRIOV VF object
1231  * @arg vf_trust 	Pointer to store VF trust value
1232  *
1233  * @see rtnl_link_get_num_vf()
1234  * @see rtnl_link_set_trust()
1235  *
1236  * @return 0 if trust is present and vf_trust is set
1237  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
1238  * @return -NLE_NOATTR if the VF trust setting is not set
1239  */
rtnl_link_vf_get_trust(struct rtnl_link_vf * vf_data,uint32_t * vf_trust)1240 int rtnl_link_vf_get_trust(struct rtnl_link_vf *vf_data, uint32_t *vf_trust)
1241 {
1242 	if (!vf_data)
1243 		return -NLE_OBJ_NOTFOUND;
1244 
1245 	if (vf_data->ce_mask & SRIOV_ATTR_TRUST)
1246 		*vf_trust = vf_data->vf_trust;
1247 	else
1248 		return -NLE_NOATTR;
1249 
1250 	return 0;
1251 }
1252 
1253 /**
1254  * Set user trust setting on SRIOV Virtual Function Object
1255  * @param vf_data
1256  * @param vf_trust
1257  *
1258  * @see rtnl_link_vf_get_trust()
1259  */
rtnl_link_vf_set_trust(struct rtnl_link_vf * vf_data,uint32_t vf_trust)1260 void rtnl_link_vf_set_trust(struct rtnl_link_vf *vf_data, uint32_t vf_trust) {
1261 	vf_data->vf_trust = vf_trust;
1262 	vf_data->ce_mask |= SRIOV_ATTR_TRUST;
1263 
1264 	return;
1265 }
1266 
1267 /**
1268  * Get an array of VLANS on SRIOV Virtual Function
1269  * @arg vf_data 	SRIOV VF object
1270  * @arg vf_vlans 	Pointer to nl_vf_vlans_t struct to store vlan info.
1271  *
1272  * @see rtnl_link_get_num_vf()
1273  *
1274  * The SRIOV VF VLANs object must be returned to the SRIOV VF object with
1275  * rtnl_link_vf_vlans_put() when operations are done to prevent memory leaks.
1276  *
1277  * @copydoc pointer_lifetime_warning
1278  * @return 0 if VLAN info is present and vf_vlans is set
1279  * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
1280  * @return -NLE_NOATTR if the VF vlans is not set
1281  */
rtnl_link_vf_get_vlans(struct rtnl_link_vf * vf_data,nl_vf_vlans_t ** vf_vlans)1282 int rtnl_link_vf_get_vlans(struct rtnl_link_vf *vf_data,
1283 			   nl_vf_vlans_t **vf_vlans) {
1284 	nl_vf_vlans_t *vf;
1285 
1286 	if (!vf_data)
1287 		return -NLE_OBJ_NOTFOUND;
1288 
1289 	if (vf_data->ce_mask & SRIOV_ATTR_VLAN) {
1290 		vf = vf_data->vf_vlans;
1291 		vf->ce_refcnt++;
1292 		*vf_vlans = vf;
1293 	} else
1294 		return -NLE_NOATTR;
1295 
1296 	return 0;
1297 }
1298 
1299 /**
1300  * Add a SRIOV VF VLANs object to the SRIOV Virtual Function Object
1301  * @param vf_data 	SRIOV VF object
1302  * @param vf_vlans 	SRIOV VF VLANs object
1303  *
1304  * @see rtnl_link_vf_get_vlans()
1305  * @see rtnl_link_vf_vlan_alloc()
1306  *
1307  * This function assigns ownership of the SRIOV VF object \p vf_vlans
1308  * to the SRIOV Virtual Function object \p vf_data. Do not use
1309  * rtnl_link_vf_vlan_put() on \p vf_vlans after this.
1310  */
rtnl_link_vf_set_vlans(struct rtnl_link_vf * vf_data,nl_vf_vlans_t * vf_vlans)1311 void rtnl_link_vf_set_vlans(struct rtnl_link_vf *vf_data,
1312 			    nl_vf_vlans_t *vf_vlans) {
1313 	if (!vf_data||!vf_vlans)
1314 		return;
1315 
1316 	vf_data->vf_vlans = vf_vlans;
1317 	vf_data->vf_vlans->ce_refcnt++;
1318 	vf_data->ce_mask |= SRIOV_ATTR_VLAN;
1319 
1320 	return;
1321 }
1322 
1323 /**
1324  * Allocate a SRIOV VF VLAN object
1325  * @param vf_vlans 	Pointer to store VLAN object at
1326  * @param vlan_count 	Number of VLANs that will be stored in VLAN object
1327  *
1328  * The SRIOV VF VLANs object must be returned to the sRIOV VF object with
1329  * rtnl_link_vf_vlan_put() when operations are done to prevent memory leaks.
1330  *
1331  * @return 0 if VLAN object is created and vf_vlans is set.
1332  * @return -NLE_NOMEM if object could not be allocated.
1333  * @return -NLE_INVAL if vlan_count is more than supported by SRIOV VF
1334  */
rtnl_link_vf_vlan_alloc(nl_vf_vlans_t ** vf_vlans,int vlan_count)1335 int rtnl_link_vf_vlan_alloc(nl_vf_vlans_t **vf_vlans, int vlan_count) {
1336 	nl_vf_vlans_t *vlans;
1337 	nl_vf_vlan_info_t *vlan_info;
1338 
1339 	if (vlan_count > MAX_VLAN_LIST_LEN)
1340 		return -NLE_INVAL;
1341 
1342 	vlans = calloc(1, sizeof(*vlans));
1343 	if (!vlans)
1344 		return -NLE_NOMEM;
1345 
1346 	vlan_info = calloc(vlan_count+1, sizeof(*vlan_info));
1347 	if (!vlan_info) {
1348 		free(vlans);
1349 		return -NLE_NOMEM;
1350 	}
1351 
1352 	NL_DBG(4, "Allocated new SRIOV VF VLANs object %p\n", vlans);
1353 
1354 	vlans->ce_refcnt = 1;
1355 	vlans->size = vlan_count;
1356 	vlans->vlans = vlan_info;
1357 	*vf_vlans = vlans;
1358 
1359 	return 0;
1360 }
1361 
1362 /**
1363  * Free an allocated SRIOV VF VLANs object
1364  * @param vf_vlans 	SRIOV VF VLANs object
1365  */
rtnl_link_vf_vlan_free(nl_vf_vlans_t * vf_vlans)1366 void rtnl_link_vf_vlan_free(nl_vf_vlans_t *vf_vlans) {
1367 	if (!vf_vlans)
1368 		return;
1369 
1370 	if (vf_vlans->ce_refcnt > 0)
1371 		NL_DBG(1, "Warning: Freeing SRIOV VF VLANs object in use...\n");
1372 
1373 	NL_DBG(4, "Freed SRIOV VF object %p\n", vf_vlans);
1374 	free(vf_vlans->vlans);
1375 	free(vf_vlans);
1376 
1377 	return;
1378 }
1379 
1380 /**
1381  * Return SRIOV VF VLANs object to the owning SRIOV VF object.
1382  * @param vf_vlans 	SRIOV VF VLANs object
1383  */
rtnl_link_vf_vlan_put(nl_vf_vlans_t * vf_vlans)1384 void rtnl_link_vf_vlan_put(nl_vf_vlans_t *vf_vlans) {
1385 	if (!vf_vlans)
1386 		return;
1387 
1388 	vf_vlans->ce_refcnt--;
1389 	NL_DBG(4, "Returned SRIOV VF VLANs object reference %p, %i remaining\n",
1390 	       vf_vlans, vf_vlans->ce_refcnt);
1391 
1392 	if (vf_vlans->ce_refcnt < 0)
1393 		BUG();
1394 
1395 	if (vf_vlans->ce_refcnt <= 0)
1396 		rtnl_link_vf_vlan_free(vf_vlans);
1397 
1398 	return;
1399 }
1400 
1401 /** @} */
1402 
1403 /**
1404  * @name Utilities
1405  * @{
1406  */
1407 
1408 static const struct trans_tbl vf_link_states[] = {
1409 	__ADD(IFLA_VF_LINK_STATE_AUTO, autodetect),
1410 	__ADD(IFLA_VF_LINK_STATE_ENABLE, up),
1411 	__ADD(IFLA_VF_LINK_STATE_DISABLE, down),
1412 };
1413 
rtnl_link_vf_linkstate2str(uint32_t ls,char * buf,size_t len)1414 char *rtnl_link_vf_linkstate2str(uint32_t ls, char *buf, size_t len)
1415 {
1416 	return __type2str(ls, buf, len, vf_link_states,
1417 			  ARRAY_SIZE(vf_link_states));
1418 }
1419 
rtnl_link_vf_str2linkstate(const char * name)1420 int rtnl_link_vf_str2linkstate(const char *name)
1421 {
1422 	return __str2type(name, vf_link_states, ARRAY_SIZE(vf_link_states));
1423 }
1424 
1425 static const struct trans_tbl vf_vlan_proto[] = {
1426 	__ADD(ETH_P_8021Q, 8021Q),
1427 	__ADD(ETH_P_8021AD, 8021AD),
1428 };
1429 
rtnl_link_vf_vlanproto2str(uint16_t proto,char * buf,size_t len)1430 char *rtnl_link_vf_vlanproto2str(uint16_t proto, char *buf, size_t len)
1431 {
1432 	return __type2str(proto, buf, len, vf_vlan_proto,
1433 			  ARRAY_SIZE(vf_vlan_proto));
1434 }
1435 
rtnl_link_vf_str2vlanproto(const char * name)1436 int rtnl_link_vf_str2vlanproto(const char *name)
1437 {
1438 	return __str2type(name, vf_vlan_proto, ARRAY_SIZE(vf_vlan_proto));
1439 }
1440 
1441 /* Return a guid from a format checked string.
1442  * Format string must be xx:xx:xx:xx:xx:xx:xx:xx where XX can be an
1443  * arbitrary hex digit
1444  *
1445  * Function modified from original at iproute2/lib/utils.c:get_guid()
1446  * Original by Eli Cohen <[email protected]>.
1447  * iproute2 git commit d91fb3f4c7e4dba806541bdc90b1fb60a3581541
1448  */
rtnl_link_vf_str2guid(uint64_t * guid,const char * guid_s)1449 int rtnl_link_vf_str2guid(uint64_t *guid, const char *guid_s) {
1450 	unsigned long int tmp;
1451 	char *endptr;
1452 	int i;
1453 
1454 	if (strlen(guid_s) != RTNL_VF_GUID_STR_LEN)
1455 		return -1;
1456 
1457 	for (i = 0; i < 7; i++) {
1458 		if (guid_s[2 + i * 3] != ':')
1459 			return -1;
1460 	}
1461 
1462 	*guid = 0;
1463 	for (i = 0; i < 8; i++) {
1464 		tmp = strtoul(guid_s + i * 3, &endptr, 16);
1465 		if (endptr != guid_s + i * 3 + 2)
1466 			return -1;
1467 
1468 		if (tmp > 255)
1469 			return -1;
1470 
1471 		*guid |= tmp << (56 - 8 * i);
1472 	}
1473 
1474 	return 0;
1475 }
1476 
1477 /** @} */
1478 
1479 /** @} */
1480