{
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;
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);
}
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 *);
/*
}
}
+/**
+ * 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)
{
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
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;
}
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; }
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)
{
}
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)
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);
DBG("Static: take off!\n");
WALK_LIST(r, c->other_routes)
- static_add(p, r);
+ static_add(p, c, r);
return PS_UP;
}
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);
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);
static_install(p, r, ifa);
}
WALK_LIST(r, n->other_routes)
- static_add(p, r);
+ static_add(p, n, r);
return 1;
}
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 {