+ [bgpd] Added new route-map set statement: "as-path ignore"
diff --git a/NEWS b/NEWS
index 74d258f..ff28e1a 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@
- [bgpd] 4-byte AS support added
- [bgpd] MRT format changes to version 2. Those relying on
bgpd MRT table dumps may need to update their tools.
+- [bgpd] Added new route-map set statement: "as-path ignore"
* Changes in Quagga 0.99.2
diff --git a/bgpd/ChangeLog b/bgpd/ChangeLog
index f3b6a8c..7f94565 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 <paul.jakma@sun.com>
* (various) Remove 0 entries from struct message's, unneeded due to
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index d7e985d..38c9caa 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1225,6 +1225,81 @@
/* 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 @@
}
/* 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 3bb616f..d8b41fa 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -69,6 +69,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 (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 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 9ddeca5..4fbc4ba 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -5694,7 +5694,7 @@
/* 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 @@
/* 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 @@
{
/* 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 @@
{
/* 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 @@
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 b246e2a..b93b268 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -94,6 +94,7 @@
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 @@
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 @@
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 @@
"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 @@
"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 @@
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 @@
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);