{
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",
{
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,
#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 */
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 */
/* 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;
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);
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))
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 */
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))
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))
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))
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))
};
-#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 },
};
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;
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)
{
if (fl & IFF_MULTICAST)
f.flags |= IF_MULTICAST;
+ if (kind && !strcmp(kind, "vrf"))
+ f.flags |= IF_VRF;
+
ifi = if_update(&f);
if (!scan)