The branch main has been updated by emaste:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=4d7a1361ef3227fd3d78c7a5da132cbba351dc9d

commit 4d7a1361ef3227fd3d78c7a5da132cbba351dc9d
Author:     Gleb Smirnoff <gleb...@freebsd.org>
AuthorDate: 2022-01-27 05:58:50 +0000
Commit:     Ed Maste <ema...@freebsd.org>
CommitDate: 2022-05-05 18:38:07 +0000

    ifnet/mbuf: provide KPI to serialize/restore m->m_pkthdr.rcvif
    
    Supplement ifindex table with generation count and use it to
    serialize & restore an ifnet pointer.
    
    Reviewed by:            kp
    Differential revision:  https://reviews.freebsd.org/D33266
    Fun note:               git show e6abef09187a
    
    (cherry picked from commit e1882428dcbbafd2814d7e17b977a8f686784b39)
---
 sys/kern/kern_mbuf.c | 22 ++++++++++++++++++++++
 sys/net/if.c         | 49 ++++++++++++++++++++++++++++++++++++-------------
 sys/net/if_var.h     |  9 ++++++++-
 sys/sys/mbuf.h       |  6 ++++++
 4 files changed, 72 insertions(+), 14 deletions(-)

diff --git a/sys/kern/kern_mbuf.c b/sys/kern/kern_mbuf.c
index f1e76ef00c65..5c69f663c0e2 100644
--- a/sys/kern/kern_mbuf.c
+++ b/sys/kern/kern_mbuf.c
@@ -1635,6 +1635,28 @@ m_snd_tag_destroy(struct m_snd_tag *mst)
        counter_u64_add(snd_tag_count, -1);
 }
 
+void
+m_rcvif_serialize(struct mbuf *m)
+{
+       u_short idx, gen;
+
+       M_ASSERTPKTHDR(m);
+       idx = m->m_pkthdr.rcvif->if_index;
+       gen = m->m_pkthdr.rcvif->if_idxgen;
+       m->m_pkthdr.rcvidx = idx;
+       m->m_pkthdr.rcvgen = gen;
+}
+
+struct ifnet *
+m_rcvif_restore(struct mbuf *m)
+{
+
+       M_ASSERTPKTHDR(m);
+
+       return ((m->m_pkthdr.rcvif = ifnet_byindexgen(m->m_pkthdr.rcvidx,
+           m->m_pkthdr.rcvgen)));
+}
+
 /*
  * Allocate an mbuf with anonymous external pages.
  */
diff --git a/sys/net/if.c b/sys/net/if.c
index 3b303fe42e99..ff7071cea364 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -313,7 +313,10 @@ VNET_DEFINE(struct ifgrouphead, ifg_head);
 /* Table of ifnet by index. */
 static int if_index;
 static int if_indexlim = 8;
-static struct ifnet **ifindex_table;
+static struct ifindex_entry {
+       struct ifnet    *ife_ifnet;
+       uint16_t        ife_gencnt;
+} *ifindex_table;
 
 SYSCTL_NODE(_net_link_generic, IFMIB_SYSTEM, system,
     CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
@@ -325,8 +328,8 @@ sysctl_ifcount(SYSCTL_HANDLER_ARGS)
 
        IFNET_RLOCK();
        for (int i = 1; i <= if_index; i++)
-               if (ifindex_table[i] != NULL &&
-                   ifindex_table[i]->if_vnet == curvnet)
+               if (ifindex_table[i].ife_ifnet != NULL &&
+                   ifindex_table[i].ife_ifnet->if_vnet == curvnet)
                        rv = i;
        IFNET_RUNLOCK();
 
@@ -370,7 +373,7 @@ ifnet_byindex(u_int idx)
        if (__predict_false(idx > if_index))
                return (NULL);
 
-       ifp = ck_pr_load_ptr(&ifindex_table[idx]);
+       ifp = ck_pr_load_ptr(&ifindex_table[idx].ife_ifnet);
 
        if (curvnet != NULL && ifp != NULL && ifp->if_vnet != curvnet)
                ifp = NULL;
@@ -391,6 +394,24 @@ ifnet_byindex_ref(u_int idx)
        return (ifp);
 }
 
+struct ifnet *
+ifnet_byindexgen(uint16_t idx, uint16_t gen)
+{
+       struct ifnet *ifp;
+
+       NET_EPOCH_ASSERT();
+
+       if (__predict_false(idx > if_index))
+               return (NULL);
+
+       ifp = ck_pr_load_ptr(&ifindex_table[idx].ife_ifnet);
+
+       if (ifindex_table[idx].ife_gencnt == gen)
+               return (ifp);
+       else
+               return (NULL);
+}
+
 /*
  * Network interface utility routines.
  *
@@ -557,13 +578,13 @@ if_alloc_domain(u_char type, int numa_domain)
         * next slot.
         */
        for (idx = 1; idx <= if_index; idx++) {
-               if (ifindex_table[idx] == NULL)
+               if (ifindex_table[idx].ife_ifnet == NULL)
                        break;
        }
 
        /* Catch if_index overflow. */
        if (idx >= if_indexlim) {
-               struct ifnet **new, **old;
+               struct ifindex_entry *new, *old;
                int newlim;
 
                newlim = if_indexlim * 2;
@@ -579,7 +600,8 @@ if_alloc_domain(u_char type, int numa_domain)
                if_index = idx;
 
        ifp->if_index = idx;
-       ck_pr_store_ptr(&ifindex_table[idx], ifp);
+       ifp->if_idxgen = ifindex_table[idx].ife_gencnt;
+       ck_pr_store_ptr(&ifindex_table[idx].ife_ifnet, ifp);
        IFNET_WUNLOCK();
 
        return (ifp);
@@ -654,9 +676,10 @@ if_free(struct ifnet *ifp)
         * virtualized and interface would outlive the vnet.
         */
        IFNET_WLOCK();
-       MPASS(ifindex_table[ifp->if_index] == ifp);
-       ck_pr_store_ptr(&ifindex_table[ifp->if_index], NULL);
-       while (if_index > 0 && ifindex_table[if_index] == NULL)
+       MPASS(ifindex_table[ifp->if_index].ife_ifnet == ifp);
+       ck_pr_store_ptr(&ifindex_table[ifp->if_index].ife_ifnet, NULL);
+       ifindex_table[ifp->if_index].ife_gencnt++;
+       while (if_index > 0 && ifindex_table[if_index].ife_ifnet == NULL)
                if_index--;
        IFNET_WUNLOCK();
 
@@ -805,7 +828,7 @@ if_attach_internal(struct ifnet *ifp, bool vmove)
        struct sockaddr_dl *sdl;
        struct ifaddr *ifa;
 
-       MPASS(ifindex_table[ifp->if_index] == ifp);
+       MPASS(ifindex_table[ifp->if_index].ife_ifnet == ifp);
 
 #ifdef VIMAGE
        ifp->if_vnet = curvnet;
@@ -4494,8 +4517,8 @@ if_show_ifnet(struct ifnet *ifp)
        IF_DB_PRINTF("%d", if_dunit);
        IF_DB_PRINTF("%s", if_description);
        IF_DB_PRINTF("%u", if_index);
+       IF_DB_PRINTF("%d", if_idxgen);
        IF_DB_PRINTF("%u", if_refcount);
-       IF_DB_PRINTF("%d", if_index_reserved);
        IF_DB_PRINTF("%p", if_softc);
        IF_DB_PRINTF("%p", if_l2com);
        IF_DB_PRINTF("%p", if_llsoftc);
@@ -4550,7 +4573,7 @@ DB_SHOW_ALL_COMMAND(ifnets, db_show_all_ifnets)
        u_short idx;
 
        for (idx = 1; idx <= if_index; idx++) {
-               ifp = ifindex_table[idx];
+               ifp = ifindex_table[idx].ife_ifnet;
                if (ifp == NULL)
                        continue;
                db_printf( "%20s ifp=%p\n", ifp->if_xname, ifp);
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index d741d8abee2e..e054c613e9e6 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -334,7 +334,7 @@ struct ifnet {
        const char *if_dname;           /* driver name */
        int     if_dunit;               /* unit or IF_DUNIT_NONE */
        u_short if_index;               /* numeric abbreviation for this if  */
-       short   if_index_reserved;      /* spare space to grow if_index */
+       u_short if_idxgen;              /* ... and its generation count */
        char    if_xname[IFNAMSIZ];     /* external name (name + unit) */
        char    *if_description;        /* interface description */
 
@@ -644,6 +644,13 @@ extern     struct sx ifnet_sxlock;
 struct ifnet   *ifnet_byindex(u_int);
 struct ifnet   *ifnet_byindex_ref(u_int);
 
+/*
+ * ifnet_byindexgen() looks up ifnet by index and generation count,
+ * attempting to restore a weak pointer that had been stored across
+ * the epoch.
+ */
+struct ifnet   *ifnet_byindexgen(uint16_t idx, uint16_t gen);
+
 VNET_DECLARE(struct ifnethead, ifnet);
 VNET_DECLARE(struct ifgrouphead, ifg_head);
 VNET_DECLARE(struct ifnet *, loif);    /* first loopback interface */
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index 8ca23b60269d..78b175ebe2c0 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -159,6 +159,10 @@ struct pkthdr {
        union {
                struct m_snd_tag *snd_tag;      /* send tag, if any */
                struct ifnet    *rcvif;         /* rcv interface */
+               struct {
+                       uint16_t rcvidx;        /* rcv interface index ... */
+                       uint16_t rcvgen;        /* ... and generation count */
+               };
        };
        SLIST_HEAD(packet_tags, m_tag) tags; /* list of packet tags */
        int32_t          len;           /* total packet length */
@@ -862,6 +866,8 @@ int          m_snd_tag_alloc(struct ifnet *,
 void            m_snd_tag_init(struct m_snd_tag *, struct ifnet *,
                    const struct if_snd_tag_sw *);
 void            m_snd_tag_destroy(struct m_snd_tag *);
+void            m_rcvif_serialize(struct mbuf *);
+struct ifnet   *m_rcvif_restore(struct mbuf *);
 
 static __inline int
 m_gettype(int size)

Reply via email to