summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/if.c8
-rw-r--r--lib/if.h1
-rw-r--r--pimd/pim_iface.c8
-rw-r--r--pimd/pim_iface.h2
-rw-r--r--pimd/pim_pim.c4
-rw-r--r--zebra/zebra_rib.c26
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;