From: Don Slice Date: Mon, 10 Feb 2020 18:58:41 +0000 (+0000) Subject: zebra: add all ipv6 global addresses to RA messages X-Git-Tag: base_7.4~352^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=2a85576310187cd6f4e43849e028faed986b551b;p=matthieu%2Ffrr.git zebra: add all ipv6 global addresses to RA messages RFC 4861 states that ipv6 RA messages sent out an interface should contain all global ipv6 addresses on that interface. This fix adds that capability. To override the default flags and timer settings for a particular prefix, the existing "ipv6 nd prefix ..." command should be used via vtysh under the appropriate interface. Ticket: CM-20363 Signed-off-by: Don Slice --- diff --git a/zebra/connected.c b/zebra/connected.c index 0ff474d787..0ee41afa8f 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -490,6 +490,10 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, p->prefixlen = prefixlen; ifc->address = (struct prefix *)p; + /* Add global ipv6 address to the RA prefix list */ + if (!IN6_IS_ADDR_LINKLOCAL(&p->prefix)) + rtadv_add_prefix(ifp->info, p); + if (dest) { p = prefix_ipv6_new(); p->family = AF_INET6; @@ -533,6 +537,10 @@ void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, memcpy(&p.u.prefix6, address, sizeof(struct in6_addr)); p.prefixlen = prefixlen; + /* Delete global ipv6 address from RA prefix list */ + if (!IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) + rtadv_delete_prefix(ifp->info, &p); + if (dest) { memset(&d, 0, sizeof(struct prefix)); d.family = AF_INET6; diff --git a/zebra/rtadv.c b/zebra/rtadv.c index e9a97d4b15..e36af00b4e 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -876,18 +876,48 @@ static struct rtadv_prefix *rtadv_prefix_get(struct list *rplist, return rprefix; } +static void rtadv_prefix_set_defaults(struct rtadv_prefix *rp) +{ + rp->AdvAutonomousFlag = 1; + rp->AdvOnLinkFlag = 1; + rp->AdvRouterAddressFlag = 0; + rp->AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; + rp->AdvValidLifetime = RTADV_VALID_LIFETIME; +} + static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp) { struct rtadv_prefix *rprefix; rprefix = rtadv_prefix_get(zif->rtadv.AdvPrefixList, &rp->prefix); - /* Set parameters. */ - rprefix->AdvValidLifetime = rp->AdvValidLifetime; - rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime; - rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag; - rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag; - rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag; + /* + * Set parameters based on where the prefix is created. + * If auto-created based on kernel address addition, set the + * default values. If created from a manual "ipv6 nd prefix" + * command, take the parameters from the manual command. Note + * that if the manual command exists, the default values will + * not overwrite the manual values. + */ + if (rp->AdvPrefixCreate == PREFIX_SRC_MANUAL) { + if (rprefix->AdvPrefixCreate == PREFIX_SRC_AUTO) + rprefix->AdvPrefixCreate = PREFIX_SRC_BOTH; + else + rprefix->AdvPrefixCreate = PREFIX_SRC_MANUAL; + + rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag; + rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag; + rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag; + rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime; + rprefix->AdvValidLifetime = rp->AdvValidLifetime; + } else if (rp->AdvPrefixCreate == PREFIX_SRC_AUTO) { + if (rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL) + rprefix->AdvPrefixCreate = PREFIX_SRC_BOTH; + else { + rprefix->AdvPrefixCreate = PREFIX_SRC_AUTO; + rtadv_prefix_set_defaults(rprefix); + } + } } static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp) @@ -896,6 +926,27 @@ static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp) rprefix = rtadv_prefix_lookup(zif->rtadv.AdvPrefixList, &rp->prefix); if (rprefix != NULL) { + + /* + * When deleting an address from the list, need to take care + * it wasn't defined both automatically via kernel + * address addition as well as manually by vtysh cli. If both, + * we don't actually delete but may change the parameters + * back to default if a manually defined entry is deleted. + */ + if (rp->AdvPrefixCreate == PREFIX_SRC_MANUAL) { + if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) { + rprefix->AdvPrefixCreate = PREFIX_SRC_AUTO; + rtadv_prefix_set_defaults(rprefix); + return 1; + } + } else if (rp->AdvPrefixCreate == PREFIX_SRC_AUTO) { + if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) { + rprefix->AdvPrefixCreate = PREFIX_SRC_MANUAL; + return 1; + } + } + listnode_delete(zif->rtadv.AdvPrefixList, (void *)rprefix); rtadv_prefix_free(rprefix); return 1; @@ -903,6 +954,28 @@ static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp) return 0; } +/* Add IPv6 prefixes learned from the kernel to the RA prefix list */ +void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p) +{ + struct rtadv_prefix rp; + + rp.prefix = *p; + apply_mask_ipv6(&rp.prefix); + rp.AdvPrefixCreate = PREFIX_SRC_AUTO; + rtadv_prefix_set(zif, &rp); +} + +/* Delete IPv6 prefixes removed by the kernel from the RA prefix list */ +void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p) +{ + struct rtadv_prefix rp; + + rp.prefix = *((struct prefix_ipv6 *)p); + apply_mask_ipv6(&rp.prefix); + rp.AdvPrefixCreate = PREFIX_SRC_AUTO; + rtadv_prefix_reset(zif, &rp); +} + static void ipv6_nd_suppress_ra_set(struct interface *ifp, ipv6_nd_suppress_ra_status status) { @@ -1601,6 +1674,7 @@ DEFUN (ipv6_nd_prefix, rp.AdvRouterAddressFlag = routeraddr; rp.AdvValidLifetime = RTADV_VALID_LIFETIME; rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME; + rp.AdvPrefixCreate = PREFIX_SRC_MANUAL; if (lifetimes) { rp.AdvValidLifetime = strmatch(lifetime, "infinite") @@ -1651,6 +1725,7 @@ DEFUN (no_ipv6_nd_prefix, return CMD_WARNING_CONFIG_FAILED; } apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */ + rp.AdvPrefixCreate = PREFIX_SRC_MANUAL; ret = rtadv_prefix_reset(zebra_if, &rp); if (!ret) { @@ -2182,29 +2257,34 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU); for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) { - vty_out(vty, " ipv6 nd prefix %s", - prefix2str(&rprefix->prefix, buf, sizeof(buf))); - if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) - || (rprefix->AdvPreferredLifetime - != RTADV_PREFERRED_LIFETIME)) { - if (rprefix->AdvValidLifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", rprefix->AdvValidLifetime); - if (rprefix->AdvPreferredLifetime == UINT32_MAX) - vty_out(vty, " infinite"); - else - vty_out(vty, " %u", - rprefix->AdvPreferredLifetime); + if ((rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL) + || (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH)) { + vty_out(vty, " ipv6 nd prefix %s", + prefix2str(&rprefix->prefix, buf, sizeof(buf))); + if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) + || (rprefix->AdvPreferredLifetime + != RTADV_PREFERRED_LIFETIME)) { + if (rprefix->AdvValidLifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", + rprefix->AdvValidLifetime); + if (rprefix->AdvPreferredLifetime == UINT32_MAX) + vty_out(vty, " infinite"); + else + vty_out(vty, " %u", + rprefix->AdvPreferredLifetime); + } + if (!rprefix->AdvOnLinkFlag) + vty_out(vty, " off-link"); + if (!rprefix->AdvAutonomousFlag) + vty_out(vty, " no-autoconfig"); + if (rprefix->AdvRouterAddressFlag) + vty_out(vty, " router-address"); + vty_out(vty, "\n"); } - if (!rprefix->AdvOnLinkFlag) - vty_out(vty, " off-link"); - if (!rprefix->AdvAutonomousFlag) - vty_out(vty, " no-autoconfig"); - if (rprefix->AdvRouterAddressFlag) - vty_out(vty, " router-address"); - vty_out(vty, "\n"); } + for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) { char buf[INET6_ADDRSTRLEN]; diff --git a/zebra/rtadv.h b/zebra/rtadv.h index 63cec94434..64b28cbfd6 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -37,6 +37,9 @@ struct rtadv_prefix { /* Prefix to be advertised. */ struct prefix_ipv6 prefix; + /* The prefix was manually/automatically defined. */ + int AdvPrefixCreate; + /* The value to be placed in the Valid Lifetime in the Prefix */ uint32_t AdvValidLifetime; #define RTADV_VALID_LIFETIME 2592000 @@ -133,6 +136,17 @@ struct nd_opt_dnssl { /* DNS search list option [RFC8106 5.2] */ #endif /* HAVE_RTADV */ +/* + * ipv6 nd prefixes can be manually defined, derived from the kernel interface + * configs or both. If both, manual flag/timer settings are used. + */ +enum ipv6_nd_prefix_source { + PREFIX_SRC_NONE = 0, + PREFIX_SRC_MANUAL, + PREFIX_SRC_AUTO, + PREFIX_SRC_BOTH, +}; + typedef enum { RA_ENABLE = 0, RA_SUPPRESS, @@ -145,6 +159,8 @@ extern void rtadv_stop_ra_all(void); extern void rtadv_cmd_init(void); extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS); extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS); +extern void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p); +extern void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p); #ifdef __cplusplus }