struct f_path_mask *h;
struct password_item *p;
struct rt_show_data *ra;
+ struct iface *iface;
void *g;
bird_clock_t time;
struct prefix px;
%token <a> IPA
%token <s> SYM
%token <t> TEXT
+%type <iface> ipa_scope
%type <i> expr bool pxlen
%type <time> datetime
}
;
+ipa_scope:
+ /* empty */ { $$ = NULL; }
+ | '%' SYM { $$ = if_get_by_name($2->name); }
+ ;
+
prefix:
ipa pxlen {
if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix");
return NULL;
}
+struct iface *
+if_get_by_name(char *name)
+{
+ struct iface *i;
+
+ if (i = if_find_by_name(name))
+ return i;
+
+ /* No active iface, create a dummy */
+ i = mb_allocz(if_pool, sizeof(struct iface));
+ strncpy(i->name, name, sizeof(i->name)-1);
+ i->flags = IF_SHUTDOWN;
+ init_list(&i->addrs);
+ init_list(&i->neighbors);
+ add_tail(&iface_list, &i->n);
+ return i;
+}
+
struct ifa *kif_choose_primary(struct iface *i);
static int
void if_feed_baby(struct proto *);
struct iface *if_find_by_index(unsigned);
struct iface *if_find_by_name(char *);
+struct iface *if_get_by_name(char *);
void ifa_recalc_all_primary_addresses(void);
/* The Neighbor Cache */
void *data; /* Protocol-specific data */
unsigned aux; /* Protocol-specific data */
unsigned flags;
- unsigned scope; /* Address scope, SCOPE_HOST when it's our own address */
+ int scope; /* Address scope, -1 for unreachable sticky neighbors,
+ SCOPE_HOST when it's our own address */
} neighbor;
#define NEF_STICKY 1
#define NEF_ONLINK 2
+#define NEF_BIND 4 /* Used internally for neighbors bound to an iface */
neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags);
neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags);
if (ifa)
{
scope = if_connected(a, ifa);
+ flags |= NEF_BIND;
if ((scope < 0) && (flags & NEF_ONLINK))
scope = class & IADDR_SCOPE_MASK;
}
else
{
- /* sticky flag does not work for link-local neighbors;
- fortunately, we don't use this combination */
add_tail(&sticky_neigh_list, &n->n);
- ifa = NULL;
scope = -1;
}
n->iface = ifa;
{
DBG("Flushing neighbor %I on %s\n", n->addr, i->name);
rem_node(&n->if_n);
- n->iface = NULL;
+ if (! (n->flags & NEF_BIND))
+ n->iface = NULL;
+ n->scope = -1;
if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
n->proto->neigh_notify(n);
rem_node(&n->n);
int scope;
WALK_LIST_DELSAFE(n, next, sticky_neigh_list)
- if ((scope = if_connected(&n->addr, i)) >= 0)
+ if ((!n->iface || n->iface == i) &&
+ ((scope = if_connected(&n->addr, i)) >= 0))
neigh_up(n, i, scope);
}
if (n->proto->proto_state != PS_DOWN)
return;
rem_node(&n->n);
- if (n->iface)
+ if (n->scope >= 0)
rem_node(&n->if_n);
sl_free(neigh_slab, n);
}
return;
}
- if (p->neigh->iface)
+ if (p->neigh->scope > 0)
bgp_start_neighbor(p);
else
BGP_TRACE(D_EVENTS, "Waiting for %I to become my neighbor", cf->remote_ip);
;
stat_multipath1:
- VIA ipa {
+ VIA ipa ipa_scope {
last_srt_nh = this_srt_nh;
this_srt_nh = cfg_allocz(sizeof(struct static_route));
this_srt_nh->dest = RTD_NONE;
this_srt_nh->via = $2;
+ this_srt_nh->via_if = $3;
this_srt_nh->if_name = (void *) this_srt; /* really */
}
| stat_multipath1 WEIGHT expr {
;
stat_route:
- stat_route0 VIA ipa {
+ stat_route0 VIA ipa ipa_scope {
this_srt->dest = RTD_ROUTER;
this_srt->via = $3;
+ this_srt->via_if = $4;
}
| stat_route0 VIA TEXT {
this_srt->dest = RTD_DEVICE;
/* r->dest != RTD_MULTIPATH, but may be RTD_NONE (part of multipath route)
the route also have to be valid (r->neigh != NULL) */
- struct iface *ifa = r->neigh->iface;
-
- if (!ifa)
+ if (r->neigh->scope < 0)
return 0;
- if (cf->check_link && !(ifa->flags & IF_LINK_UP))
+ if (cf->check_link && !(r->neigh->iface->flags & IF_LINK_UP))
return 0;
return 1;
{
case RTD_ROUTER:
{
- struct neighbor *n = neigh_find(p, &r->via, NEF_STICKY);
+ struct neighbor *n = neigh_find2(p, &r->via, r->via_if, NEF_STICKY);
if (n)
{
r->chain = n->data;
for (r2 = r->mp_next; r2; r2 = r2->mp_next)
{
- struct neighbor *n = neigh_find(p, &r2->via, NEF_STICKY);
+ struct neighbor *n = neigh_find2(p, &r2->via, r2->via_if, NEF_STICKY);
if (n)
{
r2->chain = n->data;
switch (x->dest)
{
case RTD_ROUTER:
- return ipa_equal(x->via, y->via);
+ return ipa_equal(x->via, y->via) && (x->via_if == y->via_if);
case RTD_DEVICE:
return !strcmp(x->if_name, y->if_name);
for (x = x->mp_next, y = y->mp_next;
x && y;
x = x->mp_next, y = y->mp_next)
- if (!ipa_equal(x->via, y->via))
+ if (!ipa_equal(x->via, y->via) || (x->via_if != y->via_if))
return 0;
return !x && !y;
int masklen; /* Mask length */
int dest; /* Destination type (RTD_*) */
ip_addr via; /* Destination router */
+ struct iface *via_if; /* Destination iface, for link-local vias */
struct neighbor *neigh;
byte *if_name; /* Name for RTD_DEVICE routes */
struct static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */