From 873a5f68e60c807aaf559cd54108f1cc9b196a41 Mon Sep 17 00:00:00 2001
From: Erin Shepherd <erin.shepherd@e43.eu>
Date: Sun, 16 Jul 2023 16:59:20 +0200
Subject: [PATCH] Treat the VRF interface as inside the VRF

On Linux, one can define IPs on the VRF interface, which are treated
similar to defining IP addresses on lo in the "main" VRF. Treating
the VRF interface as inside the VRF allows e.g. OSPF to pick up IP
addresses defined on the VRF interface
---
 nest/iface.c        | 4 ++--
 nest/iface.h        | 6 +++++-
 nest/neighbor.c     | 4 ++--
 proto/babel/babel.c | 2 +-
 proto/bgp/packets.c | 2 +-
 proto/ospf/iface.c  | 4 ++--
 proto/radv/radv.c   | 2 +-
 proto/rip/rip.c     | 2 +-
 8 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/nest/iface.c b/nest/iface.c
index 682340c5..ed3e3fde 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -147,7 +147,7 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
 {
   if (p->ifa_notify &&
       (p->proto_state != PS_DOWN) &&
-      (!p->vrf_set || p->vrf == a->iface->master))
+      (!p->vrf_set || if_in_vrf(a->iface, p->vrf)))
     {
       if (p->debug & D_IFACES)
 	log(L_TRACE "%s < address %N on interface %s %s",
@@ -185,7 +185,7 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i)
 {
   if (p->if_notify &&
       (p->proto_state != PS_DOWN) &&
-      (!p->vrf_set || p->vrf == i->master))
+      (!p->vrf_set || if_in_vrf(i, p->vrf)))
     {
       if (p->debug & D_IFACES)
 	log(L_TRACE "%s < interface %s %s", p->name, i->name,
diff --git a/nest/iface.h b/nest/iface.h
index 1189cdd4..20f38c30 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -118,7 +118,11 @@ struct iface *if_find_by_index(unsigned);
 struct iface *if_find_by_name(const char *);
 struct iface *if_get_by_name(const char *);
 void if_recalc_all_preferred_addresses(void);
-
+static inline int
+if_in_vrf(struct iface *i, struct iface *vrf)
+{
+  return i == vrf || i->master == vrf;
+}
 
 /* The Neighbor Cache */
 
diff --git a/nest/neighbor.c b/nest/neighbor.c
index 7cf9c85d..f9ca027e 100644
--- a/nest/neighbor.c
+++ b/nest/neighbor.c
@@ -153,7 +153,7 @@ if_connected_any(ip_addr a, struct iface *vrf, uint vrf_set, struct iface **ifac
 
   /* Prefer SCOPE_HOST or longer prefix */
   WALK_LIST(i, iface_list)
-    if ((!vrf_set || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0))
+    if ((!vrf_set || if_in_vrf(i, vrf)) && ((s = if_connected(a, i, &b, flags)) >= 0))
       if (scope_better(s, scope) || (scope_remote(s, scope) && ifa_better(b, *addr)))
       {
 	*iface = i;
@@ -369,7 +369,7 @@ neigh_update(neighbor *n, struct iface *iface)
     return;
 
   /* VRF-bound neighbors ignore changes in other VRFs */
-  if (p->vrf_set && (p->vrf != iface->master))
+  if (p->vrf_set && !if_in_vrf(iface, p->vrf))
     return;
 
   scope = if_connected(n->addr, iface, &ifa, n->flags);
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 7f0cca73..96990423 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -2062,7 +2062,7 @@ babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf)
 
   WALK_LIST(iface, iface_list)
   {
-    if (p->p.vrf_set && p->p.vrf != iface->master)
+    if (p->p.vrf_set && !if_in_vrf(iface, p->p.vrf))
       continue;
 
     if (!(iface->flags & IF_UP))
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 6e6e41ca..c74b17d6 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1170,7 +1170,7 @@ bgp_use_gateway(struct bgp_export_state *s)
     return 0;
 
   /* Do not use gateway from different VRF */
-  if (p->p.vrf_set && ra->nh.iface && (p->p.vrf != ra->nh.iface->master))
+  if (p->p.vrf_set && ra->nh.iface && !if_in_vrf(ra->nh.iface, p->p.vrf))
     return 0;
 
   /* Use it when exported to internal peers */
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 87e3d95e..cb0b3a3a 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -1227,7 +1227,7 @@ ospf_reconfigure_ifaces2(struct ospf_proto *p)
 
   WALK_LIST(iface, iface_list)
   {
-    if (p->p.vrf_set && p->p.vrf != iface->master)
+    if (p->p.vrf_set && !if_in_vrf(iface, p->p.vrf))
       continue;
 
     if (! (iface->flags & IF_UP))
@@ -1276,7 +1276,7 @@ ospf_reconfigure_ifaces3(struct ospf_proto *p)
 
   WALK_LIST(iface, iface_list)
   {
-    if (p->p.vrf_set && p->p.vrf != iface->master)
+    if (p->p.vrf_set && !if_in_vrf(iface, p->p.vrf))
       continue;
 
     if (! (iface->flags & IF_UP))
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 119a8dc4..e3c319fb 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -663,7 +663,7 @@ radv_reconfigure(struct proto *P, struct proto_config *CF)
   struct iface *iface;
   WALK_LIST(iface, iface_list)
   {
-    if (p->p.vrf_set && p->p.vrf != iface->master)
+    if (p->p.vrf_set && !if_in_vrf(iface, p->p.vrf))
       continue;
 
     if (!(iface->flags & IF_UP))
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 8c2d5aeb..73582c95 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -797,7 +797,7 @@ rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
 
   WALK_LIST(iface, iface_list)
   {
-    if (p->p.vrf_set && p->p.vrf != iface->master)
+    if (p->p.vrf_set && !if_in_vrf(iface, p->p.vrf))
       continue;
 
     if (!(iface->flags & IF_UP))
-- 
2.39.2

