zebra, lib/memtypes.c: the netlink sockets work per VRF
This patch lets the netlink sockets work per VRF.
* The definition of "struct nlsock" is moved into zebra/rib.h.
* The previous global variables "netlink" and "netlink_cmd" now
become the members of "struct zebra_vrf", and are initialized
in zebra_vrf_alloc().
* All relative functions now work for a specific VRF, by adding
a new parameter which specifies the working VRF, except those
functions in which the VRF ID can be obtained from the interface.
* kernel_init(), interface_list() and route_read() are now also
working per VRF, and moved from main() to zebra_vrf_enable().
* A new function kernel_terminate() is added to release the
netlink sockets. It is called from zebra_vrf_disable().
* Correct VRF ID, instead of the previous VRF_DEFAULT, are now
passed to the functions of processing interfaces or route
entries.
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: Donald Sharp <sharpd@cumulusnetworks.com>
diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c
index f357e15..8df877d 100644
--- a/zebra/if_ioctl.c
+++ b/zebra/if_ioctl.c
@@ -29,8 +29,10 @@
#include "connected.h"
#include "memory.h"
#include "log.h"
+#include "vrf.h"
#include "zebra/interface.h"
+#include "zebra/rib.h"
/* Interface looking up using infamous SIOCGIFCONF. */
static int
@@ -442,8 +444,13 @@
/* Lookup all interface information. */
void
-interface_list ()
+interface_list (struct zebra_vrf *zvrf)
{
+ if (zvrf->vrf_id != VRF_DEFAULT)
+ {
+ zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
+ return;
+ }
/* Linux can do both proc & ioctl, ioctl is the only way to get
interface aliases in 2.2 series kernels. */
#ifdef HAVE_PROC_NET_DEV
diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c
index fc384ea..3f33f74 100644
--- a/zebra/if_ioctl_solaris.c
+++ b/zebra/if_ioctl_solaris.c
@@ -30,8 +30,10 @@
#include "memory.h"
#include "log.h"
#include "privs.h"
+#include "vrf.h"
#include "zebra/interface.h"
+#include "zebra/rib.h"
void lifreq_set_name (struct lifreq *, const char *);
int if_get_flags_direct (const char *, uint64_t *, unsigned int af);
@@ -349,8 +351,13 @@
/* Lookup all interface information. */
void
-interface_list ()
+interface_list (struct zebra_vrf *zvrf)
{
+ if (zvrf->vrf_id != VRF_DEFAULT)
+ {
+ zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
+ return;
+ }
interface_list_ioctl (AF_INET);
interface_list_ioctl (AF_INET6);
interface_list_ioctl (AF_UNSPEC);
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 8701416..245b7b2 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -27,7 +27,7 @@
/* Interface information read by netlink. */
void
-interface_list (void)
+interface_list (struct zebra_vrf *zvrf)
{
- interface_lookup_netlink ();
+ interface_lookup_netlink (zvrf);
}
diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c
index ffa6927..bb48f61 100644
--- a/zebra/if_sysctl.c
+++ b/zebra/if_sysctl.c
@@ -30,9 +30,11 @@
#include "ioctl.h"
#include "log.h"
#include "interface.h"
+#include "vrf.h"
#include "zebra/rt.h"
#include "zebra/kernel_socket.h"
+#include "zebra/rib.h"
void
ifstat_update_sysctl (void)
@@ -90,7 +92,7 @@
/* Interface listing up function using sysctl(). */
void
-interface_list ()
+interface_list (struct zebra_vrf *zvrf)
{
caddr_t ref, buf, end;
size_t bufsiz;
@@ -107,6 +109,12 @@
0
};
+ if (zvrf->vrf_id != VRF_DEFAULT)
+ {
+ zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
+ return;
+ }
+
/* Query buffer size. */
if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0)
{
diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c
index 4cd43db..58d2c3a 100644
--- a/zebra/kernel_null.c
+++ b/zebra/kernel_null.c
@@ -28,6 +28,7 @@
#include "zebra/rt.h"
#include "zebra/redistribute.h"
#include "zebra/connected.h"
+#include "zebra/rib.h"
int kernel_add_ipv4 (struct prefix *a, struct rib *b) { return 0; }
#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA
@@ -64,9 +65,10 @@
return 0;
}
-void kernel_init (void) { return; }
+void kernel_init (struct zebra_vrf *zvrf) { return; }
+void kernel_terminate (struct zebra_vrf *zvrf) { return; }
#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA
#pragma weak route_read = kernel_init
#else
-void route_read (void) { return; }
+void route_read (struct zebra_vrf *zvrf) { return; }
#endif
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 374ca41..fd0d8fd 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -38,6 +38,7 @@
#include "zebra/zserv.h"
#include "zebra/debug.h"
#include "zebra/kernel_socket.h"
+#include "zebra/rib.h"
extern struct zebra_privs_t zserv_privs;
extern struct zebra_t zebrad;
@@ -1273,8 +1274,11 @@
/* Make routing socket. */
static void
-routing_socket (void)
+routing_socket (struct zebra_vrf *zvrf)
{
+ if (zvrf->vrf_id != VRF_DEFAULT)
+ return;
+
if ( zserv_privs.change (ZPRIVS_RAISE) )
zlog_err ("routing_socket: Can't raise privileges");
@@ -1305,7 +1309,13 @@
/* Exported interface function. This function simply calls
routing_socket (). */
void
-kernel_init (void)
+kernel_init (struct zebra_vrf *zvrf)
{
- routing_socket ();
+ routing_socket (zvrf);
+}
+
+void
+kernel_terminate (struct zebra_vrf *zvrf)
+{
+ return;
}
diff --git a/zebra/main.c b/zebra/main.c
index 08cc247..c5d1d76 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -232,6 +232,10 @@
#ifdef RTADV
rtadv_init (zvrf);
#endif
+ kernel_init (zvrf);
+ interface_list (zvrf);
+ route_read (zvrf);
+
return 0;
}
@@ -259,6 +263,7 @@
#ifdef RTADV
rtadv_terminate (zvrf);
#endif
+ kernel_terminate (zvrf);
list_delete_all_node (zvrf->rid_all_sorted_list);
list_delete_all_node (zvrf->rid_lo_sorted_list);
@@ -412,9 +417,6 @@
/* Initialize VRF module, and make kernel routing socket. */
zebra_vrf_init ();
- kernel_init ();
- interface_list ();
- route_read ();
#ifdef HAVE_SNMP
zebra_snmp_init ();
diff --git a/zebra/rib.h b/zebra/rib.h
index 9972941..8328f23 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -355,6 +355,17 @@
};
#endif /* RTADV && HAVE_IPV6 */
+#ifdef HAVE_NETLINK
+/* Socket interface to kernel */
+struct nlsock
+{
+ int sock;
+ int seq;
+ struct sockaddr_nl snl;
+ const char *name;
+};
+#endif
+
/* Routing table instance. */
struct zebra_vrf
{
@@ -376,6 +387,12 @@
/* Static route configuration. */
struct route_table *stable[AFI_MAX][SAFI_MAX];
+#ifdef HAVE_NETLINK
+ struct nlsock netlink; /* kernel messages */
+ struct nlsock netlink_cmd; /* command channel */
+ struct thread *t_netlink;
+#endif
+
/* 2nd pointer type used primarily to quell a warning on
* ALL_LIST_ELEMENTS_RO
*/
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index cf6ce0c..0f0f3fe 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -46,16 +46,6 @@
#include "rt_netlink.h"
-/* Socket interface to kernel */
-struct nlsock
-{
- int sock;
- int seq;
- struct sockaddr_nl snl;
- const char *name;
-} netlink = { -1, 0, {0}, "netlink-listen"}, /* kernel messages */
- netlink_cmd = { -1, 0, {0}, "netlink-cmd"}; /* command channel */
-
static const struct message nlmsg_str[] = {
{RTM_NEWROUTE, "RTM_NEWROUTE"},
{RTM_DELROUTE, "RTM_DELROUTE"},
@@ -155,7 +145,7 @@
/* Make socket for Linux netlink interface. */
static int
-netlink_socket (struct nlsock *nl, unsigned long groups)
+netlink_socket (struct nlsock *nl, unsigned long groups, vrf_id_t vrf_id)
{
int ret;
struct sockaddr_nl snl;
@@ -169,7 +159,7 @@
return -1;
}
- sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ sock = vrf_socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, vrf_id);
if (sock < 0)
{
zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
@@ -273,8 +263,9 @@
/* Receive message from netlink interface and pass those information
to the given function. */
static int
-netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
- struct nlsock *nl)
+netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *,
+ vrf_id_t),
+ struct nlsock *nl, struct zebra_vrf *zvrf)
{
int status;
int ret = 0;
@@ -363,7 +354,7 @@
}
/* Deal with errors that occur because of races in link handling */
- if (nl == &netlink_cmd
+ if (nl == &zvrf->netlink_cmd
&& ((msg_type == RTM_DELROUTE &&
(-errnum == ENODEV || -errnum == ESRCH))
|| (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
@@ -393,16 +384,17 @@
/* skip unsolicited messages originating from command socket
* linux sets the originators port-id for {NEW|DEL}ADDR messages,
* so this has to be checked here. */
- if (nl != &netlink_cmd && h->nlmsg_pid == netlink_cmd.snl.nl_pid
+ if (nl != &zvrf->netlink_cmd
+ && h->nlmsg_pid == zvrf->netlink_cmd.snl.nl_pid
&& (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR))
{
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug ("netlink_parse_info: %s packet comes from %s",
- netlink_cmd.name, nl->name);
+ zvrf->netlink_cmd.name, nl->name);
continue;
}
- error = (*filter) (&snl, h);
+ error = (*filter) (&snl, h, zvrf->vrf_id);
if (error < 0)
{
zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
@@ -473,7 +465,8 @@
/* Called from interface_lookup_netlink(). This function is only used
during bootstrap. */
static int
-netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h)
+netlink_interface (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ vrf_id_t vrf_id)
{
int len;
struct ifinfomsg *ifi;
@@ -509,7 +502,7 @@
name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
/* Add interface. */
- ifp = if_get_by_name (name);
+ ifp = if_get_by_name_vrf (name, vrf_id);
set_ifindex(ifp, ifi->ifi_index);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
@@ -526,7 +519,8 @@
/* Lookup interface IPv4/IPv6 address. */
static int
-netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h)
+netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ vrf_id_t vrf_id)
{
int len;
struct ifaddrmsg *ifa;
@@ -556,19 +550,19 @@
memset (tb, 0, sizeof tb);
netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
- ifp = if_lookup_by_index (ifa->ifa_index);
+ ifp = if_lookup_by_index_vrf (ifa->ifa_index, vrf_id);
if (ifp == NULL)
{
- zlog_err ("netlink_interface_addr can't find interface by index %d",
- ifa->ifa_index);
+ zlog_err ("netlink_interface_addr can't find interface by index %d vrf %u",
+ ifa->ifa_index, vrf_id);
return -1;
}
if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
{
char buf[BUFSIZ];
- zlog_debug ("netlink_interface_addr %s %s:",
- lookup (nlmsg_str, h->nlmsg_type), ifp->name);
+ zlog_debug ("netlink_interface_addr %s %s vrf %u:",
+ lookup (nlmsg_str, h->nlmsg_type), ifp->name, vrf_id);
if (tb[IFA_LOCAL])
zlog_debug (" IFA_LOCAL %s/%d",
inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]),
@@ -661,7 +655,8 @@
/* Looking up routing table by netlink interface. */
static int
-netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h)
+netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ vrf_id_t vrf_id)
{
int len;
struct rtmsg *rtm;
@@ -744,7 +739,7 @@
if (!tb[RTA_MULTIPATH])
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index,
- VRF_DEFAULT, table, metric, 0, SAFI_UNICAST);
+ vrf_id, table, metric, 0, SAFI_UNICAST);
else
{
/* This is a multipath route */
@@ -760,7 +755,7 @@
rib->distance = 0;
rib->flags = flags;
rib->metric = metric;
- rib->vrf_id = VRF_DEFAULT;
+ rib->vrf_id = vrf_id;
rib->table = table;
rib->nexthop_num = 0;
rib->uptime = time (NULL);
@@ -810,7 +805,7 @@
memcpy (&p.prefix, dest, 16);
p.prefixlen = rtm->rtm_dst_len;
- rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, VRF_DEFAULT,
+ rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, vrf_id,
table, metric, 0, SAFI_UNICAST);
}
#endif /* HAVE_IPV6 */
@@ -835,7 +830,8 @@
/* Routing information change from the kernel. */
static int
-netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
+netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ vrf_id_t vrf_id)
{
int len;
struct rtmsg *rtm;
@@ -856,18 +852,19 @@
if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
{
/* If this is not route add/delete message print warning. */
- zlog_warn ("Kernel message: %d\n", h->nlmsg_type);
+ zlog_warn ("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id);
return 0;
}
/* Connected route. */
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("%s %s %s proto %s",
+ zlog_debug ("%s %s %s proto %s vrf %u",
h->nlmsg_type ==
RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
rtm->rtm_family == AF_INET ? "ipv4" : "ipv6",
rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast",
- lookup (rtproto_str, rtm->rtm_protocol));
+ lookup (rtproto_str, rtm->rtm_protocol),
+ vrf_id);
if (rtm->rtm_type != RTN_UNICAST)
{
@@ -899,7 +896,7 @@
if (rtm->rtm_src_len != 0)
{
- zlog_warn ("netlink_route_change(): no src len");
+ zlog_warn ("netlink_route_change(): no src len, vrf %u", vrf_id);
return 0;
}
@@ -936,15 +933,15 @@
if (IS_ZEBRA_DEBUG_KERNEL)
{
char buf[PREFIX_STRLEN];
- zlog_debug ("%s %s",
+ zlog_debug ("%s %s vrf %u",
h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
- prefix2str (&p, buf, sizeof(buf)));
+ prefix2str (&p, buf, sizeof(buf)), vrf_id);
}
if (h->nlmsg_type == RTM_NEWROUTE)
{
if (!tb[RTA_MULTIPATH])
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, VRF_DEFAULT,
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, vrf_id,
table, metric, 0, SAFI_UNICAST);
else
{
@@ -961,7 +958,7 @@
rib->distance = 0;
rib->flags = 0;
rib->metric = metric;
- rib->vrf_id = VRF_DEFAULT;
+ rib->vrf_id = vrf_id;
rib->table = table;
rib->nexthop_num = 0;
rib->uptime = time (NULL);
@@ -1004,7 +1001,7 @@
}
}
else
- rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT,
+ rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
SAFI_UNICAST);
}
@@ -1020,16 +1017,16 @@
if (IS_ZEBRA_DEBUG_KERNEL)
{
char buf[PREFIX_STRLEN];
- zlog_debug ("%s %s",
+ zlog_debug ("%s %s vrf %u",
h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE",
- prefix2str (&p, buf, sizeof(buf)));
+ prefix2str (&p, buf, sizeof(buf)), vrf_id);
}
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT, table,
+ rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id, table,
metric, 0, SAFI_UNICAST);
else
- rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, VRF_DEFAULT,
+ rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, vrf_id,
SAFI_UNICAST);
}
#endif /* HAVE_IPV6 */
@@ -1038,7 +1035,8 @@
}
static int
-netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h)
+netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ vrf_id_t vrf_id)
{
int len;
struct ifinfomsg *ifi;
@@ -1051,8 +1049,8 @@
if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK))
{
/* If this is not link add/delete message so print warning. */
- zlog_warn ("netlink_link_change: wrong kernel message %d\n",
- h->nlmsg_type);
+ zlog_warn ("netlink_link_change: wrong kernel message %d vrf %u\n",
+ h->nlmsg_type, vrf_id);
return 0;
}
@@ -1069,7 +1067,8 @@
if ((tb[IFLA_WIRELESS] != NULL) && (ifi->ifi_change == 0))
{
if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("%s: ignoring IFLA_WIRELESS message", __func__);
+ zlog_debug ("%s: ignoring IFLA_WIRELESS message, vrf %u", __func__,
+ vrf_id);
return 0;
}
#endif /* IFLA_WIRELESS */
@@ -1081,12 +1080,12 @@
/* Add interface. */
if (h->nlmsg_type == RTM_NEWLINK)
{
- ifp = if_lookup_by_name (name);
+ ifp = if_lookup_by_name_vrf (name, vrf_id);
if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
{
if (ifp == NULL)
- ifp = if_get_by_name (name);
+ ifp = if_get_by_name_vrf (name, vrf_id);
set_ifindex(ifp, ifi->ifi_index);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
@@ -1127,12 +1126,12 @@
else
{
/* RTM_DELLINK. */
- ifp = if_lookup_by_name (name);
+ ifp = if_lookup_by_name_vrf (name, vrf_id);
if (ifp == NULL)
{
- zlog (NULL, LOG_WARNING, "interface %s is deleted but can't find",
- name);
+ zlog_warn ("interface %s vrf %u is deleted but can't find",
+ name, vrf_id);
return 0;
}
@@ -1143,7 +1142,8 @@
}
static int
-netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h)
+netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ vrf_id_t vrf_id)
{
/* JF: Ignore messages that aren't from the kernel */
if ( snl->nl_pid != 0 )
@@ -1155,25 +1155,26 @@
switch (h->nlmsg_type)
{
case RTM_NEWROUTE:
- return netlink_route_change (snl, h);
+ return netlink_route_change (snl, h, vrf_id);
break;
case RTM_DELROUTE:
- return netlink_route_change (snl, h);
+ return netlink_route_change (snl, h, vrf_id);
break;
case RTM_NEWLINK:
- return netlink_link_change (snl, h);
+ return netlink_link_change (snl, h, vrf_id);
break;
case RTM_DELLINK:
- return netlink_link_change (snl, h);
+ return netlink_link_change (snl, h, vrf_id);
break;
case RTM_NEWADDR:
- return netlink_interface_addr (snl, h);
+ return netlink_interface_addr (snl, h, vrf_id);
break;
case RTM_DELADDR:
- return netlink_interface_addr (snl, h);
+ return netlink_interface_addr (snl, h, vrf_id);
break;
default:
- zlog_warn ("Unknown netlink nlmsg_type %d\n", h->nlmsg_type);
+ zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
+ vrf_id);
break;
}
return 0;
@@ -1181,32 +1182,32 @@
/* Interface lookup by netlink socket. */
int
-interface_lookup_netlink (void)
+interface_lookup_netlink (struct zebra_vrf *zvrf)
{
int ret;
/* Get interface information. */
- ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
+ ret = netlink_request (AF_PACKET, RTM_GETLINK, &zvrf->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface, &netlink_cmd);
+ ret = netlink_parse_info (netlink_interface, &zvrf->netlink_cmd, zvrf);
if (ret < 0)
return ret;
/* Get IPv4 address of the interfaces. */
- ret = netlink_request (AF_INET, RTM_GETADDR, &netlink_cmd);
+ ret = netlink_request (AF_INET, RTM_GETADDR, &zvrf->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
+ ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf);
if (ret < 0)
return ret;
#ifdef HAVE_IPV6
/* Get IPv6 address of the interfaces. */
- ret = netlink_request (AF_INET6, RTM_GETADDR, &netlink_cmd);
+ ret = netlink_request (AF_INET6, RTM_GETADDR, &zvrf->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface_addr, &netlink_cmd);
+ ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf);
if (ret < 0)
return ret;
#endif /* HAVE_IPV6 */
@@ -1217,24 +1218,24 @@
/* Routing table read function using netlink interface. Only called
bootstrap time. */
int
-netlink_route_read (void)
+netlink_route_read (struct zebra_vrf *zvrf)
{
int ret;
/* Get IPv4 routing table. */
- ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
+ ret = netlink_request (AF_INET, RTM_GETROUTE, &zvrf->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
+ ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf);
if (ret < 0)
return ret;
#ifdef HAVE_IPV6
/* Get IPv6 routing table. */
- ret = netlink_request (AF_INET6, RTM_GETROUTE, &netlink_cmd);
+ ret = netlink_request (AF_INET6, RTM_GETROUTE, &zvrf->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_routing_table, &netlink_cmd);
+ ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf);
if (ret < 0)
return ret;
#endif /* HAVE_IPV6 */
@@ -1307,15 +1308,17 @@
}
static int
-netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h)
+netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,
+ vrf_id_t vrf_id)
{
- zlog_warn ("netlink_talk: ignoring message type 0x%04x", h->nlmsg_type);
+ zlog_warn ("netlink_talk: ignoring message type 0x%04x vrf %u", h->nlmsg_type,
+ vrf_id);
return 0;
}
/* sendmsg() to netlink socket then recvmsg(). */
static int
-netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
+netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_vrf *zvrf)
{
int status;
struct sockaddr_nl snl;
@@ -1364,7 +1367,7 @@
* Get reply from netlink socket.
* The reply should either be an acknowlegement or an error.
*/
- return netlink_parse_info (netlink_talk_filter, nl);
+ return netlink_parse_info (netlink_talk_filter, nl, zvrf);
}
/* This function takes a nexthop as argument and adds
@@ -1558,12 +1561,13 @@
struct prefix *p,
struct nexthop *nexthop,
const char *routedesc,
- int family)
+ int family,
+ struct zebra_vrf *zvrf)
{
if (IS_ZEBRA_DEBUG_KERNEL)
{
char buf[PREFIX_STRLEN];
- zlog_debug ("netlink_route_multipath() (%s): %s %s type %s",
+ zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s",
routedesc,
lookup (nlmsg_str, cmd),
prefix2str (p, buf, sizeof(buf)),
@@ -1591,6 +1595,8 @@
char buf[NL_PKT_BUF_SIZE];
} req;
+ struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id);
+
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
bytelen = (family == AF_INET ? 4 : 16);
@@ -1675,7 +1681,7 @@
{
routedesc = recursing ? "recursive, 1 hop" : "single hop";
- _netlink_route_debug(cmd, p, nexthop, routedesc, family);
+ _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf);
_netlink_route_build_singlepath(routedesc, bytelen,
nexthop, &req.n, &req.r,
sizeof req);
@@ -1717,7 +1723,7 @@
nexthop_num++;
_netlink_route_debug(cmd, p, nexthop,
- routedesc, family);
+ routedesc, family, zvrf);
_netlink_route_build_multipath(routedesc, bytelen,
nexthop, rta, rtnh, &src);
rtnh = RTNH_NEXT (rtnh);
@@ -1749,7 +1755,7 @@
snl.nl_family = AF_NETLINK;
/* Talk to netlink socket. */
- return netlink_talk (&req.n, &netlink_cmd);
+ return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf);
}
int
@@ -1793,6 +1799,8 @@
char buf[NL_PKT_BUF_SIZE];
} req;
+ struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
+
p = ifc->address;
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
@@ -1825,7 +1833,7 @@
addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
strlen (ifc->label) + 1);
- return netlink_talk (&req.n, &netlink_cmd);
+ return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf);
}
int
@@ -1847,8 +1855,10 @@
static int
kernel_read (struct thread *thread)
{
- netlink_parse_info (netlink_information_fetch, &netlink);
- thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
+ struct zebra_vrf *zvrf = (struct zebra_vrf *)THREAD_ARG (thread);
+ netlink_parse_info (netlink_information_fetch, &zvrf->netlink, zvrf);
+ zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf,
+ zvrf->netlink.sock);
return 0;
}
@@ -1887,7 +1897,7 @@
/* Exported interface function. This function simply calls
netlink_socket (). */
void
-kernel_init (void)
+kernel_init (struct zebra_vrf *zvrf)
{
unsigned long groups;
@@ -1895,23 +1905,42 @@
#ifdef HAVE_IPV6
groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
#endif /* HAVE_IPV6 */
- netlink_socket (&netlink, groups);
- netlink_socket (&netlink_cmd, 0);
+ netlink_socket (&zvrf->netlink, groups, zvrf->vrf_id);
+ netlink_socket (&zvrf->netlink_cmd, 0, zvrf->vrf_id);
/* Register kernel socket. */
- if (netlink.sock > 0)
+ if (zvrf->netlink.sock > 0)
{
/* Only want non-blocking on the netlink event socket */
- if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
- zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
- safe_strerror (errno));
+ if (fcntl (zvrf->netlink.sock, F_SETFL, O_NONBLOCK) < 0)
+ zlog_err ("Can't set %s socket flags: %s", zvrf->netlink.name,
+ safe_strerror (errno));
/* Set receive buffer size if it's set from command line */
if (nl_rcvbufsize)
- netlink_recvbuf (&netlink, nl_rcvbufsize);
+ netlink_recvbuf (&zvrf->netlink, nl_rcvbufsize);
- netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
- thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
+ netlink_install_filter (zvrf->netlink.sock, zvrf->netlink_cmd.snl.nl_pid);
+ zvrf->t_netlink = thread_add_read (zebrad.master, kernel_read, zvrf,
+ zvrf->netlink.sock);
+ }
+}
+
+void
+kernel_terminate (struct zebra_vrf *zvrf)
+{
+ THREAD_READ_OFF (zvrf->t_netlink);
+
+ if (zvrf->netlink.sock >= 0)
+ {
+ close (zvrf->netlink.sock);
+ zvrf->netlink.sock = -1;
+ }
+
+ if (zvrf->netlink_cmd.sock >= 0)
+ {
+ close (zvrf->netlink_cmd.sock);
+ zvrf->netlink_cmd.sock = -1;
}
}
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index d8f9db8..40fa8eb 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -41,8 +41,8 @@
nl_rtproto_to_str (u_char rtproto);
-extern int interface_lookup_netlink (void);
-extern int netlink_route_read (void);
+extern int interface_lookup_netlink (struct zebra_vrf *zvrf);
+extern int netlink_route_read (struct zebra_vrf *zvrf);
#endif /* HAVE_NETLINK */
diff --git a/zebra/rtread_getmsg.c b/zebra/rtread_getmsg.c
index 83ef648..7fb916f 100644
--- a/zebra/rtread_getmsg.c
+++ b/zebra/rtread_getmsg.c
@@ -96,7 +96,7 @@
}
void
-route_read (void)
+route_read (struct zebra_vrf *zvrf)
{
char storage[RT_BUFSIZ];
@@ -111,6 +111,10 @@
struct strbuf msgdata;
int flags, dev, retval, process;
+ if (zvrf->vrf_id != VRF_DEFAULT) {
+ return;
+ }
+
if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) {
zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE,
safe_strerror (errno));
diff --git a/zebra/rtread_netlink.c b/zebra/rtread_netlink.c
index 7abbc59..1f65864 100644
--- a/zebra/rtread_netlink.c
+++ b/zebra/rtread_netlink.c
@@ -25,7 +25,7 @@
#include "zebra/zserv.h"
#include "rt_netlink.h"
-void route_read (void)
+void route_read (struct zebra_vrf *zvrf)
{
- netlink_route_read ();
+ netlink_route_read (zvrf);
}
diff --git a/zebra/rtread_sysctl.c b/zebra/rtread_sysctl.c
index b8f5bde..385e150 100644
--- a/zebra/rtread_sysctl.c
+++ b/zebra/rtread_sysctl.c
@@ -24,6 +24,7 @@
#include "memory.h"
#include "log.h"
+#include "vrf.h"
#include "zebra/zserv.h"
#include "zebra/rt.h"
@@ -31,7 +32,7 @@
/* Kernel routing table read up by sysctl function. */
void
-route_read (void)
+route_read (struct zebra_vrf *zvrf)
{
caddr_t buf, end, ref;
size_t bufsiz;
@@ -47,7 +48,10 @@
NET_RT_DUMP,
0
};
-
+
+ if (zvrf->vrf_id != VRF_DEFAULT)
+ return;
+
/* Get buffer size. */
if (sysctl (mib, MIBSIZ, NULL, &bufsiz, NULL, 0) < 0)
{
diff --git a/zebra/test_main.c b/zebra/test_main.c
index 17014ea..448d1ef 100644
--- a/zebra/test_main.c
+++ b/zebra/test_main.c
@@ -220,6 +220,9 @@
assert (zvrf);
+ kernel_init (zvrf);
+ route_read (zvrf);
+
return 0;
}
@@ -244,6 +247,8 @@
if_down (ifp);
}
+ kernel_terminate (zvrf);
+
return 0;
}
@@ -355,8 +360,6 @@
/* Make kernel routing socket. */
zebra_vrf_init ();
- kernel_init ();
- route_read ();
zebra_vty_init();
/* Configuration file read*/
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 9d966a0..084af38 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -3447,6 +3447,9 @@
zebra_vrf_alloc (vrf_id_t vrf_id)
{
struct zebra_vrf *zvrf;
+#ifdef HAVE_NETLINK
+ char nl_name[64];
+#endif
zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf));
@@ -3463,6 +3466,17 @@
/* Set VRF ID */
zvrf->vrf_id = vrf_id;
+#ifdef HAVE_NETLINK
+ /* Initialize netlink sockets */
+ snprintf (nl_name, 64, "netlink-listen (vrf %u)", vrf_id);
+ zvrf->netlink.sock = -1;
+ zvrf->netlink.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name);
+
+ snprintf (nl_name, 64, "netlink-cmd (vrf %u)", vrf_id);
+ zvrf->netlink_cmd.sock = -1;
+ zvrf->netlink_cmd.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name);
+#endif
+
return zvrf;
}
diff --git a/zebra/zserv.h b/zebra/zserv.h
index eaa164b..af005f8 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -92,9 +92,10 @@
extern void zebra_zserv_socket_init (char *path);
extern void hostinfo_get (void);
extern void rib_init (void);
-extern void interface_list (void);
-extern void kernel_init (void);
-extern void route_read (void);
+extern void interface_list (struct zebra_vrf *);
+extern void route_read (struct zebra_vrf *);
+extern void kernel_init (struct zebra_vrf *);
+extern void kernel_terminate (struct zebra_vrf *);
extern void zebra_route_map_init (void);
extern void zebra_snmp_init (void);
extern void zebra_vty_init (void);