From: vivek Date: Tue, 3 May 2016 19:10:22 +0000 (-0700) Subject: Zebra: Update/fix router_lifetime in IPv6 RAs X-Git-Tag: frr-2.0-rc1~941 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=690baa53592320dddee5c729f959150cc9a72699;p=matthieu%2Ffrr.git Zebra: Update/fix router_lifetime in IPv6 RAs 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 Reviewed-by: Daniel Walton Ticket: CM-9815 Reviewed By: CCR-4611 Testing Done: Manual, bgp-min etc. (defails in defect) --- diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 9179701302..003459dd5f 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -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); } diff --git a/zebra/zserv.c b/zebra/zserv.c index 9491b39a91..c31a0b6a9e 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -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) diff --git a/zebra/zserv.h b/zebra/zserv.h index 3fa3440519..e055672990 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -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 *);