Index: sys/kern/kern_mbuf.c =================================================================== --- sys/kern/kern_mbuf.c +++ sys/kern/kern_mbuf.c @@ -1635,6 +1635,28 @@ 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_idx; + 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. */ Index: sys/net/if.c =================================================================== --- sys/net/if.c +++ sys/net/if.c @@ -406,6 +406,24 @@ return (ifp); } +struct ifnet * +ifnet_byindexgen(uint16_t idx, uint16_t gen) +{ + struct ifnet *ifp; + + NET_EPOCH_ASSERT(); + + if (__predict_false(idx > if_idx)) + return (NULL); + + ifp = ck_pr_load_ptr(&if_table[idx].ife_ifnet); + + if (ck_pr_load_16(&if_table[idx].ife_gencnt) == gen) + return (ifp); + else + return (NULL); +} + /* * Allocate global and virtual ifindex entries for ifnet. * For a new interface ife = NULL. For interface being if_vmove'd, Index: sys/net/if_var.h =================================================================== --- sys/net/if_var.h +++ sys/net/if_var.h @@ -614,12 +614,18 @@ #define IFNET_RUNLOCK() sx_sunlock(&ifnet_sxlock) /* - * Look up an ifnet given its index. The returned value protected from + * Look up an ifnet given its *vnet* index. The returned value protected from * being freed by the network epoch. The _ref variant also acquires a * reference that must be freed using if_rele(). */ struct ifnet *ifnet_byindex(int); struct ifnet *ifnet_byindex_ref(int); +/* + * ifnet_byindexgen() looks up ifnet by *global* 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); /* * Given the index, ifaddr_byindex() returns the one and only Index: sys/sys/mbuf.h =================================================================== --- sys/sys/mbuf.h +++ sys/sys/mbuf.h @@ -159,6 +159,10 @@ 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 @@ 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)