Source-Changes-D archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: CVS commit: src/sys/net



On 16/02/2016 08:38, Roy Marples wrote:
> On Tuesday 16 February 2016 13:37:28 you wrote:
>>> Oh, I see. We shouldn't drop any events of link state changes.
>>
>> i don't see any point in keeping a huge series of link changes
>> if they can be collapsed into an equivalent sequence.  with VMs
>> and other user-controlled systems it's possible to flood such a
>> link state checking engine.
> 
> The queue can be kept quite short because we don't care about any prior 
> entries each time state changes to LINK_STATE_DOWN.
> Also, we don't care about any prior entries (other than LINK_STATE_DOWN) when 
> setting LINK_STATE_UNKNOWN.
> Finally we set LINK_STATE_UP.
> 
> So the queue should only ever hold a maximum of 3 items. Could even work it 
> like so

I found the time to work on this, here is the patch I've been running
for an hour or so upping and downing interfaces.

OK to commit?

Roy
Index: sys/net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.324
diff -u -r1.324 if.c
--- sys/net/if.c	15 Feb 2016 08:08:04 -0000	1.324
+++ sys/net/if.c	16 Feb 2016 13:22:43 -0000
@@ -603,7 +603,6 @@
 	ifp->if_broadcastaddr = 0; /* reliably crash if used uninitialized */
 
 	ifp->if_link_state = LINK_STATE_UNKNOWN;
-	ifp->if_old_link_state = LINK_STATE_UNKNOWN;
 
 	ifp->if_capenable = 0;
 	ifp->if_csum_flags_tx = 0;
@@ -1562,41 +1561,73 @@
 	}
 }
 
+/* Priority list for link state changes */
+static const int
+if_link_state_prio[LINK_STATE_MAX] = {
+	0,	/* LINK_STATE_UNKNOWN */
+	-1,	/* LINK_STATE_DOWN */
+	1,	/* LINK_STATE_UP */
+};
+
 /*
  * Handle a change in the interface link state.
- * XXX: We should listen to the routing socket in-kernel rather
- * than calling in6_if_link_* functions directly from here.
  */
 void
 if_link_state_change(struct ifnet *ifp, int link_state)
 {
-	int s;
+	int s, i;
+
+	KASSERT(link_state >= 0 && link_state < LINK_STATE_MAX);
 
 	s = splnet();
-	if (ifp->if_link_state == link_state) {
-		splx(s);
-		return;
+	if (ifp->if_link_state == link_state && ifp->if_link_queue_len == 0)
+		goto out;
+
+	for (i = 0; i < ifp->if_link_queue_len; i++) {
+		if (if_link_state_prio[link_state] <=
+		    if_link_state_prio[ifp->if_link_queue[i]])
+		{
+			ifp->if_link_queue[i] = link_state;
+			ifp->if_link_queue_len = i + 1;
+			/* Because we are trimming the queue,
+			 * there is no need to call softint_schedule again. */
+			goto out;
+		}
 	}
 
-	ifp->if_link_state = link_state;
+	KASSERT(ifp->if_link_queue_len + 1 < __arraycount(ifp->if_link_queue));
+	ifp->if_link_queue[ifp->if_link_queue_len++] = link_state;
 	softint_schedule(ifp->if_link_si);
 
+out:
 	splx(s);
 }
 
-
 static void
 if_link_state_change_si(void *arg)
 {
 	struct ifnet *ifp = arg;
-	int s;
+	int s, i;
 	int link_state, old_link_state;
 	struct domain *dp;
 
 	s = splnet();
-	link_state = ifp->if_link_state;
-	old_link_state = ifp->if_old_link_state;
-	ifp->if_old_link_state = ifp->if_link_state;
+	KASSERT(ifp->if_link_queue_len >= 0); /* unlikely */
+	if (ifp->if_link_queue_len == 0)
+		goto out;
+
+	/* Pop the link state change from the queue */
+	link_state = ifp->if_link_queue[0];
+	ifp->if_link_queue_len--;
+	for (i = 0; i < ifp->if_link_queue_len; i++)
+		ifp->if_link_queue[i] = ifp->if_link_queue[i + 1];
+
+	/* Ensure link state is actually changing */
+	if (ifp->if_link_state == link_state)
+		goto out;
+
+	old_link_state = ifp->if_link_state;
+	ifp->if_link_state = link_state;
 
 #ifdef DEBUG
 	log(LOG_DEBUG, "%s: link state %s (was %s)\n", ifp->if_xname,
@@ -1640,6 +1671,7 @@
 			dp->dom_if_link_state_change(ifp, link_state);
 	}
 
+out:
 	splx(s);
 }
 
Index: sys/net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.197
diff -u -r1.197 if.h
--- sys/net/if.h	16 Feb 2016 01:31:26 -0000	1.197
+++ sys/net/if.h	16 Feb 2016 13:22:43 -0000
@@ -191,10 +191,12 @@
 
 /*
  * Values for if_link_state.
+ * When changing these values, consider if_link_state_prio in if.c.
  */
 #define	LINK_STATE_UNKNOWN	0	/* link invalid/unknown */
 #define	LINK_STATE_DOWN		1	/* link is down */
 #define	LINK_STATE_UP		2	/* link is up */
+#define	LINK_STATE_MAX		3	/* size of link states */
 
 /*
  * Structure defining a queue for a network interface.
@@ -351,7 +353,8 @@
 	struct krwlock	*if_afdata_lock;
 	struct if_percpuq	*if_percpuq; /* We should remove it in the future */
 	void	*if_link_si;		/* softint to handle link state changes */
-	int	if_old_link_state;	/* previous link state */
+	int	if_link_queue[LINK_STATE_MAX];	/* link state change queue */
+	int	if_link_queue_len;	/* length of link state change queue */
 #endif
 } ifnet_t;
  


Home | Main Index | Thread Index | Old Index