]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_routemap.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_routemap.c
index f779b34371e13ff5bb7207b933c4dbe7ae2b9643..8fd46d00af771347c1648d61f29588c3d78d0a5d 100644 (file)
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /* 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 this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -228,7 +213,7 @@ static void *route_aspath_compile(const char *arg)
 {
        struct aspath *aspath;
 
-       aspath = aspath_str2aspath(arg);
+       aspath = aspath_str2aspath(arg, bgp_get_asnotation(NULL));
        if (!aspath)
                return NULL;
        return aspath;
@@ -475,8 +460,13 @@ route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
 
        if (prefix->family == AF_INET) {
                alist = access_list_lookup(AFI_IP, (char *)rule);
-               if (alist == NULL)
+               if (alist == NULL) {
+                       if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                               zlog_debug(
+                                       "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+                                       __func__, (char *)rule);
                        return RMAP_NOMATCH;
+               }
 
                return (access_list_apply(alist, prefix) == FILTER_DENY
                                ? RMAP_NOMATCH
@@ -489,6 +479,13 @@ route_match_ip_address(void *rule, const struct prefix *prefix, void *object)
    access-list name. */
 static void *route_match_ip_address_compile(const char *arg)
 {
+       struct access_list *alist;
+
+       alist = access_list_lookup(AFI_IP, arg);
+       if (!alist)
+               zlog_warn(
+                       "Access List specified %s does not exist yet, default will be NO_MATCH until it is created",
+                       arg);
        return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
 }
 
@@ -506,7 +503,7 @@ static const struct route_map_rule_cmd route_match_ip_address_cmd = {
        route_match_ip_address_free
 };
 
-/* `match ip next-hop IP_ADDRESS' */
+/* `match ip next-hop <IP_ADDRESS_ACCESS_LIST_NAME>' */
 
 /* Match function return 1 if match is success else return zero. */
 static enum route_map_cmd_result_t
@@ -523,8 +520,14 @@ route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object)
                p.prefixlen = IPV4_MAX_BITLEN;
 
                alist = access_list_lookup(AFI_IP, (char *)rule);
-               if (alist == NULL)
+               if (alist == NULL) {
+                       if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                               zlog_debug(
+                                       "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+                                       __func__, (char *)rule);
+
                        return RMAP_NOMATCH;
+               }
 
                return (access_list_apply(alist, &p) == FILTER_DENY
                                ? RMAP_NOMATCH
@@ -577,8 +580,14 @@ route_match_ip_route_source(void *rule, const struct prefix *pfx, void *object)
                p.prefixlen = IPV4_MAX_BITLEN;
 
                alist = access_list_lookup(AFI_IP, (char *)rule);
-               if (alist == NULL)
+               if (alist == NULL) {
+                       if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                               zlog_debug(
+                                       "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+                                       __func__, (char *)rule);
+
                        return RMAP_NOMATCH;
+               }
 
                return (access_list_apply(alist, &p) == FILTER_DENY
                                ? RMAP_NOMATCH
@@ -666,8 +675,13 @@ route_match_address_prefix_list(void *rule, afi_t afi,
        struct prefix_list *plist;
 
        plist = prefix_list_lookup(afi, (char *)rule);
-       if (plist == NULL)
+       if (plist == NULL) {
+               if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                       zlog_debug(
+                               "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+                               __func__, (char *)rule);
                return RMAP_NOMATCH;
+       }
 
        if (prefix->family == AF_FLOWSPEC)
                return route_match_prefix_list_flowspec(afi, plist,
@@ -722,8 +736,13 @@ route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
                p.prefixlen = IPV4_MAX_BITLEN;
 
                plist = prefix_list_lookup(AFI_IP, (char *)rule);
-               if (plist == NULL)
+               if (plist == NULL) {
+                       if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                               zlog_debug(
+                                       "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+                                       __func__, (char *)rule);
                        return RMAP_NOMATCH;
+               }
 
                return (prefix_list_apply(plist, &p) == PREFIX_DENY
                                ? RMAP_NOMATCH
@@ -766,8 +785,13 @@ route_match_ipv6_next_hop_prefix_list(void *rule, const struct prefix *prefix,
                p.prefixlen = IPV6_MAX_BITLEN;
 
                plist = prefix_list_lookup(AFI_IP6, (char *)rule);
-               if (!plist)
+               if (!plist) {
+                       if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                               zlog_debug(
+                                       "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+                                       __func__, (char *)rule);
                        return RMAP_NOMATCH;
+               }
 
                if (prefix_list_apply(plist, &p) == PREFIX_PERMIT)
                        return RMAP_MATCH;
@@ -866,8 +890,13 @@ route_match_ip_route_source_prefix_list(void *rule, const struct prefix *prefix,
                p.prefixlen = IPV4_MAX_BITLEN;
 
                plist = prefix_list_lookup(AFI_IP, (char *)rule);
-               if (plist == NULL)
+               if (plist == NULL) {
+                       if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                               zlog_debug(
+                                       "%s: Prefix List %s specified does not exist defaulting to NO_MATCH",
+                                       __func__, (char *)rule);
                        return RMAP_NOMATCH;
+               }
 
                return (prefix_list_apply(plist, &p) == PREFIX_DENY
                                ? RMAP_NOMATCH
@@ -926,11 +955,21 @@ route_match_mac_address(void *rule, const struct prefix *prefix, void *object)
        struct prefix p;
 
        alist = access_list_lookup(AFI_L2VPN, (char *)rule);
-       if (alist == NULL)
-               return RMAP_NOMATCH;
+       if (alist == NULL) {
+               if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                       zlog_debug(
+                               "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+                               __func__, (char *)rule);
 
-       if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE)
                return RMAP_NOMATCH;
+       }
+       if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE) {
+               if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                       zlog_debug(
+                               "%s: Prefix %pFX is not a EVPN MAC IP ROUTE defaulting to NO_MATCH",
+                               __func__, prefix);
+               return RMAP_NOMATCH;
+       }
 
        p.family = AF_ETHERNET;
        p.prefixlen = ETH_ALEN * 8;
@@ -1349,10 +1388,6 @@ static void *route_match_local_pref_compile(const char *arg)
        char *endptr = NULL;
        unsigned long tmpval;
 
-       /* Locpref value shoud be integer. */
-       if (!all_digit(arg))
-               return NULL;
-
        errno = 0;
        tmpval = strtoul(arg, &endptr, 10);
        if (*endptr != '\0' || errno || tmpval > UINT32_MAX)
@@ -2989,11 +3024,11 @@ static void *route_set_origin_compile(const char *arg)
        origin = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t));
 
        if (strcmp(arg, "igp") == 0)
-               *origin = 0;
+               *origin = BGP_ORIGIN_IGP;
        else if (strcmp(arg, "egp") == 0)
-               *origin = 1;
+               *origin = BGP_ORIGIN_EGP;
        else
-               *origin = 2;
+               *origin = BGP_ORIGIN_INCOMPLETE;
 
        return origin;
 }
@@ -3206,8 +3241,14 @@ route_match_ipv6_address(void *rule, const struct prefix *prefix, void *object)
 
        if (prefix->family == AF_INET6) {
                alist = access_list_lookup(AFI_IP6, (char *)rule);
-               if (alist == NULL)
+               if (alist == NULL) {
+                       if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                               zlog_debug(
+                                       "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+                                       __func__, (char *)rule);
+
                        return RMAP_NOMATCH;
+               }
 
                return (access_list_apply(alist, prefix) == FILTER_DENY
                                ? RMAP_NOMATCH
@@ -3218,6 +3259,14 @@ route_match_ipv6_address(void *rule, const struct prefix *prefix, void *object)
 
 static void *route_match_ipv6_address_compile(const char *arg)
 {
+       struct access_list *alist;
+
+       alist = access_list_lookup(AFI_IP6, arg);
+       if (!alist)
+               zlog_warn(
+                       "Access List specified %s does not exist yet, default will be NO_MATCH until it is created",
+                       arg);
+
        return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
 }
 
@@ -3249,8 +3298,14 @@ route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object)
                p.prefixlen = IPV6_MAX_BITLEN;
 
                alist = access_list_lookup(AFI_IP6, (char *)rule);
-               if (!alist)
+               if (!alist) {
+                       if (CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))
+                               zlog_debug(
+                                       "%s: Access-List Specified: %s does not exist defaulting to NO_MATCH",
+                                       __func__, (char *)rule);
+
                        return RMAP_NOMATCH;
+               }
 
                if (access_list_apply(alist, &p) == FILTER_PERMIT)
                        return RMAP_MATCH;
@@ -3332,7 +3387,7 @@ static const struct route_map_rule_cmd route_match_ipv6_next_hop_address_cmd = {
        route_match_ipv6_next_hop_address_free
 };
 
-/* `match ip next-hop IP_ADDRESS' */
+/* `match ip next-hop address IP_ADDRESS' */
 
 static enum route_map_cmd_result_t
 route_match_ipv4_next_hop(void *rule, const struct prefix *prefix, void *object)
@@ -3531,11 +3586,11 @@ route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
        if (CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN)
            || CHECK_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) {
                /* Set next hop preference to global */
-               SET_FLAG(path->attr->nh_flag, BGP_ATTR_NH_MP_PREFER_GLOBAL);
+               path->attr->mp_nexthop_prefer_global = true;
                SET_FLAG(path->attr->rmap_change_flags,
                         BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
        } else {
-               UNSET_FLAG(path->attr->nh_flag, BGP_ATTR_NH_MP_PREFER_GLOBAL);
+               path->attr->mp_nexthop_prefer_global = false;
                SET_FLAG(path->attr->rmap_change_flags,
                         BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED);
        }
@@ -3576,16 +3631,29 @@ route_set_ipv6_nexthop_local(void *rule, const struct prefix *p, void *object)
 {
        struct in6_addr *address;
        struct bgp_path_info *path;
+       struct bgp_dest *dest;
+       struct bgp_table *table = NULL;
 
        /* Fetch routemap's rule information. */
        address = rule;
        path = object;
+       dest = path->net;
+
+       if (!dest)
+               return RMAP_OKAY;
+
+       table = bgp_dest_table(dest);
+       if (!table)
+               return RMAP_OKAY;
 
        /* Set next hop value. */
        path->attr->mp_nexthop_local = *address;
 
        /* Set nexthop length. */
-       if (path->attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
+       if (table->safi == SAFI_MPLS_VPN || table->safi == SAFI_ENCAP ||
+           table->safi == SAFI_EVPN)
+               path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL;
+       else
                path->attr->mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL;
 
        SET_FLAG(path->attr->rmap_change_flags,
@@ -5607,15 +5675,16 @@ DEFUN_YANG (no_set_label_index,
 
 DEFUN_YANG (set_aspath_prepend_asn,
            set_aspath_prepend_asn_cmd,
-           "set as-path prepend (1-4294967295)...",
+           "set as-path prepend ASNUM...",
            SET_STR
            "Transform BGP AS_PATH attribute\n"
            "Prepend to the as-path\n"
-           "AS number\n")
+           AS_STR)
 {
        int idx_asn = 3;
        int ret;
        char *str;
+       struct aspath *aspath;
 
        str = argv_concat(argv, argc, idx_asn);
 
@@ -5623,6 +5692,12 @@ DEFUN_YANG (set_aspath_prepend_asn,
                "./set-action[action='frr-bgp-route-map:as-path-prepend']";
        char xpath_value[XPATH_MAXLEN];
 
+       aspath = route_aspath_compile(str);
+       if (!aspath) {
+               vty_out(vty, "%% Invalid AS path value %s\n", str);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       route_aspath_free(aspath);
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
        snprintf(xpath_value, sizeof(xpath_value),
                 "%s/rmap-set-action/frr-bgp-route-map:prepend-as-path", xpath);
@@ -5657,16 +5732,22 @@ DEFUN_YANG (set_aspath_prepend_lastas,
 
 DEFPY_YANG (set_aspath_replace_asn,
            set_aspath_replace_asn_cmd,
-           "set as-path replace <any|(1-4294967295)>$replace",
+           "set as-path replace <any|ASNUM>$replace",
            SET_STR
            "Transform BGP AS_PATH attribute\n"
            "Replace AS number to local AS number\n"
            "Replace any AS number to local AS number\n"
-           "Replace a specific AS number to local AS number\n")
+           "Replace a specific AS number in plain or dotted format to local AS number\n")
 {
        const char *xpath =
                "./set-action[action='frr-bgp-route-map:as-path-replace']";
        char xpath_value[XPATH_MAXLEN];
+       as_t as_value;
+
+       if (!strmatch(replace, "any") && !asn_str2asn(replace, &as_value)) {
+               vty_out(vty, "%% Invalid AS value %s\n", replace);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
 
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
        snprintf(xpath_value, sizeof(xpath_value),
@@ -5677,13 +5758,13 @@ DEFPY_YANG (set_aspath_replace_asn,
 
 DEFPY_YANG (no_set_aspath_replace_asn,
            no_set_aspath_replace_asn_cmd,
-           "no set as-path replace [<any|(1-4294967295)>]",
+           "no set as-path replace [<any|ASNUM>]",
            NO_STR
            SET_STR
            "Transform BGP AS_PATH attribute\n"
            "Replace AS number to local AS number\n"
            "Replace any AS number to local AS number\n"
-           "Replace a specific AS number to local AS number\n")
+           "Replace a specific AS number in plain or dotted format to local AS number\n")
 {
        const char *xpath =
                "./set-action[action='frr-bgp-route-map:as-path-replace']";
@@ -5694,12 +5775,12 @@ DEFPY_YANG (no_set_aspath_replace_asn,
 
 DEFUN_YANG (no_set_aspath_prepend,
            no_set_aspath_prepend_cmd,
-           "no set as-path prepend [(1-4294967295)]",
+           "no set as-path prepend [ASNUM]",
            NO_STR
            SET_STR
            "Transform BGP AS_PATH attribute\n"
            "Prepend to the as-path\n"
-           "AS number\n")
+           AS_STR)
 {
        const char *xpath =
                "./set-action[action='frr-bgp-route-map:as-path-prepend']";
@@ -5727,15 +5808,16 @@ DEFUN_YANG (no_set_aspath_prepend_lastas,
 
 DEFUN_YANG (set_aspath_exclude,
            set_aspath_exclude_cmd,
-           "set as-path exclude (1-4294967295)...",
+           "set as-path exclude ASNUM...",
            SET_STR
            "Transform BGP AS-path attribute\n"
            "Exclude from the as-path\n"
-           "AS number\n")
+           AS_STR)
 {
        int idx_asn = 3;
        int ret;
        char *str;
+       struct aspath *aspath;
 
        str = argv_concat(argv, argc, idx_asn);
 
@@ -5743,6 +5825,12 @@ DEFUN_YANG (set_aspath_exclude,
                "./set-action[action='frr-bgp-route-map:as-path-exclude']";
        char xpath_value[XPATH_MAXLEN];
 
+       aspath = route_aspath_compile(str);
+       if (!aspath) {
+               vty_out(vty, "%% Invalid AS path value %s\n", str);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       route_aspath_free(aspath);
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
        snprintf(xpath_value, sizeof(xpath_value),
                 "%s/rmap-set-action/frr-bgp-route-map:exclude-as-path", xpath);
@@ -5754,7 +5842,7 @@ DEFUN_YANG (set_aspath_exclude,
 
 DEFUN_YANG (no_set_aspath_exclude,
            no_set_aspath_exclude_cmd,
-           "no set as-path exclude (1-4294967295)...",
+           "no set as-path exclude ASNUM...",
            NO_STR
            SET_STR
            "Transform BGP AS_PATH attribute\n"
@@ -5814,9 +5902,14 @@ DEFUN_YANG (set_community,
                else
                        first = 1;
 
+#if CONFDATE > 20230801
+CPP_NOTICE("Deprecate COMMUNITY_INTERNET BGP community")
+#endif
                if (strncmp(argv[i]->arg, "internet", strlen(argv[i]->arg))
                    == 0) {
                        buffer_putstr(b, "internet");
+                       vty_out(vty, "%% `internet` community is deprecated\n");
+                       zlog_warn("`internet` community is deprecated");
                        continue;
                }
                if (strncmp(argv[i]->arg, "local-AS", strlen(argv[i]->arg))
@@ -6440,11 +6533,11 @@ DEFPY_YANG (no_set_aigp_metric,
 
 DEFUN_YANG (set_aggregator_as,
            set_aggregator_as_cmd,
-           "set aggregator as (1-4294967295) A.B.C.D",
+           "set aggregator as ASNUM A.B.C.D",
            SET_STR
            "BGP aggregator attribute\n"
            "AS number of aggregator\n"
-           "AS number\n"
+           AS_STR
            "IP address of aggregator\n")
 {
        int idx_number = 3;
@@ -6453,6 +6546,12 @@ DEFUN_YANG (set_aggregator_as,
        char xpath_addr[XPATH_MAXLEN];
        const char *xpath =
                "./set-action[action='frr-bgp-route-map:aggregator']";
+       as_t as_value;
+
+       if (!asn_str2asn(argv[idx_number]->arg, &as_value)) {
+               vty_out(vty, "%% Invalid AS value %s\n", argv[idx_number]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
 
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
 
@@ -6475,12 +6574,12 @@ DEFUN_YANG (set_aggregator_as,
 
 DEFUN_YANG (no_set_aggregator_as,
            no_set_aggregator_as_cmd,
-           "no set aggregator as [(1-4294967295) A.B.C.D]",
+           "no set aggregator as [ASNUM A.B.C.D]",
            NO_STR
            SET_STR
            "BGP aggregator attribute\n"
            "AS number of aggregator\n"
-           "AS number\n"
+           AS_STR
            "IP address of aggregator\n")
 {
        const char *xpath =