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