summaryrefslogtreecommitdiff
path: root/proto/bgp/attrs.c
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/bgp/attrs.c
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/bgp/attrs.c')
-rw-r--r--proto/bgp/attrs.c76
1 files changed, 76 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)
{