ndp: implement delayed anycast and proxy NA
Reviewed by: bms Differential Revision: https://reviews.freebsd.org/D55141
This commit is contained in:
@@ -155,11 +155,13 @@ struct in6_ndifreq {
|
||||
/* ND6 queue flags */
|
||||
#define ND6_QUEUE_FLAG_NEWGUA 0x01 /* new global unicast address event */
|
||||
#define ND6_QUEUE_FLAG_LLADDR 0x02 /* link-layer address change event */
|
||||
#define ND6_QUEUE_FLAG_ANYCAST 0x04 /* delay NA for anycast or proxy address */
|
||||
|
||||
/* protocol constants */
|
||||
#define MAX_RTR_SOLICITATION_DELAY 1 /* 1sec */
|
||||
#define RTR_SOLICITATION_INTERVAL 4 /* 4sec */
|
||||
#define MAX_RTR_SOLICITATIONS 3
|
||||
#define MAX_ANYCAST_DELAY_TIME 1 /* 1sec */
|
||||
|
||||
#define ND6_INFINITE_LIFETIME 0xffffffff
|
||||
|
||||
@@ -373,6 +375,7 @@ void nd6_dad_start(struct ifaddr *, int);
|
||||
void nd6_dad_stop(struct ifaddr *);
|
||||
void nd6_grand_start(struct ifaddr *, uint32_t);
|
||||
void nd6_queue_stop(struct ifaddr *);
|
||||
void nd6_delayed_na_start(struct ifaddr *, struct in6_addr *, u_int, uint32_t);
|
||||
|
||||
/* nd6_rtr.c */
|
||||
void nd6_rs_input(struct mbuf *, int, int);
|
||||
|
||||
+54
-24
@@ -124,6 +124,7 @@ SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_ND6_ONLINKNSRFC4861,
|
||||
struct nd_queue {
|
||||
TAILQ_ENTRY(nd_queue) ndq_list;
|
||||
struct ifaddr *ndq_ifa;
|
||||
struct in6_addr ndq_daddr;
|
||||
uint32_t ndq_flags;
|
||||
struct callout ndq_callout;
|
||||
};
|
||||
@@ -355,8 +356,17 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
|
||||
rflag |= ND_NA_FLAG_SOLICITED;
|
||||
}
|
||||
|
||||
nd6_na_output_fib(ifp, &saddr6, &taddr6, rflag, tlladdr,
|
||||
proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
|
||||
/*
|
||||
* RFC 4861, anycast or proxy NA sent in response to a NS SHOULD
|
||||
* be delayed by a random time between 0 and MAX_ANYCAST_DELAY_TIME
|
||||
* to reduce the probability of network congestion.
|
||||
*/
|
||||
if (anycast == 0 && proxy == 0)
|
||||
nd6_na_output_fib(ifp, &saddr6, &taddr6, rflag, tlladdr,
|
||||
proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
|
||||
else
|
||||
nd6_delayed_na_start(ifa, &saddr6, arc4random() %
|
||||
(MAX_ANYCAST_DELAY_TIME * hz), ND6_QUEUE_FLAG_ANYCAST);
|
||||
freeit:
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
@@ -648,10 +658,6 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *saddr6,
|
||||
*
|
||||
* Based on RFC 2461
|
||||
* Based on RFC 2462 (duplicate address detection)
|
||||
*
|
||||
* the following items are not implemented yet:
|
||||
* - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
|
||||
* - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
|
||||
*/
|
||||
void
|
||||
nd6_na_input(struct mbuf *m, int off, int icmp6len)
|
||||
@@ -966,10 +972,6 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
|
||||
*
|
||||
* Based on RFC 2461
|
||||
*
|
||||
* the following items are not implemented yet:
|
||||
* - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD)
|
||||
* - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD)
|
||||
*
|
||||
* tlladdr:
|
||||
* - 0x01 if include target link-layer address
|
||||
* - 0x02 if target address is CARP MASTER
|
||||
@@ -1669,7 +1671,6 @@ nd6_queue_timer(void *arg)
|
||||
struct ifaddr *ifa = ndq->ndq_ifa;
|
||||
struct ifnet *ifp = ifa->ifa_ifp;
|
||||
struct in6_ifextra *ext = ifp->if_inet6;
|
||||
struct in6_addr taddr6 = IN6ADDR_ANY_INIT;
|
||||
struct epoch_tracker et;
|
||||
int delay, tlladdr;
|
||||
u_long flags;
|
||||
@@ -1685,12 +1686,10 @@ nd6_queue_timer(void *arg)
|
||||
flags &= ~ND_NA_FLAG_ROUTER;
|
||||
|
||||
/*
|
||||
* RFC 9131 Section 6.1.2: if new global address added,
|
||||
* use the all-routers multicast address.
|
||||
* If the address is preferred, then the Override flag SHOULD NOT be set.
|
||||
* RFC 9131 Section 6.1.2: If the address is preferred,
|
||||
* then the Override flag SHOULD NOT be set.
|
||||
*/
|
||||
if ((ndq->ndq_flags & ND6_QUEUE_FLAG_NEWGUA) != 0) {
|
||||
taddr6 = in6addr_linklocal_allrouters;
|
||||
/*
|
||||
* XXX: If the address is in the Optimistic state,
|
||||
* then the Override flag MUST NOT be set.
|
||||
@@ -1700,29 +1699,31 @@ nd6_queue_timer(void *arg)
|
||||
flags |= ND_NA_FLAG_OVERRIDE;
|
||||
}
|
||||
/*
|
||||
* RFC 4891 Section 7.2.6: if link-layer address changed,
|
||||
* use the all-nodes multicast address.
|
||||
* RFC 4861 Section 7.2.6: if link-layer address changed,
|
||||
* The Override flag MAY be set to either zero or one.
|
||||
*/
|
||||
if ((ndq->ndq_flags & ND6_QUEUE_FLAG_LLADDR) != 0) {
|
||||
taddr6 = in6addr_linklocal_allnodes;
|
||||
if ((ndq->ndq_flags & ND6_QUEUE_FLAG_LLADDR) != 0)
|
||||
flags |= ND_NA_FLAG_OVERRIDE;
|
||||
}
|
||||
/* anycast advertisement delay rule (RFC 4861 7.2.7, SHOULD) */
|
||||
if ((ndq->ndq_flags & ND6_QUEUE_FLAG_ANYCAST) != 0)
|
||||
flags |= ND_NA_FLAG_SOLICITED;
|
||||
|
||||
/* Wait at least a RetransTimer before removing from queue */
|
||||
delay = ext->nd_retrans * hz / 1000;
|
||||
callout_reset(&ndq->ndq_callout, delay, nd6_queue_rel, ndq);
|
||||
IF_ADDR_WUNLOCK(ifp);
|
||||
|
||||
if (__predict_true(in6_setscope(&taddr6, ifp, NULL) == 0))
|
||||
nd6_na_output_fib(ifp, &taddr6, IFA_IN6(ifa), flags, tlladdr, NULL, ifp->if_fib);
|
||||
if (__predict_true(in6_setscope(&ndq->ndq_daddr, ifp, NULL) == 0))
|
||||
nd6_na_output_fib(ifp, &ndq->ndq_daddr, IFA_IN6(ifa), flags, tlladdr,
|
||||
NULL, ifp->if_fib);
|
||||
|
||||
NET_EPOCH_EXIT(et);
|
||||
CURVNET_RESTORE();
|
||||
}
|
||||
|
||||
static void
|
||||
nd6_queue_add(struct ifaddr *ifa, int delay, uint32_t flags)
|
||||
nd6_queue_add(struct ifaddr *ifa, struct in6_addr *daddr,
|
||||
int delay, uint32_t flags)
|
||||
{
|
||||
struct nd_queue *ndq;
|
||||
struct ifnet *ifp = ifa->ifa_ifp;
|
||||
@@ -1749,6 +1750,7 @@ nd6_queue_add(struct ifaddr *ifa, int delay, uint32_t flags)
|
||||
|
||||
ndq->ndq_ifa = ifa;
|
||||
ifa_ref(ndq->ndq_ifa);
|
||||
memcpy(&ndq->ndq_daddr, daddr, sizeof(struct in6_addr));
|
||||
ndq->ndq_flags = flags;
|
||||
|
||||
TAILQ_INSERT_TAIL(&ext->nd_queue, ndq, ndq_list);
|
||||
@@ -1765,6 +1767,7 @@ nd6_grand_start(struct ifaddr *ifa, uint32_t flags)
|
||||
{
|
||||
struct nd_queue *ndq;
|
||||
struct in6_ifextra *ext = ifa->ifa_ifp->if_inet6;
|
||||
struct in6_addr daddr = IN6ADDR_ANY_INIT;
|
||||
int delay, count = 0;
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
@@ -1794,8 +1797,22 @@ nd6_grand_start(struct ifaddr *ifa, uint32_t flags)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 9131 Section 6.1.2: if new global address added,
|
||||
* use the all-routers multicast address.
|
||||
*/
|
||||
if ((flags & ND6_QUEUE_FLAG_NEWGUA) != 0)
|
||||
daddr = in6addr_linklocal_allrouters;
|
||||
|
||||
/*
|
||||
* RFC 4861 Section 7.2.6: if link-layer address changed,
|
||||
* use the all-nodes multicast address.
|
||||
*/
|
||||
if ((flags & ND6_QUEUE_FLAG_LLADDR) != 0)
|
||||
daddr = in6addr_linklocal_allnodes;
|
||||
|
||||
delay = ext->nd_retrans * hz / 1000;
|
||||
nd6_queue_add(ifa, count * delay, flags);
|
||||
nd6_queue_add(ifa, &daddr, count * delay, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1817,3 +1834,16 @@ nd6_queue_stop(struct ifaddr *ifa)
|
||||
}
|
||||
IF_ADDR_WUNLOCK(ifa->ifa_ifp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send delayed NA for specified address.
|
||||
* Called by nd6_ns_input for anycast or proxy NA
|
||||
*/
|
||||
void
|
||||
nd6_delayed_na_start(struct ifaddr *ifa, struct in6_addr *daddr,
|
||||
u_int delay, uint32_t flags)
|
||||
{
|
||||
|
||||
NET_EPOCH_ASSERT();
|
||||
nd6_queue_add(ifa, daddr, delay, flags);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user