Use lladdr_event to propagate gratiotus arp.

Differential Revision:	https://reviews.freebsd.org/D4019
This commit is contained in:
Alexander V. Chernikov 2015-11-09 10:11:14 +00:00
parent 042c83fdc8
commit b13c5b5db2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=290603
5 changed files with 42 additions and 15 deletions

View File

@ -2512,7 +2512,8 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
return (error); return (error);
error = if_setlladdr(ifp, error = if_setlladdr(ifp,
ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
EVENTHANDLER_INVOKE(iflladdr_event, ifp); if (error == 0)
EVENTHANDLER_INVOKE(iflladdr_event, ifp);
break; break;
case SIOCAIFGROUP: case SIOCAIFGROUP:
@ -3375,16 +3376,6 @@ if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
ifr.ifr_flagshigh = ifp->if_flags >> 16; ifr.ifr_flagshigh = ifp->if_flags >> 16;
(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
} }
#ifdef INET
/*
* Also send gratuitous ARPs to notify other nodes about
* the address change.
*/
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family == AF_INET)
arp_ifinit(ifp, ifa);
}
#endif
} }
return (0); return (0);
} }

View File

@ -523,7 +523,7 @@ vlan_iflladdr(void *arg __unused, struct ifnet *ifp)
#ifndef VLAN_ARRAY #ifndef VLAN_ARRAY
struct ifvlan *next; struct ifvlan *next;
#endif #endif
int i; int error, i;
/* /*
* Check if it's a trunk interface first of all * Check if it's a trunk interface first of all
@ -544,8 +544,11 @@ vlan_iflladdr(void *arg __unused, struct ifnet *ifp)
LIST_FOREACH_SAFE(ifv, &ifp->if_vlantrunk->hash[i], ifv_list, next) { LIST_FOREACH_SAFE(ifv, &ifp->if_vlantrunk->hash[i], ifv_list, next) {
#endif /* VLAN_ARRAY */ #endif /* VLAN_ARRAY */
VLAN_UNLOCK(); VLAN_UNLOCK();
if_setlladdr(ifv->ifv_ifp, IF_LLADDR(ifp), error = if_setlladdr(ifv->ifv_ifp, IF_LLADDR(ifp),
ifp->if_addrlen); ifp->if_addrlen);
if (error == 0)
EVENTHANDLER_INVOKE(iflladdr_event,
ifv->ifv_ifp);
VLAN_LOCK(); VLAN_LOCK();
} }
VLAN_UNLOCK(); VLAN_UNLOCK();

View File

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

View File

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

View File

@ -142,7 +142,9 @@ static void in_arpinput(struct mbuf *);
static void arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr, static void arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr,
struct ifnet *ifp, int bridged, struct llentry *la); struct ifnet *ifp, int bridged, struct llentry *la);
static void arp_mark_lle_reachable(struct llentry *la); static void arp_mark_lle_reachable(struct llentry *la);
static void arp_iflladdr(void *arg __unused, struct ifnet *ifp);
static eventhandler_tag iflladdr_tag;
static const struct netisr_handler arp_nh = { static const struct netisr_handler arp_nh = {
.nh_name = "arp", .nh_name = "arp",
@ -1150,10 +1152,39 @@ arp_ifinit2(struct ifnet *ifp, struct ifaddr *ifa, u_char *enaddr)
ifa->ifa_rtrequest = NULL; ifa->ifa_rtrequest = NULL;
} }
/*
* Sends gratuitous ARPs for each ifaddr to notify other
* nodes about the address change.
*/
static __noinline void
arp_handle_ifllchange(struct ifnet *ifp)
{
struct ifaddr *ifa;
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family == AF_INET)
arp_ifinit(ifp, ifa);
}
}
/*
* A handler for interface link layer address change event.
*/
static __noinline void
arp_iflladdr(void *arg __unused, struct ifnet *ifp)
{
if ((ifp->if_flags & IFF_UP) != 0)
arp_handle_ifllchange(ifp);
}
static void static void
arp_init(void) arp_init(void)
{ {
netisr_register(&arp_nh); netisr_register(&arp_nh);
if (IS_DEFAULT_VNET(curvnet))
iflladdr_tag = EVENTHANDLER_REGISTER(iflladdr_event,
arp_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
} }
SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0); SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0);