diff options
Diffstat (limited to 'proto')
-rw-r--r-- | proto/bgp/attrs.c | 3 | ||||
-rw-r--r-- | proto/bgp/packets.c | 18 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 2 | ||||
-rw-r--r-- | proto/ospf/rt.c | 64 | ||||
-rw-r--r-- | proto/ospf/rt.h | 2 | ||||
-rw-r--r-- | proto/ospf/topology.c | 4 | ||||
-rw-r--r-- | proto/ospf/topology.h | 2 | ||||
-rw-r--r-- | proto/pipe/pipe.c | 15 | ||||
-rw-r--r-- | proto/rip/rip.c | 31 | ||||
-rw-r--r-- | proto/rpki/rpki.c | 3 | ||||
-rw-r--r-- | proto/static/config.Y | 116 | ||||
-rw-r--r-- | proto/static/static.c | 455 | ||||
-rw-r--r-- | proto/static/static.h | 20 |
13 files changed, 375 insertions, 360 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 73318c6a..f2a8e8b5 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1491,8 +1491,7 @@ bgp_get_neighbor(rte *r) static inline int rte_resolvable(rte *rt) { - int rd = rt->attrs->dest; - return (rd == RTD_ROUTER) || (rd == RTD_DEVICE) || (rd == RTD_MULTIPATH); + return rt->attrs->dest == RTD_UNICAST; } int diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 385d5a36..2106e0d1 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -743,9 +743,8 @@ 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 = (struct nexthop){ .gw = nbr->addr, .iface = nbr->iface }; a->hostentry = NULL; a->igp_metric = 0; } @@ -792,8 +791,8 @@ bgp_use_gateway(struct bgp_export_state *s) if (s->channel->cf->next_hop_self) return 0; - /* We need valid global gateway */ - if ((ra->dest != RTD_ROUTER) || ipa_zero(ra->gw) || ipa_is_link_local(ra->gw)) + /* We need one valid global gateway */ + 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 */ @@ -801,7 +800,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 @@ -811,7 +810,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 @@ -1706,13 +1705,10 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis if (ea) { - a = alloca(sizeof(struct rta)); - memset(a, 0, sizeof(struct rta)); + a = allocz(sizeof(struct rta)); a->source = RTS_BGP; a->scope = SCOPE_UNIVERSE; - a->cast = RTC_UNICAST; - a->dest = RTD_UNREACHABLE; a->from = s->proto->cf->remote_ip; a->eattrs = ea; 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 49167ceb..df9eb75b 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,20 +33,19 @@ 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_allocz(p->nhpool, sizeof(struct nexthop)); nh->gw = gw; nh->iface = iface; - nh->next = NULL; nh->weight = weight; return nh; } /* 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 +55,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 +72,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 +86,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 +282,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 +298,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; } @@ -1674,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; @@ -1813,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)", @@ -1851,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; } @@ -1907,8 +1906,7 @@ 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); + !nexthop_same(&(nr->nh), &(or->nh)); } static void @@ -1932,7 +1930,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)) { @@ -1955,26 +1953,10 @@ again1: .src = p->p.main_source, .source = nf->n.type, .scope = SCOPE_UNIVERSE, - .cast = RTC_UNICAST + .dest = RTD_UNICAST, + .nh = *(nf->n.nhs), }; - 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; - } - if (reload || ort_changed(nf, &a0)) { rta *a = rta_lookup(&a0); diff --git a/proto/ospf/rt.h b/proto/ospf/rt.h index 118d09b7..589d2bc5 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/pipe/pipe.c b/proto/pipe/pipe.c index 8924c200..310f3c01 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -51,7 +51,7 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o struct rte_src *src; rte *e; - rta a; + rta *a; if (!new && !old) return; @@ -65,12 +65,13 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o if (new) { - memcpy(&a, new->attrs, sizeof(rta)); + a = alloca(rta_size(new->attrs)); + memcpy(a, new->attrs, rta_size(new->attrs)); - a.aflags = 0; - a.eattrs = attrs; - a.hostentry = NULL; - e = rte_get_temp(&a); + a->aflags = 0; + a->eattrs = attrs; + a->hostentry = NULL; + e = rte_get_temp(a); e->pflags = 0; /* Copy protocol specific embedded attributes. */ @@ -78,7 +79,7 @@ pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *o e->pref = new->pref; e->pflags = new->pflags; - src = a.src; + src = a->src; } else { diff --git a/proto/rip/rip.c b/proto/rip/rip.c index d87a078c..157093aa 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -147,21 +147,16 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) .src = p->p.main_source, .source = RTS_RIP, .scope = SCOPE_UNIVERSE, - .cast = RTC_UNICAST + .dest = RTD_UNICAST, }; u8 rt_metric = rt->metric; u16 rt_tag = rt->tag; - struct rip_rte *rt2 = rt->next; - /* Find second valid rte */ - while (rt2 && !rip_valid_rte(rt2)) - rt2 = rt2->next; - - if (p->ecmp && rt2) + if (p->ecmp) { /* ECMP route */ - struct mpnh *nhs = NULL; + struct nexthop *nhs = NULL; int num = 0; for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next) @@ -169,33 +164,33 @@ 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 = allocz(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); + + nexthop_insert(&nhs, nh); num++; if (rt->tag != rt_tag) rt_tag = 0; } - a0.dest = RTD_MULTIPATH; - a0.nexthops = nhs; + a0.nh = *nhs; } else { /* Unipath route */ - a0.dest = RTD_ROUTER; - a0.gw = rt->next_hop; - a0.iface = rt->from->nbr->iface; a0.from = rt->from->nbr->addr; + a0.nh.gw = rt->next_hop; + a0.nh.iface = rt->from->nbr->iface; } 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 +340,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/rpki/rpki.c b/proto/rpki/rpki.c index 0d4b1fd3..5459d9c3 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -124,8 +124,7 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_ .src = p->p.main_source, .source = RTS_RPKI, .scope = SCOPE_UNIVERSE, - .cast = RTC_UNICAST, - .dest = RTD_BLACKHOLE, + .dest = RTD_NONE, }; rta *a = rta_lookup(&a0); diff --git a/proto/static/config.Y b/proto/static/config.Y index 86359f0b..16c276ce 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -13,25 +13,41 @@ 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, *this_snh; static struct f_inst **this_srt_last_cmd; -static void -static_route_finish(void) +static struct static_route * +static_nexthop_new(void) { - struct static_route *r; + struct static_route *nh; + + if (!this_snh) + { + /* First next hop */ + nh = this_srt; + rem_node(&this_srt->n); + } + else + { + /* Additional next hop */ + nh = cfg_allocz(sizeof(struct static_route)); + nh->net = this_srt->net; + this_snh->mp_next = nh; + } + + nh->dest = RTD_UNICAST; + nh->mp_head = this_srt; + return nh; +}; - /* 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; -} +static void +static_route_finish(void) +{ } CF_DECLS CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK) -CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD) +CF_KEYWORDS(WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS) CF_GRAMMAR @@ -53,58 +69,59 @@ static_proto: | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); } ; +stat_nexthop: + VIA ipa ipa_scope { + this_snh = static_nexthop_new(); + this_snh->via = $2; + this_snh->iface = $3; + add_tail(&STATIC_CFG->neigh_routes, &this_snh->n); + } + | VIA TEXT { + this_snh = static_nexthop_new(); + this_snh->via = IPA_NONE; + this_snh->if_name = $2; + add_tail(&STATIC_CFG->iface_routes, &this_snh->n); + } + | stat_nexthop MPLS label_stack { + this_snh->label_count = $3[0]; + this_snh->label_stack = &($3[1]); + } + | stat_nexthop WEIGHT expr { + this_snh->weight = $3 - 1; + if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); + } + | stat_nexthop BFD bool { + this_snh->use_bfd = $3; cf_check_bfd($3); + } +; + +stat_nexthops: + stat_nexthop + | stat_nexthops stat_nexthop +; + stat_route0: ROUTE net_any { this_srt = cfg_allocz(sizeof(struct static_route)); 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; + this_snh = 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 */ - } - | stat_multipath1 WEIGHT expr { - this_srt_nh->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); - } - ; - -stat_multipath: - stat_multipath1 { this_srt->mp_next = this_srt_nh; } - | stat_multipath stat_multipath1 { last_srt_nh->mp_next = this_srt_nh; } - ; - stat_route: - stat_route0 VIA ipa ipa_scope { - this_srt->dest = RTD_ROUTER; + stat_route0 stat_nexthops + | stat_route0 RECURSIVE ipa { + this_srt->dest = RTDX_RECURSIVE; this_srt->via = $3; - this_srt->via_if = $4; - } - | stat_route0 VIA TEXT { - this_srt->dest = RTD_DEVICE; - 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 RECURSIVE ipa { + | stat_route0 RECURSIVE ipa MPLS label_stack { this_srt->dest = RTDX_RECURSIVE; this_srt->via = $3; + this_srt->label_count = $5[0]; + this_srt->label_stack = &($5[1]); } - | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; } | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } | stat_route0 BLACKHOLE { this_srt->dest = RTD_BLACKHOLE; } @@ -114,7 +131,6 @@ stat_route: stat_route_item: cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); } - | BFD bool ';' { this_srt->use_bfd = $2; cf_check_bfd($2); } ; stat_route_opts: diff --git a/proto/static/static.c b/proto/static/static.c index fb547537..e5251bf6 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -58,81 +58,88 @@ 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; + rta *ap = allocz(RTA_MAX_SIZE); rte *e; - if (r->installed > 0) - return; + if (!(r->state & STS_WANT) && (r->state & (STS_INSTALLED | STS_FORCE)) && r->dest != RTD_UNICAST) + goto drop; 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.scope = SCOPE_UNIVERSE; - a.cast = RTC_UNICAST; - a.dest = r->dest; - a.gw = r->via; - a.iface = ifa; - - if (r->dest == RTD_MULTIPATH) + ap->src = p->main_source; + ap->source = RTS_STATIC; + ap->scope = SCOPE_UNIVERSE; + ap->dest = r->dest; + + if (r->dest == RTD_UNICAST) { + struct nexthop *nhs = NULL; struct static_route *r2; - struct mpnh *nhs = NULL; + int update = 0; - for (r2 = r->mp_next; r2; r2 = r2->mp_next) - if (r2->installed) - { - struct mpnh *nh = alloca(sizeof(struct mpnh)); - nh->gw = r2->via; - nh->iface = r2->neigh->iface; - nh->weight = r2->weight; - mpnh_insert(&nhs, nh); - } + r = r->mp_head; + for (r2 = r; r2; r2 = r2->mp_next) + { + if ((r2->state & STS_FORCE) || + (!!(r2->state & STS_INSTALLED) != !!(r2->state & STS_WANT))) + update++; - /* There is at least one nexthop */ - if (!nhs->next) + if (r2->state & STS_WANT) { - /* Fallback to unipath route for exactly one nexthop */ - a.dest = RTD_ROUTER; - a.gw = nhs->gw; - a.iface = nhs->iface; + struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE); + + nh->gw = r2->via; + nh->iface = r2->neigh ? r2->neigh->iface : r2->iface; + nh->weight = r2->weight; + nh->labels = r2->label_count; + memcpy(nh->label, r2->label_stack, r2->label_count * sizeof(u32)); + + r2->state |= STS_INSTALLED; + nexthop_insert(&nhs, nh); } - else - a.nexthops = nhs; + else + r2->state = 0; + } + + if (!update) // Nothing changed + return; + + if (!nhs) // No nexthop to install + { +drop: + rte_update(p, r->net, NULL); + return; + } + + ap->dest = RTD_UNICAST; + nexthop_link(ap, nhs); } + else + r->state |= STS_INSTALLED; if (r->dest == RTDX_RECURSIVE) - rta_set_recursive_next_hop(p->main_channel->table, &a, p_igp_table(p), r->via, IPA_NONE); + { + ap->nh.labels_append = ap->nh.labels = r->label_count; + memcpy(ap->nh.label, r->label_stack, r->label_count * sizeof(u32)); + rta_set_recursive_next_hop(p->main_channel->table, ap, p_igp_table(p), r->via, IPA_NONE); + } /* We skip rta_lookup() here */ - e = rte_get_temp(&a); + e = rte_get_temp(ap); e->pflags = 0; if (r->cmds) f_eval_rte(r->cmds, &e, static_lp); rte_update(p, r->net, e); - r->installed = 1; if (r->cmds) lp_flush(static_lp); } static void -static_remove(struct proto *p, struct static_route *r) -{ - if (!r->installed) - return; - - DBG("Removing static route %N via %I\n", r->net, r->via); - rte_update(p, r->net, NULL); - r->installed = 0; -} - -static void static_bfd_notify(struct bfd_request *req); static void @@ -161,6 +168,8 @@ static_decide(struct static_config *cf, struct static_route *r) /* r->dest != RTD_MULTIPATH, but may be RTD_NONE (part of multipath route) the route also have to be valid (r->neigh != NULL) */ + r->state &= ~STS_WANT; + if (r->neigh->scope < 0) return 0; @@ -170,6 +179,7 @@ static_decide(struct static_config *cf, struct static_route *r) if (r->bfd_req && r->bfd_req->state != BFD_STATE_UP) return 0; + r->state |= STS_WANT; return 1; } @@ -177,43 +187,23 @@ static_decide(struct static_config *cf, struct static_route *r) static void static_add(struct proto *p, struct static_config *cf, struct static_route *r) { + if (r->mp_head && r != r->mp_head) + return; + 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 (ipa_zero(r2->via)) // No struct neighbor for device routes + continue; + + struct neighbor *n = neigh_find2(p, &r2->via, r2->iface, NEF_STICKY); if (n) { r2->chain = n->data; @@ -221,46 +211,41 @@ 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; + static_decide(cf,r2); + 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); + static_install(p, r); + break; } default: - static_install(p, r, NULL); + static_install(p, r); } } 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->mp_head && (r != r->mp_head)) + return; - 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; - } + struct static_route *r2; + + for (r2 = r; r2; r2 = r2->mp_next) + if (r2->bfd_req) + { + rfree(r2->bfd_req); + r2->bfd_req = NULL; + } } static int @@ -280,8 +265,15 @@ static_start(struct proto *p) /* We have to go UP before routes could be installed */ proto_notify_state(p, PS_UP); - WALK_LIST(r, cf->other_routes) + WALK_LIST(r, cf->neigh_routes) + static_add(p, cf, r); + + WALK_LIST(r, cf->iface_routes) static_add(p, cf, r); + + WALK_LIST(r, cf->other_routes) + static_install(p, r); + return PS_UP; } @@ -292,12 +284,17 @@ static_shutdown(struct proto *p) struct static_route *r; /* Just reset the flag, the routes will be flushed by the nest */ - WALK_LIST(r, cf->iface_routes) - r->installed = 0; WALK_LIST(r, cf->other_routes) { static_rte_cleanup(p, r); - r->installed = 0; + r->state = 0; + } + WALK_LIST(r, cf->iface_routes) + r->state = 0; + WALK_LIST(r, cf->neigh_routes) + { + static_rte_cleanup(p, r); + r->state = 0; } /* Handle failure during channel reconfigure */ @@ -305,10 +302,12 @@ static_shutdown(struct proto *p) cf = (void *) p->cf_new; if (cf) { - WALK_LIST(r, cf->iface_routes) - r->installed = 0; WALK_LIST(r, cf->other_routes) - r->installed = 0; + r->state = 0; + WALK_LIST(r, cf->iface_routes) + r->state = 0; + WALK_LIST(r, cf->neigh_routes) + r->state = 0; } return PS_DOWN; @@ -326,40 +325,11 @@ 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; - } - } + static_decide((struct static_config *) p->cf, r); + static_install(p, r); } static void @@ -391,18 +361,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 @@ -411,12 +376,15 @@ static_dump(struct proto *p) struct static_config *c = (void *) p->cf; struct static_route *r; - debug("Independent static routes:\n"); - WALK_LIST(r, c->other_routes) + debug("Independent static nexthops:\n"); + WALK_LIST(r, c->neigh_routes) static_dump_rt(r); - debug("Device static routes:\n"); + debug("Device static nexthops:\n"); WALK_LIST(r, c->iface_routes) static_dump_rt(r); + debug("Other static routes:\n"); + WALK_LIST(r, c->other_routes) + static_dump_rt(r); } static void @@ -429,13 +397,21 @@ static_if_notify(struct proto *p, unsigned flags, struct iface *i) { WALK_LIST(r, c->iface_routes) if (!strcmp(r->if_name, i->name)) - static_install(p, r, i); + { + r->state |= STS_WANT; + r->iface = i; + static_install(p, r); + } } else if (flags & IF_CHANGE_DOWN) { WALK_LIST(r, c->iface_routes) if (!strcmp(r->if_name, i->name)) - static_remove(p, r); + { + r->state &= ~STS_WANT; + r->iface = NULL; + static_install(p, r); + } } } @@ -448,6 +424,7 @@ static_rte_mergable(rte *pri UNUSED, rte *sec UNUSED) void static_init_config(struct static_config *c) { + init_list(&c->neigh_routes); init_list(&c->iface_routes); init_list(&c->other_routes); } @@ -462,8 +439,12 @@ static_postconfig(struct proto_config *CF) cf_error("Channel not specified"); + WALK_LIST(r, cf->neigh_routes) + if (r->net && (r->net->type != CF->net_type)) + cf_error("Route %N incompatible with channel type", r->net); + WALK_LIST(r, cf->iface_routes) - if (r->net->type != CF->net_type) + if (r->net && (r->net->type != CF->net_type)) cf_error("Route %N incompatible with channel type", r->net); WALK_LIST(r, cf->other_routes) @@ -496,22 +477,33 @@ 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->iface != y->iface) || + (x->use_bfd != y->use_bfd) || + (x->weight != y->weight) || + (x->label_count != y->label_count)) + return 0; + for (int i=0; i<x->label_count; i++) + if (x->label_stack[i] != y->label_stack[i]) + return 0; + } + else + if ((!x->if_name) || (!y->if_name) || + 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); @@ -533,6 +525,9 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n) { struct static_route *t; + if (r->mp_head && (r->mp_head != r)) + return; + /* * For given old route *r we find whether a route to the same * network is also in the new route list. In that case, we keep the @@ -543,23 +538,28 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n) if (r->neigh) r->neigh->data = NULL; + WALK_LIST(t, n->neigh_routes) + if ((!t->mp_head || (t->mp_head == t)) && net_equal(r->net, t->net)) + goto found; + WALK_LIST(t, n->iface_routes) - if (net_equal(r->net, t->net)) + if ((!t->mp_head || (t->mp_head == t)) && net_equal(r->net, t->net)) goto found; WALK_LIST(t, n->other_routes) if (net_equal(r->net, t->net)) goto found; - static_remove(p, r); + r->state &= ~STS_WANT; + static_install(p, r); return; found: + t->state = r->state; + /* If destination is different, force reinstall */ - if ((r->installed > 0) && !static_same_rte(r, t)) - t->installed = -1; - else - t->installed = r->installed; + if (!static_same_rte(r, t)) + t->state |= STS_FORCE; } static inline rtable * @@ -582,20 +582,34 @@ static_reconfigure(struct proto *p, struct proto_config *CF) return 0; /* Delete all obsolete routes and reset neighbor entries */ + WALK_LIST(r, o->other_routes) + static_match(p, r, n); WALK_LIST(r, o->iface_routes) static_match(p, r, n); - WALK_LIST(r, o->other_routes) + WALK_LIST(r, o->neigh_routes) static_match(p, r, n); /* Now add all new routes, those not changed will be ignored by static_install() */ + WALK_LIST(r, n->neigh_routes) + static_add(p, n, r); + WALK_LIST(r, o->neigh_routes) + static_rte_cleanup(p, r); + WALK_LIST(r, n->iface_routes) { struct iface *ifa; if ((ifa = if_find_by_name(r->if_name)) && (ifa->flags & IF_UP)) - static_install(p, r, ifa); + { + r->iface = ifa; + static_install(p, r); + } } + WALK_LIST(r, n->other_routes) - static_add(p, n, r); + { + r->state |= STS_WANT; + static_install(p, r); + } WALK_LIST(r, o->other_routes) static_rte_cleanup(p, r); @@ -606,37 +620,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->mp_head; 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; + } } } @@ -647,6 +648,7 @@ static_copy_config(struct proto_config *dest, struct proto_config *src) struct static_config *s = (struct static_config *) src; /* Copy route lists */ + static_copy_routes(&d->neigh_routes, &s->neigh_routes); static_copy_routes(&d->iface_routes, &s->iface_routes); static_copy_routes(&d->other_routes, &s->other_routes); } @@ -668,30 +670,45 @@ 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->iface); + 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_head && (r != r->mp_head)) + return; + 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)"); + if (r2->mp_next == r) + break; + } + } + else + cli_msg(-1009, "%N %s%s%s", r->net, static_format_via(r), + r->bfd_req ? " (bfd)" : "", (r->state & STS_INSTALLED) ? "" : " (dormant)"); } void @@ -700,9 +717,11 @@ static_show(struct proto *P) struct static_config *c = (void *) P->cf; struct static_route *r; - WALK_LIST(r, c->other_routes) + WALK_LIST(r, c->neigh_routes) static_show_rt(r); WALK_LIST(r, c->iface_routes) static_show_rt(r); + WALK_LIST(r, c->other_routes) + static_show_rt(r); cli_msg(0, ""); } diff --git a/proto/static/static.h b/proto/static/static.h index 51486e83..aeb9660a 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -15,7 +15,8 @@ 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 neigh_routes; /* Routes to search on neighbor events */ + list other_routes; /* Non-nexthop routes */ int check_link; /* Whether iface link state is used */ struct rtable_config *igp_table; /* Table used for recursive next hop lookups */ }; @@ -29,17 +30,24 @@ struct static_route { net_addr *net; /* Network we route */ int dest; /* Destination type (RTD_*) */ ip_addr via; /* Destination router */ - struct iface *via_if; /* Destination iface, for link-local vias */ + struct iface *iface; /* Destination iface, for link-local vias or device routes */ struct neighbor *neigh; - byte *if_name; /* Name for RTD_DEVICE routes */ - struct static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */ + byte *if_name; /* Name for device routes */ + struct static_route *mp_next; /* Nexthops for multipath routes */ + struct static_route *mp_head; /* First nexthop of this route */ struct f_inst *cmds; /* List of commands for setting attributes */ - int installed; /* Installed in rt table, -1 for reinstall */ - int use_bfd; /* Configured to use BFD */ + u32 state; /* Current state: STS_* */ int weight; /* Multipath next hop weight */ + byte use_bfd; /* Configured to use BFD */ + byte label_count; /* Number of labels in stack */ struct bfd_request *bfd_req; /* BFD request, if BFD is used */ + u32 *label_stack; /* Label stack if label_count > 0 */ }; +#define STS_INSTALLED 0x1 +#define STS_WANT 0x2 +#define STS_FORCE 0x4 + /* Dummy nodes (parts of multipath route) abuses masklen field for weight and if_name field for a ptr to the master (RTD_MULTIPATH) node. */ |