Acked-by: Donald Sharp <sha...@cumulusnetworks.com>

On Thu, Jun 4, 2015 at 8:10 AM, Nicolas Dichtel <nicolas.dich...@6wind.com>
wrote:

> From: Feng Lu <lu.f...@6wind.com>
>
> 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.f...@6wind.com>
> Reviewed-by: Alain Ritoux <alain.rit...@6wind.com>
> Signed-off-by: Nicolas Dichtel <nicolas.dich...@6wind.com>
> Acked-by: Donald Sharp <sha...@cumulusnetworks.com>
> ---
>  lib/memtypes.c           |   1 +
>  zebra/if_ioctl.c         |   9 +-
>  zebra/if_ioctl_solaris.c |   9 +-
>  zebra/if_netlink.c       |   4 +-
>  zebra/if_sysctl.c        |  10 ++-
>  zebra/kernel_null.c      |   6 +-
>  zebra/kernel_socket.c    |  16 +++-
>  zebra/main.c             |   8 +-
>  zebra/rib.h              |  17 ++++
>  zebra/rt_netlink.c       | 219
> +++++++++++++++++++++++++++--------------------
>  zebra/rt_netlink.h       |   4 +-
>  zebra/rtread_getmsg.c    |   6 +-
>  zebra/rtread_netlink.c   |   4 +-
>  zebra/rtread_sysctl.c    |   8 +-
>  zebra/test_main.c        |   7 +-
>  zebra/zebra_rib.c        |  14 +++
>  zebra/zserv.h            |   7 +-
>  17 files changed, 229 insertions(+), 120 deletions(-)
>
> diff --git a/lib/memtypes.c b/lib/memtypes.c
> index 3e599f673238..60f24e6a7915 100644
> --- a/lib/memtypes.c
> +++ b/lib/memtypes.c
> @@ -85,6 +85,7 @@ struct memory_list memory_list_zebra[] =
>    { MTYPE_STATIC_IPV6,         "Static IPv6 route"             },
>    { MTYPE_RIB_DEST,            "RIB destination"               },
>    { MTYPE_RIB_TABLE_INFO,      "RIB table info"                },
> +  { MTYPE_NETLINK_NAME,        "Netlink name"                  },
>    { -1, NULL },
>  };
>
> diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c
> index f357e15447c3..8df877dbaaa1 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 @@ interface_info_ioctl ()
>
>  /* 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 fc384ea29a3f..3f33f749af46 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 @@ interface_info_ioctl (struct interface *ifp)
>
>  /* 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 87014160cfb5..245b7b2509d0 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 ffa6927d617e..bb48f61828a9 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 @@ ifstat_update_sysctl (void)
>
>  /* 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 @@ interface_list ()
>      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 4cd43db48753..58d2c3ae758b 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 @@ int kernel_address_delete_ipv4 (struct interface *a,
> struct connected *b)
>    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 374ca412aef3..fd0d8fd1b656 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 @@ kernel_read (struct thread *thread)
>
>  /* 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 @@ routing_socket (void)
>  /* Exported interface function.  This function simply calls
>     routing_socket (). */
>  void
> -kernel_init (void)
> +kernel_init (struct zebra_vrf *zvrf)
> +{
> +  routing_socket (zvrf);
> +}
> +
> +void
> +kernel_terminate (struct zebra_vrf *zvrf)
>  {
> -  routing_socket ();
> +  return;
>  }
> diff --git a/zebra/main.c b/zebra/main.c
> index 08cc247d8a74..c5d1d76c527f 100644
> --- a/zebra/main.c
> +++ b/zebra/main.c
> @@ -232,6 +232,10 @@ zebra_vrf_enable (vrf_id_t vrf_id, void **info)
>  #ifdef RTADV
>    rtadv_init (zvrf);
>  #endif
> +  kernel_init (zvrf);
> +  interface_list (zvrf);
> +  route_read (zvrf);
> +
>    return 0;
>  }
>
> @@ -259,6 +263,7 @@ zebra_vrf_disable (vrf_id_t vrf_id, void **info)
>  #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 @@ main (int argc, char **argv)
>
>    /* 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 99729411fc38..8328f23bb80c 100644
> --- a/zebra/rib.h
> +++ b/zebra/rib.h
> @@ -355,6 +355,17 @@ struct rtadv
>  };
>  #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 @@ struct zebra_vrf
>    /* 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 cf6ce0cdeb42..0f0f3fed308a 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 @@ netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
>
>  /* 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 @@ netlink_socket (struct nlsock *nl, unsigned long
> groups)
>        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 @@ netlink_request (int family, int type, struct nlsock
> *nl)
>  /* 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 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl
> *, struct nlmsghdr *),
>                  }
>
>                /* 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 @@ netlink_parse_info (int (*filter) (struct
> sockaddr_nl *, struct nlmsghdr *),
>            /* 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 @@ netlink_interface_update_hw_addr (struct rtattr **tb,
> struct interface *ifp)
>  /* 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 @@ netlink_interface (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>    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 @@ netlink_interface (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>
>  /* 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 @@ netlink_interface_addr (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>    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 @@ netlink_interface_addr (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>
>  /* 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 @@ netlink_routing_table (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>
>        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 @@ netlink_routing_table (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>            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 @@ netlink_routing_table (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>        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 @@ static const struct message rtproto_str[] = {
>
>  /* 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 @@ netlink_route_change (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>    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 @@ netlink_route_change (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>
>    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 @@ netlink_route_change (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>        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 @@ netlink_route_change (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>                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 @@ netlink_route_change (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>              }
>          }
>        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 @@ netlink_route_change (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>        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 @@ netlink_route_change (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>  }
>
>  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 @@ netlink_link_change (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>    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 @@ netlink_link_change (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>    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 @@ netlink_link_change (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>    /* 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 @@ netlink_link_change (struct sockaddr_nl *snl,
> struct nlmsghdr *h)
>    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 @@ netlink_link_change (struct sockaddr_nl *snl, struct
> nlmsghdr *h)
>  }
>
>  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 @@ netlink_information_fetch (struct sockaddr_nl
> *snl, struct nlmsghdr *h)
>    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 @@ netlink_information_fetch (struct sockaddr_nl
> *snl, struct nlmsghdr *h)
>
>  /* 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 @@ interface_lookup_netlink (void)
>  /* 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 @@ addattr32 (struct nlmsghdr *n, size_t maxlen, int
> type, int data)
>  }
>
>  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 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
>     * 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 @@ _netlink_route_debug(
>          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 @@ netlink_route_multipath (int cmd, struct prefix *p,
> struct rib *rib,
>      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 @@ netlink_route_multipath (int cmd, struct prefix *p,
> struct rib *rib,
>              {
>                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 @@ netlink_route_multipath (int cmd, struct prefix *p,
> struct rib *rib,
>                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 @@ skip:
>    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 @@ netlink_address (int cmd, int family, struct
> interface *ifp,
>      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 @@ netlink_address (int cmd, int family, struct
> interface *ifp,
>      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 @@ extern struct thread_master *master;
>  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 @@ static void netlink_install_filter (int sock, __u32
> pid)
>  /* 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 @@ kernel_init (void)
>  #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 d8f9db8561fe..40fa8eb4b8ce 100644
> --- a/zebra/rt_netlink.h
> +++ b/zebra/rt_netlink.h
> @@ -41,8 +41,8 @@ extern const char *
>  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 83ef64832388..7fb916ffa52a 100644
> --- a/zebra/rtread_getmsg.c
> +++ b/zebra/rtread_getmsg.c
> @@ -96,7 +96,7 @@ handle_route_entry (mib2_ipRouteEntry_t *routeEntry)
>  }
>
>  void
> -route_read (void)
> +route_read (struct zebra_vrf *zvrf)
>  {
>         char                    storage[RT_BUFSIZ];
>
> @@ -111,6 +111,10 @@ route_read (void)
>         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 7abbc590a4df..1f658646e0ac 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 b8f5bde70e3d..385e15069fae 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 @@ route_read (void)
>      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 17014ea7312b..448d1ef9f1ac 100644
> --- a/zebra/test_main.c
> +++ b/zebra/test_main.c
> @@ -220,6 +220,9 @@ zebra_vrf_enable (vrf_id_t vrf_id, void **info)
>
>    assert (zvrf);
>
> +  kernel_init (zvrf);
> +  route_read (zvrf);
> +
>    return 0;
>  }
>
> @@ -244,6 +247,8 @@ zebra_vrf_disable (vrf_id_t vrf_id, void **info)
>          if_down (ifp);
>      }
>
> +  kernel_terminate (zvrf);
> +
>    return 0;
>  }
>
> @@ -355,8 +360,6 @@ main (int argc, char **argv)
>
>    /* 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 9d966a0f2f9c..084af3802323 100644
> --- a/zebra/zebra_rib.c
> +++ b/zebra/zebra_rib.c
> @@ -3447,6 +3447,9 @@ struct zebra_vrf *
>  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 @@ zebra_vrf_alloc (vrf_id_t vrf_id)
>    /* 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 eaa164b956f2..af005f851d2a 100644
> --- a/zebra/zserv.h
> +++ b/zebra/zserv.h
> @@ -92,9 +92,10 @@ extern void zebra_if_init (void);
>  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);
> --
> 2.4.2
>
>
_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev

Reply via email to