summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorJan Moskyto Matejka <mq@ucw.cz>2016-05-06 15:48:35 +0200
committerJan Moskyto Matejka <mq@ucw.cz>2016-12-22 13:01:06 +0100
commit4e276a8920ed0496836f002f144943ab42f120f6 (patch)
treeb2d24394f036cbd825330e0087a7f9f4ca167174 /proto
parentb7605d5c953902b461e5c9e87aa3dfa60ddce5bc (diff)
Merged multipath and single-path data structures.
Dropped struct mpnh and mpnh_*() Now struct nexthop exists, nexthop_*(), and also included struct nexthop into struct rta. Also converted RTD_DEVICE and RTD_ROUTER to RTD_UNICAST. If it is needed to distinguish between these two cases, RTD_DEVICE is equivalent to IPA_ZERO(a->nh.gw), RTD_ROUTER is then IPA_NONZERO(a->nh.gw). From now on, we also explicitely want C99 compatible compiler. We assume that this 20-year norm should be known almost everywhere.
Diffstat (limited to 'proto')
-rw-r--r--proto/bgp/attrs.c2
-rw-r--r--proto/bgp/packets.c13
-rw-r--r--proto/ospf/ospf.c2
-rw-r--r--proto/ospf/rt.c62
-rw-r--r--proto/ospf/rt.h2
-rw-r--r--proto/ospf/topology.c4
-rw-r--r--proto/ospf/topology.h2
-rw-r--r--proto/rip/rip.c25
-rw-r--r--proto/static/config.Y43
-rw-r--r--proto/static/static.c295
-rw-r--r--proto/static/static.h9
11 files changed, 196 insertions, 263 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 52b56efa..11666f30 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -1462,7 +1462,7 @@ static inline int
rte_resolvable(rte *rt)
{
int rd = rt->attrs->dest;
- return (rd == RTD_ROUTER) || (rd == RTD_DEVICE) || (rd == RTD_MULTIPATH);
+ return (rd == RTD_UNICAST);
}
int
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 66561ee4..0baa84c9 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -699,9 +699,10 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
if (!nbr || (nbr->scope == SCOPE_HOST))
WITHDRAW(BAD_NEXT_HOP);
- a->dest = RTD_ROUTER;
- a->gw = nbr->addr;
- a->iface = nbr->iface;
+ a->dest = RTD_UNICAST;
+ a->nh.gw = nbr->addr;
+ a->nh.iface = nbr->iface;
+ a->nh.next = NULL;
a->hostentry = NULL;
a->igp_metric = 0;
}
@@ -749,7 +750,7 @@ bgp_use_gateway(struct bgp_export_state *s)
return 0;
/* We need valid global gateway */
- if ((ra->dest != RTD_ROUTER) || ipa_zero(ra->gw) || ipa_is_link_local(ra->gw))
+ if ((ra->dest != RTD_UNICAST) || (ra->nh.next) || ipa_zero(ra->nh.gw) || ipa_is_link_local(ra->nh.gw))
return 0;
/* Use it when exported to internal peers */
@@ -757,7 +758,7 @@ bgp_use_gateway(struct bgp_export_state *s)
return 1;
/* Use it when forwarded to single-hop BGP peer on on the same iface */
- return p->neigh && (p->neigh->iface == ra->iface);
+ return p->neigh && (p->neigh->iface == ra->nh.iface);
}
static void
@@ -767,7 +768,7 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to)
{
if (bgp_use_gateway(s))
{
- ip_addr nh[1] = { s->route->attrs->gw };
+ ip_addr nh[1] = { s->route->attrs->nh.gw };
bgp_set_attr_data(to, s->pool, BA_NEXT_HOP, 0, nh, 16);
}
else
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index d074600a..daf76ff2 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -235,7 +235,7 @@ ospf_start(struct proto *P)
p->lsab_size = 256;
p->lsab_used = 0;
p->lsab = mb_alloc(P->pool, p->lsab_size);
- p->nhpool = lp_new(P->pool, 12*sizeof(struct mpnh));
+ p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop));
init_list(&(p->iface_list));
init_list(&(p->area_list));
fib_init(&p->rtf, P->pool, p->ospf2 ? NET_IP4 : NET_IP6,
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index 054841ca..09cc5776 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -22,7 +22,7 @@ static inline void reset_ri(ort *ort)
}
static inline int
-nh_is_vlink(struct mpnh *nhs)
+nh_is_vlink(struct nexthop *nhs)
{
return !nhs->iface;
}
@@ -33,10 +33,10 @@ unresolved_vlink(ort *ort)
return ort->n.nhs && nh_is_vlink(ort->n.nhs);
}
-static inline struct mpnh *
+static inline struct nexthop *
new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight)
{
- struct mpnh *nh = lp_alloc(p->nhpool, sizeof(struct mpnh));
+ struct nexthop *nh = lp_alloc(p->nhpool, sizeof(struct nexthop));
nh->gw = gw;
nh->iface = iface;
nh->next = NULL;
@@ -46,7 +46,7 @@ new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight)
/* Returns true if there are device nexthops in n */
static inline int
-has_device_nexthops(const struct mpnh *n)
+has_device_nexthops(const struct nexthop *n)
{
for (; n; n = n->next)
if (ipa_zero(n->gw))
@@ -56,13 +56,13 @@ has_device_nexthops(const struct mpnh *n)
}
/* Replace device nexthops with nexthops to gw */
-static struct mpnh *
-fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw)
+static struct nexthop *
+fix_device_nexthops(struct ospf_proto *p, const struct nexthop *n, ip_addr gw)
{
- struct mpnh *root1 = NULL;
- struct mpnh *root2 = NULL;
- struct mpnh **nn1 = &root1;
- struct mpnh **nn2 = &root2;
+ struct nexthop *root1 = NULL;
+ struct nexthop *root2 = NULL;
+ struct nexthop **nn1 = &root1;
+ struct nexthop **nn2 = &root2;
if (!p->ecmp)
return new_nexthop(p, gw, n->iface, n->weight);
@@ -73,7 +73,7 @@ fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw)
for (; n; n = n->next)
{
- struct mpnh *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight);
+ struct nexthop *nn = new_nexthop(p, ipa_zero(n->gw) ? gw : n->gw, n->iface, n->weight);
if (ipa_zero(n->gw))
{
@@ -87,7 +87,7 @@ fix_device_nexthops(struct ospf_proto *p, const struct mpnh *n, ip_addr gw)
}
}
- return mpnh_merge(root1, root2, 1, 1, p->ecmp, p->nhpool);
+ return nexthop_merge(root1, root2, 1, 1, p->ecmp, p->nhpool);
}
@@ -283,7 +283,7 @@ ort_merge(struct ospf_proto *p, ort *o, const orta *new)
if (old->nhs != new->nhs)
{
- old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
+ old->nhs = nexthop_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
p->ecmp, p->nhpool);
old->nhs_reuse = 1;
}
@@ -299,7 +299,7 @@ ort_merge_ext(struct ospf_proto *p, ort *o, const orta *new)
if (old->nhs != new->nhs)
{
- old->nhs = mpnh_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
+ old->nhs = nexthop_merge(old->nhs, new->nhs, old->nhs_reuse, new->nhs_reuse,
p->ecmp, p->nhpool);
old->nhs_reuse = 1;
}
@@ -1673,18 +1673,18 @@ ospf_rt_spf(struct ospf_proto *p)
static inline int
-inherit_nexthops(struct mpnh *pn)
+inherit_nexthops(struct nexthop *pn)
{
/* Proper nexthops (with defined GW) or dummy vlink nexthops (without iface) */
return pn && (ipa_nonzero(pn->gw) || !pn->iface);
}
-static struct mpnh *
+static struct nexthop *
calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
struct top_hash_entry *par, int pos)
{
struct ospf_proto *p = oa->po;
- struct mpnh *pn = par->nhs;
+ struct nexthop *pn = par->nhs;
struct ospf_iface *ifa;
u32 rid = en->lsa.rt;
@@ -1812,7 +1812,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
if (!link_back(oa, en, par))
return;
- struct mpnh *nhs = calc_next_hop(oa, en, par, pos);
+ struct nexthop *nhs = calc_next_hop(oa, en, par, pos);
if (!nhs)
{
log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
@@ -1850,7 +1850,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
/* Merge old and new */
int new_reuse = (par->nhs != nhs);
- en->nhs = mpnh_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool);
+ en->nhs = nexthop_merge(en->nhs, nhs, en->nhs_reuse, new_reuse, p->ecmp, p->nhpool);
en->nhs_reuse = 1;
return;
}
@@ -1906,8 +1906,8 @@ ort_changed(ort *nf, rta *nr)
(nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) ||
(nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) ||
(nr->source != or->source) || (nr->dest != or->dest) ||
- (nr->iface != or->iface) || !ipa_equal(nr->gw, or->gw) ||
- !mpnh_same(nr->nexthops, or->nexthops);
+ (nr->nh.iface != or->nh.iface) || !ipa_equal(nr->nh.gw, or->nh.gw) ||
+ !nexthop_same(&(nr->nh), &(or->nh));
}
static void
@@ -1931,7 +1931,7 @@ again1:
/* Sanity check of next-hop addresses, failure should not happen */
if (nf->n.type)
{
- struct mpnh *nh;
+ struct nexthop *nh;
for (nh = nf->n.nhs; nh; nh = nh->next)
if (ipa_nonzero(nh->gw))
{
@@ -1954,22 +1954,8 @@ again1:
.cast = RTC_UNICAST
};
- if (nf->n.nhs->next)
- {
- a0.dest = RTD_MULTIPATH;
- a0.nexthops = nf->n.nhs;
- }
- else if (ipa_nonzero(nf->n.nhs->gw))
- {
- a0.dest = RTD_ROUTER;
- a0.iface = nf->n.nhs->iface;
- a0.gw = nf->n.nhs->gw;
- }
- else
- {
- a0.dest = RTD_DEVICE;
- a0.iface = nf->n.nhs->iface;
- }
+ nexthop_link(&a0, nf->n.nhs);
+ a0.dest = RTD_UNICAST;
if (reload || ort_changed(nf, &a0))
{
diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h
index 959d12e9..842792f0 100644
--- a/proto/ospf/rt.h
+++ b/proto/ospf/rt.h
@@ -53,7 +53,7 @@ typedef struct orta
struct ospf_area *oa;
struct ospf_area *voa; /* Used when route is replaced in ospf_rt_sum_tr(),
NULL otherwise */
- struct mpnh *nhs; /* Next hops computed during SPF */
+ struct nexthop *nhs; /* Next hops computed during SPF */
struct top_hash_entry *en; /* LSA responsible for this orta */
}
orta;
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index aaaf2e8e..ce77f57a 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -1288,8 +1288,8 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
ip_addr fwd = IPA_NONE;
- if ((a->dest == RTD_ROUTER) && use_gw_for_fwaddr(p, a->gw, a->iface))
- fwd = a->gw;
+ if ((a->dest == RTD_UNICAST) && use_gw_for_fwaddr(p, a->nh.gw, a->nh.iface))
+ fwd = a->nh.gw;
/* NSSA-LSA with P-bit set must have non-zero forwarding address */
if (oa && ipa_zero(fwd))
diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h
index 38447fdf..d1682c54 100644
--- a/proto/ospf/topology.h
+++ b/proto/ospf/topology.h
@@ -28,7 +28,7 @@ struct top_hash_entry
u16 next_lsa_opts; /* For postponed LSA origination */
bird_clock_t inst_time; /* Time of installation into DB */
struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */
- struct mpnh *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
+ struct nexthop *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
u32 dist; /* Distance from the root */
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index d87a078c..8b09330c 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -158,10 +158,10 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
while (rt2 && !rip_valid_rte(rt2))
rt2 = rt2->next;
+ a0.dest = RTD_UNICAST;
if (p->ecmp && rt2)
{
/* ECMP route */
- struct mpnh *nhs = NULL;
int num = 0;
for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
@@ -169,33 +169,34 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (!rip_valid_rte(rt))
continue;
- struct mpnh *nh = alloca(sizeof(struct mpnh));
+ struct nexthop *nh = (a0.nh.next ? &(a0.nh) : alloca(sizeof(struct nexthop)));
+
nh->gw = rt->next_hop;
nh->iface = rt->from->nbr->iface;
nh->weight = rt->from->ifa->cf->ecmp_weight;
- mpnh_insert(&nhs, nh);
+
+ if (a0.nh.next)
+ nexthop_insert(&(a0.nh), nh);
+
num++;
if (rt->tag != rt_tag)
rt_tag = 0;
}
-
- a0.dest = RTD_MULTIPATH;
- a0.nexthops = nhs;
}
else
{
/* Unipath route */
- a0.dest = RTD_ROUTER;
- a0.gw = rt->next_hop;
- a0.iface = rt->from->nbr->iface;
+ a0.nh.next = NULL;
+ a0.nh.gw = rt->next_hop;
+ a0.nh.iface = rt->from->nbr->iface;
a0.from = rt->from->nbr->addr;
}
rta *a = rta_lookup(&a0);
rte *e = rte_get_temp(a);
- e->u.rip.from = a0.iface;
+ e->u.rip.from = a0.nh.iface;
e->u.rip.metric = rt_metric;
e->u.rip.tag = rt_tag;
@@ -345,8 +346,8 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
en->metric = rt_metric;
en->tag = rt_tag;
en->from = (new->attrs->src->proto == P) ? new->u.rip.from : NULL;
- en->iface = new->attrs->iface;
- en->next_hop = new->attrs->gw;
+ en->iface = new->attrs->nh.iface;
+ en->next_hop = new->attrs->nh.gw;
}
else
{
diff --git a/proto/static/config.Y b/proto/static/config.Y
index 86359f0b..8103166d 100644
--- a/proto/static/config.Y
+++ b/proto/static/config.Y
@@ -13,7 +13,7 @@ CF_HDR
CF_DEFINES
#define STATIC_CFG ((struct static_config *) this_proto)
-static struct static_route *this_srt, *this_srt_nh, *last_srt_nh;
+static struct static_route *this_srt, *last_srt;
static struct f_inst **this_srt_last_cmd;
static void
@@ -22,10 +22,9 @@ static_route_finish(void)
struct static_route *r;
/* Update undefined use_bfd entries in multipath nexthops */
- if (this_srt->dest == RTD_MULTIPATH)
- for (r = this_srt->mp_next; r; r = r->mp_next)
- if (r->use_bfd < 0)
- r->use_bfd = this_srt->use_bfd;
+ for (r = this_srt->mp_next; r; r = r->mp_next)
+ if (r->use_bfd < 0)
+ r->use_bfd = this_srt->use_bfd;
}
CF_DECLS
@@ -58,48 +57,50 @@ stat_route0: ROUTE net_any {
add_tail(&STATIC_CFG->other_routes, &this_srt->n);
this_srt->net = $2;
this_srt_last_cmd = &(this_srt->cmds);
+ this_srt->mp_next = NULL;
+ last_srt = NULL;
}
;
stat_multipath1:
VIA ipa ipa_scope {
- last_srt_nh = this_srt_nh;
- this_srt_nh = cfg_allocz(sizeof(struct static_route));
- this_srt_nh->dest = RTD_NONE;
- this_srt_nh->via = $2;
- this_srt_nh->via_if = $3;
- this_srt_nh->if_name = (void *) this_srt; /* really */
- this_srt_nh->use_bfd = -1; /* undefined */
+ last_srt = last_srt ? last_srt->mp_next = cfg_allocz(sizeof(struct static_route)) : this_srt;
+
+ last_srt->dest = RTD_UNICAST;
+ last_srt->via = $2;
+ last_srt->via_if = $3;
+ last_srt->if_name = (void *) this_srt; /* really */
+ last_srt->use_bfd = -1; /* undefined */
+ last_srt->mp_next = NULL;
}
| stat_multipath1 WEIGHT expr {
- this_srt_nh->weight = $3 - 1;
+ last_srt->weight = $3 - 1;
if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256");
}
| stat_multipath1 BFD bool {
- this_srt_nh->use_bfd = $3; cf_check_bfd($3);
+ last_srt->use_bfd = $3; cf_check_bfd($3);
}
;
stat_multipath:
- stat_multipath1 { this_srt->mp_next = this_srt_nh; }
- | stat_multipath stat_multipath1 { last_srt_nh->mp_next = this_srt_nh; }
+ stat_multipath1
+ | stat_multipath stat_multipath1
;
stat_route:
stat_route0 VIA ipa ipa_scope {
- this_srt->dest = RTD_ROUTER;
+ this_srt->dest = RTD_UNICAST;
this_srt->via = $3;
this_srt->via_if = $4;
}
| stat_route0 VIA TEXT {
- this_srt->dest = RTD_DEVICE;
+ this_srt->dest = RTD_UNICAST;
+ this_srt->via = IPA_NONE;
this_srt->if_name = $3;
rem_node(&this_srt->n);
add_tail(&STATIC_CFG->iface_routes, &this_srt->n);
}
- | stat_route0 MULTIPATH stat_multipath {
- this_srt->dest = RTD_MULTIPATH;
- }
+ | stat_route0 MULTIPATH stat_multipath
| stat_route0 RECURSIVE ipa {
this_srt->dest = RTDX_RECURSIVE;
this_srt->via = $3;
diff --git a/proto/static/static.c b/proto/static/static.c
index fb547537..f3cfec01 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -58,49 +58,53 @@ p_igp_table(struct proto *p)
}
static void
-static_install(struct proto *p, struct static_route *r, struct iface *ifa)
+static_install(struct proto *p, struct static_route *r)
{
rta a;
rte *e;
- if (r->installed > 0)
+ if (!(r->state & STS_WANT) && r->dest != RTD_UNICAST)
return;
DBG("Installing static route %N, rtd=%d\n", r->net, r->dest);
bzero(&a, sizeof(a));
a.src = p->main_source;
- a.source = (r->dest == RTD_DEVICE) ? RTS_STATIC_DEVICE : RTS_STATIC;
+ a.source = ((r->dest == RTD_UNICAST) && ipa_zero(r->via)) ? RTS_STATIC_DEVICE : RTS_STATIC;
a.scope = SCOPE_UNIVERSE;
a.cast = RTC_UNICAST;
a.dest = r->dest;
- a.gw = r->via;
- a.iface = ifa;
-
- if (r->dest == RTD_MULTIPATH)
+ if (r->dest == RTD_UNICAST)
{
struct static_route *r2;
- struct mpnh *nhs = NULL;
+ int num = 0;
+
+ for (r2 = r; r2; r2 = r2->mp_next)
+ {
+ if ((r2->state & STS_INSTALLED) && !(r2->state & STS_FORCE))
+ continue;
- for (r2 = r->mp_next; r2; r2 = r2->mp_next)
- if (r2->installed)
+ if (r2->state & STS_WANT)
{
- struct mpnh *nh = alloca(sizeof(struct mpnh));
+ struct nexthop *nh = (a.nh.next) ? alloca(sizeof(struct nexthop)) : &(a.nh);
nh->gw = r2->via;
nh->iface = r2->neigh->iface;
nh->weight = r2->weight;
- mpnh_insert(&nhs, nh);
+ if (a.nh.next)
+ nexthop_insert(&(a.nh), nh);
+ r2->state |= STS_INSTALLED;
+ num++;
}
+ else
+ r2->state = 0;
+ }
- /* There is at least one nexthop */
- if (!nhs->next)
- {
- /* Fallback to unipath route for exactly one nexthop */
- a.dest = RTD_ROUTER;
- a.gw = nhs->gw;
- a.iface = nhs->iface;
- }
- else
- a.nexthops = nhs;
+ if (!num) // No nexthop to install
+ {
+ if (r->state & STS_INSTALLED_ANY)
+ rte_update(p, r->net, NULL);
+
+ return;
+ }
}
if (r->dest == RTDX_RECURSIVE)
@@ -115,7 +119,6 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa)
f_eval_rte(r->cmds, &e, static_lp);
rte_update(p, r->net, e);
- r->installed = 1;
if (r->cmds)
lp_flush(static_lp);
@@ -124,12 +127,13 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa)
static void
static_remove(struct proto *p, struct static_route *r)
{
- if (!r->installed)
+ if (!(r->state & STS_INSTALLED_ANY))
return;
DBG("Removing static route %N via %I\n", r->net, r->via);
rte_update(p, r->net, NULL);
- r->installed = 0;
+
+ r->state &= ~(STS_INSTALLED | STS_INSTALLED_ANY);
}
static void
@@ -180,38 +184,12 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
DBG("static_add(%N,%d)\n", r->net, r->dest);
switch (r->dest)
{
- case RTD_ROUTER:
- {
- struct neighbor *n = neigh_find2(p, &r->via, r->via_if, NEF_STICKY);
- if (n)
- {
- r->chain = n->data;
- n->data = r;
- r->neigh = n;
-
- static_update_bfd(p, r);
- 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);
- static_remove(p, r);
- }
- break;
- }
-
- case RTD_DEVICE:
- break;
-
- case RTD_MULTIPATH:
+ case RTD_UNICAST:
{
int count = 0;
struct static_route *r2;
- for (r2 = r->mp_next; r2; r2 = r2->mp_next)
+ for (r2 = r; r2; r2 = r2->mp_next)
{
struct neighbor *n = neigh_find2(p, &r2->via, r2->via_if, NEF_STICKY);
if (n)
@@ -221,20 +199,19 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
r2->neigh = n;
static_update_bfd(p, r2);
- r2->installed = static_decide(cf, r2);
- count += r2->installed;
+ r2->state = static_decide(cf,r2) ? STS_WANT : 0;
+ count++;
}
else
{
log(L_ERR "Static route destination %I is invalid. Ignoring.", r2->via);
- r2->installed = 0;
+ r2->state = 0;
}
}
if (count)
static_install(p, r, NULL);
- else
- static_remove(p, r);
+
break;
}
@@ -247,20 +224,13 @@ static void
static_rte_cleanup(struct proto *p UNUSED, struct static_route *r)
{
struct static_route *r2;
-
- if (r->bfd_req)
- {
- rfree(r->bfd_req);
- r->bfd_req = NULL;
- }
-
- if (r->dest == RTD_MULTIPATH)
- for (r2 = r->mp_next; r2; r2 = r2->mp_next)
- if (r2->bfd_req)
- {
- rfree(r2->bfd_req);
- r2->bfd_req = NULL;
- }
+
+ for (r2 = r; r2; r2 = r2->mp_next)
+ if (r2->bfd_req)
+ {
+ rfree(r2->bfd_req);
+ r2->bfd_req = NULL;
+ }
}
static int
@@ -293,11 +263,11 @@ static_shutdown(struct proto *p)
/* Just reset the flag, the routes will be flushed by the nest */
WALK_LIST(r, cf->iface_routes)
- r->installed = 0;
+ r->state = 0;
WALK_LIST(r, cf->other_routes)
{
static_rte_cleanup(p, r);
- r->installed = 0;
+ r->state = 0;
}
/* Handle failure during channel reconfigure */
@@ -306,9 +276,9 @@ static_shutdown(struct proto *p)
if (cf)
{
WALK_LIST(r, cf->iface_routes)
- r->installed = 0;
+ r->state = 0;
WALK_LIST(r, cf->other_routes)
- r->installed = 0;
+ r->state = 0;
}
return PS_DOWN;
@@ -326,40 +296,13 @@ static_cleanup(struct proto *p)
static void
static_update_rte(struct proto *p, struct static_route *r)
{
- switch (r->dest)
- {
- case RTD_ROUTER:
- if (static_decide((struct static_config *) p->cf, r))
- static_install(p, r, r->neigh->iface);
- else
- static_remove(p, r);
- break;
-
- case RTD_NONE: /* a part of multipath route */
- {
- int decision = static_decide((struct static_config *) p->cf, r);
- if (decision == r->installed)
- break; /* no change */
- r->installed = decision;
-
- struct static_route *r1, *r2;
- int count = 0;
- r1 = (void *) r->if_name; /* really */
- for (r2 = r1->mp_next; r2; r2 = r2->mp_next)
- count += r2->installed;
-
- if (count)
- {
- /* Set of nexthops changed - force reinstall */
- r1->installed = 0;
- static_install(p, r1, NULL);
- }
- else
- static_remove(p, r1);
+ if (r->dest != RTD_UNICAST)
+ return;
- break;
- }
- }
+ if (static_decide((struct static_config *) p->cf, r))
+ static_install(p, r, r->neigh->iface);
+ else
+ static_remove(p, r);
}
static void
@@ -391,18 +334,13 @@ static void
static_dump_rt(struct static_route *r)
{
debug("%-1N: ", r->net);
- switch (r->dest)
- {
- case RTD_ROUTER:
- debug("via %I\n", r->via);
- break;
- case RTD_DEVICE:
+ if (r->dest == RTD_UNICAST)
+ if (ipa_zero(r->via))
debug("dev %s\n", r->if_name);
- break;
- default:
- debug("rtd %d\n", r->dest);
- break;
- }
+ else
+ debug("via %I\n", r->via);
+ else
+ debug("rtd %d\n", r->dest);
}
static void
@@ -496,22 +434,27 @@ static_same_dest(struct static_route *x, struct static_route *y)
switch (x->dest)
{
- case RTD_ROUTER:
- return ipa_equal(x->via, y->via) && (x->via_if == y->via_if);
-
- case RTD_DEVICE:
- return !strcmp(x->if_name, y->if_name);
-
- case RTD_MULTIPATH:
- for (x = x->mp_next, y = y->mp_next;
- x && y;
- x = x->mp_next, y = y->mp_next)
- if (!ipa_equal(x->via, y->via) ||
- (x->via_if != y->via_if) ||
- (x->use_bfd != y->use_bfd) ||
- (x->weight != y->weight))
- return 0;
- return !x && !y;
+ case RTD_UNICAST:
+ {
+ struct static_route *xc, *yc;
+ for (xc = x, yc = y; xc && yc; xc = xc->mp_next, yc = yc->mp_next)
+ {
+ if (ipa_nonzero(xc->via) && ipa_nonzero(yc->via))
+ {
+ if (!ipa_equal(x->via, y->via) ||
+ (x->via_if != y->via_if) ||
+ (x->use_bfd != y->use_bfd) ||
+ (x->weight != y->weight))
+ return 0;
+ }
+ else
+ if (strcmp(x->if_name, y->if_name) ||
+ (x->use_bfd != y->use_bfd) ||
+ (x->weight != y->weight))
+ return 0;
+ }
+ return 1;
+ }
case RTDX_RECURSIVE:
return ipa_equal(x->via, y->via);
@@ -556,10 +499,10 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n)
found:
/* If destination is different, force reinstall */
- if ((r->installed > 0) && !static_same_rte(r, t))
- t->installed = -1;
+ if (r->state && !static_same_rte(r, t))
+ t->state = r->state | STS_WANT | STS_FORCE;
else
- t->installed = r->installed;
+ t->state = r->state;
}
static inline rtable *
@@ -606,37 +549,24 @@ static_reconfigure(struct proto *p, struct proto_config *CF)
static void
static_copy_routes(list *dlst, list *slst)
{
- struct static_route *dr, *sr;
+ struct static_route *sr;
init_list(dlst);
WALK_LIST(sr, *slst)
{
- /* copy one route */
- dr = cfg_alloc(sizeof(struct static_route));
- memcpy(dr, sr, sizeof(struct static_route));
-
- /* This fn is supposed to be called on fresh src routes, which have 'live'
- fields (like .chain, .neigh or .installed) zero, so no need to zero them */
-
- /* We need to copy multipath chain, because there are backptrs in 'if_name' */
- if (dr->dest == RTD_MULTIPATH)
- {
- struct static_route *md, *ms, **mp_last;
-
- mp_last = &(dr->mp_next);
- for (ms = sr->mp_next; ms; ms = ms->mp_next)
- {
- md = cfg_alloc(sizeof(struct static_route));
- memcpy(md, ms, sizeof(struct static_route));
- md->if_name = (void *) dr; /* really */
-
- *mp_last = md;
- mp_last = &(md->mp_next);
- }
- *mp_last = NULL;
- }
+ struct static_route *srr, *drr = NULL;
+ for (srr = sr; srr; srr = srr->mp_next)
+ {
+ /* copy one route */
+ struct static_route *dr = cfg_alloc(sizeof(struct static_route));
+ if (drr)
+ drr->mp_next = dr;
+ else
+ add_tail(dlst, &(dr->n));
- add_tail(dlst, (node *) dr);
+ memcpy(dr, sr, sizeof(struct static_route));
+ drr = dr;
+ }
}
}
@@ -668,30 +598,39 @@ struct protocol proto_static = {
.copy_config = static_copy_config
};
-static void
-static_show_rt(struct static_route *r)
+static byte *
+static_format_via(struct static_route *r)
{
- byte via[IPA_MAX_TEXT_LENGTH + 25];
+ static byte via[IPA_MAX_TEXT_LENGTH + 25];
switch (r->dest)
{
- case RTD_ROUTER: bsprintf(via, "via %I%J", r->via, r->via_if); break;
- case RTD_DEVICE: bsprintf(via, "dev %s", r->if_name); break;
+ case RTD_UNICAST: if (ipa_zero(r->via)) bsprintf(via, "dev %s", r->if_name);
+ else bsprintf(via, "via %I%J", r->via, r->via_if);
+ break;
case RTD_BLACKHOLE: bsprintf(via, "blackhole"); break;
case RTD_UNREACHABLE: bsprintf(via, "unreachable"); break;
case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
- case RTD_MULTIPATH: bsprintf(via, "multipath"); break;
case RTDX_RECURSIVE: bsprintf(via, "recursive %I", r->via); break;
default: bsprintf(via, "???");
}
- cli_msg(-1009, "%N %s%s%s", r->net, via,
- r->bfd_req ? " (bfd)" : "", r->installed ? "" : " (dormant)");
+ return via;
+}
- struct static_route *r2;
- if (r->dest == RTD_MULTIPATH)
- for (r2 = r->mp_next; r2; r2 = r2->mp_next)
- cli_msg(-1009, "\tvia %I%J weight %d%s%s", r2->via, r2->via_if, r2->weight + 1,
- r2->bfd_req ? " (bfd)" : "", r2->installed ? "" : " (dormant)");
+static void
+static_show_rt(struct static_route *r)
+{
+ if (r->mp_next)
+ {
+ cli_msg(-1009, "%N", r->net);
+ struct static_route *r2;
+ for (r2 = r; r2; r2 = r2->mp_next)
+ cli_msg(-1009, "\t%s weight %d%s%s", static_format_via(r2), r2->weight + 1,
+ r2->bfd_req ? " (bfd)" : "", (r2->state & STS_INSTALLED) ? "" : " (dormant)");
+ }
+ else
+ cli_msg(-1009, "%N %s%s%s", r->net, static_format_via(r),
+ r->bfd_req ? " (bfd)" : "", (r->state & STS_INSTALLED) ? "" : " (dormant)");
}
void
diff --git a/proto/static/static.h b/proto/static/static.h
index 51486e83..418b3076 100644
--- a/proto/static/static.h
+++ b/proto/static/static.h
@@ -32,14 +32,19 @@ struct static_route {
struct iface *via_if; /* Destination iface, for link-local vias */
struct neighbor *neigh;
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 multipath routes */
struct f_inst *cmds; /* List of commands for setting attributes */
- int installed; /* Installed in rt table, -1 for reinstall */
+ u32 state; /* Current state: STS_* */
int use_bfd; /* Configured to use BFD */
int weight; /* Multipath next hop weight */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
};
+#define STS_INSTALLED 0x1
+#define STS_INSTALLED_ANY 0x2
+#define STS_WANT 0x4
+#define STS_FORCE 0x8
+
/* Dummy nodes (parts of multipath route) abuses masklen field for weight
and if_name field for a ptr to the master (RTD_MULTIPATH) node. */