1*41418a7cSKevin Bowling /*
2*41418a7cSKevin Bowling * SPDX-License-Identifier: BSD-2-Clause
3*41418a7cSKevin Bowling *
4*41418a7cSKevin Bowling * Copyright (c) 2019 Intel Corporation
5*41418a7cSKevin Bowling * Copyright (c) 2026 Kevin Bowling <kbowling@FreeBSD.org>
6*41418a7cSKevin Bowling */
7*41418a7cSKevin Bowling
8*41418a7cSKevin Bowling #include <sys/types.h>
9*41418a7cSKevin Bowling
10*41418a7cSKevin Bowling #include <net/ethernet.h>
11*41418a7cSKevin Bowling #include <net/if.h>
12*41418a7cSKevin Bowling
13*41418a7cSKevin Bowling #include <err.h>
14*41418a7cSKevin Bowling #include <errno.h>
15*41418a7cSKevin Bowling #include <inttypes.h>
16*41418a7cSKevin Bowling #include <stdio.h>
17*41418a7cSKevin Bowling
18*41418a7cSKevin Bowling #include "ifconfig.h"
19*41418a7cSKevin Bowling
20*41418a7cSKevin Bowling static void
vf_group_begin(bool * printed,const char * name)21*41418a7cSKevin Bowling vf_group_begin(bool *printed, const char *name)
22*41418a7cSKevin Bowling {
23*41418a7cSKevin Bowling
24*41418a7cSKevin Bowling if (!*printed) {
25*41418a7cSKevin Bowling printf("\t\t\t%s:", name);
26*41418a7cSKevin Bowling *printed = true;
27*41418a7cSKevin Bowling }
28*41418a7cSKevin Bowling }
29*41418a7cSKevin Bowling
30*41418a7cSKevin Bowling static void
vf_group_end(bool printed)31*41418a7cSKevin Bowling vf_group_end(bool printed)
32*41418a7cSKevin Bowling {
33*41418a7cSKevin Bowling
34*41418a7cSKevin Bowling if (printed)
35*41418a7cSKevin Bowling putchar('\n');
36*41418a7cSKevin Bowling }
37*41418a7cSKevin Bowling
38*41418a7cSKevin Bowling static void
vf_print_rate(const char * name,uint64_t rate,const char * zero)39*41418a7cSKevin Bowling vf_print_rate(const char *name, uint64_t rate, const char *zero)
40*41418a7cSKevin Bowling {
41*41418a7cSKevin Bowling
42*41418a7cSKevin Bowling if (rate == 0)
43*41418a7cSKevin Bowling printf(" %s=%s", name, zero);
44*41418a7cSKevin Bowling else if (rate % IF_Mbps(1) == 0)
45*41418a7cSKevin Bowling printf(" %s=%" PRIu64 "Mbps", name, rate / IF_Mbps(1));
46*41418a7cSKevin Bowling else
47*41418a7cSKevin Bowling printf(" %s=%" PRIu64 "bps", name, rate);
48*41418a7cSKevin Bowling }
49*41418a7cSKevin Bowling
50*41418a7cSKevin Bowling static const char *
vf_link_state_name(enum ifconfig_vf_link_state state)51*41418a7cSKevin Bowling vf_link_state_name(enum ifconfig_vf_link_state state)
52*41418a7cSKevin Bowling {
53*41418a7cSKevin Bowling
54*41418a7cSKevin Bowling switch (state) {
55*41418a7cSKevin Bowling case IFCONFIG_VF_LINK_DOWN:
56*41418a7cSKevin Bowling return ("down");
57*41418a7cSKevin Bowling case IFCONFIG_VF_LINK_UP:
58*41418a7cSKevin Bowling return ("up");
59*41418a7cSKevin Bowling case IFCONFIG_VF_LINK_AUTO:
60*41418a7cSKevin Bowling return ("auto");
61*41418a7cSKevin Bowling default:
62*41418a7cSKevin Bowling return ("unknown");
63*41418a7cSKevin Bowling }
64*41418a7cSKevin Bowling }
65*41418a7cSKevin Bowling
66*41418a7cSKevin Bowling static const char *
vf_vlan_mode_name(enum ifconfig_vf_vlan_mode mode)67*41418a7cSKevin Bowling vf_vlan_mode_name(enum ifconfig_vf_vlan_mode mode)
68*41418a7cSKevin Bowling {
69*41418a7cSKevin Bowling
70*41418a7cSKevin Bowling switch (mode) {
71*41418a7cSKevin Bowling case IFCONFIG_VF_VLAN_ACCESS:
72*41418a7cSKevin Bowling return ("access");
73*41418a7cSKevin Bowling case IFCONFIG_VF_VLAN_TRUNK:
74*41418a7cSKevin Bowling return ("trunk");
75*41418a7cSKevin Bowling default:
76*41418a7cSKevin Bowling return ("unknown");
77*41418a7cSKevin Bowling }
78*41418a7cSKevin Bowling }
79*41418a7cSKevin Bowling
80*41418a7cSKevin Bowling static void
vf_print_vlan_proto(uint16_t proto)81*41418a7cSKevin Bowling vf_print_vlan_proto(uint16_t proto)
82*41418a7cSKevin Bowling {
83*41418a7cSKevin Bowling
84*41418a7cSKevin Bowling switch (proto) {
85*41418a7cSKevin Bowling case ETHERTYPE_VLAN:
86*41418a7cSKevin Bowling printf("802.1q");
87*41418a7cSKevin Bowling break;
88*41418a7cSKevin Bowling case ETHERTYPE_QINQ:
89*41418a7cSKevin Bowling printf("802.1ad");
90*41418a7cSKevin Bowling break;
91*41418a7cSKevin Bowling default:
92*41418a7cSKevin Bowling printf("0x%04x", proto);
93*41418a7cSKevin Bowling break;
94*41418a7cSKevin Bowling }
95*41418a7cSKevin Bowling }
96*41418a7cSKevin Bowling
97*41418a7cSKevin Bowling static void
vf_driver_field(const struct ifconfig_vf_extension_field * field)98*41418a7cSKevin Bowling vf_driver_field(const struct ifconfig_vf_extension_field *field)
99*41418a7cSKevin Bowling {
100*41418a7cSKevin Bowling const uint8_t *data;
101*41418a7cSKevin Bowling size_t i, length;
102*41418a7cSKevin Bowling
103*41418a7cSKevin Bowling printf(" %s=", field->name);
104*41418a7cSKevin Bowling switch (field->type) {
105*41418a7cSKevin Bowling case IFCONFIG_VF_EXT_BOOL:
106*41418a7cSKevin Bowling printf("%s", field->value.boolean ? "yes" : "no");
107*41418a7cSKevin Bowling break;
108*41418a7cSKevin Bowling case IFCONFIG_VF_EXT_NUMBER:
109*41418a7cSKevin Bowling printf("%" PRIu64, field->value.number);
110*41418a7cSKevin Bowling break;
111*41418a7cSKevin Bowling case IFCONFIG_VF_EXT_STRING:
112*41418a7cSKevin Bowling printf("%s", field->value.string);
113*41418a7cSKevin Bowling break;
114*41418a7cSKevin Bowling case IFCONFIG_VF_EXT_BINARY:
115*41418a7cSKevin Bowling data = field->value.binary.data;
116*41418a7cSKevin Bowling length = field->value.binary.length;
117*41418a7cSKevin Bowling printf("0x");
118*41418a7cSKevin Bowling for (i = 0; i < length; i++)
119*41418a7cSKevin Bowling printf("%02x", data[i]);
120*41418a7cSKevin Bowling break;
121*41418a7cSKevin Bowling default:
122*41418a7cSKevin Bowling break;
123*41418a7cSKevin Bowling }
124*41418a7cSKevin Bowling }
125*41418a7cSKevin Bowling
126*41418a7cSKevin Bowling static void
vf_driver_status(const struct ifconfig_vf_info * vf)127*41418a7cSKevin Bowling vf_driver_status(const struct ifconfig_vf_info *vf)
128*41418a7cSKevin Bowling {
129*41418a7cSKevin Bowling const struct ifconfig_vf_extension *driver;
130*41418a7cSKevin Bowling const struct ifconfig_vf_extension_field *field;
131*41418a7cSKevin Bowling size_t i, j;
132*41418a7cSKevin Bowling
133*41418a7cSKevin Bowling for (i = 0; i < vf->num_extensions; i++) {
134*41418a7cSKevin Bowling driver = &vf->extensions[i];
135*41418a7cSKevin Bowling printf("\t\t\t%s: version=%u", driver->name,
136*41418a7cSKevin Bowling driver->version);
137*41418a7cSKevin Bowling for (j = 0; j < driver->num_fields; j++) {
138*41418a7cSKevin Bowling field = &driver->fields[j];
139*41418a7cSKevin Bowling vf_driver_field(field);
140*41418a7cSKevin Bowling }
141*41418a7cSKevin Bowling putchar('\n');
142*41418a7cSKevin Bowling }
143*41418a7cSKevin Bowling }
144*41418a7cSKevin Bowling
145*41418a7cSKevin Bowling void
vf_status(if_ctx * ctx)146*41418a7cSKevin Bowling vf_status(if_ctx *ctx)
147*41418a7cSKevin Bowling {
148*41418a7cSKevin Bowling struct ifconfig_vf_status *status;
149*41418a7cSKevin Bowling const struct ifconfig_vf_info *vf;
150*41418a7cSKevin Bowling const struct ether_addr *mac;
151*41418a7cSKevin Bowling const char *mode;
152*41418a7cSKevin Bowling uint64_t speed;
153*41418a7cSKevin Bowling bool printed;
154*41418a7cSKevin Bowling size_t i;
155*41418a7cSKevin Bowling int error;
156*41418a7cSKevin Bowling
157*41418a7cSKevin Bowling if (ifconfig_get_vf_status(lifh, ctx->ifname, &status) != 0) {
158*41418a7cSKevin Bowling error = ifconfig_err_errno(lifh);
159*41418a7cSKevin Bowling if (error != EOPNOTSUPP)
160*41418a7cSKevin Bowling warnc(error, "%s: VF status", ctx->ifname);
161*41418a7cSKevin Bowling return;
162*41418a7cSKevin Bowling }
163*41418a7cSKevin Bowling
164*41418a7cSKevin Bowling if (status->pf_link_state_present) {
165*41418a7cSKevin Bowling printf("\tVF-visible PF link: state=%s",
166*41418a7cSKevin Bowling vf_link_state_name(status->pf_link_state));
167*41418a7cSKevin Bowling }
168*41418a7cSKevin Bowling speed = status->pf_link_speed;
169*41418a7cSKevin Bowling if (status->pf_link_speed_present) {
170*41418a7cSKevin Bowling if (speed % IF_Mbps(1) == 0)
171*41418a7cSKevin Bowling printf(" speed=%" PRIu64 "Mbps", speed / IF_Mbps(1));
172*41418a7cSKevin Bowling else
173*41418a7cSKevin Bowling printf(" speed=%" PRIu64 "bps", speed);
174*41418a7cSKevin Bowling }
175*41418a7cSKevin Bowling if (status->pf_link_state_present || status->pf_link_speed_present)
176*41418a7cSKevin Bowling putchar('\n');
177*41418a7cSKevin Bowling
178*41418a7cSKevin Bowling printf("\tvirtual functions: %zu\n", status->num_vfs);
179*41418a7cSKevin Bowling for (i = 0; i < status->num_vfs; i++) {
180*41418a7cSKevin Bowling vf = status->vfs[i];
181*41418a7cSKevin Bowling printf("\t\tvf %3u:\n", vf->index);
182*41418a7cSKevin Bowling
183*41418a7cSKevin Bowling printed = false;
184*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_MAC)) != 0) {
185*41418a7cSKevin Bowling mac = (const struct ether_addr *)(const void *)vf->mac;
186*41418a7cSKevin Bowling vf_group_begin(&printed, "identity");
187*41418a7cSKevin Bowling printf(" mac=%s", ether_ntoa(mac));
188*41418a7cSKevin Bowling }
189*41418a7cSKevin Bowling vf_group_end(printed);
190*41418a7cSKevin Bowling
191*41418a7cSKevin Bowling printed = false;
192*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_CONFIGURED)) != 0) {
193*41418a7cSKevin Bowling vf_group_begin(&printed, "state");
194*41418a7cSKevin Bowling printf(" configured=%s", vf->configured ? "yes" : "no");
195*41418a7cSKevin Bowling }
196*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_INITIALIZED)) != 0) {
197*41418a7cSKevin Bowling vf_group_begin(&printed, "state");
198*41418a7cSKevin Bowling printf(" initialized=%s", vf->initialized ? "yes" : "no");
199*41418a7cSKevin Bowling }
200*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_TRAFFIC_ALLOWED)) != 0) {
201*41418a7cSKevin Bowling vf_group_begin(&printed, "state");
202*41418a7cSKevin Bowling printf(" traffic=%s", vf->traffic_allowed ?
203*41418a7cSKevin Bowling "allowed" : "denied");
204*41418a7cSKevin Bowling }
205*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_FAULT_BLOCKED)) != 0) {
206*41418a7cSKevin Bowling vf_group_begin(&printed, "state");
207*41418a7cSKevin Bowling printf(" fault-blocked=%s", vf->fault_blocked ?
208*41418a7cSKevin Bowling "yes" : "no");
209*41418a7cSKevin Bowling }
210*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_QUARANTINED)) != 0) {
211*41418a7cSKevin Bowling vf_group_begin(&printed, "state");
212*41418a7cSKevin Bowling printf(" quarantined=%s", vf->quarantined ? "yes" : "no");
213*41418a7cSKevin Bowling }
214*41418a7cSKevin Bowling vf_group_end(printed);
215*41418a7cSKevin Bowling
216*41418a7cSKevin Bowling printed = false;
217*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_NUM_TX_QUEUES)) != 0) {
218*41418a7cSKevin Bowling vf_group_begin(&printed, "resources");
219*41418a7cSKevin Bowling printf(" tx-queues=%u", vf->tx_queue_count);
220*41418a7cSKevin Bowling }
221*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_NUM_RX_QUEUES)) != 0) {
222*41418a7cSKevin Bowling vf_group_begin(&printed, "resources");
223*41418a7cSKevin Bowling printf(" rx-queues=%u", vf->rx_queue_count);
224*41418a7cSKevin Bowling }
225*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_MIN_TX_RATE)) != 0) {
226*41418a7cSKevin Bowling vf_group_begin(&printed, "resources");
227*41418a7cSKevin Bowling vf_print_rate("min-tx-rate", vf->min_tx_rate_bps, "none");
228*41418a7cSKevin Bowling }
229*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_MAX_TX_RATE)) != 0) {
230*41418a7cSKevin Bowling vf_group_begin(&printed, "resources");
231*41418a7cSKevin Bowling vf_print_rate("max-tx-rate", vf->max_tx_rate_bps,
232*41418a7cSKevin Bowling "unlimited");
233*41418a7cSKevin Bowling }
234*41418a7cSKevin Bowling vf_group_end(printed);
235*41418a7cSKevin Bowling
236*41418a7cSKevin Bowling printed = false;
237*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_VLAN_MODE)) != 0) {
238*41418a7cSKevin Bowling mode = vf_vlan_mode_name(vf->vlan_mode);
239*41418a7cSKevin Bowling vf_group_begin(&printed, "vlan");
240*41418a7cSKevin Bowling printf(" mode=%s", mode);
241*41418a7cSKevin Bowling if (vf->vlan_mode == IFCONFIG_VF_VLAN_ACCESS &&
242*41418a7cSKevin Bowling (vf->fields & (1ULL << IFLAF_VF_VLAN)) != 0)
243*41418a7cSKevin Bowling printf(" vid=%u", vf->vlan);
244*41418a7cSKevin Bowling if (vf->vlan_mode == IFCONFIG_VF_VLAN_ACCESS &&
245*41418a7cSKevin Bowling (vf->fields & (1ULL << IFLAF_VF_VLAN_PCP)) != 0)
246*41418a7cSKevin Bowling printf(" pcp=%u", vf->vlan_pcp);
247*41418a7cSKevin Bowling if (vf->vlan_mode == IFCONFIG_VF_VLAN_ACCESS &&
248*41418a7cSKevin Bowling (vf->fields & (1ULL << IFLAF_VF_VLAN_PROTO)) != 0) {
249*41418a7cSKevin Bowling printf(" proto=");
250*41418a7cSKevin Bowling vf_print_vlan_proto(vf->vlan_proto);
251*41418a7cSKevin Bowling }
252*41418a7cSKevin Bowling }
253*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_VLAN_COUNT)) != 0) {
254*41418a7cSKevin Bowling vf_group_begin(&printed, "vlan");
255*41418a7cSKevin Bowling printf(" filters=%u", vf->vlan_count);
256*41418a7cSKevin Bowling }
257*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_VLAN_LIMIT)) != 0) {
258*41418a7cSKevin Bowling vf_group_begin(&printed, "vlan");
259*41418a7cSKevin Bowling printf(" limit=%u", vf->vlan_limit);
260*41418a7cSKevin Bowling }
261*41418a7cSKevin Bowling vf_group_end(printed);
262*41418a7cSKevin Bowling
263*41418a7cSKevin Bowling printed = false;
264*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_ALLOW_SET_MAC)) != 0) {
265*41418a7cSKevin Bowling vf_group_begin(&printed, "policy");
266*41418a7cSKevin Bowling printf(" set-mac=%s", vf->allow_set_mac ?
267*41418a7cSKevin Bowling "allowed" : "denied");
268*41418a7cSKevin Bowling }
269*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_ALLOW_SET_VLAN)) != 0) {
270*41418a7cSKevin Bowling vf_group_begin(&printed, "policy");
271*41418a7cSKevin Bowling printf(" set-vlan=%s", vf->allow_set_vlan ?
272*41418a7cSKevin Bowling "allowed" : "denied");
273*41418a7cSKevin Bowling }
274*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_MAC_ANTI_SPOOF)) != 0) {
275*41418a7cSKevin Bowling vf_group_begin(&printed, "policy");
276*41418a7cSKevin Bowling printf(" anti-spoof=%s", vf->mac_anti_spoof ? "on" : "off");
277*41418a7cSKevin Bowling }
278*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_ALLOW_PROMISC)) != 0) {
279*41418a7cSKevin Bowling vf_group_begin(&printed, "policy");
280*41418a7cSKevin Bowling printf(" promisc=%s", vf->allow_promisc ?
281*41418a7cSKevin Bowling "allowed" : "denied");
282*41418a7cSKevin Bowling }
283*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_LINK_STATE_POLICY)) != 0) {
284*41418a7cSKevin Bowling vf_group_begin(&printed, "policy");
285*41418a7cSKevin Bowling printf(" link-state=%s",
286*41418a7cSKevin Bowling vf_link_state_name(vf->link_state_policy));
287*41418a7cSKevin Bowling }
288*41418a7cSKevin Bowling vf_group_end(printed);
289*41418a7cSKevin Bowling
290*41418a7cSKevin Bowling printed = false;
291*41418a7cSKevin Bowling if ((vf->fields & (1ULL << IFLAF_VF_API_VERSION)) != 0) {
292*41418a7cSKevin Bowling vf_group_begin(&printed, "protocol");
293*41418a7cSKevin Bowling printf(" api=%s", vf->api_version);
294*41418a7cSKevin Bowling }
295*41418a7cSKevin Bowling vf_group_end(printed);
296*41418a7cSKevin Bowling
297*41418a7cSKevin Bowling vf_driver_status(vf);
298*41418a7cSKevin Bowling }
299*41418a7cSKevin Bowling ifconfig_free_vf_status(status);
300*41418a7cSKevin Bowling }
301