git: 80f03e63d67e - main - netlink: improve interface handling
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 14 Dec 2022 19:53:15 UTC
The branch main has been updated by melifaro:
URL: https://cgit.FreeBSD.org/src/commit/?id=80f03e63d67ede8fedbed4bd6bf6b12ec2ab2cfb
commit 80f03e63d67ede8fedbed4bd6bf6b12ec2ab2cfb
Author: Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2022-12-14 19:45:01 +0000
Commit: Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2022-12-14 19:52:35 +0000
netlink: improve interface handling
* Separate interface creation from interface modification code
* Support setting some interface attributes (ifdescr, mtu, up/down, promisc)
* Improve interaction with the cloners requiring to parse/write custom
interface attributes
* Add bitmask-based way of checking if the attribute is present in the
message
* Don't use multipart RTM_GETLINK replies when searching for the
specific interface names
* Use ENODEV instead of ENOENT in case of failed RTM_GETLINK search
* Add python netlink test helpers
* Add some netlink interface tests
Differential Revision: https://reviews.freebsd.org/D37668
---
etc/mtree/BSD.tests.dist | 2 +
share/man/man4/rtnetlink.4 | 2 +
sys/netlink/netlink_message_parser.c | 20 +-
sys/netlink/netlink_message_parser.h | 28 +-
sys/netlink/route/iface.c | 208 ++++-
sys/netlink/route/iface_drivers.c | 100 ++-
sys/netlink/route/interface.h | 2 +-
sys/netlink/route/route_var.h | 15 +-
tests/atf_python/sys/net/Makefile | 2 +-
tests/atf_python/sys/net/netlink.py | 1495 ++++++++++++++++++++++++++++++++++
tests/sys/netlink/Makefile | 14 +
tests/sys/netlink/test_rtnl_iface.py | 281 +++++++
12 files changed, 2116 insertions(+), 53 deletions(-)
diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
index 5fbcd3c31669..7724138d3298 100644
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -826,6 +826,8 @@
tunnel
..
..
+ netlink
+ ..
netmap
..
netpfil
diff --git a/share/man/man4/rtnetlink.4 b/share/man/man4/rtnetlink.4
index 9f20671719f0..a06807809691 100644
--- a/share/man/man4/rtnetlink.4
+++ b/share/man/man4/rtnetlink.4
@@ -309,6 +309,8 @@ IFLA_ALT_IFNAME interface name
(binary) (readonly) Link-level broadcast address.
.It Dv IFLA_IFNAME
(string) New interface name.
+.It Dv IFLA_IFALIAS
+(string) Interface description.
.It Dv IFLA_LINK
(uint32_t) (readonly) Interface index.
.It Dv IFLA_MASTER
diff --git a/sys/netlink/netlink_message_parser.c b/sys/netlink/netlink_message_parser.c
index d33eddb800e4..451d9d497491 100644
--- a/sys/netlink/netlink_message_parser.c
+++ b/sys/netlink/netlink_message_parser.c
@@ -147,17 +147,23 @@ nl_parse_attrs_raw(struct nlattr *nla_head, int len, const struct nlattr_parser
return (0);
}
-int
-nl_parse_attrs(struct nlmsghdr *hdr, int hdrlen, struct nlattr_parser *ps, int pslen,
- struct nl_pstate *npt, void *target)
+void
+nl_get_attrs_bmask_raw(struct nlattr *nla_head, int len, struct nlattr_bmask *bm)
{
- int off = NLMSG_HDRLEN + NETLINK_ALIGN(hdrlen);
- int len = hdr->nlmsg_len - off;
- struct nlattr *nla_head = (struct nlattr *)((char *)hdr + off);
+ struct nlattr *nla = NULL;
+
+ bzero(bm->mask, sizeof(bm->mask));
- return (nl_parse_attrs_raw(nla_head, len, ps, pslen, npt, target));
+ NLA_FOREACH(nla, nla_head, len) {
+ if (nla->nla_len < sizeof(struct nlattr))
+ return;
+ int nla_type = nla->nla_type & NLA_TYPE_MASK;
+ if (nla_type <= sizeof(bm->mask) * 8)
+ bm->mask[nla_type / 8] |= 1 << (nla_type % 8);
+ }
}
+
int
nlattr_get_flag(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
{
diff --git a/sys/netlink/netlink_message_parser.h b/sys/netlink/netlink_message_parser.h
index b23b223ef80e..96fd1c7337b7 100644
--- a/sys/netlink/netlink_message_parser.h
+++ b/sys/netlink/netlink_message_parser.h
@@ -152,15 +152,21 @@ static const struct nlhdr_parser _name = { \
.np_size = NL_ARRAY_LEN(_np), \
}
-struct nlarr_hdr {
- int num_items;
- int max_items;
+struct nlattr_bmask {
+ uint64_t mask[2];
};
+static inline bool
+nl_has_attr(const struct nlattr_bmask *bm, unsigned int attr_type)
+{
+ MPASS(attr_type < sizeof(bm->mask) * 8);
+
+ return ((bm->mask[attr_type / 8] & (1 << (attr_type % 8))));
+}
+void nl_get_attrs_bmask_raw(struct nlattr *nla_head, int len, struct nlattr_bmask *bm);
+
int nl_parse_attrs_raw(struct nlattr *nla_head, int len, const struct nlattr_parser *ps,
int pslen, struct nl_pstate *npt, void *target);
-int nl_parse_attrs(struct nlmsghdr *hdr, int hdrlen, struct nlattr_parser *ps,
- int pslen, struct nl_pstate *npt, void *target);
int nlattr_get_flag(struct nlattr *nla, struct nl_pstate *npt,
const void *arg, void *target);
@@ -270,5 +276,17 @@ nl_parse_nlmsg(struct nlmsghdr *hdr, const struct nlhdr_parser *parser,
return (nl_parse_header(hdr + 1, hdr->nlmsg_len - sizeof(*hdr), parser, npt, target));
}
+static inline void
+nl_get_attrs_bmask_nlmsg(struct nlmsghdr *hdr, const struct nlhdr_parser *parser,
+ struct nlattr_bmask *bm)
+{
+ struct nlattr *nla_head;
+
+ nla_head = (struct nlattr *)((char *)(hdr + 1) + parser->nl_hdr_off);
+ int len = hdr->nlmsg_len - sizeof(*hdr) - parser->nl_hdr_off;
+
+ nl_get_attrs_bmask_raw(nla_head, len, bm);
+}
+
#endif
#endif
diff --git a/sys/netlink/route/iface.c b/sys/netlink/route/iface.c
index 579869e9662c..b033ba71009d 100644
--- a/sys/netlink/route/iface.c
+++ b/sys/netlink/route/iface.c
@@ -75,6 +75,8 @@ static SLIST_HEAD(, nl_cloner) nl_cloners = SLIST_HEAD_INITIALIZER(nl_cloners);
static struct sx rtnl_cloner_lock;
SX_SYSINIT(rtnl_cloner_lock, &rtnl_cloner_lock, "rtnl cloner lock");
+static struct nl_cloner *rtnl_iface_find_cloner_locked(const char *name);
+
/*
* RTM_GETLINK request
* sendto(3, {{len=32, type=RTM_GETLINK, flags=NLM_F_REQUEST|NLM_F_DUMP, seq=1641940952, pid=0},
@@ -286,11 +288,23 @@ dump_iface(struct nl_writer *nw, struct ifnet *ifp, const struct nlmsghdr *hdr,
nlattr_add_u32(nw, IFLA_MAX_MTU, 9000);
nlattr_add_u32(nw, IFLA_GROUP, 0);
*/
+
+ if (ifp->if_description != NULL)
+ nlattr_add_string(nw, IFLA_IFALIAS, ifp->if_description);
+
get_stats(nw, ifp);
uint32_t val = (ifp->if_flags & IFF_PROMISC) != 0;
nlattr_add_u32(nw, IFLA_PROMISCUITY, val);
+ sx_slock(&rtnl_cloner_lock);
+ struct nl_cloner *cloner = rtnl_iface_find_cloner_locked(ifp->if_dname);
+ if (cloner != NULL && cloner->dump_f != NULL) {
+ /* Ignore any dump error */
+ cloner->dump_f(ifp, nw);
+ }
+ sx_sunlock(&rtnl_cloner_lock);
+
if (nlmsg_end(nw))
return (true);
@@ -320,6 +334,8 @@ check_ifmsg(void *hdr, struct nl_pstate *npt)
static const struct nlfield_parser nlf_p_if[] = {
{ .off_in = _IN(ifi_type), .off_out = _OUT(ifi_type), .cb = nlf_get_u16 },
{ .off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = nlf_get_u32 },
+ { .off_in = _IN(ifi_flags), .off_out = _OUT(ifi_flags), .cb = nlf_get_u32 },
+ { .off_in = _IN(ifi_change), .off_out = _OUT(ifi_change), .cb = nlf_get_u32 },
};
static const struct nlattr_parser nla_p_linfo[] = {
@@ -333,6 +349,7 @@ static const struct nlattr_parser nla_p_if[] = {
{ .type = IFLA_MTU, .off = _OUT(ifla_mtu), .cb = nlattr_get_uint32 },
{ .type = IFLA_LINK, .off = _OUT(ifi_index), .cb = nlattr_get_uint32 },
{ .type = IFLA_LINKINFO, .arg = &linfo_parser, .cb = nlattr_get_nested },
+ { .type = IFLA_IFALIAS, .off = _OUT(ifla_ifalias), .cb = nlattr_get_string },
{ .type = IFLA_GROUP, .off = _OUT(ifla_group), .cb = nlattr_get_string },
{ .type = IFLA_ALT_IFNAME, .off = _OUT(ifla_ifname), .cb = nlattr_get_string },
};
@@ -379,28 +396,39 @@ rtnl_handle_getlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *n
.nw = npt->nw,
.hdr.nlmsg_pid = hdr->nlmsg_pid,
.hdr.nlmsg_seq = hdr->nlmsg_seq,
- .hdr.nlmsg_flags = hdr->nlmsg_flags | NLM_F_MULTI,
+ .hdr.nlmsg_flags = hdr->nlmsg_flags,
.hdr.nlmsg_type = NL_RTM_NEWLINK,
};
- /* Fast track for an interface w/ explicit index match */
- if (attrs.ifi_index != 0) {
- NET_EPOCH_ENTER(et);
- ifp = ifnet_byindex_ref(attrs.ifi_index);
- NET_EPOCH_EXIT(et);
- NLP_LOG(LOG_DEBUG3, nlp, "fast track -> searching index %u", attrs.ifi_index);
+ /* Fast track for an interface w/ explicit name or index match */
+ if ((attrs.ifi_index != 0) || (attrs.ifla_ifname != NULL)) {
+ if (attrs.ifi_index != 0) {
+ NLP_LOG(LOG_DEBUG3, nlp, "fast track -> searching index %u",
+ attrs.ifi_index);
+ NET_EPOCH_ENTER(et);
+ ifp = ifnet_byindex_ref(attrs.ifi_index);
+ NET_EPOCH_EXIT(et);
+ } else {
+ NLP_LOG(LOG_DEBUG3, nlp, "fast track -> searching name %s",
+ attrs.ifla_ifname);
+ ifp = ifunit_ref(attrs.ifla_ifname);
+ }
+
if (ifp != NULL) {
if (match_iface(&attrs, ifp)) {
if (!dump_iface(wa.nw, ifp, &wa.hdr, 0))
error = ENOMEM;
} else
- error = ESRCH;
+ error = ENODEV;
if_rele(ifp);
} else
- error = ESRCH;
+ error = ENODEV;
return (error);
}
+ /* Always treat non-direct-match as a multipart message */
+ wa.hdr.nlmsg_flags |= NLM_F_MULTI;
+
/*
* Fetching some link properties require performing ioctl's that may be blocking.
* Address it by saving referenced pointers of the matching links,
@@ -504,48 +532,146 @@ rtnl_handle_dellink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *n
return (error);
}
+/*
+ * New link:
+ * type=RTM_NEWLINK, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, seq=1668185590, pid=0},
+ * {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0}
+ * [
+ * {{nla_len=8, nla_type=IFLA_MTU}, 123},
+ * {{nla_len=10, nla_type=IFLA_IFNAME}, "vlan1"},
+ * {{nla_len=24, nla_type=IFLA_LINKINFO},
+ * [
+ * {{nla_len=8, nla_type=IFLA_INFO_KIND}, "vlan"...},
+ * {{nla_len=12, nla_type=IFLA_INFO_DATA}, "\x06\x00\x01\x00\x7b\x00\x00\x00"}]}]}
+ *
+ * Update link:
+ * type=RTM_NEWLINK, flags=NLM_F_REQUEST|NLM_F_ACK, seq=1668185923, pid=0},
+ * {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=if_nametoindex("lo"), ifi_flags=0, ifi_change=0},
+ * {{nla_len=8, nla_type=IFLA_MTU}, 123}}
+ *
+ *
+ * Check command availability:
+ * type=RTM_NEWLINK, flags=NLM_F_REQUEST|NLM_F_ACK, seq=0, pid=0},
+ * {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0}
+ */
+
+
static int
-rtnl_handle_newlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
+create_link(struct nlmsghdr *hdr, struct nl_parsed_link *lattrs,
+ struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt)
{
- struct nl_cloner *cloner;
- int error;
+ if (lattrs->ifla_ifname == NULL || strlen(lattrs->ifla_ifname) == 0) {
+ NLMSG_REPORT_ERR_MSG(npt, "empty IFLA_IFNAME attribute");
+ return (EINVAL);
+ }
+ if (lattrs->ifla_cloner == NULL || strlen(lattrs->ifla_cloner) == 0) {
+ NLMSG_REPORT_ERR_MSG(npt, "empty IFLA_INFO_KIND attribute");
+ return (EINVAL);
+ }
- struct nl_parsed_link attrs = {};
- error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs);
- if (error != 0)
- return (error);
+ bool found = false;
+ int error = 0;
+
+ sx_slock(&rtnl_cloner_lock);
+ struct nl_cloner *cloner = rtnl_iface_find_cloner_locked(lattrs->ifla_cloner);
+ if (cloner != NULL) {
+ found = true;
+ error = cloner->create_f(lattrs, bm, nlp, npt);
+ }
+ sx_sunlock(&rtnl_cloner_lock);
+
+ if (!found)
+ error = generic_cloner.create_f(lattrs, bm, nlp, npt);
+
+ return (error);
+}
+
+static int
+modify_link(struct nlmsghdr *hdr, struct nl_parsed_link *lattrs,
+ struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt)
+{
+ struct ifnet *ifp = NULL;
+ struct epoch_tracker et;
- if (attrs.ifla_ifname == NULL || strlen(attrs.ifla_ifname) == 0) {
- /* Applications like ip(8) verify RTM_NEWLINK existance
- * by calling it with empty arguments. Always return "innocent"
- * error.
+ if (lattrs->ifi_index == 0 && lattrs->ifla_ifname == NULL) {
+ /*
+ * Applications like ip(8) verify RTM_NEWLINK command
+ * existence by calling it with empty arguments. Always
+ * return "innocent" error in that case.
*/
- NLMSG_REPORT_ERR_MSG(npt, "empty IFLA_IFNAME attribute");
+ NLMSG_REPORT_ERR_MSG(npt, "empty ifi_index field");
return (EPERM);
}
- if (attrs.ifla_cloner == NULL || strlen(attrs.ifla_cloner) == 0) {
- NLMSG_REPORT_ERR_MSG(npt, "empty IFLA_INFO_KIND attribute");
- return (EINVAL);
+ if (lattrs->ifi_index != 0) {
+ NET_EPOCH_ENTER(et);
+ ifp = ifnet_byindex_ref(lattrs->ifi_index);
+ NET_EPOCH_EXIT(et);
+ if (ifp == NULL) {
+ NLMSG_REPORT_ERR_MSG(npt, "unable to find interface #%u",
+ lattrs->ifi_index);
+ return (ENOENT);
+ }
}
- sx_slock(&rtnl_cloner_lock);
- SLIST_FOREACH(cloner, &nl_cloners, next) {
- if (!strcmp(attrs.ifla_cloner, cloner->name)) {
- error = cloner->create_f(&attrs, nlp, npt);
- sx_sunlock(&rtnl_cloner_lock);
- return (error);
+ if (ifp == NULL && lattrs->ifla_ifname != NULL) {
+ ifp = ifunit_ref(lattrs->ifla_ifname);
+ if (ifp == NULL) {
+ NLMSG_REPORT_ERR_MSG(npt, "unable to find interface %s",
+ lattrs->ifla_ifname);
+ return (ENOENT);
}
}
+
+ MPASS(ifp != NULL);
+
+ /*
+ * There can be multiple kinds of interfaces:
+ * 1) cloned, with additional options
+ * 2) cloned, but w/o additional options
+ * 3) non-cloned (e.g. "physical).
+ *
+ * Thus, try to find cloner-specific callback and fallback to the
+ * "default" handler if not found.
+ */
+ bool found = false;
+ int error = 0;
+
+ sx_slock(&rtnl_cloner_lock);
+ struct nl_cloner *cloner = rtnl_iface_find_cloner_locked(ifp->if_dname);
+ if (cloner != NULL) {
+ found = true;
+ error = cloner->modify_f(ifp, lattrs, bm, nlp, npt);
+ }
sx_sunlock(&rtnl_cloner_lock);
- /* TODO: load cloner module if not exists & privilege permits */
- NLMSG_REPORT_ERR_MSG(npt, "interface type %s not supported", attrs.ifla_cloner);
- return (ENOTSUP);
+ if (!found)
+ error = generic_cloner.modify_f(ifp, lattrs, bm, nlp, npt);
+
+ if_rele(ifp);
return (error);
}
+
+static int
+rtnl_handle_newlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *npt)
+{
+ struct nlattr_bmask bm;
+ int error;
+
+ struct nl_parsed_link attrs = {};
+ error = nl_parse_nlmsg(hdr, &ifmsg_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+ nl_get_attrs_bmask_nlmsg(hdr, &ifmsg_parser, &bm);
+
+ if (hdr->nlmsg_flags & NLM_F_CREATE)
+ return (create_link(hdr, &attrs, &bm, nlp, npt));
+ else
+ return (modify_link(hdr, &attrs, &bm, nlp, npt));
+}
+
/*
{ifa_family=AF_INET, ifa_prefixlen=8, ifa_flags=IFA_F_PERMANENT, ifa_scope=RT_SCOPE_HOST, ifa_index=if_nametoindex("lo")},
@@ -863,13 +989,27 @@ rtnl_iface_add_cloner(struct nl_cloner *cloner)
sx_xunlock(&rtnl_cloner_lock);
}
-void rtnl_iface_del_cloner(struct nl_cloner *cloner)
+void
+rtnl_iface_del_cloner(struct nl_cloner *cloner)
{
sx_xlock(&rtnl_cloner_lock);
SLIST_REMOVE(&nl_cloners, cloner, nl_cloner, next);
sx_xunlock(&rtnl_cloner_lock);
}
+static struct nl_cloner *
+rtnl_iface_find_cloner_locked(const char *name)
+{
+ struct nl_cloner *cloner;
+
+ SLIST_FOREACH(cloner, &nl_cloners, next) {
+ if (!strcmp(name, cloner->name))
+ return (cloner);
+ }
+
+ return (NULL);
+}
+
void
rtnl_ifaces_init(void)
{
diff --git a/sys/netlink/route/iface_drivers.c b/sys/netlink/route/iface_drivers.c
index ccc8f2184fa3..7f098b808743 100644
--- a/sys/netlink/route/iface_drivers.c
+++ b/sys/netlink/route/iface_drivers.c
@@ -58,6 +58,95 @@ __FBSDID("$FreeBSD$");
#include <netlink/netlink_debug.h>
_DECLARE_DEBUG(LOG_DEBUG);
+/*
+ * Generic modification interface handler.
+ * Responsible for changing network stack interface attributes
+ * such as state, mtu or description.
+ */
+static int
+modify_generic(struct ifnet *ifp, struct nl_parsed_link *lattrs,
+ const struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt)
+{
+ int error;
+
+ if (lattrs->ifla_ifalias != NULL) {
+ if (nlp_has_priv(nlp, PRIV_NET_SETIFDESCR)) {
+ int len = strlen(lattrs->ifla_ifalias) + 1;
+ char *buf = if_allocdescr(len, true);
+
+ memcpy(buf, lattrs->ifla_ifalias, len);
+ if_setdescr(ifp, buf);
+ getmicrotime(&ifp->if_lastchange);
+ } else {
+ nlmsg_report_err_msg(npt, "Not enough privileges to set descr");
+ return (EPERM);
+ }
+ }
+
+ if ((lattrs->ifi_change & IFF_UP) && (lattrs->ifi_flags & IFF_UP) == 0) {
+ /* Request to down the interface */
+ if_down(ifp);
+ }
+
+ if (lattrs->ifla_mtu > 0) {
+ if (nlp_has_priv(nlp, PRIV_NET_SETIFMTU)) {
+ struct ifreq ifr = { .ifr_mtu = lattrs->ifla_mtu };
+ error = ifhwioctl(SIOCSIFMTU, ifp, (char *)&ifr, curthread);
+ } else {
+ nlmsg_report_err_msg(npt, "Not enough privileges to set mtu");
+ return (EPERM);
+ }
+ }
+
+ if (lattrs->ifi_change & IFF_PROMISC) {
+ error = ifpromisc(ifp, lattrs->ifi_flags & IFF_PROMISC);
+ if (error != 0) {
+ nlmsg_report_err_msg(npt, "unable to set promisc");
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Generic creation interface handler.
+ * Responsible for creating interfaces w/o parameters and setting
+ * misc attributes such as state, mtu or description.
+ */
+static int
+create_generic(struct nl_parsed_link *lattrs, const struct nlattr_bmask *bm,
+ struct nlpcb *nlp, struct nl_pstate *npt)
+{
+ int error = 0;
+
+ struct ifc_data ifd = {};
+ struct ifnet *ifp = NULL;
+ error = ifc_create_ifp(lattrs->ifla_ifname, &ifd, &ifp);
+
+ NLP_LOG(LOG_DEBUG2, nlp, "clone for %s returned %d", lattrs->ifla_ifname, error);
+
+ if (error == 0) {
+ struct epoch_tracker et;
+
+ NET_EPOCH_ENTER(et);
+ bool success = if_try_ref(ifp);
+ NET_EPOCH_EXIT(et);
+ if (!success)
+ return (EINVAL);
+ error = modify_generic(ifp, lattrs, bm, nlp, npt);
+ if_rele(ifp);
+ }
+
+ return (error);
+}
+
+struct nl_cloner generic_cloner = {
+ .name = "_default_",
+ .create_f = create_generic,
+ .modify_f = modify_generic,
+};
+
/*
*
* {len=76, type=RTM_NEWLINK, flags=NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE, seq=1662892737, pid=0},
@@ -87,7 +176,8 @@ static const struct nlattr_parser nla_p_vlan[] = {
NL_DECLARE_ATTR_PARSER(vlan_parser, nla_p_vlan);
static int
-create_vlan(struct nl_parsed_link *lattrs, struct nlpcb *nlp, struct nl_pstate *npt)
+create_vlan(struct nl_parsed_link *lattrs, const struct nlattr_bmask *bm,
+ struct nlpcb *nlp, struct nl_pstate *npt)
{
struct epoch_tracker et;
struct ifnet *ifp;
@@ -147,9 +237,17 @@ create_vlan(struct nl_parsed_link *lattrs, struct nlpcb *nlp, struct nl_pstate *
return (error);
}
+static int
+dump_vlan(struct ifnet *ifp, struct nl_writer *nw)
+{
+ return (0);
+}
+
static struct nl_cloner vlan_cloner = {
.name = "vlan",
.create_f = create_vlan,
+ .modify_f = modify_generic,
+ .dump_f = dump_vlan,
};
diff --git a/sys/netlink/route/interface.h b/sys/netlink/route/interface.h
index 1b8f1cf7b53d..12a8aa718993 100644
--- a/sys/netlink/route/interface.h
+++ b/sys/netlink/route/interface.h
@@ -92,7 +92,7 @@ enum {
#define IFLA_LINKINFO IFLA_LINKINFO
IFLA_NET_NS_PID = 19, /* u32: vnet id (not supported) */
#define IFLA_NET_NS_PID IFLA_NET_NS_PID
- IFLA_IFALIAS = 20, /* not supported */
+ IFLA_IFALIAS = 20, /* string: interface description */
#define IFLA_IFALIAS IFLA_IFALIAS
IFLA_NUM_VF = 21, /* not supported */
#define IFLA_NUM_VF IFLA_NUM_VF
diff --git a/sys/netlink/route/route_var.h b/sys/netlink/route/route_var.h
index 0bcfcc962020..f1e522c7ae05 100644
--- a/sys/netlink/route/route_var.h
+++ b/sys/netlink/route/route_var.h
@@ -66,24 +66,31 @@ struct nl_parsed_link {
char *ifla_group;
char *ifla_ifname;
char *ifla_cloner;
+ char *ifla_ifalias;
struct nlattr *ifla_idata;
unsigned short ifi_type;
int ifi_index;
uint32_t ifla_mtu;
+ uint32_t ifi_flags;
+ uint32_t ifi_change;
};
-typedef int rtnl_iface_create_f(struct nl_parsed_link *lattrs, struct nlpcb *nlp,
- struct nl_pstate *npt);
-typedef int rtnl_iface_modify_f(struct nl_parsed_link *lattrs, struct nlpcb *nlp,
- struct nl_pstate *npt);
+typedef int rtnl_iface_create_f(struct nl_parsed_link *lattrs,
+ const struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt);
+typedef int rtnl_iface_modify_f(struct ifnet *ifp, struct nl_parsed_link *lattrs,
+ const struct nlattr_bmask *bm, struct nlpcb *nlp, struct nl_pstate *npt);
+typedef int rtnl_iface_dump_f(struct ifnet *ifp, struct nl_writer *nw);
struct nl_cloner {
const char *name;
rtnl_iface_create_f *create_f;
rtnl_iface_modify_f *modify_f;
+ rtnl_iface_dump_f *dump_f;
SLIST_ENTRY(nl_cloner) next;
};
+extern struct nl_cloner generic_cloner;
+
void rtnl_ifaces_init(void);
void rtnl_ifaces_destroy(void);
void rtnl_iface_add_cloner(struct nl_cloner *cloner);
diff --git a/tests/atf_python/sys/net/Makefile b/tests/atf_python/sys/net/Makefile
index 05b1d8afe863..63efefd27142 100644
--- a/tests/atf_python/sys/net/Makefile
+++ b/tests/atf_python/sys/net/Makefile
@@ -2,7 +2,7 @@
.PATH: ${.CURDIR}
-FILES= __init__.py rtsock.py tools.py vnet.py
+FILES= __init__.py netlink.py rtsock.py tools.py vnet.py
.include <bsd.own.mk>
FILESDIR= ${TESTSBASE}/atf_python/sys/net
diff --git a/tests/atf_python/sys/net/netlink.py b/tests/atf_python/sys/net/netlink.py
new file mode 100644
index 000000000000..046519ce0343
--- /dev/null
+++ b/tests/atf_python/sys/net/netlink.py
@@ -0,0 +1,1495 @@
+#!/usr/local/bin/python3
+import os
+import socket
+import struct
+import sys
+import unittest
+from ctypes import c_int
+from ctypes import c_ubyte
+from ctypes import c_uint
+from ctypes import c_ushort
+from ctypes import sizeof
+from ctypes import Structure
+from enum import auto
+from enum import Enum
+from typing import Any
+from typing import Dict
+from typing import List
+from typing import NamedTuple
+
+
+def roundup2(val: int, num: int) -> int:
+ if val % num:
+ return (val | (num - 1)) + 1
+ else:
+ return val
+
+
+def align4(val: int) -> int:
+ return roundup2(val, 4)
+
+
+class SockaddrNl(Structure):
+ _fields_ = [
+ ("nl_len", c_ubyte),
+ ("nl_family", c_ubyte),
+ ("nl_pad", c_ushort),
+ ("nl_pid", c_uint),
+ ("nl_groups", c_uint),
+ ]
+
+
+class Nlmsghdr(Structure):
+ _fields_ = [
+ ("nlmsg_len", c_uint),
+ ("nlmsg_type", c_ushort),
+ ("nlmsg_flags", c_ushort),
+ ("nlmsg_seq", c_uint),
+ ("nlmsg_pid", c_uint),
+ ]
+
+
+class Nlmsgerr(Structure):
+ _fields_ = [
+ ("error", c_int),
+ ("msg", Nlmsghdr),
+ ]
+
+
+class NlErrattrType(Enum):
+ NLMSGERR_ATTR_UNUSED = 0
+ NLMSGERR_ATTR_MSG = auto()
+ NLMSGERR_ATTR_OFFS = auto()
+ NLMSGERR_ATTR_COOKIE = auto()
+ NLMSGERR_ATTR_POLICY = auto()
+
+
+class RtattrType(Enum):
+ RTA_UNSPEC = 0
+ RTA_DST = auto()
+ RTA_SRC = auto()
+ RTA_IIF = auto()
+ RTA_OIF = auto()
+ RTA_GATEWAY = auto()
+ RTA_PRIORITY = auto()
+ RTA_PREFSRC = auto()
+ RTA_METRICS = auto()
+ RTA_MULTIPATH = auto()
+ RTA_PROTOINFO = auto()
+ RTA_FLOW = auto()
+ RTA_CACHEINFO = auto()
+ RTA_SESSION = auto()
+ RTA_MP_ALGO = auto()
+ RTA_TABLE = auto()
+ RTA_MARK = auto()
+ RTA_MFC_STATS = auto()
+ RTA_VIA = auto()
+ RTA_NEWDST = auto()
+ RTA_PREF = auto()
+ RTA_ENCAP_TYPE = auto()
+ RTA_ENCAP = auto()
+ RTA_EXPIRES = auto()
+ RTA_PAD = auto()
+ RTA_UID = auto()
+ RTA_TTL_PROPAGATE = auto()
+ RTA_IP_PROTO = auto()
+ RTA_SPORT = auto()
+ RTA_DPORT = auto()
+ RTA_NH_ID = auto()
+
+
+class NlMsgType(Enum):
+ NLMSG_NOOP = 1
+ NLMSG_ERROR = 2
+ NLMSG_DONE = 3
+ NLMSG_OVERRUN = 4
+
+
+class NlRtMsgType(Enum):
+ RTM_NEWLINK = 16
+ RTM_DELLINK = 17
+ RTM_GETLINK = 18
+ RTM_SETLINK = 19
+ RTM_NEWADDR = 20
+ RTM_DELADDR = 21
+ RTM_GETADDR = 22
+ RTM_NEWROUTE = 24
+ RTM_DELROUTE = 25
+ RTM_GETROUTE = 26
+ RTM_NEWNEIGH = 28
+ RTM_DELNEIGH = 27
+ RTM_GETNEIGH = 28
+ RTM_NEWRULE = 32
+ RTM_DELRULE = 33
+ RTM_GETRULE = 34
+ RTM_NEWQDISC = 36
+ RTM_DELQDISC = 37
+ RTM_GETQDISC = 38
+ RTM_NEWTCLASS = 40
+ RTM_DELTCLASS = 41
+ RTM_GETTCLASS = 42
+ RTM_NEWTFILTER = 44
+ RTM_DELTFILTER = 45
+ RTM_GETTFILTER = 46
+ RTM_NEWACTION = 48
+ RTM_DELACTION = 49
+ RTM_GETACTION = 50
+ RTM_NEWPREFIX = 52
+ RTM_GETMULTICAST = 58
+ RTM_GETANYCAST = 62
+ RTM_NEWNEIGHTBL = 64
+ RTM_GETNEIGHTBL = 66
+ RTM_SETNEIGHTBL = 67
+ RTM_NEWNDUSEROPT = 68
+ RTM_NEWADDRLABEL = 72
+ RTM_DELADDRLABEL = 73
+ RTM_GETADDRLABEL = 74
+ RTM_GETDCB = 78
+ RTM_SETDCB = 79
+ RTM_NEWNETCONF = 80
+ RTM_GETNETCONF = 82
+ RTM_NEWMDB = 84
+ RTM_DELMDB = 85
+ RTM_GETMDB = 86
+ RTM_NEWNSID = 88
+ RTM_DELNSID = 89
+ RTM_GETNSID = 90
+ RTM_NEWSTATS = 92
+ RTM_GETSTATS = 94
+
+
+class RtAttr(Structure):
+ _fields_ = [
+ ("rta_len", c_ushort),
+ ("rta_type", c_ushort),
+ ]
+
+
+class RtMsgHdr(Structure):
+ _fields_ = [
+ ("rtm_family", c_ubyte),
+ ("rtm_dst_len", c_ubyte),
+ ("rtm_src_len", c_ubyte),
+ ("rtm_tos", c_ubyte),
+ ("rtm_table", c_ubyte),
+ ("rtm_protocol", c_ubyte),
+ ("rtm_scope", c_ubyte),
+ ("rtm_type", c_ubyte),
+ ("rtm_flags", c_uint),
+ ]
+
+
+class RtMsgFlags(Enum):
+ RTM_F_NOTIFY = 0x100
+ RTM_F_CLONED = 0x200
+ RTM_F_EQUALIZE = 0x400
+ RTM_F_PREFIX = 0x800
+ RTM_F_LOOKUP_TABLE = 0x1000
+ RTM_F_FIB_MATCH = 0x2000
+ RTM_F_OFFLOAD = 0x4000
+ RTM_F_TRAP = 0x8000
+ RTM_F_OFFLOAD_FAILED = 0x20000000
+
+
+class AddressFamilyLinux(Enum):
+ AF_INET = socket.AF_INET
+ AF_INET6 = socket.AF_INET6
+ AF_NETLINK = 16
+
+
+class AddressFamilyBsd(Enum):
+ AF_INET = socket.AF_INET
+ AF_INET6 = socket.AF_INET6
+ AF_NETLINK = 38
+
+
+class NlmBaseFlags(Enum):
+ NLM_F_REQUEST = 0x01
+ NLM_F_MULTI = 0x02
+ NLM_F_ACK = 0x04
+ NLM_F_ECHO = 0x08
+ NLM_F_DUMP_INTR = 0x10
+ NLM_F_DUMP_FILTERED = 0x20
+
+
+# XXX: in python3.8 it is possible to
+# class NlmGetFlags(Enum, NlmBaseFlags):
+
+
+class NlmGetFlags(Enum):
+ NLM_F_ROOT = 0x100
+ NLM_F_MATCH = 0x200
+ NLM_F_ATOMIC = 0x400
+
+
+class NlmNewFlags(Enum):
+ NLM_F_REPLACE = 0x100
+ NLM_F_EXCL = 0x200
+ NLM_F_CREATE = 0x400
+ NLM_F_APPEND = 0x800
+
+
+class NlmDeleteFlags(Enum):
+ NLM_F_NONREC = 0x100
+
+
+class NlmAckFlags(Enum):
+ NLM_F_CAPPED = 0x100
+ NLM_F_ACK_TLVS = 0x200
+
+
+class RtScope(Enum):
+ RT_SCOPE_UNIVERSE = 0
+ RT_SCOPE_SITE = 200
+ RT_SCOPE_LINK = 253
+ RT_SCOPE_HOST = 254
+ RT_SCOPE_NOWHERE = 255
+
+
+class RtType(Enum):
+ RTN_UNSPEC = 0
+ RTN_UNICAST = auto()
+ RTN_LOCAL = auto()
+ RTN_BROADCAST = auto()
+ RTN_ANYCAST = auto()
+ RTN_MULTICAST = auto()
+ RTN_BLACKHOLE = auto()
+ RTN_UNREACHABLE = auto()
+ RTN_PROHIBIT = auto()
+ RTN_THROW = auto()
+ RTN_NAT = auto()
+ RTN_XRESOLVE = auto()
+
+
+class RtProto(Enum):
+ RTPROT_UNSPEC = 0
+ RTPROT_REDIRECT = 1
+ RTPROT_KERNEL = 2
+ RTPROT_BOOT = 3
+ RTPROT_STATIC = 4
+ RTPROT_GATED = 8
+ RTPROT_RA = 9
+ RTPROT_MRT = 10
+ RTPROT_ZEBRA = 11
+ RTPROT_BIRD = 12
+ RTPROT_DNROUTED = 13
+ RTPROT_XORP = 14
+ RTPROT_NTK = 15
+ RTPROT_DHCP = 16
+ RTPROT_MROUTED = 17
+ RTPROT_KEEPALIVED = 18
+ RTPROT_BABEL = 42
+ RTPROT_OPENR = 99
+ RTPROT_BGP = 186
+ RTPROT_ISIS = 187
+ RTPROT_OSPF = 188
+ RTPROT_RIP = 189
+ RTPROT_EIGRP = 192
+
+
+class NlRtaxType(Enum):
+ RTAX_UNSPEC = 0
+ RTAX_LOCK = auto()
+ RTAX_MTU = auto()
+ RTAX_WINDOW = auto()
+ RTAX_RTT = auto()
+ RTAX_RTTVAR = auto()
+ RTAX_SSTHRESH = auto()
+ RTAX_CWND = auto()
+ RTAX_ADVMSS = auto()
+ RTAX_REORDERING = auto()
+ RTAX_HOPLIMIT = auto()
+ RTAX_INITCWND = auto()
+ RTAX_FEATURES = auto()
+ RTAX_RTO_MIN = auto()
+ RTAX_INITRWND = auto()
+ RTAX_QUICKACK = auto()
+ RTAX_CC_ALGO = auto()
+ RTAX_FASTOPEN_NO_COOKIE = auto()
+
+
+class NlRtGroup(Enum):
+ RTNLGRP_NONE = 0
+ RTNLGRP_LINK = auto()
+ RTNLGRP_NOTIFY = auto()
+ RTNLGRP_NEIGH = auto()
+ RTNLGRP_TC = auto()
+ RTNLGRP_IPV4_IFADDR = auto()
+ RTNLGRP_IPV4_MROUTE = auto()
+ RTNLGRP_IPV4_ROUTE = auto()
+ RTNLGRP_IPV4_RULE = auto()
+ RTNLGRP_IPV6_IFADDR = auto()
+ RTNLGRP_IPV6_MROUTE = auto()
+ RTNLGRP_IPV6_ROUTE = auto()
+ RTNLGRP_IPV6_IFINFO = auto()
+ RTNLGRP_DECnet_IFADDR = auto()
+ RTNLGRP_NOP2 = auto()
+ RTNLGRP_DECnet_ROUTE = auto()
+ RTNLGRP_DECnet_RULE = auto()
+ RTNLGRP_NOP4 = auto()
+ RTNLGRP_IPV6_PREFIX = auto()
+ RTNLGRP_IPV6_RULE = auto()
+ RTNLGRP_ND_USEROPT = auto()
+ RTNLGRP_PHONET_IFADDR = auto()
+ RTNLGRP_PHONET_ROUTE = auto()
*** 1468 LINES SKIPPED ***