#include "zclient.h"
#include "linklist.h"
#include "log.h"
+#include "vrf.h"
#include "zebra/rib.h"
#include "zebra/zserv.h"
#include "zebra/debug.h"
#include "zebra/router-id.h"
+#define ZEBRA_PTM_SUPPORT
+
+
/* master zebra server structure */
extern struct zebra_t zebrad;
-static int
-zebra_check_addr (struct prefix *p)
-{
- if (p->family == AF_INET)
- {
- u_int32_t addr;
-
- addr = p->u.prefix4.s_addr;
- addr = ntohl (addr);
+/* array holding redistribute info about table redistribution */
+/* bit AFI is set if that AFI is redistributing routes from this table */
+static u_char zebra_import_table_used[ZEBRA_KERNEL_TABLE_MAX];
+static u_int32_t zebra_import_table_distance[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX];
- if (IPV4_NET127 (addr) || IN_CLASSD (addr))
- return 0;
- }
-#ifdef HAVE_IPV6
- if (p->family == AF_INET6)
+int
+is_zebra_import_table_enabled(afi_t afi, u_int32_t table_id)
+{
+ if (is_zebra_valid_kernel_table(table_id))
{
- if (IN6_IS_ADDR_LOOPBACK (&p->u.prefix6))
- return 0;
- if (IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6))
+ if (CHECK_FLAG(zebra_import_table_used[table_id], (u_char)afi))
+ return 1;
+ else
return 0;
}
-#endif /* HAVE_IPV6 */
- return 1;
+
+ return 0;
}
-static int
+int
is_default (struct prefix *p)
{
if (p->family == AF_INET)
}
static void
-zebra_redistribute_default (struct zserv *client)
+zebra_redistribute_default (struct zserv *client, vrf_id_t vrf_id)
{
struct prefix_ipv4 p;
struct route_table *table;
p.family = AF_INET;
/* Lookup table. */
- table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (table)
{
rn = route_node_lookup (table, (struct prefix *)&p);
if (rn)
{
- for (newrib = rn->info; newrib; newrib = newrib->next)
+ RNODE_FOREACH_RIB (rn, newrib)
if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
&& newrib->distance != DISTANCE_INFINITY)
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, &rn->p, newrib);
route_unlock_node (rn);
}
}
p6.family = AF_INET6;
/* Lookup table. */
- table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+ table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (table)
{
rn = route_node_lookup (table, (struct prefix *)&p6);
if (rn)
{
- for (newrib = rn->info; newrib; newrib = newrib->next)
+ RNODE_FOREACH_RIB (rn, newrib)
if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
&& newrib->distance != DISTANCE_INFINITY)
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, &rn->p, newrib);
route_unlock_node (rn);
}
}
/* Redistribute routes. */
static void
-zebra_redistribute (struct zserv *client, int type)
+zebra_redistribute (struct zserv *client, int type, u_short instance, vrf_id_t vrf_id)
{
struct rib *newrib;
struct route_table *table;
struct route_node *rn;
- table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
+ table = zebra_vrf_table (AFI_IP, SAFI_UNICAST, vrf_id);
if (table)
for (rn = route_top (table); rn; rn = route_next (rn))
- for (newrib = rn->info; newrib; newrib = newrib->next)
+ RNODE_FOREACH_RIB (rn, newrib)
if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
- && newrib->type == type
+ && newrib->type == type
+ && newrib->instance == instance
&& newrib->distance != DISTANCE_INFINITY
&& zebra_check_addr (&rn->p))
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, &rn->p, newrib);
+ {
+ client->redist_v4_add_cnt++;
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client, &rn->p, newrib);
+ }
#ifdef HAVE_IPV6
- table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
+ table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id);
if (table)
for (rn = route_top (table); rn; rn = route_next (rn))
- for (newrib = rn->info; newrib; newrib = newrib->next)
+ RNODE_FOREACH_RIB (rn, newrib)
if (CHECK_FLAG (newrib->flags, ZEBRA_FLAG_SELECTED)
- && newrib->type == type
+ && newrib->type == type
+ && newrib->instance == instance
&& newrib->distance != DISTANCE_INFINITY
&& zebra_check_addr (&rn->p))
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, &rn->p, newrib);
+ {
+ client->redist_v6_add_cnt++;
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client, &rn->p, newrib);
+ }
#endif /* HAVE_IPV6 */
}
+/* Either advertise a route for redistribution to registered clients or */
+/* withdraw redistribution if add cannot be done for client */
void
-redistribute_add (struct prefix *p, struct rib *rib)
+redistribute_update (struct prefix *p, struct rib *rib, struct rib *prev_rib)
{
struct listnode *node, *nnode;
struct zserv *client;
+ int send_redistribute;
+ int afi;
+ char buf[INET6_ADDRSTRLEN];
+
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
+ zlog_debug ("%u:%s/%d: Redist update rib %p (type %d), old %p (type %d)",
+ rib->vrf_id, buf, p->prefixlen, rib, rib->type,
+ prev_rib, prev_rib ? prev_rib->type : -1);
+ }
+
+ afi = family2afi(p->family);
+ if (!afi)
+ {
+ zlog_warn("%s: Unknown AFI/SAFI prefix received\n", __FUNCTION__);
+ return;
+ }
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
{
- if (is_default (p))
- {
- if (client->redist_default || client->redist[rib->type])
- {
- if (p->family == AF_INET)
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
-#ifdef HAVE_IPV6
- if (p->family == AF_INET6)
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
-#endif /* HAVE_IPV6 */
+ send_redistribute = 0;
+
+ if (is_default(p) && client->redist_default)
+ send_redistribute = 1;
+
+ if (rib->instance && redist_check_instance(&client->mi_redist[afi][rib->type],
+ rib->instance))
+ send_redistribute = 1;
+ else
+ if ((is_default (p) &&
+ vrf_bitmap_check (client->redist_default, rib->vrf_id))
+ || vrf_bitmap_check (client->redist[afi][rib->type], rib->vrf_id))
+ send_redistribute = 1;
+
+ if (send_redistribute)
+ {
+ switch (afi)
+ {
+ case AFI_IP:
+ client->redist_v4_add_cnt++;
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_ADD, client,
+ p, rib);
+ break;
+ case AFI_IP6:
+ client->redist_v6_add_cnt++;
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_ADD, client,
+ p, rib);
+ break;
+ default:
+ zlog_warn("%s: Unknown AFI/SAFI prefix received\n", __FUNCTION__);
+ break;
}
- }
- else if (client->redist[rib->type])
- {
- if (p->family == AF_INET)
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_ADD, client, p, rib);
-#ifdef HAVE_IPV6
- if (p->family == AF_INET6)
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_ADD, client, p, rib);
-#endif /* HAVE_IPV6 */
- }
+ }
+ else if (prev_rib &&
+ ((rib->instance &&
+ redist_check_instance(&client->mi_redist[afi][prev_rib->type],
+ rib->instance)) ||
+ vrf_bitmap_check (client->redist[afi][prev_rib->type], rib->vrf_id)))
+ {
+ switch (afi)
+ {
+ case AFI_IP:
+ client->redist_v4_del_cnt++;
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
+ prev_rib);
+ break;
+ case AFI_IP6:
+ client->redist_v6_del_cnt++;
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
+ prev_rib);
+ break;
+ default:
+ break;
+ }
+ }
}
}
{
struct listnode *node, *nnode;
struct zserv *client;
+ char buf[INET6_ADDRSTRLEN];
+
+ if (IS_ZEBRA_DEBUG_RIB)
+ {
+ inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN);
+ zlog_debug ("%u:%s/%d: Redist delete rib %p (type %d)",
+ rib->vrf_id, buf, p->prefixlen, rib, rib->type);
+ }
/* Add DISTANCE_INFINITY check. */
if (rib->distance == DISTANCE_INFINITY)
{
if (is_default (p))
{
- if (client->redist_default || client->redist[rib->type])
- {
- if (p->family == AF_INET)
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p,
+ if ((p->family == AF_INET) &&
+ (vrf_bitmap_check (client->redist_default, rib->vrf_id) ||
+ (rib->instance &&
+ redist_check_instance(&client->mi_redist[AFI_IP][rib->type],
+ rib->instance)) ||
+ vrf_bitmap_check (client->redist[AFI_IP][rib->type], rib->vrf_id)))
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
rib);
#ifdef HAVE_IPV6
- if (p->family == AF_INET6)
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p,
- rib);
+ if ((p->family == AF_INET6) &&
+ (vrf_bitmap_check (client->redist_default, rib->vrf_id) ||
+ (rib->instance &&
+ redist_check_instance(&client->mi_redist[AFI_IP6][rib->type],
+ rib->instance)) ||
+ vrf_bitmap_check (client->redist[AFI_IP6][rib->type], rib->vrf_id)))
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
+ rib);
#endif /* HAVE_IPV6 */
- }
}
- else if (client->redist[rib->type])
- {
- if (p->family == AF_INET)
- zsend_route_multipath (ZEBRA_IPV4_ROUTE_DELETE, client, p, rib);
+ else
+ {
+ if ((p->family == AF_INET) &&
+ ((rib->instance &&
+ redist_check_instance(&client->mi_redist[AFI_IP][rib->type],
+ rib->instance)) ||
+ vrf_bitmap_check (client->redist[AFI_IP][rib->type], rib->vrf_id)))
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV4_DEL, client, p,
+ rib);
#ifdef HAVE_IPV6
- if (p->family == AF_INET6)
- zsend_route_multipath (ZEBRA_IPV6_ROUTE_DELETE, client, p, rib);
+ if ((p->family == AF_INET6) &&
+ ((rib->instance &&
+ redist_check_instance(&client->mi_redist[AFI_IP6][rib->type],
+ rib->instance)) ||
+ vrf_bitmap_check (client->redist[AFI_IP6][rib->type], rib->vrf_id)))
+ zsend_redistribute_route (ZEBRA_REDISTRIBUTE_IPV6_DEL, client, p,
+ rib);
#endif /* HAVE_IPV6 */
}
}
}
void
-zebra_redistribute_add (int command, struct zserv *client, int length)
+zebra_redistribute_add (int command, struct zserv *client, int length,
+ vrf_id_t vrf_id)
{
+ afi_t afi;
int type;
+ u_short instance;
+ afi = stream_getc (client->ibuf);
type = stream_getc (client->ibuf);
+ instance = stream_getw (client->ibuf);
- switch (type)
+ if (type == 0 || type >= ZEBRA_ROUTE_MAX)
+ return;
+
+ if (instance && !redist_check_instance(&client->mi_redist[afi][type], instance))
{
- case ZEBRA_ROUTE_KERNEL:
- case ZEBRA_ROUTE_CONNECT:
- case ZEBRA_ROUTE_STATIC:
- case ZEBRA_ROUTE_RIP:
- case ZEBRA_ROUTE_RIPNG:
- case ZEBRA_ROUTE_OSPF:
- case ZEBRA_ROUTE_OSPF6:
- case ZEBRA_ROUTE_BGP:
- if (! client->redist[type])
- {
- client->redist[type] = 1;
- zebra_redistribute (client, type);
- }
- break;
- default:
- break;
+ redist_add_instance(&client->mi_redist[afi][type], instance);
+ zebra_redistribute (client, type, instance, vrf_id);
}
-}
+ else
+ if (! vrf_bitmap_check (client->redist[afi][type], vrf_id))
+ {
+ vrf_bitmap_set (client->redist[afi][type], vrf_id);
+ zebra_redistribute (client, type, 0, vrf_id);
+ }
+}
void
-zebra_redistribute_delete (int command, struct zserv *client, int length)
+zebra_redistribute_delete (int command, struct zserv *client, int length,
+ vrf_id_t vrf_id)
{
+ afi_t afi;
int type;
+ u_short instance;
+ afi = stream_getc (client->ibuf);
type = stream_getc (client->ibuf);
+ instance = stream_getw (client->ibuf);
- switch (type)
+ if (type == 0 || type >= ZEBRA_ROUTE_MAX)
+ return;
+
+ if (instance && redist_check_instance(&client->mi_redist[afi][type], instance))
{
- case ZEBRA_ROUTE_KERNEL:
- case ZEBRA_ROUTE_CONNECT:
- case ZEBRA_ROUTE_STATIC:
- case ZEBRA_ROUTE_RIP:
- case ZEBRA_ROUTE_RIPNG:
- case ZEBRA_ROUTE_OSPF:
- case ZEBRA_ROUTE_OSPF6:
- case ZEBRA_ROUTE_BGP:
- client->redist[type] = 0;
- break;
- default:
- break;
+ redist_del_instance(&client->mi_redist[afi][type], instance);
+ //Pending: why no reaction here?
}
-}
+ vrf_bitmap_unset (client->redist[afi][type], vrf_id);
+}
void
-zebra_redistribute_default_add (int command, struct zserv *client, int length)
+zebra_redistribute_default_add (int command, struct zserv *client, int length,
+ vrf_id_t vrf_id)
{
- client->redist_default = 1;
- zebra_redistribute_default (client);
+ vrf_bitmap_set (client->redist_default, vrf_id);
+ zebra_redistribute_default (client, vrf_id);
}
void
zebra_redistribute_default_delete (int command, struct zserv *client,
- int length)
+ int length, vrf_id_t vrf_id)
{
- client->redist_default = 0;;
+ vrf_bitmap_unset (client->redist_default, vrf_id);
}
/* Interface up information. */
if (IS_ZEBRA_DEBUG_EVENT)
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_UP %s", ifp->name);
- for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
- zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp);
+ if (ifp->ptm_status || !ifp->ptm_enable) {
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ {
+ zsend_interface_update (ZEBRA_INTERFACE_UP, client, ifp);
+ }
+ }
}
/* Interface down information. */
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_DOWN %s", ifp->name);
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
- zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp);
+ {
+ zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp);
+ }
}
/* Interface information update. */
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo)
- zsend_interface_add (client, ifp);
+ {
+ client->ifadd_cnt++;
+ zsend_interface_add (client, ifp);
+ }
}
void
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo)
- zsend_interface_delete (client, ifp);
+ {
+ client->ifdel_cnt++;
+ zsend_interface_delete (client, ifp);
+ }
+}
+
+/* VRF information update. */
+void
+zebra_vrf_add_update (struct zebra_vrf *zvrf)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug ("MESSAGE: ZEBRA_VRF_ADD %s", zvrf->name);
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ zsend_vrf_add (client, zvrf);
+}
+
+void
+zebra_vrf_delete_update (struct zebra_vrf *zvrf)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug ("MESSAGE: ZEBRA_VRF_DELETE %s", zvrf->name);
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ zsend_vrf_delete (client, zvrf);
}
+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_info_lookup (vrf->vrf_id));
+ }
+}
+
+
/* Interface address addition. */
void
zebra_interface_address_add_update (struct interface *ifp,
struct listnode *node, *nnode;
struct zserv *client;
struct prefix *p;
- char buf[BUFSIZ];
if (IS_ZEBRA_DEBUG_EVENT)
{
+ char buf[INET6_ADDRSTRLEN];
+
p = ifc->address;
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %s/%d on %s",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN),
p->prefixlen, ifc->ifp->name);
}
+ if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
+ zlog_warn("WARNING: advertising address to clients that is not yet usable.");
+
router_id_add_address(ifc);
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc);
+ {
+ client->connected_rt_add_cnt++;
+ zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client, ifp, ifc);
+ }
}
/* Interface address deletion. */
struct listnode *node, *nnode;
struct zserv *client;
struct prefix *p;
- char buf[BUFSIZ];
if (IS_ZEBRA_DEBUG_EVENT)
{
+ char buf[INET6_ADDRSTRLEN];
+
p = ifc->address;
zlog_debug ("MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %s/%d on %s",
- inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
+ inet_ntop (p->family, &p->u.prefix, buf, INET6_ADDRSTRLEN),
p->prefixlen, ifc->ifp->name);
}
for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
if (client->ifinfo && CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc);
+ {
+ client->connected_rt_del_cnt++;
+ zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_DELETE, client, ifp, ifc);
+ }
+}
+
+/* Interface VRF change. May need to delete from clients not interested in
+ * the new VRF. Note that this function is invoked *prior* to the VRF change.
+ */
+void
+zebra_interface_vrf_update_del (struct interface *ifp, vrf_id_t new_vrf_id)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug ("MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u",
+ ifp->name, ifp->vrf_id, new_vrf_id);
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ {
+ /* Skip clients not interested in both VRFs. */
+ if (!vrf_bitmap_check (client->ifinfo, ifp->vrf_id) &&
+ !vrf_bitmap_check (client->ifinfo, new_vrf_id))
+ continue;
+
+ if (!vrf_bitmap_check (client->ifinfo, new_vrf_id))
+ {
+ /* Need to delete if the client is not interested in the new VRF. */
+ zsend_interface_update (ZEBRA_INTERFACE_DOWN, client, ifp);
+ client->ifdel_cnt++;
+ zsend_interface_delete (client, ifp);
+ }
+ else if (vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
+ {
+ /* Client is interested in both VRFs, inform about the change. */
+ zsend_interface_vrf_update (client, ifp, new_vrf_id);
+ }
+ }
+}
+
+/* Interface VRF change. This function is invoked *post* VRF change and sends an
+ * add to clients who are interested in the new VRF but not in the old VRF.
+ */
+void
+zebra_interface_vrf_update_add (struct interface *ifp, vrf_id_t old_vrf_id)
+{
+ struct listnode *node, *nnode;
+ struct zserv *client;
+
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug ("MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u",
+ ifp->name, old_vrf_id, ifp->vrf_id);
+
+ for (ALL_LIST_ELEMENTS (zebrad.client_list, node, nnode, client))
+ {
+ /* Skip clients interested in both VRFs - they would've got an Update. */
+ if (vrf_bitmap_check (client->ifinfo, ifp->vrf_id) &&
+ vrf_bitmap_check (client->ifinfo, old_vrf_id))
+ continue;
+
+ /* Skip clients not interested in the new VRF - they would've
+ * got a Delete.
+ */
+ if (!vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
+ continue;
+
+ /* Need to add if the client is interested in the new VRF. */
+ client->ifadd_cnt++;
+ zsend_interface_add (client, ifp);
+ zsend_interface_addresses (client, ifp);
+ }
+}
+
+int
+zebra_add_import_table_entry (struct route_node *rn, struct rib *rib)
+{
+ struct rib *newrib;
+ struct prefix_ipv4 p4;
+ struct nexthop *nhop;
+ struct in_addr *gate;
+
+ if (rn->p.family == AF_INET)
+ {
+ p4.family = AF_INET;
+ p4.prefixlen = rn->p.prefixlen;
+ p4.prefix = rn->p.u.prefix4;
+
+ if (rib->nexthop_num == 1)
+ {
+ nhop = rib->nexthop;
+ if (nhop->type == NEXTHOP_TYPE_IFINDEX)
+ gate = NULL;
+ else
+ gate = &nhop->gate.ipv4;
+
+ rib_add_ipv4(ZEBRA_ROUTE_TABLE, rib->table, 0, &p4,
+ gate, &nhop->src.ipv4,
+ nhop->ifindex, rib->vrf_id, zebrad.rtm_table_default,
+ rib->metric,
+ zebra_import_table_distance[AFI_IP][rib->table],
+ SAFI_UNICAST);
+ }
+ else if (rib->nexthop_num > 1)
+ {
+ newrib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
+ newrib->type = ZEBRA_ROUTE_TABLE;
+ newrib->distance = zebra_import_table_distance[AFI_IP][rib->table];
+ newrib->flags = rib->flags;
+ newrib->metric = rib->metric;
+ newrib->table = zebrad.rtm_table_default;
+ newrib->nexthop_num = 0;
+ newrib->uptime = time(NULL);
+ newrib->instance = rib->table;
+
+ /* Assuming these routes are never recursive */
+ for (nhop = rib->nexthop; nhop; nhop = nhop->next)
+ rib_copy_nexthops(newrib, nhop);
+
+ rib_add_ipv4_multipath(&p4, newrib, SAFI_UNICAST);
+ }
+ }
+ /* DD: Add IPv6 code */
+ return 0;
+}
+
+int
+zebra_del_import_table_entry (struct route_node *rn, struct rib *rib)
+{
+ struct prefix_ipv4 p4;
+
+ if (rn->p.family == AF_INET)
+ {
+ p4.family = AF_INET;
+ p4.prefixlen = rn->p.prefixlen;
+ p4.prefix = rn->p.u.prefix4;
+
+ rib_delete_ipv4(ZEBRA_ROUTE_TABLE, rib->table, rib->flags, &p4, NULL,
+ 0, rib->vrf_id, zebrad.rtm_table_default, SAFI_UNICAST);
+ }
+ /* DD: Add IPv6 code */
+
+ return 0;
+}
+
+/* Assuming no one calls this with the main routing table */
+int
+zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t distance, int add)
+{
+ struct route_table *table;
+ struct rib *rib;
+ struct route_node *rn;
+
+ if (!is_zebra_valid_kernel_table(table_id) ||
+ ((table_id == RT_TABLE_MAIN) || (table_id == zebrad.rtm_table_default)))
+ return (-1);
+
+ if (afi >= AFI_MAX)
+ return (-1);
+
+ table = zebra_vrf_other_route_table(afi, table_id, VRF_DEFAULT);
+ if (table == NULL)
+ {
+ return 0;
+ }
+ else if (IS_ZEBRA_DEBUG_RIB)
+ {
+ zlog_debug ("%s routes from table %d",
+ add ? "Importing" : "Unimporting", table_id);
+ }
+
+ if (add)
+ {
+ SET_FLAG(zebra_import_table_used[table_id], afi);
+ zebra_import_table_distance[afi][table_id] = distance;
+ }
+ else
+ {
+ UNSET_FLAG(zebra_import_table_used[table_id], (u_char)afi);
+ zebra_import_table_distance[afi][table_id] = ZEBRA_TABLE_DISTANCE_DEFAULT;
+ }
+
+ for (rn = route_top(table); rn; rn = route_next(rn))
+ {
+ /* For each entry in the non-default routing table,
+ * add the entry in the main table
+ */
+ if (!rn->info)
+ continue;
+
+ RNODE_FOREACH_RIB (rn, rib)
+ {
+ if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED))
+ continue;
+ break;
+ }
+
+ if (!rib)
+ continue;
+
+ if (((afi == AFI_IP) && (rn->p.family == AF_INET)) ||
+ ((afi == AFI_IP6) && (rn->p.family == AF_INET6)))
+ {
+ if (add)
+ zebra_add_import_table_entry (rn, rib);
+ else
+ zebra_del_import_table_entry (rn, rib);
+ }
+ }
+ return 0;
+}
+
+int
+zebra_import_table_config (struct vty *vty)
+{
+ int i;
+ afi_t afi;
+ int write = 0;
+ char afi_str[AFI_MAX][6] = {"", "ip", "ipv6"};
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ {
+ for (i = 1; i < ZEBRA_KERNEL_TABLE_MAX; i++)
+ {
+ if (is_zebra_import_table_enabled(afi, i))
+ {
+ if (zebra_import_table_distance[afi][i] != ZEBRA_TABLE_DISTANCE_DEFAULT)
+ {
+ vty_out(vty, "%s import-table %d distance %d%s", afi_str[afi],
+ i, zebra_import_table_distance[afi][i], VTY_NEWLINE);
+ }
+ else
+ {
+ vty_out(vty, "%s import-table %d%s", afi_str[afi], i,
+ VTY_NEWLINE);
+ }
+ write = 1;
+ }
+ }
+ }
+
+ return write;
}