summaryrefslogtreecommitdiff
path: root/proto
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2015-06-08 02:20:43 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2015-06-08 02:24:08 +0200
commit8d9eef17713a9b38cd42bd59c4ce76c3ef6c2fc2 (patch)
tree3115be5be954d6bbfd05db675b4a5508a50ed9d2 /proto
parentdb027a41d47b8fc52b65067ccabe2024554e53ca (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.c76
-rw-r--r--proto/bgp/bgp.c1
-rw-r--r--proto/bgp/bgp.h1
-rw-r--r--proto/static/static.c7
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;
}