Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102808836
D39032.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
29 KB
Referenced Files
None
Subscribers
None
D39032.diff
View Options
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 = ¶ms };
+
+ 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 = ¶ms };
-
- 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
Details
Attached
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)
Attached To
Mode
D39032: netlink: add netlink interfaces to if_clone
Attached
Detach File
Event Timeline
Log In to Comment