]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: add all ipv6 global addresses to RA messages 5811/head
authorDon Slice <dslice@cumulusnetworks.com>
Mon, 10 Feb 2020 18:58:41 +0000 (18:58 +0000)
committerDon Slice <dslice@cumulusnetworks.com>
Fri, 14 Feb 2020 17:03:16 +0000 (17:03 +0000)
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 <dslice@cumulusnetworks.com>
zebra/connected.c
zebra/rtadv.c
zebra/rtadv.h

index 0ff474d7873bf9912302fed34e9cb207af41b0af..0ee41afa8f23ecd5e0f05199c7f7bfb98ac59742 100644 (file)
@@ -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;
index e9a97d4b152cd704726bcf695588854c4466486f..e36af00b4e7bb0318628bab343c61b15d04b2dfb 100644 (file)
@@ -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];
 
index 63cec944341d90ffc9d3ebf7a49eb9831b15f326..64b28cbfd6febc93177cd6b9ad5baab1180b23d5 100644 (file)
@@ -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
 }