0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-11-08 12:18:42 +00:00

Nest: Treat VRF interfaces as inside respective VRFs

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!
This commit is contained in:
Ondrej Zajicek 2023-08-23 15:55:31 +02:00
parent 5121101136
commit e3c0eca956
9 changed files with 36 additions and 12 deletions

View File

@ -147,7 +147,7 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
{ {
if (p->ifa_notify && if (p->ifa_notify &&
(p->proto_state != PS_DOWN) && (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) if (p->debug & D_IFACES)
log(L_TRACE "%s < address %N on interface %s %s", 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 && if (p->if_notify &&
(p->proto_state != PS_DOWN) && (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) if (p->debug & D_IFACES)
log(L_TRACE "%s < interface %s %s", p->name, i->name, log(L_TRACE "%s < interface %s %s", p->name, i->name,

View File

@ -53,6 +53,7 @@ struct iface {
#define IF_IGNORE 0x40 /* Not to be used by routing protocols (loopbacks etc.) */ #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_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_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_PRIMARY 0x10000 /* This address is primary */
#define IA_SECONDARY 0x20000 /* This address has been reported as secondary by the kernel */ #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 *); struct iface *if_get_by_name(const char *);
void if_recalc_all_preferred_addresses(void); 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 */ /* The Neighbor Cache */

View 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 */ /* Prefer SCOPE_HOST or longer prefix */
WALK_LIST(i, iface_list) 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))) if (scope_better(s, scope) || (scope_remote(s, scope) && ifa_better(b, *addr)))
{ {
*iface = i; *iface = i;
@ -369,7 +369,7 @@ neigh_update(neighbor *n, struct iface *iface)
return; return;
/* VRF-bound neighbors ignore changes in other VRFs */ /* 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; return;
scope = if_connected(n->addr, iface, &ifa, n->flags); scope = if_connected(n->addr, iface, &ifa, n->flags);

View File

@ -2062,7 +2062,7 @@ babel_reconfigure_ifaces(struct babel_proto *p, struct babel_config *cf)
WALK_LIST(iface, iface_list) 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; continue;
if (!(iface->flags & IF_UP)) if (!(iface->flags & IF_UP))

View File

@ -1179,7 +1179,7 @@ bgp_use_gateway(struct bgp_export_state *s)
return 0; return 0;
/* Do not use gateway from different VRF */ /* 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; return 0;
/* Use it when exported to internal peers */ /* Use it when exported to internal peers */

View File

@ -1227,7 +1227,7 @@ ospf_reconfigure_ifaces2(struct ospf_proto *p)
WALK_LIST(iface, iface_list) 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; continue;
if (! (iface->flags & IF_UP)) if (! (iface->flags & IF_UP))
@ -1276,7 +1276,7 @@ ospf_reconfigure_ifaces3(struct ospf_proto *p)
WALK_LIST(iface, iface_list) 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; continue;
if (! (iface->flags & IF_UP)) if (! (iface->flags & IF_UP))

View File

@ -663,7 +663,7 @@ radv_reconfigure(struct proto *P, struct proto_config *CF)
struct iface *iface; struct iface *iface;
WALK_LIST(iface, iface_list) 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; continue;
if (!(iface->flags & IF_UP)) if (!(iface->flags & IF_UP))

View File

@ -797,7 +797,7 @@ rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
WALK_LIST(iface, iface_list) 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; continue;
if (!(iface->flags & IF_UP)) if (!(iface->flags & IF_UP))

View 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] = { static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
[IFLA_IFNAME] = { 1, 0, 0 }, [IFLA_IFNAME] = { 1, 0, 0 },
[IFLA_MTU] = { 1, 1, sizeof(u32) }, [IFLA_MTU] = { 1, 1, sizeof(u32) },
[IFLA_MASTER] = { 1, 1, sizeof(u32) }, [IFLA_MASTER] = { 1, 1, sizeof(u32) },
[IFLA_WIRELESS] = { 1, 0, 0 }, [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; int new = h->nlmsg_type == RTM_NEWLINK;
struct iface f = {}; struct iface f = {};
struct iface *ifi; struct iface *ifi;
char *name; const char *name, *kind = NULL;
u32 mtu, master = 0; u32 mtu, master = 0;
uint fl; uint fl;
@ -895,6 +903,15 @@ nl_parse_link(struct nlmsghdr *h, int scan)
if (a[IFLA_MASTER]) if (a[IFLA_MASTER])
master = rta_get_u32(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); ifi = if_find_by_index(i->ifi_index);
if (!new) if (!new)
{ {
@ -934,6 +951,9 @@ nl_parse_link(struct nlmsghdr *h, int scan)
if (fl & IFF_MULTICAST) if (fl & IFF_MULTICAST)
f.flags |= IF_MULTICAST; f.flags |= IF_MULTICAST;
if (kind && !strcmp(kind, "vrf"))
f.flags |= IF_VRF;
ifi = if_update(&f); ifi = if_update(&f);
if (!scan) if (!scan)