Convert the rest of zebra over to use a Namespae and VRF.
Signed-off-by: Vipin Kumar <vipin@cumulusnetworks.com>
Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
#define ZEBRA_REDISTRIBUTE_IPV6_ADD 40
#define ZEBRA_REDISTRIBUTE_IPV6_DEL 41
#define ZEBRA_VRF_UNREGISTER 42
-#define ZEBRA_MESSAGE_MAX 43
+#define ZEBRA_VRF_ADD 43
+#define ZEBRA_VRF_DELETE 44
+#define ZEBRA_MESSAGE_MAX 45
/* Marker value used in new Zserv, in the byte location corresponding
* the command value in the old zserv header. To allow old and new
/* Lookup all interface information. */
void
-interface_list (struct zebra_vrf *zvrf)
+interface_list (struct zebra_ns *zns)
{
- if (zvrf->vrf_id != VRF_DEFAULT)
- {
- zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
- return;
- }
+
+ zlog_info ("interface_list: NS %u", zns->ns_id);
+
/* 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
/* Lookup all interface information. */
void
-interface_list (struct zebra_vrf *zvrf)
+interface_list (struct zebra_ns *zns)
{
- if (zvrf->vrf_id != VRF_DEFAULT)
+ if (zns->ns_id != NS_DEFAULT)
{
- zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
+ zlog_warn ("interface_list: ignore NS %u", zns->ns_id);
return;
}
interface_list_ioctl (AF_INET);
/* Interface information read by netlink. */
void
-interface_list (struct zebra_vrf *zvrf)
+interface_list (struct zebra_ns *zns)
{
- interface_lookup_netlink (zvrf);
+ interface_lookup_netlink (zns);
}
/* Interface listing up function using sysctl(). */
void
-interface_list (struct zebra_vrf *zvrf)
+interface_list (struct zebra_ns *zns)
{
caddr_t ref, buf, end;
size_t bufsiz;
0
};
- if (zvrf->vrf_id != VRF_DEFAULT)
+ if (zns->ns_id != NS_DEFAULT)
{
- zlog_warn ("interface_list: ignore VRF %u", zvrf->vrf_id);
+ zlog_warn ("interface_list: ignore NS %u", zns->ns_id);
return;
}
const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 };
#endif /* HAVE_RTADV */
+struct zebra_ns *dzns;
+
/* Called when new interface is added. */
static int
if_zebra_new_hook (struct interface *ifp)
return 0;
}
+/* Build the table key */
+static void
+if_build_key (u_int32_t ifindex, struct prefix *p)
+{
+ p->family = AF_INET;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ p->u.prefix4.s_addr = ifindex;
+}
+
+/* Link an interface in a per NS interface tree */
+struct interface *
+if_link_per_ns (struct zebra_ns *ns, struct interface *ifp)
+{
+ struct prefix p;
+ struct route_node *rn;
+
+ if (ifp->ifindex == IFINDEX_INTERNAL)
+ return NULL;
+
+ if_build_key (ifp->ifindex, &p);
+ rn = route_node_get (ns->if_table, &p);
+ if (rn->info)
+ {
+ ifp = (struct interface *)rn->info;
+ route_unlock_node (rn); /* get */
+ return ifp;
+ }
+
+ rn->info = ifp;
+ ifp->node = rn;
+
+ return ifp;
+}
+
+/* Delete a VRF. This is called in vrf_terminate(). */
+void
+if_unlink_per_ns (struct interface *ifp)
+{
+ ifp->node->info = NULL;
+ route_unlock_node(ifp->node);
+}
+
+/* Look up an interface by identifier within a NS */
+struct interface *
+if_lookup_by_index_per_ns (struct zebra_ns *ns, u_int32_t ifindex)
+{
+ struct prefix p;
+ struct route_node *rn;
+ struct interface *ifp = NULL;
+
+ if_build_key (ifindex, &p);
+ rn = route_node_lookup (ns->if_table, &p);
+ if (rn)
+ {
+ ifp = (struct interface *)rn->info;
+ route_unlock_node (rn); /* lookup */
+ }
+ return ifp;
+}
+
+
/* Tie an interface address to its derived subnet list of addresses. */
int
if_subnet_add (struct interface *ifp, struct connected *ifc)
{
struct zebra_if *if_data;
+ if_link_per_ns(dzns, ifp);
+
if_data = ifp->info;
if (if_data->multicast == IF_ZEBRA_MULTICAST_ON)
if_set_flags (ifp, IFF_MULTICAST);
}
zebra_interface_delete_update (ifp);
+ if_unlink_per_ns(ifp);
+
/* Update ifindex after distributing the delete message. This is in
case any client needs to have the old value of ifindex available
while processing the deletion. Each client daemon is responsible
ifp->ifindex = IFINDEX_INTERNAL;
}
+/* Handle VRF addition */
+void
+vrf_add_update (struct vrf *vrfp)
+{
+ zebra_vrf_add_update (vrfp);
+
+ if (! CHECK_FLAG (vrfp->status, ZEBRA_VRF_ACTIVE))
+ {
+ SET_FLAG (vrfp->status, ZEBRA_VRF_ACTIVE);
+
+ //Pending: Check if the equivalent of if_addr_wakeup (ifp) is needed here.
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("VRF %s id %u becomes active.",
+ vrfp->name, vrfp->vrf_id);
+ }
+ else
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("VRF %s id %u is added.",
+ vrfp->name, vrfp->vrf_id);
+ }
+}
+
+/* Handle an interface delete event */
+void
+vrf_delete_update (struct vrf *vrfp)
+{
+ /* Mark VRF as inactive */
+ UNSET_FLAG (vrfp->status, ZEBRA_VRF_ACTIVE);
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("VRF %s id %u is now inactive.",
+ vrfp->name, vrfp->vrf_id);
+
+ zebra_vrf_delete_update (vrfp);
+
+ /* Pending: Update ifindex after distributing the delete message. This is in
+ case any client needs to have the old value of ifindex available
+ while processing the deletion. Each client daemon is responsible
+ for setting vrf-id to IFINDEX_INTERNAL after processing the
+ interface deletion message. */
+ vrfp->vrf_id = 0;
+}
+
+
static void
ipv6_ll_address_to_mac (struct in6_addr *address, u_char *mac)
{
1
};
+/* Wrapper hook point for zebra daemon so that ifindex can be set
+ * DEFUN macro not used as extract.pl HAS to ignore this
+ * See also interface_cmd in lib/if.c
+ */
+DEFUN_NOSH (zebra_vrf,
+ zebra_vrf_cmd,
+ "vrf NAME",
+ "Select a VRF to configure\n"
+ "VRF's name\n")
+{
+ int ret;
+
+ /* Call lib vrf() */
+ if ((ret = vrf_cmd.func (self, vty, argc, argv)) != CMD_SUCCESS)
+ return ret;
+
+ // vrfp = vty->index;
+
+ return ret;
+}
+
+struct cmd_node vrf_node =
+{
+ VRF_NODE,
+ "%s(config-vrf)# ",
+ 1
+};
+
/* Show all interfaces to vty. */
DEFUN (show_interface, show_interface_cmd,
"show interface",
#endif /* HAVE_NET_RT_IFLIST */
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
/* All interface print. */
for (ALL_LIST_ELEMENTS_RO (vrf_iflist (vrf_id), node, ifp))
#endif /* HAVE_NET_RT_IFLIST */
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
/* Specified interface print. */
ifp = if_lookup_by_name_vrf (argv[0], vrf_id);
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
if_show_description (vty, vrf_id);
struct listnode *addrnode;
struct connected *ifc;
struct prefix *p;
+ struct vrf *vrf;
if_data = ifp->info;
+ vrf = vrf_lookup(ifp->vrf_id);
if (ifp->vrf_id == VRF_DEFAULT)
vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE);
else
- vty_out (vty, "interface %s vrf %u%s", ifp->name, ifp->vrf_id,
+ vty_out (vty, "interface %s vrf %s%s", ifp->name, vrf->name,
VTY_NEWLINE);
if (if_data)
return 0;
}
+static int
+vrf_config_write (struct vty *vty)
+{
+ struct listnode *node;
+ struct vrf *vrf;
+
+ for (ALL_LIST_ELEMENTS_RO (vrf_list, node, vrf))
+ {
+ if (strcmp(vrf->name, VRF_DEFAULT_NAME))
+ {
+ vty_out (vty, "vrf %s%s", vrf->name, VTY_NEWLINE);
+ vty_out (vty, "!%s", VTY_NEWLINE);
+ }
+ }
+ return 0;
+}
+
/* Allocate and initialize interface vector. */
void
zebra_if_init (void)
/* Install configuration write function. */
install_node (&interface_node, if_config_write);
+ install_node (&vrf_node, vrf_config_write);
install_element (VIEW_NODE, &show_interface_cmd);
install_element (VIEW_NODE, &show_interface_vrf_cmd);
install_element (INTERFACE_NODE, &ip_address_label_cmd);
install_element (INTERFACE_NODE, &no_ip_address_label_cmd);
#endif /* HAVE_NETLINK */
+
+ install_element (CONFIG_NODE, &zebra_vrf_cmd);
+ install_element (CONFIG_NODE, &no_vrf_cmd);
+ install_default (VRF_NODE);
+
}
#define _ZEBRA_INTERFACE_H
#include "redistribute.h"
+#include "vrf.h"
#ifdef HAVE_IRDP
#include "zebra/irdp.h"
#endif /* SUNOS_5 */
};
+
+extern struct interface *if_lookup_by_index_per_ns (struct zebra_ns *, u_int32_t);
+extern struct interface *if_link_per_ns (struct zebra_ns *, struct interface *);
+extern void if_unlink_per_ns (struct interface *);
extern void if_nbr_ipv6ll_to_ipv4ll_neigh_update (struct interface *ifp,
struct in6_addr *address, int add);
extern void if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (struct interface *ifp);
extern int if_subnet_delete (struct interface *, struct connected *);
extern int ipv6_address_configured (struct interface *ifp);
+extern void vrf_delete_update (struct vrf *vrfp);
+extern void vrf_add_update (struct vrf *vrfp);
+
#ifdef HAVE_PROC_NET_DEV
extern void ifstat_update_proc (void);
#endif /* HAVE_PROC_NET_DEV */
struct prefix_ipv4 *p;
p = (struct prefix_ipv4 *) ifc->address;
- rib_lookup_and_pushup (p);
+ rib_lookup_and_pushup (p, ifp->vrf_id);
memset (&addreq, 0, sizeof addreq);
strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name);
return 0;
}
-void kernel_init (struct zebra_vrf *zvrf) { return; }
-void kernel_terminate (struct zebra_vrf *zvrf) { return; }
+void kernel_init (struct zebra_ns *zns) { return; }
+void kernel_terminate (struct zebra_ns *zns) { return; }
#ifdef HAVE_SYS_WEAK_ALIAS_PRAGMA
#pragma weak route_read = kernel_init
#else
-void route_read (struct zebra_vrf *zvrf) { return; }
+void route_read (struct zebra_ns *zns) { return; }
#endif
/* Make routing socket. */
static void
-routing_socket (struct zebra_vrf *zvrf)
+routing_socket (struct zebra_ns *zns)
{
- if (zvrf->vrf_id != VRF_DEFAULT)
- return;
-
if ( zserv_privs.change (ZPRIVS_RAISE) )
zlog_err ("routing_socket: Can't raise privileges");
/* Exported interface function. This function simply calls
routing_socket (). */
void
-kernel_init (struct zebra_vrf *zvrf)
+kernel_init (struct zebra_ns *zns)
{
- routing_socket (zvrf);
+ routing_socket (zns);
}
void
-kernel_terminate (struct zebra_vrf *zvrf)
+kernel_terminate (struct zebra_ns *zns)
{
return;
}
.handler = &sigint,
},
};
-
+
/* Callback upon creating a new VRF. */
static int
zebra_vrf_new (vrf_id_t vrf_id, const char *name, void **info)
{
struct zebra_vrf *zvrf = *info;
+ zlog_info ("ZVRF %s with id %u", name, vrf_id);
+
if (! zvrf)
{
- zvrf = zebra_vrf_alloc (vrf_id);
+ zvrf = zebra_vrf_alloc (vrf_id, name);
*info = (void *)zvrf;
router_id_init (zvrf);
}
return 0;
}
+static int
+zebra_ns_enable (ns_id_t ns_id, void **info)
+{
+ struct zebra_ns *zns = (struct zebra_ns *) (*info);
+#ifdef HAVE_NETLINK
+ char nl_name[64];
+#endif
+
+#ifdef HAVE_NETLINK
+ /* Initialize netlink sockets */
+ snprintf (nl_name, 64, "netlink-listen (NS %u)", ns_id);
+ zns->netlink.sock = -1;
+ zns->netlink.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name);
+
+ snprintf (nl_name, 64, "netlink-cmd (NS %u)", ns_id);
+ zns->netlink_cmd.sock = -1;
+ zns->netlink_cmd.name = XSTRDUP (MTYPE_NETLINK_NAME, nl_name);
+#endif
+ zns->if_table = route_table_init ();
+ kernel_init (zns);
+ interface_list (zns);
+ route_read (zns);
+
+ return 0;
+}
+
/* Callback upon enabling a VRF. */
static int
zebra_vrf_enable (vrf_id_t vrf_id, const char *name, void **info)
#if defined (HAVE_RTADV)
rtadv_init (zvrf);
#endif
- kernel_init (zvrf);
- interface_list (zvrf);
- route_read (zvrf);
return 0;
}
+/*
+static int
+zebra_ns_disable (ns_id_t ns_id, void **info)
+{
+ struct zebra_ns *zns = (struct zebra_ns *) (*info);
+
+ kernel_terminate (zns);
+
+ return 0;
+}
+*/
+
/* Callback upon disabling a VRF. */
static int
zebra_vrf_disable (vrf_id_t vrf_id, const char *name, void **info)
#if defined (HAVE_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);
static void
zebra_vrf_init (void)
{
+ struct zebra_ns *zns;
+
vrf_add_hook (VRF_NEW_HOOK, zebra_vrf_new);
vrf_add_hook (VRF_ENABLE_HOOK, zebra_vrf_enable);
vrf_add_hook (VRF_DISABLE_HOOK, zebra_vrf_disable);
+
+ /* Default NS initialization */
+
+ zns = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_ns));
+ dzns = zns; //Pending: Doing it all for the default namespace only for now.
+
vrf_init ();
+ zebra_ns_enable (0, (void **)&zns);
}
/* Main startup routine. */
}
}
+/* VRF information update. */
+void
+zebra_vrf_add_update (struct vrf *vrfp)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug ("MESSAGE: ZEBRA_VRF_ADD %s", vrfp->name);
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ zsend_vrf_add (client, vrfp);
+}
+
+void
+zebra_vrf_delete_update (struct vrf *vrfp)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug ("MESSAGE: ZEBRA_VRF_DELETE %s", vrfp->name);
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ zsend_vrf_delete (client, vrfp);
+}
+
+void
+zebra_vrf_update_all (struct zserv *client)
+{
+ struct vrf *vrf;
+ vrf_iter_t iter;
+
+ for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+ {
+ if ((vrf = vrf_iter2vrf (iter)) && vrf->vrf_id)
+ zsend_vrf_add (client, vrf);
+ }
+}
+
+
/* Interface address addition. */
void
zebra_interface_address_add_update (struct interface *ifp,
#include "table.h"
#include "zserv.h"
#include "vty.h"
+#include "vrf.h"
extern void zebra_redistribute_add (int, struct zserv *, int, vrf_id_t);
extern void zebra_redistribute_delete (int, struct zserv *, int, vrf_id_t);
extern void zebra_interface_up_update (struct interface *);
extern void zebra_interface_down_update (struct interface *);
+extern void zebra_vrf_add_update (struct vrf *);
+extern void zebra_vrf_update_all (struct zserv *);
+extern void zebra_vrf_delete_update (struct vrf *);
extern void zebra_interface_add_update (struct interface *);
extern void zebra_interface_delete_update (struct interface *);
{ return; }
#endif
+void zebra_vrf_add_update (struct vrf *a)
+{ return; }
+void zebra_vrf_delete_update (struct vrf *a)
+{ return; }
+
void zebra_interface_address_add_update (struct interface *a,
struct connected *b)
{ return; }
/* Identifier. */
ns_id_t ns_id;
+#ifdef HAVE_NETLINK
+ struct nlsock netlink; /* kernel messages */
+ struct nlsock netlink_cmd; /* command channel */
+ struct thread *t_netlink;
+#endif
+
struct route_table *if_table;
};
-
/* Routing table instance. */
struct zebra_vrf
{
/* Routing tables off of main table for redistribute table */
struct route_table *other_table[AFI_MAX][ZEBRA_KERNEL_TABLE_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
*/
struct zebra_ns *zns;
};
+extern struct zebra_ns *dzns;
+
/*
* rib_table_info_t
*
extern void rib_copy_nexthops (struct rib *rib, struct nexthop *nh);
extern int nexthop_has_fib_child(struct nexthop *);
-extern void rib_lookup_and_dump (struct prefix_ipv4 *);
-extern void rib_lookup_and_pushup (struct prefix_ipv4 *);
+extern void rib_lookup_and_dump (struct prefix_ipv4 *, vrf_id_t);
+extern void rib_lookup_and_pushup (struct prefix_ipv4 *, vrf_id_t);
#define rib_dump(prefix ,rib) _rib_dump(__func__, prefix, rib)
extern void _rib_dump (const char *,
union prefix46constptr, const struct rib *);
unsigned int ifindex);
extern struct zebra_vrf *zebra_vrf_lookup (vrf_id_t vrf_id);
-extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t);
+extern struct zebra_vrf *zebra_vrf_alloc (vrf_id_t, const char *);
extern struct route_table *zebra_vrf_table (afi_t, safi_t, vrf_id_t);
extern struct route_table *zebra_vrf_static_table (afi_t, safi_t, vrf_id_t);
extern struct route_table *zebra_vrf_other_route_table (afi_t afi, u_int32_t table_id,
rid.family = AF_INET;
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
router_id_set (&rid, vrf_id);
rid.family = AF_INET;
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
router_id_set (&rid, vrf_id);
#include "zebra/redistribute.h"
#include "zebra/interface.h"
#include "zebra/debug.h"
+#include "zebra/rtadv.h"
#include "rt_netlink.h"
{
struct interface *oifp;
- if (((oifp = if_lookup_by_index(ifi_index)) != NULL) && (oifp != ifp))
+ if (((oifp = if_lookup_by_index_per_ns (dzns, ifi_index)) != NULL) && (oifp != ifp))
{
if (ifi_index == IFINDEX_INTERNAL)
zlog_err("Netlink is setting interface %s ifindex to reserved "
/* Make socket for Linux netlink interface. */
static int
-netlink_socket (struct nlsock *nl, unsigned long groups, vrf_id_t vrf_id)
+netlink_socket (struct nlsock *nl, unsigned long groups, ns_id_t ns_id)
{
int ret;
struct sockaddr_nl snl;
return -1;
}
- sock = vrf_socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, vrf_id);
+ sock = vrf_socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, ns_id);
if (sock < 0)
{
zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
return 0;
}
+/*
+Pending: create an efficient table_id (in a tree/hash) based lookup)
+ */
+static vrf_id_t
+vrf_lookup_by_table (u_int32_t table_id)
+{
+ struct zebra_vrf *zvrf;
+ vrf_iter_t iter;
+
+ for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+ {
+ if ((zvrf = vrf_iter2info (iter)) == NULL ||
+ (zvrf->table_id != table_id))
+ continue;
+
+ return zvrf->vrf_id;
+ }
+
+ return VRF_DEFAULT;
+}
+
/* 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 *,
- vrf_id_t),
- struct nlsock *nl, struct zebra_vrf *zvrf)
+ ns_id_t),
+ struct nlsock *nl, struct zebra_ns *zns)
{
int status;
int ret = 0;
}
/* Deal with errors that occur because of races in link handling */
- if (nl == &zvrf->netlink_cmd
+ if (nl == &zns->netlink_cmd
&& ((msg_type == RTM_DELROUTE &&
(-errnum == ENODEV || -errnum == ESRCH))
|| (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
return 0;
}
- if (nl == &zvrf->netlink_cmd
+ if (nl == &zns->netlink_cmd
&& msg_type == RTM_NEWROUTE && -errnum == ESRCH)
{
/* This is known to happen in some situations, don't log
/* 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 != &zvrf->netlink_cmd
- && h->nlmsg_pid == zvrf->netlink_cmd.snl.nl_pid
+ if (nl != &zns->netlink_cmd
+ && h->nlmsg_pid == zns->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",
- zvrf->netlink_cmd.name, nl->name);
+ zns->netlink_cmd.name, nl->name);
continue;
}
- error = (*filter) (&snl, h, zvrf->vrf_id);
+ error = (*filter) (&snl, h, zns->ns_id);
if (error < 0)
{
zlog (NULL, LOG_ERR, "%s filter function error", nl->name);
}
}
+#define parse_rtattr_nested(tb, max, rta) \
+ netlink_parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))
+
+static void
+netlink_vrf_change (struct nlmsghdr *h, struct rtattr *tb, const char *name)
+{
+ struct ifinfomsg *ifi;
+ struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+ struct rtattr *attr[IFLA_VRF_MAX+1];
+ struct vrf *vrf;
+ struct zebra_vrf *zvrf;
+ u_int32_t nl_table_id;
+
+ ifi = NLMSG_DATA (h);
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: received VRF device message: %s", __func__, name);
+
+ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);
+
+ if (!linkinfo[IFLA_INFO_DATA]) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: IFLA_INFO_DATA missing from VRF message: %s", __func__, name);
+ return;
+ }
+
+ parse_rtattr_nested(attr, IFLA_VRF_MAX, linkinfo[IFLA_INFO_DATA]);
+ if (!attr[IFLA_VRF_TABLE]) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: IFLA_VRF_TABLE missing from VRF message: %s", __func__, name);
+ return;
+ }
+
+ nl_table_id = *(u_int32_t *)RTA_DATA(attr[IFLA_VRF_TABLE]);
+
+ if (h->nlmsg_type == RTM_NEWLINK)
+ {
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: RTM_NEWLINK for VRF index %u, table %u", __func__,
+ ifi->ifi_index, nl_table_id);
+
+ vrf = vrf_get((vrf_id_t)ifi->ifi_index, name); // It would create vrf
+ if (!vrf)
+ {
+ zlog_err ("VRF %s id %u not created", name, ifi->ifi_index);
+ return;
+ }
+
+ /* Enable the created VRF. */
+ if (!vrf_enable (vrf))
+ {
+ zlog_err ("Failed to enable VRF %s id %u", name, ifi->ifi_index);
+ return;
+ }
+
+ /*Pending: See if you want to optimize this code.. vrf, zvrf all have name */
+ zvrf = vrf->info;
+ zvrf->table_id = nl_table_id;
+
+ vrf_add_update(vrf);
+ }
+ else //h->nlmsg_type == RTM_DELLINK
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: RTM_DELLINK for vrf id %u", __func__, ifi->ifi_index);
+
+ vrf = vrf_lookup ((vrf_id_t)ifi->ifi_index);
+
+ if (!vrf)
+ zlog_warn ("%s: vrf not found", __func__);
+
+ vrf_delete_update(vrf);
+
+ //Pending: keeping VRF around just like its for other links.
+ //vrf_delete (vrf);
+ }
+}
+
+static char *
+parse_link_kind (struct rtattr *tb)
+{
+ struct rtattr *linkinfo[IFLA_INFO_MAX+1];
+
+ memset (linkinfo, 0, sizeof(struct rtattr *)*(IFLA_INFO_MAX+1));
+ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb);
+
+ if (linkinfo[IFLA_INFO_KIND])
+ return RTA_DATA(linkinfo[IFLA_INFO_KIND]);
+
+ return NULL;
+}
/* Called from interface_lookup_netlink(). This function is only used
during bootstrap. */
static int
return -1;
name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
+ if (tb[IFLA_LINKINFO])
+ {
+ char *kind = parse_link_kind(tb[IFLA_LINKINFO]);
+
+ if (kind && strcmp(kind, "vrf") == 0)
+ {
+ netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
+ return 0;
+ }
+ }
+
+ if (tb[IFLA_MASTER])
+ vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
+
/* Add interface. */
ifp = if_get_by_name_vrf (name, vrf_id);
set_ifindex(ifp, ifi->ifi_index);
/* Lookup interface IPv4/IPv6 address. */
static int
netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h,
- vrf_id_t vrf_id)
+ ns_id_t ns_id)
{
int len;
struct ifaddrmsg *ifa;
u_char flags = 0;
char *label = NULL;
+ vrf_id_t vrf_id = ns_id;
+
ifa = NLMSG_DATA (h);
if (ifa->ifa_family != AF_INET
memset (tb, 0, sizeof tb);
netlink_parse_rtattr (tb, IFA_MAX, IFA_RTA (ifa), len);
- ifp = if_lookup_by_index_vrf (ifa->ifa_index, vrf_id);
+ ifp = if_lookup_by_index_per_ns (dzns, ifa->ifa_index);
if (ifp == NULL)
{
zlog_err ("netlink_interface_addr can't find interface by index %d vrf %u",
if (!is_zebra_valid_kernel_table(table) && !is_zebra_main_routing_table(table))
return 0;
+ vrf_id = vrf_lookup_by_table(table);
+
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
if (len < 0)
return -1;
/* Routing information change from the kernel. */
static int
netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
- vrf_id_t vrf_id)
+ ns_id_t ns_id)
{
int len;
struct rtmsg *rtm;
void *gate;
void *src;
+ vrf_id_t vrf_id = ns_id;
+
rtm = NLMSG_DATA (h);
if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
if (!is_zebra_valid_kernel_table(table) && !is_zebra_main_routing_table(table))
return 0;
+ vrf_id = vrf_lookup_by_table(table);
+
len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
if (len < 0)
return -1;
static int
netlink_link_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
- vrf_id_t vrf_id)
+ ns_id_t ns_id)
{
int len;
struct ifinfomsg *ifi;
struct rtattr *tb[IFLA_MAX + 1];
struct interface *ifp;
char *name;
+ struct connected *ifc;
+ struct listnode *node;
+
+ vrf_id_t vrf_id = ns_id;
ifi = NLMSG_DATA (h);
return -1;
name = (char *) RTA_DATA (tb[IFLA_IFNAME]);
+ if (tb[IFLA_LINKINFO])
+ {
+ char *kind = parse_link_kind(tb[IFLA_LINKINFO]);
+
+ if (kind && strcmp(kind, "vrf") == 0)
+ {
+ netlink_vrf_change(h, tb[IFLA_LINKINFO], name);
+ return 0;
+ }
+ }
+
/* Add interface. */
if (h->nlmsg_type == RTM_NEWLINK)
{
- ifp = if_lookup_by_name_vrf (name, vrf_id);
+ if (tb[IFLA_MASTER])
+ vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
- if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE))
+ /* clean up any old ifps in a different VRF */
+ ifp = if_lookup_by_index_per_ns (dzns, ifi->ifi_index);
+ if (ifp && ifp->vrf_id != vrf_id)
+ {
+ if_down (ifp); //Ideally, we should have down/delete come from kernel
+ // if_delete_update (ifp); //Pending: see how best to make the old ifp unusable
+ for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
+ if (ifc->address->family == AF_INET6)
+ ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS);
+ }
+
+ if (ifp == NULL || !CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE) ||
+ ifp->vrf_id != vrf_id)
{
if (ifp == NULL)
ifp = if_get_by_name_vrf (name, vrf_id);
+ else
+ {
+ if_update_vrf (ifp, name, strlen(name), vrf_id);
+
+ for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
+ if (ifc->address->family == AF_INET6)
+ ipv6_nd_suppress_ra_set (ifp, RA_ENABLE);
+ }
set_ifindex(ifp, ifi->ifi_index);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 0;
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: RTM_NEWLINK for %s vrf_id %u", __func__, name,
+ ifp->vrf_id);
+
+
netlink_interface_update_hw_addr (tb, ifp);
/* If new link is added. */
ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 0;
+ // Pending, handle the vrf_id change..
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: RTM_NEWLINK status for %s vrf_id %u", __func__, name,
+ ifp->vrf_id);
+
netlink_interface_update_hw_addr (tb, ifp);
if (if_is_no_ptm_operative (ifp))
}
else
{
+ if (tb[IFLA_MASTER])
+ vrf_id = *(u_int32_t *)RTA_DATA(tb[IFLA_MASTER]);
+
/* RTM_DELLINK. */
ifp = if_lookup_by_name_vrf (name, vrf_id);
static int
netlink_information_fetch (struct sockaddr_nl *snl, struct nlmsghdr *h,
- vrf_id_t vrf_id)
+ ns_id_t ns_id)
{
/* JF: Ignore messages that aren't from the kernel */
if ( snl->nl_pid != 0 )
switch (h->nlmsg_type)
{
case RTM_NEWROUTE:
- return netlink_route_change (snl, h, vrf_id);
+ return netlink_route_change (snl, h, ns_id);
break;
case RTM_DELROUTE:
- return netlink_route_change (snl, h, vrf_id);
+ return netlink_route_change (snl, h, ns_id);
break;
case RTM_NEWLINK:
- return netlink_link_change (snl, h, vrf_id);
+ return netlink_link_change (snl, h, ns_id);
break;
case RTM_DELLINK:
- return netlink_link_change (snl, h, vrf_id);
+ return netlink_link_change (snl, h, ns_id);
break;
case RTM_NEWADDR:
- return netlink_interface_addr (snl, h, vrf_id);
+ return netlink_interface_addr (snl, h, ns_id);
break;
case RTM_DELADDR:
- return netlink_interface_addr (snl, h, vrf_id);
+ return netlink_interface_addr (snl, h, ns_id);
break;
default:
zlog_warn ("Unknown netlink nlmsg_type %d vrf %u\n", h->nlmsg_type,
- vrf_id);
+ ns_id);
break;
}
return 0;
/* Interface lookup by netlink socket. */
int
-interface_lookup_netlink (struct zebra_vrf *zvrf)
+interface_lookup_netlink (struct zebra_ns *zns)
{
int ret;
/* Get interface information. */
- ret = netlink_request (AF_PACKET, RTM_GETLINK, &zvrf->netlink_cmd);
+ ret = netlink_request (AF_PACKET, RTM_GETLINK, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface, &zvrf->netlink_cmd, zvrf);
+ ret = netlink_parse_info (netlink_interface, &zns->netlink_cmd, zns);
if (ret < 0)
return ret;
/* Get IPv4 address of the interfaces. */
- ret = netlink_request (AF_INET, RTM_GETADDR, &zvrf->netlink_cmd);
+ ret = netlink_request (AF_INET, RTM_GETADDR, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf);
+ ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns);
if (ret < 0)
return ret;
#ifdef HAVE_IPV6
/* Get IPv6 address of the interfaces. */
- ret = netlink_request (AF_INET6, RTM_GETADDR, &zvrf->netlink_cmd);
+ ret = netlink_request (AF_INET6, RTM_GETADDR, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_interface_addr, &zvrf->netlink_cmd, zvrf);
+ ret = netlink_parse_info (netlink_interface_addr, &zns->netlink_cmd, zns);
if (ret < 0)
return ret;
#endif /* HAVE_IPV6 */
/* Routing table read function using netlink interface. Only called
bootstrap time. */
int
-netlink_route_read (struct zebra_vrf *zvrf)
+netlink_route_read (struct zebra_ns *zns)
{
int ret;
/* Get IPv4 routing table. */
- ret = netlink_request (AF_INET, RTM_GETROUTE, &zvrf->netlink_cmd);
+ ret = netlink_request (AF_INET, RTM_GETROUTE, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf);
+ ret = netlink_parse_info (netlink_routing_table, &zns->netlink_cmd, zns);
if (ret < 0)
return ret;
#ifdef HAVE_IPV6
/* Get IPv6 routing table. */
- ret = netlink_request (AF_INET6, RTM_GETROUTE, &zvrf->netlink_cmd);
+ ret = netlink_request (AF_INET6, RTM_GETROUTE, &zns->netlink_cmd);
if (ret < 0)
return ret;
- ret = netlink_parse_info (netlink_routing_table, &zvrf->netlink_cmd, zvrf);
+ ret = netlink_parse_info (netlink_routing_table, &zns->netlink_cmd, zns);
if (ret < 0)
return ret;
#endif /* HAVE_IPV6 */
static int
netlink_talk_filter (struct sockaddr_nl *snl, struct nlmsghdr *h,
- vrf_id_t vrf_id)
+ ns_id_t ns_id)
{
- zlog_warn ("netlink_talk: ignoring message type 0x%04x vrf %u", h->nlmsg_type,
- vrf_id);
+ zlog_warn ("netlink_talk: ignoring message type 0x%04x NS %u", h->nlmsg_type,
+ ns_id);
return 0;
}
/* sendmsg() to netlink socket then recvmsg(). */
static int
-netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_vrf *zvrf)
+netlink_talk (struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns)
{
int status;
struct sockaddr_nl snl;
* Get reply from netlink socket.
* The reply should either be an acknowlegement or an error.
*/
- return netlink_parse_info (netlink_talk_filter, nl, zvrf);
+ return netlink_parse_info (netlink_talk_filter, nl, zns);
}
/* Routing table change via netlink interface. */
struct sockaddr_nl snl;
int discard;
- struct zebra_vrf *zvrf = vrf_info_lookup (VRF_DEFAULT); //Pending
+ struct zebra_ns *zns = dzns;
struct
{
snl.nl_family = AF_NETLINK;
/* Talk to netlink socket. */
- ret = netlink_talk (&req.n, &zvrf->netlink_cmd, VRF_DEFAULT);
+ ret = netlink_talk (&req.n, &zns->netlink_cmd, NS_DEFAULT);
if (ret < 0)
return -1;
char buf[256];
} req;
- struct zebra_vrf *zvrf = vrf_info_lookup (VRF_DEFAULT); //Pending
+ struct zebra_ns *zns = dzns;
memset(&req.n, 0, sizeof(req.n));
memset(&req.ndm, 0, sizeof(req.ndm));
addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
- return netlink_talk (&req.n, &zvrf->netlink_cmd, VRF_DEFAULT);
+ return netlink_talk (&req.n, &zns->netlink_cmd, NS_DEFAULT);
}
/* Routing table change via netlink interface. */
char buf[NL_PKT_BUF_SIZE];
} req;
+ struct zebra_ns *zns = dzns;
struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id);
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
snl.nl_family = AF_NETLINK;
/* Talk to netlink socket. */
- return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf);
+ return netlink_talk (&req.n, &zns->netlink_cmd, zns);
}
int
char buf[NL_PKT_BUF_SIZE];
} req;
- struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
+ struct zebra_ns *zns = dzns; //vrf_info_lookup (ifp->vrf_id);
p = ifc->address;
memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
addattr_l (&req.n, sizeof req, IFA_LABEL, ifc->label,
strlen (ifc->label) + 1);
- return netlink_talk (&req.n, &zvrf->netlink_cmd, zvrf);
+ return netlink_talk (&req.n, &zns->netlink_cmd, zns);
}
int
static int
kernel_read (struct thread *thread)
{
- 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);
+ struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG (thread);
+ netlink_parse_info (netlink_information_fetch, &zns->netlink, zns);
+ zns->t_netlink = thread_add_read (zebrad.master, kernel_read, zns,
+ zns->netlink.sock);
return 0;
}
/* Exported interface function. This function simply calls
netlink_socket (). */
void
-kernel_init (struct zebra_vrf *zvrf)
+kernel_init (struct zebra_ns *zns)
{
unsigned long groups;
#ifdef HAVE_IPV6
groups |= RTMGRP_IPV6_ROUTE | RTMGRP_IPV6_IFADDR;
#endif /* HAVE_IPV6 */
- netlink_socket (&zvrf->netlink, groups, zvrf->vrf_id);
- netlink_socket (&zvrf->netlink_cmd, 0, zvrf->vrf_id);
+ netlink_socket (&zns->netlink, groups, zns->ns_id);
+ netlink_socket (&zns->netlink_cmd, 0, zns->ns_id);
/* Register kernel socket. */
- if (zvrf->netlink.sock > 0)
+ if (zns->netlink.sock > 0)
{
/* Only want non-blocking on the netlink event socket */
- if (fcntl (zvrf->netlink.sock, F_SETFL, O_NONBLOCK) < 0)
- zlog_err ("Can't set %s socket flags: %s", zvrf->netlink.name,
+ if (fcntl (zns->netlink.sock, F_SETFL, O_NONBLOCK) < 0)
+ zlog_err ("Can't set %s socket flags: %s", zns->netlink.name,
safe_strerror (errno));
/* Set receive buffer size if it's set from command line */
if (nl_rcvbufsize)
- netlink_recvbuf (&zvrf->netlink, nl_rcvbufsize);
+ netlink_recvbuf (&zns->netlink, nl_rcvbufsize);
- 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);
+ netlink_install_filter (zns->netlink.sock, zns->netlink_cmd.snl.nl_pid);
+ zns->t_netlink = thread_add_read (zebrad.master, kernel_read, zns,
+ zns->netlink.sock);
}
}
void
-kernel_terminate (struct zebra_vrf *zvrf)
+kernel_terminate (struct zebra_ns *zns)
{
- THREAD_READ_OFF (zvrf->t_netlink);
+ THREAD_READ_OFF (zns->t_netlink);
- if (zvrf->netlink.sock >= 0)
+ if (zns->netlink.sock >= 0)
{
- close (zvrf->netlink.sock);
- zvrf->netlink.sock = -1;
+ close (zns->netlink.sock);
+ zns->netlink.sock = -1;
}
- if (zvrf->netlink_cmd.sock >= 0)
+ if (zns->netlink_cmd.sock >= 0)
{
- close (zvrf->netlink_cmd.sock);
- zvrf->netlink_cmd.sock = -1;
+ close (zns->netlink_cmd.sock);
+ zns->netlink_cmd.sock = -1;
}
}
int
netlink_neigh_update (int cmd, int ifindex, __u32 addr, char *lla, int llalen);
-extern int interface_lookup_netlink (struct zebra_vrf *zvrf);
-extern int netlink_route_read (struct zebra_vrf *zvrf);
+extern int interface_lookup_netlink (struct zebra_ns *zns);
+extern int netlink_route_read (struct zebra_ns *zns);
#endif /* HAVE_NETLINK */
}
void
-route_read (struct zebra_vrf *zvrf)
+route_read (struct zebra_ns *zns)
{
char storage[RT_BUFSIZ];
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));
#include "zebra/zserv.h"
#include "zebra/rt_netlink.h"
-void route_read (struct zebra_vrf *zvrf)
+void route_read (struct zebra_ns *zns)
{
- netlink_route_read (zvrf);
+ netlink_route_read (zns);
}
/* Kernel routing table read up by sysctl function. */
void
-route_read (struct zebra_vrf *zvrf)
+route_read (struct zebra_ns *zns)
{
caddr_t buf, end, ref;
size_t bufsiz;
0
};
- if (zvrf->vrf_id != VRF_DEFAULT)
+ if (zns->ns_id != NS_DEFAULT)
return;
/* Get buffer size. */
if (! zvrf)
{
- zvrf = zebra_vrf_alloc (vrf_id);
+ zvrf = zebra_vrf_alloc (vrf_id, name);
*info = (void *)zvrf;
}
assert (zvrf);
- kernel_init (zvrf);
- route_read (zvrf);
-
return 0;
}
if_down (ifp);
}
- kernel_terminate (zvrf);
-
return 0;
}
s = client->obuf;
stream_reset (s);
- zserv_create_header (s, cmd, VRF_DEFAULT); //Pending:
+ zserv_create_header (s, cmd, VRF_DEFAULT); //Pending: adjust when multi-vrf bfd work
/* Write packet size. */
stream_putw_at (s, 0, stream_get_endp (s));
nexthop->src.ipv4 = *src;
nexthop->ifindex = ifindex;
ifp = if_lookup_by_index (nexthop->ifindex);
+ /*Pending: need to think if null ifp here is ok during bootup?
+ There was a crash because ifp here was coming to be NULL */
+ if (ifp)
if (connected_is_unnumbered(ifp)) {
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
}
rib->next = head;
dest->routes = rib;
- /* Further processing only if entry is in main table */
- if ((rib->table == RT_TABLE_MAIN) || (rib->table == zebrad.rtm_table_default))
- {
- if (process)
- rib_queue_add (&zebrad, rn);
- }
+ afi = (rn->p.family == AF_INET) ? AFI_IP :
+ (rn->p.family == AF_INET6) ? AFI_IP6 : AFI_MAX;
+ if (is_zebra_import_table_enabled (afi, rib->table))
+ zebra_add_import_table_entry(rn, rib);
else
- {
- afi = (rn->p.family == AF_INET) ? AFI_IP :
- (rn->p.family == AF_INET6) ? AFI_IP6 : AFI_MAX;
- if (is_zebra_import_table_enabled (afi, rib->table))
- zebra_add_import_table_entry(rn, rib);
- }
+ if (process)
+ rib_queue_add (&zebrad, rn);
}
static void
SET_FLAG (rib->status, RIB_ENTRY_REMOVED);
- if ((rib->table == RT_TABLE_MAIN) || (rib->table == zebrad.rtm_table_default))
- rib_queue_add (&zebrad, rn);
- else
+ afi = (rn->p.family == AF_INET) ? AFI_IP :
+ (rn->p.family == AF_INET6) ? AFI_IP6 : AFI_MAX;
+ if (is_zebra_import_table_enabled (afi, rib->table))
{
- afi = (rn->p.family == AF_INET) ? AFI_IP :
- (rn->p.family == AF_INET6) ? AFI_IP6 : AFI_MAX;
- if (is_zebra_import_table_enabled (afi, rib->table))
- zebra_del_import_table_entry(rn, rib);
+ zebra_del_import_table_entry(rn, rib);
/* Just clean up if non main table */
if (IS_ZEBRA_DEBUG_RIB)
{
rib_unlink(rn, rib);
}
+ else
+ {
+ rib_queue_add (&zebrad, rn);
+ }
}
int
* RIB entry found by rib_lookup_ipv4_route()
*/
-void rib_lookup_and_dump (struct prefix_ipv4 * p)
+void rib_lookup_and_dump (struct prefix_ipv4 * p, vrf_id_t vrf_id)
{
struct route_table *table;
struct route_node *rn;
char prefix_buf[INET_ADDRSTRLEN];
/* Lookup table. */
- table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
+ table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
{
zlog_err ("%s: zebra_vrf_table() returned NULL", __func__);
* actions, if needed: remove such a route from FIB and deSELECT
* corresponding RIB entry. Then put affected RN into RIBQ head.
*/
-void rib_lookup_and_pushup (struct prefix_ipv4 * p)
+void rib_lookup_and_pushup (struct prefix_ipv4 * p, vrf_id_t vrf_id)
{
struct route_table *table;
struct route_node *rn;
struct rib *rib;
unsigned changed = 0;
- if (NULL == (table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT)))
+ if (NULL == (table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id)))
{
zlog_err ("%s: zebra_vrf_table() returned NULL", __func__);
return;
rib->distance = si->distance;
rib->metric = 0;
rib->vrf_id = si->vrf_id;
- rib->table = zebrad.rtm_table_default;
+ rib->table = si->vrf_id ? (zebra_vrf_lookup(si->vrf_id))->table_id : zebrad.rtm_table_default;
rib->nexthop_num = 0;
rib->tag = si->tag;
if (!rib)
return 0;
- table = zebra_vrf_table (AFI_IP, safi, VRF_DEFAULT);
+ table = zebra_vrf_table (AFI_IP, safi, rib->vrf_id);
if (!table)
return 0;
/* Make it sure prefixlen is applied to the prefix. */
/* Lookup table. */
if ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default))
{
- table = zebra_vrf_table (AFI_IP6, safi, VRF_DEFAULT);
+ table = zebra_vrf_table (AFI_IP6, safi, rib->vrf_id);
}
else
{
- table = zebra_vrf_other_route_table(AFI_IP6, table_id, VRF_DEFAULT);
+ table = zebra_vrf_other_route_table(AFI_IP6, table_id, rib->vrf_id);
}
if (! table)
}
/* XXX factor with rib_delete_ipv6 */
+
int
rib_delete_ipv6 (int type, u_short instance, int flags, struct prefix_ipv6 *p,
struct in6_addr *gate, unsigned int ifindex, vrf_id_t vrf_id,
}
else
{
- table = zebra_vrf_other_route_table(AFI_IP6, table_id, VRF_DEFAULT);
+ table = zebra_vrf_other_route_table(AFI_IP6, table_id, vrf_id);
}
if (! table)
return 0;
/* Allocate new zebra VRF. */
struct zebra_vrf *
-zebra_vrf_alloc (vrf_id_t vrf_id)
+zebra_vrf_alloc (vrf_id_t vrf_id, const char *name)
{
struct zebra_vrf *zvrf;
-#ifdef HAVE_NETLINK
- char nl_name[64];
-#endif
zvrf = XCALLOC (MTYPE_ZEBRA_VRF, sizeof (struct zebra_vrf));
/* 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
+ if (name)
+ {
+ strncpy (zvrf->name, name, strlen(name));
+ zvrf->name[strlen(name)] = '\0';
+ }
return zvrf;
}
if (table_id >= ZEBRA_KERNEL_TABLE_MAX)
return NULL;
+ /* Pending: This is a MUST-DO for import-table feature.
+ - Making it work like zebra_vrf_table() for now. Ideally, we want to
+ implement import table in a way, so that the other_table doesnt have to be
+ maintained separately.
+ - Need to explore how to provide import table concept
+ (May be only the default VRF?)
+ - How/if to provide some safety against picking a import table to be same as
+ a table associated/used in some other vrf.
if (zvrf->other_table[afi][table_id] == NULL)
{
zvrf->other_table[afi][table_id] = route_table_init();
}
-
return (zvrf->other_table[afi][table_id]);
+ */
+
+ return zvrf->table[afi][SAFI_UNICAST];
}
/* VRF id */
if (vrf_id_str)
- VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str);
+ VRF_GET_ID (vrf_id, vrf_id_str); //Pending: create VRF if the given vrf doesnt exist?
/* Null0 static route. */
if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0))
struct route_node *rn;
struct rib *rib;
int first = 1;
+ vrf_id_t vrf_id = VRF_DEFAULT;
- table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, VRF_DEFAULT);
+ if (argc)
+ VRF_GET_ID (vrf_id, argv[0]);
+
+ table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
return CMD_SUCCESS;
IP_STR
"IP nexthop tracking table\n")
{
- zebra_print_rnh_table(0, AF_INET, vty, RNH_NEXTHOP_TYPE);
+ vrf_id_t vrf_id = VRF_DEFAULT;
+
+ if (argc)
+ VRF_GET_ID (vrf_id, argv[0]);
+
+ zebra_print_rnh_table(vrf_id, AF_INET, vty, RNH_NEXTHOP_TYPE);
return CMD_SUCCESS;
}
+ALIAS (show_ip_nht,
+ show_ip_nht_vrf_cmd,
+ "show ip nht " VRF_CMD_STR,
+ SHOW_STR
+ IP_STR
+ "IP nexthop tracking table\n"
+ VRF_CMD_HELP_STR)
+
DEFUN (show_ipv6_nht,
show_ipv6_nht_cmd,
"show ipv6 nht",
IP_STR
"IPv6 nexthop tracking table\n")
{
- zebra_print_rnh_table(0, AF_INET6, vty, RNH_NEXTHOP_TYPE);
+ vrf_id_t vrf_id = VRF_DEFAULT;
+
+ if (argc)
+ VRF_GET_ID (vrf_id, argv[0]);
+
+ zebra_print_rnh_table(vrf_id, AF_INET6, vty, RNH_NEXTHOP_TYPE);
return CMD_SUCCESS;
}
+ALIAS (show_ipv6_nht,
+ show_ipv6_nht_vrf_cmd,
+ "show ipv6 nht " VRF_CMD_STR,
+ SHOW_STR
+ IP_STR
+ "IPv6 nexthop tracking table\n"
+ VRF_CMD_HELP_STR)
+
DEFUN (ip_nht_default_route,
ip_nht_default_route_cmd,
"ip nht resolve-via-default",
}
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
}
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
}
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
}
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (! table)
vty_out (vty, " %d", si->distance);
if (si->vrf_id != VRF_DEFAULT)
- vty_out (vty, " vrf %u", si->vrf_id);
+ {
+ struct vrf *vrf;
+
+ vrf = vrf_lookup(si->vrf_id);
+ vty_out (vty, " vrf %s", vrf ? vrf->name : "");
+ }
vty_out (vty, "%s", VTY_NEWLINE);
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
table = zebra_vrf_table (AFI_IP, SAFI_MULTICAST, vrf_id);
if (! table)
/* VRF id */
if (vrf_id_str)
- VTY_GET_INTEGER ("VRF ID", vrf_id, vrf_id_str);
+ VRF_GET_ID (vrf_id, vrf_id_str);
if (add_cmd)
static_add_ipv6 (&p, type, gate, ifindex, flag, tag, distance, vrf_id);
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (! table)
}
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (! table)
}
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (! table)
}
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (! table)
}
if (argc > 1)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
+ VRF_GET_ID (vrf_id, argv[1]);
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (! table)
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (! table)
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (! table)
vrf_id_t vrf_id = VRF_DEFAULT;
if (argc > 0)
- VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
+ VRF_GET_ID (vrf_id, argv[0]);
table = zebra_vrf_table (AFI_IP6, SAFI_MULTICAST, vrf_id);
if (! table)
return CMD_SUCCESS;
}
+/* show vrf */
+DEFUN (show_vrf,
+ show_vrf_cmd,
+ "show vrf",
+ SHOW_STR
+ "VRF\n")
+{
+ struct zebra_vrf *zvrf;
+ vrf_iter_t iter;
+
+ for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
+ {
+ if ((zvrf = vrf_iter2info (iter)) == NULL)
+ continue;
+ if (!zvrf->vrf_id)
+ continue;
+
+ vty_out (vty, "vrf %s id %u table %u%s",
+ zvrf->name, zvrf->vrf_id, zvrf->table_id, VTY_NEWLINE);
+
+ }
+
+ return CMD_SUCCESS;
+}
+
/* Static ip route configuration write function. */
static int
zebra_ip_config (struct vty *vty)
install_element (CONFIG_NODE, &no_ip_zebra_import_table_cmd);
install_element (CONFIG_NODE, &no_ip_zebra_import_table_distance_cmd);
+ install_element (VIEW_NODE, &show_vrf_cmd);
install_element (VIEW_NODE, &show_ip_route_cmd);
install_element (VIEW_NODE, &show_ip_route_ospf_instance_cmd);
install_element (VIEW_NODE, &show_ip_route_tag_cmd);
install_element (VIEW_NODE, &show_ip_nht_cmd);
+ install_element (VIEW_NODE, &show_ip_nht_vrf_cmd);
install_element (VIEW_NODE, &show_ipv6_nht_cmd);
+ install_element (VIEW_NODE, &show_ipv6_nht_vrf_cmd);
install_element (VIEW_NODE, &show_ip_route_addr_cmd);
install_element (VIEW_NODE, &show_ip_route_prefix_cmd);
install_element (VIEW_NODE, &show_ip_route_prefix_longer_cmd);
install_element (VIEW_NODE, &show_ip_route_supernets_cmd);
install_element (VIEW_NODE, &show_ip_route_summary_cmd);
install_element (VIEW_NODE, &show_ip_route_summary_prefix_cmd);
+ install_element (ENABLE_NODE, &show_vrf_cmd);
install_element (ENABLE_NODE, &show_ip_route_cmd);
install_element (ENABLE_NODE, &show_ip_route_ospf_instance_cmd);
install_element (ENABLE_NODE, &show_ip_route_tag_cmd);
install_element (ENABLE_NODE, &show_ip_nht_cmd);
- install_element (ENABLE_NODE, &show_ipv6_nht_cmd);
+ install_element (ENABLE_NODE, &show_ip_nht_vrf_cmd);
+ install_element (ENABLE_NODE, &show_ipv6_nht_vrf_cmd);
install_element (ENABLE_NODE, &show_ip_route_addr_cmd);
install_element (ENABLE_NODE, &show_ip_route_prefix_cmd);
install_element (ENABLE_NODE, &show_ip_route_prefix_longer_cmd);
stream_putw_at (s, 0, stream_get_endp (s));
}
+static void
+zserv_encode_vrf (struct stream *s, struct vrf *vrfp)
+{
+ /* Interface information. */
+ stream_put (s, vrfp->name, VRF_NAMSIZ);
+
+ /* Write packet size. */
+ stream_putw_at (s, 0, stream_get_endp (s));
+}
+
/* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
/*
* This function is called in the following situations:
return zebra_server_send_message (client);
}
+int
+zsend_vrf_add (struct zserv *client, struct vrf *vrfp)
+{
+ struct stream *s;
+
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_VRF_ADD, vrfp->vrf_id);
+ zserv_encode_vrf (s, vrfp);
+
+ client->vrfadd_cnt++;
+ return zebra_server_send_message(client);
+}
+
+/* VRF deletion from zebra daemon. */
+int
+zsend_vrf_delete (struct zserv *client, struct vrf *vrfp)
+{
+ struct stream *s;
+
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_VRF_DELETE, vrfp->vrf_id);
+ zserv_encode_vrf (s, vrfp);
+
+ client->vrfdel_cnt++;
+ return zebra_server_send_message (client);
+}
+
/* Interface address is added/deleted. Send ZEBRA_INTERFACE_ADDRESS_ADD or
* ZEBRA_INTERFACE_ADDRESS_DELETE to the client.
*
p.family);
return -1;
}
- rnh = zebra_add_rnh(&p, 0, type);
+ rnh = zebra_add_rnh(&p, vrf_id, type);
if (type == RNH_NEXTHOP_TYPE)
{
if (flags && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
zebra_add_rnh_client(rnh, client, type, vrf_id);
/* Anything not AF_INET/INET6 has been filtered out above */
- zebra_evaluate_rnh(0, p.family, 1, type, &p);
+ zebra_evaluate_rnh(vrf_id, p.family, 1, type, &p);
}
return 0;
}
/* Nexthop register */
static int
zserv_rnh_unregister (struct zserv *client, int sock, u_short length,
- rnh_type_t type)
+ rnh_type_t type, vrf_id_t vrf_id)
{
struct rnh *rnh;
struct stream *s;
p.family);
return -1;
}
- rnh = zebra_lookup_rnh(&p, 0, type);
+ rnh = zebra_lookup_rnh(&p, vrf_id, type);
if (rnh)
{
client->nh_dereg_time = quagga_time(NULL);
rib->tag = 0;
/* Table */
- rib->table=zebrad.rtm_table_default;
+ if (vrf_id)
+ {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup (vrf_id);
+ if (zvrf)
+ rib->table = zvrf->table_id;
+ }
+ else
+ {
+ rib->table=zebrad.rtm_table_default;
+ }
ret = rib_add_ipv4_multipath (&p, rib, safi);
/* Stats */
struct prefix_ipv4 p;
u_char nexthop_num;
u_char nexthop_type;
+ u_int32_t table_id;
+ table_id = client->rtm_table;
+
s = client->ibuf;
ifindex = 0;
nexthop.s_addr = 0;
else
api.tag = 0;
+ if (vrf_id)
+ {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup (vrf_id);
+ if (zvrf)
+ table_id = zvrf->table_id;
+ }
+ else
+ {
+ table_id = client->rtm_table;
+ }
+
rib_delete_ipv4 (api.type, api.instance, api.flags, &p, nexthop_p, ifindex,
- vrf_id, client->rtm_table, api.safi);
+ vrf_id, table_id, api.safi);
client->v4_route_del_cnt++;
return 0;
}
#ifdef HAVE_IPV6
/* Zebra server IPv6 prefix add function. */
static int
-zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length)
+zread_ipv4_route_ipv6_nexthop_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
{
int i;
struct stream *s;
rib->tag = 0;
/* Table */
- rib->table=zebrad.rtm_table_default;
+ if (vrf_id)
+ {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup (vrf_id);
+ if (zvrf)
+ rib->table = zvrf->table_id;
+ }
+ else
+ {
+ rib->table=zebrad.rtm_table_default;
+ }
ret = rib_add_ipv6_multipath ((struct prefix *)&p, rib, safi, ifindex);
/* Stats */
if (ret > 0)
else
rib->tag = 0;
- /* Table */
- rib->table=zebrad.rtm_table_default;
rib->vrf_id = vrf_id;
+ /* Table */
+ if (vrf_id)
+ {
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup (vrf_id);
+ if (zvrf)
+ rib->table = zvrf->table_id;
+ }
+ else
+ {
+ rib->table=zebrad.rtm_table_default;
+ }
ret = rib_add_ipv6_multipath ((struct prefix *)&p, rib, safi, ifindex);
/* Stats */
if (ret > 0)
/* Make new read thread. */
zebra_event (ZEBRA_READ, sock, client);
+
+ zebra_vrf_update_all (client);
}
/* Handler of zebra service request. */
break;
#ifdef HAVE_IPV6
case ZEBRA_IPV4_ROUTE_IPV6_NEXTHOP_ADD:
- zread_ipv4_route_ipv6_nexthop_add (client, length);
+ zread_ipv4_route_ipv6_nexthop_add (client, length, vrf_id);
break;
case ZEBRA_IPV6_ROUTE_ADD:
zread_ipv6_add (client, length, vrf_id);
zserv_rnh_register(client, sock, length, RNH_NEXTHOP_TYPE, vrf_id);
break;
case ZEBRA_NEXTHOP_UNREGISTER:
- zserv_rnh_unregister(client, sock, length, RNH_NEXTHOP_TYPE);
+ zserv_rnh_unregister(client, sock, length, RNH_NEXTHOP_TYPE, vrf_id);
break;
case ZEBRA_IMPORT_ROUTE_REGISTER:
zserv_rnh_register(client, sock, length, RNH_IMPORT_CHECK_TYPE, vrf_id);
break;
case ZEBRA_IMPORT_ROUTE_UNREGISTER:
- zserv_rnh_unregister(client, sock, length, RNH_IMPORT_CHECK_TYPE);
+ zserv_rnh_unregister(client, sock, length, RNH_IMPORT_CHECK_TYPE, vrf_id);
break;
case ZEBRA_BFD_DEST_UPDATE:
case ZEBRA_BFD_DEST_REGISTER:
u_int32_t bfd_peer_upd8_cnt;
u_int32_t bfd_peer_del_cnt;
u_int32_t bfd_peer_replay_cnt;
+ u_int32_t vrfadd_cnt;
+ u_int32_t vrfdel_cnt;
time_t connect_time;
time_t last_read_time;
extern void zebra_zserv_socket_init (char *path);
extern void hostinfo_get (void);
extern void rib_init (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 interface_list (struct zebra_ns *);
+extern void route_read (struct zebra_ns *);
+extern void kernel_init (struct zebra_ns *);
+extern void kernel_terminate (struct zebra_ns *);
extern void zebra_route_map_init (void);
extern void zebra_snmp_init (void);
extern void zebra_vty_init (void);
+extern int zsend_vrf_add (struct zserv *, struct vrf *);
+extern int zsend_vrf_delete (struct zserv *, struct vrf *);
+
extern int zsend_interface_add (struct zserv *, struct interface *);
extern int zsend_interface_delete (struct zserv *, struct interface *);
extern int zsend_interface_address (int, struct zserv *, struct interface *,