Page MenuHomeFreeBSD

D39032.diff
No OneTemporary

D39032.diff

diff --git a/sys/net/if_clone.h b/sys/net/if_clone.h
--- a/sys/net/if_clone.h
+++ b/sys/net/if_clone.h
@@ -56,6 +56,26 @@
struct ifc_data *ifd, struct ifnet **ifpp);
typedef int ifc_destroy_f(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags);
+struct nl_parsed_link;
+struct nlattr_bmask;
+struct nl_pstate;
+struct nl_writer;
+struct ifc_data_nl {
+ struct nl_parsed_link *lattrs;/* (in) Parsed link attributes */
+ const struct nlattr_bmask *bm; /* (in) Bitmask of set link attributes */
+ struct nl_pstate *npt; /* (in) Netlink context */
+ void *params;/* (in) (Compat) data from ioctl */
+ uint32_t flags; /* (in) IFC_F flags */
+ uint32_t unit; /* (in/out) Selected unit when IFC_C_AUTOUNIT set */
+ int error; /* (out) Return error code */
+ struct ifnet *ifp; /* (out) Returned ifp */
+};
+
+typedef int ifc_create_nl_f(struct if_clone *ifc, char *name, size_t maxlen,
+ struct ifc_data_nl *ifd);
+typedef int ifc_modify_nl_f(struct ifnet *ifp, struct ifc_data_nl *ifd);
+typedef void ifc_dump_nl_f(struct ifnet *ifp, struct nl_writer *nw);
+
struct if_clone_addreq {
uint16_t version; /* Always 0 for now */
uint16_t spare;
@@ -66,17 +86,35 @@
ifc_destroy_f *destroy_f;
};
+struct if_clone_addreq_v2 {
+ uint16_t version; /* 2 */
+ uint16_t spare;
+ uint32_t flags;
+ uint32_t maxunit; /* Maximum allowed unit number */
+ ifc_match_f *match_f;
+ ifc_create_f *create_f;
+ ifc_destroy_f *destroy_f;
+ ifc_create_nl_f *create_nl_f;
+ ifc_modify_nl_f *modify_nl_f;
+ ifc_dump_nl_f *dump_nl_f;
+};
+
+
#define IFC_F_NOGROUP 0x01 /* Creation flag: don't add unit group */
#define IFC_F_AUTOUNIT 0x02 /* Creation flag: automatically select unit */
#define IFC_F_SYSSPACE 0x04 /* Cloner callback: params pointer is in kernel memory */
#define IFC_F_FORCE 0x08 /* Deletion flag: force interface deletion */
+#define IFC_F_CREATE 0x10 /* Creation flag: indicate creation request */
#define IFC_NOGROUP IFC_F_NOGROUP
struct if_clone *ifc_attach_cloner(const char *name, struct if_clone_addreq *req);
void ifc_detach_cloner(struct if_clone *ifc);
-int ifc_create_ifp(const char *name, struct ifc_data *ifd,
- struct ifnet **ifpp);
+int ifc_create_ifp(const char *name, struct ifc_data *ifd, struct ifnet **ifpp);
+
+bool ifc_create_ifp_nl(const char *name, struct ifc_data_nl *ifd);
+bool ifc_modify_ifp_nl(struct ifnet *ifp, struct ifc_data_nl *ifd);
+bool ifc_dump_ifp_nl(struct ifnet *ifp, struct nl_writer *nw);
void ifc_link_ifp(struct if_clone *ifc, struct ifnet *ifp);
bool ifc_unlink_ifp(struct if_clone *ifc, struct ifnet *ifp);
diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c
--- a/sys/net/if_clone.c
+++ b/sys/net/if_clone.c
@@ -33,6 +33,8 @@
* $FreeBSD$
*/
+#include "opt_netlink.h"
+
#include <sys/param.h>
#include <sys/eventhandler.h>
#include <sys/malloc.h>
@@ -52,6 +54,11 @@
#include <net/route.h>
#include <net/vnet.h>
+#include <netlink/netlink.h>
+#include <netlink/netlink_ctl.h>
+#include <netlink/netlink_route.h>
+#include <netlink/route/route_var.h>
+
/* Current IF_MAXUNIT expands maximum to 5 characters. */
#define IFCLOSIZ (IFNAMSIZ - 5)
@@ -77,6 +84,10 @@
ifc_create_f *ifc_create; /* (c) Creates new interface */
ifc_destroy_f *ifc_destroy; /* (c) Destroys cloned interface */
+ ifc_create_nl_f *create_nl; /* (c) Netlink creation handler */
+ ifc_modify_nl_f *modify_nl; /* (c) Netlink modification handler */
+ ifc_dump_nl_f *dump_nl; /* (c) Netlink dump handler */
+
#ifdef CLONE_COMPAT_13
/* (c) Driver specific cloning functions. Called with no locks held. */
union {
@@ -104,8 +115,8 @@
static void if_clone_free(struct if_clone *ifc);
-static int if_clone_createif(struct if_clone *ifc, char *name, size_t len,
- struct ifc_data *ifd, struct ifnet **ifpp);
+static int if_clone_createif_nl(struct if_clone *ifc, const char *name,
+ struct ifc_data_nl *ifd);
static int ifc_simple_match(struct if_clone *ifc, const char *name);
static int ifc_handle_unit(struct if_clone *ifc, char *name, size_t len, int *punit);
@@ -188,27 +199,41 @@
* Lookup and create a clone network interface.
*/
int
-ifc_create_ifp(const char *name, struct ifc_data *ifd,
- struct ifnet **ifpp)
+ifc_create_ifp(const char *name, struct ifc_data *ifd, struct ifnet **ifpp)
{
- struct if_clone *ifc;
- char ifname[IFNAMSIZ];
- struct ifnet *ifp = NULL;
- int error;
+ struct if_clone *ifc = ifc_find_cloner_match(name);
- /* Try to find an applicable cloner for this request */
- ifc = ifc_find_cloner_match(name);
if (ifc == NULL)
return (EINVAL);
- strlcpy(ifname, name, IFNAMSIZ);
- error = if_clone_createif(ifc, ifname, IFNAMSIZ, ifd, &ifp);
+ struct ifc_data_nl ifd_new = {
+ .flags = ifd->flags,
+ .unit = ifd->unit,
+ .params = ifd->params,
+ };
+
+ int error = if_clone_createif_nl(ifc, name, &ifd_new);
+
if (ifpp != NULL)
- *ifpp = ifp;
+ *ifpp = ifd_new.ifp;
return (error);
}
+bool
+ifc_create_ifp_nl(const char *name, struct ifc_data_nl *ifd)
+{
+ struct if_clone *ifc = ifc_find_cloner_match(name);
+ if (ifc == NULL) {
+ ifd->error = EINVAL;
+ return (false);
+ }
+
+ ifd->error = if_clone_createif_nl(ifc, name, ifd);
+
+ return (true);
+}
+
int
if_clone_create(char *name, size_t len, caddr_t params)
{
@@ -223,6 +248,62 @@
return (error);
}
+bool
+ifc_modify_ifp_nl(struct ifnet *ifp, struct ifc_data_nl *ifd)
+{
+ struct if_clone *ifc = ifc_find_cloner(ifp->if_dname);
+ if (ifc == NULL) {
+ ifd->error = EINVAL;
+ return (false);
+ }
+
+ ifd->error = (*ifc->modify_nl)(ifp, ifd);
+ return (true);
+}
+
+bool
+ifc_dump_ifp_nl(struct ifnet *ifp, struct nl_writer *nw)
+{
+ struct if_clone *ifc = ifc_find_cloner(ifp->if_dname);
+ if (ifc == NULL)
+ return (false);
+
+ (*ifc->dump_nl)(ifp, nw);
+ return (true);
+}
+
+static int
+ifc_create_ifp_nl_default(struct if_clone *ifc, char *name, size_t len,
+ struct ifc_data_nl *ifd)
+{
+ struct ifc_data ifd_new = {
+ .flags = ifd->flags,
+ .unit = ifd->unit,
+ .params = ifd->params,
+ };
+
+ return ((*ifc->ifc_create)(ifc, name, len, &ifd_new, &ifd->ifp));
+}
+
+static int
+ifc_modify_ifp_nl_default(struct ifnet *ifp, struct ifc_data_nl *ifd)
+{
+ if (ifd->lattrs != NULL)
+ return (nl_modify_ifp_generic(ifp, ifd->lattrs, ifd->bm, ifd->npt));
+ return (0);
+}
+
+static void
+ifc_dump_ifp_nl_default(struct ifnet *ifp, struct nl_writer *nw)
+{
+ int off = nlattr_add_nested(nw, IFLA_LINKINFO);
+
+ if (off != 0) {
+ nlattr_add_string(nw, IFLA_INFO_KIND, ifp->if_dname);
+ nlattr_set_len(nw, off);
+ }
+}
+
void
ifc_link_ifp(struct if_clone *ifc, struct ifnet *ifp)
{
@@ -306,29 +387,38 @@
* Create a clone network interface.
*/
static int
-if_clone_createif(struct if_clone *ifc, char *name, size_t len,
- struct ifc_data *ifd, struct ifnet **ifpp)
+if_clone_createif_nl(struct if_clone *ifc, const char *ifname, struct ifc_data_nl *ifd)
{
- int err, unit = 0;
+ char name[IFNAMSIZ];
+ int error;
+
+ strlcpy(name, ifname, sizeof(name));
if (ifunit(name) != NULL)
return (EEXIST);
if (ifc->ifc_flags & IFC_F_AUTOUNIT) {
- if ((err = ifc_handle_unit(ifc, name, len, &unit)) != 0)
- return (err);
- ifd->unit = unit;
+ if ((error = ifc_handle_unit(ifc, name, sizeof(name), &ifd->unit)) != 0)
+ return (error);
}
- *ifpp = NULL;
- err = (*ifc->ifc_create)(ifc, name, len, ifd, ifpp);
- if (err == 0) {
- MPASS(*ifpp != NULL);
- if_clone_addif(ifc, *ifpp);
- } else if (ifc->ifc_flags & IFC_F_AUTOUNIT)
- ifc_free_unit(ifc, unit);
+ if (ifd->lattrs != NULL)
+ error = (*ifc->create_nl)(ifc, name, sizeof(name), ifd);
+ else
+ error = ifc_create_ifp_nl_default(ifc, name, sizeof(name), ifd);
+ if (error != 0) {
+ if (ifc->ifc_flags & IFC_F_AUTOUNIT)
+ ifc_free_unit(ifc, ifd->unit);
+ return (error);
+ }
- return (err);
+ MPASS(ifd->ifp != NULL);
+ if_clone_addif(ifc, ifd->ifp);
+
+ if (ifd->lattrs != NULL)
+ error = (*ifc->modify_nl)(ifd->ifp, ifd);
+
+ return (error);
}
/*
@@ -408,6 +498,10 @@
ifc->ifc_unrhdr = new_unrhdr(0, ifc->ifc_maxunit, &ifc->ifc_mtx);
LIST_INIT(&ifc->ifc_iflist);
+ ifc->create_nl = ifc_create_ifp_nl_default;
+ ifc->modify_nl = ifc_modify_ifp_nl_default;
+ ifc->dump_nl = ifc_dump_ifp_nl_default;
+
return (ifc);
}
@@ -444,6 +538,16 @@
ifc->ifc_destroy = req->destroy_f;
ifc->ifc_flags = (req->flags & (IFC_F_AUTOUNIT | IFC_F_NOGROUP));
+ if (req->version == 2) {
+ struct if_clone_addreq_v2 *req2 = (struct if_clone_addreq_v2 *)req;
+
+ ifc->create_nl = req2->create_nl_f;
+ ifc->modify_nl = req2->modify_nl_f;
+ ifc->dump_nl = req2->dump_nl_f;
+ }
+
+ ifc->dump_nl = ifc_dump_ifp_nl_default;
+
if (if_clone_attach(ifc) != 0)
return (NULL);
@@ -546,11 +650,10 @@
for (unit = 0; unit < minifs; unit++) {
char name[IFNAMSIZ];
int error __unused;
- struct ifc_data ifd = {};
- struct ifnet *ifp;
+ struct ifc_data_nl ifd = {};
snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit);
- error = if_clone_createif(ifc, name, IFNAMSIZ, &ifd, &ifp);
+ error = if_clone_createif_nl(ifc, name, &ifd);
KASSERT(error == 0,
("%s: failed to create required interface %s",
__func__, name));
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -48,6 +48,7 @@
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_kern_tls.h"
+#include "opt_netlink.h"
#include "opt_vlan.h"
#include "opt_ratelimit.h"
@@ -85,6 +86,11 @@
#include <netinet/if_ether.h>
#endif
+#include <netlink/netlink.h>
+#include <netlink/netlink_ctl.h>
+#include <netlink/netlink_route.h>
+#include <netlink/route/route_var.h>
+
#define VLAN_DEF_HWIDTH 4
#define VLAN_IFFLAGS (IFF_BROADCAST | IFF_MULTICAST)
@@ -320,6 +326,11 @@
struct ifc_data *, struct ifnet **);
static int vlan_clone_destroy(struct if_clone *, struct ifnet *, uint32_t);
+static int vlan_clone_create_nl(struct if_clone *ifc, char *name, size_t len,
+ struct ifc_data_nl *ifd);
+static int vlan_clone_modify_nl(struct ifnet *ifp, struct ifc_data_nl *ifd);
+static void vlan_clone_dump_nl(struct ifnet *ifp, struct nl_writer *nw);
+
static void vlan_ifdetach(void *arg, struct ifnet *ifp);
static void vlan_iflladdr(void *arg, struct ifnet *ifp);
static void vlan_ifevent(void *arg, struct ifnet *ifp, int event);
@@ -896,10 +907,14 @@
/* For if_link_state_change() eyes only... */
extern void (*vlan_link_state_p)(struct ifnet *);
-static struct if_clone_addreq vlan_addreq = {
+static struct if_clone_addreq_v2 vlan_addreq = {
+ .version = 2,
.match_f = vlan_clone_match,
.create_f = vlan_clone_create,
.destroy_f = vlan_clone_destroy,
+ .create_nl_f = vlan_clone_create_nl,
+ .modify_nl_f = vlan_clone_modify_nl,
+ .dump_nl_f = vlan_clone_dump_nl,
};
static int
@@ -931,7 +946,7 @@
vlan_pcp_p = vlan_pcp;
vlan_devat_p = vlan_devat;
#ifndef VIMAGE
- vlan_cloner = ifc_attach_cloner(vlanname, &vlan_addreq);
+ vlan_cloner = ifc_attach_cloner(vlanname, (struct if_clone_addreq *)&vlan_addreq);
#endif
if (bootverbose)
printf("vlan: initialized, using "
@@ -981,7 +996,7 @@
static void
vnet_vlan_init(const void *unused __unused)
{
- vlan_cloner = ifc_attach_cloner(vlanname, &vlan_addreq);
+ vlan_cloner = ifc_attach_cloner(vlanname, (struct if_clone_addreq *)&vlan_addreq);
V_vlan_cloner = vlan_cloner;
}
VNET_SYSINIT(vnet_vlan_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
@@ -1222,6 +1237,165 @@
return (0);
}
+/*
+ *
+ * Parsers of IFLA_INFO_DATA inside IFLA_LINKINFO of RTM_NEWLINK
+ * {{nla_len=8, nla_type=IFLA_LINK}, 2},
+ * {{nla_len=12, nla_type=IFLA_IFNAME}, "xvlan22"},
+ * {{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\x16\x00\x00\x00"}]}
+ */
+
+struct nl_parsed_vlan {
+ uint16_t vlan_id;
+ uint16_t vlan_proto;
+ struct ifla_vlan_flags vlan_flags;
+};
+
+#define _OUT(_field) offsetof(struct nl_parsed_vlan, _field)
+static const struct nlattr_parser nla_p_vlan[] = {
+ { .type = IFLA_VLAN_ID, .off = _OUT(vlan_id), .cb = nlattr_get_uint16 },
+ { .type = IFLA_VLAN_FLAGS, .off = _OUT(vlan_flags), .cb = nlattr_get_nla },
+ { .type = IFLA_VLAN_PROTOCOL, .off = _OUT(vlan_proto), .cb = nlattr_get_uint16 },
+};
+#undef _OUT
+NL_DECLARE_ATTR_PARSER(vlan_parser, nla_p_vlan);
+
+static int
+vlan_clone_create_nl(struct if_clone *ifc, char *name, size_t len,
+ struct ifc_data_nl *ifd)
+{
+ struct epoch_tracker et;
+ struct ifnet *ifp_parent;
+ struct nl_pstate *npt = ifd->npt;
+ struct nl_parsed_link *lattrs = ifd->lattrs;
+ int error;
+
+ /*
+ * lattrs.ifla_ifname is the new interface name
+ * lattrs.ifi_index contains parent interface index
+ * lattrs.ifla_idata contains un-parsed vlan data
+ */
+ struct nl_parsed_vlan attrs = {
+ .vlan_id = 0xFEFE,
+ .vlan_proto = ETHERTYPE_VLAN
+ };
+
+ if (lattrs->ifla_idata == NULL) {
+ nlmsg_report_err_msg(npt, "vlan id is required, guessing not supported");
+ return (ENOTSUP);
+ }
+
+ error = nl_parse_nested(lattrs->ifla_idata, &vlan_parser, npt, &attrs);
+ if (error != 0)
+ return (error);
+ if (attrs.vlan_id > 4095) {
+ nlmsg_report_err_msg(npt, "Invalid VID: %d", attrs.vlan_id);
+ return (EINVAL);
+ }
+ if (attrs.vlan_proto != ETHERTYPE_VLAN && attrs.vlan_proto != ETHERTYPE_QINQ) {
+ nlmsg_report_err_msg(npt, "Unsupported ethertype: 0x%04X", attrs.vlan_proto);
+ return (ENOTSUP);
+ }
+
+ struct vlanreq params = {
+ .vlr_tag = attrs.vlan_id,
+ .vlr_proto = attrs.vlan_proto,
+ };
+ struct ifc_data ifd_new = { .flags = IFC_F_SYSSPACE, .unit = ifd->unit, .params = &params };
+
+ NET_EPOCH_ENTER(et);
+ ifp_parent = ifnet_byindex(lattrs->ifi_index);
+ if (ifp_parent != NULL)
+ strlcpy(params.vlr_parent, if_name(ifp_parent), sizeof(params.vlr_parent));
+ NET_EPOCH_EXIT(et);
+
+ if (ifp_parent == NULL) {
+ nlmsg_report_err_msg(npt, "unable to find parent interface %u", lattrs->ifi_index);
+ return (ENOENT);
+ }
+
+ error = vlan_clone_create(ifc, name, len, &ifd_new, &ifd->ifp);
+
+ return (error);
+}
+
+static int
+vlan_clone_modify_nl(struct ifnet *ifp, struct ifc_data_nl *ifd)
+{
+ struct nl_parsed_link *lattrs = ifd->lattrs;
+
+ if ((lattrs->ifla_idata != NULL) && ((ifd->flags & IFC_F_CREATE) == 0)) {
+ struct epoch_tracker et;
+ struct nl_parsed_vlan attrs = {
+ .vlan_proto = ETHERTYPE_VLAN,
+ };
+ int error;
+
+ error = nl_parse_nested(lattrs->ifla_idata, &vlan_parser, ifd->npt, &attrs);
+ if (error != 0)
+ return (error);
+
+ NET_EPOCH_ENTER(et);
+ struct ifnet *ifp_parent = ifnet_byindex_ref(lattrs->ifla_link);
+ NET_EPOCH_EXIT(et);
+
+ if (ifp_parent == NULL) {
+ nlmsg_report_err_msg(ifd->npt, "unable to find parent interface %u",
+ lattrs->ifla_link);
+ return (ENOENT);
+ }
+
+ struct ifvlan *ifv = ifp->if_softc;
+ error = vlan_config(ifv, ifp_parent, attrs.vlan_id, attrs.vlan_proto);
+
+ if_rele(ifp_parent);
+ if (error != 0)
+ return (error);
+ }
+
+ return (nl_modify_ifp_generic(ifp, ifd->lattrs, ifd->bm, ifd->npt));
+}
+
+/*
+ * {{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\x16\x00\x00\x00"}]}
+ */
+static void
+vlan_clone_dump_nl(struct ifnet *ifp, struct nl_writer *nw)
+{
+ uint32_t parent_index = 0;
+ uint16_t vlan_id = 0;
+ uint16_t vlan_proto = 0;
+
+ VLAN_SLOCK();
+ struct ifvlan *ifv = ifp->if_softc;
+ if (TRUNK(ifv) != NULL)
+ parent_index = PARENT(ifv)->if_index;
+ vlan_id = ifv->ifv_vid;
+ vlan_proto = ifv->ifv_proto;
+ VLAN_SUNLOCK();
+
+ if (parent_index != 0)
+ nlattr_add_u32(nw, IFLA_LINK, parent_index);
+
+ int off = nlattr_add_nested(nw, IFLA_LINKINFO);
+ if (off != 0) {
+ nlattr_add_string(nw, IFLA_INFO_KIND, "vlan");
+ int off2 = nlattr_add_nested(nw, IFLA_INFO_DATA);
+ if (off2 != 0) {
+ nlattr_add_u16(nw, IFLA_VLAN_ID, vlan_id);
+ nlattr_add_u16(nw, IFLA_VLAN_PROTOCOL, vlan_proto);
+ nlattr_set_len(nw, off2);
+ }
+ nlattr_set_len(nw, off);
+ }
+}
+
static int
vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
{
diff --git a/sys/netlink/netlink_glue.c b/sys/netlink/netlink_glue.c
--- a/sys/netlink/netlink_glue.c
+++ b/sys/netlink/netlink_glue.c
@@ -177,6 +177,19 @@
return (false);
}
+static int
+nl_modify_ifp_generic_stub(struct ifnet *ifp __unused,
+ struct nl_parsed_link *lattrs __unused, const struct nlattr_bmask *bm __unused,
+ struct nl_pstate *npt __unused)
+{
+ return (ENOTSUP);
+}
+
+static void
+nl_store_ifp_cookie_stub(struct nl_pstate *npt __unused, struct ifnet *ifp __unused)
+{
+}
+
const static struct nl_function_wrapper nl_stub = {
.nlmsg_add = nlmsg_add_stub,
.nlmsg_refill_buffer = nlmsg_refill_buffer_stub,
@@ -188,6 +201,8 @@
.nlmsg_get_group_writer = nlmsg_get_group_writer_stub,
.nlmsg_get_chain_writer = nlmsg_get_chain_writer_stub,
.nlmsg_end_dump = nlmsg_end_dump_stub,
+ .nl_modify_ifp_generic = nl_modify_ifp_generic_stub,
+ .nl_store_ifp_cookie = nl_store_ifp_cookie_stub,
};
/*
@@ -262,5 +277,19 @@
{
return (_nl->nlmsg_end_dump(nw, error, hdr));
}
+
+int
+nl_modify_ifp_generic(struct ifnet *ifp, struct nl_parsed_link *lattrs,
+ const struct nlattr_bmask *bm , struct nl_pstate *npt)
+{
+ return (_nl->nl_modify_ifp(ifp, lattrs, bm, npt));
+}
+
+static void
+nl_store_ifp_cookie_stub(struct nl_pstate *npt, struct ifnet *ifp)
+{
+ return (_nl->nl_store_ifp_cookie(npt, ifp));
+}
+
#endif /* !NETLINK */
diff --git a/sys/netlink/netlink_module.c b/sys/netlink/netlink_module.c
--- a/sys/netlink/netlink_module.c
+++ b/sys/netlink/netlink_module.c
@@ -43,6 +43,7 @@
#include <netlink/netlink.h>
#include <netlink/netlink_ctl.h>
#include <netlink/netlink_var.h>
+#include <netlink/route/route_var.h>
#include <machine/atomic.h>
diff --git a/sys/netlink/netlink_var.h b/sys/netlink/netlink_var.h
--- a/sys/netlink/netlink_var.h
+++ b/sys/netlink/netlink_var.h
@@ -172,6 +172,11 @@
#define CTRL_FAMILY_NAME "nlctrl"
+struct ifnet;
+struct nl_parsed_link;
+struct nlattr_bmask;
+struct nl_pstate;
+
/* Function map */
struct nl_function_wrapper {
bool (*nlmsg_add)(struct nl_writer *nw, uint32_t portid, uint32_t seq, uint16_t type,
@@ -185,8 +190,13 @@
bool (*nlmsg_get_group_writer)(struct nl_writer *nw, int size, int protocol, int group_id);
bool (*nlmsg_get_chain_writer)(struct nl_writer *nw, int size, struct mbuf **pm);
bool (*nlmsg_end_dump)(struct nl_writer *nw, int error, struct nlmsghdr *hdr);
+ int (*nl_modify_ifp_generic)(struct ifnet *ifp, struct nl_parsed_link *lattrs,
+ const struct nlattr_bmask *bm, struct nl_pstate *npt);
+ void (*nl_store_ifp_cookie)(struct nl_pstate *npt, struct ifnet *ifp);
};
void nl_set_functions(const struct nl_function_wrapper *nl);
+
+
#endif
#endif
diff --git a/sys/netlink/route/iface.c b/sys/netlink/route/iface.c
--- a/sys/netlink/route/iface.c
+++ b/sys/netlink/route/iface.c
@@ -303,13 +303,7 @@
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);
+ ifc_dump_ifp_nl(ifp, nw);
if (nlmsg_end(nw))
return (true);
@@ -353,7 +347,7 @@
static const struct nlattr_parser nla_p_if[] = {
{ .type = IFLA_IFNAME, .off = _OUT(ifla_ifname), .cb = nlattr_get_string },
{ .type = IFLA_MTU, .off = _OUT(ifla_mtu), .cb = nlattr_get_uint32 },
- { .type = IFLA_LINK, .off = _OUT(ifi_index), .cb = nlattr_get_uint32 },
+ { .type = IFLA_LINK, .off = _OUT(ifla_link), .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 },
@@ -545,21 +539,16 @@
return (EINVAL);
}
- 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);
+ struct ifc_data_nl ifd = {
+ .flags = IFC_F_CREATE,
+ .lattrs = lattrs,
+ .bm = bm,
+ .npt = npt,
+ };
+ if (ifc_create_ifp_nl(lattrs->ifla_ifname, &ifd) && ifd.error == 0)
+ nl_store_ifp_cookie(npt, ifd.ifp);
- return (error);
+ return (ifd.error);
}
static int
@@ -602,31 +591,20 @@
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.
+ * Modification request can address either
+ * 1) cloned interface, in which case we call the cloner-specific
+ * modification routine
+ * or
+ * 2) non-cloned (e.g. "physical") interface, in which case we call
+ * generic modification routine
*/
- 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);
-
- if (!found)
- error = generic_cloner.modify_f(ifp, lattrs, bm, nlp, npt);
+ struct ifc_data_nl ifd = { .lattrs = lattrs, .bm = bm, .npt = npt };
+ if (!ifc_modify_ifp_nl(ifp, &ifd))
+ ifd.error = nl_modify_ifp_generic(ifp, lattrs, bm, npt);
if_rele(ifp);
- return (error);
+ return (ifd.error);
}
@@ -1067,7 +1045,6 @@
ifnet_link_event, rtnl_handle_iflink, NULL,
EVENTHANDLER_PRI_ANY);
NL_VERIFY_PARSERS(all_parsers);
- rtnl_iface_drivers_register();
rtnl_register_messages(cmd_handlers, NL_ARRAY_LEN(cmd_handlers));
}
diff --git a/sys/netlink/route/iface_drivers.c b/sys/netlink/route/iface_drivers.c
--- a/sys/netlink/route/iface_drivers.c
+++ b/sys/netlink/route/iface_drivers.c
@@ -63,14 +63,14 @@
* 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
+nl_modify_ifp_generic(struct ifnet *ifp, struct nl_parsed_link *lattrs,
+ const struct nlattr_bmask *bm, struct nl_pstate *npt)
{
int error;
if (lattrs->ifla_ifalias != NULL) {
- if (nlp_has_priv(nlp, PRIV_NET_SETIFDESCR)) {
+ if (nlp_has_priv(npt->nlp, PRIV_NET_SETIFDESCR)) {
int len = strlen(lattrs->ifla_ifalias) + 1;
char *buf = if_allocdescr(len, M_WAITOK);
@@ -89,7 +89,7 @@
}
if (lattrs->ifla_mtu > 0) {
- if (nlp_has_priv(nlp, PRIV_NET_SETIFMTU)) {
+ if (nlp_has_priv(npt->nlp, PRIV_NET_SETIFMTU)) {
struct ifreq ifr = { .ifr_mtu = lattrs->ifla_mtu };
error = ifhwioctl(SIOCSIFMTU, ifp, (char *)&ifr, curthread);
} else {
@@ -117,8 +117,8 @@
* IFLA_NEW_IFINDEX(u32)
* IFLA_IFNAME(string)
*/
-static void
-store_cookie(struct nl_pstate *npt, struct ifnet *ifp)
+void
+nl_store_ifp_cookie(struct nl_pstate *npt, struct ifnet *ifp)
{
int ifname_len = strlen(if_name(ifp));
uint32_t ifindex = (uint32_t)ifp->if_index;
@@ -144,161 +144,3 @@
nlmsg_report_cookie(npt, nla_cookie);
}
-static int
-create_generic_ifd(struct nl_parsed_link *lattrs, const struct nlattr_bmask *bm,
- struct ifc_data *ifd, struct nlpcb *nlp, struct nl_pstate *npt)
-{
- int error = 0;
-
- 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 (error == 0)
- store_cookie(npt, ifp);
- if_rele(ifp);
- }
-
- return (error);
-}
-/*
- * 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)
-{
- struct ifc_data ifd = {};
-
- return (create_generic_ifd(lattrs, bm, &ifd, nlp, npt));
-}
-
-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},
- * {ifi_family=AF_UNSPEC, ifi_type=ARPHRD_NETROM, ifi_index=0, ifi_flags=0, ifi_change=0},
- * [
- * {{nla_len=8, nla_type=IFLA_LINK}, 2},
- * {{nla_len=12, nla_type=IFLA_IFNAME}, "xvlan22"},
- * {{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\x16\x00\x00\x00"}]}]}, iov_len=76}], msg_iovlen=1, msg_controllen=0, msg_flags=0}, 0) = 76
- */
-
-struct nl_parsed_vlan {
- uint16_t vlan_id;
- uint16_t vlan_proto;
- struct ifla_vlan_flags vlan_flags;
-};
-
-#define _OUT(_field) offsetof(struct nl_parsed_vlan, _field)
-static const struct nlattr_parser nla_p_vlan[] = {
- { .type = IFLA_VLAN_ID, .off = _OUT(vlan_id), .cb = nlattr_get_uint16 },
- { .type = IFLA_VLAN_FLAGS, .off = _OUT(vlan_flags), .cb = nlattr_get_nla },
- { .type = IFLA_VLAN_PROTOCOL, .off = _OUT(vlan_proto), .cb = nlattr_get_uint16 },
-};
-#undef _OUT
-NL_DECLARE_ATTR_PARSER(vlan_parser, nla_p_vlan);
-
-static int
-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;
- int error;
-
- /*
- * lattrs.ifla_ifname is the new interface name
- * lattrs.ifi_index contains parent interface index
- * lattrs.ifla_idata contains un-parsed vlan data
- */
-
- struct nl_parsed_vlan attrs = {
- .vlan_id = 0xFEFE,
- .vlan_proto = ETHERTYPE_VLAN
- };
- NLP_LOG(LOG_DEBUG3, nlp, "nested: %p len %d", lattrs->ifla_idata, lattrs->ifla_idata->nla_len);
-
- if (lattrs->ifla_idata == NULL) {
- NLMSG_REPORT_ERR_MSG(npt, "vlan id is required, guessing not supported");
- return (ENOTSUP);
- }
-
- error = nl_parse_nested(lattrs->ifla_idata, &vlan_parser, npt, &attrs);
- if (error != 0)
- return (error);
- if (attrs.vlan_id > 4095) {
- NLMSG_REPORT_ERR_MSG(npt, "Invalid VID: %d", attrs.vlan_id);
- return (EINVAL);
- }
- if (attrs.vlan_proto != ETHERTYPE_VLAN && attrs.vlan_proto != ETHERTYPE_QINQ) {
- NLMSG_REPORT_ERR_MSG(npt, "Unsupported ethertype: 0x%04X", attrs.vlan_proto);
- return (ENOTSUP);
- }
-
- NET_EPOCH_ENTER(et);
- ifp = ifnet_byindex_ref(lattrs->ifi_index);
- NET_EPOCH_EXIT(et);
- if (ifp == NULL) {
- NLP_LOG(LOG_DEBUG, nlp, "unable to find parent interface %u",
- lattrs->ifi_index);
- return (ENOENT);
- }
-
- struct vlanreq params = {
- .vlr_tag = attrs.vlan_id,
- .vlr_proto = attrs.vlan_proto,
- };
- strlcpy(params.vlr_parent, if_name(ifp), sizeof(params.vlr_parent));
- struct ifc_data ifd = { .flags = IFC_F_SYSSPACE, .params = &params };
-
- error = create_generic_ifd(lattrs, bm, &ifd, nlp, npt);
-
- if_rele(ifp);
- 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,
-
-};
-
-static const struct nlhdr_parser *all_parsers[] = { &vlan_parser };
-
-void
-rtnl_iface_drivers_register(void)
-{
- rtnl_iface_add_cloner(&vlan_cloner);
- NL_VERIFY_PARSERS(all_parsers);
-}
-
-
diff --git a/sys/netlink/route/route_var.h b/sys/netlink/route/route_var.h
--- a/sys/netlink/route/route_var.h
+++ b/sys/netlink/route/route_var.h
@@ -71,11 +71,17 @@
struct nlattr *ifla_idata;
unsigned short ifi_type;
int ifi_index;
+ uint32_t ifla_link;
uint32_t ifla_mtu;
uint32_t ifi_flags;
uint32_t ifi_change;
};
+int nl_modify_ifp_generic(struct ifnet *ifp, struct nl_parsed_link *lattrs,
+ const struct nlattr_bmask *bm, struct nl_pstate *npt);
+void nl_store_ifp_cookie(struct nl_pstate *npt, struct ifnet *ifp);
+
+
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,
diff --git a/tests/sys/netlink/test_rtnl_iface.py b/tests/sys/netlink/test_rtnl_iface.py
--- a/tests/sys/netlink/test_rtnl_iface.py
+++ b/tests/sys/netlink/test_rtnl_iface.py
@@ -19,6 +19,7 @@
from atf_python.sys.netlink.netlink_route import NlRtMsgType
from atf_python.sys.netlink.netlink_route import rtnl_ifla_attrs
from atf_python.sys.net.vnet import SingleVnetTestTemplate
+from atf_python.sys.net.tools import ToolsHelper
class TestRtNlIface(NetlinkTestTemplate, SingleVnetTestTemplate):
@@ -324,6 +325,7 @@
msg.nl_hdr.nlmsg_flags = (
flags | NlmBaseFlags.NLM_F_ACK.value | NlmBaseFlags.NLM_F_REQUEST.value
)
+ msg.base_hdr.ifi_index = ifindex
msg.add_nla(NlAttrU32(IflattrType.IFLA_LINK, ifindex))
msg.add_nla(NlAttrStr(IflattrType.IFLA_IFNAME, "vlan22"))
@@ -347,5 +349,6 @@
assert rx_msg.is_type(NlMsgType.NLMSG_ERROR)
assert rx_msg.error_code == 0
+ ToolsHelper.print_net_debug()
self.get_interface_byname("vlan22")
# ToolsHelper.print_net_debug()

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 18, 11:26 AM (21 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14695467
Default Alt Text
D39032.diff (29 KB)

Event Timeline