Skip to content

Commit 716acd9

Browse files
committed
carp6: revise the generation of ND6 NA
* use ND_NA_FLAG_ROUTER flag in carp_send_na() when we work as router. * use in6addr_any as destination address for nd6_na_output(), then it will use ipv6-all-nodes multicast address. * add in6_selectsrc_nbr() function that accepts additional argument ip6_moptions. Use this function from ND6 code to avoid cases when nd6_na_output/nd6_ns_output can not find source address for multicast destinations. * add some comments from RFC2461 for better understanding. * use tlladdr argument as flags and use ND6_NA_OPT_LLA when we need to add target link-layer address option, and ND6_NA_CARP_MASTER when we know that target address is CARP master. Then we can prepare correct CARP's mac address if target address is CARP master. * move blocks of code where multicast options is initialized and use it when destination address is multicast. Reviewed by: kp Obtained from: Yandex LLC MFC after: 2 weeks Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D52825
1 parent 08b497d commit 716acd9

File tree

5 files changed

+119
-89
lines changed

5 files changed

+119
-89
lines changed

sys/netinet/ip_carp.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,18 +1640,31 @@ carp_iamatch(struct ifaddr *ifa, uint8_t **enaddr)
16401640
static void
16411641
carp_send_na(struct carp_softc *sc)
16421642
{
1643-
static struct in6_addr mcast = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
16441643
struct ifaddr *ifa;
1645-
struct in6_addr *in6;
1644+
int flags;
16461645

1646+
/*
1647+
* Sending Unsolicited Neighbor Advertisements
1648+
*
1649+
* If the node is a router, we MUST set the Router flag to one.
1650+
* We set Override flag to one and send link-layer address option,
1651+
* thus neighboring nodes will install the new link-layer address.
1652+
*/
1653+
flags = ND_NA_FLAG_OVERRIDE;
1654+
if (V_ip6_forwarding)
1655+
flags |= ND_NA_FLAG_ROUTER;
16471656
CARP_FOREACH_IFA(sc, ifa) {
16481657
if (ifa->ifa_addr->sa_family != AF_INET6)
16491658
continue;
1650-
1651-
in6 = IFA_IN6(ifa);
1652-
nd6_na_output(sc->sc_carpdev, &mcast, in6,
1653-
ND_NA_FLAG_OVERRIDE, 1, NULL);
1654-
DELAY(1000); /* XXX */
1659+
/*
1660+
* We use unspecified address as destination here to avoid
1661+
* scope initialization for each call.
1662+
* nd6_na_output() will use all nodes multicast address if
1663+
* destinaion address is unspecified.
1664+
*/
1665+
nd6_na_output(sc->sc_carpdev, &in6addr_any, IFA_IN6(ifa),
1666+
flags, ND6_NA_OPT_LLA | ND6_NA_CARP_MASTER, NULL);
1667+
DELAY(1000); /* RetransTimer */
16551668
}
16561669
}
16571670

sys/netinet6/in6_src.c

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ static int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
132132
struct ip6_moptions *, struct ifnet **,
133133
struct ifnet *, u_int);
134134
static int in6_selectsrc(uint32_t, struct sockaddr_in6 *,
135-
struct ip6_pktopts *, struct inpcb *, struct ucred *,
136-
struct ifnet **, struct in6_addr *);
135+
struct ip6_pktopts *, struct ip6_moptions *, struct inpcb *,
136+
struct ucred *, struct ifnet **, struct in6_addr *);
137137

138138
static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
139139

@@ -173,8 +173,8 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
173173

174174
static int
175175
in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
176-
struct ip6_pktopts *opts, struct inpcb *inp, struct ucred *cred,
177-
struct ifnet **ifpp, struct in6_addr *srcp)
176+
struct ip6_pktopts *opts, struct ip6_moptions *mopts, struct inpcb *inp,
177+
struct ucred *cred, struct ifnet **ifpp, struct in6_addr *srcp)
178178
{
179179
struct rm_priotracker in6_ifa_tracker;
180180
struct in6_addr dst, tmp;
@@ -186,7 +186,6 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
186186
u_int32_t odstzone;
187187
int prefer_tempaddr;
188188
int error;
189-
struct ip6_moptions *mopts;
190189

191190
NET_EPOCH_ASSERT();
192191
KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
@@ -205,13 +204,6 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
205204
*ifpp = NULL;
206205
}
207206

208-
if (inp != NULL) {
209-
INP_LOCK_ASSERT(inp);
210-
mopts = inp->in6p_moptions;
211-
} else {
212-
mopts = NULL;
213-
}
214-
215207
/*
216208
* If the source address is explicitly specified by the caller,
217209
* check if the requested source address is indeed a unicast address
@@ -552,10 +544,13 @@ in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
552544
uint32_t fibnum;
553545
int error;
554546

547+
INP_LOCK_ASSERT(inp);
548+
555549
fibnum = inp->inp_inc.inc_fibnum;
556550
retifp = NULL;
557551

558-
error = in6_selectsrc(fibnum, dstsock, opts, inp, cred, &retifp, srcp);
552+
error = in6_selectsrc(fibnum, dstsock, opts, inp->in6p_moptions,
553+
inp, cred, &retifp, srcp);
559554
if (error != 0)
560555
return (error);
561556

@@ -583,7 +578,7 @@ in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
583578
* Stores selected address to @srcp.
584579
* Returns 0 on success.
585580
*
586-
* Used by non-socket based consumers (ND code mostly)
581+
* Used by non-socket based consumers
587582
*/
588583
int
589584
in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst,
@@ -602,13 +597,42 @@ in6_selectsrc_addr(uint32_t fibnum, const struct in6_addr *dst,
602597
dst_sa.sin6_scope_id = scopeid;
603598
sa6_embedscope(&dst_sa, 0);
604599

605-
error = in6_selectsrc(fibnum, &dst_sa, NULL, NULL, NULL, &retifp, srcp);
600+
error = in6_selectsrc(fibnum, &dst_sa, NULL, NULL,
601+
NULL, NULL, &retifp, srcp);
606602
if (hlim != NULL)
607603
*hlim = in6_selecthlim(NULL, retifp);
608604

609605
return (error);
610606
}
611607

608+
/*
609+
* Select source address based on @fibnum, @dst and @mopts.
610+
* Stores selected address to @srcp.
611+
* Returns 0 on success.
612+
*
613+
* Used by non-socket based consumers (ND code mostly)
614+
*/
615+
int
616+
in6_selectsrc_nbr(uint32_t fibnum, const struct in6_addr *dst,
617+
struct ip6_moptions *mopts, struct ifnet *ifp, struct in6_addr *srcp)
618+
{
619+
struct sockaddr_in6 dst_sa;
620+
struct ifnet *retifp;
621+
int error;
622+
623+
retifp = ifp;
624+
bzero(&dst_sa, sizeof(dst_sa));
625+
dst_sa.sin6_family = AF_INET6;
626+
dst_sa.sin6_len = sizeof(dst_sa);
627+
dst_sa.sin6_addr = *dst;
628+
dst_sa.sin6_scope_id = ntohs(in6_getscope(dst));
629+
sa6_embedscope(&dst_sa, 0);
630+
631+
error = in6_selectsrc(fibnum, &dst_sa, NULL, mopts,
632+
NULL, NULL, &retifp, srcp);
633+
return (error);
634+
}
635+
612636
static struct nhop_object *
613637
cache_route(uint32_t fibnum, const struct sockaddr_in6 *dst, struct route_in6 *ro,
614638
uint32_t flowid)

sys/netinet6/ip6_var.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ int in6_selectsrc_socket(struct sockaddr_in6 *, struct ip6_pktopts *,
440440
struct inpcb *, struct ucred *, int, struct in6_addr *, int *);
441441
int in6_selectsrc_addr(uint32_t, const struct in6_addr *,
442442
uint32_t, struct ifnet *, struct in6_addr *, int *);
443+
int in6_selectsrc_nbr(uint32_t, const struct in6_addr *,
444+
struct ip6_moptions *, struct ifnet *, struct in6_addr *);
443445
int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
444446
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
445447
struct nhop_object **, u_int, uint32_t);

sys/netinet6/nd6.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,10 @@ struct in6_ndifreq {
171171
#define NDPRF_ONLINK 0x1
172172
#define NDPRF_DETACHED 0x2
173173

174+
/* ND6 NA output flags */
175+
#define ND6_NA_OPT_LLA 0x01
176+
#define ND6_NA_CARP_MASTER 0x02
177+
174178
/* protocol constants */
175179
#define MAX_RTR_SOLICITATION_DELAY 1 /* 1sec */
176180
#define RTR_SOLICITATION_INTERVAL 4 /* 4sec */

0 commit comments

Comments
 (0)