summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_routemap.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_routemap.c')
-rw-r--r--bgpd/bgp_routemap.c3207
1 files changed, 3207 insertions, 0 deletions
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
new file mode 100644
index 000000000..498a60055
--- /dev/null
+++ b/bgpd/bgp_routemap.c
@@ -0,0 +1,3207 @@
+/* Route map function of bgpd.
+ Copyright (C) 1998, 1999 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "filter.h"
+#include "routemap.h"
+#include "command.h"
+#include "linklist.h"
+#include "plist.h"
+#include "memory.h"
+#include "log.h"
+#ifdef HAVE_GNU_REGEX
+#include <regex.h>
+#else
+#include "regex-gnu.h"
+#endif /* HAVE_GNU_REGEX */
+#include "buffer.h"
+#include "sockunion.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_regex.h"
+#include "bgpd/bgp_community.h"
+#include "bgpd/bgp_clist.h"
+#include "bgpd/bgp_filter.h"
+#include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_ecommunity.h"
+
+/* Memo of route-map commands.
+
+o Cisco route-map
+
+ match as-path : Done
+ community : Done
+ interface : Not yet
+ ip address : Done
+ ip next-hop : Done
+ ip route-source : (This will not be implemented by bgpd)
+ ip prefix-list : Done
+ ipv6 address : Done
+ ipv6 next-hop : Done
+ ipv6 route-source: (This will not be implemented by bgpd)
+ ipv6 prefix-list : Done
+ length : (This will not be implemented by bgpd)
+ metric : Done
+ route-type : (This will not be implemented by bgpd)
+ tag : (This will not be implemented by bgpd)
+
+ set as-path prepend : Done
+ as-path tag : Not yet
+ automatic-tag : (This will not be implemented by bgpd)
+ community : Done
+ comm-list : Not yet
+ dampning : Not yet
+ default : (This will not be implemented by bgpd)
+ interface : (This will not be implemented by bgpd)
+ ip default : (This will not be implemented by bgpd)
+ ip next-hop : Done
+ ip precedence : (This will not be implemented by bgpd)
+ ip tos : (This will not be implemented by bgpd)
+ level : (This will not be implemented by bgpd)
+ local-preference : Done
+ metric : Done
+ metric-type : Not yet
+ origin : Done
+ tag : (This will not be implemented by bgpd)
+ weight : Done
+
+o Local extention
+
+ set ipv6 next-hop global: Done
+ set ipv6 next-hop local : Done
+
+*/
+
+/* `match ip address IP_ACCESS_LIST' */
+
+/* Match function should return 1 if match is success else return
+ zero. */
+route_map_result_t
+route_match_ip_address (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
+ /* struct prefix_ipv4 match; */
+
+ if (type == RMAP_BGP)
+ {
+ alist = access_list_lookup (AFI_IP, (char *) rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ return (access_list_apply (alist, prefix) == FILTER_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `ip address' match statement. `arg' should be
+ access-list name. */
+void *
+route_match_ip_address_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_address_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_ip_address_cmd =
+{
+ "ip address",
+ route_match_ip_address,
+ route_match_ip_address_compile,
+ route_match_ip_address_free
+};
+
+/* `match ip next-hop IP_ADDRESS' */
+
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_ip_next_hop (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
+ struct bgp_info *bgp_info;
+ struct prefix_ipv4 p;
+
+ if (type == RMAP_BGP)
+ {
+ bgp_info = object;
+ p.family = AF_INET;
+ p.prefix = bgp_info->attr->nexthop;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ alist = access_list_lookup (AFI_IP, (char *) rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ return (access_list_apply (alist, &p) == FILTER_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `ip next-hop' match statement. `arg' is
+ access-list name. */
+void *
+route_match_ip_next_hop_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_ip_next_hop_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip next-hop matching. */
+struct route_map_rule_cmd route_match_ip_next_hop_cmd =
+{
+ "ip next-hop",
+ route_match_ip_next_hop,
+ route_match_ip_next_hop_compile,
+ route_match_ip_next_hop_free
+};
+
+/* `match ip address prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_address_prefix_list (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+
+ if (type == RMAP_BGP)
+ {
+ plist = prefix_list_lookup (AFI_IP, (char *) rule);
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_address_prefix_list_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_address_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd =
+{
+ "ip address prefix-list",
+ route_match_ip_address_prefix_list,
+ route_match_ip_address_prefix_list_compile,
+ route_match_ip_address_prefix_list_free
+};
+
+/* `match ip next-hop prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ip_next_hop_prefix_list (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+ struct bgp_info *bgp_info;
+ struct prefix_ipv4 p;
+
+ if (type == RMAP_BGP)
+ {
+ bgp_info = object;
+ p.family = AF_INET;
+ p.prefix = bgp_info->attr->nexthop;
+ p.prefixlen = IPV4_MAX_BITLEN;
+
+ plist = prefix_list_lookup (AFI_IP, (char *) rule);
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, &p) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+void *
+route_match_ip_next_hop_prefix_list_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ip_next_hop_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd =
+{
+ "ip next-hop prefix-list",
+ route_match_ip_next_hop_prefix_list,
+ route_match_ip_next_hop_prefix_list_compile,
+ route_match_ip_next_hop_prefix_list_free
+};
+
+/* `match metric METRIC' */
+
+/* Match function return 1 if match is success else return zero. */
+route_map_result_t
+route_match_metric (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *med;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ med = rule;
+ bgp_info = object;
+
+ if (bgp_info->attr->med == *med)
+ return RMAP_MATCH;
+ else
+ return RMAP_NOMATCH;
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Route map `match metric' match statement. `arg' is MED value */
+void *
+route_match_metric_compile (char *arg)
+{
+ u_int32_t *med;
+ char *endptr = NULL;
+
+ med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+ *med = strtoul (arg, &endptr, 10);
+ if (*endptr != '\0' || *med == ULONG_MAX)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, med);
+ return NULL;
+ }
+ return med;
+}
+
+/* Free route map's compiled `match metric' value. */
+void
+route_match_metric_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for metric matching. */
+struct route_map_rule_cmd route_match_metric_cmd =
+{
+ "metric",
+ route_match_metric,
+ route_match_metric_compile,
+ route_match_metric_free
+};
+
+/* `match as-path ASPATH' */
+
+/* Match function for as-path match. I assume given object is */
+route_map_result_t
+route_match_aspath (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+
+ struct as_list *as_list;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ as_list = as_list_lookup ((char *) rule);
+ if (as_list == NULL)
+ return RMAP_NOMATCH;
+
+ bgp_info = object;
+
+ /* Perform match. */
+ return ((as_list_apply (as_list, bgp_info->attr->aspath) == AS_FILTER_DENY) ? RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Compile function for as-path match. */
+void *
+route_match_aspath_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Compile function for as-path match. */
+void
+route_match_aspath_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for aspath matching. */
+struct route_map_rule_cmd route_match_aspath_cmd =
+{
+ "as-path",
+ route_match_aspath,
+ route_match_aspath_compile,
+ route_match_aspath_free
+};
+
+#if ROUTE_MATCH_ASPATH_OLD
+/* `match as-path ASPATH' */
+
+/* Match function for as-path match. I assume given object is */
+int
+route_match_aspath (void *rule, struct prefix *prefix, void *object)
+{
+ regex_t *regex;
+ struct bgp_info *bgp_info;
+
+ regex = rule;
+ bgp_info = object;
+
+ /* Perform match. */
+ return bgp_regexec (regex, bgp_info->attr->aspath);
+}
+
+/* Compile function for as-path match. */
+void *
+route_match_aspath_compile (char *arg)
+{
+ regex_t *regex;
+
+ regex = bgp_regcomp (arg);
+ if (! regex)
+ return NULL;
+
+ return regex;
+}
+
+/* Compile function for as-path match. */
+void
+route_match_aspath_free (void *rule)
+{
+ regex_t *regex = rule;
+
+ bgp_regex_free (regex);
+}
+
+/* Route map commands for aspath matching. */
+struct route_map_rule_cmd route_match_aspath_cmd =
+{
+ "as-path",
+ route_match_aspath,
+ route_match_aspath_compile,
+ route_match_aspath_free
+};
+#endif /* ROUTE_MATCH_ASPATH_OLD */
+
+/* `match community COMMUNIY' */
+struct rmap_community
+{
+ char *name;
+ int exact;
+};
+
+/* Match function for community match. */
+route_map_result_t
+route_match_community (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct community_list *list;
+ struct bgp_info *bgp_info;
+ struct rmap_community *rcom;
+
+ if (type == RMAP_BGP)
+ {
+ bgp_info = object;
+ rcom = rule;
+
+ list = community_list_lookup (bgp_clist, rcom->name, COMMUNITY_LIST_AUTO);
+ if (! list)
+ return RMAP_NOMATCH;
+
+ if (rcom->exact)
+ {
+ if (community_list_exact_match (bgp_info->attr->community, list))
+ return RMAP_MATCH;
+ }
+ else
+ {
+ if (community_list_match (bgp_info->attr->community, list))
+ return RMAP_MATCH;
+ }
+ }
+ return RMAP_NOMATCH;
+}
+
+/* Compile function for community match. */
+void *
+route_match_community_compile (char *arg)
+{
+ struct rmap_community *rcom;
+ int len;
+ char *p;
+
+ rcom = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_community));
+
+ p = strchr (arg, ' ');
+ if (p)
+ {
+ len = p - arg;
+ rcom->name = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+ memcpy (rcom->name, arg, len);
+ rcom->exact = 1;
+ }
+ else
+ {
+ rcom->name = XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+ rcom->exact = 0;
+ }
+ return rcom;
+}
+
+/* Compile function for community match. */
+void
+route_match_community_free (void *rule)
+{
+ struct rmap_community *rcom = rule;
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom->name);
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rcom);
+}
+
+/* Route map commands for community matching. */
+struct route_map_rule_cmd route_match_community_cmd =
+{
+ "community",
+ route_match_community,
+ route_match_community_compile,
+ route_match_community_free
+};
+
+/* `match nlri` and `set nlri` are replaced by `address-family ipv4`
+ and `address-family vpnv4'. */
+
+/* `match origin' */
+route_map_result_t
+route_match_origin (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_char *origin;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ origin = rule;
+ bgp_info = object;
+
+ if (bgp_info->attr->origin == *origin)
+ return RMAP_MATCH;
+ }
+
+ return RMAP_NOMATCH;
+}
+
+void *
+route_match_origin_compile (char *arg)
+{
+ u_char *origin;
+
+ origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char));
+
+ if (strcmp (arg, "igp") == 0)
+ *origin = 0;
+ else if (strcmp (arg, "egp") == 0)
+ *origin = 1;
+ else
+ *origin = 2;
+
+ return origin;
+}
+
+/* Free route map's compiled `ip address' value. */
+void
+route_match_origin_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for origin matching. */
+struct route_map_rule_cmd route_match_origin_cmd =
+{
+ "origin",
+ route_match_origin,
+ route_match_origin_compile,
+ route_match_origin_free
+};
+/* `set ip next-hop IP_ADDRESS' */
+
+/* Set nexthop to object. ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ip_nexthop (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct in_addr *address;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ /* Fetch routemap's rule information. */
+ address = rule;
+ bgp_info = object;
+
+ /* Set next hop value. */
+ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
+ bgp_info->attr->nexthop = *address;
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Route map `ip nexthop' compile function. Given string is converted
+ to struct in_addr structure. */
+void *
+route_set_ip_nexthop_compile (char *arg)
+{
+ int ret;
+ struct in_addr *address;
+
+ address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+ ret = inet_aton (arg, address);
+
+ if (ret == 0)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+ return NULL;
+ }
+
+ return address;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+void
+route_set_ip_nexthop_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_ip_nexthop_cmd =
+{
+ "ip next-hop",
+ route_set_ip_nexthop,
+ route_set_ip_nexthop_compile,
+ route_set_ip_nexthop_free
+};
+
+/* `set local-preference LOCAL_PREF' */
+
+/* Set local preference. */
+route_map_result_t
+route_set_local_pref (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ u_int32_t *local_pref;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ /* Fetch routemap's rule information. */
+ local_pref = rule;
+ bgp_info = object;
+
+ /* Set local preference value. */
+ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
+ bgp_info->attr->local_pref = *local_pref;
+ }
+
+ return RMAP_OKAY;
+}
+
+/* set local preference compilation. */
+void *
+route_set_local_pref_compile (char *arg)
+{
+ u_int32_t *local_pref;
+ char *endptr = NULL;
+
+ /* Local preference value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+ *local_pref = strtoul (arg, &endptr, 10);
+ if (*endptr != '\0' || *local_pref == ULONG_MAX)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, local_pref);
+ return NULL;
+ }
+ return local_pref;
+}
+
+/* Free route map's local preference value. */
+void
+route_set_local_pref_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set local preference rule structure. */
+struct route_map_rule_cmd route_set_local_pref_cmd =
+{
+ "local-preference",
+ route_set_local_pref,
+ route_set_local_pref_compile,
+ route_set_local_pref_free,
+};
+
+/* `set weight WEIGHT' */
+
+/* Set weight. */
+route_map_result_t
+route_set_weight (void *rule, struct prefix *prefix, route_map_object_t type,
+ void *object)
+{
+ u_int32_t *weight;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ /* Fetch routemap's rule information. */
+ weight = rule;
+ bgp_info = object;
+
+ /* Set weight value. */
+ bgp_info->attr->weight = *weight;
+ }
+
+ return RMAP_OKAY;
+}
+
+/* set local preference compilation. */
+void *
+route_set_weight_compile (char *arg)
+{
+ u_int32_t *weight;
+ char *endptr = NULL;
+
+ /* Local preference value shoud be integer. */
+ if (! all_digit (arg))
+ return NULL;
+
+ weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));
+ *weight = strtoul (arg, &endptr, 10);
+ if (*endptr != '\0' || *weight == ULONG_MAX)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, weight);
+ return NULL;
+ }
+ return weight;
+}
+
+/* Free route map's local preference value. */
+void
+route_set_weight_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set local preference rule structure. */
+struct route_map_rule_cmd route_set_weight_cmd =
+{
+ "weight",
+ route_set_weight,
+ route_set_weight_compile,
+ route_set_weight_free,
+};
+
+/* `set metric METRIC' */
+
+/* Set metric to attribute. */
+route_map_result_t
+route_set_metric (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ char *metric;
+ u_int32_t metric_val;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ /* Fetch routemap's rule information. */
+ metric = rule;
+ bgp_info = object;
+
+ if (! (bgp_info->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)))
+ bgp_info->attr->med = 0;
+ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
+
+ if (all_digit (metric))
+ {
+ metric_val = strtoul (metric, (char **)NULL, 10);
+ bgp_info->attr->med = metric_val;
+ }
+ else
+ {
+ metric_val = strtoul (metric+1, (char **)NULL, 10);
+
+ if (strncmp (metric, "+", 1) == 0)
+ {
+ if (bgp_info->attr->med/2 + metric_val/2 > ULONG_MAX/2)
+ bgp_info->attr->med = ULONG_MAX-1;
+ else
+ bgp_info->attr->med += metric_val;
+ }
+ else if (strncmp (metric, "-", 1) == 0)
+ {
+ if (bgp_info->attr->med <= metric_val)
+ bgp_info->attr->med = 0;
+ else
+ bgp_info->attr->med -= metric_val;
+ }
+ }
+ }
+ return RMAP_OKAY;
+}
+
+/* set metric compilation. */
+void *
+route_set_metric_compile (char *arg)
+{
+ u_int32_t metric;
+ char *endptr = NULL;
+
+ if (all_digit (arg))
+ {
+ /* set metric value check*/
+ metric = strtoul (arg, &endptr, 10);
+ if (*endptr != '\0' || metric == ULONG_MAX)
+ return NULL;
+ }
+ else
+ {
+ /* set metric +/-value check */
+ if ((strncmp (arg, "+", 1) != 0
+ && strncmp (arg, "-", 1) != 0)
+ || (! all_digit (arg+1)))
+ return NULL;
+
+ metric = strtoul (arg+1, &endptr, 10);
+ if (*endptr != '\0' || metric == ULONG_MAX)
+ return NULL;
+ }
+
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+/* Free route map's compiled `set metric' value. */
+void
+route_set_metric_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_metric_cmd =
+{
+ "metric",
+ route_set_metric,
+ route_set_metric_compile,
+ route_set_metric_free,
+};
+
+/* `set as-path prepend ASPATH' */
+
+/* For AS path prepend mechanism. */
+route_map_result_t
+route_set_aspath_prepend (void *rule, struct prefix *prefix, route_map_object_t type, void *object)
+{
+ struct aspath *aspath;
+ struct aspath *new;
+ struct bgp_info *binfo;
+
+ if (type == RMAP_BGP)
+ {
+ aspath = rule;
+ binfo = object;
+
+ if (binfo->attr->aspath->refcnt)
+ new = aspath_dup (binfo->attr->aspath);
+ else
+ new = binfo->attr->aspath;
+
+ aspath_prepend (aspath, new);
+ binfo->attr->aspath = new;
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Compile function for as-path prepend. */
+void *
+route_set_aspath_prepend_compile (char *arg)
+{
+ struct aspath *aspath;
+
+ aspath = aspath_str2aspath (arg);
+ if (! aspath)
+ return NULL;
+ return aspath;
+}
+
+/* Compile function for as-path prepend. */
+void
+route_set_aspath_prepend_free (void *rule)
+{
+ struct aspath *aspath = rule;
+ aspath_free (aspath);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_aspath_prepend_cmd =
+{
+ "as-path prepend",
+ route_set_aspath_prepend,
+ route_set_aspath_prepend_compile,
+ route_set_aspath_prepend_free,
+};
+
+/* `set community COMMUNITY' */
+struct rmap_com_set
+{
+ struct community *com;
+ int additive;
+ int none;
+};
+
+/* For community set mechanism. */
+route_map_result_t
+route_set_community (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct rmap_com_set *rcs;
+ struct bgp_info *binfo;
+ struct attr *attr;
+ struct community *new = NULL;
+ struct community *old;
+ struct community *merge;
+
+ if (type == RMAP_BGP)
+ {
+ rcs = rule;
+ binfo = object;
+ attr = binfo->attr;
+ old = attr->community;
+
+ /* "none" case. */
+ if (rcs->none)
+ {
+ attr->flag &= ~(ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES));
+ attr->community = NULL;
+ return RMAP_OKAY;
+ }
+
+ /* "additive" case. */
+ if (rcs->additive && old)
+ {
+ merge = community_merge (community_dup (old), rcs->com);
+ new = community_uniq_sort (merge);
+ community_free (merge);
+ }
+ else
+ new = community_dup (rcs->com);
+
+ attr->community = new;
+ attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+void *
+route_set_community_compile (char *arg)
+{
+ struct rmap_com_set *rcs;
+ struct community *com = NULL;
+ char *sp;
+ int additive = 0;
+ int none = 0;
+
+ if (strcmp (arg, "none") == 0)
+ none = 1;
+ else
+ {
+ sp = strstr (arg, "additive");
+
+ if (sp && sp > arg)
+ {
+ /* "additive" keyworkd is included. */
+ additive = 1;
+ *(sp - 1) = '\0';
+ }
+
+ com = community_str2com (arg);
+
+ if (additive)
+ *(sp - 1) = ' ';
+
+ if (! com)
+ return NULL;
+ }
+
+ rcs = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct rmap_com_set));
+ memset (rcs, 0, sizeof (struct rmap_com_set));
+
+ rcs->com = com;
+ rcs->additive = additive;
+ rcs->none = none;
+
+ return rcs;
+}
+
+/* Free function for set community. */
+void
+route_set_community_free (void *rule)
+{
+ struct rmap_com_set *rcs = rule;
+
+ if (rcs->com)
+ community_free (rcs->com);
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rcs);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_community_cmd =
+{
+ "community",
+ route_set_community,
+ route_set_community_compile,
+ route_set_community_free,
+};
+
+/* `set comm-list (<1-99>|<100-199>|WORD) delete' */
+
+/* For community set mechanism. */
+route_map_result_t
+route_set_community_delete (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct community_list *list;
+ struct community *merge;
+ struct community *new;
+ struct community *old;
+ struct bgp_info *binfo;
+
+ if (type == RMAP_BGP)
+ {
+ if (! rule)
+ return RMAP_OKAY;
+
+ binfo = object;
+ list = community_list_lookup (bgp_clist, rule, COMMUNITY_LIST_AUTO);
+ old = binfo->attr->community;
+
+ if (list && old)
+ {
+ merge = community_list_match_delete (community_dup (old), list);
+ new = community_uniq_sort (merge);
+ community_free (merge);
+
+ if (new->size == 0)
+ {
+ binfo->attr->community = NULL;
+ binfo->attr->flag &= ~ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
+ community_free (new);
+ }
+ else
+ {
+ binfo->attr->community = new;
+ binfo->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
+ }
+ }
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+void *
+route_set_community_delete_compile (char *arg)
+{
+ char *p;
+ char *str;
+ int len;
+
+ p = strchr (arg, ' ');
+ if (p)
+ {
+ len = p - arg;
+ str = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, len + 1);
+ memcpy (str, arg, len);
+ }
+ else
+ str = NULL;
+
+ return str;
+}
+
+/* Free function for set community. */
+void
+route_set_community_delete_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_community_delete_cmd =
+{
+ "comm-list",
+ route_set_community_delete,
+ route_set_community_delete_compile,
+ route_set_community_delete_free,
+};
+
+/* `set extcommunity rt COMMUNITY' */
+
+/* For community set mechanism. */
+route_map_result_t
+route_set_ecommunity_rt (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct ecommunity *ecom;
+ struct ecommunity *new_ecom;
+ struct ecommunity *old_ecom;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ ecom = rule;
+ bgp_info = object;
+
+ if (! ecom)
+ return RMAP_OKAY;
+
+ /* We assume additive for Extended Community. */
+ old_ecom = bgp_info->attr->ecommunity;
+
+ if (old_ecom)
+ new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom);
+ else
+ new_ecom = ecommunity_dup (ecom);
+
+ bgp_info->attr->ecommunity = new_ecom;
+
+ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
+ }
+ return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+void *
+route_set_ecommunity_rt_compile (char *arg)
+{
+ struct ecommunity *ecom;
+
+ ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0);
+ if (! ecom)
+ return NULL;
+ return ecom;
+}
+
+/* Free function for set community. */
+void
+route_set_ecommunity_rt_free (void *rule)
+{
+ struct ecommunity *ecom = rule;
+ ecommunity_free (ecom);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_ecommunity_rt_cmd =
+{
+ "extcommunity rt",
+ route_set_ecommunity_rt,
+ route_set_ecommunity_rt_compile,
+ route_set_ecommunity_rt_free,
+};
+
+/* `set extcommunity soo COMMUNITY' */
+
+/* For community set mechanism. */
+route_map_result_t
+route_set_ecommunity_soo (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct ecommunity *ecom;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ ecom = rule;
+ bgp_info = object;
+
+ if (! ecom)
+ return RMAP_OKAY;
+
+ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
+ bgp_info->attr->ecommunity = ecommunity_dup (ecom);
+ }
+ return RMAP_OKAY;
+}
+
+/* Compile function for set community. */
+void *
+route_set_ecommunity_soo_compile (char *arg)
+{
+ struct ecommunity *ecom;
+
+ ecom = ecommunity_str2com (arg, ECOMMUNITY_SITE_ORIGIN, 0);
+ if (! ecom)
+ return NULL;
+
+ return ecom;
+}
+
+/* Free function for set community. */
+void
+route_set_ecommunity_soo_free (void *rule)
+{
+ struct ecommunity *ecom = rule;
+ ecommunity_free (ecom);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_ecommunity_soo_cmd =
+{
+ "extcommunity soo",
+ route_set_ecommunity_soo,
+ route_set_ecommunity_soo_compile,
+ route_set_ecommunity_soo_free,
+};
+
+/* `set origin ORIGIN' */
+
+/* For origin set. */
+route_map_result_t
+route_set_origin (void *rule, struct prefix *prefix, route_map_object_t type, void *object)
+{
+ u_char *origin;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ origin = rule;
+ bgp_info = object;
+
+ bgp_info->attr->origin = *origin;
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Compile function for origin set. */
+void *
+route_set_origin_compile (char *arg)
+{
+ u_char *origin;
+
+ origin = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_char));
+
+ if (strcmp (arg, "igp") == 0)
+ *origin = 0;
+ else if (strcmp (arg, "egp") == 0)
+ *origin = 1;
+ else
+ *origin = 2;
+
+ return origin;
+}
+
+/* Compile function for origin set. */
+void
+route_set_origin_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_origin_cmd =
+{
+ "origin",
+ route_set_origin,
+ route_set_origin_compile,
+ route_set_origin_free,
+};
+
+/* `set atomic-aggregate' */
+
+/* For atomic aggregate set. */
+route_map_result_t
+route_set_atomic_aggregate (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ bgp_info = object;
+ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Compile function for atomic aggregate. */
+void *
+route_set_atomic_aggregate_compile (char *arg)
+{
+ return (void *)1;
+}
+
+/* Compile function for atomic aggregate. */
+void
+route_set_atomic_aggregate_free (void *rule)
+{
+ return;
+}
+
+/* Set atomic aggregate rule structure. */
+struct route_map_rule_cmd route_set_atomic_aggregate_cmd =
+{
+ "atomic-aggregate",
+ route_set_atomic_aggregate,
+ route_set_atomic_aggregate_compile,
+ route_set_atomic_aggregate_free,
+};
+
+/* `set aggregator as AS A.B.C.D' */
+struct aggregator
+{
+ as_t as;
+ struct in_addr address;
+};
+
+route_map_result_t
+route_set_aggregator_as (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct bgp_info *bgp_info;
+ struct aggregator *aggregator;
+
+ if (type == RMAP_BGP)
+ {
+ bgp_info = object;
+ aggregator = rule;
+
+ bgp_info->attr->aggregator_as = aggregator->as;
+ bgp_info->attr->aggregator_addr = aggregator->address;
+ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
+ }
+
+ return RMAP_OKAY;
+}
+
+void *
+route_set_aggregator_as_compile (char *arg)
+{
+ struct aggregator *aggregator;
+ char as[10];
+ char address[20];
+
+ aggregator = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct aggregator));
+ memset (aggregator, 0, sizeof (struct aggregator));
+
+ sscanf (arg, "%s %s", as, address);
+
+ aggregator->as = strtoul (as, NULL, 10);
+ inet_aton (address, &aggregator->address);
+
+ return aggregator;
+}
+
+void
+route_set_aggregator_as_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_set_aggregator_as_cmd =
+{
+ "aggregator as",
+ route_set_aggregator_as,
+ route_set_aggregator_as_compile,
+ route_set_aggregator_as_free,
+};
+
+#ifdef HAVE_IPV6
+/* `match ipv6 address IP_ACCESS_LIST' */
+
+route_map_result_t
+route_match_ipv6_address (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct access_list *alist;
+
+ if (type == RMAP_BGP)
+ {
+ alist = access_list_lookup (AFI_IP6, (char *) rule);
+ if (alist == NULL)
+ return RMAP_NOMATCH;
+
+ return (access_list_apply (alist, prefix) == FILTER_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+void *
+route_match_ipv6_address_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ipv6_address_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip address matching. */
+struct route_map_rule_cmd route_match_ipv6_address_cmd =
+{
+ "ipv6 address",
+ route_match_ipv6_address,
+ route_match_ipv6_address_compile,
+ route_match_ipv6_address_free
+};
+
+/* `match ipv6 next-hop IP_ADDRESS' */
+
+route_map_result_t
+route_match_ipv6_next_hop (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct in6_addr *addr;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ addr = rule;
+ bgp_info = object;
+
+ if (IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_global, rule))
+ return RMAP_MATCH;
+
+ if (bgp_info->attr->mp_nexthop_len == 32 &&
+ IPV6_ADDR_SAME (&bgp_info->attr->mp_nexthop_local, rule))
+ return RMAP_MATCH;
+
+ return RMAP_NOMATCH;
+ }
+
+ return RMAP_NOMATCH;
+}
+
+void *
+route_match_ipv6_next_hop_compile (char *arg)
+{
+ struct in6_addr *address;
+ int ret;
+
+ address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr));
+
+ ret = inet_pton (AF_INET6, arg, address);
+ if (!ret)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+ return NULL;
+ }
+
+ return address;
+}
+
+void
+route_match_ipv6_next_hop_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ipv6_next_hop_cmd =
+{
+ "ipv6 next-hop",
+ route_match_ipv6_next_hop,
+ route_match_ipv6_next_hop_compile,
+ route_match_ipv6_next_hop_free
+};
+
+/* `match ipv6 address prefix-list PREFIX_LIST' */
+
+route_map_result_t
+route_match_ipv6_address_prefix_list (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct prefix_list *plist;
+
+ if (type == RMAP_BGP)
+ {
+ plist = prefix_list_lookup (AFI_IP6, (char *) rule);
+ if (plist == NULL)
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply (plist, prefix) == PREFIX_DENY ?
+ RMAP_NOMATCH : RMAP_MATCH);
+ }
+ return RMAP_NOMATCH;
+}
+
+void *
+route_match_ipv6_address_prefix_list_compile (char *arg)
+{
+ return XSTRDUP (MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+void
+route_match_ipv6_address_prefix_list_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd =
+{
+ "ipv6 address prefix-list",
+ route_match_ipv6_address_prefix_list,
+ route_match_ipv6_address_prefix_list_compile,
+ route_match_ipv6_address_prefix_list_free
+};
+
+/* `set ipv6 nexthop global IP_ADDRESS' */
+
+/* Set nexthop to object. ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct in6_addr *address;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ /* Fetch routemap's rule information. */
+ address = rule;
+ bgp_info = object;
+
+ /* Set next hop value. */
+ bgp_info->attr->mp_nexthop_global = *address;
+
+ /* Set nexthop length. */
+ if (bgp_info->attr->mp_nexthop_len == 0)
+ bgp_info->attr->mp_nexthop_len = 16;
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Route map `ip next-hop' compile function. Given string is converted
+ to struct in_addr structure. */
+void *
+route_set_ipv6_nexthop_global_compile (char *arg)
+{
+ int ret;
+ struct in6_addr *address;
+
+ address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr));
+
+ ret = inet_pton (AF_INET6, arg, address);
+
+ if (ret == 0)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+ return NULL;
+ }
+
+ return address;
+}
+
+/* Free route map's compiled `ip next-hop' value. */
+void
+route_set_ipv6_nexthop_global_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd =
+{
+ "ipv6 next-hop global",
+ route_set_ipv6_nexthop_global,
+ route_set_ipv6_nexthop_global_compile,
+ route_set_ipv6_nexthop_global_free
+};
+
+/* `set ipv6 nexthop local IP_ADDRESS' */
+
+/* Set nexthop to object. ojbect must be pointer to struct attr. */
+route_map_result_t
+route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct in6_addr *address;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ /* Fetch routemap's rule information. */
+ address = rule;
+ bgp_info = object;
+
+ /* Set next hop value. */
+ bgp_info->attr->mp_nexthop_local = *address;
+
+ /* Set nexthop length. */
+ if (bgp_info->attr->mp_nexthop_len != 32)
+ bgp_info->attr->mp_nexthop_len = 32;
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Route map `ip nexthop' compile function. Given string is converted
+ to struct in_addr structure. */
+void *
+route_set_ipv6_nexthop_local_compile (char *arg)
+{
+ int ret;
+ struct in6_addr *address;
+
+ address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in6_addr));
+
+ ret = inet_pton (AF_INET6, arg, address);
+
+ if (ret == 0)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+ return NULL;
+ }
+
+ return address;
+}
+
+/* Free route map's compiled `ip nexthop' value. */
+void
+route_set_ipv6_nexthop_local_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd =
+{
+ "ipv6 next-hop local",
+ route_set_ipv6_nexthop_local,
+ route_set_ipv6_nexthop_local_compile,
+ route_set_ipv6_nexthop_local_free
+};
+#endif /* HAVE_IPV6 */
+
+/* `set vpnv4 nexthop A.B.C.D' */
+
+route_map_result_t
+route_set_vpnv4_nexthop (void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
+{
+ struct in_addr *address;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ /* Fetch routemap's rule information. */
+ address = rule;
+ bgp_info = object;
+
+ /* Set next hop value. */
+ bgp_info->attr->mp_nexthop_global_in = *address;
+ }
+
+ return RMAP_OKAY;
+}
+
+void *
+route_set_vpnv4_nexthop_compile (char *arg)
+{
+ int ret;
+ struct in_addr *address;
+
+ address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+ ret = inet_aton (arg, address);
+
+ if (ret == 0)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+ return NULL;
+ }
+
+ return address;
+}
+
+void
+route_set_vpnv4_nexthop_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for ip nexthop set. */
+struct route_map_rule_cmd route_set_vpnv4_nexthop_cmd =
+{
+ "vpnv4 next-hop",
+ route_set_vpnv4_nexthop,
+ route_set_vpnv4_nexthop_compile,
+ route_set_vpnv4_nexthop_free
+};
+
+/* `set originator-id' */
+
+/* For origin set. */
+route_map_result_t
+route_set_originator_id (void *rule, struct prefix *prefix, route_map_object_t type, void *object)
+{
+ struct in_addr *address;
+ struct bgp_info *bgp_info;
+
+ if (type == RMAP_BGP)
+ {
+ address = rule;
+ bgp_info = object;
+
+ bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
+ bgp_info->attr->originator_id = *address;
+ }
+
+ return RMAP_OKAY;
+}
+
+/* Compile function for originator-id set. */
+void *
+route_set_originator_id_compile (char *arg)
+{
+ int ret;
+ struct in_addr *address;
+
+ address = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (struct in_addr));
+
+ ret = inet_aton (arg, address);
+
+ if (ret == 0)
+ {
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, address);
+ return NULL;
+ }
+
+ return address;
+}
+
+/* Compile function for originator_id set. */
+void
+route_set_originator_id_free (void *rule)
+{
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set metric rule structure. */
+struct route_map_rule_cmd route_set_originator_id_cmd =
+{
+ "originator-id",
+ route_set_originator_id,
+ route_set_originator_id_compile,
+ route_set_originator_id_free,
+};
+
+/* Add bgp route map rule. */
+int
+bgp_route_match_add (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_add_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Delete bgp route map rule. */
+int
+bgp_route_match_delete (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_match (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Add bgp route map rule. */
+int
+bgp_route_set_add (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_add_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Delete bgp route map rule. */
+int
+bgp_route_set_delete (struct vty *vty, struct route_map_index *index,
+ char *command, char *arg)
+{
+ int ret;
+
+ ret = route_map_delete_set (index, command, arg);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case RMAP_RULE_MISSING:
+ vty_out (vty, "%% Can't find rule.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ case RMAP_COMPILE_ERROR:
+ vty_out (vty, "%% Argument is malformed.%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ break;
+ }
+ }
+ return CMD_SUCCESS;
+}
+
+/* Hook function for updating route_map assignment. */
+void
+bgp_route_map_update ()
+{
+ int i;
+ afi_t afi;
+ safi_t safi;
+ int direct;
+ struct listnode *nn, *nm;
+ struct bgp *bgp;
+ struct peer *peer;
+ struct peer_group *group;
+ struct bgp_filter *filter;
+ struct bgp_node *bn;
+ struct bgp_static *bgp_static;
+
+ /* For neighbor route-map updates. */
+ LIST_LOOP (bm->bgp, bgp, nn)
+ {
+ LIST_LOOP (bgp->peer, peer, nm)
+ {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ filter = &peer->filter[afi][safi];
+
+ for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+ {
+ if (filter->map[direct].name)
+ filter->map[direct].map =
+ route_map_lookup_by_name (filter->map[direct].name);
+ else
+ filter->map[direct].map = NULL;
+ }
+
+ if (filter->usmap.name)
+ filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
+ else
+ filter->usmap.map = NULL;
+ }
+ }
+ LIST_LOOP (bgp->group, group, nm)
+ {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ filter = &group->conf->filter[afi][safi];
+
+ for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
+ {
+ if (filter->map[direct].name)
+ filter->map[direct].map =
+ route_map_lookup_by_name (filter->map[direct].name);
+ else
+ filter->map[direct].map = NULL;
+ }
+
+ if (filter->usmap.name)
+ filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
+ else
+ filter->usmap.map = NULL;
+ }
+ }
+ }
+
+ /* For default-originate route-map updates. */
+ LIST_LOOP (bm->bgp, bgp, nn)
+ {
+ LIST_LOOP (bgp->peer, peer, nm)
+ {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (peer->default_rmap[afi][safi].name)
+ peer->default_rmap[afi][safi].map =
+ route_map_lookup_by_name (peer->default_rmap[afi][safi].name);
+ else
+ peer->default_rmap[afi][safi].map = NULL;
+ }
+ }
+ }
+
+ /* For network route-map updates. */
+ LIST_LOOP (bm->bgp, bgp, nn)
+ {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ for (bn = bgp_table_top (bgp->route[afi][safi]); bn;
+ bn = bgp_route_next (bn))
+ if ((bgp_static = bn->info) != NULL)
+ {
+ if (bgp_static->rmap.name)
+ bgp_static->rmap.map =
+ route_map_lookup_by_name (bgp_static->rmap.name);
+ else
+ bgp_static->rmap.map = NULL;
+ }
+ }
+
+ /* For redistribute route-map updates. */
+ LIST_LOOP (bm->bgp, bgp, nn)
+ {
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ {
+ if (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name)
+ bgp->rmap[ZEBRA_FAMILY_IPV4][i].map =
+ route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV4][i].name);
+#ifdef HAVE_IPV6
+ if (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name)
+ bgp->rmap[ZEBRA_FAMILY_IPV6][i].map =
+ route_map_lookup_by_name (bgp->rmap[ZEBRA_FAMILY_IPV6][i].name);
+#endif /* HAVE_IPV6 */
+ }
+ }
+}
+
+DEFUN (match_ip_address,
+ match_ip_address_cmd,
+ "match ip address (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "ip address", argv[0]);
+}
+
+DEFUN (no_match_ip_address,
+ no_match_ip_address_cmd,
+ "no match ip address",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n")
+{
+ if (argc == 0)
+ return bgp_route_match_delete (vty, vty->index, "ip address", NULL);
+
+ return bgp_route_match_delete (vty, vty->index, "ip address", argv[0]);
+}
+
+ALIAS (no_match_ip_address,
+ no_match_ip_address_val_cmd,
+ "no match ip address (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+
+DEFUN (match_ip_next_hop,
+ match_ip_next_hop_cmd,
+ "match ip next-hop (<1-199>|<1300-2699>|WORD)",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop,
+ no_match_ip_next_hop_cmd,
+ "no match ip next-hop",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n")
+{
+ if (argc == 0)
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop", NULL);
+
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop,
+ no_match_ip_next_hop_val_cmd,
+ "no match ip next-hop (<1-199>|<1300-2699>|WORD)",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "IP access-list number\n"
+ "IP access-list number (expanded range)\n"
+ "IP Access-list name\n")
+
+DEFUN (match_ip_address_prefix_list,
+ match_ip_address_prefix_list_cmd,
+ "match ip address prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_cmd,
+ "no match ip address prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n")
+{
+ if (argc == 0)
+ return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", NULL);
+
+ return bgp_route_match_delete (vty, vty->index, "ip address prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_address_prefix_list,
+ no_match_ip_address_prefix_list_val_cmd,
+ "no match ip address prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFUN (match_ip_next_hop_prefix_list,
+ match_ip_next_hop_prefix_list_cmd,
+ "match ip next-hop prefix-list WORD",
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_cmd,
+ "no match ip next-hop prefix-list",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n")
+{
+ if (argc == 0)
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", NULL);
+
+ return bgp_route_match_delete (vty, vty->index, "ip next-hop prefix-list", argv[0]);
+}
+
+ALIAS (no_match_ip_next_hop_prefix_list,
+ no_match_ip_next_hop_prefix_list_val_cmd,
+ "no match ip next-hop prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IP_STR
+ "Match next-hop address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+
+DEFUN (match_metric,
+ match_metric_cmd,
+ "match metric <0-4294967295>",
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+{
+ return bgp_route_match_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_match_metric,
+ no_match_metric_cmd,
+ "no match metric",
+ NO_STR
+ MATCH_STR
+ "Match metric of route\n")
+{
+ if (argc == 0)
+ return bgp_route_match_delete (vty, vty->index, "metric", NULL);
+
+ return bgp_route_match_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_match_metric,
+ no_match_metric_val_cmd,
+ "no match metric <0-4294967295>",
+ NO_STR
+ MATCH_STR
+ "Match metric of route\n"
+ "Metric value\n")
+
+DEFUN (match_community,
+ match_community_cmd,
+ "match community (<1-99>|<100-199>|WORD)",
+ MATCH_STR
+ "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "Community-list name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "community", argv[0]);
+}
+
+DEFUN (match_community_exact,
+ match_community_exact_cmd,
+ "match community (<1-99>|<100-199>|WORD) exact-match",
+ MATCH_STR
+ "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "Community-list name\n"
+ "Do exact matching of communities\n")
+{
+ int ret;
+ char *argstr;
+
+ argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
+ strlen (argv[0]) + strlen ("exact-match") + 2);
+
+ sprintf (argstr, "%s exact-match", argv[0]);
+
+ ret = bgp_route_match_add (vty, vty->index, "community", argstr);
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr);
+
+ return ret;
+}
+
+DEFUN (no_match_community,
+ no_match_community_cmd,
+ "no match community",
+ NO_STR
+ MATCH_STR
+ "Match BGP community list\n")
+{
+ return bgp_route_match_delete (vty, vty->index, "community", NULL);
+}
+
+ALIAS (no_match_community,
+ no_match_community_val_cmd,
+ "no match community (<1-99>|<100-199>|WORD)",
+ NO_STR
+ MATCH_STR
+ "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "Community-list name\n")
+
+ALIAS (no_match_community,
+ no_match_community_exact_cmd,
+ "no match community (<1-99>|<100-199>|WORD) exact-match",
+ NO_STR
+ MATCH_STR
+ "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "Community-list name\n"
+ "Do exact matching of communities\n")
+
+DEFUN (match_aspath,
+ match_aspath_cmd,
+ "match as-path WORD",
+ MATCH_STR
+ "Match BGP AS path list\n"
+ "AS path access-list name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "as-path", argv[0]);
+}
+
+DEFUN (no_match_aspath,
+ no_match_aspath_cmd,
+ "no match as-path",
+ NO_STR
+ MATCH_STR
+ "Match BGP AS path list\n")
+{
+ return bgp_route_match_delete (vty, vty->index, "as-path", NULL);
+}
+
+ALIAS (no_match_aspath,
+ no_match_aspath_val_cmd,
+ "no match as-path WORD",
+ NO_STR
+ MATCH_STR
+ "Match BGP AS path list\n"
+ "AS path access-list name\n")
+
+DEFUN (match_origin,
+ match_origin_cmd,
+ "match origin (egp|igp|incomplete)",
+ MATCH_STR
+ "BGP origin code\n"
+ "remote EGP\n"
+ "local IGP\n"
+ "unknown heritage\n")
+{
+ if (strncmp (argv[0], "igp", 2) == 0)
+ return bgp_route_match_add (vty, vty->index, "origin", "igp");
+ if (strncmp (argv[0], "egp", 1) == 0)
+ return bgp_route_match_add (vty, vty->index, "origin", "egp");
+ if (strncmp (argv[0], "incomplete", 2) == 0)
+ return bgp_route_match_add (vty, vty->index, "origin", "incomplete");
+
+ return CMD_WARNING;
+}
+
+DEFUN (no_match_origin,
+ no_match_origin_cmd,
+ "no match origin",
+ NO_STR
+ MATCH_STR
+ "BGP origin code\n")
+{
+ return bgp_route_match_delete (vty, vty->index, "origin", NULL);
+}
+
+ALIAS (no_match_origin,
+ no_match_origin_val_cmd,
+ "no match origin (egp|igp|incomplete)",
+ NO_STR
+ MATCH_STR
+ "BGP origin code\n"
+ "remote EGP\n"
+ "local IGP\n"
+ "unknown heritage\n")
+
+DEFUN (set_ip_nexthop,
+ set_ip_nexthop_cmd,
+ "set ip next-hop A.B.C.D",
+ SET_STR
+ IP_STR
+ "Next hop address\n"
+ "IP address of next hop\n")
+{
+ union sockunion su;
+ int ret;
+
+ ret = str2sockunion (argv[0], &su);
+ if (ret < 0)
+ {
+ vty_out (vty, "%% Malformed Next-hop address%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ return bgp_route_set_add (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+DEFUN (no_set_ip_nexthop,
+ no_set_ip_nexthop_cmd,
+ "no set ip next-hop",
+ NO_STR
+ SET_STR
+ IP_STR
+ "Next hop address\n")
+{
+ if (argc == 0)
+ return bgp_route_set_delete (vty, vty->index, "ip next-hop", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "ip next-hop", argv[0]);
+}
+
+ALIAS (no_set_ip_nexthop,
+ no_set_ip_nexthop_val_cmd,
+ "no set ip next-hop A.B.C.D",
+ NO_STR
+ SET_STR
+ IP_STR
+ "Next hop address\n"
+ "IP address of next hop\n")
+
+DEFUN (set_metric,
+ set_metric_cmd,
+ "set metric (<0-4294967295>|<+/-metric>)",
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n"
+ "Add or subtract metric\n")
+{
+ return bgp_route_set_add (vty, vty->index, "metric", argv[0]);
+}
+
+DEFUN (no_set_metric,
+ no_set_metric_cmd,
+ "no set metric",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n")
+{
+ if (argc == 0)
+ return bgp_route_set_delete (vty, vty->index, "metric", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "metric", argv[0]);
+}
+
+ALIAS (no_set_metric,
+ no_set_metric_val_cmd,
+ "no set metric <0-4294967295>",
+ NO_STR
+ SET_STR
+ "Metric value for destination routing protocol\n"
+ "Metric value\n")
+
+DEFUN (set_local_pref,
+ set_local_pref_cmd,
+ "set local-preference <0-4294967295>",
+ SET_STR
+ "BGP local preference path attribute\n"
+ "Preference value\n")
+{
+ return bgp_route_set_add (vty, vty->index, "local-preference", argv[0]);
+}
+
+DEFUN (no_set_local_pref,
+ no_set_local_pref_cmd,
+ "no set local-preference",
+ NO_STR
+ SET_STR
+ "BGP local preference path attribute\n")
+{
+ if (argc == 0)
+ return bgp_route_set_delete (vty, vty->index, "local-preference", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "local-preference", argv[0]);
+}
+
+ALIAS (no_set_local_pref,
+ no_set_local_pref_val_cmd,
+ "no set local-preference <0-4294967295>",
+ NO_STR
+ SET_STR
+ "BGP local preference path attribute\n"
+ "Preference value\n")
+
+DEFUN (set_weight,
+ set_weight_cmd,
+ "set weight <0-4294967295>",
+ SET_STR
+ "BGP weight for routing table\n"
+ "Weight value\n")
+{
+ return bgp_route_set_add (vty, vty->index, "weight", argv[0]);
+}
+
+DEFUN (no_set_weight,
+ no_set_weight_cmd,
+ "no set weight",
+ NO_STR
+ SET_STR
+ "BGP weight for routing table\n")
+{
+ if (argc == 0)
+ return bgp_route_set_delete (vty, vty->index, "weight", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "weight", argv[0]);
+}
+
+ALIAS (no_set_weight,
+ no_set_weight_val_cmd,
+ "no set weight <0-4294967295>",
+ NO_STR
+ SET_STR
+ "BGP weight for routing table\n"
+ "Weight value\n")
+
+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"
+ "Prepend to 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 prepend", str);
+ XFREE (MTYPE_TMP, str);
+
+ return ret;
+}
+
+DEFUN (no_set_aspath_prepend,
+ no_set_aspath_prepend_cmd,
+ "no set as-path prepend",
+ NO_STR
+ SET_STR
+ "Prepend string for a BGP AS-path attribute\n"
+ "Prepend to the as-path\n")
+{
+ return bgp_route_set_delete (vty, vty->index, "as-path prepend", NULL);
+}
+
+ALIAS (no_set_aspath_prepend,
+ no_set_aspath_prepend_val_cmd,
+ "no set as-path prepend .<1-65535>",
+ NO_STR
+ SET_STR
+ "Prepend string for a BGP AS-path attribute\n"
+ "Prepend to the as-path\n"
+ "AS number\n")
+
+DEFUN (set_community,
+ set_community_cmd,
+ "set community .AA:NN",
+ SET_STR
+ "BGP community attribute\n"
+ "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n")
+{
+ int i;
+ int first = 0;
+ int additive = 0;
+ struct buffer *b;
+ struct community *com = NULL;
+ char *str;
+ char *argstr;
+ int ret;
+
+ b = buffer_new (1024);
+
+ for (i = 0; i < argc; i++)
+ {
+ if (strncmp (argv[i], "additive", strlen (argv[i])) == 0)
+ {
+ additive = 1;
+ continue;
+ }
+
+ if (first)
+ buffer_putc (b, ' ');
+ else
+ first = 1;
+
+ if (strncmp (argv[i], "internet", strlen (argv[i])) == 0)
+ {
+ buffer_putstr (b, "internet");
+ continue;
+ }
+ if (strncmp (argv[i], "local-AS", strlen (argv[i])) == 0)
+ {
+ buffer_putstr (b, "local-AS");
+ continue;
+ }
+ if (strncmp (argv[i], "no-a", strlen ("no-a")) == 0
+ && strncmp (argv[i], "no-advertise", strlen (argv[i])) == 0)
+ {
+ buffer_putstr (b, "no-advertise");
+ continue;
+ }
+ if (strncmp (argv[i], "no-e", strlen ("no-e"))== 0
+ && strncmp (argv[i], "no-export", strlen (argv[i])) == 0)
+ {
+ buffer_putstr (b, "no-export");
+ continue;
+ }
+ buffer_putstr (b, argv[i]);
+ }
+ buffer_putc (b, '\0');
+
+ /* Fetch result string then compile it to communities attribute. */
+ str = buffer_getstr (b);
+ buffer_free (b);
+
+ if (str)
+ {
+ com = community_str2com (str);
+ free (str);
+ }
+
+ /* Can't compile user input into communities attribute. */
+ if (! com)
+ {
+ vty_out (vty, "%% Malformed communities attribute%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ /* Set communites attribute string. */
+ str = community_str (com);
+
+ if (additive)
+ {
+ argstr = XCALLOC (MTYPE_TMP, strlen (str) + strlen (" additive") + 1);
+ strcpy (argstr, str);
+ strcpy (argstr + strlen (str), " additive");
+ ret = bgp_route_set_add (vty, vty->index, "community", argstr);
+ XFREE (MTYPE_TMP, argstr);
+ }
+ else
+ ret = bgp_route_set_add (vty, vty->index, "community", str);
+
+ community_free (com);
+
+ return ret;
+}
+
+DEFUN (set_community_none,
+ set_community_none_cmd,
+ "set community none",
+ SET_STR
+ "BGP community attribute\n"
+ "No community attribute\n")
+{
+ return bgp_route_set_add (vty, vty->index, "community", "none");
+}
+
+DEFUN (no_set_community,
+ no_set_community_cmd,
+ "no set community",
+ NO_STR
+ SET_STR
+ "BGP community attribute\n")
+{
+ return bgp_route_set_delete (vty, vty->index, "community", NULL);
+}
+
+ALIAS (no_set_community,
+ no_set_community_val_cmd,
+ "no set community .AA:NN",
+ NO_STR
+ SET_STR
+ "BGP community attribute\n"
+ "Community number in aa:nn format or local-AS|no-advertise|no-export|internet or additive\n")
+
+ALIAS (no_set_community,
+ no_set_community_none_cmd,
+ "no set community none",
+ NO_STR
+ SET_STR
+ "BGP community attribute\n"
+ "No community attribute\n")
+
+DEFUN (set_community_delete,
+ set_community_delete_cmd,
+ "set comm-list (<1-99>|<100-199>|WORD) delete",
+ SET_STR
+ "set BGP community list (for deletion)\n"
+ "Community-list number (standard)\n"
+ "Communitly-list number (expanded)\n"
+ "Community-list name\n"
+ "Delete matching communities\n")
+{
+ char *str;
+
+ str = XCALLOC (MTYPE_TMP, strlen (argv[0]) + strlen (" delete") + 1);
+ strcpy (str, argv[0]);
+ strcpy (str + strlen (argv[0]), " delete");
+
+ bgp_route_set_add (vty, vty->index, "comm-list", str);
+
+ XFREE (MTYPE_TMP, str);
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_set_community_delete,
+ no_set_community_delete_cmd,
+ "no set comm-list",
+ NO_STR
+ SET_STR
+ "set BGP community list (for deletion)\n")
+{
+ return bgp_route_set_delete (vty, vty->index, "comm-list", NULL);
+}
+
+ALIAS (no_set_community_delete,
+ no_set_community_delete_val_cmd,
+ "no set comm-list (<1-99>|<100-199>|WORD) delete",
+ NO_STR
+ SET_STR
+ "set BGP community list (for deletion)\n"
+ "Community-list number (standard)\n"
+ "Communitly-list number (expanded)\n"
+ "Community-list name\n"
+ "Delete matching communities\n")
+
+DEFUN (set_ecommunity_rt,
+ set_ecommunity_rt_cmd,
+ "set extcommunity rt .ASN:nn_or_IP-address:nn",
+ SET_STR
+ "BGP extended community attribute\n"
+ "Route Target extened communityt\n"
+ "VPN extended community\n")
+{
+ int ret;
+ char *str;
+
+ str = argv_concat (argv, argc, 0);
+ ret = bgp_route_set_add (vty, vty->index, "extcommunity rt", str);
+ XFREE (MTYPE_TMP, str);
+
+ return ret;
+}
+
+DEFUN (no_set_ecommunity_rt,
+ no_set_ecommunity_rt_cmd,
+ "no set extcommunity rt",
+ NO_STR
+ SET_STR
+ "BGP extended community attribute\n"
+ "Route Target extened communityt\n")
+{
+ return bgp_route_set_delete (vty, vty->index, "extcommunity rt", NULL);
+}
+
+ALIAS (no_set_ecommunity_rt,
+ no_set_ecommunity_rt_val_cmd,
+ "no set extcommunity rt .ASN:nn_or_IP-address:nn",
+ NO_STR
+ SET_STR
+ "BGP extended community attribute\n"
+ "Route Target extened communityt\n"
+ "VPN extended community\n")
+
+DEFUN (set_ecommunity_soo,
+ set_ecommunity_soo_cmd,
+ "set extcommunity soo .ASN:nn_or_IP-address:nn",
+ SET_STR
+ "BGP extended community attribute\n"
+ "Site-of-Origin extended community\n"
+ "VPN extended community\n")
+{
+ int ret;
+ char *str;
+
+ str = argv_concat (argv, argc, 0);
+ ret = bgp_route_set_add (vty, vty->index, "extcommunity soo", str);
+ XFREE (MTYPE_TMP, str);
+ return ret;
+}
+
+DEFUN (no_set_ecommunity_soo,
+ no_set_ecommunity_soo_cmd,
+ "no set extcommunity soo",
+ NO_STR
+ SET_STR
+ "BGP extended community attribute\n"
+ "Site-of-Origin extended community\n")
+{
+ return bgp_route_set_delete (vty, vty->index, "extcommunity soo", NULL);
+}
+
+ALIAS (no_set_ecommunity_soo,
+ no_set_ecommunity_soo_val_cmd,
+ "no set extcommunity soo .ASN:nn_or_IP-address:nn",
+ NO_STR
+ SET_STR
+ "BGP extended community attribute\n"
+ "Site-of-Origin extended community\n"
+ "VPN extended community\n")
+
+DEFUN (set_origin,
+ set_origin_cmd,
+ "set origin (egp|igp|incomplete)",
+ SET_STR
+ "BGP origin code\n"
+ "remote EGP\n"
+ "local IGP\n"
+ "unknown heritage\n")
+{
+ if (strncmp (argv[0], "igp", 2) == 0)
+ return bgp_route_set_add (vty, vty->index, "origin", "igp");
+ if (strncmp (argv[0], "egp", 1) == 0)
+ return bgp_route_set_add (vty, vty->index, "origin", "egp");
+ if (strncmp (argv[0], "incomplete", 2) == 0)
+ return bgp_route_set_add (vty, vty->index, "origin", "incomplete");
+
+ return CMD_WARNING;
+}
+
+DEFUN (no_set_origin,
+ no_set_origin_cmd,
+ "no set origin",
+ NO_STR
+ SET_STR
+ "BGP origin code\n")
+{
+ return bgp_route_set_delete (vty, vty->index, "origin", NULL);
+}
+
+ALIAS (no_set_origin,
+ no_set_origin_val_cmd,
+ "no set origin (egp|igp|incomplete)",
+ NO_STR
+ SET_STR
+ "BGP origin code\n"
+ "remote EGP\n"
+ "local IGP\n"
+ "unknown heritage\n")
+
+DEFUN (set_atomic_aggregate,
+ set_atomic_aggregate_cmd,
+ "set atomic-aggregate",
+ SET_STR
+ "BGP atomic aggregate attribute\n" )
+{
+ return bgp_route_set_add (vty, vty->index, "atomic-aggregate", NULL);
+}
+
+DEFUN (no_set_atomic_aggregate,
+ no_set_atomic_aggregate_cmd,
+ "no set atomic-aggregate",
+ NO_STR
+ SET_STR
+ "BGP atomic aggregate attribute\n" )
+{
+ return bgp_route_set_delete (vty, vty->index, "atomic-aggregate", NULL);
+}
+
+DEFUN (set_aggregator_as,
+ set_aggregator_as_cmd,
+ "set aggregator as <1-65535> A.B.C.D",
+ SET_STR
+ "BGP aggregator attribute\n"
+ "AS number of aggregator\n"
+ "AS number\n"
+ "IP address of aggregator\n")
+{
+ int ret;
+ as_t as;
+ struct in_addr address;
+ char *endptr = NULL;
+ char *argstr;
+
+ as = strtoul (argv[0], &endptr, 10);
+ if (as == 0 || as == ULONG_MAX || *endptr != '\0')
+ {
+ vty_out (vty, "AS path value malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = inet_aton (argv[1], &address);
+ if (ret == 0)
+ {
+ vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
+ strlen (argv[0]) + strlen (argv[1]) + 2);
+
+ sprintf (argstr, "%s %s", argv[0], argv[1]);
+
+ ret = bgp_route_set_add (vty, vty->index, "aggregator as", argstr);
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr);
+
+ return ret;
+}
+
+DEFUN (no_set_aggregator_as,
+ no_set_aggregator_as_cmd,
+ "no set aggregator as",
+ NO_STR
+ SET_STR
+ "BGP aggregator attribute\n"
+ "AS number of aggregator\n")
+{
+ int ret;
+ as_t as;
+ struct in_addr address;
+ char *endptr = NULL;
+ char *argstr;
+
+ if (argv == 0)
+ return bgp_route_set_delete (vty, vty->index, "aggregator as", NULL);
+
+ as = strtoul (argv[0], &endptr, 10);
+ if (as == 0 || as == ULONG_MAX || *endptr != '\0')
+ {
+ vty_out (vty, "AS path value malformed%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ ret = inet_aton (argv[1], &address);
+ if (ret == 0)
+ {
+ vty_out (vty, "Aggregator IP address is invalid%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ argstr = XMALLOC (MTYPE_ROUTE_MAP_COMPILED,
+ strlen (argv[0]) + strlen (argv[1]) + 2);
+
+ sprintf (argstr, "%s %s", argv[0], argv[1]);
+
+ ret = bgp_route_set_delete (vty, vty->index, "aggregator as", argstr);
+
+ XFREE (MTYPE_ROUTE_MAP_COMPILED, argstr);
+
+ return ret;
+}
+
+ALIAS (no_set_aggregator_as,
+ no_set_aggregator_as_val_cmd,
+ "no set aggregator as <1-65535> A.B.C.D",
+ NO_STR
+ SET_STR
+ "BGP aggregator attribute\n"
+ "AS number of aggregator\n"
+ "AS number\n"
+ "IP address of aggregator\n")
+
+
+#ifdef HAVE_IPV6
+DEFUN (match_ipv6_address,
+ match_ipv6_address_cmd,
+ "match ipv6 address WORD",
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "ipv6 address", argv[0]);
+}
+
+DEFUN (no_match_ipv6_address,
+ no_match_ipv6_address_cmd,
+ "no match ipv6 address WORD",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 address of route\n"
+ "IPv6 access-list name\n")
+{
+ return bgp_route_match_delete (vty, vty->index, "ipv6 address", argv[0]);
+}
+
+DEFUN (match_ipv6_next_hop,
+ match_ipv6_next_hop_cmd,
+ "match ipv6 next-hop X:X::X:X",
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 next-hop address of route\n"
+ "IPv6 address of next hop\n")
+{
+ return bgp_route_match_add (vty, vty->index, "ipv6 next-hop", argv[0]);
+}
+
+DEFUN (no_match_ipv6_next_hop,
+ no_match_ipv6_next_hop_cmd,
+ "no match ipv6 next-hop X:X::X:X",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match IPv6 next-hop address of route\n"
+ "IPv6 address of next hop\n")
+{
+ return bgp_route_match_delete (vty, vty->index, "ipv6 next-hop", argv[0]);
+}
+
+DEFUN (match_ipv6_address_prefix_list,
+ match_ipv6_address_prefix_list_cmd,
+ "match ipv6 address prefix-list WORD",
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return bgp_route_match_add (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+}
+
+DEFUN (no_match_ipv6_address_prefix_list,
+ no_match_ipv6_address_prefix_list_cmd,
+ "no match ipv6 address prefix-list WORD",
+ NO_STR
+ MATCH_STR
+ IPV6_STR
+ "Match address of route\n"
+ "Match entries of prefix-lists\n"
+ "IP prefix-list name\n")
+{
+ return bgp_route_match_delete (vty, vty->index, "ipv6 address prefix-list", argv[0]);
+}
+
+DEFUN (set_ipv6_nexthop_global,
+ set_ipv6_nexthop_global_cmd,
+ "set ipv6 next-hop global X:X::X:X",
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 global address\n"
+ "IPv6 address of next hop\n")
+{
+ return bgp_route_set_add (vty, vty->index, "ipv6 next-hop global", argv[0]);
+}
+
+DEFUN (no_set_ipv6_nexthop_global,
+ no_set_ipv6_nexthop_global_cmd,
+ "no set ipv6 next-hop global",
+ NO_STR
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 global address\n")
+{
+ if (argc == 0)
+ return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop global", argv[0]);
+}
+
+ALIAS (no_set_ipv6_nexthop_global,
+ no_set_ipv6_nexthop_global_val_cmd,
+ "no set ipv6 next-hop global X:X::X:X",
+ NO_STR
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 global address\n"
+ "IPv6 address of next hop\n")
+
+DEFUN (set_ipv6_nexthop_local,
+ set_ipv6_nexthop_local_cmd,
+ "set ipv6 next-hop local X:X::X:X",
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+{
+ return bgp_route_set_add (vty, vty->index, "ipv6 next-hop local", argv[0]);
+}
+
+DEFUN (no_set_ipv6_nexthop_local,
+ no_set_ipv6_nexthop_local_cmd,
+ "no set ipv6 next-hop local",
+ NO_STR
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n")
+{
+ if (argc == 0)
+ return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop local", argv[0]);
+}
+
+ALIAS (no_set_ipv6_nexthop_local,
+ no_set_ipv6_nexthop_local_val_cmd,
+ "no set ipv6 next-hop local X:X::X:X",
+ NO_STR
+ SET_STR
+ IPV6_STR
+ "IPv6 next-hop address\n"
+ "IPv6 local address\n"
+ "IPv6 address of next hop\n")
+#endif /* HAVE_IPV6 */
+
+DEFUN (set_vpnv4_nexthop,
+ set_vpnv4_nexthop_cmd,
+ "set vpnv4 next-hop A.B.C.D",
+ SET_STR
+ "VPNv4 information\n"
+ "VPNv4 next-hop address\n"
+ "IP address of next hop\n")
+{
+ return bgp_route_set_add (vty, vty->index, "vpnv4 next-hop", argv[0]);
+}
+
+DEFUN (no_set_vpnv4_nexthop,
+ no_set_vpnv4_nexthop_cmd,
+ "no set vpnv4 next-hop",
+ NO_STR
+ SET_STR
+ "VPNv4 information\n"
+ "VPNv4 next-hop address\n")
+{
+ if (argc == 0)
+ return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "vpnv4 next-hop", argv[0]);
+}
+
+ALIAS (no_set_vpnv4_nexthop,
+ no_set_vpnv4_nexthop_val_cmd,
+ "no set vpnv4 next-hop A.B.C.D",
+ NO_STR
+ SET_STR
+ "VPNv4 information\n"
+ "VPNv4 next-hop address\n"
+ "IP address of next hop\n")
+
+DEFUN (set_originator_id,
+ set_originator_id_cmd,
+ "set originator-id A.B.C.D",
+ SET_STR
+ "BGP originator ID attribute\n"
+ "IP address of originator\n")
+{
+ return bgp_route_set_add (vty, vty->index, "originator-id", argv[0]);
+}
+
+DEFUN (no_set_originator_id,
+ no_set_originator_id_cmd,
+ "no set originator-id",
+ NO_STR
+ SET_STR
+ "BGP originator ID attribute\n")
+{
+ if (argc == 0)
+ return bgp_route_set_delete (vty, vty->index, "originator-id", NULL);
+
+ return bgp_route_set_delete (vty, vty->index, "originator-id", argv[0]);
+}
+
+ALIAS (no_set_originator_id,
+ no_set_originator_id_val_cmd,
+ "no set originator-id A.B.C.D",
+ NO_STR
+ SET_STR
+ "BGP originator ID attribute\n"
+ "IP address of originator\n")
+
+
+/* Initialization of route map. */
+void
+bgp_route_map_init ()
+{
+ route_map_init ();
+ route_map_init_vty ();
+ route_map_add_hook (bgp_route_map_update);
+ route_map_delete_hook (bgp_route_map_update);
+
+ route_map_install_match (&route_match_ip_address_cmd);
+ route_map_install_match (&route_match_ip_next_hop_cmd);
+ route_map_install_match (&route_match_ip_address_prefix_list_cmd);
+ route_map_install_match (&route_match_ip_next_hop_prefix_list_cmd);
+ route_map_install_match (&route_match_aspath_cmd);
+ route_map_install_match (&route_match_community_cmd);
+ route_map_install_match (&route_match_metric_cmd);
+ route_map_install_match (&route_match_origin_cmd);
+
+ route_map_install_set (&route_set_ip_nexthop_cmd);
+ route_map_install_set (&route_set_local_pref_cmd);
+ 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_origin_cmd);
+ route_map_install_set (&route_set_atomic_aggregate_cmd);
+ route_map_install_set (&route_set_aggregator_as_cmd);
+ route_map_install_set (&route_set_community_cmd);
+ route_map_install_set (&route_set_community_delete_cmd);
+ route_map_install_set (&route_set_vpnv4_nexthop_cmd);
+ route_map_install_set (&route_set_originator_id_cmd);
+ route_map_install_set (&route_set_ecommunity_rt_cmd);
+ route_map_install_set (&route_set_ecommunity_soo_cmd);
+
+ install_element (RMAP_NODE, &match_ip_address_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_val_cmd);
+ install_element (RMAP_NODE, &match_ip_next_hop_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_val_cmd);
+
+ install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd);
+ install_element (RMAP_NODE, &match_ip_next_hop_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ip_next_hop_prefix_list_val_cmd);
+
+ install_element (RMAP_NODE, &match_aspath_cmd);
+ install_element (RMAP_NODE, &no_match_aspath_cmd);
+ install_element (RMAP_NODE, &no_match_aspath_val_cmd);
+ install_element (RMAP_NODE, &match_metric_cmd);
+ install_element (RMAP_NODE, &no_match_metric_cmd);
+ install_element (RMAP_NODE, &no_match_metric_val_cmd);
+ install_element (RMAP_NODE, &match_community_cmd);
+ install_element (RMAP_NODE, &match_community_exact_cmd);
+ install_element (RMAP_NODE, &no_match_community_cmd);
+ install_element (RMAP_NODE, &no_match_community_val_cmd);
+ install_element (RMAP_NODE, &no_match_community_exact_cmd);
+ install_element (RMAP_NODE, &match_origin_cmd);
+ install_element (RMAP_NODE, &no_match_origin_cmd);
+ install_element (RMAP_NODE, &no_match_origin_val_cmd);
+
+ install_element (RMAP_NODE, &set_ip_nexthop_cmd);
+ install_element (RMAP_NODE, &no_set_ip_nexthop_cmd);
+ install_element (RMAP_NODE, &no_set_ip_nexthop_val_cmd);
+ install_element (RMAP_NODE, &set_local_pref_cmd);
+ install_element (RMAP_NODE, &no_set_local_pref_cmd);
+ install_element (RMAP_NODE, &no_set_local_pref_val_cmd);
+ install_element (RMAP_NODE, &set_weight_cmd);
+ install_element (RMAP_NODE, &no_set_weight_cmd);
+ install_element (RMAP_NODE, &no_set_weight_val_cmd);
+ install_element (RMAP_NODE, &set_metric_cmd);
+ 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, &no_set_aspath_prepend_cmd);
+ install_element (RMAP_NODE, &no_set_aspath_prepend_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);
+ install_element (RMAP_NODE, &set_atomic_aggregate_cmd);
+ install_element (RMAP_NODE, &no_set_atomic_aggregate_cmd);
+ install_element (RMAP_NODE, &set_aggregator_as_cmd);
+ install_element (RMAP_NODE, &no_set_aggregator_as_cmd);
+ install_element (RMAP_NODE, &no_set_aggregator_as_val_cmd);
+ install_element (RMAP_NODE, &set_community_cmd);
+ install_element (RMAP_NODE, &set_community_none_cmd);
+ install_element (RMAP_NODE, &no_set_community_cmd);
+ install_element (RMAP_NODE, &no_set_community_val_cmd);
+ install_element (RMAP_NODE, &no_set_community_none_cmd);
+ install_element (RMAP_NODE, &set_community_delete_cmd);
+ install_element (RMAP_NODE, &no_set_community_delete_cmd);
+ install_element (RMAP_NODE, &no_set_community_delete_val_cmd);
+ install_element (RMAP_NODE, &set_ecommunity_rt_cmd);
+ install_element (RMAP_NODE, &no_set_ecommunity_rt_cmd);
+ install_element (RMAP_NODE, &no_set_ecommunity_rt_val_cmd);
+ install_element (RMAP_NODE, &set_ecommunity_soo_cmd);
+ install_element (RMAP_NODE, &no_set_ecommunity_soo_cmd);
+ install_element (RMAP_NODE, &no_set_ecommunity_soo_val_cmd);
+ install_element (RMAP_NODE, &set_vpnv4_nexthop_cmd);
+ install_element (RMAP_NODE, &no_set_vpnv4_nexthop_cmd);
+ install_element (RMAP_NODE, &no_set_vpnv4_nexthop_val_cmd);
+ install_element (RMAP_NODE, &set_originator_id_cmd);
+ install_element (RMAP_NODE, &no_set_originator_id_cmd);
+ install_element (RMAP_NODE, &no_set_originator_id_val_cmd);
+
+#ifdef HAVE_IPV6
+ route_map_install_match (&route_match_ipv6_address_cmd);
+ route_map_install_match (&route_match_ipv6_next_hop_cmd);
+ route_map_install_match (&route_match_ipv6_address_prefix_list_cmd);
+ route_map_install_set (&route_set_ipv6_nexthop_global_cmd);
+ route_map_install_set (&route_set_ipv6_nexthop_local_cmd);
+
+ install_element (RMAP_NODE, &match_ipv6_address_cmd);
+ install_element (RMAP_NODE, &no_match_ipv6_address_cmd);
+ install_element (RMAP_NODE, &match_ipv6_next_hop_cmd);
+ install_element (RMAP_NODE, &no_match_ipv6_next_hop_cmd);
+ install_element (RMAP_NODE, &match_ipv6_address_prefix_list_cmd);
+ install_element (RMAP_NODE, &no_match_ipv6_address_prefix_list_cmd);
+ install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd);
+ install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd);
+ install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd);
+#endif /* HAVE_IPV6 */
+}