diff options
-rw-r--r-- | conf/confbase.Y | 7 | ||||
-rw-r--r-- | nest/iface.c | 18 | ||||
-rw-r--r-- | nest/iface.h | 5 | ||||
-rw-r--r-- | nest/neighbor.c | 13 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 2 | ||||
-rw-r--r-- | proto/static/config.Y | 6 | ||||
-rw-r--r-- | proto/static/static.c | 14 | ||||
-rw-r--r-- | proto/static/static.h | 1 |
8 files changed, 48 insertions, 18 deletions
diff --git a/conf/confbase.Y b/conf/confbase.Y index 499a770e..14893f47 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -50,6 +50,7 @@ CF_DECLS 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; @@ -65,6 +66,7 @@ CF_DECLS %token <a> IPA %token <s> SYM %token <t> TEXT +%type <iface> ipa_scope %type <i> expr bool pxlen %type <time> datetime @@ -140,6 +142,11 @@ ipa: } ; +ipa_scope: + /* empty */ { $$ = NULL; } + | '%' SYM { $$ = if_get_by_name($2->name); } + ; + prefix: ipa pxlen { if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix"); diff --git a/nest/iface.c b/nest/iface.c index bf57a9b1..b8b214e5 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -424,6 +424,24 @@ if_find_by_name(char *name) 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 diff --git a/nest/iface.h b/nest/iface.h index 7307844e..d6d58ff9 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -97,6 +97,7 @@ void if_flush_ifaces(struct proto *p); 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 */ @@ -110,11 +111,13 @@ typedef struct neighbor { 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); diff --git a/nest/neighbor.c b/nest/neighbor.c index 67bd32b3..506d9bde 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -133,6 +133,7 @@ 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; @@ -160,10 +161,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags) } 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; @@ -235,7 +233,9 @@ neigh_down(neighbor *n) { 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); @@ -262,7 +262,8 @@ neigh_if_up(struct iface *i) 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); } @@ -339,7 +340,7 @@ neigh_prune_one(neighbor *n) 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); } diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 28396a52..6bd18f09 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -804,7 +804,7 @@ bgp_start_locked(struct object_lock *lock) 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); diff --git a/proto/static/config.Y b/proto/static/config.Y index 621fdf9b..f8e84f92 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -48,11 +48,12 @@ stat_route0: ROUTE prefix { ; 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 { @@ -67,9 +68,10 @@ stat_multipath: ; 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; diff --git a/proto/static/static.c b/proto/static/static.c index e5b293c0..3323c7ee 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -138,12 +138,10 @@ static_decide(struct static_config *cf, struct static_route *r) /* 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; @@ -158,7 +156,7 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) { 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; @@ -187,7 +185,7 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) 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; @@ -385,7 +383,7 @@ static_same_dest(struct static_route *x, struct static_route *y) 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); @@ -394,7 +392,7 @@ static_same_dest(struct static_route *x, struct static_route *y) 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; diff --git a/proto/static/static.h b/proto/static/static.h index 775743cf..eb87ddec 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -27,6 +27,7 @@ struct static_route { 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 */ |