21
21
#include "vrf.h"
22
22
#include "ns.h"
23
23
#include "lib_errors.h"
24
+ #include "wheel.h"
25
+ #include "network.h"
24
26
25
27
#include "zebra/interface.h"
26
28
#include "zebra/rtadv.h"
@@ -36,6 +38,19 @@ extern struct zebra_privs_t zserv_privs;
36
38
static uint32_t interfaces_configured_for_ra_from_bgp ;
37
39
#define RTADV_ADATA_SIZE 1024
38
40
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
+
39
54
#if defined(HAVE_RTADV )
40
55
41
56
#include "zebra/rtadv_clippy.c"
@@ -58,6 +73,12 @@ DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface");
58
73
#define ALLNODE "ff02::1"
59
74
#define ALLROUTER "ff02::2"
60
75
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
+
61
82
/* adv list node */
62
83
struct adv_if {
63
84
char name [IFNAMSIZ ];
@@ -462,6 +483,60 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
462
483
zif -> ra_sent ++ ;
463
484
}
464
485
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
+
465
540
static void rtadv_timer (struct event * thread )
466
541
{
467
542
struct zebra_vrf * zvrf = EVENT_ARG (thread );
@@ -1261,7 +1336,13 @@ static void rtadv_start_interface_events(struct zebra_vrf *zvrf,
1261
1336
if (adv_if != NULL )
1262
1337
return ; /* Already added */
1263
1338
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
+ }
1265
1346
1266
1347
if (adv_if_list_count (& zvrf -> rtadv .adv_if ) == 1 )
1267
1348
rtadv_event (zvrf , RTADV_START , 0 );
@@ -1281,6 +1362,8 @@ void ipv6_nd_suppress_ra_set(struct interface *ifp,
1281
1362
if (status == RA_SUPPRESS ) {
1282
1363
/* RA is currently enabled */
1283
1364
if (zif -> rtadv .AdvSendAdvertisements ) {
1365
+ /* Try to delete from the ra wheel */
1366
+ wheel_remove_item (zrouter .ra_wheel , ifp );
1284
1367
rtadv_send_packet (zvrf -> rtadv .sock , ifp , RA_SUPPRESS );
1285
1368
zif -> rtadv .AdvSendAdvertisements = 0 ;
1286
1369
zif -> rtadv .AdvIntervalTimer = 0 ;
@@ -1311,6 +1394,7 @@ void ipv6_nd_suppress_ra_set(struct interface *ifp,
1311
1394
RTADV_NUM_FAST_REXMITS ;
1312
1395
}
1313
1396
1397
+ wheel_add_item (zrouter .ra_wheel , ifp );
1314
1398
rtadv_start_interface_events (zvrf , zif );
1315
1399
}
1316
1400
}
@@ -1438,6 +1522,12 @@ void rtadv_stop_ra(struct interface *ifp)
1438
1522
zif = ifp -> info ;
1439
1523
zvrf = rtadv_interface_get_zvrf (ifp );
1440
1524
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
+
1441
1531
if (zif -> rtadv .AdvSendAdvertisements )
1442
1532
rtadv_send_packet (zvrf -> rtadv .sock , ifp , RA_SUPPRESS );
1443
1533
}
@@ -1730,8 +1820,7 @@ static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
1730
1820
case RTADV_START :
1731
1821
event_add_read (zrouter .master , rtadv_read , zvrf , rtadv -> sock ,
1732
1822
& rtadv -> ra_read );
1733
- event_add_event (zrouter .master , rtadv_timer , zvrf , 0 ,
1734
- & rtadv -> ra_timer );
1823
+
1735
1824
break ;
1736
1825
case RTADV_STOP :
1737
1826
EVENT_OFF (rtadv -> ra_timer );
@@ -1862,24 +1951,114 @@ void rtadv_cmd_init(void)
1862
1951
install_element (VIEW_NODE , & show_ipv6_nd_ra_if_cmd );
1863
1952
}
1864
1953
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
+
1865
2036
static int if_join_all_router (int sock , struct interface * ifp )
1866
2037
{
1867
2038
int ret ;
1868
2039
1869
2040
struct ipv6_mreq mreq ;
1870
2041
2042
+ if (is_interface_in_group (ifp -> name , ALLROUTER ))
2043
+ /* Interface is already part of the group, so return sucess */
2044
+ return 0 ;
2045
+
1871
2046
memset (& mreq , 0 , sizeof (mreq ));
1872
2047
inet_pton (AF_INET6 , ALLROUTER , & mreq .ipv6mr_multiaddr );
1873
2048
mreq .ipv6mr_interface = ifp -> ifindex ;
1874
2049
1875
2050
ret = setsockopt (sock , IPPROTO_IPV6 , IPV6_JOIN_GROUP , (char * )& mreq ,
1876
2051
sizeof (mreq ));
1877
- if (ret < 0 )
2052
+
2053
+ if (ret < 0 ) {
1878
2054
flog_err_sys (EC_LIB_SOCKET ,
1879
2055
"%s(%u): Failed to join group, socket %u error %s" ,
1880
2056
ifp -> name , ifp -> ifindex , sock ,
1881
2057
safe_strerror (errno ));
1882
2058
2059
+ return ret ;
2060
+ }
2061
+
1883
2062
if (IS_ZEBRA_DEBUG_EVENT )
1884
2063
zlog_debug (
1885
2064
"%s(%s:%u): Join All-Routers multicast group, socket %u" ,
0 commit comments