summaryrefslogtreecommitdiff
path: root/zebra/interface.c
diff options
context:
space:
mode:
authorvivek <vivek@cumulusnetworks.com>2016-02-25 19:30:53 +0000
committervivek <vivek@cumulusnetworks.com>2016-02-25 19:30:53 +0000
commitc8e264b60e405e60b666cca62d5c96c20a9cf3bd (patch)
tree85f3ad0f6bf667d1ddb04a5330fe51bb1bc3d1e4 /zebra/interface.c
parentb47b0a8480cbbfa30de4794f149f39ca8ad43921 (diff)
Quagga: Implement VRF change semantics for an interface
Implement VRF change semantics for an interface to be invoked when an interface is moved from one VRF (e.g., the Default) to another. This includes the message definition as well as updating, deleting or adding the interface from clients, depending on their interest in the VRFs (old and new). Also handle replay of the addresses on the interface upon VRF change, if required. Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com> Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com> Reviewed-by: Don Slice <dslice@cumulusnetworks.com> Ticket: CM-9527 Reviewed By: CCR-4174 Testing Done: Manual tests of various scenarios
Diffstat (limited to 'zebra/interface.c')
-rw-r--r--zebra/interface.c185
1 files changed, 127 insertions, 58 deletions
diff --git a/zebra/interface.c b/zebra/interface.c
index 7b19379910..5a47f60fa0 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -54,6 +54,8 @@
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. */
@@ -482,32 +484,64 @@ if_add_update (struct interface *ifp)
}
}
-/* 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;
@@ -571,7 +605,6 @@ if_delete_update (struct interface *ifp)
rn->info = NULL;
route_unlock_node (rn);
}
-#ifdef HAVE_IPV6
else if (p->family == AF_INET6)
{
connected_down_ipv6 (ifp, ifc);
@@ -589,13 +622,36 @@ if_delete_update (struct interface *ifp)
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);
@@ -608,6 +664,55 @@ if_delete_update (struct interface *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)
@@ -728,11 +833,6 @@ if_down_del_nbr_connected (struct interface *ifp)
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__,
@@ -744,20 +844,7 @@ if_up (struct interface *ifp)
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",
@@ -770,29 +857,11 @@ if_up (struct interface *ifp)
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",