]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nest: Treat VRF interfaces as inside respective VRFs
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 23 Aug 2023 13:55:31 +0000 (15:55 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 23 Aug 2023 14:08:40 +0000 (16:08 +0200)
Despite not having defined 'master interface', VRF interfaces should be
treated as being inside respective VRFs. They behave as a loopback for
respective VRFs. Treating the VRF interface as inside the VRF allows
e.g. OSPF to pick up IP addresses defined on the VRF interface.

For this, we also need to tell apart VRF interfaces and regular interfaces.
Extend Netlink code to parse interface type and mark VRF interfaces with
IF_VRF flag.

Based on the patch from Erin Shepherd, thanks!

nest/iface.c
nest/iface.h
nest/neighbor.c
proto/babel/babel.c
proto/bgp/packets.c
proto/ospf/iface.c
proto/radv/radv.c
proto/rip/rip.c
sysdep/linux/netlink.c

index 682340c56cff227e880187f4d7ac6eabe4795932..6c84cbcf0977b509f5e2e68db9e9a6f7244811b3 100644 (file)
@@ -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,
index 1189cdd4cad49955339f3a665842e6f04f84a65d..f8e9285053c11afe013666747920edbcc65168ea 100644 (file)
@@ -53,6 +53,7 @@ struct iface {
 #define IF_IGNORE 0x40                 /* Not to be used by routing protocols (loopbacks etc.) */
 #define IF_ADMIN_UP 0x80               /* Administrative up (e.g. IFF_UP in Linux) */
 #define IF_LINK_UP 0x100               /* Link available (e.g. IFF_LOWER_UP in Linux) */
+#define IF_VRF 0x200                   /* Iface is VRF master */
 
 #define IA_PRIMARY 0x10000             /* This address is primary */
 #define IA_SECONDARY 0x20000           /* This address has been reported as secondary by the kernel */
@@ -119,6 +120,9 @@ 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->flags & IF_VRF) ? (i == vrf) : (i->master == vrf); }
+
 
 /* The Neighbor Cache */
 
index 7cf9c85d75e117a4cf65c9c27033c82e5b59fe5f..2c2d3adfdee4e5f14895462e5967da450feeb296 100644 (file)
@@ -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);
index 7f0cca73c929796c1c6a8881b8152ba4e66e180d..4187d258aa3b596f710217d2c8500909c8d1b2dc 100644 (file)
@@ -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))
index ee98115de26395d51a22eaeec50a6a6c5e979c09..dc52e8051de656a712a757b94e331a08d712efa6 100644 (file)
@@ -1179,7 +1179,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 */
index 87e3d95eb6aecbd8ab06b66216dc06c9b39c5cb7..dd922b00af3e316d9348e2efa299bb8334c6f205 100644 (file)
@@ -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))
index 119a8dc41c980d4cfe9209c1b2757a84cd3507ae..ba31e1a845f2aed5af6bc73b1d4768f44a2fddde 100644 (file)
@@ -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))
index 8c2d5aebdee75829b13e0d8895b027f89552d515..1c3509e408611ad806076c3438aa0b4149170d94 100644 (file)
@@ -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))
index e3298a0f5549c5f677cc5467ddd0ebcba2d45020..1af78766b9d4c088c74d9ea25fc3f114b50bcbac 100644 (file)
@@ -333,13 +333,21 @@ struct nl_want_attrs {
 };
 
 
-#define BIRD_IFLA_MAX (IFLA_WIRELESS+1)
+#define BIRD_IFLA_MAX (IFLA_LINKINFO+1)
 
 static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
   [IFLA_IFNAME]          = { 1, 0, 0 },
   [IFLA_MTU]     = { 1, 1, sizeof(u32) },
   [IFLA_MASTER]          = { 1, 1, sizeof(u32) },
   [IFLA_WIRELESS] = { 1, 0, 0 },
+  [IFLA_LINKINFO] = { 1, 0, 0 },
+};
+
+#define BIRD_INFO_MAX (IFLA_INFO_DATA+1)
+
+static struct nl_want_attrs ifinfo_attr_want[BIRD_INFO_MAX] = {
+  [IFLA_INFO_KIND]= { 1, 0, 0 },
+  [IFLA_INFO_DATA]= { 1, 0, 0 },
 };
 
 
@@ -868,7 +876,7 @@ nl_parse_link(struct nlmsghdr *h, int scan)
   int new = h->nlmsg_type == RTM_NEWLINK;
   struct iface f = {};
   struct iface *ifi;
-  char *name;
+  const char *name, *kind = NULL;
   u32 mtu, master = 0;
   uint fl;
 
@@ -895,6 +903,15 @@ nl_parse_link(struct nlmsghdr *h, int scan)
   if (a[IFLA_MASTER])
     master = rta_get_u32(a[IFLA_MASTER]);
 
+  if (a[IFLA_LINKINFO])
+  {
+    struct rtattr *li[BIRD_INFO_MAX];
+    nl_attr_len = RTA_PAYLOAD(a[IFLA_LINKINFO]);
+    nl_parse_attrs(RTA_DATA(a[IFLA_LINKINFO]), ifinfo_attr_want, li, sizeof(li));
+    if (li[IFLA_INFO_KIND])
+      kind = RTA_DATA(li[IFLA_INFO_KIND]);
+  }
+
   ifi = if_find_by_index(i->ifi_index);
   if (!new)
     {
@@ -934,6 +951,9 @@ nl_parse_link(struct nlmsghdr *h, int scan)
       if (fl & IFF_MULTICAST)
        f.flags |= IF_MULTICAST;
 
+      if (kind && !strcmp(kind, "vrf"))
+       f.flags |= IF_VRF;
+
       ifi = if_update(&f);
 
       if (!scan)