]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_routemap.c
*: Convert some route map functions to return the enum
[mirror_frr.git] / bgpd / bgp_routemap.c
index e43f9486f636de9bf0aa783ec2e1292972ef4006..545ca19762997fd1d2e1db2b507090a7f9eee891 100644 (file)
@@ -60,6 +60,9 @@
 #include "bgpd/bgp_evpn_private.h"
 #include "bgpd/bgp_evpn_vty.h"
 #include "bgpd/bgp_mplsvpn.h"
+#include "bgpd/bgp_pbr.h"
+#include "bgpd/bgp_flowspec_util.h"
+#include "bgpd/bgp_encap_types.h"
 
 #if ENABLE_BGP_VNC
 #include "bgpd/rfapi/bgp_rfapi_cfg.h"
@@ -237,10 +240,9 @@ struct bgp_match_peer_compiled {
 /* Compares the peer specified in the 'match peer' clause with the peer
     received in bgp_path_info->peer. If it is the same, or if the peer structure
     received is a peer_group containing it, returns RMAP_MATCH. */
-static route_map_result_t route_match_peer(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_cmd_result_t
+route_match_peer(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        struct bgp_match_peer_compiled *pc;
        union sockunion *su;
@@ -333,10 +335,9 @@ struct route_map_rule_cmd route_match_peer_cmd = {"peer", route_match_peer,
                                                  route_match_peer_free};
 
 #if defined(HAVE_LUA)
-static route_map_result_t route_match_command(void *rule,
-                                             const struct prefix *prefix,
-                                             route_map_object_t type,
-                                             void *object)
+static enum route_map_cmd_result_t
+route_match_command(void *rule, const struct prefix *prefix,
+                   route_map_object_t type, void *object)
 {
        int status = RMAP_NOMATCH;
        u_int32_t locpref = 0;
@@ -432,10 +433,9 @@ struct route_map_rule_cmd route_match_command_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_ip_address(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_cmd_result_t
+route_match_ip_address(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -472,10 +472,9 @@ struct route_map_rule_cmd route_match_ip_address_cmd = {
 /* `match ip next-hop IP_ADDRESS' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_next_hop(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_cmd_result_t
+route_match_ip_next_hop(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct bgp_path_info *path;
@@ -519,10 +518,9 @@ struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
 /* `match ip route-source ACCESS-LIST' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_ip_route_source(void *rule,
-                                                     const struct prefix *pfx,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_cmd_result_t
+route_match_ip_route_source(void *rule, const struct prefix *pfx,
+                           route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct bgp_path_info *path;
@@ -569,26 +567,68 @@ struct route_map_rule_cmd route_match_ip_route_source_cmd = {
        "ip route-source", route_match_ip_route_source,
        route_match_ip_route_source_compile, route_match_ip_route_source_free};
 
-/* `match ip address prefix-list PREFIX_LIST' */
-
-static route_map_result_t
-route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
-                                  route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist,
+                                const struct prefix *p)
 {
-       struct prefix_list *plist;
+       int ret;
+       struct bgp_pbr_entry_main api;
 
-       if (type == RMAP_BGP && prefix->family == AF_INET) {
-               plist = prefix_list_lookup(AFI_IP, (char *)rule);
-               if (plist == NULL)
-                       return RMAP_NOMATCH;
+       memset(&api, 0, sizeof(api));
 
-               return (prefix_list_apply(plist, prefix) == PREFIX_DENY
-                               ? RMAP_NOMATCH
-                               : RMAP_MATCH);
+       /* extract match from flowspec entries */
+       ret = bgp_flowspec_match_rules_fill(
+                                           (uint8_t *)p->u.prefix_flowspec.ptr,
+                                           p->u.prefix_flowspec.prefixlen, &api);
+       if (ret < 0)
+               return RMAP_NOMATCH;
+       if (api.match_bitmask & PREFIX_DST_PRESENT ||
+           api.match_bitmask_iprule & PREFIX_DST_PRESENT) {
+               if (family2afi((&api.dst_prefix)->family) != afi)
+                       return RMAP_NOMATCH;
+               return prefix_list_apply(plist, &api.dst_prefix) == PREFIX_DENY
+                       ? RMAP_NOMATCH
+                       : RMAP_MATCH;
+       } else if (api.match_bitmask & PREFIX_SRC_PRESENT ||
+                  api.match_bitmask_iprule & PREFIX_SRC_PRESENT) {
+               if (family2afi((&api.src_prefix)->family) != afi)
+                       return RMAP_NOMATCH;
+               return (prefix_list_apply(plist, &api.src_prefix) == PREFIX_DENY
+                       ? RMAP_NOMATCH
+                       : RMAP_MATCH);
        }
        return RMAP_NOMATCH;
 }
 
+static enum route_map_cmd_result_t
+route_match_address_prefix_list(void *rule, afi_t afi,
+                               const struct prefix *prefix,
+                               route_map_object_t type, void *object)
+{
+       struct prefix_list *plist;
+
+       if (type != RMAP_BGP)
+               return RMAP_NOMATCH;
+
+       plist = prefix_list_lookup(afi, (char *)rule);
+       if (plist == NULL)
+               return RMAP_NOMATCH;
+
+       if (prefix->family == AF_FLOWSPEC)
+               return route_match_prefix_list_flowspec(afi, plist,
+                                                       prefix);
+       return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
+                                                               : RMAP_MATCH);
+}
+
+static enum route_map_cmd_result_t
+route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
+                                  route_map_object_t type, void *object)
+{
+       return route_match_address_prefix_list(rule, AFI_IP, prefix, type,
+                                              object);
+}
+
 static void *route_match_ip_address_prefix_list_compile(const char *arg)
 {
        return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
@@ -606,7 +646,7 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
 
 /* `match ip next-hop prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_cmd_result_t
 route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
                                    route_map_object_t type, void *object)
 {
@@ -648,7 +688,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
 
 /* `match ip next-hop type <blackhole>' */
 
-static route_map_result_t
+static enum route_map_cmd_result_t
 route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
                             route_map_object_t type, void *object)
 {
@@ -657,7 +697,7 @@ route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
        if (type == RMAP_BGP && prefix->family == AF_INET) {
                path = (struct bgp_path_info *)object;
                if (!path || !path->attr)
-                       return RMAP_DENYMATCH;
+                       return RMAP_NOMATCH;
 
                /* If nexthop interface's index can't be resolved and nexthop is
                   set to any address then mark it as type `blackhole`.
@@ -687,7 +727,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = {
 
 /* `match ip route-source prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_cmd_result_t
 route_match_ip_route_source_prefix_list(void *rule,
                                        const struct prefix *prefix,
                                        route_map_object_t type, void *object)
@@ -737,10 +777,9 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = {
 /* `match evpn default-route' */
 
 /* Match function should return 1 if match is success else 0 */
-static route_map_result_t route_match_evpn_default_route(void *rule,
-                                                        const struct prefix *p,
-                                                        route_map_object_t
-                                                        type, void *object)
+static enum route_map_cmd_result_t
+route_match_evpn_default_route(void *rule, const struct prefix *p,
+                              route_map_object_t type, void *object)
 {
        if (type == RMAP_BGP && is_evpn_prefix_default(p))
                return RMAP_MATCH;
@@ -756,10 +795,9 @@ struct route_map_rule_cmd route_match_evpn_default_route_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_mac_address(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_cmd_result_t
+route_match_mac_address(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct access_list *alist;
        struct prefix p;
@@ -802,26 +840,51 @@ struct route_map_rule_cmd route_match_mac_address_cmd = {
        "mac address", route_match_mac_address, route_match_mac_address_compile,
        route_match_mac_address_free};
 
-/* `match vni' */
-
-/* Match function should return 1 if match is success else return
-   zero. */
-static route_map_result_t route_match_vni(void *rule,
-                                         const struct prefix *prefix,
-                                         route_map_object_t type, void *object)
+/*
+ * Match function returns:
+ * ...RMAP_MATCH if match is found.
+ * ...RMAP_NOMATCH if match is not found.
+ * ...RMAP_NOOP to ignore this match check.
+ */
+static enum route_map_cmd_result_t
+route_match_vni(void *rule, const struct prefix *prefix,
+               route_map_object_t type, void *object)
 {
        vni_t vni = 0;
+       unsigned int label_cnt = 0;
        struct bgp_path_info *path = NULL;
+       struct prefix_evpn *evp = (struct prefix_evpn *) prefix;
 
        if (type == RMAP_BGP) {
                vni = *((vni_t *)rule);
                path = (struct bgp_path_info *)object;
 
+               /*
+                * This rmap filter is valid for vxlan tunnel type only.
+                * For any other tunnel type, return noop to ignore
+                * this check.
+                */
+               if (path->attr && path->attr->encap_tunneltype !=
+                       BGP_ENCAP_TYPE_VXLAN)
+                       return RMAP_NOOP;
+
+               /*
+                * Apply filter to type 1, 2, 5 routes only.
+                * Other route types do not have vni label.
+                */
+               if (evp && (evp->prefix.route_type != BGP_EVPN_AD_ROUTE &&
+                       evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE &&
+                       evp->prefix.route_type != BGP_EVPN_IP_PREFIX_ROUTE))
+                       return RMAP_NOOP;
+
                if (path->extra == NULL)
                        return RMAP_NOMATCH;
 
-               if (vni == label2vni(&path->extra->label[0]))
-                       return RMAP_MATCH;
+               for ( ; label_cnt < BGP_MAX_LABELS &&
+                       label_cnt < path->extra->num_labels; label_cnt++) {
+                       if (vni == label2vni(&path->extra->label[label_cnt]))
+                               return RMAP_MATCH;
+               }
        }
 
        return RMAP_NOMATCH;
@@ -859,10 +922,9 @@ struct route_map_rule_cmd route_match_evpn_vni_cmd = {
 
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_evpn_route_type(void *rule,
-                                                     const struct prefix *pfx,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_cmd_result_t
+route_match_evpn_route_type(void *rule, const struct prefix *pfx,
+                           route_map_object_t type, void *object)
 {
        uint8_t route_type = 0;
 
@@ -905,7 +967,7 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = {
        route_match_evpn_route_type_compile, route_match_evpn_route_type_free};
 
 /* Route map commands for VRF route leak with source vrf matching */
-static route_map_result_t
+static enum route_map_cmd_result_t
 route_match_vrl_source_vrf(void *rule, const struct prefix *prefix,
                           route_map_object_t type, void *object)
 {
@@ -954,10 +1016,9 @@ struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = {
 /* `match local-preference LOCAL-PREF' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_local_pref(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_cmd_result_t
+route_match_local_pref(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        uint32_t *local_pref;
        struct bgp_path_info *path;
@@ -1011,10 +1072,9 @@ struct route_map_rule_cmd route_match_local_pref_cmd = {
 /* `match metric METRIC' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_metric(void *rule,
-                                            const struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_cmd_result_t
+route_match_metric(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -1035,10 +1095,9 @@ struct route_map_rule_cmd route_match_metric_cmd = {
 /* `match as-path ASPATH' */
 
 /* Match function for as-path match.  I assume given object is */
-static route_map_result_t route_match_aspath(void *rule,
-                                            const struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_cmd_result_t
+route_match_aspath(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
 {
 
        struct as_list *as_list;
@@ -1085,10 +1144,9 @@ struct rmap_community {
 };
 
 /* Match function for community match. */
-static route_map_result_t route_match_community(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_cmd_result_t
+route_match_community(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct bgp_path_info *path;
@@ -1155,10 +1213,9 @@ struct route_map_rule_cmd route_match_community_cmd = {
        route_match_community_free};
 
 /* Match function for lcommunity match. */
-static route_map_result_t route_match_lcommunity(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_cmd_result_t
+route_match_lcommunity(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct bgp_path_info *path;
@@ -1228,10 +1285,9 @@ struct route_map_rule_cmd route_match_lcommunity_cmd = {
 
 
 /* Match function for extcommunity match. */
-static route_map_result_t route_match_ecommunity(void *rule,
-                                                const struct prefix *prefix,
-                                                route_map_object_t type,
-                                                void *object)
+static enum route_map_cmd_result_t
+route_match_ecommunity(void *rule, const struct prefix *prefix,
+                      route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct bgp_path_info *path;
@@ -1282,10 +1338,9 @@ struct route_map_rule_cmd route_match_ecommunity_cmd = {
    and `address-family vpnv4'.  */
 
 /* `match origin' */
-static route_map_result_t route_match_origin(void *rule,
-                                            const struct prefix *prefix,
-                                            route_map_object_t type,
-                                            void *object)
+static enum route_map_cmd_result_t
+route_match_origin(void *rule, const struct prefix *prefix,
+                  route_map_object_t type, void *object)
 {
        uint8_t *origin;
        struct bgp_path_info *path;
@@ -1330,10 +1385,9 @@ struct route_map_rule_cmd route_match_origin_cmd = {
 
 /* match probability  { */
 
-static route_map_result_t route_match_probability(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_cmd_result_t
+route_match_probability(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        long r = random();
 
@@ -1385,10 +1439,9 @@ struct route_map_rule_cmd route_match_probability_cmd = {
 /* `match interface IFNAME' */
 /* Match function should return 1 if match is success else return
    zero. */
-static route_map_result_t route_match_interface(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_cmd_result_t
+route_match_interface(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct interface *ifp;
        struct bgp_path_info *path;
@@ -1432,9 +1485,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
 /* `set ip next-hop IP_ADDRESS' */
 
 /* Match function return 1 if match is success else return zero. */
-static route_map_result_t route_match_tag(void *rule,
-                                         const struct prefix *prefix,
-                                         route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_match_tag(void *rule, const struct prefix *prefix,
+               route_map_object_t type, void *object)
 {
        route_tag_t *tag;
        struct bgp_path_info *path;
@@ -1464,10 +1517,9 @@ struct rmap_ip_nexthop_set {
        int unchanged;
 };
 
-static route_map_result_t route_set_ip_nexthop(void *rule,
-                                              const struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_cmd_result_t
+route_set_ip_nexthop(void *rule, const struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        struct rmap_ip_nexthop_set *rins = rule;
        struct bgp_path_info *path;
@@ -1570,10 +1622,9 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
 /* `set local-preference LOCAL_PREF' */
 
 /* Set local preference. */
-static route_map_result_t route_set_local_pref(void *rule,
-                                              const struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_cmd_result_t
+route_set_local_pref(void *rule, const struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -1605,10 +1656,9 @@ struct route_map_rule_cmd route_set_local_pref_cmd = {
 /* `set weight WEIGHT' */
 
 /* Set weight. */
-static route_map_result_t route_set_weight(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_cmd_result_t
+route_set_weight(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -1633,10 +1683,9 @@ struct route_map_rule_cmd route_set_weight_cmd = {
 /* `set metric METRIC' */
 
 /* Set metric to attribute. */
-static route_map_result_t route_set_metric(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_cmd_result_t
+route_set_metric(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -1664,10 +1713,9 @@ struct route_map_rule_cmd route_set_metric_cmd = {
 /* `set as-path prepend ASPATH' */
 
 /* For AS path prepend mechanism. */
-static route_map_result_t route_set_aspath_prepend(void *rule,
-                                                  const struct prefix *prefix,
-                                                  route_map_object_t type,
-                                                  void *object)
+static enum route_map_cmd_result_t
+route_set_aspath_prepend(void *rule, const struct prefix *prefix,
+                        route_map_object_t type, void *object)
 {
        struct aspath *aspath;
        struct aspath *new;
@@ -1727,10 +1775,9 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
  * 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,
-                                                  const struct prefix *dummy,
-                                                  route_map_object_t type,
-                                                  void *object)
+static enum route_map_cmd_result_t
+route_set_aspath_exclude(void *rule, const struct prefix *dummy,
+                        route_map_object_t type, void *object)
 {
        struct aspath *new_path, *exclude_path;
        struct bgp_path_info *path;
@@ -1762,10 +1809,9 @@ struct rmap_com_set {
 };
 
 /* For community set mechanism. */
-static route_map_result_t route_set_community(void *rule,
-                                             const struct prefix *prefix,
-                                             route_map_object_t type,
-                                             void *object)
+static enum route_map_cmd_result_t
+route_set_community(void *rule, const struct prefix *prefix,
+                   route_map_object_t type, void *object)
 {
        struct rmap_com_set *rcs;
        struct bgp_path_info *path;
@@ -1878,10 +1924,9 @@ struct rmap_lcom_set {
 
 
 /* For lcommunity set mechanism. */
-static route_map_result_t route_set_lcommunity(void *rule,
-                                              const struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_cmd_result_t
+route_set_lcommunity(void *rule, const struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        struct rmap_lcom_set *rcs;
        struct bgp_path_info *path;
@@ -1991,10 +2036,9 @@ struct route_map_rule_cmd route_set_lcommunity_cmd = {
 /* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
 
 /* For large community set mechanism. */
-static route_map_result_t route_set_lcommunity_delete(void *rule,
-                                                     const struct prefix *pfx,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_cmd_result_t
+route_set_lcommunity_delete(void *rule, const struct prefix *pfx,
+                           route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct lcommunity *merge;
@@ -2047,12 +2091,19 @@ static route_map_result_t route_set_lcommunity_delete(void *rule,
 static void *route_set_lcommunity_delete_compile(const char *arg)
 {
        struct rmap_community *rcom;
+       char **splits;
+       int num;
 
-       rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
+       frrstr_split(arg, " ", &splits, &num);
 
-       rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+       rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
+       rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]);
        rcom->name_hash = bgp_clist_hash_key(rcom->name);
 
+       for (int i = 0; i < num; i++)
+               XFREE(MTYPE_TMP, splits[i]);
+       XFREE(MTYPE_TMP, splits);
+
        return rcom;
 }
 
@@ -2075,11 +2126,9 @@ struct route_map_rule_cmd route_set_lcommunity_delete_cmd = {
 /* `set comm-list (<1-99>|<100-500>|WORD) delete' */
 
 /* For community set mechanism. */
-static route_map_result_t route_set_community_delete(
-       void *rule,
-       const struct prefix *prefix,
-       route_map_object_t type,
-       void *object)
+static enum route_map_cmd_result_t
+route_set_community_delete(void *rule, const struct prefix *prefix,
+                          route_map_object_t type, void *object)
 {
        struct community_list *list;
        struct community *merge;
@@ -2132,12 +2181,19 @@ static route_map_result_t route_set_community_delete(
 static void *route_set_community_delete_compile(const char *arg)
 {
        struct rmap_community *rcom;
+       char **splits;
+       int num;
 
-       rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
+       frrstr_split(arg, " ", &splits, &num);
 
-       rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+       rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
+       rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]);
        rcom->name_hash = bgp_clist_hash_key(rcom->name);
 
+       for (int i = 0; i < num; i++)
+               XFREE(MTYPE_TMP, splits[i]);
+       XFREE(MTYPE_TMP, splits);
+
        return rcom;
 }
 
@@ -2159,10 +2215,9 @@ struct route_map_rule_cmd route_set_community_delete_cmd = {
 /* `set extcommunity rt COMMUNITY' */
 
 /* For community set mechanism.  Used by _rt and _soo. */
-static route_map_result_t route_set_ecommunity(void *rule,
-                                              const struct prefix *prefix,
-                                              route_map_object_t type,
-                                              void *object)
+static enum route_map_cmd_result_t
+route_set_ecommunity(void *rule, const struct prefix *prefix,
+                    route_map_object_t type, void *object)
 {
        struct ecommunity *ecom;
        struct ecommunity *new_ecom;
@@ -2247,10 +2302,9 @@ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = {
 /* `set origin ORIGIN' */
 
 /* For origin set. */
-static route_map_result_t route_set_origin(void *rule,
-                                          const struct prefix *prefix,
-                                          route_map_object_t type,
-                                          void *object)
+static enum route_map_cmd_result_t
+route_set_origin(void *rule, const struct prefix *prefix,
+                route_map_object_t type, void *object)
 {
        uint8_t *origin;
        struct bgp_path_info *path;
@@ -2297,10 +2351,9 @@ struct route_map_rule_cmd route_set_origin_cmd = {
 /* `set atomic-aggregate' */
 
 /* For atomic aggregate set. */
-static route_map_result_t route_set_atomic_aggregate(void *rule,
-                                                    const struct prefix *pfx,
-                                                    route_map_object_t type,
-                                                    void *object)
+static enum route_map_cmd_result_t
+route_set_atomic_aggregate(void *rule, const struct prefix *pfx,
+                          route_map_object_t type, void *object)
 {
        struct bgp_path_info *path;
 
@@ -2336,10 +2389,9 @@ struct aggregator {
        struct in_addr address;
 };
 
-static route_map_result_t route_set_aggregator_as(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_cmd_result_t
+route_set_aggregator_as(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct bgp_path_info *path;
        struct aggregator *aggregator;
@@ -2390,9 +2442,9 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = {
 };
 
 /* Set tag to object. object must be pointer to struct bgp_path_info */
-static route_map_result_t route_set_tag(void *rule,
-                                       const struct prefix *prefix,
-                                       route_map_object_t type, void *object)
+static enum route_map_cmd_result_t
+route_set_tag(void *rule, const struct prefix *prefix,
+             route_map_object_t type, void *object)
 {
        route_tag_t *tag;
        struct bgp_path_info *path;
@@ -2415,10 +2467,9 @@ static struct route_map_rule_cmd route_set_tag_cmd = {
 };
 
 /* Set label-index to object. object must be pointer to struct bgp_path_info */
-static route_map_result_t route_set_label_index(void *rule,
-                                               const struct prefix *prefix,
-                                               route_map_object_t type,
-                                               void *object)
+static enum route_map_cmd_result_t
+route_set_label_index(void *rule, const struct prefix *prefix,
+                     route_map_object_t type, void *object)
 {
        struct rmap_value *rv;
        struct bgp_path_info *path;
@@ -2448,10 +2499,9 @@ static struct route_map_rule_cmd route_set_label_index_cmd = {
 
 /* `match ipv6 address IP_ACCESS_LIST' */
 
-static route_map_result_t route_match_ipv6_address(void *rule,
-                                                  const struct prefix *prefix,
-                                                  route_map_object_t type,
-                                                  void *object)
+static enum route_map_cmd_result_t
+route_match_ipv6_address(void *rule, const struct prefix *prefix,
+                        route_map_object_t type, void *object)
 {
        struct access_list *alist;
 
@@ -2484,10 +2534,9 @@ struct route_map_rule_cmd route_match_ipv6_address_cmd = {
 
 /* `match ipv6 next-hop IP_ADDRESS' */
 
-static route_map_result_t route_match_ipv6_next_hop(void *rule,
-                                                   const struct prefix *prefix,
-                                                   route_map_object_t type,
-                                                   void *object)
+static enum route_map_cmd_result_t
+route_match_ipv6_next_hop(void *rule, const struct prefix *prefix,
+                         route_map_object_t type, void *object)
 {
        struct in6_addr *addr = rule;
        struct bgp_path_info *path;
@@ -2536,22 +2585,12 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = {
 
 /* `match ipv6 address prefix-list PREFIX_LIST' */
 
-static route_map_result_t
+static enum route_map_cmd_result_t
 route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
                                     route_map_object_t type, void *object)
 {
-       struct prefix_list *plist;
-
-       if (type == RMAP_BGP && prefix->family == AF_INET6) {
-               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;
+       return route_match_address_prefix_list(rule, AFI_IP6, prefix, type,
+                                              object);
 }
 
 static void *route_match_ipv6_address_prefix_list_compile(const char *arg)
@@ -2571,9 +2610,9 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
 
 /* `match ipv6 next-hop type <TYPE>' */
 
-static route_map_result_t
+static enum route_map_cmd_result_t
 route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
-                             route_map_object_t type, void *object)
+                              route_map_object_t type, void *object)
 {
        struct bgp_path_info *path;
        struct in6_addr *addr = rule;
@@ -2581,7 +2620,7 @@ route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
        if (type == RMAP_BGP && prefix->family == AF_INET6) {
                path = (struct bgp_path_info *)object;
                if (!path || !path->attr)
-                       return RMAP_DENYMATCH;
+                       return RMAP_NOMATCH;
 
                if (IPV6_ADDR_SAME(&path->attr->mp_nexthop_global, addr)
                    && !path->attr->nh_ifindex)
@@ -2619,10 +2658,9 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = {
 /* `set ipv6 nexthop global IP_ADDRESS' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_global(void *rule,
-                                                       const struct prefix *p,
-                                                       route_map_object_t type,
-                                                       void *object)
+static enum route_map_cmd_result_t
+route_set_ipv6_nexthop_global(void *rule, const struct prefix *p,
+                             route_map_object_t type, void *object)
 {
        struct in6_addr *address;
        struct bgp_path_info *path;
@@ -2678,7 +2716,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = {
        route_set_ipv6_nexthop_global_free};
 
 /* Set next-hop preference value. */
-static route_map_result_t
+static enum route_map_cmd_result_t
 route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
                                     route_map_object_t type, void *object)
 {
@@ -2732,10 +2770,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = {
 /* `set ipv6 nexthop local IP_ADDRESS' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
-                                                      const struct prefix *p,
-                                                      route_map_object_t type,
-                                                      void *object)
+static enum route_map_cmd_result_t
+route_set_ipv6_nexthop_local(void *rule, const struct prefix *p,
+                            route_map_object_t type, void *object)
 {
        struct in6_addr *address;
        struct bgp_path_info *path;
@@ -2795,10 +2832,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = {
 /* `set ipv6 nexthop peer-address' */
 
 /* Set nexthop to object.  ojbect must be pointer to struct attr. */
-static route_map_result_t route_set_ipv6_nexthop_peer(void *rule,
-                                                     const struct prefix *pfx,
-                                                     route_map_object_t type,
-                                                     void *object)
+static enum route_map_cmd_result_t
+route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx,
+                           route_map_object_t type, void *object)
 {
        struct in6_addr peer_address;
        struct bgp_path_info *path;
@@ -2873,10 +2909,9 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = {
 
 /* `set ipv4 vpn next-hop A.B.C.D' */
 
-static route_map_result_t route_set_vpnv4_nexthop(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_cmd_result_t
+route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct in_addr *address;
        struct bgp_path_info *path;
@@ -2913,10 +2948,9 @@ static void *route_set_vpnv4_nexthop_compile(const char *arg)
 
 /* `set ipv6 vpn next-hop A.B.C.D' */
 
-static route_map_result_t route_set_vpnv6_nexthop(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_cmd_result_t
+route_set_vpnv6_nexthop(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct in6_addr *address;
        struct bgp_path_info *path;
@@ -2969,10 +3003,9 @@ struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = {
 /* `set originator-id' */
 
 /* For origin set. */
-static route_map_result_t route_set_originator_id(void *rule,
-                                                 const struct prefix *prefix,
-                                                 route_map_object_t type,
-                                                 void *object)
+static enum route_map_cmd_result_t
+route_set_originator_id(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
 {
        struct in_addr *address;
        struct bgp_path_info *path;
@@ -3024,7 +3057,7 @@ static int bgp_route_match_add(struct vty *vty, const char *command,
 {
        VTY_DECLVAR_CONTEXT(route_map_index, index);
        int retval = CMD_SUCCESS;
-       int ret;
+       enum rmap_compile_rets ret;
 
        ret = route_map_add_match(index, command, arg, type);
        switch (ret) {
@@ -3041,6 +3074,11 @@ static int bgp_route_match_add(struct vty *vty, const char *command,
                        route_map_upd8_dependency(type, arg, index->map->name);
                }
                break;
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Intentionally doing nothing here.
+                */
+               break;
        }
 
        return retval;
@@ -3051,7 +3089,7 @@ static int bgp_route_match_delete(struct vty *vty, const char *command,
                                  const char *arg, route_map_event_t type)
 {
        VTY_DECLVAR_CONTEXT(route_map_index, index);
-       int ret;
+       enum rmap_compile_rets ret;
        int retval = CMD_SUCCESS;
        char *dep_name = NULL;
        const char *tmpstr;
@@ -3084,6 +3122,11 @@ static int bgp_route_match_delete(struct vty *vty, const char *command,
                if (type != RMAP_EVENT_MATCH_DELETED && dep_name)
                        route_map_upd8_dependency(type, dep_name, rmap_name);
                break;
+       case RMAP_DUPLICATE_RULE:
+               /*
+                * Nothing to do here
+                */
+               break;
        }
 
        XFREE(MTYPE_ROUTE_MAP_RULE, dep_name);
@@ -3373,31 +3416,34 @@ int bgp_route_map_update_timer(struct thread *thread)
 
 static void bgp_route_map_mark_update(const char *rmap_name)
 {
-       if (bm->t_rmap_update == NULL) {
-               struct listnode *node, *nnode;
-               struct bgp *bgp;
-
-               /* rmap_update_timer of 0 means don't do route updates */
-               if (bm->rmap_update_timer) {
-                       bm->t_rmap_update = NULL;
-                       thread_add_timer(bm->master, bgp_route_map_update_timer,
-                                        NULL, bm->rmap_update_timer,
-                                        &bm->t_rmap_update);
-
-                       /* Signal the groups that a route-map update event has
-                        * started */
-                       for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
-                               update_group_policy_update(bgp,
-                                                          BGP_POLICY_ROUTE_MAP,
-                                                          rmap_name, 1, 1);
-               } else {
-                       for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
-                               bgp_route_map_process_update(bgp, rmap_name, 0);
+       struct listnode *node, *nnode;
+       struct bgp *bgp;
+
+       /* If new update is received before the current timer timed out,
+        * turn it off and start a new timer.
+        */
+       if (bm->t_rmap_update != NULL)
+               THREAD_OFF(bm->t_rmap_update);
+
+       /* rmap_update_timer of 0 means don't do route updates */
+       if (bm->rmap_update_timer) {
+               thread_add_timer(bm->master, bgp_route_map_update_timer,
+                                NULL, bm->rmap_update_timer,
+                                &bm->t_rmap_update);
+
+               /* Signal the groups that a route-map update event has
+                * started */
+               for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+                       update_group_policy_update(bgp,
+                                                  BGP_POLICY_ROUTE_MAP,
+                                                  rmap_name, 1, 1);
+       } else {
+               for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+                       bgp_route_map_process_update(bgp, rmap_name, 0);
 #if ENABLE_BGP_VNC
-                       zlog_debug("%s: calling vnc_routemap_update", __func__);
-                       vnc_routemap_update(bgp, __func__);
+               zlog_debug("%s: calling vnc_routemap_update", __func__);
+               vnc_routemap_update(bgp, __func__);
 #endif
-               }
        }
 }
 
@@ -4122,6 +4168,18 @@ DEFUN (no_set_aspath_prepend,
        return ret;
 }
 
+DEFUN (no_set_aspath_prepend_lastas,
+       no_set_aspath_prepend_lastas_cmd,
+       "no set as-path prepend last-as [(1-10)]",
+       NO_STR
+       SET_STR
+       "Transform BGP AS_PATH attribute\n"
+       "Prepend to the as-path\n"
+       "Use the peers AS-number\n"
+       "Number of times to insert\n")
+{
+       return no_set_aspath_prepend(self, vty, argc, argv);
+}
 
 DEFUN (set_aspath_exclude,
        set_aspath_exclude_cmd,
@@ -4309,9 +4367,12 @@ DEFUN (set_community_delete,
        "Delete matching communities\n")
 {
        int idx_comm_list = 2;
+       char *args;
 
+       args = argv_concat(argv, argc, idx_comm_list);
        generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), "comm-list",
-                       argv[idx_comm_list]->arg);
+                       args);
+       XFREE(MTYPE_TMP, args);
 
        return CMD_SUCCESS;
 }
@@ -4401,8 +4462,13 @@ DEFUN (set_lcommunity_delete,
        "Large Community-list name\n"
        "Delete matching large communities\n")
 {
+       int idx_lcomm_list = 2;
+       char *args;
+
+       args = argv_concat(argv, argc, idx_lcomm_list);
        generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
-                       "large-comm-list", argv[2]->arg);
+                       "large-comm-list", args);
+       XFREE(MTYPE_TMP, args);
 
        return CMD_SUCCESS;
 }
@@ -5079,6 +5145,7 @@ void bgp_route_map_init(void)
        install_element(RMAP_NODE, &set_aspath_prepend_lastas_cmd);
        install_element(RMAP_NODE, &set_aspath_exclude_cmd);
        install_element(RMAP_NODE, &no_set_aspath_prepend_cmd);
+       install_element(RMAP_NODE, &no_set_aspath_prepend_lastas_cmd);
        install_element(RMAP_NODE, &no_set_aspath_exclude_cmd);
        install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd);
        install_element(RMAP_NODE, &set_origin_cmd);