+ {
+ 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;