Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167245426
D58777.id184030.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D58777.id184030.diff
View Options
diff --git a/lib/libifconfig/Symbol.map b/lib/libifconfig/Symbol.map
--- a/lib/libifconfig/Symbol.map
+++ b/lib/libifconfig/Symbol.map
@@ -84,3 +84,8 @@
ifconfig_sfp_rev_description;
ifconfig_sfp_rev_symbol;
};
+
+FBSD_1.9 {
+ ifconfig_free_vf_status;
+ ifconfig_get_vf_status;
+};
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -28,6 +28,7 @@
#include <sys/types.h>
+#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_bridgevar.h> /* for ifbvlan_set_t */
@@ -198,6 +199,124 @@
int ifconfig_get_ifstatus(ifconfig_handle_t *h, const char *name,
struct ifstat *stat);
+/*
+ * SR-IOV VF status schema contract.
+ *
+ * The presence mask distinguishes an omitted fact from false or zero. The
+ * common fields have transport-independent meanings. Driver-specific facts
+ * remain owned by a stable, versioned driver namespace: that driver defines
+ * the names, types, and meanings of its fields. Their named, typed form lets
+ * generic consumers carry or display extensions without knowing each driver's
+ * schema. Consumers that interpret extensions must ignore unknown namespaces
+ * and fields. Additive optional fields retain a namespace version; an
+ * incompatible type or semantic change requires a new version. All pointed-to
+ * storage belongs to the returned status object and is released by
+ * ifconfig_free_vf_status().
+ */
+
+/* Optional fields in struct ifconfig_vf_info. */
+#define IFCONFIG_VF_F_CONFIGURED (1ULL << 0)
+#define IFCONFIG_VF_F_INITIALIZED (1ULL << 1)
+#define IFCONFIG_VF_F_MAC (1ULL << 2)
+#define IFCONFIG_VF_F_VLAN_MODE (1ULL << 3)
+#define IFCONFIG_VF_F_VLAN (1ULL << 4)
+#define IFCONFIG_VF_F_VLAN_COUNT (1ULL << 5)
+#define IFCONFIG_VF_F_VLAN_LIMIT (1ULL << 6)
+#define IFCONFIG_VF_F_NUM_QUEUES (1ULL << 7)
+#define IFCONFIG_VF_F_ALLOW_SET_MAC (1ULL << 8)
+#define IFCONFIG_VF_F_ALLOW_SET_VLAN (1ULL << 9)
+#define IFCONFIG_VF_F_MAC_ANTI_SPOOF (1ULL << 10)
+#define IFCONFIG_VF_F_ALLOW_PROMISC (1ULL << 11)
+#define IFCONFIG_VF_F_TRAFFIC_ENABLED (1ULL << 12)
+#define IFCONFIG_VF_F_MDD_BLOCKED (1ULL << 13)
+#define IFCONFIG_VF_F_QUARANTINED (1ULL << 14)
+#define IFCONFIG_VF_F_API_VERSION (1ULL << 15)
+#define IFCONFIG_VF_F_LINK_STATE_POLICY (1ULL << 16)
+
+enum ifconfig_vf_vlan_mode {
+ IFCONFIG_VF_VLAN_UNKNOWN = 0,
+ IFCONFIG_VF_VLAN_ACCESS,
+ IFCONFIG_VF_VLAN_TRUNK,
+};
+
+enum ifconfig_vf_link_state {
+ IFCONFIG_VF_LINK_UNKNOWN = 0,
+ IFCONFIG_VF_LINK_DOWN,
+ IFCONFIG_VF_LINK_UP,
+ IFCONFIG_VF_LINK_AUTO,
+};
+
+enum ifconfig_vf_extension_type {
+ IFCONFIG_VF_EXT_BOOL = 1,
+ IFCONFIG_VF_EXT_NUMBER,
+ IFCONFIG_VF_EXT_STRING,
+ IFCONFIG_VF_EXT_BINARY,
+};
+
+struct ifconfig_vf_extension_field {
+ char *name;
+ enum ifconfig_vf_extension_type type;
+ union {
+ bool boolean;
+ uint64_t number;
+ char *string;
+ struct {
+ void *data;
+ size_t length;
+ } binary;
+ } value;
+};
+
+struct ifconfig_vf_extension {
+ char *name;
+ uint32_t version;
+ size_t num_fields;
+ struct ifconfig_vf_extension_field *fields;
+};
+
+struct ifconfig_vf_info {
+ uint64_t fields;
+ uint32_t index;
+ uint32_t vlan_count;
+ uint32_t vlan_limit;
+ uint32_t num_queues;
+ uint16_t vlan;
+ uint8_t mac[ETHER_ADDR_LEN];
+ enum ifconfig_vf_vlan_mode vlan_mode;
+ enum ifconfig_vf_link_state link_state_policy;
+ bool configured;
+ bool initialized;
+ bool allow_set_mac;
+ bool allow_set_vlan;
+ bool mac_anti_spoof;
+ bool allow_promisc;
+ bool traffic_enabled;
+ bool mdd_blocked;
+ bool quarantined;
+ char *api_version;
+ size_t num_extensions;
+ struct ifconfig_vf_extension *extensions;
+};
+
+struct ifconfig_vf_status {
+ uint64_t pf_link_speed;
+ enum ifconfig_vf_link_state pf_link_state;
+ bool pf_link_state_present;
+ bool pf_link_speed_present;
+ size_t num_vfs;
+ struct ifconfig_vf_info *vfs;
+};
+
+/** Retrieve structured SR-IOV VF status for an interface through rtnetlink.
+ * @param h An open ifconfig state object
+ * @param name The PF interface name
+ * @param statusp Return argument. Free it with ifconfig_free_vf_status().
+ * @return 0 on success, -1 on failure
+ */
+int ifconfig_get_vf_status(ifconfig_handle_t *h, const char *name,
+ struct ifconfig_vf_status **statusp);
+void ifconfig_free_vf_status(struct ifconfig_vf_status *status);
+
/** Retrieve the interface media information
* @param h An open ifconfig state object
* @param name The interface name
diff --git a/lib/libifconfig/libifconfig_nl.c b/lib/libifconfig/libifconfig_nl.c
--- a/lib/libifconfig/libifconfig_nl.c
+++ b/lib/libifconfig/libifconfig_nl.c
@@ -4,11 +4,18 @@
* Copyright (c) 2025, Muhammad Saheed <saheed@FreeBSD.org>
*/
+#include <sys/param.h>
+
#include <netlink/netlink.h>
#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_route_parsers.h>
#include <netlink/route/common.h>
#include <netlink/route/interface.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
#include "libifconfig.h"
#include "libifconfig_internal.h"
@@ -70,3 +77,298 @@
return (ifconfig_modify_flags(h, ifname, flag, IFF_UP));
}
+
+void
+ifconfig_free_vf_status(struct ifconfig_vf_status *status)
+{
+ struct ifconfig_vf_extension_field *field;
+ struct ifconfig_vf_extension *extension;
+ struct ifconfig_vf_info *vf;
+ size_t i, j, k;
+
+ if (status == NULL)
+ return;
+ for (i = 0; i < status->num_vfs; i++) {
+ vf = &status->vfs[i];
+ free(vf->api_version);
+ for (j = 0; j < vf->num_extensions; j++) {
+ extension = &vf->extensions[j];
+ free(extension->name);
+ for (k = 0; k < extension->num_fields; k++) {
+ field = &extension->fields[k];
+ free(field->name);
+ if (field->type == IFCONFIG_VF_EXT_STRING)
+ free(field->value.string);
+ else if (field->type == IFCONFIG_VF_EXT_BINARY)
+ free(field->value.binary.data);
+ }
+ free(extension->fields);
+ }
+ free(vf->extensions);
+ }
+ free(status->vfs);
+ free(status);
+}
+
+static int
+ifconfig_copy_vf_extension_field(struct ifconfig_vf_extension_field *dst,
+ const struct snl_parsed_vf_driver_field *src)
+{
+ size_t length;
+
+ dst->name = strdup(src->name);
+ if (dst->name == NULL)
+ return (ENOMEM);
+ switch (src->type) {
+ case SNL_VFDF_BOOL:
+ dst->type = IFCONFIG_VF_EXT_BOOL;
+ dst->value.boolean = src->boolean;
+ break;
+ case SNL_VFDF_NUMBER:
+ dst->type = IFCONFIG_VF_EXT_NUMBER;
+ dst->value.number = src->number;
+ break;
+ case SNL_VFDF_STRING:
+ dst->type = IFCONFIG_VF_EXT_STRING;
+ dst->value.string = strdup(src->string);
+ if (dst->value.string == NULL)
+ return (ENOMEM);
+ break;
+ case SNL_VFDF_BINARY:
+ dst->type = IFCONFIG_VF_EXT_BINARY;
+ length = NLA_DATA_LEN(src->binary);
+ if (length == 0)
+ return (EBADMSG);
+ dst->value.binary.data = malloc(length);
+ if (dst->value.binary.data == NULL)
+ return (ENOMEM);
+ memcpy(dst->value.binary.data, NLA_DATA(src->binary), length);
+ dst->value.binary.length = length;
+ break;
+ default:
+ return (EBADMSG);
+ }
+ return (0);
+}
+
+static int
+ifconfig_copy_vf_extensions(struct ifconfig_vf_info *dst,
+ const struct snl_parsed_vf *src)
+{
+ const struct snl_parsed_vf_driver_field *src_field;
+ const struct snl_parsed_vf_driver *src_extension;
+ struct ifconfig_vf_extension *extension;
+ size_t i, j;
+ int error;
+
+ dst->num_extensions = src->drivers.count;
+ if (dst->num_extensions == 0)
+ return (0);
+ dst->extensions = calloc(dst->num_extensions, sizeof(*dst->extensions));
+ if (dst->extensions == NULL)
+ return (ENOMEM);
+ for (i = 0; i < dst->num_extensions; i++) {
+ src_extension = src->drivers.items[i];
+ extension = &dst->extensions[i];
+ extension->name = strdup(src_extension->name);
+ if (extension->name == NULL)
+ return (ENOMEM);
+ extension->version = src_extension->version;
+ extension->num_fields = src_extension->fields.count;
+ if (extension->num_fields == 0)
+ continue;
+ extension->fields = calloc(extension->num_fields,
+ sizeof(*extension->fields));
+ if (extension->fields == NULL)
+ return (ENOMEM);
+ for (j = 0; j < extension->num_fields; j++) {
+ src_field = src_extension->fields.items[j];
+ error = ifconfig_copy_vf_extension_field(
+ &extension->fields[j], src_field);
+ if (error != 0)
+ return (error);
+ }
+ }
+ return (0);
+}
+
+static uint64_t
+ifconfig_vf_fields(uint64_t attrs)
+{
+ static const struct {
+ uint32_t attr;
+ uint64_t field;
+ } map[] = {
+ { IFLAF_VF_CONFIGURED, IFCONFIG_VF_F_CONFIGURED },
+ { IFLAF_VF_INITIALIZED, IFCONFIG_VF_F_INITIALIZED },
+ { IFLAF_VF_MAC, IFCONFIG_VF_F_MAC },
+ { IFLAF_VF_VLAN_MODE, IFCONFIG_VF_F_VLAN_MODE },
+ { IFLAF_VF_VLAN, IFCONFIG_VF_F_VLAN },
+ { IFLAF_VF_VLAN_COUNT, IFCONFIG_VF_F_VLAN_COUNT },
+ { IFLAF_VF_VLAN_LIMIT, IFCONFIG_VF_F_VLAN_LIMIT },
+ { IFLAF_VF_NUM_QUEUES, IFCONFIG_VF_F_NUM_QUEUES },
+ { IFLAF_VF_ALLOW_SET_MAC, IFCONFIG_VF_F_ALLOW_SET_MAC },
+ { IFLAF_VF_ALLOW_SET_VLAN, IFCONFIG_VF_F_ALLOW_SET_VLAN },
+ { IFLAF_VF_MAC_ANTI_SPOOF, IFCONFIG_VF_F_MAC_ANTI_SPOOF },
+ { IFLAF_VF_ALLOW_PROMISC, IFCONFIG_VF_F_ALLOW_PROMISC },
+ { IFLAF_VF_TRAFFIC_ENABLED, IFCONFIG_VF_F_TRAFFIC_ENABLED },
+ { IFLAF_VF_MDD_BLOCKED, IFCONFIG_VF_F_MDD_BLOCKED },
+ { IFLAF_VF_QUARANTINED, IFCONFIG_VF_F_QUARANTINED },
+ { IFLAF_VF_API_VERSION, IFCONFIG_VF_F_API_VERSION },
+ { IFLAF_VF_LINK_STATE_POLICY,
+ IFCONFIG_VF_F_LINK_STATE_POLICY },
+ };
+ uint64_t fields;
+ size_t i;
+
+ fields = 0;
+ for (i = 0; i < nitems(map); i++) {
+ if ((attrs & (1ULL << map[i].attr)) != 0)
+ fields |= map[i].field;
+ }
+ return (fields);
+}
+
+static int
+ifconfig_copy_vf(struct ifconfig_vf_info *dst,
+ const struct snl_parsed_vf *src)
+{
+
+ dst->fields = ifconfig_vf_fields(src->attrs);
+ dst->index = src->index;
+ dst->vlan_count = src->vlan_count;
+ dst->vlan_limit = src->vlan_limit;
+ dst->num_queues = src->num_queues;
+ dst->vlan = src->vlan;
+ if ((src->attrs & (1ULL << IFLAF_VF_MAC)) != 0) {
+ if (NLA_DATA_LEN(src->mac) != sizeof(dst->mac))
+ return (EBADMSG);
+ memcpy(dst->mac, NLA_DATA(src->mac), sizeof(dst->mac));
+ }
+ dst->vlan_mode = (enum ifconfig_vf_vlan_mode)src->vlan_mode;
+ dst->link_state_policy =
+ (enum ifconfig_vf_link_state)src->link_state_policy;
+ dst->configured = src->configured;
+ dst->initialized = src->initialized;
+ dst->allow_set_mac = src->allow_set_mac;
+ dst->allow_set_vlan = src->allow_set_vlan;
+ dst->mac_anti_spoof = src->mac_anti_spoof;
+ dst->allow_promisc = src->allow_promisc;
+ dst->traffic_enabled = src->traffic_enabled;
+ dst->mdd_blocked = src->mdd_blocked;
+ dst->quarantined = src->quarantined;
+ if ((src->attrs & (1ULL << IFLAF_VF_API_VERSION)) != 0) {
+ dst->api_version = strdup(src->api_version);
+ if (dst->api_version == NULL)
+ return (ENOMEM);
+ }
+ return (ifconfig_copy_vf_extensions(dst, src));
+}
+
+int
+ifconfig_get_vf_status(ifconfig_handle_t *h, const char *name,
+ struct ifconfig_vf_status **statusp)
+{
+ struct ifconfig_vf_status *status;
+ struct snl_parsed_link link = {};
+ struct snl_errmsg_data e = {};
+ struct snl_state ss = {};
+ struct snl_writer nw = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq;
+ size_t i;
+ int error;
+
+ if (h == NULL || name == NULL || statusp == NULL) {
+ if (h != NULL)
+ ifconfig_error(h, OTHER, EINVAL);
+ return (-1);
+ }
+ *statusp = NULL;
+ if (strnlen(name, IFNAMSIZ) == IFNAMSIZ) {
+ ifconfig_error(h, OTHER, ENAMETOOLONG);
+ return (-1);
+ }
+ if (!snl_init(&ss, NETLINK_ROUTE)) {
+ ifconfig_error(h, NETLINK, ENOTSUP);
+ return (-1);
+ }
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_msg_request(&nw, NL_RTM_GETLINK);
+ if (hdr == NULL ||
+ snl_reserve_msg_object(&nw, struct ifinfomsg) == NULL ||
+ !snl_add_msg_attr_string(&nw, IFLA_IFNAME, name) ||
+ !snl_add_msg_attr_u32(&nw, IFLA_EXT_MASK, RTEXT_FILTER_VF) ||
+ (hdr = snl_finalize_msg(&nw)) == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
+ seq = hdr->nlmsg_seq;
+ if (!snl_send_message(&ss, hdr)) {
+ error = EIO;
+ goto fail;
+ }
+ hdr = snl_read_reply(&ss, seq);
+ if (hdr == NULL) {
+ error = EIO;
+ goto fail;
+ }
+ if (hdr->nlmsg_type == NLMSG_ERROR) {
+ if (!snl_parse_errmsg(&ss, hdr, &e) || e.error == 0)
+ error = EBADMSG;
+ else
+ error = e.error;
+ goto fail;
+ }
+ if (hdr->nlmsg_type != NL_RTM_NEWLINK ||
+ !snl_parse_nlmsg(&ss, hdr, &snl_rtm_link_parser, &link) ||
+ !link.iflaf_vf_status.present) {
+ error = EOPNOTSUPP;
+ goto fail;
+ }
+ if (link.iflaf_vf_status.error != 0) {
+ error = link.iflaf_vf_status.error;
+ goto fail;
+ }
+ if (link.ifla_num_vf != link.iflaf_vf_status.vfs.count) {
+ error = EBADMSG;
+ goto fail;
+ }
+
+ status = calloc(1, sizeof(*status));
+ if (status == NULL) {
+ error = ENOMEM;
+ goto fail;
+ }
+ status->pf_link_state = (enum ifconfig_vf_link_state)
+ link.iflaf_vf_status.pf_link_state;
+ status->pf_link_state_present = true;
+ status->pf_link_speed = link.iflaf_vf_status.pf_link_speed;
+ status->pf_link_speed_present = status->pf_link_speed != 0;
+ status->num_vfs = link.iflaf_vf_status.vfs.count;
+ if (status->num_vfs != 0) {
+ status->vfs = calloc(status->num_vfs, sizeof(*status->vfs));
+ if (status->vfs == NULL) {
+ error = ENOMEM;
+ goto fail_status;
+ }
+ }
+ for (i = 0; i < status->num_vfs; i++) {
+ error = ifconfig_copy_vf(&status->vfs[i],
+ link.iflaf_vf_status.vfs.items[i]);
+ if (error != 0)
+ goto fail_status;
+ }
+ ifconfig_error_clear(h);
+ *statusp = status;
+ snl_free(&ss);
+ return (0);
+
+fail_status:
+ ifconfig_free_vf_status(status);
+fail:
+ ifconfig_error(h, error == ENOMEM ? OTHER : NETLINK, error);
+ snl_free(&ss);
+ return (-1);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Aug 21, 7:57 AM (5 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37025341
Default Alt Text
D58777.id184030.diff (13 KB)
Attached To
Mode
D58777: libifconfig: Add a native SR-IOV VF status query
Attached
Detach File
Event Timeline
Log In to Comment