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