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