From 841f7a57b13b8cba4efd51db4e7ac13fd403b17b Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Thu, 10 Apr 2008 11:47:45 +0000 Subject: + [bgpd] Added new route-map set statement: "as-path ignore" --- bgpd/ChangeLog | 11 +++++ bgpd/bgp_aspath.c | 82 ++++++++++++++++++++++++++++++++++++- bgpd/bgp_aspath.h | 3 +- bgpd/bgp_route.c | 10 ++--- bgpd/bgp_routemap.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 211 insertions(+), 10 deletions(-) (limited to 'bgpd') diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog index f3b6a8c1..7f94565c 100644 --- a/bgpd/ChangeLog +++ b/bgpd/ChangeLog @@ -1,3 +1,14 @@ +2008-04-10 Denis Ovsienko + * bgp_aspath.[ch]: (aspath_filter_exclude) New function allows + filtering out arbitrary ASns from AS_PATH attribute. + * bgp_aspath.[ch]: (aspath_print_vty) Accept suffix to let calling + functions signal, if they want the separator or not. + * bgp_route.c: (route_vty_out, route_vty_out_tmp, damp_route_vty_out, + flap_route_vty_out, route_vty_out_detail) Fix aspath_print_vty() + calls to have AS_PATH output nicely. + * bgp_routemap.c: Introduce "set as-path exclude" route-map command + to employ new filtering functionality. + 2008-03-13 Paul Jakma * (various) Remove 0 entries from struct message's, unneeded due to diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index d7e985d4..38c9caa6 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1225,6 +1225,81 @@ aspath_prepend (struct aspath *as1, struct aspath *as2) /* Not reached */ } +/* Iterate over AS_PATH segments and wipe all occurences of the + * listed AS numbers. Hence some segments may lose some or even + * all data on the way, the operation is implemented as a smarter + * version of aspath_dup(), which allocates memory to hold the new + * data, not the original. The new AS path is returned. + */ +struct aspath * +aspath_filter_exclude (struct aspath * source, struct aspath * exclude_list) +{ + struct assegment * srcseg, * exclseg, * lastseg; + struct aspath * newpath; + + newpath = aspath_new(); + lastseg = NULL; + + for (srcseg = source->segments; srcseg; srcseg = srcseg->next) + { + unsigned i, y, newlen = 0, done = 0, skip_as; + struct assegment * newseg; + + /* Find out, how much ASns are we going to pick from this segment. + * We can't perform filtering right inline, because the size of + * the new segment isn't known at the moment yet. + */ + for (i = 0; i < srcseg->length; i++) + { + skip_as = 0; + for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next) + for (y = 0; y < exclseg->length; y++) + if (srcseg->as[i] == exclseg->as[y]) + { + skip_as = 1; + // There's no sense in testing the rest of exclusion list, bail out. + break; + } + if (!skip_as) + newlen++; + } + /* newlen is now the number of ASns to copy */ + if (!newlen) + continue; + + /* Actual copying. Allocate memory and iterate once more, performing filtering. */ + newseg = assegment_new (srcseg->type, newlen); + for (i = 0; i < srcseg->length; i++) + { + skip_as = 0; + for (exclseg = exclude_list->segments; exclseg && !skip_as; exclseg = exclseg->next) + for (y = 0; y < exclseg->length; y++) + if (srcseg->as[i] == exclseg->as[y]) + { + skip_as = 1; + break; + } + if (skip_as) + continue; + newseg->as[done++] = srcseg->as[i]; + } + /* At his point newlen must be equal to done, and both must be positive. Append + * the filtered segment to the gross result. */ + if (!lastseg) + newpath->segments = newseg; + else + lastseg->next = newseg; + lastseg = newseg; + } + aspath_str_update (newpath); + /* We are happy returning even an empty AS_PATH, because the administrator + * might expect this very behaviour. There's a mean to avoid this, if necessary, + * by having a match rule against certain AS_PATH regexps in the route-map index. + */ + aspath_free (source); + return newpath; +} + /* Add specified AS to the leftmost of aspath. */ static struct aspath * aspath_add_one_as (struct aspath *aspath, as_t asno, u_char type) @@ -1741,11 +1816,16 @@ aspath_print (struct aspath *as) } /* Printing functions */ +/* Feed the AS_PATH to the vty; the suffix string follows it only in case + * AS_PATH wasn't empty. + */ void -aspath_print_vty (struct vty *vty, const char *format, struct aspath *as) +aspath_print_vty (struct vty *vty, const char *format, struct aspath *as, const char * suffix) { assert (format); vty_out (vty, format, as->str); + if (strlen (as->str) && strlen (suffix)) + vty_out (vty, "%s", suffix); } static void diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index 3bb616f7..d8b41fa9 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -69,6 +69,7 @@ extern struct aspath *aspath_parse (struct stream *, size_t, int); 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 (struct aspath *, as_t); extern struct aspath *aspath_add_confed_seq (struct aspath *, as_t); extern int aspath_cmp_left (struct aspath *, struct aspath *); @@ -81,7 +82,7 @@ extern void aspath_free (struct aspath *); extern struct aspath *aspath_intern (struct aspath *); extern void aspath_unintern (struct aspath *); extern const char *aspath_print (struct aspath *); -extern void aspath_print_vty (struct vty *, const char *, struct aspath *); +extern void aspath_print_vty (struct vty *, const char *, struct aspath *, const char *); extern void aspath_print_all_vty (struct vty *); extern unsigned int aspath_key_make (void *); extern int aspath_loop_check (struct aspath *, as_t); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9ddeca54..4fbc4bab 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5694,7 +5694,7 @@ route_vty_out (struct vty *vty, struct prefix *p, /* Print aspath */ if (attr->aspath) - aspath_print_vty (vty, "%s ", attr->aspath); + aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); @@ -5759,7 +5759,7 @@ route_vty_out_tmp (struct vty *vty, struct prefix *p, /* Print aspath */ if (attr->aspath) - aspath_print_vty (vty, "%s ", attr->aspath); + aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); @@ -5859,7 +5859,7 @@ damp_route_vty_out (struct vty *vty, struct prefix *p, { /* Print aspath */ if (attr->aspath) - aspath_print_vty (vty, "%s ", attr->aspath); + aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); @@ -5922,7 +5922,7 @@ flap_route_vty_out (struct vty *vty, struct prefix *p, { /* Print aspath */ if (attr->aspath) - aspath_print_vty (vty, "%s ", attr->aspath); + aspath_print_vty (vty, "%s", attr->aspath, " "); /* Print origin */ vty_out (vty, "%s", bgp_origin_str[attr->origin]); @@ -5950,7 +5950,7 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (aspath_count_hops (attr->aspath) == 0) vty_out (vty, "Local"); else - aspath_print_vty (vty, "%s", attr->aspath); + aspath_print_vty (vty, "%s", attr->aspath, ""); } if (CHECK_FLAG (binfo->flags, BGP_INFO_REMOVED)) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b246e2ab..b93b2682 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -94,6 +94,7 @@ o Local extention set ipv6 next-hop global: Done set ipv6 next-hop local : Done set pathlimit ttl : Done + set as-path exclude : Done match pathlimit as : Done */ @@ -1274,6 +1275,64 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd = route_set_aspath_prepend_free, }; +/* `set as-path exclude ASn' */ + +/* For ASN exclude mechanism. + * Iterate over ASns requested and filter them from the given AS_PATH one by one. + * Make a deep copy of existing AS_PATH, but for the first ASn only. + */ +static route_map_result_t +route_set_aspath_exclude (void *rule, struct prefix *dummy, route_map_object_t type, void *object) +{ + struct aspath * new_path, * exclude_path; + struct bgp_info *binfo; + + if (type == RMAP_BGP) + { + exclude_path = rule; + binfo = object; + if (binfo->attr->aspath->refcnt) + new_path = aspath_dup (binfo->attr->aspath); + else + new_path = binfo->attr->aspath; + binfo->attr->aspath = aspath_filter_exclude (new_path, exclude_path); + } + return RMAP_OKAY; +} + +/* FIXME: consider using route_set_aspath_prepend_compile() and + * route_set_aspath_prepend_free(), which two below function are + * exact clones of. + */ + +/* Compile function for as-path exclude. */ +static void * +route_set_aspath_exclude_compile (const char *arg) +{ + struct aspath *aspath; + + aspath = aspath_str2aspath (arg); + if (! aspath) + return NULL; + return aspath; +} + +static void +route_set_aspath_exclude_free (void *rule) +{ + struct aspath *aspath = rule; + aspath_free (aspath); +} + +/* Set ASn exlude rule structure. */ +struct route_map_rule_cmd route_set_aspath_exclude_cmd = +{ + "as-path exclude", + route_set_aspath_exclude, + route_set_aspath_exclude_compile, + route_set_aspath_exclude_free, +}; + /* `set community COMMUNITY' */ struct rmap_com_set { @@ -2996,7 +3055,7 @@ DEFUN (set_aspath_prepend, set_aspath_prepend_cmd, "set as-path prepend .<1-65535>", SET_STR - "Prepend string for a BGP AS-path attribute\n" + "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") { @@ -3015,7 +3074,7 @@ DEFUN (no_set_aspath_prepend, "no set as-path prepend", NO_STR SET_STR - "Prepend string for a BGP AS-path attribute\n" + "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n") { int ret; @@ -3035,10 +3094,56 @@ ALIAS (no_set_aspath_prepend, "no set as-path prepend .<1-65535>", NO_STR SET_STR - "Prepend string for a BGP AS-path attribute\n" + "Transform BGP AS_PATH attribute\n" "Prepend to the as-path\n" "AS number\n") +DEFUN (set_aspath_exclude, + set_aspath_exclude_cmd, + "set as-path exclude .<1-65535>", + SET_STR + "Transform BGP AS-path attribute\n" + "Exclude from the as-path\n" + "AS number\n") +{ + int ret; + char *str; + + str = argv_concat (argv, argc, 0); + ret = bgp_route_set_add (vty, vty->index, "as-path exclude", str); + XFREE (MTYPE_TMP, str); + return ret; +} + +DEFUN (no_set_aspath_exclude, + no_set_aspath_exclude_cmd, + "no set as-path exclude", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Exclude from the as-path\n") +{ + int ret; + char *str; + + if (argc == 0) + return bgp_route_set_delete (vty, vty->index, "as-path exclude", NULL); + + str = argv_concat (argv, argc, 0); + ret = bgp_route_set_delete (vty, vty->index, "as-path exclude", str); + XFREE (MTYPE_TMP, str); + return ret; +} + +ALIAS (no_set_aspath_exclude, + no_set_aspath_exclude_val_cmd, + "no set as-path exclude .<1-65535>", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Exclude from the as-path\n" + "AS number\n") + DEFUN (set_community, set_community_cmd, "set community .AA:NN", @@ -3731,6 +3836,7 @@ bgp_route_map_init (void) route_map_install_set (&route_set_weight_cmd); route_map_install_set (&route_set_metric_cmd); route_map_install_set (&route_set_aspath_prepend_cmd); + route_map_install_set (&route_set_aspath_exclude_cmd); route_map_install_set (&route_set_origin_cmd); route_map_install_set (&route_set_atomic_aggregate_cmd); route_map_install_set (&route_set_aggregator_as_cmd); @@ -3799,8 +3905,11 @@ 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_exclude_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_cmd); install_element (RMAP_NODE, &no_set_aspath_prepend_val_cmd); + install_element (RMAP_NODE, &no_set_aspath_exclude_cmd); + install_element (RMAP_NODE, &no_set_aspath_exclude_val_cmd); install_element (RMAP_NODE, &set_origin_cmd); install_element (RMAP_NODE, &no_set_origin_cmd); install_element (RMAP_NODE, &no_set_origin_val_cmd); -- cgit v1.2.1