Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Jun 2005 17:01:27 +0400
From:      Yar Tikhiy <yar@FreeBSD.org>
To:        dan@obluda.cz
Cc:        freebsd-bugs@FreeBSD.org
Subject:   Re: kern/81978: [ PATCH ] if_vlan didn't pass the ALLMULTI to the parent interface
Message-ID:  <20050629130127.GA51085@comp.chem.msu.su>
In-Reply-To: <200506141202.j5EC28O7026407@freefall.freebsd.org>
References:  <200506141202.j5EC28O7026407@freefall.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Dan,

Would you mind testing the following patch in 5-STABLE?
I tried to reduce code duplication since the cases of
promiscuous and all-multi modes are very close.  Thanks!

Apropos, how do you turn on all-multicast mode on an
interface?  It doesn't seem possible from the userland
using ioctl(2).

-- 
Yar

Index: if_vlan.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_vlan.c,v
retrieving revision 1.73.2.2
diff -u -r1.73.2.2 if_vlan.c
--- if_vlan.c	31 Jan 2005 23:26:23 -0000	1.73.2.2
+++ if_vlan.c	29 Jun 2005 11:40:16 -0000
@@ -79,6 +79,7 @@
 struct	ifvlan {
 	struct	arpcom ifv_ac;	/* make this an interface */
 	struct	ifnet *ifv_p;	/* parent inteface of this vlan */
+	int	ifv_pflags;	/* special flags we have set on parent */
 	struct	ifv_linkmib {
 		int	ifvm_parent;
 		int	ifvm_encaplen;	/* encapsulation length */
@@ -89,7 +90,6 @@
 	}	ifv_mib;
 	SLIST_HEAD(__vlan_mchead, vlan_mc_entry)	vlan_mc_listhead;
 	LIST_ENTRY(ifvlan) ifv_list;
-	int	ifv_flags;
 };
 #define	ifv_if	ifv_ac.ac_if
 #define	ifv_tag	ifv_mib.ifvm_tag
@@ -97,8 +97,6 @@
 #define	ifv_mtufudge	ifv_mib.ifvm_mtufudge
 #define	ifv_mintu	ifv_mib.ifvm_mintu
 
-#define	IFVF_PROMISC	0x01		/* promiscuous mode enabled */
-
 SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
 SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
@@ -122,11 +120,13 @@
 static	void vlan_ifinit(void *foo);
 static	void vlan_input(struct ifnet *ifp, struct mbuf *m);
 static	int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
+static	int
+    vlan_setflag(struct ifnet *ifp, int flag, int (*func)(struct ifnet *, int));
+static	int vlan_setflags(struct ifnet *ifp);
 static	int vlan_setmulti(struct ifnet *ifp);
 static	int vlan_unconfig(struct ifnet *ifp);
 static	int vlan_config(struct ifvlan *ifv, struct ifnet *p);
 static	void vlan_link_state(struct ifnet *ifp, int link);
-static	int vlan_set_promisc(struct ifnet *ifp);
 
 static	struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
     const char *, int *);
@@ -411,8 +411,8 @@
 		ifp->if_flags |= IFF_RUNNING;
 		VLAN_UNLOCK();
 
-		/* Update promiscuous mode, if necessary. */
-		vlan_set_promisc(ifp);
+		/* Update flags on the parent, if necessary. */
+		vlan_setflags(ifp);
 	}
 
 	return (0);
@@ -648,7 +648,7 @@
 
 	ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
 	ifv->ifv_mintu = ETHERMIN;
-	ifv->ifv_flags = 0;
+	ifv->ifv_pflags = 0;
 
 	/*
 	 * The active VLAN counter on the parent is used
@@ -772,8 +772,8 @@
 
 	/* Disconnect from parent. */
 	ifv->ifv_p = NULL;
+	ifv->ifv_pflags = 0;
 	ifv->ifv_if.if_mtu = ETHERMTU;		/* XXX why not 0? */
-	ifv->ifv_flags = 0;
 	ifv->ifv_if.if_link_state = LINK_STATE_UNKNOWN;
 
 	/* Clear our MAC address. */
@@ -787,27 +787,41 @@
 	return (0);
 }
 
+/* Handle a reference counted flag that should be set on the parent as well */
 static int
-vlan_set_promisc(struct ifnet *ifp)
+vlan_setflag(struct ifnet *ifp, int flag, int (*func)(struct ifnet *, int))
 {
-	struct ifvlan *ifv = ifp->if_softc;
-	int error = 0;
+	struct ifvlan *ifv;
+	int error, status;
 
-	if ((ifp->if_flags & IFF_PROMISC) != 0) {
-		if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
-			error = ifpromisc(ifv->ifv_p, 1);
-			if (error == 0)
-				ifv->ifv_flags |= IFVF_PROMISC;
-		}
-	} else {
-		if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
-			error = ifpromisc(ifv->ifv_p, 0);
-			if (error == 0)
-				ifv->ifv_flags &= ~IFVF_PROMISC;
-		}
+	/* XXX VLAN_LOCK_ASSERT(); */
+
+	ifv = ifp->if_softc;
+	status = ifp->if_flags & flag;
+
+	if (status != (ifv->ifv_pflags & flag)) {
+		error = (*func)(ifv->ifv_p, status);
+		if (error)
+			return (error);
+		ifv->ifv_pflags &= ~flag;
+		ifv->ifv_pflags |= status;
 	}
+	return (0);
+}
 
-	return (error);
+/* Handle IFF_* flags that require certain changes in the parent's status */
+static int
+vlan_setflags(struct ifnet *ifp)
+{
+	int error;
+	
+	error = vlan_setflag(ifp, IFF_PROMISC, ifpromisc);
+	if (error)
+		return (error);
+	error = vlan_setflag(ifp, IFF_ALLMULTI, if_allmulti);
+	if (error)
+		return (error);
+	return (0);
 }
 
 /* Inform all vlans that their parent has changed link state */
@@ -948,8 +962,8 @@
 		ifp->if_flags |= IFF_RUNNING;
 		VLAN_UNLOCK();
 
-		/* Update promiscuous mode, if necessary. */
-		vlan_set_promisc(ifp);
+		/* Update flags on the parent, if necessary. */
+		vlan_setflags(ifp);
 		break;
 
 	case SIOCGETVLAN:
@@ -966,11 +980,11 @@
 		
 	case SIOCSIFFLAGS:
 		/*
-		 * For promiscuous mode, we enable promiscuous mode on
-		 * the parent if we need promiscuous on the VLAN interface.
+		 * We should propagate selected flags to the parent,
+		 * e.g., promiscuous mode.
 		 */
 		if (ifv->ifv_p != NULL)
-			error = vlan_set_promisc(ifp);
+			error = vlan_setflags(ifp);
 		break;
 
 	case SIOCADDMULTI:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20050629130127.GA51085>