2121#include "vrf.h"
2222#include "ns.h"
2323#include "lib_errors.h"
24+ #include "wheel.h"
25+ #include "network.h"
2426
2527#include "zebra/interface.h"
2628#include "zebra/rtadv.h"
@@ -36,6 +38,19 @@ extern struct zebra_privs_t zserv_privs;
3638static uint32_t interfaces_configured_for_ra_from_bgp ;
3739#define RTADV_ADATA_SIZE 1024
3840
41+ #define PROC_IGMP6 "/proc/net/igmp6"
42+
43+ /* 32 hex chars
44+ * say for 2001:db8:85a3::8a2e:370:7334
45+ * hex string is 20010db885a3000000008a2e03707334,
46+ * which is 32 chars long
47+ */
48+ #define MAX_V6ADDR_LEN 32
49+
50+ #define MAX_INTERFACE_NAME_LEN 25
51+
52+ #define MAX_CHARS_PER_LINE 1024
53+
3954#if defined(HAVE_RTADV )
4055
4156#include "zebra/rtadv_clippy.c"
@@ -58,6 +73,12 @@ DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface");
5873#define ALLNODE "ff02::1"
5974#define ALLROUTER "ff02::2"
6075
76+ static bool is_interface_in_group (const char * ifname_in , const char * mcast_addr_in );
77+
78+ #ifdef __linux__
79+ static bool v6_addr_hex_str_to_in6_addr (const char * hex_str , struct in6_addr * addr );
80+ #endif
81+
6182/* adv list node */
6283struct adv_if {
6384 char name [IFNAMSIZ ];
@@ -462,6 +483,60 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
462483 zif -> ra_sent ++ ;
463484}
464485
486+ static void start_icmpv6_join_timer (struct event * thread )
487+ {
488+ struct interface * ifp = EVENT_ARG (thread );
489+ struct zebra_if * zif = ifp -> info ;
490+ struct zebra_vrf * zvrf = rtadv_interface_get_zvrf (ifp );
491+
492+ if (if_join_all_router (zvrf -> rtadv .sock , ifp )) {
493+ /*Wait random amount of time between 1 ms to ICMPV6_JOIN_TIMER_EXP_MS ms*/
494+ int random_ms = (frr_weak_random () % ICMPV6_JOIN_TIMER_EXP_MS ) + 1 ;
495+ event_add_timer_msec (zrouter .master , start_icmpv6_join_timer , ifp , random_ms ,
496+ & zif -> icmpv6_join_timer );
497+ }
498+
499+ if (IS_ZEBRA_DEBUG_EVENT )
500+ zlog_debug ("Processing ICMPv6 join on interface %s(%s:%u)" , ifp -> name ,
501+ ifp -> vrf -> name , ifp -> ifindex );
502+ }
503+
504+ void process_rtadv (void * arg )
505+ {
506+ struct interface * ifp = arg ;
507+ struct zebra_if * zif = ifp -> info ;
508+ struct zebra_vrf * zvrf = rtadv_interface_get_zvrf (ifp );
509+
510+ if (zif -> rtadv .inFastRexmit && zif -> rtadv .UseFastRexmit ) {
511+ if (-- zif -> rtadv .NumFastReXmitsRemain <= 0 )
512+ zif -> rtadv .inFastRexmit = 0 ;
513+
514+ if (IS_ZEBRA_DEBUG_SEND )
515+ zlog_debug ("Doing fast RA Rexmit on interface %s(%s:%u)" , ifp -> name ,
516+ ifp -> vrf -> name , ifp -> ifindex );
517+
518+ rtadv_send_packet (zvrf -> rtadv .sock , ifp , RA_ENABLE );
519+ } else {
520+ zif -> rtadv .AdvIntervalTimer -= RTADV_TIMER_WHEEL_PERIOD_MS ;
521+ /* Wait atleast AdvIntervalTimer time before sending next RA
522+ * AdvIntervalTimer can go negative, when ra_wheel timer expiry
523+ * interval is not a multiple of AdvIntervalTimer. Say ra_wheel
524+ * expiry time is 10 ms and, AdvIntervalTimer == 1005 ms. Allowing
525+ * AdvIntervalTimer to go negative and checking, gurantees that
526+ * we have waited Wait atleast AdvIntervalTimer, so RA can be
527+ * sent now.
528+ */
529+ if (zif -> rtadv .AdvIntervalTimer <= 0 ) {
530+ zif -> rtadv .AdvIntervalTimer = zif -> rtadv .MaxRtrAdvInterval ;
531+ if (IS_ZEBRA_DEBUG_SEND )
532+ zlog_debug ("Doing regular RA Rexmit on interface %s(%s:%u)" ,
533+ ifp -> name , ifp -> vrf -> name , ifp -> ifindex );
534+
535+ rtadv_send_packet (zvrf -> rtadv .sock , ifp , RA_ENABLE );
536+ }
537+ }
538+ }
539+
465540static void rtadv_timer (struct event * thread )
466541{
467542 struct zebra_vrf * zvrf = EVENT_ARG (thread );
@@ -1261,7 +1336,13 @@ static void rtadv_start_interface_events(struct zebra_vrf *zvrf,
12611336 if (adv_if != NULL )
12621337 return ; /* Already added */
12631338
1264- if_join_all_router (zvrf -> rtadv .sock , zif -> ifp );
1339+ if (if_join_all_router (zvrf -> rtadv .sock , zif -> ifp )) {
1340+ /*Failed to join on 1st attempt, wait random amount of time between 1 ms
1341+ to ICMPV6_JOIN_TIMER_EXP_MS ms*/
1342+ int random_ms = (frr_weak_random () % ICMPV6_JOIN_TIMER_EXP_MS ) + 1 ;
1343+ event_add_timer_msec (zrouter .master , start_icmpv6_join_timer , zif -> ifp , random_ms ,
1344+ & zif -> icmpv6_join_timer );
1345+ }
12651346
12661347 if (adv_if_list_count (& zvrf -> rtadv .adv_if ) == 1 )
12671348 rtadv_event (zvrf , RTADV_START , 0 );
@@ -1281,6 +1362,8 @@ void ipv6_nd_suppress_ra_set(struct interface *ifp,
12811362 if (status == RA_SUPPRESS ) {
12821363 /* RA is currently enabled */
12831364 if (zif -> rtadv .AdvSendAdvertisements ) {
1365+ /* Try to delete from the ra wheel */
1366+ wheel_remove_item (zrouter .ra_wheel , ifp );
12841367 rtadv_send_packet (zvrf -> rtadv .sock , ifp , RA_SUPPRESS );
12851368 zif -> rtadv .AdvSendAdvertisements = 0 ;
12861369 zif -> rtadv .AdvIntervalTimer = 0 ;
@@ -1311,6 +1394,7 @@ void ipv6_nd_suppress_ra_set(struct interface *ifp,
13111394 RTADV_NUM_FAST_REXMITS ;
13121395 }
13131396
1397+ wheel_add_item (zrouter .ra_wheel , ifp );
13141398 rtadv_start_interface_events (zvrf , zif );
13151399 }
13161400 }
@@ -1438,6 +1522,12 @@ void rtadv_stop_ra(struct interface *ifp)
14381522 zif = ifp -> info ;
14391523 zvrf = rtadv_interface_get_zvrf (ifp );
14401524
1525+ /*Try to delete from ra wheels */
1526+ wheel_remove_item (zrouter .ra_wheel , ifp );
1527+
1528+ /*Turn off event for ICMPv6 join*/
1529+ EVENT_OFF (zif -> icmpv6_join_timer );
1530+
14411531 if (zif -> rtadv .AdvSendAdvertisements )
14421532 rtadv_send_packet (zvrf -> rtadv .sock , ifp , RA_SUPPRESS );
14431533}
@@ -1730,8 +1820,7 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
17301820 case RTADV_START :
17311821 event_add_read (zrouter .master , rtadv_read , zvrf , rtadv -> sock ,
17321822 & rtadv -> ra_read );
1733- event_add_event (zrouter .master , rtadv_timer , zvrf , 0 ,
1734- & rtadv -> ra_timer );
1823+
17351824 break ;
17361825 case RTADV_STOP :
17371826 EVENT_OFF (rtadv -> ra_timer );
@@ -1862,24 +1951,114 @@ void rtadv_cmd_init(void)
18621951 install_element (VIEW_NODE , & show_ipv6_nd_ra_if_cmd );
18631952}
18641953
1954+ #ifdef __linux__
1955+ static bool v6_addr_hex_str_to_in6_addr (const char * hex_str , struct in6_addr * addr )
1956+ {
1957+ size_t str_len = strlen (hex_str );
1958+
1959+ if (str_len != MAX_V6ADDR_LEN ) {
1960+ flog_err_sys (EC_LIB_SYSTEM_CALL , "Invalid V6 addr hex len %zu" , str_len );
1961+ return false;
1962+ }
1963+
1964+ for (int i = 0 ; i < 16 ; i ++ ) {
1965+ char byte_str [3 ] = { hex_str [i * 2 ], hex_str [i * 2 + 1 ], '\0' };
1966+ addr -> s6_addr [i ] = (uint8_t )strtol (byte_str , NULL , 16 );
1967+ }
1968+
1969+ return true;
1970+ }
1971+ #endif
1972+
1973+ /* Checks if an interface is part of a multicast group, no null check for input strings */
1974+ static bool is_interface_in_group (const char * ifname_in , const char * mcast_addr_in )
1975+ {
1976+ #ifdef __linux__
1977+ char line [MAX_CHARS_PER_LINE ];
1978+ char ifname_found [MAX_INTERFACE_NAME_LEN ];
1979+ char mcast_addr_found_hex_str [MAX_V6ADDR_LEN + 5 ];
1980+ struct in6_addr mcast_addr_in_bin ;
1981+ struct in6_addr mcast_addr_found_bin ;
1982+ int if_index = -1 ;
1983+ int ifname_in_len = 0 ;
1984+ int ifname_found_len = 0 ;
1985+
1986+ FILE * fp = fopen (PROC_IGMP6 , "r" );
1987+
1988+ if (!fp ) {
1989+ flog_err_sys (EC_LIB_SYSTEM_CALL , "Failed to open %s" , PROC_IGMP6 );
1990+ return false;
1991+ }
1992+
1993+ /* Convert input IPv6 address to binary */
1994+ if (inet_pton (AF_INET6 , mcast_addr_in , & mcast_addr_in_bin ) != 1 ) {
1995+ flog_err_sys (EC_LIB_SYSTEM_CALL , "Invalid IPv6 address format %s" , mcast_addr_in );
1996+ fclose (fp );
1997+ return false;
1998+ }
1999+
2000+ /* Convert binary to hex format */
2001+ while (fgets (line , sizeof (line ), fp )) {
2002+ sscanf (line , "%d %s %s" , & if_index , ifname_found , mcast_addr_found_hex_str );
2003+
2004+ ifname_in_len = strlen (ifname_in );
2005+ ifname_found_len = strlen (ifname_found );
2006+ if (ifname_in_len != ifname_found_len )
2007+ continue ;
2008+
2009+ /* Locate 'x' if "0x" is present or not, if present go past that */
2010+ const char * clean_mcast_addr_hex_str = strchr (mcast_addr_found_hex_str , 'x' );
2011+ if (clean_mcast_addr_hex_str ) {
2012+ clean_mcast_addr_hex_str ++ ;
2013+ } else {
2014+ clean_mcast_addr_hex_str = mcast_addr_found_hex_str ;
2015+ }
2016+
2017+ if (!v6_addr_hex_str_to_in6_addr (clean_mcast_addr_hex_str , & mcast_addr_found_bin ))
2018+ continue ;
2019+
2020+ if ((!strncmp (ifname_in , ifname_found , ifname_in_len )) &&
2021+ (!IPV6_ADDR_CMP (& mcast_addr_in_bin , & mcast_addr_found_bin ))) {
2022+ fclose (fp );
2023+ /* Already joined */
2024+ return true;
2025+ }
2026+ }
2027+
2028+ fclose (fp );
2029+
2030+ #endif
2031+
2032+ /* Not joined */
2033+ return false;
2034+ }
2035+
18652036static int if_join_all_router (int sock , struct interface * ifp )
18662037{
18672038 int ret ;
18682039
18692040 struct ipv6_mreq mreq ;
18702041
2042+ if (is_interface_in_group (ifp -> name , ALLROUTER ))
2043+ /* Interface is already part of the group, so return sucess */
2044+ return 0 ;
2045+
18712046 memset (& mreq , 0 , sizeof (mreq ));
18722047 inet_pton (AF_INET6 , ALLROUTER , & mreq .ipv6mr_multiaddr );
18732048 mreq .ipv6mr_interface = ifp -> ifindex ;
18742049
18752050 ret = setsockopt (sock , IPPROTO_IPV6 , IPV6_JOIN_GROUP , (char * )& mreq ,
18762051 sizeof (mreq ));
1877- if (ret < 0 )
2052+
2053+ if (ret < 0 ) {
18782054 flog_err_sys (EC_LIB_SOCKET ,
18792055 "%s(%u): Failed to join group, socket %u error %s" ,
18802056 ifp -> name , ifp -> ifindex , sock ,
18812057 safe_strerror (errno ));
18822058
2059+ return ret ;
2060+ }
2061+
18832062 if (IS_ZEBRA_DEBUG_EVENT )
18842063 zlog_debug (
18852064 "%s(%s:%u): Join All-Routers multicast group, socket %u" ,
0 commit comments