diff --git a/nest/iface.c b/nest/iface.c index 682340c5..6c84cbcf 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..f8e92850 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -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 */ diff --git a/nest/neighbor.c b/nest/neighbor.c index 7cf9c85d..2c2d3adf 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..4187d258 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 ee98115d..dc52e805 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -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 */ diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 87e3d95e..dd922b00 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..ba31e1a8 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..1c3509e4 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)) diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index e3298a0f..1af78766 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -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)