Declare a new EVENTHANDLER called iflladdr_event which signals that the L2

address on an interface has changed. This lets stacked interfaces such as
vlan(4) detect that their lower interface has changed and adjust things in
order to keep working. Previously this situation broke at least vlan(4) and
lagg(4) configurations.

The EVENTHANDLER_INVOKE call was not placed within if_setlladdr() due to the
risk of a loop.

PR:		kern/142927
Submitted by:	Nikolay Denev
This commit is contained in:
Andrew Thompson 2010-01-18 20:34:00 +00:00
parent 0424a37bea
commit ea4ca115b7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=202588
8 changed files with 52 additions and 0 deletions

View File

@ -2268,6 +2268,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
return (error);
error = if_setlladdr(ifp,
ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
EVENTHANDLER_INVOKE(iflladdr_event, ifp);
break;
case SIOCAIFGROUP:

View File

@ -917,6 +917,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
sc->sc_ifaddr = fif;
}
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
}
bridge_mutecaps(sc); /* recalcuate now this interface is removed */
@ -1033,6 +1034,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
!memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) {
bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
sc->sc_ifaddr = ifs;
EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
}
ifs->if_bridge = sc;

View File

@ -305,6 +305,7 @@ lagg_lladdr(struct lagg_softc *sc, uint8_t *lladdr)
/* Let the protocol know the MAC has changed */
if (sc->sc_lladdr != NULL)
(*sc->sc_lladdr)(sc);
EVENTHANDLER_INVOKE(iflladdr_event, ifp);
}
static void

View File

@ -339,6 +339,9 @@ void if_maddr_runlock(struct ifnet *ifp); /* if_multiaddrs */
} while(0)
#ifdef _KERNEL
/* interface link layer address change event */
typedef void (*iflladdr_event_handler_t)(void *, struct ifnet *);
EVENTHANDLER_DECLARE(iflladdr_event, iflladdr_event_handler_t);
/* interface address change event */
typedef void (*ifaddr_event_handler_t)(void *, struct ifnet *);
EVENTHANDLER_DECLARE(ifaddr_event, ifaddr_event_handler_t);

View File

@ -138,6 +138,7 @@ SYSCTL_INT(_net_link_vlan, OID_AUTO, soft_pad, CTLFLAG_RW, &soft_pad, 0,
static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface");
static eventhandler_tag ifdetach_tag;
static eventhandler_tag iflladdr_tag;
/*
* We have a global mutex, that is used to serialize configuration
@ -199,6 +200,7 @@ static int vlan_clone_create(struct if_clone *, char *, size_t, caddr_t);
static int vlan_clone_destroy(struct if_clone *, struct ifnet *);
static void vlan_ifdetach(void *arg, struct ifnet *ifp);
static void vlan_iflladdr(void *arg, struct ifnet *ifp);
static struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL,
IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
@ -462,6 +464,41 @@ vlan_setmulti(struct ifnet *ifp)
return (0);
}
/*
* A handler for parent interface link layer address changes.
* If the parent interface link layer address is changed we
* should also change it on all children vlans.
*/
static void
vlan_iflladdr(void *arg __unused, struct ifnet *ifp)
{
struct ifvlan *ifv;
int i;
/*
* Check if it's a trunk interface first of all
* to avoid needless locking.
*/
if (ifp->if_vlantrunk == NULL)
return;
VLAN_LOCK();
/*
* OK, it's a trunk. Loop over and change all vlan's lladdrs on it.
*/
#ifdef VLAN_ARRAY
for (i = 0; i < VLAN_ARRAY_SIZE; i++)
if ((ifv = ifp->if_vlantrunk->vlans[i]))
if_setlladdr(ifv->ifv_ifp, IF_LLADDR(ifp), ETHER_ADDR_LEN);
#else /* VLAN_ARRAY */
for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++)
LIST_FOREACH(ifv, &ifp->if_vlantrunk->hash[i], ifv_list)
if_setlladdr(ifv->ifv_ifp, IF_LLADDR(ifp), ETHER_ADDR_LEN);
#endif /* VLAN_ARRAY */
VLAN_UNLOCK();
}
/*
* A handler for network interface departure events.
* Track departure of trunks here so that we don't access invalid
@ -537,6 +574,10 @@ vlan_modevent(module_t mod, int type, void *data)
vlan_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
if (ifdetach_tag == NULL)
return (ENOMEM);
iflladdr_tag = EVENTHANDLER_REGISTER(iflladdr_event,
vlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
if (iflladdr_tag == NULL)
return (ENOMEM);
VLAN_LOCK_INIT();
vlan_input_p = vlan_input;
vlan_link_state_p = vlan_link_state;
@ -555,6 +596,7 @@ vlan_modevent(module_t mod, int type, void *data)
case MOD_UNLOAD:
if_clone_detach(&vlan_cloner);
EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifdetach_tag);
EVENTHANDLER_DEREGISTER(iflladdr_event, iflladdr_tag);
vlan_input_p = NULL;
vlan_link_state_p = NULL;
vlan_trunk_cap_p = NULL;

View File

@ -431,6 +431,7 @@ ng_eiface_rcvmsg(node_p node, item_p item, hook_p lasthook)
}
error = if_setlladdr(priv->ifp,
(u_char *)msg->data, ETHER_ADDR_LEN);
EVENTHANDLER_INVOKE(iflladdr_event, priv->ifp);
break;
}

View File

@ -481,6 +481,7 @@ ng_ether_rcvmsg(node_p node, item_p item, hook_p lasthook)
}
error = if_setlladdr(priv->ifp,
(u_char *)msg->data, ETHER_ADDR_LEN);
EVENTHANDLER_INVOKE(iflladdr_event, priv->ifp);
break;
}
case NGM_ETHER_GET_PROMISC:

View File

@ -433,6 +433,7 @@ ng_fec_addport(struct ng_fec_private *priv, char *iface)
/* Set up phony MAC address. */
if_setlladdr(bifp, IF_LLADDR(ifp), ETHER_ADDR_LEN);
EVENTHANDLER_INVOKE(iflladdr_event, bifp);
/* Save original input vector */
new->fec_if_input = bifp->if_input;