diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2015-06-08 02:20:43 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2015-06-08 02:24:08 +0200 |
commit | 8d9eef17713a9b38cd42bd59c4ce76c3ef6c2fc2 (patch) | |
tree | 3115be5be954d6bbfd05db675b4a5508a50ed9d2 /proto | |
parent | db027a41d47b8fc52b65067ccabe2024554e53ca (diff) |
BGP multipath support
Kernel option 'merge paths' allows to merge routes exported to kernel
protocol (currently BGP and static routes) to multipath routes.
Diffstat (limited to 'proto')
-rw-r--r-- | proto/bgp/attrs.c | 76 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 1 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 1 | ||||
-rw-r--r-- | proto/static/static.c | 7 |
4 files changed, 85 insertions, 0 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index d56c017d..d85afa8f 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -1312,6 +1312,82 @@ bgp_rte_better(rte *new, rte *old) } +int +bgp_rte_mergable(rte *pri, rte *sec) +{ + struct bgp_proto *pri_bgp = (struct bgp_proto *) pri->attrs->src->proto; + struct bgp_proto *sec_bgp = (struct bgp_proto *) sec->attrs->src->proto; + eattr *x, *y; + u32 p, s; + + /* Skip suppressed routes (see bgp_rte_recalculate()) */ + if (pri->u.bgp.suppressed != sec->u.bgp.suppressed) + return 0; + + /* RFC 4271 9.1.2.1. Route resolvability test */ + if (!rte_resolvable(sec)) + return 0; + + /* Start with local preferences */ + x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF)); + y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF)); + p = x ? x->u.data : pri_bgp->cf->default_local_pref; + s = y ? y->u.data : sec_bgp->cf->default_local_pref; + if (p != s) + return 0; + + /* RFC 4271 9.1.2.2. a) Use AS path lengths */ + if (pri_bgp->cf->compare_path_lengths || sec_bgp->cf->compare_path_lengths) + { + x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)); + y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)); + p = x ? as_path_getlen(x->u.ptr) : AS_PATH_MAXLEN; + s = y ? as_path_getlen(y->u.ptr) : AS_PATH_MAXLEN; + + if (p != s) + return 0; + +// if (DELTA(p, s) > pri_bgp->cf->relax_multipath) +// return 0; + } + + /* RFC 4271 9.1.2.2. b) Use origins */ + x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN)); + y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGIN)); + p = x ? x->u.data : ORIGIN_INCOMPLETE; + s = y ? y->u.data : ORIGIN_INCOMPLETE; + if (p != s) + return 0; + + /* RFC 4271 9.1.2.2. c) Compare MED's */ + if (pri_bgp->cf->med_metric || sec_bgp->cf->med_metric || + (bgp_get_neighbor(pri) == bgp_get_neighbor(sec))) + { + x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); + y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_MULTI_EXIT_DISC)); + p = x ? x->u.data : pri_bgp->cf->default_med; + s = y ? y->u.data : sec_bgp->cf->default_med; + if (p != s) + return 0; + } + + /* RFC 4271 9.1.2.2. d) Prefer external peers */ + if (pri_bgp->is_internal != sec_bgp->is_internal) + return 0; + + /* RFC 4271 9.1.2.2. e) Compare IGP metrics */ + p = pri_bgp->cf->igp_metric ? pri->attrs->igp_metric : 0; + s = sec_bgp->cf->igp_metric ? sec->attrs->igp_metric : 0; + if (p != s) + return 0; + + /* Remaining criteria are ignored */ + + return 1; +} + + + static inline int same_group(rte *r, u32 lpref, u32 lasn) { diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index e48b643b..9e28b278 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -1243,6 +1243,7 @@ bgp_init(struct proto_config *C) P->feed_begin = bgp_feed_begin; P->feed_end = bgp_feed_end; P->rte_better = bgp_rte_better; + P->rte_mergable = bgp_rte_mergable; P->rte_recalculate = c->deterministic_med ? bgp_rte_recalculate : NULL; p->cf = c; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 446fc857..b6e80fe5 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -238,6 +238,7 @@ byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned att struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, uint len, struct linpool *pool, int mandatory); int bgp_get_attr(struct eattr *e, byte *buf, int buflen); int bgp_rte_better(struct rte *, struct rte *); +int bgp_rte_mergable(rte *pri, rte *sec); int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best); void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs); int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *); diff --git a/proto/static/static.c b/proto/static/static.c index 4b72fa9d..e7e7ab15 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -352,6 +352,12 @@ static_if_notify(struct proto *p, unsigned flags, struct iface *i) } } +int +static_rte_mergable(rte *pri, rte *sec) +{ + return 1; +} + void static_init_config(struct static_config *c) { @@ -366,6 +372,7 @@ static_init(struct proto_config *c) p->neigh_notify = static_neigh_notify; p->if_notify = static_if_notify; + p->rte_mergable = static_rte_mergable; return p; } |