zebra: maintain RTADV per VRF
This moves the global variable "rtadv" into the "struct zebra_vrf",
so that RTADV feature can work per VRF.
* rtadv.c/rtadv.h:
Add a proper parameter to the functions so that the entity of the
"struct zebra_vrf" and interfaces can be obtained from the specified
VRF.
The old rtadv_init() is splitted into:
- rtadv_cmd_init(): it installs the RTADV commands; is called from
main();
- new rtadv_init(): it creates the socket; is called from
zebra_vrf_enable().
rtadv_terminate() is added to stop the threads, close the socket and
clear the counters. It is called from zebra_vrf_disable().
rtadv_make_socket() now calls vrf_socket() to create a socket in
the VRF.
* interface.h and rib.h: define the macro RTADV.
* main.c: according changes, refer to rtadv.c.
Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Vincent JARDIN <vincent.jardin@6wind.com>
Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
diff --git a/zebra/interface.h b/zebra/interface.h
index 0f081f6..fe24604 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -38,11 +38,13 @@
#define IF_ZEBRA_SHUTDOWN_ON 1
/* Router advertisement feature. */
+#ifndef RTADV
#if (defined(LINUX_IPV6) && (!defined(__GLIBC__) || defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME)
#ifdef HAVE_RTADV
#define RTADV
#endif
#endif
+#endif
#ifdef RTADV
/* Router advertisement parameter. From RFC4861, RFC6275 and RFC4191. */
diff --git a/zebra/main.c b/zebra/main.c
index 1e9757b..08cc247 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -229,6 +229,9 @@
assert (zvrf);
+#ifdef RTADV
+ rtadv_init (zvrf);
+#endif
return 0;
}
@@ -253,6 +256,10 @@
if_down (ifp);
}
+#ifdef RTADV
+ rtadv_terminate (zvrf);
+#endif
+
list_delete_all_node (zvrf->rid_all_sorted_list);
list_delete_all_node (zvrf->rid_lo_sorted_list);
@@ -394,7 +401,7 @@
access_list_init ();
prefix_list_init ();
#ifdef RTADV
- rtadv_init ();
+ rtadv_cmd_init ();
#endif
#ifdef HAVE_IRDP
irdp_init();
diff --git a/zebra/rib.h b/zebra/rib.h
index 5663f30..9972941 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -332,6 +332,29 @@
vrf_id_t vrf_id;
};
+/* Router advertisement feature. */
+#ifndef RTADV
+#if (defined(LINUX_IPV6) && (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1)) || defined(KAME)
+ #ifdef HAVE_RTADV
+ #define RTADV
+ #endif
+#endif
+#endif
+
+#if defined (HAVE_IPV6) && defined (RTADV)
+/* Structure which hold status of router advertisement. */
+struct rtadv
+{
+ int sock;
+
+ int adv_if_count;
+ int adv_msec_if_count;
+
+ struct thread *ra_read;
+ struct thread *ra_timer;
+};
+#endif /* RTADV && HAVE_IPV6 */
+
/* Routing table instance. */
struct zebra_vrf
{
@@ -361,6 +384,10 @@
struct list *rid_all_sorted_list;
struct list *rid_lo_sorted_list;
struct prefix rid_user_assigned;
+
+#if defined (HAVE_IPV6) && defined (RTADV)
+ struct rtadv rtadv;
+#endif /* RTADV && HAVE_IPV6 */
};
/*
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index b395982..be4aeb1 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -31,6 +31,7 @@
#include "linklist.h"
#include "command.h"
#include "privs.h"
+#include "vrf.h"
#include "zebra/interface.h"
#include "zebra/rtadv.h"
@@ -62,31 +63,11 @@
enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER,
RTADV_TIMER_MSEC, RTADV_READ};
-static void rtadv_event (enum rtadv_event, int);
+static void rtadv_event (struct zebra_vrf *, enum rtadv_event, int);
static int if_join_all_router (int, struct interface *);
static int if_leave_all_router (int, struct interface *);
-/* Structure which hold status of router advertisement. */
-struct rtadv
-{
- int sock;
-
- int adv_if_count;
- int adv_msec_if_count;
-
- struct thread *ra_read;
- struct thread *ra_timer;
-};
-
-struct rtadv *rtadv = NULL;
-
-static struct rtadv *
-rtadv_new (void)
-{
- return XCALLOC (MTYPE_TMP, sizeof (struct rtadv));
-}
-
static int
rtadv_recv_packet (int sock, u_char *buf, int buflen,
struct sockaddr_in6 *from, unsigned int *ifindex,
@@ -389,24 +370,25 @@
static int
rtadv_timer (struct thread *thread)
{
+ struct zebra_vrf *zvrf = THREAD_ARG (thread);
struct listnode *node, *nnode;
struct interface *ifp;
struct zebra_if *zif;
int period;
- rtadv->ra_timer = NULL;
- if (rtadv->adv_msec_if_count == 0)
+ zvrf->rtadv.ra_timer = NULL;
+ if (zvrf->rtadv.adv_msec_if_count == 0)
{
period = 1000; /* 1 s */
- rtadv_event (RTADV_TIMER, 1 /* 1 s */);
+ rtadv_event (zvrf, RTADV_TIMER, 1 /* 1 s */);
}
else
{
period = 10; /* 10 ms */
- rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */);
+ rtadv_event (zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */);
}
- for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
+ for (ALL_LIST_ELEMENTS (vrf_iflist (zvrf->vrf_id), node, nnode, ifp))
{
if (if_is_loopback (ifp) || ! if_is_operative (ifp))
continue;
@@ -421,7 +403,7 @@
/* FIXME: using MaxRtrAdvInterval each time isn't what section
6.2.4 of RFC4861 tells to do. */
zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
- rtadv_send_packet (rtadv->sock, ifp);
+ rtadv_send_packet (zvrf->rtadv.sock, ifp);
}
}
}
@@ -431,9 +413,11 @@
static void
rtadv_process_solicit (struct interface *ifp)
{
- zlog_info ("Router solicitation received on %s", ifp->name);
+ struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
- rtadv_send_packet (rtadv->sock, ifp);
+ zlog_info ("Router solicitation received on %s vrf %u", ifp->name, zvrf->vrf_id);
+
+ rtadv_send_packet (zvrf->rtadv.sock, ifp);
}
static void
@@ -443,17 +427,18 @@
}
static void
-rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit)
+rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex,
+ int hoplimit, vrf_id_t vrf_id)
{
struct icmp6_hdr *icmph;
struct interface *ifp;
struct zebra_if *zif;
/* Interface search. */
- ifp = if_lookup_by_index (ifindex);
+ ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
if (ifp == NULL)
{
- zlog_warn ("Unknown interface index: %d", ifindex);
+ zlog_warn ("Unknown interface index: %d, vrf %u", ifindex, vrf_id);
return;
}
@@ -508,12 +493,13 @@
struct sockaddr_in6 from;
unsigned int ifindex = 0;
int hoplimit = -1;
+ struct zebra_vrf *zvrf = THREAD_ARG (thread);
sock = THREAD_FD (thread);
- rtadv->ra_read = NULL;
+ zvrf->rtadv.ra_read = NULL;
/* Register myself. */
- rtadv_event (RTADV_READ, sock);
+ rtadv_event (zvrf, RTADV_READ, sock);
len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
@@ -523,13 +509,13 @@
return len;
}
- rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit);
+ rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id);
return 0;
}
static int
-rtadv_make_socket (void)
+rtadv_make_socket (vrf_id_t vrf_id)
{
int sock;
int ret;
@@ -539,7 +525,7 @@
zlog_err ("rtadv_make_socket: could not raise privs, %s",
safe_strerror (errno) );
- sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ sock = vrf_socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, vrf_id);
if ( zserv_privs.change (ZPRIVS_LOWER) )
zlog_err ("rtadv_make_socket: could not lower privs, %s",
@@ -661,9 +647,11 @@
{
struct interface *ifp;
struct zebra_if *zif;
+ struct zebra_vrf *zvrf;
ifp = vty->index;
zif = ifp->info;
+ zvrf = vrf_info_lookup (ifp->vrf_id);
if (if_is_loopback (ifp))
{
@@ -675,12 +663,12 @@
{
zif->rtadv.AdvSendAdvertisements = 0;
zif->rtadv.AdvIntervalTimer = 0;
- rtadv->adv_if_count--;
+ zvrf->rtadv.adv_if_count--;
- if_leave_all_router (rtadv->sock, ifp);
+ if_leave_all_router (zvrf->rtadv.sock, ifp);
- if (rtadv->adv_if_count == 0)
- rtadv_event (RTADV_STOP, 0);
+ if (zvrf->rtadv.adv_if_count == 0)
+ rtadv_event (zvrf, RTADV_STOP, 0);
}
return CMD_SUCCESS;
@@ -696,9 +684,11 @@
{
struct interface *ifp;
struct zebra_if *zif;
+ struct zebra_vrf *zvrf;
ifp = vty->index;
zif = ifp->info;
+ zvrf = vrf_info_lookup (ifp->vrf_id);
if (if_is_loopback (ifp))
{
@@ -710,12 +700,12 @@
{
zif->rtadv.AdvSendAdvertisements = 1;
zif->rtadv.AdvIntervalTimer = 0;
- rtadv->adv_if_count++;
+ zvrf->rtadv.adv_if_count++;
- if_join_all_router (rtadv->sock, ifp);
+ if_join_all_router (zvrf->rtadv.sock, ifp);
- if (rtadv->adv_if_count == 1)
- rtadv_event (RTADV_START, rtadv->sock);
+ if (zvrf->rtadv.adv_if_count == 1)
+ rtadv_event (zvrf, RTADV_START, zvrf->rtadv.sock);
}
return CMD_SUCCESS;
@@ -732,6 +722,7 @@
unsigned interval;
struct interface *ifp = (struct interface *) vty->index;
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000);
if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000))
@@ -741,10 +732,10 @@
}
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- rtadv->adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
if (interval % 1000)
- rtadv->adv_msec_if_count++;
+ zvrf->rtadv.adv_msec_if_count++;
zif->rtadv.MaxRtrAdvInterval = interval;
zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
@@ -764,6 +755,7 @@
unsigned interval;
struct interface *ifp = (struct interface *) vty->index;
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800);
if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime))
@@ -773,7 +765,7 @@
}
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- rtadv->adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
/* convert to milliseconds */
interval = interval * 1000;
@@ -795,12 +787,14 @@
{
struct interface *ifp;
struct zebra_if *zif;
+ struct zebra_vrf *zvrf;
ifp = (struct interface *) vty->index;
zif = ifp->info;
+ zvrf = vrf_info_lookup (ifp->vrf_id);
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- rtadv->adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
@@ -1540,9 +1534,6 @@
char buf[PREFIX_STRLEN];
int interval;
- if (! rtadv)
- return;
-
zif = ifp->info;
if (! if_is_loopback (ifp))
@@ -1627,16 +1618,18 @@
static void
-rtadv_event (enum rtadv_event event, int val)
+rtadv_event (struct zebra_vrf *zvrf, enum rtadv_event event, int val)
{
+ struct rtadv *rtadv = &zvrf->rtadv;
+
switch (event)
{
case RTADV_START:
if (! rtadv->ra_read)
- rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
+ rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val);
if (! rtadv->ra_timer)
rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
- NULL, 0);
+ zvrf, 0);
break;
case RTADV_STOP:
if (rtadv->ra_timer)
@@ -1652,17 +1645,17 @@
break;
case RTADV_TIMER:
if (! rtadv->ra_timer)
- rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL,
+ rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, zvrf,
val);
break;
case RTADV_TIMER_MSEC:
if (! rtadv->ra_timer)
rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer,
- NULL, val);
+ zvrf, val);
break;
case RTADV_READ:
if (! rtadv->ra_read)
- rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
+ rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val);
break;
default:
break;
@@ -1671,17 +1664,29 @@
}
void
-rtadv_init (void)
+rtadv_init (struct zebra_vrf *zvrf)
{
- int sock;
+ zvrf->rtadv.sock = rtadv_make_socket (zvrf->vrf_id);
+}
- sock = rtadv_make_socket ();
- if (sock < 0)
- return;
+void
+rtadv_terminate (struct zebra_vrf *zvrf)
+{
+ rtadv_event (zvrf, RTADV_STOP, 0);
- rtadv = rtadv_new ();
- rtadv->sock = sock;
+ if (zvrf->rtadv.sock >= 0)
+ {
+ close (zvrf->rtadv.sock);
+ zvrf->rtadv.sock = -1;
+ }
+ zvrf->rtadv.adv_if_count = 0;
+ zvrf->rtadv.adv_msec_if_count = 0;
+}
+
+void
+rtadv_cmd_init (void)
+{
install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
@@ -1776,7 +1781,17 @@
#else
void
-rtadv_init (void)
+rtadv_init (struct zebra_vrf *zvrf)
+{
+ /* Empty.*/;
+}
+void
+rtadv_terminate (struct zebra_vrf *zvrf)
+{
+ /* Empty.*/;
+}
+void
+rtadv_cmd_init (void)
{
/* Empty.*/;
}
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 1e1aec9..76f98cf 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -100,6 +100,8 @@
#endif /* RTADV */
-extern void rtadv_init (void);
+extern void rtadv_init (struct zebra_vrf *);
+extern void rtadv_terminate (struct zebra_vrf *);
+extern void rtadv_cmd_init (void);
#endif /* _ZEBRA_RTADV_H */