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