Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145025477
D4111.id10146.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D4111.id10146.diff
View Options
Index: sys/net/if.c
===================================================================
--- sys/net/if.c
+++ sys/net/if.c
@@ -126,7 +126,7 @@
void (*bridge_linkstate_p)(struct ifnet *ifp);
void (*ng_ether_link_state_p)(struct ifnet *ifp, int state);
-void (*lagg_linkstate_p)(struct ifnet *ifp, int state);
+void (*lagg_linkstate_p)(struct ifnet *ifp);
/* These are external hooks for CARP. */
void (*carp_linkstate_p)(struct ifnet *ifp);
void (*carp_demote_adj_p)(int, char *);
@@ -1980,6 +1980,8 @@
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
+ if (ifp->if_lagg)
+ (*lagg_linkstate_p)(ifp);
rt_ifmsg(ifp);
}
@@ -2001,6 +2003,8 @@
pfctlinput(PRC_IFUP, ifa->ifa_addr);
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
+ if (ifp->if_lagg)
+ (*lagg_linkstate_p)(ifp);
rt_ifmsg(ifp);
#ifdef INET6
in6_if_up(ifp);
@@ -2015,17 +2019,27 @@
int (*vlan_setcookie_p)(struct ifnet *, void *);
void *(*vlan_cookie_p)(struct ifnet *);
+void
+if_link_state_change(struct ifnet *ifp, int link_state)
+{
+
+ return if_link_state_change_cond(ifp, link_state, 0);
+}
+
/*
* Handle a change in the interface link state. To avoid LORs
* between driver lock and upper layer locks, as well as possible
* recursions, we post event to taskqueue, and all job
* is done in static do_link_state_change().
+ *
+ * If the current link state matches link_state and force isn't
+ * specified no action is taken.
*/
void
-if_link_state_change(struct ifnet *ifp, int link_state)
+if_link_state_change_cond(struct ifnet *ifp, int link_state, int force)
{
- /* Return if state hasn't changed. */
- if (ifp->if_link_state == link_state)
+
+ if (ifp->if_link_state == link_state && !force)
return;
ifp->if_link_state = link_state;
@@ -2053,7 +2067,7 @@
if (ifp->if_bridge)
(*bridge_linkstate_p)(ifp);
if (ifp->if_lagg)
- (*lagg_linkstate_p)(ifp, link_state);
+ (*lagg_linkstate_p)(ifp);
if (IS_DEFAULT_VNET(curvnet))
devctl_notify("IFNET", ifp->if_xname,
Index: sys/net/if_lagg.h
===================================================================
--- sys/net/if_lagg.h
+++ sys/net/if_lagg.h
@@ -281,7 +281,7 @@
#define LAGG_UNLOCK_ASSERT(_sc) rm_assert(&(_sc)->sc_mtx, RA_UNLOCKED)
extern struct mbuf *(*lagg_input_p)(struct ifnet *, struct mbuf *);
-extern void (*lagg_linkstate_p)(struct ifnet *, int );
+extern void (*lagg_linkstate_p)(struct ifnet *);
int lagg_enqueue(struct ifnet *, struct mbuf *);
Index: sys/net/if_lagg.c
===================================================================
--- sys/net/if_lagg.c
+++ sys/net/if_lagg.c
@@ -106,7 +106,7 @@
static int lagg_port_destroy(struct lagg_port *, int);
static struct mbuf *lagg_input(struct ifnet *, struct mbuf *);
static void lagg_linkstate(struct lagg_softc *);
-static void lagg_port_state(struct ifnet *, int);
+static void lagg_port_state(struct ifnet *);
static int lagg_port_ioctl(struct ifnet *, u_long, caddr_t);
static int lagg_port_output(struct ifnet *, struct mbuf *,
const struct sockaddr *, struct route *);
@@ -1128,7 +1128,7 @@
LAGG_WUNLOCK(sc);
}
-static void
+static __noinline void
lagg_port2req(struct lagg_port *lp, struct lagg_reqport *rp)
{
struct lagg_softc *sc = lp->lp_softc;
@@ -1779,7 +1779,12 @@
break;
}
}
- if_link_state_change(sc->sc_ifp, new_link);
+
+ /*
+ * Force state change to ensure ifnet_link_event is generated allowing
+ * protocols to notify other nodes of potential address move.
+ */
+ if_link_state_change_cond(sc->sc_ifp, new_link, 1);
/* Update if_baudrate to reflect the max possible speed */
switch (sc->sc_proto) {
@@ -1802,7 +1807,7 @@
}
static void
-lagg_port_state(struct ifnet *ifp, int state)
+lagg_port_state(struct ifnet *ifp)
{
struct lagg_port *lp = (struct lagg_port *)ifp->if_lagg;
struct lagg_softc *sc = NULL;
@@ -1818,7 +1823,7 @@
LAGG_WUNLOCK(sc);
}
-struct lagg_port *
+static struct lagg_port *
lagg_link_active(struct lagg_softc *sc, struct lagg_port *lp)
{
struct lagg_port *lp_next, *rval = NULL;
Index: sys/net/if_var.h
===================================================================
--- sys/net/if_var.h
+++ sys/net/if_var.h
@@ -492,6 +492,7 @@
void if_free(struct ifnet *);
void if_initname(struct ifnet *, const char *, int);
void if_link_state_change(struct ifnet *, int);
+void if_link_state_change_cond(struct ifnet *, int, int);
int if_printf(struct ifnet *, const char *, ...) __printflike(2, 3);
void if_ref(struct ifnet *);
void if_rele(struct ifnet *);
Index: sys/netinet/if_ether.h
===================================================================
--- sys/netinet/if_ether.h
+++ sys/netinet/if_ether.h
@@ -119,7 +119,8 @@
void arprequest(struct ifnet *, const struct in_addr *,
const struct in_addr *, u_char *);
void arp_ifinit(struct ifnet *, struct ifaddr *);
-void arp_announce_ifaddr(struct ifnet *, struct in_addr addr, u_char *);
+void arp_announce(struct ifnet *);
+void arp_announce_ifaddr(struct ifnet *, const struct in_addr *addr, u_char *);
#endif
#endif
Index: sys/netinet/if_ether.c
===================================================================
--- sys/netinet/if_ether.c
+++ sys/netinet/if_ether.c
@@ -145,6 +145,7 @@
static void arp_iflladdr(void *arg __unused, struct ifnet *ifp);
static eventhandler_tag iflladdr_tag;
+static eventhandler_tag ifnet_link_event_tag;
static const struct netisr_handler arp_nh = {
.nh_name = "arp",
@@ -1144,43 +1145,96 @@
if (ntohl(dst_in->sin_addr.s_addr) == INADDR_ANY)
return;
- arp_announce_ifaddr(ifp, dst_in->sin_addr, IF_LLADDR(ifp));
+ arp_announce_ifaddr(ifp, &dst_in->sin_addr, IF_LLADDR(ifp));
arp_add_ifa_lle(ifp, dst);
}
void
-arp_announce_ifaddr(struct ifnet *ifp, struct in_addr addr, u_char *enaddr)
+arp_announce_ifaddr(struct ifnet *ifp, const struct in_addr *addr, u_char *enaddr)
{
- if (ntohl(addr.s_addr) != INADDR_ANY)
- arprequest(ifp, &addr, &addr, enaddr);
+ if (ntohl(addr->s_addr) != INADDR_ANY)
+ arprequest(ifp, addr, addr, enaddr);
}
/*
- * Sends gratuitous ARPs for each ifaddr to notify other
- * nodes about the address change.
+ * Send gratuitous ARPs for all interfaces addresses to notify other nodes of
+ * changes.
+ *
+ * This is a noop if the interface isn't up or has been flagged for no ARP.
*/
-static __noinline void
-arp_handle_ifllchange(struct ifnet *ifp)
+void __noinline
+arp_announce(struct ifnet *ifp)
{
+ int i, cnt, entries;
+ u_char *lladdr;
struct ifaddr *ifa;
+ struct in_addr *addr, *head;
+
+ if (!(ifp->if_flags & IFF_UP) || (ifp->if_flags & IFF_NOARP))
+ return;
+
+ entries = 8;
+ cnt = 0;
+ head = malloc(sizeof(*addr) * entries, M_TEMP, M_NOWAIT);
+ if (head == NULL) {
+ log(LOG_INFO, "arp_announce: malloc %d entries failed\n",
+ entries);
+ return;
+ }
+ /* Take a copy then process to avoid locking issues. */
+ IF_ADDR_RLOCK(ifp);
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- if (ifa->ifa_addr->sa_family == AF_INET)
- arp_ifinit(ifp, ifa);
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+
+ if (cnt == entries) {
+ addr = (struct in_addr *)realloc(head, sizeof(*addr) *
+ (entries + 8), M_TEMP, M_NOWAIT);
+ if (addr == NULL) {
+ log(LOG_INFO, "arp_announce: realloc to %d "
+ "entries failed\n", entries + 8);
+ /* Process what we have. */
+ break;
+ }
+ entries += 8;
+ head = addr;
+ }
+
+ addr = head + cnt;
+ bcopy(IFA_IN(ifa), addr, sizeof(*addr));
+ cnt++;
}
+ IF_ADDR_RUNLOCK(ifp);
+
+ lladdr = IF_LLADDR(ifp);
+ for (i = 0; i < cnt; i++) {
+ arp_announce_ifaddr(ifp, head + i, lladdr);
+ }
+ free(head, M_TEMP);
+}
+
+/*
+ * A handler for interface linkstate change events.
+ */
+static void
+arp_ifnet_link_event(void *arg __unused, struct ifnet *ifp, int linkstate)
+{
+
+ if (linkstate == LINK_STATE_UP)
+ arp_announce(ifp);
}
/*
- * A handler for interface link layer address change event.
+ * A handler for interface link layer address change events.
*/
static __noinline void
arp_iflladdr(void *arg __unused, struct ifnet *ifp)
{
- if ((ifp->if_flags & IFF_UP) != 0)
- arp_handle_ifllchange(ifp);
+ arp_announce(ifp);
}
static void
@@ -1188,8 +1242,12 @@
{
netisr_register(&arp_nh);
- if (IS_DEFAULT_VNET(curvnet))
+
+ if (IS_DEFAULT_VNET(curvnet)) {
iflladdr_tag = EVENTHANDLER_REGISTER(iflladdr_event,
arp_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
+ ifnet_link_event_tag = EVENTHANDLER_REGISTER(ifnet_link_event,
+ arp_ifnet_link_event, 0, EVENTHANDLER_PRI_ANY);
+ }
}
SYSINIT(arp, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, arp_init, 0);
Index: sys/netinet/in_var.h
===================================================================
--- sys/netinet/in_var.h
+++ sys/netinet/in_var.h
@@ -129,6 +129,9 @@
#define IN_IFADDR_WLOCK_ASSERT() rm_assert(&in_ifaddr_lock, RA_WLOCKED)
#define IN_IFADDR_WUNLOCK() rm_wunlock(&in_ifaddr_lock)
+#define IFA_IN(ifa) \
+ (&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr)
+
/*
* Macro for finding the internet address structure (in_ifaddr)
* corresponding to one of our IP addresses (in_addr).
Index: sys/netinet/ip_carp.c
===================================================================
--- sys/netinet/ip_carp.c
+++ sys/netinet/ip_carp.c
@@ -1009,13 +1009,12 @@
carp_send_arp(struct carp_softc *sc)
{
struct ifaddr *ifa;
- struct in_addr addr;
CARP_FOREACH_IFA(sc, ifa) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
- addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
- arp_announce_ifaddr(sc->sc_carpdev, addr, LLADDR(&sc->sc_addr));
+ arp_announce_ifaddr(sc->sc_carpdev, IFA_IN(ifa),
+ LLADDR(&sc->sc_addr));
}
}
@@ -1037,18 +1036,16 @@
static void
carp_send_na(struct carp_softc *sc)
{
- static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
struct ifaddr *ifa;
- struct in6_addr *in6;
CARP_FOREACH_IFA(sc, ifa) {
- if (ifa->ifa_addr->sa_family != AF_INET6)
+ if (ifa->ifa_addr->sa_family != AF_INET6 ||
+ IFA_ND6_NA_UNSOLICITED_SKIP(ifa))
continue;
- in6 = IFA_IN6(ifa);
- nd6_na_output(sc->sc_carpdev, &mcast, in6,
- ND_NA_FLAG_OVERRIDE, 1, NULL);
- DELAY(1000); /* XXX */
+ nd6_na_output_unsolicited_addr(sc->sc_carpdev, IFA_IN6(ifa),
+ IFA_ND6_NA_BASE_FLAGS(sc->sc_carpdev, ifa));
+ nd6_na_unsolicited_addr_delay(ifa);
}
}
Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -113,7 +113,7 @@
#define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix)
/*
- * Definitions of some costant IP6 addresses.
+ * Definitions of some constant IP6 addresses.
*/
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
Index: sys/netinet6/in6_var.h
===================================================================
--- sys/netinet6/in6_var.h
+++ sys/netinet6/in6_var.h
@@ -399,6 +399,16 @@
#define IA6_SIN6(ia) (&((ia)->ia_addr))
#define IA6_DSTSIN6(ia) (&((ia)->ia_dstaddr))
#define IFA_IN6(x) (&((struct sockaddr_in6 *)((x)->ifa_addr))->sin6_addr)
+#define IFA_IN6_FLAGS(ifa) ((struct in6_ifaddr *)ifa)->ia6_flags
+#define IFA_ND6_NA_BASE_FLAGS(ifp, ifa) \
+ (IFA_IN6_FLAGS(ifa) & IN6_IFF_ANYCAST ? 0 : ND_NA_FLAG_OVERRIDE) | \
+ ((V_ip6_forwarding && !(ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && \
+ V_ip6_norbit_raif)) ? ND_NA_FLAG_ROUTER : 0)
+#define IFA_ND6_NA_UNSOLICITED_SKIP(ifa) \
+ (IFA_IN6_FLAGS(ifa) & (IN6_IFF_DUPLICATED | IN6_IFF_DEPRECATED | \
+ IN6_IFF_TENTATIVE)) != 0
+#define IN6_MAX_ANYCAST_DELAY_TIME_MS 1000000
+#define IN6_BROADCAST_DELAY_TIME_MS 1000
#define IFA_DSTIN6(x) (&((struct sockaddr_in6 *)((x)->ifa_dstaddr))->sin6_addr)
#define IFPR_IN6(x) (&((struct sockaddr_in6 *)((x)->ifpr_prefix))->sin6_addr)
Index: sys/netinet6/nd6.h
===================================================================
--- sys/netinet6/nd6.h
+++ sys/netinet6/nd6.h
@@ -398,6 +398,10 @@
#ifdef VIMAGE
void nd6_destroy(void);
#endif
+void nd6_na_output_unsolicited(struct ifnet *);
+void nd6_na_output_unsolicited_addr(struct ifnet *, const struct in6_addr *,
+ u_long);
+int nd6_na_unsolicited_addr_delay(struct ifaddr *);
struct nd_ifinfo *nd6_ifattach(struct ifnet *);
void nd6_ifdetach(struct nd_ifinfo *);
int nd6_is_addr_neighbor(const struct sockaddr_in6 *, struct ifnet *);
Index: sys/netinet6/nd6.c
===================================================================
--- sys/netinet6/nd6.c
+++ sys/netinet6/nd6.c
@@ -38,6 +38,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/callout.h>
+#include <sys/random.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
@@ -112,6 +113,7 @@
#endif
static eventhandler_tag lle_event_eh;
+static eventhandler_tag ifnet_link_event_eh;
/* for debugging? */
#if 0
@@ -196,6 +198,13 @@
type == RTM_ADD ? RTF_UP: 0), 0, RT_DEFAULT_FIB);
}
+static void
+nd6_ifnet_link_event(void *arg __unused, struct ifnet *ifp, int linkstate)
+{
+
+ if (linkstate == LINK_STATE_UP)
+ nd6_na_output_unsolicited(ifp);
+}
void
nd6_init(void)
{
@@ -211,9 +220,12 @@
nd6_slowtimo, curvnet);
nd6_dad_init();
- if (IS_DEFAULT_VNET(curvnet))
+ if (IS_DEFAULT_VNET(curvnet)) {
lle_event_eh = EVENTHANDLER_REGISTER(lle_event, nd6_lle_event,
NULL, EVENTHANDLER_PRI_ANY);
+ ifnet_link_event_eh = EVENTHANDLER_REGISTER(ifnet_link_event,
+ nd6_ifnet_link_event, NULL, EVENTHANDLER_PRI_ANY);
+ }
}
#ifdef VIMAGE
@@ -223,8 +235,10 @@
callout_drain(&V_nd6_slowtimo_ch);
callout_drain(&V_nd6_timer_ch);
- if (IS_DEFAULT_VNET(curvnet))
+ if (IS_DEFAULT_VNET(curvnet)) {
EVENTHANDLER_DEREGISTER(lle_event, lle_event_eh);
+ EVENTHANDLER_DEREGISTER(ifnet_link_event, ifnet_link_event_eh);
+ }
}
#endif
Index: sys/netinet6/nd6_nbr.c
===================================================================
--- sys/netinet6/nd6_nbr.c
+++ sys/netinet6/nd6_nbr.c
@@ -124,20 +124,16 @@
struct in6_addr saddr6 = ip6->ip6_src;
struct in6_addr daddr6 = ip6->ip6_dst;
struct in6_addr taddr6;
- struct in6_addr myaddr6;
char *lladdr = NULL;
struct ifaddr *ifa = NULL;
+ u_long flags;
int lladdrlen = 0;
- int anycast = 0, proxy = 0, tentative = 0;
+ int proxy = 0;
int tlladdr;
- int rflag;
union nd_opts ndopts;
struct sockaddr_dl proxydl;
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
- rflag = (V_ip6_forwarding) ? ND_NA_FLAG_ROUTER : 0;
- if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV && V_ip6_norbit_raif)
- rflag = 0;
#ifndef PULLDOWN_TEST
IP6_EXTHDR_CHECK(m, off, icmp6len,);
nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off);
@@ -229,10 +225,7 @@
* In implementation, we add target link-layer address by default.
* We do not add one in MUST NOT cases.
*/
- if (!IN6_IS_ADDR_MULTICAST(&daddr6))
- tlladdr = 0;
- else
- tlladdr = 1;
+ tlladdr = !IN6_IS_ADDR_MULTICAST(&daddr6);
/*
* Target address (taddr6) must be either:
@@ -289,9 +282,6 @@
*/
goto freeit;
}
- myaddr6 = *IFA_IN6(ifa);
- anycast = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST;
- tentative = ((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE;
if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DUPLICATED)
goto freeit;
@@ -303,7 +293,7 @@
goto bad;
}
- if (IN6_ARE_ADDR_EQUAL(&myaddr6, &saddr6)) {
+ if (IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &saddr6)) {
nd6log((LOG_INFO, "nd6_ns_input: duplicate IP6 address %s\n",
ip6_sprintf(ip6bufs, &saddr6)));
goto freeit;
@@ -321,7 +311,7 @@
*
* The processing is defined in RFC 2462.
*/
- if (tentative) {
+ if (IFA_IN6_FLAGS(ifa) & IN6_IFF_TENTATIVE) {
/*
* If source address is unspecified address, it is for
* duplicate address detection.
@@ -335,6 +325,10 @@
goto freeit;
}
+ flags = IFA_ND6_NA_BASE_FLAGS(ifp, ifa);
+ if (proxy || !tlladdr)
+ flags &= ~ND_NA_FLAG_OVERRIDE;
+
/*
* If the source address is unspecified address, entries must not
* be created or updated.
@@ -349,20 +343,16 @@
in6_all = in6addr_linklocal_allnodes;
if (in6_setscope(&in6_all, ifp, NULL) != 0)
goto bad;
- nd6_na_output_fib(ifp, &in6_all, &taddr6,
- ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
- M_GETFIB(m));
+ nd6_na_output_fib(ifp, &in6_all, &taddr6, flags, tlladdr,
+ proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
goto freeit;
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
ND_NEIGHBOR_SOLICIT, 0);
- nd6_na_output_fib(ifp, &saddr6, &taddr6,
- ((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- rflag | ND_NA_FLAG_SOLICITED, tlladdr,
- proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
+ nd6_na_output_fib(ifp, &saddr6, &taddr6, flags | ND_NA_FLAG_SOLICITED,
+ tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
freeit:
if (ifa != NULL)
ifa_free(ifa);
@@ -1589,3 +1579,99 @@
nd6_dad_rele(dp);
}
}
+
+/*
+ * Send unsolicited neighbor advertisements for all interface addresses to
+ * notify other nodes of changes.
+ *
+ * This is a noop if the interface isn't up.
+ */
+void __noinline
+nd6_na_output_unsolicited(struct ifnet *ifp)
+{
+ int i, cnt, entries;
+ struct ifaddr *ifa;
+ struct ann {
+ struct in6_addr addr;
+ u_long flags;
+ int delay;
+ } *ann1, *head;
+
+ if (!(ifp->if_flags & IFF_UP))
+ return;
+
+ entries = 8;
+ cnt = 0;
+ head = malloc(sizeof(struct ann) * entries, M_TEMP, M_WAITOK);
+
+ /* Take a copy then process to avoid locking issues. */
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6 ||
+ IFA_ND6_NA_UNSOLICITED_SKIP(ifa))
+ continue;
+
+ if (cnt == entries) {
+ ann1 = (struct ann*)realloc(head, sizeof(struct ann) *
+ (entries + 8), M_TEMP, M_NOWAIT);
+ if (ann1 == NULL) {
+ log(LOG_INFO, "nd6_announce: realloc to %d "
+ "entries failed\n", entries + 8);
+ /* Process what we have. */
+ break;
+ }
+ entries += 8;
+ head = ann1;
+ }
+
+ ann1 = head + cnt;
+ bcopy(IFA_IN6(ifa), &ann1->addr, sizeof(ann1->addr));
+ ann1->flags = IFA_ND6_NA_BASE_FLAGS(ifp, ifa);
+ ann1->delay = nd6_na_unsolicited_addr_delay(ifa);
+ cnt++;
+ }
+ IF_ADDR_RUNLOCK(ifp);
+
+ for (i = 0; i < cnt;) {
+ ann1 = head + i;
+ nd6_na_output_unsolicited_addr(ifp, &ann1->addr, ann1->flags);
+ i++;
+ if (i == cnt)
+ break;
+ DELAY(ann1->delay);
+ }
+ free(head, M_TEMP);
+}
+
+/*
+ * Return the delay required for announcements of the address as per RFC 4861.
+ */
+int
+nd6_na_unsolicited_addr_delay(struct ifaddr *ifa)
+{
+
+ if (IFA_IN6_FLAGS(ifa) & IN6_IFF_ANYCAST) {
+ /*
+ * Random value between 0 and MAX_ANYCAST_DELAY_TIME
+ * as per section 7.2.7.
+ */
+ return (random() % IN6_MAX_ANYCAST_DELAY_TIME_MS);
+ }
+
+ /* Small delay as per section 7.2.6. */
+ return (IN6_BROADCAST_DELAY_TIME_MS);
+}
+
+/*
+ * Send an unsolicited neighbor advertisement for an address to notify other
+ * nodes of changes.
+ */
+void
+nd6_na_output_unsolicited_addr(struct ifnet *ifp, const struct in6_addr *addr,
+ u_long flags)
+{
+
+ nd6_na_output(ifp, &in6addr_linklocal_allnodes, addr, flags, 1, NULL);
+}
+
+
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Feb 16, 4:36 AM (11 h, 39 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28766857
Default Alt Text
D4111.id10146.diff (18 KB)
Attached To
Mode
D4111: Fix lagg failover mode caused by missing node notifications
Attached
Detach File
Event Timeline
Log In to Comment