From: Ondrej Zajicek Date: Sat, 23 Nov 2013 10:50:34 +0000 (+0100) Subject: Merge branch 'master' into add-path X-Git-Tag: v1.4.1~23^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=736e143fa50607fcd88132291e96089b899af979;p=thirdparty%2Fbird.git Merge branch 'master' into add-path Conflicts: filter/filter.c nest/proto.c nest/rt-table.c proto/bgp/bgp.h proto/bgp/config.Y --- 736e143fa50607fcd88132291e96089b899af979 diff --cc filter/filter.c index 7c883fffe,e0451aa15..ed8efd54e --- a/filter/filter.c +++ b/filter/filter.c @@@ -821,26 -792,26 +792,26 @@@ interpret(struct f_inst *what break; case 'a': /* rta access */ { + ACCESS_RTE; struct rta *rta = (*f_rte)->attrs; res.type = what->aux; - switch(res.type) { - case T_IP: - res.val.px.ip = * (ip_addr *) ((char *) rta + what->a2.i); - break; - case T_ENUM: - res.val.i = * ((char *) rta + what->a2.i); - break; - case T_STRING: /* Warning: this is a special case for proto attribute */ - res.val.s = rta->src->proto->name; - break; - case T_PREFIX: /* Warning: this works only for prefix of network */ - { - res.val.px.ip = (*f_rte)->net->n.prefix; - res.val.px.len = (*f_rte)->net->n.pxlen; - break; - } + + switch (what->a2.i) + { + case SA_FROM: res.val.px.ip = rta->from; break; + case SA_GW: res.val.px.ip = rta->gw; break; + case SA_NET: res.val.px.ip = (*f_rte)->net->n.prefix; + res.val.px.len = (*f_rte)->net->n.pxlen; break; - case SA_PROTO: res.val.s = rta->proto->name; break; ++ case SA_PROTO: res.val.s = rta->src->proto->name; break; + case SA_SOURCE: res.val.i = rta->source; break; + case SA_SCOPE: res.val.i = rta->scope; break; + case SA_CAST: res.val.i = rta->cast; break; + case SA_DEST: res.val.i = rta->dest; break; + case SA_IFNAME: res.val.s = rta->iface ? rta->iface->name : ""; break; + case SA_IFINDEX: res.val.i = rta->iface ? rta->iface->index : 0; break; + default: - bug( "Invalid type for rta access (%x)", res.type ); + bug("Invalid static attribute access (%x)", res.type); } } break; @@@ -851,13 -824,29 +824,29 @@@ f_rta_cow(); { struct rta *rta = (*f_rte)->attrs; - switch (what->aux) { - case T_IP: - * (ip_addr *) ((char *) rta + what->a2.i) = v1.val.px.ip; + switch (what->a2.i) + { + case SA_FROM: + rta->from = v1.val.px.ip; break; - case T_ENUM_SCOPE: + case SA_GW: + { + ip_addr ip = v1.val.px.ip; - neighbor *n = neigh_find(rta->proto, &ip, 0); ++ neighbor *n = neigh_find(rta->src->proto, &ip, 0); + if (!n || (n->scope == SCOPE_HOST)) + runtime( "Invalid gw address" ); + + rta->dest = RTD_ROUTER; + rta->gw = ip; + rta->iface = n->iface; + rta->nexthops = NULL; + rta->hostentry = NULL; + } + break; + + case SA_SCOPE: rta->scope = v1.val.i; break; diff --cc nest/proto.c index 399c02e3c,75ba10dd9..019b846ed --- a/nest/proto.c +++ b/nest/proto.c @@@ -798,9 -832,11 +836,12 @@@ proto_schedule_feed(struct proto *p, in p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats); p->main_ahook->in_filter = p->cf->in_filter; p->main_ahook->out_filter = p->cf->out_filter; + p->main_ahook->rx_limit = p->cf->rx_limit; p->main_ahook->in_limit = p->cf->in_limit; p->main_ahook->out_limit = p->cf->out_limit; + p->main_ahook->in_keep_filtered = p->cf->in_keep_filtered; + + proto_reset_limit(p->main_ahook->rx_limit); proto_reset_limit(p->main_ahook->in_limit); proto_reset_limit(p->main_ahook->out_limit); } diff --cc nest/route.h index 3b65a8550,e0b885515..f00f8b2b0 --- a/nest/route.h +++ b/nest/route.h @@@ -237,11 -251,12 +251,12 @@@ void rt_unlock_table(rtable *) void rt_setup(pool *, rtable *, char *, struct rtable_config *); static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_find(&tab->fib, &addr, len); } static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); } -rte *rte_find(net *net, struct proto *p); +rte *rte_find(net *net, struct rte_src *src); rte *rte_get_temp(struct rta *); -void rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src); -static inline void rte_update(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new) { rte_update2(p->main_ahook, net, new, src); } +void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src); +static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); } void rte_discard(rtable *tab, rte *old); + int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter); void rte_dump(rte *); void rte_free(rte *); rte *rte_do_cow(rte *); diff --cc nest/rt-attr.c index b2bb152f1,3f79ee594..0fb7c8204 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@@ -74,178 -61,6 +74,178 @@@ static u32 src_hash_order, src_hash_siz struct protocol *attr_class_to_protocol[EAP_MAX]; + +static void +rte_src_init(void) +{ + rte_src_slab = sl_new(rta_pool, sizeof(struct rte_src)); + + src_id_pos = 0; + src_id_size = SRC_ID_SIZE_DEF; + src_ids = mb_allocz(rta_pool, src_id_size * sizeof(u32)); + + /* ID 0 is reserved */ + src_ids[0] = 1; + src_id_used = 1; + + src_hash_count = 0; + src_hash_order = SRC_HASH_ORDER_DEF; + src_hash_size = 1 << src_hash_order; + src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *)); +} + +static inline int u32_cto(unsigned int x) { return ffs(~x) - 1; } + +static inline u32 +rte_src_alloc_id(void) +{ + int i, j; + for (i = src_id_pos; i < src_id_size; i++) + if (src_ids[i] != 0xffffffff) + goto found; + + /* If we are at least 7/8 full, expand */ + if (src_id_used > (src_id_size * 28)) + { + src_id_size *= 2; - src_ids = mb_realloc(rta_pool, src_ids, src_id_size * sizeof(u32)); ++ src_ids = mb_realloc(src_ids, src_id_size * sizeof(u32)); + bzero(src_ids + i, (src_id_size - i) * sizeof(u32)); + goto found; + } + + for (i = 0; i < src_id_pos; i++) + if (src_ids[i] != 0xffffffff) + goto found; + + ASSERT(0); + + found: + ASSERT(i < 0x8000000); + + src_id_pos = i; + j = u32_cto(src_ids[i]); + + src_ids[i] |= (1 << j); + src_id_used++; + return 32 * i + j; +} + +static inline void +rte_src_free_id(u32 id) +{ + int i = id / 32; + int j = id % 32; + + ASSERT((i < src_id_size) && (src_ids[i] & (1 << j))); + src_ids[i] &= ~(1 << j); + src_id_used--; +} + +static inline u32 rte_src_hash(struct proto *p, u32 x, u32 order) +{ return (x * 2902958171u) >> (32 - order); } + +static void +rte_src_rehash(int step) +{ + struct rte_src **old_tab, *src, *src_next; + u32 old_size, hash, i; + + old_tab = src_table; + old_size = src_hash_size; + + src_hash_order += step; + src_hash_size = 1 << src_hash_order; + src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *)); + + for (i = 0; i < old_size; i++) + for (src = old_tab[i]; src; src = src_next) + { + src_next = src->next; + hash = rte_src_hash(src->proto, src->private_id, src_hash_order); + src->next = src_table[hash]; + src_table[hash] = src; + } + + mb_free(old_tab); +} + +struct rte_src * +rt_find_source(struct proto *p, u32 id) +{ + struct rte_src *src; + u32 hash = rte_src_hash(p, id, src_hash_order); + + for (src = src_table[hash]; src; src = src->next) + if ((src->proto == p) && (src->private_id == id)) + return src; + + return NULL; +} + +struct rte_src * +rt_get_source(struct proto *p, u32 id) +{ + struct rte_src *src; + u32 hash = rte_src_hash(p, id, src_hash_order); + + for (src = src_table[hash]; src; src = src->next) + if ((src->proto == p) && (src->private_id == id)) + return src; + + src = sl_alloc(rte_src_slab); + src->proto = p; + src->private_id = id; + src->global_id = rte_src_alloc_id(); + src->uc = 0; + + src->next = src_table[hash]; + src_table[hash] = src; + + src_hash_count++; + if ((src_hash_count > src_hash_size) && (src_hash_order < SRC_HASH_ORDER_MAX)) + rte_src_rehash(1); + + return src; +} + +static inline void +rt_remove_source(struct rte_src **sp) +{ + struct rte_src *src = *sp; + + *sp = src->next; + rte_src_free_id(src->global_id); + sl_free(rte_src_slab, src); + src_hash_count--; +} + +void +rt_prune_sources(void) +{ + struct rte_src **sp; + int i; + + for (i = 0; i < src_hash_size; i++) + { + sp = &src_table[i]; + while (*sp) + { + if ((*sp)->uc == 0) + rt_remove_source(sp); + else + sp = &(*sp)->next; + } + } + + while ((src_hash_count < (src_hash_size / 4)) && (src_hash_order > SRC_HASH_ORDER_MIN)) + rte_src_rehash(-1); +} + + +/* + * Multipath Next Hop + */ + static inline unsigned int mpnh_hash(struct mpnh *x) { diff --cc nest/rt-table.c index ecd6e324b,fc5540814..8c91ea0aa --- a/nest/rt-table.c +++ b/nest/rt-table.c @@@ -615,11 -625,13 +632,13 @@@ rte_same(rte *x, rte *y x->flags == y->flags && x->pflags == y->pflags && x->pref == y->pref && - (!x->attrs->proto->rte_same || x->attrs->proto->rte_same(x, y)); + (!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y)); } + static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); } + static void -rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct proto *src) +rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, struct rte_src *src) { struct proto *p = ah->proto; struct rtable *table = ah->table; @@@ -911,41 -995,47 +1002,54 @@@ rte_update2(struct announce_hook *ah, n { stats->imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); - goto drop; - } - tmpa = make_tmp_attrs(new, rte_update_pool); - if (filter) + if (! ah->in_keep_filtered) + goto drop; + + /* new is a private copy, i could modify it */ + new->flags |= REF_FILTERED; + } + else { - ea_list *old_tmpa = tmpa; - int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0); - if (fr > F_ACCEPT) - if (src->make_tmp_attrs) - tmpa = src->make_tmp_attrs(new, rte_update_pool); ++ tmpa = make_tmp_attrs(new, rte_update_pool); + if (filter && (filter != FILTER_REJECT)) { - stats->imp_updates_filtered++; - rte_trace_in(D_FILTERS, p, new, "filtered out"); - goto drop; + ea_list *old_tmpa = tmpa; + int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0); + if (fr > F_ACCEPT) + { + stats->imp_updates_filtered++; + rte_trace_in(D_FILTERS, p, new, "filtered out"); + + if (! ah->in_keep_filtered) + goto drop; + + new->flags |= REF_FILTERED; + } - if (tmpa != old_tmpa && src->store_tmp_attrs) - src->store_tmp_attrs(new, tmpa); ++ if (tmpa != old_tmpa && src->proto->store_tmp_attrs) ++ src->proto->store_tmp_attrs(new, tmpa); } - if (tmpa != old_tmpa && src->proto->store_tmp_attrs) - src->proto->store_tmp_attrs(new, tmpa); } -- - if (!(new->attrs->aflags & RTAF_CACHED)) /* Need to copy attributes */ + if (!rta_is_cached(new->attrs)) /* Need to copy attributes */ new->attrs = rta_lookup(new->attrs); new->flags |= REF_COW; } else - stats->imp_withdraws_received++; + { + stats->imp_withdraws_received++; + + if (!net || !src) + { + stats->imp_withdraws_ignored++; + rte_update_unlock(); + return; + } + } + recalc: + rte_hide_dummy_routes(net, &dummy); rte_recalculate(ah, net, new, tmpa, src); + rte_unhide_dummy_routes(net, &dummy); rte_update_unlock(); return; @@@ -976,6 -1069,34 +1081,33 @@@ rte_discard(rtable *t, rte *old) /* Non rte_update_unlock(); } + /* Check rtable for best route to given net whether it would be exported do p */ + int + rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter) + { + net *n = net_find(t, prefix, pxlen); + rte *rt = n ? n->routes : NULL; + + if (!rte_is_valid(rt)) + return 0; + + rte_update_lock(); + + /* Rest is stripped down export_filter() */ - struct proto *src = rt->attrs->proto; - ea_list *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(rt, rte_update_pool) : NULL; ++ ea_list *tmpa = make_tmp_attrs(rt, rte_update_pool); + int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0; + if (v == RIC_PROCESS) + v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + + /* Discard temporary rte */ + if (rt != n->routes) + rte_free(rt); + + rte_update_unlock(); + + return v > 0; + } + /** * rte_dump - dump a route * @e: &rte to be dumped @@@ -1189,8 -1297,8 +1311,8 @@@ again rescan: for (e=n->routes; e; e=e->next) - if (e->sender->proto->core_state != FS_HAPPY && - e->sender->proto->core_state != FS_FEEDING) + if (e->sender->proto->flushing || - (step && e->attrs->proto->flushing)) ++ (step && e->attrs->src->proto->flushing)) { if (*max_feed <= 0) { @@@ -1198,6 -1306,10 +1320,10 @@@ return 0; } + if (step) + log_rl(&rl_flush, L_WARN "Route %I/%d from %s still in %s after flush", - n->n.prefix, n->n.pxlen, e->attrs->proto->name, tab->name); ++ n->n.prefix, n->n.pxlen, e->attrs->src->proto->name, tab->name); + rte_discard(tab, e); (*max_feed)--; @@@ -2001,20 -2132,25 +2149,25 @@@ rt_show_net(struct cli *c, net *n, stru int ok; bsprintf(ia, "%I/%d", n->n.prefix, n->n.pxlen); - if (n->routes) - d->net_counter++; + for(e=n->routes; e; e=e->next) { + if (rte_is_filtered(e) != d->filtered) + continue; + struct ea_list *tmpa; - struct proto *p0 = e->attrs->proto; + struct rte_src *src = e->attrs->src; struct proto *p1 = d->export_protocol; struct proto *p2 = d->show_protocol; + + if (ia[0]) + d->net_counter++; d->rt_counter++; ee = e; rte_update_lock(); /* We use the update buffer for filtering */ - tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL; + tmpa = make_tmp_attrs(e, rte_update_pool); - ok = (d->filter == FILTER_ACCEPT || f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); + ok = f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT; - if (p2 && p2 != p0) ok = 0; + if (p2 && p2 != src->proto) ok = 0; if (ok && d->export_mode) { int ic; diff --cc proto/bgp/bgp.h index b87de46ed,b5e216b78..a35c362cb --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@@ -43,7 -45,7 +45,8 @@@ struct bgp_config int passive; /* Do not initiate outgoing connection */ int interpret_communities; /* Hardwired handling of well-known communities */ int secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */ + int add_path; /* Use ADD-PATH extension [draft] */ + int allow_local_as; /* Allow that number of local ASNs in incoming AS_PATHs */ unsigned connect_retry_time; unsigned hold_time, initial_hold_time; unsigned keepalive_time; diff --cc proto/bgp/config.Y index 0b0963397,185b1bda5..ab12fed5a --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@@ -26,7 -26,7 +26,7 @@@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, H PREFER, OLDER, MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC, - SECONDARY, ADD, PATHS, RX, TX) - SECONDARY, ALLOW, BFD) ++ SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX) CF_GRAMMAR @@@ -107,11 -108,11 +108,14 @@@ bgp_proto | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; } | bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; } | bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; } + | bgp_proto ADD PATHS RX ';' { BGP_CFG->add_path = ADD_PATH_RX; } + | bgp_proto ADD PATHS TX ';' { BGP_CFG->add_path = ADD_PATH_TX; } + | bgp_proto ADD PATHS bool ';' { BGP_CFG->add_path = $4 ? ADD_PATH_FULL : 0; } + | bgp_proto ALLOW LOCAL AS ';' { BGP_CFG->allow_local_as = -1; } + | bgp_proto ALLOW LOCAL AS expr ';' { BGP_CFG->allow_local_as = $5; } | bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; } | bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; } + | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); } ; CF_ADDTO(dynamic_attr, BGP_ORIGIN diff --cc proto/rip/rip.c index 9f4f0856d,ad285bb3a..5cc40403f --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@@ -948,9 -968,11 +960,11 @@@ rip_rte_insert(net *net UNUSED, rte *rt static void rip_rte_remove(net *net UNUSED, rte *rte) { - // struct proto *p = rte->attrs->proto; + #ifdef LOCAL_DEBUG - struct proto *p = rte->attrs->proto; ++ struct proto *p = rte->attrs->src->proto; CHK_MAGIC; DBG( "rip_rte_remove: %p\n", rte ); + #endif rem_node( &rte->u.rip.garbage ); }