Page MenuHomeFreeBSD

D58777.id184030.diff
No OneTemporary

D58777.id184030.diff

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

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)

Event Timeline