From dan@kulesh.obluda.cz  Tue Jun  7 07:32:40 2005
Return-Path: <dan@kulesh.obluda.cz>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 7D01C16A41C
	for <FreeBSD-gnats-submit@freebsd.org>; Tue,  7 Jun 2005 07:32:40 +0000 (GMT)
	(envelope-from dan@kulesh.obluda.cz)
Received: from kulesh.obluda.cz (kulesh.obluda.cz [193.179.22.243])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 706DD43D5C
	for <FreeBSD-gnats-submit@freebsd.org>; Tue,  7 Jun 2005 07:32:39 +0000 (GMT)
	(envelope-from dan@kulesh.obluda.cz)
Received: from kulesh.obluda.cz (localhost.eunet.cz [127.0.0.1])
	by kulesh.obluda.cz (8.13.3/8.13.3) with ESMTP id j577WY3g039214;
	Tue, 7 Jun 2005 09:32:34 +0200 (CEST)
	(envelope-from dan@kulesh.obluda.cz)
Received: (from root@localhost)
	by kulesh.obluda.cz (8.13.3/8.13.1/Submit) id j577WYHa039213;
	Tue, 7 Jun 2005 09:32:34 +0200 (CEST)
	(envelope-from dan)
Message-Id: <200506070732.j577WYHa039213@kulesh.obluda.cz>
Date: Tue, 7 Jun 2005 09:32:34 +0200 (CEST)
From: Dan Lukes <dan@obluda.cz>
Reply-To: Dan Lukes <dan@obluda.cz>
To: FreeBSD-gnats-submit@freebsd.org
Cc: dan@obluda.cz
Subject: [ PATCH ] if_vlan didn't pass the ALLMULTI to the parent interface
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         81978
>Category:       kern
>Synopsis:       [if_vlan] [patch] if_vlan didn't pass the ALLMULTI to the parent interface
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    yar
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue Jun 07 07:40:28 GMT 2005
>Closed-Date:    Thu Jan 26 22:22:39 GMT 2006
>Last-Modified:  Thu Jan 26 22:22:39 GMT 2006
>Originator:     Dan Lukes
>Release:        FreeBSD 5.4-STABLE i386
>Organization:
Obludarium
>Environment:
System: FreeBSD 5.4-STABLE FreeBSD 5.4-STABLE #7: Wed Jun 1 00:34:28 CEST 2005 i386
src/sys/net/if_vlan.c,v 1.73.2.2 2005/01/31 23:26:23 imp

>Description:
	if_vlan didn't pass the ALLMULTI flag to the parent interface, so
multicast router daemons can't run correctly (they didn't see IGMP messages
for example)

>How-To-Repeat:
	Set IFF_ALLMULTI on an vlan interface, look for flags on it's parent
>Fix:

	The patch bellow use the same technique used on PROMISC mode. The
if.c has been prepared for it already, but if_vlan doesn't call the
if_allmulti ...

	Please note the patch has not been tested as my multicast server is
version 4 (and I'm set the ALLMULTI on the parent by hand as the workaround)

--- sys/net/if_vlan.c.ORIG	Tue Feb  1 21:02:01 2005
+++ sys/net/if_vlan.c	Tue Jun  7 09:18:53 2005
@@ -98,6 +98,7 @@
 #define	ifv_mintu	ifv_mib.ifvm_mintu
 
 #define	IFVF_PROMISC	0x01		/* promiscuous mode enabled */
+#define	IFVF_ALLMULTI	0x02		/* multicast router mode enabled */
 
 SYSCTL_DECL(_net_link);
 SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
@@ -804,6 +805,24 @@
 			error = ifpromisc(ifv->ifv_p, 0);
 			if (error == 0)
 				ifv->ifv_flags &= ~IFVF_PROMISC;
+		}
+	}
+
+	if ( error != 0 )
+		return(error);
+		
+	error=0;
+	if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
+		if ((ifv->ifv_flags & IFVF_ALLMULTI) == 0) {
+			error = if_allmulti(ifv->ifv_p, 1);
+			if (error == 0)
+				ifv->ifv_flags |= IFVF_ALLMULTI;
+		}
+	} else {
+		if ((ifv->ifv_flags & IFVF_ALLMULTI) != 0) {
+			error = if_allmulti(ifv->ifv_p, 0);
+			if (error == 0)
+				ifv->ifv_flags &= ~IFVF_ALLMULTI;
 		}
 	}
 


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->yar 
Responsible-Changed-By: glebius 
Responsible-Changed-When: Tue Jun 14 12:01:47 GMT 2005 
Responsible-Changed-Why:  
Yar maintains vlan(4). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=81978 

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
Date: Wed, 29 Jun 2005 17:01:27 +0400

 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:

From: Dan Lukes <dan@obluda.cz>
To: Yar Tikhiy <yar@freebsd.org>
Cc: freebsd-bugs@freebsd.org
Subject: Re: kern/81978: [ PATCH ] if_vlan didn't pass the ALLMULTI to the
 parent interface
Date: Sat, 02 Jul 2005 02:47:38 +0200

 Yar Tikhiy napsal/wrote, On 06/29/05 15:01:
 > 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!
 
 	It work. Well, there may be some unresolved problem - we shoult clear 
 the ALLMULTI and PROMISC flags when interface is destroyed. The 
 vlan_unconfig() seems to be best place for it.
 
 
 > Apropos, how do you turn on all-multicast mode on an interface?  It doesn't seem possible from the userland using ioctl(2).
 
 	setsockopt(s, IPPROTO_IP, MRT_ADD_VIF, ...)
 	Well, the 'parent' interface must have an IP address configured in - so 
 I configured 127.0.0.5/32 to parent interface.
 
   ===============
 
 	Unfortunatelly, there is one more big problem with VLAN interface and 
 MROUTING that hasn't been adressed by this PR and patch.
 
 	ip_mroute code isn't informed about destroying of an interface. Later 
 reference of destroyed interface cause kernel abend.
 	
 	Let add an vlanX interface as vif (using MRT_ADD_VIF), then destroy it. 
 Nothing bad happens untill we call MRT_DEL_VIF. The ip_mroute.c code 
 cache ifp within it's viftable[] despite of interface destroying. Call 
 of MRT_DEL_VIF reference free memory and kernel abends.
 
 	The 'if_detach' of if.c should notify the ip_mroute module about 
 destroying of interface so ip_mroute code can safely deinitialize 
 interface and remove references to it from it's internal structures.
 
 	We need something similar to carp_ifdetach(ifp) function of carp module 
 which is called from if_detach.
 
 	Well, this problem is not so related to VLAN module - it's problem of 
 any detachable multicast capable interface.
 
 	I should send separate PR unless you patch it also ...
 
 						Dan
 
 
 -- 
 Dan Lukes                                   SISAL MFF UK
 AKA: dan@obluda.cz, dan@freebsd.cz,dan@kolej.mff.cuni.cz
State-Changed-From-To: open->patched 
State-Changed-By: yar 
State-Changed-When: Mon Oct 3 02:25:36 GMT 2005 
State-Changed-Why:  
The problem has been fixed in if_vlan.c rev. 1.88. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=81978 
State-Changed-From-To: patched->closed 
State-Changed-By: glebius 
State-Changed-When: Thu Jan 26 22:21:57 UTC 2006 
State-Changed-Why:  
Merged to RELENG_6. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=81978 
>Unformatted:
