From: Daniel Walton Date: Thu, 26 May 2016 01:49:34 +0000 (+0000) Subject: Author: Timo Teräs X-Git-Tag: frr-2.0-rc1~767 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=bc3dd427f2b278e3d523fcaa463c4d6864101edd;p=mirror%2Ffrr.git Author: Timo Teräs Date: Tue Sep 30 11:31:53 2014 +0300 bgpd: implement route-map set as-path prepend last-as It picks up the AS to add from the aspath, or uses the peers AS number. Useful mostly in iBGP setups. Signed-off-by: Timo Teräs Reviewed-by: Paul Jakma --- diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 031f71c305..b5c8dccf87 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -490,6 +490,19 @@ aspath_highest (struct aspath *aspath) return highest; } +/* Return the left-most ASN in path */ +as_t +aspath_leftmost (struct aspath *aspath) +{ + struct assegment *seg = aspath->segments; + as_t leftmost = 0; + + if (seg && seg->length && seg->type == AS_SEQUENCE) + leftmost = seg->as[0]; + + return leftmost; +} + /* Return 1 if there are any 4-byte ASes in the path */ unsigned int aspath_has_as4 (struct aspath *aspath) @@ -1569,46 +1582,50 @@ aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list) /* Add specified AS to the leftmost of aspath. */ static struct aspath * -aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) +aspath_add_asns (struct aspath *aspath, as_t asno, u_char type, unsigned num) { struct assegment *assegment = aspath->segments; + unsigned i; - /* In case of empty aspath. */ - if (assegment == NULL || assegment->length == 0) + if (assegment && assegment->type == type) { - aspath->segments = assegment_new (type, 1); - aspath->segments->as[0] = asno; - - if (assegment) - assegment_free (assegment); - - return aspath; + /* extend existing segment */ + aspath->segments = assegment_prepend_asns (aspath->segments, asno, num); } - - if (assegment->type == type) - aspath->segments = assegment_prepend_asns (aspath->segments, asno, 1); else { - /* create new segment - * push it onto head of aspath's segment chain - */ - struct assegment *newsegment; - - newsegment = assegment_new (type, 1); - newsegment->as[0] = asno; - - newsegment->next = assegment; + /* prepend with new segment */ + struct assegment *newsegment = assegment_new (type, num); + for (i = 0; i < num; i++) + newsegment->as[i] = asno; + + /* insert potentially replacing empty segment */ + if (assegment && assegment->length == 0) + { + newsegment->next = assegment->next; + assegment_free (assegment); + } + else + newsegment->next = assegment; aspath->segments = newsegment; } + aspath_str_update (aspath); return aspath; } +/* Add specified AS to the leftmost of aspath num times. */ +struct aspath * +aspath_add_seq_n (struct aspath *aspath, as_t asno, unsigned num) +{ + return aspath_add_asns (aspath, asno, AS_SEQUENCE, num); +} + /* Add specified AS to the leftmost of aspath. */ struct aspath * aspath_add_seq (struct aspath *aspath, as_t asno) { - return aspath_add_one_as (aspath, asno, AS_SEQUENCE); + return aspath_add_asns (aspath, asno, AS_SEQUENCE, 1); } /* Compare leftmost AS value for MED check. If as1's leftmost AS and @@ -1831,7 +1848,7 @@ aspath_delete_confed_seq (struct aspath *aspath) struct aspath* aspath_add_confed_seq (struct aspath *aspath, as_t asno) { - return aspath_add_one_as (aspath, asno, AS_CONFED_SEQUENCE); + return aspath_add_asns (aspath, asno, AS_CONFED_SEQUENCE, 1); } /* Add new as value to as path structure. */ diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index e4c781385d..a8cc38e1cb 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -84,6 +84,7 @@ extern struct aspath *aspath_dup (struct aspath *); extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *); extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); extern struct aspath *aspath_filter_exclude (struct aspath *, struct aspath *); +extern struct aspath *aspath_add_seq_n (struct aspath *, as_t, unsigned); extern struct aspath *aspath_add_seq (struct aspath *, as_t); extern struct aspath *aspath_add_confed_seq (struct aspath *, as_t); extern int aspath_cmp (const void *, const void *); @@ -115,6 +116,7 @@ extern unsigned int aspath_count_hops (const struct aspath *); extern unsigned int aspath_count_confeds (struct aspath *); extern unsigned int aspath_size (struct aspath *); extern as_t aspath_highest (struct aspath *); +extern as_t aspath_leftmost (struct aspath *); extern size_t aspath_put (struct stream *, struct aspath *, int); extern struct aspath *aspath_reconcile_as4 (struct aspath *, struct aspath *); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index d8e2612175..60f5f622d6 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1435,7 +1435,6 @@ route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t if (type == RMAP_BGP) { - aspath = rule; binfo = object; if (binfo->attr->aspath->refcnt) @@ -1443,20 +1442,50 @@ route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t else new = binfo->attr->aspath; - aspath_prepend (aspath, new); + if ((uintptr_t)rule > 10) + { + aspath = rule; + aspath_prepend (aspath, new); + } + else + { + as_t as = aspath_leftmost(new); + if (!as) as = binfo->peer->as; + new = aspath_add_seq_n (new, as, (uintptr_t) rule); + } + binfo->attr->aspath = new; } return RMAP_OKAY; } +static void * +route_set_aspath_prepend_compile (const char *arg) +{ + unsigned int num; + + if (sscanf(arg, "last-as %u", &num) == 1 && num > 0 && num < 10) + return (void*)(uintptr_t)num; + + return route_aspath_compile(arg); +} + +static void +route_set_aspath_prepend_free (void *rule) +{ + if ((uintptr_t)rule > 10) + route_aspath_free(rule); +} + + /* Set as-path prepend rule structure. */ struct route_map_rule_cmd route_set_aspath_prepend_cmd = { "as-path prepend", route_set_aspath_prepend, - route_aspath_compile, - route_aspath_free, + route_set_aspath_prepend_compile, + route_set_aspath_prepend_free, }; /* `set as-path exclude ASn' */ @@ -3803,6 +3832,15 @@ DEFUN (set_aspath_prepend, return ret; } +ALIAS (set_aspath_prepend, + set_aspath_prepend_lastas_cmd, + "set as-path prepend (last-as) <1-10>", + SET_STR + "Transform BGP AS_PATH attribute\n" + "Prepend to the as-path\n" + "Use the peer's AS-number\n" + "Number of times to insert"); + DEFUN (no_set_aspath_prepend, no_set_aspath_prepend_cmd, "no set as-path prepend", @@ -4681,6 +4719,7 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &no_set_metric_cmd); install_element (RMAP_NODE, &no_set_metric_val_cmd); install_element (RMAP_NODE, &set_aspath_prepend_cmd); + install_element (RMAP_NODE, &set_aspath_prepend_lastas_cmd); install_element (RMAP_NODE, &set_aspath_exclude_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd);