DESC_ENTRY (ZEBRA_REDISTRIBUTE_IPV4_ADD),
DESC_ENTRY (ZEBRA_REDISTRIBUTE_IPV4_DEL),
DESC_ENTRY (ZEBRA_REDISTRIBUTE_IPV6_ADD),
- DESC_ENTRY (ZEBRA_REDISTRIBUTE_IPV6_DEL)
+ DESC_ENTRY (ZEBRA_REDISTRIBUTE_IPV6_DEL),
+ DESC_ENTRY (ZEBRA_INTERFACE_VRF_UPDATE)
};
#undef DESC_ENTRY
return ifc;
}
+struct interface *
+zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id,
+ vrf_id_t *new_vrf_id)
+{
+ unsigned int ifindex;
+ struct interface *ifp;
+ vrf_id_t new_id = VRF_DEFAULT;
+
+ /* Get interface index. */
+ ifindex = stream_getl (s);
+
+ /* Lookup interface. */
+ ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
+ if (ifp == NULL)
+ {
+ zlog_warn ("INTERFACE_VRF_UPDATE: Cannot find IF %u in VRF %d",
+ ifindex, vrf_id);
+ return NULL;
+ }
+
+ /* Fetch new VRF Id. */
+ new_id = stream_getw (s);
+
+ *new_vrf_id = new_id;
+ return ifp;
+}
+
/* Zebra client message read function. */
static int
zclient_read (struct thread *thread)
if (zclient->interface_down)
(*zclient->interface_down) (command, zclient, length, vrf_id);
break;
+ case ZEBRA_INTERFACE_VRF_UPDATE:
+ if (zclient->interface_vrf_update)
+ (*zclient->interface_vrf_update) (command, zclient, length, vrf_id);
+ break;
case ZEBRA_IPV4_ROUTE_ADD:
if (zclient->ipv4_route_add)
(*zclient->ipv4_route_add) (command, zclient, length, vrf_id);
int (*interface_bfd_dest_update) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_nbr_address_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*interface_nbr_address_delete) (int, struct zclient *, uint16_t, vrf_id_t);
+ int (*interface_vrf_update) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv4_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv4_route_delete) (int, struct zclient *, uint16_t, vrf_id_t);
int (*ipv6_route_add) (int, struct zclient *, uint16_t, vrf_id_t);
extern struct interface *zebra_interface_state_read (struct stream *s, vrf_id_t);
extern struct connected *zebra_interface_address_read (int, struct stream *, vrf_id_t);
extern struct nbr_connected *zebra_interface_nbr_address_read (int, struct stream *, vrf_id_t);
+extern struct interface * zebra_interface_vrf_update_read (struct stream *s, vrf_id_t vrf_id,
+ vrf_id_t *new_vrf_id);
extern void zebra_interface_if_set_value (struct stream *, struct interface *);
extern void zebra_router_id_update_read (struct stream *s, struct prefix *rid);
extern int zapi_ipv4_route (u_char, struct zclient *, struct prefix_ipv4 *,
#define ZEBRA_VRF_UNREGISTER 42
#define ZEBRA_VRF_ADD 43
#define ZEBRA_VRF_DELETE 44
-#define ZEBRA_MESSAGE_MAX 45
+#define ZEBRA_INTERFACE_VRF_UPDATE 45
+#define ZEBRA_MESSAGE_MAX 46
/* Marker value used in new Zserv, in the byte location corresponding
* the command value in the old zserv header. To allow old and new
const char *rtadv_pref_strs[] = { "medium", "high", "INVALID", "low", 0 };
#endif /* HAVE_RTADV */
+static void if_down_del_nbr_connected (struct interface *ifp);
+
struct zebra_ns *dzns;
/* Called when new interface is added. */
}
}
-/* Handle an interface delete event */
-void
-if_delete_update (struct interface *ifp)
+/* Install connected routes corresponding to an interface. */
+static void
+if_install_connected (struct interface *ifp)
{
+ struct listnode *node;
+ struct listnode *next;
struct connected *ifc;
struct prefix *p;
- struct route_node *rn;
- struct zebra_if *zebra_if;
- zebra_if = ifp->info;
+ if (ifp->connected)
+ {
+ for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
+ {
+ p = ifc->address;
- if (if_is_up(ifp))
+ if (p->family == AF_INET)
+ connected_up_ipv4 (ifp, ifc);
+ else if (p->family == AF_INET6)
+ connected_up_ipv6 (ifp, ifc);
+ }
+ }
+}
+
+/* Uninstall connected routes corresponding to an interface. */
+static void
+if_uninstall_connected (struct interface *ifp)
+{
+ struct listnode *node;
+ struct listnode *next;
+ struct connected *ifc;
+ struct prefix *p;
+
+ if (ifp->connected)
{
- zlog_err ("interface %s vrf %u index %d is still up while being deleted.",
- ifp->name, ifp->vrf_id, ifp->ifindex);
- return;
+ for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
+ {
+ p = ifc->address;
+
+ if (p->family == AF_INET)
+ connected_down_ipv4 (ifp, ifc);
+ else if (p->family == AF_INET6)
+ connected_down_ipv6 (ifp, ifc);
+ }
}
+}
- /* Mark interface as inactive */
- UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
-
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug ("interface %s vrf %u index %d is now inactive.",
- ifp->name, ifp->vrf_id, ifp->ifindex);
+/* Uninstall and delete connected routes corresponding to an interface. */
+/* TODO - Check why IPv4 handling here is different from install or if_down */
+static void
+if_delete_connected (struct interface *ifp)
+{
+ struct connected *ifc;
+ struct prefix *p;
+ struct route_node *rn;
+ struct zebra_if *zebra_if;
+
+ zebra_if = ifp->info;
- /* Delete connected routes from the kernel. */
if (ifp->connected)
{
struct listnode *node;
rn->info = NULL;
route_unlock_node (rn);
}
-#ifdef HAVE_IPV6
else if (p->family == AF_INET6)
{
connected_down_ipv6 (ifp, ifc);
connected_free (ifc);
}
}
-#endif /* HAVE_IPV6 */
else
{
last = node;
}
}
}
+}
+
+/* Handle an interface delete event */
+void
+if_delete_update (struct interface *ifp)
+{
+ if (if_is_up(ifp))
+ {
+ zlog_err ("interface %s vrf %u index %d is still up while being deleted.",
+ ifp->name, ifp->vrf_id, ifp->ifindex);
+ return;
+ }
+
+ /* Mark interface as inactive */
+ UNSET_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE);
+
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("interface %s vrf %u index %d is now inactive.",
+ ifp->name, ifp->vrf_id, ifp->ifindex);
+
+ /* Delete connected routes from the kernel. */
+ if_delete_connected (ifp);
+
+ /* Send out notification on interface delete. */
zebra_interface_delete_update (ifp);
if_unlink_per_ns(ifp);
ifp->ifindex = IFINDEX_INTERNAL;
}
+/* VRF change for an interface */
+void
+if_handle_vrf_change (struct interface *ifp, vrf_id_t vrf_id)
+{
+ vrf_id_t old_vrf_id;
+
+ old_vrf_id = ifp->vrf_id;
+
+ /* Uninstall connected routes. */
+ if_uninstall_connected (ifp);
+
+ /* Delete any IPv4 neighbors created to implement RFC 5549 */
+ if_nbr_ipv6ll_to_ipv4ll_neigh_del_all (ifp);
+
+ /* Delete all neighbor addresses learnt through IPv6 RA */
+ if_down_del_nbr_connected (ifp);
+
+ /* Suppress RAs on this interface, if enabled. */
+ ipv6_nd_suppress_ra_set (ifp, RA_SUPPRESS);
+
+ /* Send out notification on interface VRF change. */
+ /* This is to issue an UPDATE or a DELETE, as appropriate. */
+ zebra_interface_vrf_update_del (ifp, vrf_id);
+
+ /* update VRF */
+ if_update_vrf (ifp, ifp->name, strlen (ifp->name), vrf_id);
+
+ /* Send out notification on interface VRF change. */
+ /* This is to issue an ADD, if needed. */
+ zebra_interface_vrf_update_add (ifp, old_vrf_id);
+
+ /* Install connected routes (in new VRF). */
+ if_install_connected (ifp);
+
+ /* Enable RAs on this interface, if IPv6 addresses are present. */
+ if (ipv6_address_configured(ifp))
+ ipv6_nd_suppress_ra_set (ifp, RA_ENABLE);
+
+ /* Due to connected route change, schedule RIB processing for both old
+ * and new VRF.
+ */
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ zlog_debug ("%u: IF %s VRF change, scheduling RIB processing",
+ ifp->vrf_id, ifp->name);
+ rib_update (old_vrf_id, RIB_UPDATE_IF_CHANGE);
+ rib_update (ifp->vrf_id, RIB_UPDATE_IF_CHANGE);
+}
+
+
/* Handle VRF addition */
void
vrf_add_update (struct vrf *vrfp)
void
if_up (struct interface *ifp)
{
- struct listnode *node;
- struct listnode *next;
- struct connected *ifc;
- struct prefix *p;
-
/* Notify the protocol daemons. */
if (ifp->ptm_enable && (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)) {
zlog_warn("%s: interface %s hasn't passed ptm check\n", __func__,
if_nbr_ipv6ll_to_ipv4ll_neigh_add_all (ifp);
/* Install connected routes to the kernel. */
- if (ifp->connected)
- {
- for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
- {
- p = ifc->address;
-
- if (p->family == AF_INET)
- connected_up_ipv4 (ifp, ifc);
-#ifdef HAVE_IPV6
- else if (p->family == AF_INET6)
- connected_up_ipv6 (ifp, ifc);
-#endif /* HAVE_IPV6 */
- }
- }
+ if_install_connected (ifp);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%u: IF %s up, scheduling RIB processing",
void
if_down (struct interface *ifp)
{
- struct listnode *node;
- struct listnode *next;
- struct connected *ifc;
- struct prefix *p;
-
/* Notify to the protocol daemons. */
zebra_interface_down_update (ifp);
- /* Delete connected routes from the kernel. */
- if (ifp->connected)
- {
- for (ALL_LIST_ELEMENTS (ifp->connected, node, next, ifc))
- {
- p = ifc->address;
-
- if (p->family == AF_INET)
- connected_down_ipv4 (ifp, ifc);
-#ifdef HAVE_IPV6
- else if (p->family == AF_INET6)
- connected_down_ipv6 (ifp, ifc);
-#endif /* HAVE_IPV6 */
- }
- }
+ /* Uninstall connected routes from the kernel. */
+ if_uninstall_connected (ifp);
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug ("%u: IF %s down, scheduling RIB processing",
extern int if_subnet_add (struct interface *, struct connected *);
extern int if_subnet_delete (struct interface *, struct connected *);
extern int ipv6_address_configured (struct interface *ifp);
+extern void if_handle_vrf_change (struct interface *ifp, vrf_id_t vrf_id);
extern void vrf_delete_update (struct vrf *vrfp);
extern void vrf_add_update (struct vrf *vrfp);
}
}
+/* 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 connected *);
extern void zebra_interface_address_delete_update (struct interface *,
struct connected *c);
+extern void zebra_interface_vrf_update_del (struct interface *, vrf_id_t new_vrf_id);
+extern void zebra_interface_vrf_update_add (struct interface *, vrf_id_t old_vrf_id);
extern int zebra_import_table (afi_t afi, u_int32_t table_id,
u_int32_t metric, int add);
{ return; }
#endif
+void zebra_interface_vrf_update_del (struct interface *a, vrf_id_t new_vrf_id)
+{ return; }
+
+void zebra_interface_vrf_update_add (struct interface *a, vrf_id_t old_vrf_id)
+{ return; }
+
int zebra_import_table (afi_t afi, u_int32_t table_id, u_int32_t metric,
int add)
{ return 0; }
struct prefix *p;
/* Check this client need interface information. */
- if (! client->ifinfo)
+ if (! vrf_bitmap_check (client->ifinfo, ifp->vrf_id))
return 0;
s = client->obuf;
zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_DELETE, client, ifp, ifc);
}
+/* Send addresses on interface to client */
+int
+zsend_interface_addresses (struct zserv *client, struct interface *ifp)
+{
+ struct listnode *cnode, *cnnode;
+ struct connected *c;
+ struct nbr_connected *nc;
+
+ /* Send interface addresses. */
+ for (ALL_LIST_ELEMENTS (ifp->connected, cnode, cnnode, c))
+ {
+ if (!CHECK_FLAG (c->conf, ZEBRA_IFC_REAL))
+ continue;
+
+ if (zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client,
+ ifp, c) < 0)
+ return -1;
+ }
+
+ /* Send interface neighbors. */
+ for (ALL_LIST_ELEMENTS (ifp->nbr_connected, cnode, cnnode, nc))
+ {
+ if (zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_ADD,
+ client, ifp, nc) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Notify client about interface moving from one VRF to another.
+ * Whether client is interested in old and new VRF is checked by caller.
+ */
+int
+zsend_interface_vrf_update (struct zserv *client, struct interface *ifp,
+ vrf_id_t vrf_id)
+{
+ struct stream *s;
+
+ s = client->obuf;
+ stream_reset (s);
+
+ zserv_create_header (s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id);
+
+ /* Fill in the ifIndex of the interface and its new VRF (id) */
+ stream_putl (s, ifp->ifindex);
+ stream_putw (s, vrf_id);
+
+ /* Write packet size. */
+ stream_putw_at (s, 0, stream_get_endp (s));
+
+ client->if_vrfchg_cnt++;
+ return zebra_server_send_message(client);
+}
+
/* Add new nbr connected IPv6 address if none exists already, or replace the
existing one if an ifc entry is found on the interface. */
void
zread_interface_add (struct zserv *client, u_short length, vrf_id_t vrf_id)
{
struct listnode *ifnode, *ifnnode;
- struct listnode *cnode, *cnnode;
struct interface *ifp;
- struct connected *c;
- struct nbr_connected *nc;
/* Interface information is needed. */
vrf_bitmap_set (client->ifinfo, vrf_id);
if (zsend_interface_add (client, ifp) < 0)
return -1;
- for (ALL_LIST_ELEMENTS (ifp->connected, cnode, cnnode, c))
- {
- if (CHECK_FLAG (c->conf, ZEBRA_IFC_REAL) &&
- (zsend_interface_address (ZEBRA_INTERFACE_ADDRESS_ADD, client,
- ifp, c) < 0))
- return -1;
- }
- for (ALL_LIST_ELEMENTS (ifp->nbr_connected, cnode, cnnode, nc))
- {
- if (zsend_interface_nbr_address (ZEBRA_INTERFACE_NBR_ADDRESS_ADD, client,
- ifp, nc) < 0)
- return -1;
- }
-
+ if (zsend_interface_addresses (client, ifp) < 0)
+ return -1;
}
return 0;
}
u_int32_t bfd_peer_replay_cnt;
u_int32_t vrfadd_cnt;
u_int32_t vrfdel_cnt;
+ u_int32_t if_vrfchg_cnt;
time_t connect_time;
time_t last_read_time;
extern int zsend_interface_add (struct zserv *, struct interface *);
extern int zsend_interface_delete (struct zserv *, struct interface *);
+extern int zsend_interface_addresses (struct zserv *, struct interface *);
extern int zsend_interface_address (int, struct zserv *, struct interface *,
struct connected *);
extern void nbr_connected_replacement_add_ipv6 (struct interface *,
struct rib *);
extern int zsend_router_id_update (struct zserv *, struct prefix *,
vrf_id_t);
+extern int zsend_interface_vrf_update (struct zserv *, struct interface *,
+ vrf_id_t);
extern pid_t pid;