Subject: Alternative approach for interface events
To: None <tech-net@NetBSD.org>
From: Peter Postma <peter@pointless.nl>
List: tech-net
Date: 09/19/2004 12:31:56
I'm not really happy with the changes to pfil(9) to support interface
events (attach, detach, addresses). IMHO, the changes made the pfil(9) API
more ugly (e.g. extra conditionals in pfil_run_hooks) and I don't think that
the pfil(9) API should be used for handling such things (pfil is for packet
filtering, not watching interface events). I've created a small patch that
implements the interface events differently (patch applies to 2.0 beta).
Pros: no hacks to pfil(9), suits better and cleaner.
Cons: yet another interface that registers functions to be executed, more?
Comments?
Index: net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.139.2.1
diff -u -r1.139.2.1 if.c
--- net/if.c 28 May 2004 07:24:37 -0000 1.139.2.1
+++ net/if.c 8 Sep 2004 10:13:12 -0000
@@ -160,6 +160,9 @@
LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
int if_cloners_count;
+LIST_HEAD(, if_event) if_events = LIST_HEAD_INITIALIZER(if_events);
+int if_event_enabled = 0;
+
#if defined(INET) || defined(INET6) || defined(NETATALK) || defined(NS) || \
defined(ISO) || defined(CCITT) || defined(NATM)
static void if_detach_queues __P((struct ifnet *, struct ifqueue *));
@@ -469,6 +472,8 @@
if (domains)
if_attachdomain1(ifp);
+ if_event_invoke(IF_EVENT_ATTACH_IF, ifp);
+
/* Announce the interface. */
rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
}
@@ -577,6 +582,8 @@
(void) pfil_head_unregister(&ifp->if_pfil);
#endif
+ if_event_invoke(IF_EVENT_DETACH_IF, ifp);
+
/*
* Rip all the addresses off the interface. This should make
* all of the routes go away.
@@ -846,6 +853,7 @@
if_clone_attach(ifc)
struct if_clone *ifc;
{
+ if_event_invoke(IF_EVENT_ATTACH_CLONE, ifc);
LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
if_cloners_count++;
@@ -858,6 +866,7 @@
if_clone_detach(ifc)
struct if_clone *ifc;
{
+ if_event_invoke(IF_EVENT_DETACH_CLONE, ifc);
LIST_REMOVE(ifc, ifc_list);
if_cloners_count--;
@@ -899,6 +908,75 @@
}
/*
+ * Search for a function in the interface events list.
+ */
+static struct if_event *
+if_event_lookup(void (*func)(int, void *), int type)
+{
+ struct if_event *p;
+
+ LIST_FOREACH(p, &if_events, link)
+ if (p->type == type && p->func == func)
+ return (p);
+
+ return (NULL);
+}
+
+/*
+ * Add a function to the interface events list.
+ */
+int
+if_event_add(void (*func)(int, void *), int type)
+{
+ struct if_event *p;
+
+ if (if_event_lookup(func, type) != NULL)
+ return (EEXIST);
+
+ p = malloc(sizeof(struct if_event), M_IFADDR, M_WAITOK);
+ p->func = func;
+ p->type = type;
+
+ LIST_INSERT_HEAD(&if_events, p, link);
+
+ return (0);
+}
+
+/*
+ * Remove a function from the interface events list.
+ */
+int
+if_event_remove(void (*func)(int, void *), int type)
+{
+ struct if_event *p;
+
+ if ((p = if_event_lookup(func, type)) == NULL)
+ return (ENOENT);
+
+ free(p, M_IFADDR);
+ LIST_REMOVE(p, link);
+
+ return (0);
+}
+
+/*
+ * Run the interface events with the specified event type.
+ */
+void
+if_event_invoke(int type, void *ifp)
+{
+ struct if_event *p;
+
+ if (!if_event_enabled)
+ return;
+
+ LIST_FOREACH(p, &if_events, link) {
+ if ((p->type & type) && p->func != NULL)
+ (*p->func)(type, ifp);
+ }
+}
+
+/*
* Locate an interface based on a complete address.
*/
/*ARGSUSED*/
@@ -1699,6 +1777,24 @@
return (error);
}
+SYSCTL_SETUP(sysctl_net_if_event_setup, "sysctl net.if_events subtree setup")
+{
+ struct sysctlnode *node;
+
+ sysctl_createv(clog, 0, NULL, NULL, CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "net", NULL, NULL, 0, NULL, 0, CTL_NET, CTL_EOL);
+
+ sysctl_createv(clog, 0, NULL, &node, CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "if_events", SYSCTL_DESCR("if_events options"),
+ NULL, 0, NULL, 0, CTL_NET, CTL_CREATE, CTL_EOL);
+
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "enabled",
+ SYSCTL_DESCR("Enable or disable the interface events"),
+ NULL, 0, &if_event_enabled, 0, CTL_NET,
+ node->sysctl_num, CTL_CREATE, CTL_EOL);
+}
+
#if defined(INET) || defined(INET6)
static void
sysctl_net_ifq_setup(struct sysctllog **clog,
Index: net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.95
diff -u -r1.95 if.h
--- net/if.h 10 Dec 2003 11:46:33 -0000 1.95
+++ net/if.h 8 Sep 2004 10:13:13 -0000
@@ -159,6 +159,22 @@
};
/*
+ * Structure for the interface events.
+ */
+struct if_event {
+ void (*func)(int, void *);
+ int type;
+ LIST_ENTRY(if_event) link;
+};
+
+#define IF_EVENT_ATTACH_IF 0x01
+#define IF_EVENT_DETACH_IF 0x02
+#define IF_EVENT_ATTACH_CLONE 0x04
+#define IF_EVENT_DETACH_CLONE 0x08
+#define IF_EVENT_ADDR_V4 0x10
+#define IF_EVENT_ADDR_V6 0x20
+
+/*
* Structure defining statistics and other data kept regarding a network
* interface.
*/
@@ -773,6 +789,10 @@
int if_clone_create __P((const char *));
int if_clone_destroy __P((const char *));
+int if_event_add(void (*)(int, void *), int);
+int if_event_remove(void (*)(int, void *), int);
+void if_event_invoke(int, void *);
+
int loioctl __P((struct ifnet *, u_long, caddr_t));
void loopattach __P((int));
int looutput __P((struct ifnet *,
Index: netinet/in.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.c,v
retrieving revision 1.93.2.1
diff -u -r1.93.2.1 in.c
--- netinet/in.c 10 Jul 2004 12:42:37 -0000 1.93.2.1
+++ netinet/in.c 8 Sep 2004 10:13:13 -0000
@@ -464,6 +464,8 @@
case SIOCSIFADDR:
error = in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1);
+ if (!error)
+ if_event_invoke(IF_EVENT_ADDR_V4, ifp);
return error;
case SIOCSIFNETMASK:
@@ -503,6 +505,8 @@
if ((ifp->if_flags & IFF_BROADCAST) &&
(ifra->ifra_broadaddr.sin_family == AF_INET))
ia->ia_broadaddr = ifra->ifra_broadaddr;
+ if (!error)
+ if_event_invoke(IF_EVENT_ADDR_V4, ifp);
return (error);
case SIOCGIFALIAS:
@@ -520,6 +524,7 @@
case SIOCDIFADDR:
in_purgeaddr(&ia->ia_ifa, ifp);
+ if_event_invoke(IF_EVENT_ADDR_V4, ifp);
break;
#ifdef MROUTING
Index: netinet6/in6.c
===================================================================
RCS file: /cvsroot/src/sys/netinet6/in6.c,v
retrieving revision 1.86
diff -u -r1.86 in6.c
--- netinet6/in6.c 28 Mar 2004 08:28:06 -0000 1.86
+++ netinet6/in6.c 8 Sep 2004 10:13:15 -0000
@@ -736,6 +736,7 @@
* that is, this address might make other addresses detached.
*/
pfxlist_onlink_check();
+ if_event_invoke(IF_EVENT_ADDR_V6, ifp);
break;
}
@@ -777,6 +778,7 @@
in6_purgeaddr(&ia->ia_ifa);
if (pr && purgeprefix)
prelist_remove(pr);
+ if_event_invoke(IF_EVENT_ADDR_V6, ifp);
break;
}
--
Peter Postma