From fec4ca191ef4e7d9576feba756f728b21819ec45 Mon Sep 17 00:00:00 2001 From: Don Slice Date: Tue, 21 Aug 2018 18:03:00 +0000 Subject: [PATCH] zebra: if multiple connecteds, select loopback or vrf if present Signed-off-by: Don Slice --- lib/if.c | 8 ++++++++ lib/if.h | 1 + pimd/pim_iface.c | 8 -------- pimd/pim_iface.h | 2 -- pimd/pim_pim.c | 4 ++-- zebra/zebra_rib.c | 26 +++++++++++++++++++++++--- 6 files changed, 34 insertions(+), 15 deletions(-) diff --git a/lib/if.c b/lib/if.c index 943436f356..2bf0c6e6b5 100644 --- a/lib/if.c +++ b/lib/if.c @@ -472,6 +472,14 @@ int if_is_vrf(struct interface *ifp) return CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); } +bool if_is_loopback_or_vrf(struct interface *ifp) +{ + if (if_is_loopback(ifp) || if_is_vrf(ifp)) + return true; + + return false; +} + /* Does this interface support broadcast ? */ int if_is_broadcast(struct interface *ifp) { diff --git a/lib/if.h b/lib/if.h index 3a9c4af848..a861cf2d85 100644 --- a/lib/if.h +++ b/lib/if.h @@ -497,6 +497,7 @@ extern int if_is_operative(struct interface *); extern int if_is_no_ptm_operative(struct interface *); extern int if_is_loopback(struct interface *); extern int if_is_vrf(struct interface *ifp); +extern bool if_is_loopback_or_vrf(struct interface *ifp); extern int if_is_broadcast(struct interface *); extern int if_is_pointopoint(struct interface *); extern int if_is_multicast(struct interface *); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index e79e91d7df..72ccf3ab1e 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1495,14 +1495,6 @@ int pim_if_connected_to_source(struct interface *ifp, struct in_addr src) return 0; } -bool pim_if_is_loopback(struct interface *ifp) -{ - if (if_is_loopback(ifp) || if_is_vrf(ifp)) - return true; - - return false; -} - bool pim_if_is_vrf_device(struct interface *ifp) { if (if_is_vrf(ifp)) diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index cf025cbd4a..02926a6973 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -207,8 +207,6 @@ void pim_if_create_pimreg(struct pim_instance *pim); int pim_if_connected_to_source(struct interface *ifp, struct in_addr src); int pim_update_source_set(struct interface *ifp, struct in_addr source); -bool pim_if_is_loopback(struct interface *ifp); - bool pim_if_is_vrf_device(struct interface *ifp); int pim_if_ifchannel_count(struct pim_interface *pim_ifp); diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index b103da2e1b..7113d5405e 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -655,7 +655,7 @@ static int pim_hello_send(struct interface *ifp, uint16_t holdtime) { struct pim_interface *pim_ifp = ifp->info; - if (pim_if_is_loopback(ifp)) + if (if_is_loopback_or_vrf(ifp)) return 0; if (hello_send(ifp, holdtime)) { @@ -757,7 +757,7 @@ void pim_hello_restart_triggered(struct interface *ifp) /* * No need to ever start loopback or vrf device hello's */ - if (pim_if_is_loopback(ifp)) + if (if_is_loopback_or_vrf(ifp)) return; /* diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 99b83d5cd9..ab07549ec2 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1501,17 +1501,37 @@ static struct route_entry *rib_choose_best(struct route_entry *current, /* filter route selection in following order: * - connected beats other types + * - if both connected, loopback or vrf wins * - lower distance beats higher * - lower metric beats higher for equal distance * - last, hence oldest, route wins tie break. */ - /* Connected routes. Pick the last connected + /* Connected routes. Check to see if either are a vrf + * or loopback interface. If not, pick the last connected * route of the set of lowest metric connected routes. */ if (alternate->type == ZEBRA_ROUTE_CONNECT) { - if (current->type != ZEBRA_ROUTE_CONNECT - || alternate->metric <= current->metric) + if (current->type != ZEBRA_ROUTE_CONNECT) + return alternate; + + /* both are connected. are either loop or vrf? */ + struct nexthop *nexthop = NULL; + + for (ALL_NEXTHOPS(alternate->ng, nexthop)) { + if (if_is_loopback_or_vrf(if_lookup_by_index( + nexthop->ifindex, alternate->vrf_id))) + return alternate; + } + + for (ALL_NEXTHOPS(current->ng, nexthop)) { + if (if_is_loopback_or_vrf(if_lookup_by_index( + nexthop->ifindex, current->vrf_id))) + return current; + } + + /* Neither are loop or vrf so pick best metric */ + if (alternate->metric <= current->metric) return alternate; return current;