Allows sticky link-local neighbors.

Allows using NEF_STICKY neighbors with link-local addresses. This is
used for static route nexthops, they can be specified like fe80::1%eth0
.
This commit is contained in:
Ondrej Zajicek 2012-01-01 12:02:20 +01:00
parent c32c3f88f0
commit 69a8259c5e
8 changed files with 48 additions and 18 deletions

View file

@ -50,6 +50,7 @@ CF_DECLS
struct f_path_mask *h; struct f_path_mask *h;
struct password_item *p; struct password_item *p;
struct rt_show_data *ra; struct rt_show_data *ra;
struct iface *iface;
void *g; void *g;
bird_clock_t time; bird_clock_t time;
struct prefix px; struct prefix px;
@ -65,6 +66,7 @@ CF_DECLS
%token <a> IPA %token <a> IPA
%token <s> SYM %token <s> SYM
%token <t> TEXT %token <t> TEXT
%type <iface> ipa_scope
%type <i> expr bool pxlen %type <i> expr bool pxlen
%type <time> datetime %type <time> datetime
@ -140,6 +142,11 @@ ipa:
} }
; ;
ipa_scope:
/* empty */ { $$ = NULL; }
| '%' SYM { $$ = if_get_by_name($2->name); }
;
prefix: prefix:
ipa pxlen { ipa pxlen {
if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix"); if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix");

View file

@ -424,6 +424,24 @@ if_find_by_name(char *name)
return NULL; 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); struct ifa *kif_choose_primary(struct iface *i);
static int static int

View file

@ -97,6 +97,7 @@ void if_flush_ifaces(struct proto *p);
void if_feed_baby(struct proto *); void if_feed_baby(struct proto *);
struct iface *if_find_by_index(unsigned); struct iface *if_find_by_index(unsigned);
struct iface *if_find_by_name(char *); struct iface *if_find_by_name(char *);
struct iface *if_get_by_name(char *);
void ifa_recalc_all_primary_addresses(void); void ifa_recalc_all_primary_addresses(void);
/* The Neighbor Cache */ /* The Neighbor Cache */
@ -110,11 +111,13 @@ typedef struct neighbor {
void *data; /* Protocol-specific data */ void *data; /* Protocol-specific data */
unsigned aux; /* Protocol-specific data */ unsigned aux; /* Protocol-specific data */
unsigned flags; 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; } neighbor;
#define NEF_STICKY 1 #define NEF_STICKY 1
#define NEF_ONLINK 2 #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_find(struct proto *, ip_addr *, unsigned flags);
neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags); neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags);

View file

@ -133,6 +133,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
if (ifa) if (ifa)
{ {
scope = if_connected(a, ifa); scope = if_connected(a, ifa);
flags |= NEF_BIND;
if ((scope < 0) && (flags & NEF_ONLINK)) if ((scope < 0) && (flags & NEF_ONLINK))
scope = class & IADDR_SCOPE_MASK; scope = class & IADDR_SCOPE_MASK;
@ -160,10 +161,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
} }
else else
{ {
/* sticky flag does not work for link-local neighbors;
fortunately, we don't use this combination */
add_tail(&sticky_neigh_list, &n->n); add_tail(&sticky_neigh_list, &n->n);
ifa = NULL;
scope = -1; scope = -1;
} }
n->iface = ifa; n->iface = ifa;
@ -235,7 +233,9 @@ neigh_down(neighbor *n)
{ {
DBG("Flushing neighbor %I on %s\n", n->addr, i->name); DBG("Flushing neighbor %I on %s\n", n->addr, i->name);
rem_node(&n->if_n); 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) if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
n->proto->neigh_notify(n); n->proto->neigh_notify(n);
rem_node(&n->n); rem_node(&n->n);
@ -262,7 +262,8 @@ neigh_if_up(struct iface *i)
int scope; int scope;
WALK_LIST_DELSAFE(n, next, sticky_neigh_list) 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); neigh_up(n, i, scope);
} }
@ -339,7 +340,7 @@ neigh_prune_one(neighbor *n)
if (n->proto->proto_state != PS_DOWN) if (n->proto->proto_state != PS_DOWN)
return; return;
rem_node(&n->n); rem_node(&n->n);
if (n->iface) if (n->scope >= 0)
rem_node(&n->if_n); rem_node(&n->if_n);
sl_free(neigh_slab, n); sl_free(neigh_slab, n);
} }

View file

@ -804,7 +804,7 @@ bgp_start_locked(struct object_lock *lock)
return; return;
} }
if (p->neigh->iface) if (p->neigh->scope > 0)
bgp_start_neighbor(p); bgp_start_neighbor(p);
else else
BGP_TRACE(D_EVENTS, "Waiting for %I to become my neighbor", cf->remote_ip); BGP_TRACE(D_EVENTS, "Waiting for %I to become my neighbor", cf->remote_ip);

View file

@ -48,11 +48,12 @@ stat_route0: ROUTE prefix {
; ;
stat_multipath1: stat_multipath1:
VIA ipa { VIA ipa ipa_scope {
last_srt_nh = this_srt_nh; last_srt_nh = this_srt_nh;
this_srt_nh = cfg_allocz(sizeof(struct static_route)); this_srt_nh = cfg_allocz(sizeof(struct static_route));
this_srt_nh->dest = RTD_NONE; this_srt_nh->dest = RTD_NONE;
this_srt_nh->via = $2; this_srt_nh->via = $2;
this_srt_nh->via_if = $3;
this_srt_nh->if_name = (void *) this_srt; /* really */ this_srt_nh->if_name = (void *) this_srt; /* really */
} }
| stat_multipath1 WEIGHT expr { | stat_multipath1 WEIGHT expr {
@ -67,9 +68,10 @@ stat_multipath:
; ;
stat_route: stat_route:
stat_route0 VIA ipa { stat_route0 VIA ipa ipa_scope {
this_srt->dest = RTD_ROUTER; this_srt->dest = RTD_ROUTER;
this_srt->via = $3; this_srt->via = $3;
this_srt->via_if = $4;
} }
| stat_route0 VIA TEXT { | stat_route0 VIA TEXT {
this_srt->dest = RTD_DEVICE; this_srt->dest = RTD_DEVICE;

View file

@ -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) /* r->dest != RTD_MULTIPATH, but may be RTD_NONE (part of multipath route)
the route also have to be valid (r->neigh != NULL) */ the route also have to be valid (r->neigh != NULL) */
struct iface *ifa = r->neigh->iface; if (r->neigh->scope < 0)
if (!ifa)
return 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 0;
return 1; return 1;
@ -158,7 +156,7 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
{ {
case RTD_ROUTER: 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) if (n)
{ {
r->chain = n->data; 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) 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) if (n)
{ {
r2->chain = n->data; r2->chain = n->data;
@ -385,7 +383,7 @@ static_same_dest(struct static_route *x, struct static_route *y)
switch (x->dest) switch (x->dest)
{ {
case RTD_ROUTER: 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: case RTD_DEVICE:
return !strcmp(x->if_name, y->if_name); 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; for (x = x->mp_next, y = y->mp_next;
x && y; x && y;
x = x->mp_next, y = y->mp_next) 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 0;
return !x && !y; return !x && !y;

View file

@ -27,6 +27,7 @@ struct static_route {
int masklen; /* Mask length */ int masklen; /* Mask length */
int dest; /* Destination type (RTD_*) */ int dest; /* Destination type (RTD_*) */
ip_addr via; /* Destination router */ ip_addr via; /* Destination router */
struct iface *via_if; /* Destination iface, for link-local vias */
struct neighbor *neigh; struct neighbor *neigh;
byte *if_name; /* Name for RTD_DEVICE routes */ byte *if_name; /* Name for RTD_DEVICE routes */
struct static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */ struct static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */