The branch main has been updated by melifaro:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=089104e0e01f080c9cd45dc5f34c4f636dea4ca7

commit 089104e0e01f080c9cd45dc5f34c4f636dea4ca7
Author:     Alexander V. Chernikov <[email protected]>
AuthorDate: 2023-04-19 12:35:02 +0000
Commit:     Alexander V. Chernikov <[email protected]>
CommitDate: 2023-04-25 12:34:46 +0000

    netlink: add netlink interfaces to if_clone
    
    This change adds netlink create/modify/dump interfaces to the `if_clone.c`.
    The previous attempt with storing the logic inside 
`netlink/route/iface_drivers.c`
     did not quite work, as, for example, dumping interface-specific state
     (like vlan id or vlan parent) required some peeking into the private 
interfaces.
    
    The new interfaces are added in a compatible way - callers don't have to do 
anything
    unless they are extended with Netlink.
    
    Reviewed by:    kp
    Differential Revision: https://reviews.freebsd.org/D39032
    MFC after:      1 month
---
 sys/net/if_clone.c                   | 163 +++++++++++++++++++++++++------
 sys/net/if_clone.h                   |  42 +++++++-
 sys/net/if_vlan.c                    | 180 ++++++++++++++++++++++++++++++++++-
 sys/netlink/netlink_glue.c           |  29 ++++++
 sys/netlink/netlink_module.c         |   1 +
 sys/netlink/netlink_var.h            |  10 ++
 sys/netlink/route/iface.c            |  65 ++++---------
 sys/netlink/route/iface_drivers.c    | 172 ++-------------------------------
 sys/netlink/route/route_var.h        |   6 ++
 tests/sys/netlink/test_rtnl_iface.py |   3 +
 10 files changed, 427 insertions(+), 244 deletions(-)

diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c
index 59d60645cb89..3dd577850f82 100644
--- 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 @@ struct if_clone {
        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 @@ struct if_clone {
 
 
 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 @@ vnet_if_clone_init(void)
  * 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 @@ if_clone_create(char *name, size_t len, caddr_t params)
        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 @@ ifc_find_cloner_in_vnet(const char *name, struct vnet 
*vnet)
  * 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 @@ if_clone_alloc(const char *name, int maxunit)
        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_attach_cloner(const char *name, struct if_clone_addreq 
*req)
        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 @@ if_clone_simple(const char *name, ifcs_create_t create, 
ifcs_destroy_t destroy,
        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_clone.h b/sys/net/if_clone.h
index 1d918a012a5b..8b52c375addb 100644
--- a/sys/net/if_clone.h
+++ b/sys/net/if_clone.h
@@ -56,6 +56,26 @@ typedef int ifc_create_f(struct if_clone *ifc, char *name, 
size_t maxlen,
     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 @@ struct if_clone_addreq {
        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_vlan.c b/sys/net/if_vlan.c
index 0f2ded3f6040..f5b401c446ed 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
 #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 @@ __FBSDID("$FreeBSD$");
 #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 @@ static     int vlan_clone_create(struct if_clone *, char 
*, size_t,
     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 @@ extern    void (*vlan_input_p)(struct ifnet *, struct 
mbuf *);
 /* 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_modevent(module_t mod, int type, void *data)
                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 @@ MODULE_VERSION(if_vlan, 3);
 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 @@ vlan_clone_create(struct if_clone *ifc, char *name, 
size_t len,
        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
index 25b891036b5b..069cb9900e03 100644
--- a/sys/netlink/netlink_glue.c
+++ b/sys/netlink/netlink_glue.c
@@ -177,6 +177,19 @@ nlmsg_end_dump_stub(struct nl_writer *nw, int error, 
struct nlmsghdr *hdr)
        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 @@ const static struct nl_function_wrapper nl_stub = {
        .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 @@ nlmsg_end_dump(struct nl_writer *nw, int error, struct 
nlmsghdr *hdr)
 {
        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
index a881a7540166..051eb0cb120b 100644
--- a/sys/netlink/netlink_module.c
+++ b/sys/netlink/netlink_module.c
@@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
 #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
index 465378f8af1e..cb1e3974b5f5 100644
--- a/sys/netlink/netlink_var.h
+++ b/sys/netlink/netlink_var.h
@@ -172,6 +172,11 @@ struct genl_group *genl_get_group(uint32_t group_id);
 
 #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 @@ struct nl_function_wrapper {
        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
index b27a0193fe0d..d81dc1f0ecae 100644
--- a/sys/netlink/route/iface.c
+++ b/sys/netlink/route/iface.c
@@ -303,13 +303,7 @@ dump_iface(struct nl_writer *nw, struct ifnet *ifp, const 
struct nlmsghdr *hdr,
        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 @@ NL_DECLARE_ATTR_PARSER(linfo_parser, nla_p_linfo);
 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 @@ create_link(struct nlmsghdr *hdr, struct nl_parsed_link 
*lattrs,
                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 @@ modify_link(struct nlmsghdr *hdr, struct nl_parsed_link 
*lattrs,
        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 @@ rtnl_ifaces_init(void)
            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
index be28a0f3b676..17fbc1000d23 100644
--- a/sys/netlink/route/iface_drivers.c
+++ b/sys/netlink/route/iface_drivers.c
@@ -63,14 +63,14 @@ _DECLARE_DEBUG(LOG_DEBUG);
  * 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 @@ modify_generic(struct ifnet *ifp, struct nl_parsed_link 
*lattrs,
        }
 
        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 @@ modify_generic(struct ifnet *ifp, struct nl_parsed_link 
*lattrs,
  *  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 @@ store_cookie(struct nl_pstate *npt, struct ifnet *ifp)
        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)
-{
*** 70 LINES SKIPPED ***


Reply via email to