}
static inline void
-do_rte_announce(struct announce_hook *a, net *net, rte *new, rte *old, ea_list *tmpa, int class)
+do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, ea_list *tmpa, int class)
{
struct proto *p = a->proto;
rte *new0 = new;
/**
* rte_announce - announce a routing table change
* @tab: table the route has been added to
+ * @type: type of route announcement (RA_OPTIMAL or RA_ANY)
* @net: network in question
* @new: the new route to be announced
- * @old: previous optimal route for the same network
+ * @old: the previous route for the same network
* @tmpa: a list of temporary attributes belonging to the new route
*
* This function gets a routing table update and announces it
* to all protocols connected to the same table by their announcement hooks.
*
+ * previous optimal route for the same network FIXME
+ *
* For each such protocol, we first call its import_control() hook which
* performs basic checks on the route (each protocol has a right to veto
* or force accept of the route before any filter is asked) and adds default
* route, the rt_notify() hook of the protocol gets called.
*/
static void
-rte_announce(rtable *tab, net *net, rte *new, rte *old, ea_list *tmpa)
+rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa)
{
struct announce_hook *a;
int class = ipa_classify(net->n.prefix);
WALK_LIST(a, tab->hooks)
{
ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING);
- do_rte_announce(a, net, new, old, tmpa, class);
+ if (a->proto->accept_ra_types == type)
+ do_rte_announce(a, type, net, new, old, tmpa, class);
}
}
if (ipa_nonzero(ipa_and(n->n.prefix, ipa_not(ipa_mkmask(n->n.pxlen)))))
{
log(L_BUG "Ignoring bogus prefix %I/%d received via %s",
- n->n.prefix, n->n.pxlen, e->attrs->proto->name);
+ n->n.prefix, n->n.pxlen, e->sender->name);
return 0;
}
if (n->n.pxlen)
return 1;
}
log(L_WARN "Ignoring bogus route %I/%d received via %s",
- n->n.prefix, n->n.pxlen, e->attrs->proto->name);
+ n->n.prefix, n->n.pxlen, e->sender->name);
return 0;
}
- if ((c & IADDR_SCOPE_MASK) < e->attrs->proto->min_scope)
+ if ((c & IADDR_SCOPE_MASK) < e->sender->min_scope)
{
log(L_WARN "Ignoring %s scope route %I/%d received from %I via %s",
ip_scope_text(c & IADDR_SCOPE_MASK),
- n->n.prefix, n->n.pxlen, e->attrs->from, e->attrs->proto->name);
+ n->n.prefix, n->n.pxlen, e->attrs->from, e->sender->name);
return 0;
}
}
}
static void
-rte_recalculate(rtable *table, net *net, struct proto *p, rte *new, ea_list *tmpa)
+rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte *new, ea_list *tmpa)
{
rte *old_best = net->routes;
rte *old = NULL;
k = &net->routes; /* Find and remove original route from the same protocol */
while (old = *k)
{
- if (old->attrs->proto == p)
+ if (old->attrs->proto == src)
{
if (new && rte_same(old, new))
{
k = &old->next;
}
+ log(L_WARN "ANNOUNCE %I/%d from %s (%s) %p", net->n.prefix, net->n.pxlen, p->name, src->name, old_best);
+
+ rte_announce(table, RA_ANY, net, new, old, tmpa);
+
if (new && rte_better(new, old_best)) /* It's a new optimal route => announce and relink it */
{
rte_trace_in(D_ROUTES, p, new, "added [best]");
- rte_announce(table, net, new, old_best, tmpa);
+ rte_announce(table, RA_OPTIMAL, net, new, old_best, tmpa);
new->next = net->routes;
net->routes = new;
}
for(s=net->routes; s; s=s->next)
if (rte_better(s, r))
r = s;
- rte_announce(table, net, r, old_best, tmpa);
+ rte_announce(table, RA_OPTIMAL, net, r, old_best, tmpa);
if (r) /* Re-link the new optimal route */
{
k = &net->routes;
*/
void
rte_update(rtable *table, net *net, struct proto *p, rte *new)
+{
+ rte_update2(table, net, p, p, new);
+}
+
+void
+rte_update2(rtable *table, net *net, struct proto *p, struct proto *src, rte *new)
{
ea_list *tmpa = NULL;
rte_update_lock();
if (new)
{
+ new->sender = p;
struct filter *filter = p->in_filter;
/* Do not filter routes going to the secondary side of the pipe,
rte_trace_in(D_FILTERS, p, new, "filtered out");
goto drop;
}
- if (p->make_tmp_attrs)
- tmpa = p->make_tmp_attrs(new, rte_update_pool);
+ if (src->make_tmp_attrs)
+ tmpa = src->make_tmp_attrs(new, rte_update_pool);
if (filter)
{
ea_list *old_tmpa = tmpa;
rte_trace_in(D_FILTERS, p, new, "filtered out");
goto drop;
}
- if (tmpa != old_tmpa && p->store_tmp_attrs)
- p->store_tmp_attrs(new, tmpa);
+ if (tmpa != old_tmpa && src->store_tmp_attrs)
+ src->store_tmp_attrs(new, tmpa);
}
if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */
new->attrs = rta_lookup(new->attrs);
new->flags |= REF_COW;
}
- rte_recalculate(table, net, p, new, tmpa);
+ rte_recalculate(table, net, p, src, new, tmpa);
rte_update_unlock();
return;
void
rte_discard(rtable *t, rte *old) /* Non-filtered route deletion, used during garbage collection */
{
- net *n = old->net;
- struct proto *p = old->attrs->proto;
-
rte_update_lock();
- rte_recalculate(t, n, p, NULL, NULL);
+ rte_recalculate(t, old->net, old->sender, old->attrs->proto, NULL, NULL);
rte_update_unlock();
}
ncnt++;
rescan:
for (e=n->routes; e; e=e->next, rcnt++)
- if (e->attrs->proto->core_state != FS_HAPPY &&
- e->attrs->proto->core_state != FS_FEEDING)
+ if (e->sender->core_state != FS_HAPPY &&
+ e->sender->core_state != FS_FEEDING)
{
rte_discard(tab, e);
rdel++;
DBG("\tdone\n");
}
+static inline void
+do_feed_baby(struct proto *p, int type, struct announce_hook *h, net *n, rte *e)
+{
+ struct proto *q = e->attrs->proto;
+ ea_list *tmpa;
+
+ rte_update_lock();
+ tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL;
+ do_rte_announce(h, type, n, e, NULL, tmpa, ipa_classify(n->n.prefix));
+ rte_update_unlock();
+}
+
/**
* rt_feed_baby - advertise routes to a new protocol
* @p: protocol to be fed
FIB_ITERATE_PUT(fit, fn);
return 0;
}
- if (e)
- {
- struct proto *q = e->attrs->proto;
- ea_list *tmpa;
-
- if (p->core_state != FS_FEEDING)
- return 1; /* In the meantime, the protocol fell down. */
- rte_update_lock();
- tmpa = q->make_tmp_attrs ? q->make_tmp_attrs(e, rte_update_pool) : NULL;
- do_rte_announce(h, n, e, NULL, tmpa, ipa_classify(n->n.prefix));
- rte_update_unlock();
- max_feed--;
- }
+
+ if (p->accept_ra_types == RA_OPTIMAL)
+ if (e)
+ {
+ if (p->core_state != FS_FEEDING)
+ return 1; /* In the meantime, the protocol fell down. */
+ do_feed_baby(p, RA_OPTIMAL, h, n, e);
+ max_feed--;
+ }
+
+ if (p->accept_ra_types == RA_ANY)
+ for(e = n->routes; e != NULL; e = e->next)
+ {
+ if (p->core_state != FS_FEEDING)
+ return 1; /* In the meantime, the protocol fell down. */
+ do_feed_baby(p, RA_ANY, h, n, e);
+ max_feed--;
+ }
}
FIB_ITERATE_END(fn);
p->feed_ahook = h->next;
#include "pipe.h"
static void
-pipe_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
+pipe_send(struct pipe_proto *p, rtable *dest, net *n, rte *new, rte *old, ea_list *attrs)
{
+ struct proto *src;
net *nn;
rte *e;
rta a;
+ if (!new && !old)
+ return;
+
if (dest->pipe_busy)
{
log(L_ERR "Pipe loop detected when sending %I/%d to table %s",
if (new)
{
memcpy(&a, new->attrs, sizeof(rta));
- a.proto = &p->p;
- a.source = RTS_PIPE;
a.aflags = 0;
a.eattrs = attrs;
e = rte_get_temp(&a);
e->net = nn;
+
+ /* Copy protocol specific embedded attributes. */
+ memcpy(&(e->u), &(new->u), sizeof(e->u));
+
+ src = new->attrs->proto;
}
else
- e = NULL;
+ {
+ e = NULL;
+ src = old->attrs->proto;
+ }
+
dest->pipe_busy = 1;
- rte_update(dest, nn, &p->p, e);
+ rte_update2(dest, nn, &p->p, src, e);
dest->pipe_busy = 0;
}
static int
pipe_import_control(struct proto *P, rte **ee, ea_list **ea UNUSED, struct linpool *p UNUSED)
{
- struct proto *pp = (*ee)->attrs->proto;
+ struct proto *pp = (*ee)->sender;
if (pp == P || pp == &((struct pipe_proto *) P)->phantom->p)
return -1; /* Avoid local loops automatically */
memcpy(ph, p, sizeof(struct pipe_proto));
p->phantom = ph;
ph->phantom = p;
+ ph->p.accept_ra_types = RA_ANY;
ph->p.rt_notify = pipe_rt_notify_sec;
ph->p.proto_state = PS_UP;
ph->p.core_state = ph->p.core_goal = FS_HAPPY;
struct pipe_proto *p = (struct pipe_proto *) P;
p->peer = c->peer->table;
+ P->accept_ra_types = RA_ANY;
P->rt_notify = pipe_rt_notify_pri;
P->import_control = pipe_import_control;
return P;