Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/netinet Make IGMP and multicast group management code MP...
details: https://anonhg.NetBSD.org/src/rev/0f182291c4a0
branches: trunk
changeset: 329579:0f182291c4a0
user: rmind <rmind%NetBSD.org@localhost>
date: Thu May 29 23:02:48 2014 +0000
description:
Make IGMP and multicast group management code MP-safe. Use a read-write
lock to protect the hash table of multicast address records; also, make it
private and eliminate some macros. In the long term, the lookup path ought
to be optimised.
diffstat:
sys/netinet/igmp.c | 231 ++++++++++++++++++++++++++------------------
sys/netinet/igmp.h | 10 +-
sys/netinet/igmp_var.h | 4 +-
sys/netinet/in.c | 246 ++++++++++++++++++++++++++++++++++-------------
sys/netinet/in_var.h | 83 +++------------
sys/netinet/ip_carp.c | 8 +-
sys/netinet/ip_input.c | 8 +-
sys/netinet/ip_output.c | 11 +-
sys/netinet/ip_var.h | 19 ++-
9 files changed, 362 insertions(+), 258 deletions(-)
diffs (truncated from 1166 to 300 lines):
diff -r 1cc3205892b9 -r 0f182291c4a0 sys/netinet/igmp.c
--- a/sys/netinet/igmp.c Thu May 29 22:05:24 2014 +0000
+++ b/sys/netinet/igmp.c Thu May 29 23:02:48 2014 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: igmp.c,v 1.54 2014/02/25 18:30:12 pooka Exp $ */
+/* $NetBSD: igmp.c,v 1.55 2014/05/29 23:02:48 rmind Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@@ -40,7 +40,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.54 2014/02/25 18:30:12 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.55 2014/05/29 23:02:48 rmind Exp $");
#include "opt_mrouting.h"
@@ -50,6 +50,7 @@
#include <sys/socketvar.h>
#include <sys/protosw.h>
#include <sys/systm.h>
+#include <sys/cprng.h>
#include <sys/sysctl.h>
#include <net/if.h>
@@ -64,83 +65,107 @@
#include <netinet/igmp.h>
#include <netinet/igmp_var.h>
-#define IP_MULTICASTOPTS 0
+/*
+ * Per-interface router version information.
+ */
+typedef struct router_info {
+ LIST_ENTRY(router_info) rti_link;
+ ifnet_t * rti_ifp;
+ int rti_type; /* type of router on this interface */
+ int rti_age; /* time since last v1 query */
+} router_info_t;
-static struct pool igmp_rti_pool;
-
-static percpu_t *igmpstat_percpu;
+/*
+ * The router-info list and the timer flag are protected by in_multilock.
+ *
+ * Lock order:
+ *
+ * softnet_lock ->
+ * in_multilock
+ */
+static struct pool igmp_rti_pool __cacheline_aligned;
+static LIST_HEAD(, router_info) rti_head __cacheline_aligned;
+static int igmp_timers_on __cacheline_aligned;
+static percpu_t * igmpstat_percpu __read_mostly;
#define IGMP_STATINC(x) _NET_STATINC(igmpstat_percpu, x)
-int igmp_timers_are_running;
-static LIST_HEAD(, router_info) rti_head = LIST_HEAD_INITIALIZER(rti_head);
+static void igmp_sendpkt(struct in_multi *, int);
+static int rti_fill(struct in_multi *);
+static router_info_t * rti_find(struct ifnet *);
+static void rti_delete(struct ifnet *);
+static void sysctl_net_inet_igmp_setup(struct sysctllog **);
-void igmp_sendpkt(struct in_multi *, int);
-static int rti_fill(struct in_multi *);
-static struct router_info *rti_find(struct ifnet *);
-static void rti_delete(struct ifnet *);
-
-static void sysctl_net_inet_igmp_setup(struct sysctllog **);
-
+/*
+ * rti_fill: associate router information with the given multicast group;
+ * if there is no router information for the interface, then create it.
+ */
static int
rti_fill(struct in_multi *inm)
{
- struct router_info *rti;
+ router_info_t *rti;
- /* this function is called at splsoftnet() */
+ KASSERT(in_multi_lock_held());
+
LIST_FOREACH(rti, &rti_head, rti_link) {
if (rti->rti_ifp == inm->inm_ifp) {
inm->inm_rti = rti;
- if (rti->rti_type == IGMP_v1_ROUTER)
- return (IGMP_v1_HOST_MEMBERSHIP_REPORT);
- else
- return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
+ return rti->rti_type == IGMP_v1_ROUTER ?
+ IGMP_v1_HOST_MEMBERSHIP_REPORT :
+ IGMP_v2_HOST_MEMBERSHIP_REPORT;
}
}
-
rti = pool_get(&igmp_rti_pool, PR_NOWAIT);
- if (rti == NULL)
+ if (rti == NULL) {
return 0;
+ }
rti->rti_ifp = inm->inm_ifp;
rti->rti_type = IGMP_v2_ROUTER;
LIST_INSERT_HEAD(&rti_head, rti, rti_link);
inm->inm_rti = rti;
- return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
+ return IGMP_v2_HOST_MEMBERSHIP_REPORT;
}
-static struct router_info *
-rti_find(struct ifnet *ifp)
+/*
+ * rti_find: lookup or create router information for the given interface.
+ */
+static router_info_t *
+rti_find(ifnet_t *ifp)
{
- struct router_info *rti;
- int s = splsoftnet();
+ router_info_t *rti;
+
+ KASSERT(in_multi_lock_held());
LIST_FOREACH(rti, &rti_head, rti_link) {
if (rti->rti_ifp == ifp)
- return (rti);
+ return rti;
}
-
rti = pool_get(&igmp_rti_pool, PR_NOWAIT);
if (rti == NULL) {
- splx(s);
return NULL;
}
rti->rti_ifp = ifp;
rti->rti_type = IGMP_v2_ROUTER;
LIST_INSERT_HEAD(&rti_head, rti, rti_link);
- splx(s);
- return (rti);
+ return rti;
}
+/*
+ * rti_delete: remove and free the router information entry for the
+ * given interface.
+ */
static void
-rti_delete(struct ifnet *ifp) /* MUST be called at splsoftnet */
+rti_delete(ifnet_t *ifp)
{
- struct router_info *rti;
+ router_info_t *rti;
+
+ KASSERT(in_multi_lock_held());
LIST_FOREACH(rti, &rti_head, rti_link) {
if (rti->rti_ifp == ifp) {
LIST_REMOVE(rti, rti_link);
pool_put(&igmp_rti_pool, rti);
- return;
+ break;
}
}
}
@@ -148,29 +173,24 @@
void
igmp_init(void)
{
-
- sysctl_net_inet_igmp_setup(NULL);
- pool_init(&igmp_rti_pool, sizeof(struct router_info), 0, 0, 0,
+ pool_init(&igmp_rti_pool, sizeof(router_info_t), 0, 0, 0,
"igmppl", NULL, IPL_SOFTNET);
igmpstat_percpu = percpu_alloc(sizeof(uint64_t) * IGMP_NSTATS);
+ sysctl_net_inet_igmp_setup(NULL);
+ LIST_INIT(&rti_head);
}
void
igmp_input(struct mbuf *m, ...)
{
- int proto;
- int iphlen;
- struct ifnet *ifp = m->m_pkthdr.rcvif;
+ ifnet_t *ifp = m->m_pkthdr.rcvif;
struct ip *ip = mtod(m, struct ip *);
struct igmp *igmp;
- u_int minlen;
+ u_int minlen, timer;
struct in_multi *inm;
- struct in_multistep step;
- struct router_info *rti;
struct in_ifaddr *ia;
- u_int timer;
+ int proto, ip_len, iphlen;
va_list ap;
- u_int16_t ip_len;
va_start(ap, m);
iphlen = va_arg(ap, int);
@@ -222,11 +242,8 @@
break;
if (igmp->igmp_code == 0) {
- rti = rti_find(ifp);
- if (rti == NULL)
- break;
- rti->rti_type = IGMP_v1_ROUTER;
- rti->rti_age = 0;
+ struct in_multistep step;
+ router_info_t *rti;
if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) {
IGMP_STATINC(IGMP_STAT_RCV_BADQUERIES);
@@ -234,13 +251,23 @@
return;
}
+ in_multi_lock(RW_WRITER);
+ rti = rti_find(ifp);
+ if (rti == NULL) {
+ in_multi_unlock();
+ break;
+ }
+ rti->rti_type = IGMP_v1_ROUTER;
+ rti->rti_age = 0;
+
/*
* Start the timers in all of our membership records
* for the interface on which the query arrived,
* except those that are already running and those
* that belong to a "local" group (224.0.0.X).
*/
- IN_FIRST_MULTI(step, inm);
+
+ inm = in_first_multi(&step);
while (inm != NULL) {
if (inm->inm_ifp == ifp &&
inm->inm_timer == 0 &&
@@ -248,11 +275,14 @@
inm->inm_state = IGMP_DELAYING_MEMBER;
inm->inm_timer = IGMP_RANDOM_DELAY(
IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
- igmp_timers_are_running = 1;
+ igmp_timers_on = true;
}
- IN_NEXT_MULTI(step, inm);
+ inm = in_next_multi(&step);
}
+ in_multi_unlock();
} else {
+ struct in_multistep step;
+
if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
IGMP_STATINC(IGMP_STAT_RCV_BADQUERIES);
m_freem(m);
@@ -261,7 +291,7 @@
timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
if (timer == 0)
- timer =1;
+ timer = 1;
/*
* Start the timers in all of our membership records
@@ -271,7 +301,8 @@
* timers already running, check if they need to be
* reset.
*/
- IN_FIRST_MULTI(step, inm);
+ in_multi_lock(RW_WRITER);
+ inm = in_first_multi(&step);
while (inm != NULL) {
if (inm->inm_ifp == ifp &&
!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
@@ -289,7 +320,7 @@
IGMP_DELAYING_MEMBER;
inm->inm_timer =
IGMP_RANDOM_DELAY(timer);
- igmp_timers_are_running = 1;
+ igmp_timers_on = true;
break;
case IGMP_SLEEPING_MEMBER:
inm->inm_state =
@@ -297,8 +328,9 @@
break;
}
}
- IN_NEXT_MULTI(step, inm);
+ inm = in_next_multi(&step);
}
+ in_multi_unlock();
}
break;
@@ -335,7 +367,8 @@
Home |
Main Index |
Thread Index |
Old Index