diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2018-09-19 17:09:18 +0200 |
---|---|---|
committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2018-09-19 17:25:22 +0200 |
commit | 71974bf5612447abbb14971752217e2cf7ee7934 (patch) | |
tree | df0f58111055ecd96c0e577c8545833f12422d67 /zebra/rtadv.c | |
parent | zebra: Abstract mac neigh installation into it's own function (diff) | |
download | frr-71974bf5612447abbb14971752217e2cf7ee7934.tar.xz frr-71974bf5612447abbb14971752217e2cf7ee7934.zip |
zebra: Trust the mac address received in some situations
When we receive a v6 RA packet with an optional
ND_OPT_SOURCE_LINKADDR take that data and construct the
v4 to v6 neighbor entry for that interface to allow
v4 w/ v6 nexthops to work with only global v6 addresses
on an interface.
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
Diffstat (limited to 'zebra/rtadv.c')
-rw-r--r-- | zebra/rtadv.c | 47 |
1 files changed, 42 insertions, 5 deletions
diff --git a/zebra/rtadv.c b/zebra/rtadv.c index f9bd5ad1b..3bb75f344 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -455,6 +455,38 @@ static void rtadv_process_solicit(struct interface *ifp) rtadv_send_packet(zns->rtadv.sock, ifp); } +/* + * This function processes optional attributes off of + * end of a RA packet received. At this point in + * time we only care about this in one situation + * which is when a interface does not have a LL + * v6 address. We still need to be able to install + * the mac address for v4 to v6 resolution + */ +static void rtadv_process_optional(uint8_t *optional, unsigned int len, + struct interface *ifp, + struct sockaddr_in6 *addr) +{ + char *mac; + + while (len > 0) { + struct nd_opt_hdr *opt_hdr = (struct nd_opt_hdr *)optional; + + switch(opt_hdr->nd_opt_type) { + case ND_OPT_SOURCE_LINKADDR: + mac = (char *)(optional+2); + if_nbr_mac_to_ipv4ll_neigh_update(ifp, mac, + &addr->sin6_addr, 1); + break; + default: + break; + } + + len -= 8 * opt_hdr->nd_opt_len; + optional += 8 * opt_hdr->nd_opt_len; + } +} + static void rtadv_process_advert(uint8_t *msg, unsigned int len, struct interface *ifp, struct sockaddr_in6 *addr) @@ -469,14 +501,19 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len, inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN); if (len < sizeof(struct nd_router_advert)) { - zlog_debug("%s(%u): Rx RA with invalid length %d from %s", - ifp->name, ifp->ifindex, len, addr_str); + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s(%u): Rx RA with invalid length %d from %s", + ifp->name, ifp->ifindex, len, addr_str); return; } + if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) { - zlog_debug( - "%s(%u): Rx RA with non-linklocal source address from %s", - ifp->name, ifp->ifindex, addr_str); + rtadv_process_optional(msg + sizeof(struct nd_router_advert), + len - sizeof(struct nd_router_advert), + ifp, addr); + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s(%u): Rx RA with non-linklocal source address from %s", + ifp->name, ifp->ifindex, addr_str); return; } |