]> git.puffer.fish Git - matthieu/frr.git/commitdiff
Zebra: Update/fix router_lifetime in IPv6 RAs
authorvivek <vivek@cumulusnetworks.com>
Tue, 3 May 2016 19:10:22 +0000 (12:10 -0700)
committervivek <vivek@cumulusnetworks.com>
Tue, 3 May 2016 19:10:22 +0000 (12:10 -0700)
BGP Unnumbered relies on IPv6 Router Advertisements (RAs) to advertise our
link-local IPv6 address and learn of the peer's address in order to initiate
the BGP peering. When IPv6 RAs are enabled on an interface, Quagga currently
advertises a non-zero router lifetime which causes hosts receiving the RAs
to install the router as the default router. This may not be desirable in
many situations - the IPv6 RAs may be turned on just to get BGP unnumbered
peering up.

There is a sysctl available to control the host behavior (net.ipv6.conf.all.
accept_ra_defrtr). However, this requires setting on all hosts and this may
mean many hosts, especially if Quagga is run on the hosts.

An alternate solution arrived at was to modify Quagga to advertise a zero
router lifetime, unless a value is specifically set by the operator. This
patch implements this change. The change may not meet a strict interpretation
of the RFC, so it is under HAVE_CUMULUS. When hosts see an IPv6 RA with a
router lifetime of 0, they won't make that router a default router. The
patch also fixes an incorrect check in handling of received RAs which would
have caused us to drop RAs with a lifetime of 0.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Daniel Walton <dwalton@cumulusnetworks.com>
Ticket: CM-9815
Reviewed By: CCR-4611
Testing Done: Manual, bgp-min etc. (defails in defect)

zebra/rtadv.c
zebra/zserv.c
zebra/zserv.h

index 9179701302d2734ace14f8538eeb997088855ef3..003459dd5fc8247cf2af4571e616cdbe5281135f 100644 (file)
@@ -189,8 +189,14 @@ rtadv_send_packet (int sock, struct interface *ifp)
   rtadv->nd_ra_curhoplimit = 64;
 
   /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
+#if defined(HAVE_CUMULUS)
+  /* Uninitialized (default) lifetime means 0. */
+  rtadv->nd_ra_flags_reserved =
+    zif->rtadv.AdvDefaultLifetime <= 0 ? 0 : zif->rtadv.DefaultPreference;
+#else
   rtadv->nd_ra_flags_reserved =
     zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference;
+#endif
   rtadv->nd_ra_flags_reserved <<= 3;
 
   if (zif->rtadv.AdvManagedFlag)
@@ -207,9 +213,15 @@ rtadv_send_packet (int sock, struct interface *ifp)
    * value for this field.  To prevent this, routers SHOULD keep
    * AdvDefaultLifetime in at least one second, even if the use of
    * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
+#if defined(HAVE_CUMULUS)
+  /* Uninitialized (default) lifetime means 0. */
+  pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ?
+    zif->rtadv.AdvDefaultLifetime : 0;
+#else
   pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ?
     zif->rtadv.AdvDefaultLifetime :
     MAX (1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
+#endif
   rtadv->nd_ra_router_lifetime = htons (pkt_RouterLifetime);
   rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
   rtadv->nd_ra_retransmit = htonl (0);
@@ -448,6 +460,7 @@ rtadv_process_advert (u_char *msg, unsigned int len, struct interface *ifp,
   struct nd_router_advert *radvert;
   char addr_str[INET6_ADDRSTRLEN];
   struct zebra_if *zif;
+  struct prefix p;
 
   zif = ifp->info;
 
@@ -501,15 +514,13 @@ rtadv_process_advert (u_char *msg, unsigned int len, struct interface *ifp,
                 ifp->name, ifp->ifindex, addr_str);
     }
 
-  /* Currently supporting only P2P links, so any new RA source address is
-     considered as the replacement of the previously learnt Link-Local address.
-     As per the RFC, lifetime zero is to be considered a delete */
-  if (ntohs(radvert->nd_ra_router_lifetime))
-     nbr_connected_replacement_add_ipv6(ifp, &addr->sin6_addr, 128);
-  else
-     nbr_connected_delete_ipv6(ifp, &addr->sin6_addr, 128);
+  /* Create entry for neighbor if not known. */
+  p.family = AF_INET6;
+  IPV6_ADDR_COPY (&p.u.prefix, &addr->sin6_addr);
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
 
-  return;
+  if (!nbr_connected_check(ifp, &p))
+    nbr_connected_add_ipv6 (ifp, &addr->sin6_addr);
 }
 
 
index 9491b39a91d0dc870c4255ae65600e3326d512bd..c31a0b6a9e1743da20bf02bd9aa174e7d5a136bf 100644 (file)
@@ -471,21 +471,16 @@ zsend_interface_vrf_update (struct zserv *client, struct interface *ifp,
   return zebra_server_send_message(client);
 }
 
-/* Add new nbr connected IPv6 address if none exists already, or replace the
-   existing one if an ifc entry is found on the interface. */
+/* Add new nbr connected IPv6 address */
 void
-nbr_connected_replacement_add_ipv6 (struct interface *ifp, struct in6_addr *address,
-                                    u_char prefixlen)
+nbr_connected_add_ipv6 (struct interface *ifp, struct in6_addr *address)
 {
   struct nbr_connected *ifc;
   struct prefix p;
 
   p.family = AF_INET6;
   IPV6_ADDR_COPY (&p.u.prefix, address);
-  p.prefixlen = prefixlen;
-
-  if (nbr_connected_check(ifp, &p))
-    return;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
 
   if (!(ifc = listnode_head(ifp->nbr_connected)))
     {
@@ -504,15 +499,14 @@ nbr_connected_replacement_add_ipv6 (struct interface *ifp, struct in6_addr *addr
 }
 
 void
-nbr_connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
-                           u_char prefixlen)
+nbr_connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address)
 {
   struct nbr_connected *ifc;
   struct prefix p;
 
   p.family = AF_INET6;
   IPV6_ADDR_COPY (&p.u.prefix, address);
-  p.prefixlen = prefixlen;
+  p.prefixlen = IPV6_MAX_PREFIXLEN;
 
   ifc = nbr_connected_check(ifp, &p);
   if (!ifc)
index 3fa344051979e62c8984c0c10db4e70af47ac1c7..e055672990b53958db87c4b9ed1d89ff4b93ef66 100644 (file)
@@ -155,9 +155,8 @@ extern int zsend_interface_delete (struct zserv *, struct interface *);
 extern int zsend_interface_addresses (struct zserv *, struct interface *);
 extern int zsend_interface_address (int, struct zserv *, struct interface *,
                                     struct connected *);
-extern void nbr_connected_replacement_add_ipv6 (struct interface *,
-                                                struct in6_addr *, u_char);
-extern void nbr_connected_delete_ipv6 (struct interface *, struct in6_addr *, u_char);
+extern void nbr_connected_add_ipv6 (struct interface *, struct in6_addr *);
+extern void nbr_connected_delete_ipv6 (struct interface *, struct in6_addr *);
 extern int zsend_interface_update (int, struct zserv *, struct interface *);
 extern int zsend_redistribute_route (int, struct zserv *, struct prefix *,
                                     struct rib *);