From c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 7 Oct 2016 15:10:20 +0200 Subject: Update to FreeBSD head 2016-08-23 Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd. --- freebsd/sys/netinet/igmp.c | 462 ++++++++++++++++++++++++--------------------- 1 file changed, 246 insertions(+), 216 deletions(-) (limited to 'freebsd/sys/netinet/igmp.c') diff --git a/freebsd/sys/netinet/igmp.c b/freebsd/sys/netinet/igmp.c index 78d9685b..cd57e426 100644 --- a/freebsd/sys/netinet/igmp.c +++ b/freebsd/sys/netinet/igmp.c @@ -52,6 +52,8 @@ #include __FBSDID("$FreeBSD$"); +#include + #include #include #include @@ -60,11 +62,18 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include #include #include +#ifdef DDB +#include +#endif + #include +#include #include #include @@ -85,15 +94,15 @@ __FBSDID("$FreeBSD$"); #define KTR_IGMPV3 KTR_INET #endif -static struct igmp_ifinfo * +static struct igmp_ifsoftc * igi_alloc_locked(struct ifnet *); static void igi_delete_locked(const struct ifnet *); -static void igmp_dispatch_queue(struct ifqueue *, int, const int); +static void igmp_dispatch_queue(struct mbufq *, int, const int); static void igmp_fasttimo_vnet(void); -static void igmp_final_leave(struct in_multi *, struct igmp_ifinfo *); +static void igmp_final_leave(struct in_multi *, struct igmp_ifsoftc *); static int igmp_handle_state_change(struct in_multi *, - struct igmp_ifinfo *); -static int igmp_initial_join(struct in_multi *, struct igmp_ifinfo *); + struct igmp_ifsoftc *); +static int igmp_initial_join(struct in_multi *, struct igmp_ifsoftc *); static int igmp_input_v1_query(struct ifnet *, const struct ip *, const struct igmp *); static int igmp_input_v2_query(struct ifnet *, const struct ip *, @@ -101,7 +110,7 @@ static int igmp_input_v2_query(struct ifnet *, const struct ip *, static int igmp_input_v3_query(struct ifnet *, const struct ip *, /*const*/ struct igmpv3 *); static int igmp_input_v3_group_query(struct in_multi *, - struct igmp_ifinfo *, int, /*const*/ struct igmpv3 *); + struct igmp_ifsoftc *, int, /*const*/ struct igmpv3 *); static int igmp_input_v1_report(struct ifnet *, /*const*/ struct ip *, /*const*/ struct igmp *); static int igmp_input_v2_report(struct ifnet *, /*const*/ struct ip *, @@ -113,25 +122,25 @@ static struct mbuf * #ifdef KTR static char * igmp_rec_type_to_str(const int); #endif -static void igmp_set_version(struct igmp_ifinfo *, const int); +static void igmp_set_version(struct igmp_ifsoftc *, const int); static void igmp_slowtimo_vnet(void); static int igmp_v1v2_queue_report(struct in_multi *, const int); static void igmp_v1v2_process_group_timer(struct in_multi *, const int); -static void igmp_v1v2_process_querier_timers(struct igmp_ifinfo *); +static void igmp_v1v2_process_querier_timers(struct igmp_ifsoftc *); static void igmp_v2_update_group(struct in_multi *, const int); -static void igmp_v3_cancel_link_timers(struct igmp_ifinfo *); -static void igmp_v3_dispatch_general_query(struct igmp_ifinfo *); +static void igmp_v3_cancel_link_timers(struct igmp_ifsoftc *); +static void igmp_v3_dispatch_general_query(struct igmp_ifsoftc *); static struct mbuf * igmp_v3_encap_report(struct ifnet *, struct mbuf *); -static int igmp_v3_enqueue_group_record(struct ifqueue *, +static int igmp_v3_enqueue_group_record(struct mbufq *, struct in_multi *, const int, const int, const int); -static int igmp_v3_enqueue_filter_change(struct ifqueue *, +static int igmp_v3_enqueue_filter_change(struct mbufq *, struct in_multi *); -static void igmp_v3_process_group_timers(struct igmp_ifinfo *, - struct ifqueue *, struct ifqueue *, struct in_multi *, +static void igmp_v3_process_group_timers(struct igmp_ifsoftc *, + struct mbufq *, struct mbufq *, struct in_multi *, const int); static int igmp_v3_merge_state_changes(struct in_multi *, - struct ifqueue *); + struct mbufq *); static void igmp_v3_suppress_group_record(struct in_multi *); static int sysctl_igmp_default_version(SYSCTL_HANDLER_ARGS); static int sysctl_igmp_gsr(SYSCTL_HANDLER_ARGS); @@ -159,13 +168,13 @@ static const struct netisr_handler igmp_nh = { * * All output is delegated to the netisr. * Now that Giant has been eliminated, the netisr may be inlined. * * IN_MULTI_LOCK covers in_multi. - * * IGMP_LOCK covers igmp_ifinfo and any global variables in this file, + * * IGMP_LOCK covers igmp_ifsoftc and any global variables in this file, * including the output queue. * * IF_ADDR_LOCK covers if_multiaddrs, which is used for a variety of * per-link state iterators. - * * igmp_ifinfo is valid as long as PF_INET is attached to the interface, + * * igmp_ifsoftc is valid as long as PF_INET is attached to the interface, * therefore it is not refcounted. - * We allow unlocked reads of igmp_ifinfo when accessed via in_multi. + * We allow unlocked reads of igmp_ifsoftc when accessed via in_multi. * * Reference counting * * IGMP acquires its own reference every time an in_multi is passed to @@ -220,7 +229,8 @@ static VNET_DEFINE(int, current_state_timers_running); /* IGMPv1/v2 host #define V_state_change_timers_running VNET(state_change_timers_running) #define V_current_state_timers_running VNET(current_state_timers_running) -static VNET_DEFINE(LIST_HEAD(, igmp_ifinfo), igi_head); +static VNET_DEFINE(LIST_HEAD(, igmp_ifsoftc), igi_head) = + LIST_HEAD_INITIALIZER(igi_head); static VNET_DEFINE(struct igmpstat, igmpstat) = { .igps_version = IGPS_VERSION_3, .igps_len = sizeof(struct igmpstat), @@ -250,32 +260,32 @@ static VNET_DEFINE(int, igmp_default_version) = IGMP_VERSION_3; /* * Virtualized sysctls. */ -SYSCTL_VNET_STRUCT(_net_inet_igmp, IGMPCTL_STATS, stats, CTLFLAG_RW, +SYSCTL_STRUCT(_net_inet_igmp, IGMPCTL_STATS, stats, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(igmpstat), igmpstat, ""); -SYSCTL_VNET_INT(_net_inet_igmp, OID_AUTO, recvifkludge, CTLFLAG_RW, +SYSCTL_INT(_net_inet_igmp, OID_AUTO, recvifkludge, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(igmp_recvifkludge), 0, "Rewrite IGMPv1/v2 reports from 0.0.0.0 to contain subnet address"); -SYSCTL_VNET_INT(_net_inet_igmp, OID_AUTO, sendra, CTLFLAG_RW, +SYSCTL_INT(_net_inet_igmp, OID_AUTO, sendra, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(igmp_sendra), 0, "Send IP Router Alert option in IGMPv2/v3 messages"); -SYSCTL_VNET_INT(_net_inet_igmp, OID_AUTO, sendlocal, CTLFLAG_RW, +SYSCTL_INT(_net_inet_igmp, OID_AUTO, sendlocal, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(igmp_sendlocal), 0, "Send IGMP membership reports for 224.0.0.0/24 groups"); -SYSCTL_VNET_INT(_net_inet_igmp, OID_AUTO, v1enable, CTLFLAG_RW, +SYSCTL_INT(_net_inet_igmp, OID_AUTO, v1enable, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(igmp_v1enable), 0, "Enable backwards compatibility with IGMPv1"); -SYSCTL_VNET_INT(_net_inet_igmp, OID_AUTO, v2enable, CTLFLAG_RW, +SYSCTL_INT(_net_inet_igmp, OID_AUTO, v2enable, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(igmp_v2enable), 0, "Enable backwards compatibility with IGMPv2"); -SYSCTL_VNET_INT(_net_inet_igmp, OID_AUTO, legacysupp, CTLFLAG_RW, +SYSCTL_INT(_net_inet_igmp, OID_AUTO, legacysupp, CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(igmp_legacysupp), 0, "Allow v1/v2 reports to suppress v3 group responses"); -SYSCTL_VNET_PROC(_net_inet_igmp, OID_AUTO, default_version, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, +SYSCTL_PROC(_net_inet_igmp, OID_AUTO, default_version, + CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &VNET_NAME(igmp_default_version), 0, sysctl_igmp_default_version, "I", "Default version of IGMP to run on each interface"); -SYSCTL_VNET_PROC(_net_inet_igmp, OID_AUTO, gsrdelay, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, +SYSCTL_PROC(_net_inet_igmp, OID_AUTO, gsrdelay, + CTLFLAG_VNET | CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, &VNET_NAME(igmp_gsrdelay.tv_sec), 0, sysctl_igmp_gsr, "I", "Rate limit for IGMPv3 Group-and-Source queries in seconds"); @@ -291,7 +301,7 @@ igmp_save_context(struct mbuf *m, struct ifnet *ifp) { #ifdef VIMAGE - m->m_pkthdr.header = ifp->if_vnet; + m->m_pkthdr.PH_loc.ptr = ifp->if_vnet; #endif /* VIMAGE */ m->m_pkthdr.flowid = ifp->if_index; } @@ -300,7 +310,7 @@ static __inline void igmp_scrub_context(struct mbuf *m) { - m->m_pkthdr.header = NULL; + m->m_pkthdr.PH_loc.ptr = NULL; m->m_pkthdr.flowid = 0; } @@ -328,7 +338,7 @@ igmp_restore_context(struct mbuf *m) #ifdef notyet #if defined(VIMAGE) && defined(INVARIANTS) - KASSERT(curvnet == (m->m_pkthdr.header), + KASSERT(curvnet == (m->m_pkthdr.PH_loc.ptr), ("%s: called when curvnet was not restored", __func__)); #endif #endif @@ -413,7 +423,7 @@ out_locked: } /* - * Expose struct igmp_ifinfo to userland, keyed by ifindex. + * Expose struct igmp_ifsoftc to userland, keyed by ifindex. * For use by ifmcstat(8). * * SMPng: NOTE: Does an unlocked ifindex space read. @@ -427,7 +437,7 @@ sysctl_igmp_ifinfo(SYSCTL_HANDLER_ARGS) int error; u_int namelen; struct ifnet *ifp; - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; name = (int *)arg1; namelen = arg2; @@ -458,8 +468,18 @@ sysctl_igmp_ifinfo(SYSCTL_HANDLER_ARGS) LIST_FOREACH(igi, &V_igi_head, igi_link) { if (ifp == igi->igi_ifp) { - error = SYSCTL_OUT(req, igi, - sizeof(struct igmp_ifinfo)); + struct igmp_ifinfo info; + + info.igi_version = igi->igi_version; + info.igi_v1_timer = igi->igi_v1_timer; + info.igi_v2_timer = igi->igi_v2_timer; + info.igi_v3_timer = igi->igi_v3_timer; + info.igi_flags = igi->igi_flags; + info.igi_rv = igi->igi_rv; + info.igi_qi = igi->igi_qi; + info.igi_qri = igi->igi_qri; + info.igi_uri = igi->igi_uri; + error = SYSCTL_OUT(req, &info, sizeof(info)); break; } } @@ -476,15 +496,12 @@ out_locked: * VIMAGE: Assumes the vnet pointer has been set. */ static void -igmp_dispatch_queue(struct ifqueue *ifq, int limit, const int loop) +igmp_dispatch_queue(struct mbufq *mq, int limit, const int loop) { struct mbuf *m; - for (;;) { - _IF_DEQUEUE(ifq, m); - if (m == NULL) - break; - CTR3(KTR_IGMPV3, "%s: dispatch %p from %p", __func__, ifq, m); + while ((m = mbufq_dequeue(mq)) != NULL) { + CTR3(KTR_IGMPV3, "%s: dispatch %p from %p", __func__, mq, m); if (loop) m->m_flags |= M_IGMP_LOOP; netisr_dispatch(NETISR_IGMP, m); @@ -525,7 +542,7 @@ igmp_ra_alloc(void) struct mbuf *m; struct ipoption *p; - MGET(m, M_DONTWAIT, MT_DATA); + m = m_get(M_WAITOK, MT_DATA); p = mtod(m, struct ipoption *); p->ipopt_dst.s_addr = INADDR_ANY; p->ipopt_list[0] = IPOPT_RA; /* Router Alert Option */ @@ -540,10 +557,10 @@ igmp_ra_alloc(void) /* * Attach IGMP when PF_INET is attached to an interface. */ -struct igmp_ifinfo * +struct igmp_ifsoftc * igmp_domifattach(struct ifnet *ifp) { - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; CTR3(KTR_IGMPV3, "%s: called for ifp %p(%s)", __func__, ifp, ifp->if_xname); @@ -562,14 +579,14 @@ igmp_domifattach(struct ifnet *ifp) /* * VIMAGE: assume curvnet set by caller. */ -static struct igmp_ifinfo * +static struct igmp_ifsoftc * igi_alloc_locked(/*const*/ struct ifnet *ifp) { - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; IGMP_LOCK_ASSERT(); - igi = malloc(sizeof(struct igmp_ifinfo), M_IGMP, M_NOWAIT|M_ZERO); + igi = malloc(sizeof(struct igmp_ifsoftc), M_IGMP, M_NOWAIT|M_ZERO); if (igi == NULL) goto out; @@ -580,17 +597,12 @@ igi_alloc_locked(/*const*/ struct ifnet *ifp) igi->igi_qi = IGMP_QI_INIT; igi->igi_qri = IGMP_QRI_INIT; igi->igi_uri = IGMP_URI_INIT; - SLIST_INIT(&igi->igi_relinmhead); - - /* - * Responses to general queries are subject to bounds. - */ - IFQ_SET_MAXLEN(&igi->igi_gq, IGMP_MAX_RESPONSE_PACKETS); + mbufq_init(&igi->igi_gq, IGMP_MAX_RESPONSE_PACKETS); LIST_INSERT_HEAD(&V_igi_head, igi, igi_link); - CTR2(KTR_IGMPV3, "allocate igmp_ifinfo for ifp %p(%s)", + CTR2(KTR_IGMPV3, "allocate igmp_ifsoftc for ifp %p(%s)", ifp, ifp->if_xname); out: @@ -609,7 +621,7 @@ out: void igmp_ifdetach(struct ifnet *ifp) { - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; struct ifmultiaddr *ifma; struct in_multi *inm, *tinm; @@ -656,25 +668,21 @@ igmp_ifdetach(struct ifnet *ifp) void igmp_domifdetach(struct ifnet *ifp) { - struct igmp_ifinfo *igi; CTR3(KTR_IGMPV3, "%s: called for ifp %p(%s)", __func__, ifp, ifp->if_xname); IGMP_LOCK(); - - igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; igi_delete_locked(ifp); - IGMP_UNLOCK(); } static void igi_delete_locked(const struct ifnet *ifp) { - struct igmp_ifinfo *igi, *tigi; + struct igmp_ifsoftc *igi, *tigi; - CTR3(KTR_IGMPV3, "%s: freeing igmp_ifinfo for ifp %p(%s)", + CTR3(KTR_IGMPV3, "%s: freeing igmp_ifsoftc for ifp %p(%s)", __func__, ifp, ifp->if_xname); IGMP_LOCK_ASSERT(); @@ -684,7 +692,7 @@ igi_delete_locked(const struct ifnet *ifp) /* * Free deferred General Query responses. */ - _IF_DRAIN(&igi->igi_gq); + mbufq_drain(&igi->igi_gq); LIST_REMOVE(igi, igi_link); @@ -696,10 +704,6 @@ igi_delete_locked(const struct ifnet *ifp) return; } } - -#ifdef INVARIANTS - panic("%s: igmp_ifinfo not found for ifp %p\n", __func__, ifp); -#endif } /* @@ -713,7 +717,7 @@ igmp_input_v1_query(struct ifnet *ifp, const struct ip *ip, const struct igmp *igmp) { struct ifmultiaddr *ifma; - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; struct in_multi *inm; /* @@ -733,7 +737,7 @@ igmp_input_v1_query(struct ifnet *ifp, const struct ip *ip, IGMP_LOCK(); igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; - KASSERT(igi != NULL, ("%s: no igmp_ifinfo for ifp %p", __func__, ifp)); + KASSERT(igi != NULL, ("%s: no igmp_ifsoftc for ifp %p", __func__, ifp)); if (igi->igi_flags & IGIF_LOOPBACK) { CTR2(KTR_IGMPV3, "ignore v1 query on IGIF_LOOPBACK ifp %p(%s)", @@ -798,7 +802,7 @@ igmp_input_v2_query(struct ifnet *ifp, const struct ip *ip, const struct igmp *igmp) { struct ifmultiaddr *ifma; - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; struct in_multi *inm; int is_general_query; uint16_t timer; @@ -827,7 +831,7 @@ igmp_input_v2_query(struct ifnet *ifp, const struct ip *ip, IGMP_LOCK(); igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; - KASSERT(igi != NULL, ("%s: no igmp_ifinfo for ifp %p", __func__, ifp)); + KASSERT(igi != NULL, ("%s: no igmp_ifsoftc for ifp %p", __func__, ifp)); if (igi->igi_flags & IGIF_LOOPBACK) { CTR2(KTR_IGMPV3, "ignore v2 query on IGIF_LOOPBACK ifp %p(%s)", @@ -948,7 +952,7 @@ static int igmp_input_v3_query(struct ifnet *ifp, const struct ip *ip, /*const*/ struct igmpv3 *igmpv3) { - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; struct in_multi *inm; int is_general_query; uint32_t maxresp, nsrc, qqi; @@ -1021,7 +1025,7 @@ igmp_input_v3_query(struct ifnet *ifp, const struct ip *ip, IGMP_LOCK(); igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; - KASSERT(igi != NULL, ("%s: no igmp_ifinfo for ifp %p", __func__, ifp)); + KASSERT(igi != NULL, ("%s: no igmp_ifsoftc for ifp %p", __func__, ifp)); if (igi->igi_flags & IGIF_LOOPBACK) { CTR2(KTR_IGMPV3, "ignore v3 query on IGIF_LOOPBACK ifp %p(%s)", @@ -1104,12 +1108,12 @@ out_locked: } /* - * Process a recieved IGMPv3 group-specific or group-and-source-specific + * Process a received IGMPv3 group-specific or group-and-source-specific * query. - * Return <0 if any error occured. Currently this is ignored. + * Return <0 if any error occurred. Currently this is ignored. */ static int -igmp_input_v3_group_query(struct in_multi *inm, struct igmp_ifinfo *igi, +igmp_input_v3_group_query(struct in_multi *inm, struct igmp_ifsoftc *igi, int timer, /*const*/ struct igmpv3 *igmpv3) { int retval; @@ -1214,6 +1218,7 @@ static int igmp_input_v1_report(struct ifnet *ifp, /*const*/ struct ip *ip, /*const*/ struct igmp *igmp) { + struct rm_priotracker in_ifa_tracker; struct in_ifaddr *ia; struct in_multi *inm; @@ -1236,7 +1241,7 @@ igmp_input_v1_report(struct ifnet *ifp, /*const*/ struct ip *ip, * Replace 0.0.0.0 with the subnet address if told to do so. */ if (V_igmp_recvifkludge && in_nullhost(ip->ip_src)) { - IFP_TO_IA(ifp, ia); + IFP_TO_IA(ifp, ia, &in_ifa_tracker); if (ia != NULL) { ip->ip_src.s_addr = htonl(ia->ia_subnet); ifa_free(&ia->ia_ifa); @@ -1254,7 +1259,7 @@ igmp_input_v1_report(struct ifnet *ifp, /*const*/ struct ip *ip, IN_MULTI_LOCK(); inm = inm_lookup(ifp, igmp->igmp_group); if (inm != NULL) { - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; igi = inm->inm_igi; if (igi == NULL) { @@ -1322,6 +1327,7 @@ static int igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip, /*const*/ struct igmp *igmp) { + struct rm_priotracker in_ifa_tracker; struct in_ifaddr *ia; struct in_multi *inm; @@ -1330,7 +1336,7 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip, * leave requires knowing that we are the only member of a * group. */ - IFP_TO_IA(ifp, ia); + IFP_TO_IA(ifp, ia, &in_ifa_tracker); if (ia != NULL && in_hosteq(ip->ip_src, IA_SIN(ia)->sin_addr)) { ifa_free(&ia->ia_ifa); return (0); @@ -1378,7 +1384,7 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip, IN_MULTI_LOCK(); inm = inm_lookup(ifp, igmp->igmp_group); if (inm != NULL) { - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; igi = inm->inm_igi; KASSERT(igi != NULL, ("%s: no igi for ifp %p", __func__, ifp)); @@ -1425,26 +1431,29 @@ out_locked: return (0); } -void -igmp_input(struct mbuf *m, int off) +int +igmp_input(struct mbuf **mp, int *offp, int proto) { int iphlen; struct ifnet *ifp; struct igmp *igmp; struct ip *ip; + struct mbuf *m; int igmplen; int minlen; int queryver; - CTR3(KTR_IGMPV3, "%s: called w/mbuf (%p,%d)", __func__, m, off); + CTR3(KTR_IGMPV3, "%s: called w/mbuf (%p,%d)", __func__, *mp, *offp); + m = *mp; ifp = m->m_pkthdr.rcvif; + *mp = NULL; IGMPSTAT_INC(igps_rcv_total); ip = mtod(m, struct ip *); - iphlen = off; - igmplen = ip->ip_len; + iphlen = *offp; + igmplen = ntohs(ip->ip_len) - iphlen; /* * Validate lengths. @@ -1452,7 +1461,7 @@ igmp_input(struct mbuf *m, int off) if (igmplen < IGMP_MINLEN) { IGMPSTAT_INC(igps_rcv_tooshort); m_freem(m); - return; + return (IPPROTO_DONE); } /* @@ -1464,10 +1473,10 @@ igmp_input(struct mbuf *m, int off) minlen += IGMP_V3_QUERY_MINLEN; else minlen += IGMP_MINLEN; - if ((m->m_flags & M_EXT || m->m_len < minlen) && - (m = m_pullup(m, minlen)) == 0) { + if ((!M_WRITABLE(m) || m->m_len < minlen) && + (m = m_pullup(m, minlen)) == NULL) { IGMPSTAT_INC(igps_rcv_tooshort); - return; + return (IPPROTO_DONE); } ip = mtod(m, struct ip *); @@ -1480,7 +1489,7 @@ igmp_input(struct mbuf *m, int off) if (in_cksum(m, igmplen)) { IGMPSTAT_INC(igps_rcv_badsum); m_freem(m); - return; + return (IPPROTO_DONE); } m->m_data -= iphlen; m->m_len += iphlen; @@ -1493,7 +1502,7 @@ igmp_input(struct mbuf *m, int off) if (igmp->igmp_type != IGMP_DVMRP && ip->ip_ttl != 1) { IGMPSTAT_INC(igps_rcv_badttl); m_freem(m); - return; + return (IPPROTO_DONE); } switch (igmp->igmp_type) { @@ -1508,7 +1517,7 @@ igmp_input(struct mbuf *m, int off) } else { IGMPSTAT_INC(igps_rcv_tooshort); m_freem(m); - return; + return (IPPROTO_DONE); } switch (queryver) { @@ -1518,7 +1527,7 @@ igmp_input(struct mbuf *m, int off) break; if (igmp_input_v1_query(ifp, ip, igmp) != 0) { m_freem(m); - return; + return (IPPROTO_DONE); } break; @@ -1528,7 +1537,7 @@ igmp_input(struct mbuf *m, int off) break; if (igmp_input_v2_query(ifp, ip, igmp) != 0) { m_freem(m); - return; + return (IPPROTO_DONE); } break; @@ -1546,25 +1555,25 @@ igmp_input(struct mbuf *m, int off) if (nsrc * sizeof(in_addr_t) > UINT16_MAX - iphlen - IGMP_V3_QUERY_MINLEN) { IGMPSTAT_INC(igps_rcv_tooshort); - return; + return (IPPROTO_DONE); } /* * m_pullup() may modify m, so pullup in * this scope. */ igmpv3len = iphlen + IGMP_V3_QUERY_MINLEN + - sizeof(struct in_addr) * nsrc; - if ((m->m_flags & M_EXT || + sizeof(struct in_addr) * nsrc; + if ((!M_WRITABLE(m) || m->m_len < igmpv3len) && (m = m_pullup(m, igmpv3len)) == NULL) { IGMPSTAT_INC(igps_rcv_tooshort); - return; + return (IPPROTO_DONE); } igmpv3 = (struct igmpv3 *)(mtod(m, uint8_t *) + iphlen); if (igmp_input_v3_query(ifp, ip, igmpv3) != 0) { m_freem(m); - return; + return (IPPROTO_DONE); } } break; @@ -1576,7 +1585,7 @@ igmp_input(struct mbuf *m, int off) break; if (igmp_input_v1_report(ifp, ip, igmp) != 0) { m_freem(m); - return; + return (IPPROTO_DONE); } break; @@ -1587,7 +1596,7 @@ igmp_input(struct mbuf *m, int off) IGMPSTAT_INC(igps_rcv_nora); if (igmp_input_v2_report(ifp, ip, igmp) != 0) { m_freem(m); - return; + return (IPPROTO_DONE); } break; @@ -1608,7 +1617,8 @@ igmp_input(struct mbuf *m, int off) * Pass all valid IGMP packets up to any process(es) listening on a * raw IGMP socket. */ - rip_input(m, off); + *mp = m; + return (rip_input(mp, offp, proto)); } @@ -1639,10 +1649,10 @@ igmp_fasttimo(void) static void igmp_fasttimo_vnet(void) { - struct ifqueue scq; /* State-change packets */ - struct ifqueue qrq; /* Query response packets */ + struct mbufq scq; /* State-change packets */ + struct mbufq qrq; /* Query response packets */ struct ifnet *ifp; - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; struct ifmultiaddr *ifma; struct in_multi *inm; int loop, uri_fasthz; @@ -1701,12 +1711,8 @@ igmp_fasttimo_vnet(void) loop = (igi->igi_flags & IGIF_LOOPBACK) ? 1 : 0; uri_fasthz = IGMP_RANDOM_DELAY(igi->igi_uri * PR_FASTHZ); - - memset(&qrq, 0, sizeof(struct ifqueue)); - IFQ_SET_MAXLEN(&qrq, IGMP_MAX_G_GS_PACKETS); - - memset(&scq, 0, sizeof(struct ifqueue)); - IFQ_SET_MAXLEN(&scq, IGMP_MAX_STATE_CHANGE_PACKETS); + mbufq_init(&qrq, IGMP_MAX_G_GS_PACKETS); + mbufq_init(&scq, IGMP_MAX_STATE_CHANGE_PACKETS); } IF_ADDR_RLOCK(ifp); @@ -1804,8 +1810,8 @@ igmp_v1v2_process_group_timer(struct in_multi *inm, const int version) * Note: Unlocked read from igi. */ static void -igmp_v3_process_group_timers(struct igmp_ifinfo *igi, - struct ifqueue *qrq, struct ifqueue *scq, +igmp_v3_process_group_timers(struct igmp_ifsoftc *igi, + struct mbufq *qrq, struct mbufq *scq, struct in_multi *inm, const int uri_fasthz) { int query_response_timer_expired; @@ -1951,7 +1957,7 @@ igmp_v3_suppress_group_record(struct in_multi *inm) * as per Section 7.2.1. */ static void -igmp_set_version(struct igmp_ifinfo *igi, const int version) +igmp_set_version(struct igmp_ifsoftc *igi, const int version) { int old_version_timer; @@ -2000,7 +2006,7 @@ igmp_set_version(struct igmp_ifinfo *igi, const int version) * query processing. */ static void -igmp_v3_cancel_link_timers(struct igmp_ifinfo *igi) +igmp_v3_cancel_link_timers(struct igmp_ifsoftc *igi) { struct ifmultiaddr *ifma; struct ifnet *ifp; @@ -2067,7 +2073,7 @@ igmp_v3_cancel_link_timers(struct igmp_ifinfo *igi) */ inm->inm_sctimer = 0; inm->inm_timer = 0; - _IF_DRAIN(&inm->inm_scq); + mbufq_drain(&inm->inm_scq); } IF_ADDR_RUNLOCK(ifp); SLIST_FOREACH_SAFE(inm, &igi->igi_relinmhead, inm_nrele, tinm) { @@ -2081,7 +2087,7 @@ igmp_v3_cancel_link_timers(struct igmp_ifinfo *igi) * See Section 7.2.1 of RFC 3376. */ static void -igmp_v1v2_process_querier_timers(struct igmp_ifinfo *igi) +igmp_v1v2_process_querier_timers(struct igmp_ifsoftc *igi) { IGMP_LOCK_ASSERT(); @@ -2122,6 +2128,7 @@ igmp_v1v2_process_querier_timers(struct igmp_ifinfo *igi) __func__, igi->igi_version, IGMP_VERSION_2, igi->igi_ifp, igi->igi_ifp->if_xname); igi->igi_version = IGMP_VERSION_2; + igmp_v3_cancel_link_timers(igi); } } } else if (igi->igi_v1_timer > 0) { @@ -2176,7 +2183,7 @@ igmp_slowtimo(void) static void igmp_slowtimo_vnet(void) { - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; IGMP_LOCK(); @@ -2204,10 +2211,10 @@ igmp_v1v2_queue_report(struct in_multi *inm, const int type) ifp = inm->inm_ifp; - MGETHDR(m, M_DONTWAIT, MT_DATA); + m = m_gethdr(M_NOWAIT, MT_DATA); if (m == NULL) return (ENOMEM); - MH_ALIGN(m, sizeof(struct ip) + sizeof(struct igmp)); + M_ALIGN(m, sizeof(struct ip) + sizeof(struct igmp)); m->m_pkthdr.len = sizeof(struct ip) + sizeof(struct igmp); @@ -2226,7 +2233,7 @@ igmp_v1v2_queue_report(struct in_multi *inm, const int type) ip = mtod(m, struct ip *); ip->ip_tos = 0; - ip->ip_len = sizeof(struct ip) + sizeof(struct igmp); + ip->ip_len = htons(sizeof(struct ip) + sizeof(struct igmp)); ip->ip_off = 0; ip->ip_p = IPPROTO_IGMP; ip->ip_src.s_addr = INADDR_ANY; @@ -2272,7 +2279,7 @@ igmp_v1v2_queue_report(struct in_multi *inm, const int type) int igmp_change_state(struct in_multi *inm) { - struct igmp_ifinfo *igi; + struct igmp_ifsoftc *igi; struct ifnet *ifp; int error; @@ -2295,7 +2302,7 @@ igmp_change_state(struct in_multi *inm) IGMP_LOCK(); igi = ((struct in_ifinfo *)ifp->if_afdata[AF_INET])->ii_igmp; - KASSERT(igi != NULL, ("%s: no igmp_ifinfo for ifp %p", __func__, ifp)); + KASSERT(igi != NULL, ("%s: no igmp_ifsoftc for ifp %p", __func__, ifp)); /* * If we detect a state transition to or from MCAST_UNDEFINED @@ -2336,10 +2343,10 @@ out_locked: * initial state of the membership. */ static int -igmp_initial_join(struct in_multi *inm, struct igmp_ifinfo *igi) +igmp_initial_join(struct in_multi *inm, struct igmp_ifsoftc *igi) { struct ifnet *ifp; - struct ifqueue *ifq; + struct mbufq *mq; int error, retval, syncstates; CTR4(KTR_IGMPV3, "%s: initial join %s on ifp %p(%s)", @@ -2413,9 +2420,9 @@ igmp_initial_join(struct in_multi *inm, struct igmp_ifinfo *igi) * Don't kick the timers if there is nothing to do, * or if an error occurred. */ - ifq = &inm->inm_scq; - _IF_DRAIN(ifq); - retval = igmp_v3_enqueue_group_record(ifq, inm, 1, + mq = &inm->inm_scq; + mbufq_drain(mq); + retval = igmp_v3_enqueue_group_record(mq, inm, 1, 0, 0); CTR2(KTR_IGMPV3, "%s: enqueue record = %d", __func__, retval); @@ -2464,7 +2471,7 @@ igmp_initial_join(struct in_multi *inm, struct igmp_ifinfo *igi) * Issue an intermediate state change during the IGMP life-cycle. */ static int -igmp_handle_state_change(struct in_multi *inm, struct igmp_ifinfo *igi) +igmp_handle_state_change(struct in_multi *inm, struct igmp_ifsoftc *igi) { struct ifnet *ifp; int retval; @@ -2495,7 +2502,7 @@ igmp_handle_state_change(struct in_multi *inm, struct igmp_ifinfo *igi) return (0); } - _IF_DRAIN(&inm->inm_scq); + mbufq_drain(&inm->inm_scq); retval = igmp_v3_enqueue_group_record(&inm->inm_scq, inm, 1, 0, 0); CTR2(KTR_IGMPV3, "%s: enqueue record = %d", __func__, retval); @@ -2523,7 +2530,7 @@ igmp_handle_state_change(struct in_multi *inm, struct igmp_ifinfo *igi) * to INCLUDE {} for immediate transmission. */ static void -igmp_final_leave(struct in_multi *inm, struct igmp_ifinfo *igi) +igmp_final_leave(struct in_multi *inm, struct igmp_ifsoftc *igi) { int syncstates; @@ -2564,7 +2571,7 @@ igmp_final_leave(struct in_multi *inm, struct igmp_ifinfo *igi) * TO_IN {} to be sent on the next fast timeout, * giving us an opportunity to merge reports. */ - _IF_DRAIN(&inm->inm_scq); + mbufq_drain(&inm->inm_scq); inm->inm_timer = 0; if (igi->igi_flags & IGIF_LOOPBACK) { inm->inm_scrv = 1; @@ -2642,7 +2649,7 @@ igmp_final_leave(struct in_multi *inm, struct igmp_ifinfo *igi) * no record(s) were appended. */ static int -igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, +igmp_v3_enqueue_group_record(struct mbufq *mq, struct in_multi *inm, const int is_state_change, const int is_group_query, const int is_source_query) { @@ -2732,7 +2739,7 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, * Generate the filter list changes using a separate function. */ if (is_filter_list_change) - return (igmp_v3_enqueue_filter_change(ifq, inm)); + return (igmp_v3_enqueue_filter_change(mq, inm)); if (type == IGMP_DO_NOTHING) { CTR3(KTR_IGMPV3, "%s: nothing to do for %s/%s", @@ -2762,7 +2769,7 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, * Note: Group records for G/GSR query responses MUST be sent * in their own packet. */ - m0 = ifq->ifq_tail; + m0 = mbufq_last(mq); if (!is_group_query && m0 != NULL && (m0->m_pkthdr.PH_vt.vt_nrecs + 1 <= IGMP_V3_REPORT_MAXRECS) && @@ -2773,7 +2780,7 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, m = m0; CTR1(KTR_IGMPV3, "%s: use existing packet", __func__); } else { - if (_IF_QFULL(ifq)) { + if (mbufq_full(mq)) { CTR1(KTR_IGMPV3, "%s: outbound queue full", __func__); return (-ENOMEM); } @@ -2781,14 +2788,14 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, m0srcs = (ifp->if_mtu - IGMP_LEADINGSPACE - sizeof(struct igmp_grouprec)) / sizeof(in_addr_t); if (!is_state_change && !is_group_query) { - m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m) m->m_data += IGMP_LEADINGSPACE; } if (m == NULL) { - m = m_gethdr(M_DONTWAIT, MT_DATA); + m = m_gethdr(M_NOWAIT, MT_DATA); if (m) - MH_ALIGN(m, IGMP_LEADINGSPACE); + M_ALIGN(m, IGMP_LEADINGSPACE); } if (m == NULL) return (-ENOMEM); @@ -2886,7 +2893,7 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, if (m != m0) { CTR1(KTR_IGMPV3, "%s: enqueueing first packet", __func__); m->m_pkthdr.PH_vt.vt_nrecs = 1; - _IF_ENQUEUE(ifq, m); + mbufq_enqueue(mq, m); } else m->m_pkthdr.PH_vt.vt_nrecs++; @@ -2902,17 +2909,17 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, * Always try for a cluster first. */ while (nims != NULL) { - if (_IF_QFULL(ifq)) { + if (mbufq_full(mq)) { CTR1(KTR_IGMPV3, "%s: outbound queue full", __func__); return (-ENOMEM); } - m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m) m->m_data += IGMP_LEADINGSPACE; if (m == NULL) { - m = m_gethdr(M_DONTWAIT, MT_DATA); + m = m_gethdr(M_NOWAIT, MT_DATA); if (m) - MH_ALIGN(m, IGMP_LEADINGSPACE); + M_ALIGN(m, IGMP_LEADINGSPACE); } if (m == NULL) return (-ENOMEM); @@ -2965,7 +2972,7 @@ igmp_v3_enqueue_group_record(struct ifqueue *ifq, struct in_multi *inm, nbytes += (msrcs * sizeof(in_addr_t)); CTR1(KTR_IGMPV3, "%s: enqueueing next packet", __func__); - _IF_ENQUEUE(ifq, m); + mbufq_enqueue(mq, m); } return (nbytes); @@ -3005,7 +3012,7 @@ typedef enum { * no record(s) were appended. */ static int -igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm) +igmp_v3_enqueue_filter_change(struct mbufq *mq, struct in_multi *inm) { static const int MINRECLEN = sizeof(struct igmp_grouprec) + sizeof(in_addr_t); @@ -3049,7 +3056,7 @@ igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm) */ while (drt != REC_FULL) { do { - m0 = ifq->ifq_tail; + m0 = mbufq_last(mq); if (m0 != NULL && (m0->m_pkthdr.PH_vt.vt_nrecs + 1 <= IGMP_V3_REPORT_MAXRECS) && @@ -3062,13 +3069,13 @@ igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm) CTR1(KTR_IGMPV3, "%s: use previous packet", __func__); } else { - m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); + m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m) m->m_data += IGMP_LEADINGSPACE; if (m == NULL) { - m = m_gethdr(M_DONTWAIT, MT_DATA); + m = m_gethdr(M_NOWAIT, MT_DATA); if (m) - MH_ALIGN(m, IGMP_LEADINGSPACE); + M_ALIGN(m, IGMP_LEADINGSPACE); } if (m == NULL) { CTR1(KTR_IGMPV3, @@ -3196,7 +3203,7 @@ igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm) */ m->m_pkthdr.PH_vt.vt_nrecs++; if (m != m0) - _IF_ENQUEUE(ifq, m); + mbufq_enqueue(mq, m); nbytes += npbytes; } while (nims != NULL); drt |= crt; @@ -3210,9 +3217,9 @@ igmp_v3_enqueue_filter_change(struct ifqueue *ifq, struct in_multi *inm) } static int -igmp_v3_merge_state_changes(struct in_multi *inm, struct ifqueue *ifscq) +igmp_v3_merge_state_changes(struct in_multi *inm, struct mbufq *scq) { - struct ifqueue *gq; + struct mbufq *gq; struct mbuf *m; /* pending state-change */ struct mbuf *m0; /* copy of pending state-change */ struct mbuf *mt; /* last state-change in packet */ @@ -3235,13 +3242,13 @@ igmp_v3_merge_state_changes(struct in_multi *inm, struct ifqueue *ifscq) gq = &inm->inm_scq; #ifdef KTR - if (gq->ifq_head == NULL) { + if (mbufq_first(gq) == NULL) { CTR2(KTR_IGMPV3, "%s: WARNING: queue for inm %p is empty", __func__, inm); } #endif - m = gq->ifq_head; + m = mbufq_first(gq); while (m != NULL) { /* * Only merge the report into the current packet if @@ -3252,7 +3259,7 @@ igmp_v3_merge_state_changes(struct in_multi *inm, struct ifqueue *ifscq) * allocated clusters. */ domerge = 0; - mt = ifscq->ifq_tail; + mt = mbufq_last(scq); if (mt != NULL) { recslen = m_length(m, NULL); @@ -3264,7 +3271,7 @@ igmp_v3_merge_state_changes(struct in_multi *inm, struct ifqueue *ifscq) domerge = 1; } - if (!domerge && _IF_QFULL(gq)) { + if (!domerge && mbufq_full(gq)) { CTR2(KTR_IGMPV3, "%s: outbound queue full, skipping whole packet %p", __func__, m); @@ -3277,7 +3284,7 @@ igmp_v3_merge_state_changes(struct in_multi *inm, struct ifqueue *ifscq) if (!docopy) { CTR2(KTR_IGMPV3, "%s: dequeueing %p", __func__, m); - _IF_DEQUEUE(gq, m0); + m0 = mbufq_dequeue(gq); m = m0->m_nextpkt; } else { CTR2(KTR_IGMPV3, "%s: copying %p", __func__, m); @@ -3289,13 +3296,13 @@ igmp_v3_merge_state_changes(struct in_multi *inm, struct ifqueue *ifscq) } if (!domerge) { - CTR3(KTR_IGMPV3, "%s: queueing %p to ifscq %p)", - __func__, m0, ifscq); - _IF_ENQUEUE(ifscq, m0); + CTR3(KTR_IGMPV3, "%s: queueing %p to scq %p)", + __func__, m0, scq); + mbufq_enqueue(scq, m0); } else { struct mbuf *mtl; /* last mbuf of packet mt */ - CTR3(KTR_IGMPV3, "%s: merging %p with ifscq tail %p)", + CTR3(KTR_IGMPV3, "%s: merging %p with scq tail %p)", __func__, m0, mt); mtl = m_last(mt); @@ -3315,7 +3322,7 @@ igmp_v3_merge_state_changes(struct in_multi *inm, struct ifqueue *ifscq) * Respond to a pending IGMPv3 General Query. */ static void -igmp_v3_dispatch_general_query(struct igmp_ifinfo *igi) +igmp_v3_dispatch_general_query(struct igmp_ifsoftc *igi) { struct ifmultiaddr *ifma; struct ifnet *ifp; @@ -3328,6 +3335,15 @@ igmp_v3_dispatch_general_query(struct igmp_ifinfo *igi) KASSERT(igi->igi_version == IGMP_VERSION_3, ("%s: called when version %d", __func__, igi->igi_version)); + /* + * Check that there are some packets queued. If so, send them first. + * For large number of groups the reply to general query can take + * many packets, we should finish sending them before starting of + * queuing the new reply. + */ + if (mbufq_len(&igi->igi_gq) != 0) + goto send; + ifp = igi->igi_ifp; IF_ADDR_RLOCK(ifp); @@ -3363,13 +3379,14 @@ igmp_v3_dispatch_general_query(struct igmp_ifinfo *igi) } IF_ADDR_RUNLOCK(ifp); +send: loop = (igi->igi_flags & IGIF_LOOPBACK) ? 1 : 0; igmp_dispatch_queue(&igi->igi_gq, IGMP_MAX_RESPONSE_BURST, loop); /* * Slew transmission of bursts over 500ms intervals. */ - if (igi->igi_gq.ifq_head != NULL) { + if (mbufq_first(&igi->igi_gq) != NULL) { igi->igi_v3_timer = 1 + IGMP_RANDOM_DELAY( IGMP_RESPONSE_BURST_INTERVAL); V_interface_timers_running = 1; @@ -3403,7 +3420,7 @@ igmp_intr(struct mbuf *m) * indexes to guard against interface detach, they are * unique to each VIMAGE and must be retrieved. */ - CURVNET_SET((struct vnet *)(m->m_pkthdr.header)); + CURVNET_SET((struct vnet *)(m->m_pkthdr.PH_loc.ptr)); ifindex = igmp_restore_context(m); /* @@ -3450,7 +3467,7 @@ igmp_intr(struct mbuf *m) } igmp_scrub_context(m0); - m->m_flags &= ~(M_PROTOFLAGS); + m_clrprotoflags(m); m0->m_pkthdr.rcvif = V_loif; #ifdef MAC mac_netinet_igmp_send(ifp, m0); @@ -3485,6 +3502,7 @@ out: static struct mbuf * igmp_v3_encap_report(struct ifnet *ifp, struct mbuf *m) { + struct rm_priotracker in_ifa_tracker; struct igmp_report *igmp; struct ip *ip; int hdrlen, igmpreclen; @@ -3498,7 +3516,7 @@ igmp_v3_encap_report(struct ifnet *ifp, struct mbuf *m) if (m->m_flags & M_IGMPV3_HDR) { igmpreclen -= hdrlen; } else { - M_PREPEND(m, hdrlen, M_DONTWAIT); + M_PREPEND(m, hdrlen, M_NOWAIT); if (m == NULL) return (NULL); m->m_flags |= M_IGMPV3_HDR; @@ -3523,8 +3541,8 @@ igmp_v3_encap_report(struct ifnet *ifp, struct mbuf *m) ip = mtod(m, struct ip *); ip->ip_tos = IPTOS_PREC_INTERNETCONTROL; - ip->ip_len = hdrlen + igmpreclen; - ip->ip_off = IP_DF; + ip->ip_len = htons(hdrlen + igmpreclen); + ip->ip_off = htons(IP_DF); ip->ip_p = IPPROTO_IGMP; ip->ip_sum = 0; @@ -3533,7 +3551,7 @@ igmp_v3_encap_report(struct ifnet *ifp, struct mbuf *m) if (m->m_flags & M_IGMP_LOOP) { struct in_ifaddr *ia; - IFP_TO_IA(ifp, ia); + IFP_TO_IA(ifp, ia, &in_ifa_tracker); if (ia != NULL) { ip->ip_src = ia->ia_addr.sin_addr; ifa_free(&ia->ia_ifa); @@ -3576,70 +3594,82 @@ igmp_rec_type_to_str(const int type) } #endif +#ifdef VIMAGE static void -igmp_init(void *unused __unused) +vnet_igmp_init(const void *unused __unused) { - CTR1(KTR_IGMPV3, "%s: initializing", __func__); - - IGMP_LOCK_INIT(); - - m_raopt = igmp_ra_alloc(); - - netisr_register(&igmp_nh); + netisr_register_vnet(&igmp_nh); } -SYSINIT(igmp_init, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, igmp_init, NULL); +VNET_SYSINIT(vnet_igmp_init, SI_SUB_PROTO_MC, SI_ORDER_ANY, + vnet_igmp_init, NULL); static void -igmp_uninit(void *unused __unused) +vnet_igmp_uninit(const void *unused __unused) { + /* This can happen when we shutdown the entire network stack. */ CTR1(KTR_IGMPV3, "%s: tearing down", __func__); - netisr_unregister(&igmp_nh); - - m_free(m_raopt); - m_raopt = NULL; - - IGMP_LOCK_DESTROY(); + netisr_unregister_vnet(&igmp_nh); } -SYSUNINIT(igmp_uninit, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, igmp_uninit, NULL); +VNET_SYSUNINIT(vnet_igmp_uninit, SI_SUB_PROTO_MC, SI_ORDER_ANY, + vnet_igmp_uninit, NULL); +#endif -static void -vnet_igmp_init(const void *unused __unused) +#ifdef DDB +DB_SHOW_COMMAND(igi_list, db_show_igi_list) { + struct igmp_ifsoftc *igi, *tigi; + LIST_HEAD(_igi_list, igmp_ifsoftc) *igi_head; - CTR1(KTR_IGMPV3, "%s: initializing", __func__); - - LIST_INIT(&V_igi_head); -} -VNET_SYSINIT(vnet_igmp_init, SI_SUB_PSEUDO, SI_ORDER_ANY, vnet_igmp_init, - NULL); - -static void -vnet_igmp_uninit(const void *unused __unused) -{ - - CTR1(KTR_IGMPV3, "%s: tearing down", __func__); - - KASSERT(LIST_EMPTY(&V_igi_head), - ("%s: igi list not empty; ifnets not detached?", __func__)); + if (!have_addr) { + db_printf("usage: show igi_list \n"); + return; + } + igi_head = (struct _igi_list *)addr; + + LIST_FOREACH_SAFE(igi, igi_head, igi_link, tigi) { + db_printf("igmp_ifsoftc %p:\n", igi); + db_printf(" ifp %p\n", igi->igi_ifp); + db_printf(" version %u\n", igi->igi_version); + db_printf(" v1_timer %u\n", igi->igi_v1_timer); + db_printf(" v2_timer %u\n", igi->igi_v2_timer); + db_printf(" v3_timer %u\n", igi->igi_v3_timer); + db_printf(" flags %#x\n", igi->igi_flags); + db_printf(" rv %u\n", igi->igi_rv); + db_printf(" qi %u\n", igi->igi_qi); + db_printf(" qri %u\n", igi->igi_qri); + db_printf(" uri %u\n", igi->igi_uri); + /* SLIST_HEAD(,in_multi) igi_relinmhead */ + /* struct mbufq igi_gq; */ + db_printf("\n"); + } } -VNET_SYSUNINIT(vnet_igmp_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY, - vnet_igmp_uninit, NULL); +#endif static int igmp_modevent(module_t mod, int type, void *unused __unused) { - switch (type) { - case MOD_LOAD: - case MOD_UNLOAD: - break; - default: - return (EOPNOTSUPP); - } - return (0); + switch (type) { + case MOD_LOAD: + CTR1(KTR_IGMPV3, "%s: initializing", __func__); + IGMP_LOCK_INIT(); + m_raopt = igmp_ra_alloc(); + netisr_register(&igmp_nh); + break; + case MOD_UNLOAD: + CTR1(KTR_IGMPV3, "%s: tearing down", __func__); + netisr_unregister(&igmp_nh); + m_free(m_raopt); + m_raopt = NULL; + IGMP_LOCK_DESTROY(); + break; + default: + return (EOPNOTSUPP); + } + return (0); } static moduledata_t igmp_mod = { @@ -3647,4 +3677,4 @@ static moduledata_t igmp_mod = { igmp_modevent, 0 }; -DECLARE_MODULE(igmp, igmp_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +DECLARE_MODULE(igmp, igmp_mod, SI_SUB_PROTO_MC, SI_ORDER_MIDDLE); -- cgit v1.2.3