]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: Add an ability to match ipv6 next-hop by access-list
authorDonatas Abraitis <donatas.abraitis@gmail.com>
Mon, 22 Nov 2021 19:26:33 +0000 (21:26 +0200)
committerDonatas Abraitis <donatas.abraitis@gmail.com>
Tue, 23 Nov 2021 11:47:26 +0000 (13:47 +0200)
Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
bgpd/bgp_routemap.c
lib/routemap.c
lib/routemap.h
lib/routemap_cli.c
lib/routemap_northbound.c
yang/frr-route-map.yang

index b46fd13529ca31f656236ac016e7bee01c9bf726..b2eb70a9cca3ea6a8e82b72d99541d94b30a6a0c 100644 (file)
@@ -3023,10 +3023,60 @@ static const struct route_map_rule_cmd route_match_ipv6_address_cmd = {
        route_match_ipv6_address_free
 };
 
+/* `match ipv6 next-hop ACCESSLIST6_NAME' */
+static enum route_map_cmd_result_t
+route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object)
+{
+       struct bgp_path_info *path;
+       struct access_list *alist;
+       struct prefix_ipv6 p;
+
+       if (prefix->family == AF_INET6) {
+               path = object;
+               p.family = AF_INET6;
+               p.prefix = path->attr->mp_nexthop_global;
+               p.prefixlen = IPV6_MAX_BITLEN;
+
+               alist = access_list_lookup(AFI_IP6, (char *)rule);
+               if (!alist)
+                       return RMAP_NOMATCH;
+
+               if (access_list_apply(alist, &p) == FILTER_PERMIT)
+                       return RMAP_MATCH;
+
+               if (path->attr->mp_nexthop_len
+                   == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
+                       p.prefix = path->attr->mp_nexthop_local;
+                       if (access_list_apply(alist, &p) == FILTER_PERMIT)
+                               return RMAP_MATCH;
+               }
+       }
+
+       return RMAP_NOMATCH;
+}
+
+static void *route_match_ipv6_next_hop_compile(const char *arg)
+{
+       return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void route_match_ipv6_next_hop_free(void *rule)
+{
+       XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static const 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 next-hop IP_ADDRESS' */
 
 static enum route_map_cmd_result_t
-route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object)
+route_match_ipv6_next_hop_address(void *rule, const struct prefix *prefix,
+                                 void *object)
 {
        struct in6_addr *addr = rule;
        struct bgp_path_info *path;
@@ -3043,7 +3093,7 @@ route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object)
        return RMAP_NOMATCH;
 }
 
-static void *route_match_ipv6_next_hop_compile(const char *arg)
+static void *route_match_ipv6_next_hop_address_compile(const char *arg)
 {
        struct in6_addr *address;
        int ret;
@@ -3059,16 +3109,16 @@ static void *route_match_ipv6_next_hop_compile(const char *arg)
        return address;
 }
 
-static void route_match_ipv6_next_hop_free(void *rule)
+static void route_match_ipv6_next_hop_address_free(void *rule)
 {
        XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
 }
 
-static const struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = {
+static const struct route_map_rule_cmd route_match_ipv6_next_hop_address_cmd = {
        "ipv6 next-hop address",
-       route_match_ipv6_next_hop,
-       route_match_ipv6_next_hop_compile,
-       route_match_ipv6_next_hop_free
+       route_match_ipv6_next_hop_address,
+       route_match_ipv6_next_hop_address_compile,
+       route_match_ipv6_next_hop_address_free
 };
 
 /* `match ip next-hop IP_ADDRESS' */
@@ -6047,6 +6097,43 @@ DEFUN_YANG (no_set_aggregator_as,
 
 DEFUN_YANG (match_ipv6_next_hop,
            match_ipv6_next_hop_cmd,
+           "match ipv6 next-hop ACCESSLIST6_NAME",
+           MATCH_STR
+           IPV6_STR
+           "Match IPv6 next-hop address of route\n"
+           "IPv6 access-list name\n")
+{
+       const char *xpath =
+               "./match-condition[condition='frr-route-map:ipv6-next-hop-list']";
+       char xpath_value[XPATH_MAXLEN];
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+       snprintf(xpath_value, sizeof(xpath_value),
+                "%s/rmap-match-condition/list-name", xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+                             argv[argc - 1]->arg);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (no_match_ipv6_next_hop,
+           no_match_ipv6_next_hop_cmd,
+           "no match ipv6 next-hop [ACCESSLIST6_NAME]",
+           NO_STR
+           MATCH_STR
+           IPV6_STR
+           "Match IPv6 next-hop address of route\n"
+           "IPv6 access-list name\n")
+{
+       const char *xpath =
+               "./match-condition[condition='frr-route-map:ipv6-next-hop-list']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG (match_ipv6_next_hop_address,
+           match_ipv6_next_hop_address_cmd,
            "match ipv6 next-hop address X:X::X:X",
            MATCH_STR
            IPV6_STR
@@ -6062,13 +6149,14 @@ DEFUN_YANG (match_ipv6_next_hop,
        snprintf(xpath_value, sizeof(xpath_value),
                 "%s/rmap-match-condition/frr-bgp-route-map:ipv6-address",
                 xpath);
-       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[argc - 1]->arg);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
+                             argv[argc - 1]->arg);
 
        return nb_cli_apply_changes(vty, NULL);
 }
 
-DEFUN_YANG (no_match_ipv6_next_hop,
-           no_match_ipv6_next_hop_cmd,
+DEFUN_YANG (no_match_ipv6_next_hop_address,
+           no_match_ipv6_next_hop_address_cmd,
            "no match ipv6 next-hop address X:X::X:X",
            NO_STR
            MATCH_STR
@@ -6084,7 +6172,7 @@ DEFUN_YANG (no_match_ipv6_next_hop,
        return nb_cli_apply_changes(vty, NULL);
 }
 
-ALIAS_HIDDEN (match_ipv6_next_hop,
+ALIAS_HIDDEN (match_ipv6_next_hop_address,
              match_ipv6_next_hop_old_cmd,
              "match ipv6 next-hop X:X::X:X",
              MATCH_STR
@@ -6092,7 +6180,7 @@ ALIAS_HIDDEN (match_ipv6_next_hop,
              "Match IPv6 next-hop address of route\n"
              "IPv6 address of next hop\n")
 
-ALIAS_HIDDEN (no_match_ipv6_next_hop,
+ALIAS_HIDDEN (no_match_ipv6_next_hop_address,
              no_match_ipv6_next_hop_old_cmd,
              "no match ipv6 next-hop X:X::X:X",
              NO_STR
@@ -6460,6 +6548,9 @@ void bgp_route_map_init(void)
        route_map_match_ip_next_hop_hook(generic_match_add);
        route_map_no_match_ip_next_hop_hook(generic_match_delete);
 
+       route_map_match_ipv6_next_hop_hook(generic_match_add);
+       route_map_no_match_ipv6_next_hop_hook(generic_match_delete);
+
        route_map_match_ip_next_hop_prefix_list_hook(generic_match_add);
        route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete);
 
@@ -6657,6 +6748,7 @@ void bgp_route_map_init(void)
 
        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_next_hop_address_cmd);
        route_map_install_match(&route_match_ipv4_next_hop_cmd);
        route_map_install_match(&route_match_ipv6_address_prefix_list_cmd);
        route_map_install_match(&route_match_ipv6_next_hop_type_cmd);
@@ -6666,7 +6758,9 @@ void bgp_route_map_init(void)
        route_map_install_set(&route_set_ipv6_nexthop_peer_cmd);
 
        install_element(RMAP_NODE, &match_ipv6_next_hop_cmd);
+       install_element(RMAP_NODE, &match_ipv6_next_hop_address_cmd);
        install_element(RMAP_NODE, &no_match_ipv6_next_hop_cmd);
+       install_element(RMAP_NODE, &no_match_ipv6_next_hop_address_cmd);
        install_element(RMAP_NODE, &match_ipv6_next_hop_old_cmd);
        install_element(RMAP_NODE, &no_match_ipv6_next_hop_old_cmd);
        install_element(RMAP_NODE, &match_ipv4_next_hop_cmd);
index 09da095af4f38c8aad10d43ebab3210bdc2d60b3..c4651f39a4997944088e8e93d2d8a391f7ebaf0f 100644 (file)
@@ -175,6 +175,22 @@ void route_map_no_match_ip_next_hop_hook(int (*func)(
        rmap_match_set_hook.no_match_ip_next_hop = func;
 }
 
+/* match ipv6 next-hop */
+void route_map_match_ipv6_next_hop_hook(int (*func)(
+       struct route_map_index *index, const char *command, const char *arg,
+       route_map_event_t type, char *errmsg, size_t errmsg_len))
+{
+       rmap_match_set_hook.match_ipv6_next_hop = func;
+}
+
+/* no match ipv6 next-hop */
+void route_map_no_match_ipv6_next_hop_hook(int (*func)(
+       struct route_map_index *index, const char *command, const char *arg,
+       route_map_event_t type, char *errmsg, size_t errmsg_len))
+{
+       rmap_match_set_hook.no_match_ipv6_next_hop = func;
+}
+
 /* match ip next hop prefix list */
 void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
        struct route_map_index *index, const char *command,
index 7e17e14fa62ad681bc5a15f7812342e1f8c7b58f..675f89ba92878575380683d766668f203cee17d0 100644 (file)
@@ -244,6 +244,8 @@ DECLARE_QOBJ_TYPE(route_map);
        (strmatch(C, "frr-route-map:ipv6-address-list"))
 #define IS_MATCH_IPv4_NEXTHOP_LIST(C)                                          \
        (strmatch(C, "frr-route-map:ipv4-next-hop-list"))
+#define IS_MATCH_IPv6_NEXTHOP_LIST(C)                                          \
+       (strmatch(C, "frr-route-map:ipv6-next-hop-list"))
 #define IS_MATCH_IPv4_PREFIX_LIST(C)                                           \
        (strmatch(C, "frr-route-map:ipv4-prefix-list"))
 #define IS_MATCH_IPv6_PREFIX_LIST(C)                                           \
@@ -555,9 +557,16 @@ extern void route_map_match_ip_next_hop_hook(int (*func)(
        char *errmsg, size_t errmsg_len));
 /* no match ip next hop */
 extern void route_map_no_match_ip_next_hop_hook(int (*func)(
-       struct route_map_index *index, const char *command,
-       const char *arg, route_map_event_t type,
-       char *errmsg, size_t errmsg_len));
+       struct route_map_index *index, const char *command, const char *arg,
+       route_map_event_t type, char *errmsg, size_t errmsg_len));
+/* match ipv6 next hop */
+extern void route_map_match_ipv6_next_hop_hook(int (*func)(
+       struct route_map_index *index, const char *command, const char *arg,
+       route_map_event_t type, char *errmsg, size_t errmsg_len));
+/* no match ipv6 next hop */
+extern void route_map_no_match_ipv6_next_hop_hook(int (*func)(
+       struct route_map_index *index, const char *command, const char *arg,
+       route_map_event_t type, char *errmsg, size_t errmsg_len));
 /* match ip next hop prefix list */
 extern void route_map_match_ip_next_hop_prefix_list_hook(int (*func)(
        struct route_map_index *index, const char *command,
@@ -743,6 +752,18 @@ struct route_map_match_set_hooks {
                                    route_map_event_t type,
                                    char *errmsg, size_t errmsg_len);
 
+       /* match ipv6 next hop */
+       int (*match_ipv6_next_hop)(struct route_map_index *index,
+                                  const char *command, const char *arg,
+                                  route_map_event_t type, char *errmsg,
+                                  size_t errmsg_len);
+
+       /* no match ipv6 next hop */
+       int (*no_match_ipv6_next_hop)(struct route_map_index *index,
+                                     const char *command, const char *arg,
+                                     route_map_event_t type, char *errmsg,
+                                     size_t errmsg_len);
+
        /* match ip next hop prefix list */
        int (*match_ip_next_hop_prefix_list)(struct route_map_index *index,
                                             const char *command,
index f85be05f5ed1e73b63e48978f882a720e56a05da..e26e3a6d2d03a1c48044c8bebea081783e1c079b 100644 (file)
@@ -551,6 +551,7 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
                        yang_dnode_get_string(
                                dnode, "./rmap-match-condition/interface"));
        } else if (IS_MATCH_IPv4_ADDRESS_LIST(condition)
+                  || IS_MATCH_IPv6_NEXTHOP_LIST(condition)
                   || IS_MATCH_IPv4_NEXTHOP_LIST(condition)) {
                acl = NULL;
                if ((ln = yang_dnode_get(dnode,
@@ -562,8 +563,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
 
                if (IS_MATCH_IPv4_ADDRESS_LIST(condition))
                        vty_out(vty, " match ip address %s\n", acl);
-               else
+               else if (IS_MATCH_IPv4_NEXTHOP_LIST(condition))
                        vty_out(vty, " match ip next-hop %s\n", acl);
+               else
+                       vty_out(vty, " match ipv6 next-hop %s\n", acl);
        } else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) {
                vty_out(vty, " match ip address prefix-list %s\n",
                        yang_dnode_get_string(
index 3473ca2aea8cf12f6043d91fc5f739784aa199af..7f7bc9f9c4d1629376a1a1ced0bac67e9821c898 100644 (file)
@@ -601,6 +601,16 @@ static int lib_route_map_entry_match_condition_list_name_modify(
                        rhc->rhc_rmi, "ip next-hop", acl,
                        RMAP_EVENT_FILTER_ADDED,
                        args->errmsg, args->errmsg_len);
+       } else if (IS_MATCH_IPv6_NEXTHOP_LIST(condition)) {
+               if (rmap_match_set_hook.match_ipv6_next_hop == NULL)
+                       return NB_OK;
+               rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop;
+               rhc->rhc_rule = "ipv6 next-hop";
+               rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
+               rv = rmap_match_set_hook.match_ipv6_next_hop(
+                       rhc->rhc_rmi, "ipv6 next-hop", acl,
+                       RMAP_EVENT_FILTER_ADDED, args->errmsg,
+                       args->errmsg_len);
        } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) {
                if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL)
                        return NB_OK;
index c4eb78608b85fa3e1d3bcbbbadfbfd602733e2a9..fa55a8c7cb760949bcd9601ed2bcc3d9056ae82b 100644 (file)
@@ -106,6 +106,12 @@ module frr-route-map {
       "Match an IPv6 prefix-list";
   }
 
+  identity ipv6-next-hop-list {
+    base rmap-match-type;
+    description
+      "Match an IPv6 next-hop";
+  }
+
   identity ipv6-next-hop-type {
     base rmap-match-type;
     description
@@ -200,6 +206,7 @@ module frr-route-map {
              + "derived-from-or-self(../condition, 'ipv4-next-hop-list') or "
              + "derived-from-or-self(../condition, 'ipv4-next-hop-prefix-list') or "
              + "derived-from-or-self(../condition, 'ipv6-address-list') or "
+             + "derived-from-or-self(../condition, 'ipv6-next-hop-list') or "
              + "derived-from-or-self(../condition, 'ipv6-prefix-list')";
           leaf list-name {
             type filter:access-list-name;