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:
parent
c32c3f88f0
commit
69a8259c5e
8 changed files with 48 additions and 18 deletions
|
@ -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");
|
||||||
|
|
18
nest/iface.c
18
nest/iface.c
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in a new issue