diff options
-rw-r--r-- | nest/iface.c | 6 | ||||
-rw-r--r-- | nest/iface.h | 1 | ||||
-rw-r--r-- | nest/neighbor.c | 22 | ||||
-rw-r--r-- | proto/static/config.Y | 8 | ||||
-rw-r--r-- | proto/static/static.c | 30 | ||||
-rw-r--r-- | proto/static/static.h | 8 |
6 files changed, 62 insertions, 13 deletions
diff --git a/nest/iface.c b/nest/iface.c index 8e45936..c523678 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -117,7 +117,7 @@ if_what_changed(struct iface *i, struct iface *j) { unsigned c; - if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_TMP_DOWN | IF_JUST_CREATED)) + if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED)) || i->index != j->index) return IF_CHANGE_TOO_MUCH; c = 0; @@ -213,6 +213,10 @@ if_notify_change(unsigned c, struct iface *i) a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS); ifa_notify_change(IF_CHANGE_UP, a); } + + if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK) + neigh_if_link(i); + if (c & IF_CHANGE_DOWN) neigh_if_down(i); } diff --git a/nest/iface.h b/nest/iface.h index 471625f..1936885 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -125,6 +125,7 @@ void neigh_dump_all(void); void neigh_prune(void); void neigh_if_up(struct iface *); void neigh_if_down(struct iface *); +void neigh_if_link(struct iface *); void neigh_init(struct pool *); /* diff --git a/nest/neighbor.c b/nest/neighbor.c index 7e7cc49..785b1d4 100644 --- a/nest/neighbor.c +++ b/nest/neighbor.c @@ -278,6 +278,28 @@ neigh_if_down(struct iface *i) } } +/** + * neigh_if_link - notify neighbor cache about interface link change + * @i: the interface in question + * + * Notify the neighbor cache that an interface changed link state. + * All owners of neighbor entries connected to this interface are + * notified. + */ + +void +neigh_if_link(struct iface *i) +{ + node *x, *y; + + WALK_LIST_DELSAFE(x, y, i->neighbors) + { + neighbor *n = SKIP_BACK(neighbor, if_n, x); + if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING) + n->proto->neigh_notify(n); + } +} + static inline void neigh_prune_one(neighbor *n) { diff --git a/proto/static/config.Y b/proto/static/config.Y index a7e5016..9f4d7da 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -12,11 +12,12 @@ CF_HDR CF_DEFINES +#define STATIC_CFG ((struct static_config *) this_proto) static struct static_route *this_srt; CF_DECLS -CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE) +CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK) CF_GRAMMAR @@ -31,12 +32,13 @@ static_proto_start: proto_start STATIC { static_proto: static_proto_start proto_name '{' | static_proto proto_item ';' + | static_proto CHECK LINK ';' { STATIC_CFG->check = STATIC_CHECK_LINK; } | static_proto stat_route ';' ; stat_route0: ROUTE prefix { this_srt = cfg_allocz(sizeof(struct static_route)); - add_tail(&((struct static_config *) this_proto)->other_routes, &this_srt->n); + add_tail(&STATIC_CFG->other_routes, &this_srt->n); this_srt->net = $2.addr; this_srt->masklen = $2.len; } @@ -51,7 +53,7 @@ stat_route: this_srt->dest = RTD_DEVICE; this_srt->if_name = $3; rem_node(&this_srt->n); - add_tail(&((struct static_config *) this_proto)->iface_routes, &this_srt->n); + add_tail(&STATIC_CFG->iface_routes, &this_srt->n); } | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; } | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } diff --git a/proto/static/static.c b/proto/static/static.c index 6b42a37..4f879bd 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -64,6 +64,20 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa) r->installed = 1; } +static int +static_decide(struct static_config *cf, struct static_route *r) +{ + struct iface *ifa = r->neigh->iface; + + if (!ifa) + return 0; + + if ((cf->check == STATIC_CHECK_LINK) && !(ifa->flags & IF_LINK_UP)) + return 0; + + return 1; +} + static void static_remove(struct proto *p, struct static_route *r) { @@ -80,7 +94,7 @@ static_remove(struct proto *p, struct static_route *r) } static void -static_add(struct proto *p, struct static_route *r) +static_add(struct proto *p, struct static_config *cf, struct static_route *r) { DBG("static_add(%I/%d,%d)\n", r->net, r->masklen, r->dest); switch (r->dest) @@ -93,8 +107,10 @@ static_add(struct proto *p, struct static_route *r) r->chain = n->data; n->data = r; r->neigh = n; - if (n->iface) + if (static_decide(cf, r)) static_install(p, r, n->iface); + else + static_remove(p, r); } else log(L_ERR "Static route destination %I is invalid. Ignoring.", r->via); @@ -115,7 +131,7 @@ static_start(struct proto *p) DBG("Static: take off!\n"); WALK_LIST(r, c->other_routes) - static_add(p, r); + static_add(p, c, r); return PS_UP; } @@ -142,7 +158,7 @@ static_neigh_notify(struct neighbor *n) DBG("Static: neighbor notify for %I: iface %p\n", n->addr, n->iface); for(r=n->data; r; r=r->chain) - if (n->iface) + if (static_decide((struct static_config *) p->cf, r)) static_install(p, r, n->iface); else static_remove(p, r); @@ -249,13 +265,13 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n) WALK_LIST(t, n->iface_routes) if (static_same_net(r, t)) { - t->installed = static_same_dest(r, t); + t->installed = r->installed && static_same_dest(r, t); return; } WALK_LIST(t, n->other_routes) if (static_same_net(r, t)) { - t->installed = static_same_dest(r, t); + t->installed = r->installed && static_same_dest(r, t); return; } static_remove(p, r); @@ -282,7 +298,7 @@ static_reconfigure(struct proto *p, struct proto_config *new) static_install(p, r, ifa); } WALK_LIST(r, n->other_routes) - static_add(p, r); + static_add(p, n, r); return 1; } diff --git a/proto/static/static.h b/proto/static/static.h index 5d2bd21..40da74c 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -11,10 +11,14 @@ struct static_config { struct proto_config c; - list iface_routes; /* Routes to search on interface events */ - list other_routes; /* Routes hooked to neighbor cache and reject routes */ + list iface_routes; /* Routes to search on interface events */ + list other_routes; /* Routes hooked to neighbor cache and reject routes */ + int check; /* Condition for route install */ }; +#define STATIC_CHECK_NONE 0 +#define STATIC_CHECK_LINK 1 + void static_init_config(struct static_config *); struct static_route { |