diff options
| author | Igor Ryzhov <iryzhov@nfware.com> | 2021-11-24 19:38:07 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-24 19:38:07 +0300 |
| commit | af36ea8434c227efea3e130fd72429b73c5f833c (patch) | |
| tree | e90f5e2b3f2bd739ddd312eee07e55464a3266cb | |
| parent | 1b5a41b41e7a0e0edddb094a74211d978afa6b43 (diff) | |
| parent | c75d6ccbfe95d2708618ade7cc7198e46ee467dd (diff) | |
Merge pull request #10121 from ton31337/feature/match_ipv6_nexthop_prefixlist
bgpd: Add an ability to match ipv6 next-hop by prefix-list
| -rw-r--r-- | bgpd/bgp_routemap.c | 96 | ||||
| -rw-r--r-- | doc/user/routemap.rst | 4 | ||||
| -rw-r--r-- | lib/routemap.c | 16 | ||||
| -rw-r--r-- | lib/routemap.h | 25 | ||||
| -rw-r--r-- | lib/routemap_cli.c | 4 | ||||
| -rw-r--r-- | lib/routemap_northbound.c | 10 | ||||
| -rw-r--r-- | tests/topotests/bgp_route_map_match_ipv6_nexthop/__init__.py (renamed from tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/__init__.py) | 0 | ||||
| -rw-r--r-- | tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf (renamed from tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r1/bgpd.conf) | 5 | ||||
| -rw-r--r-- | tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/zebra.conf (renamed from tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r1/zebra.conf) | 0 | ||||
| -rw-r--r-- | tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf (renamed from tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/bgpd.conf) | 4 | ||||
| -rw-r--r-- | tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/zebra.conf (renamed from tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/zebra.conf) | 1 | ||||
| -rw-r--r-- | tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py (renamed from tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/test_bgp_route_map_match_ipv6_nexthop_access_list.py) | 7 | ||||
| -rw-r--r-- | yang/frr-route-map.yang | 7 |
13 files changed, 178 insertions, 1 deletions
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b2eb70a9cc..2a1dc1896c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -725,6 +725,57 @@ static const struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_free }; +/* `match ipv6 next-hop prefix-list PREFIXLIST_NAME' */ +static enum route_map_cmd_result_t +route_match_ipv6_next_hop_prefix_list(void *rule, const struct prefix *prefix, + void *object) +{ + struct prefix_list *plist; + struct bgp_path_info *path; + 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; + + plist = prefix_list_lookup(AFI_IP6, (char *)rule); + if (!plist) + return RMAP_NOMATCH; + + if (prefix_list_apply(plist, &p) == PREFIX_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 (prefix_list_apply(plist, &p) == PREFIX_PERMIT) + return RMAP_MATCH; + } + } + + return RMAP_NOMATCH; +} + +static void *route_match_ipv6_next_hop_prefix_list_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void route_match_ipv6_next_hop_prefix_list_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static const struct route_map_rule_cmd + route_match_ipv6_next_hop_prefix_list_cmd = { + "ipv6 next-hop prefix-list", + route_match_ipv6_next_hop_prefix_list, + route_match_ipv6_next_hop_prefix_list_compile, + route_match_ipv6_next_hop_prefix_list_free +}; + /* `match ip next-hop type <blackhole>' */ static enum route_map_cmd_result_t @@ -6189,6 +6240,45 @@ ALIAS_HIDDEN (no_match_ipv6_next_hop_address, "Match IPv6 next-hop address of route\n" "IPv6 address of next hop\n") +DEFUN_YANG (match_ipv6_next_hop_prefix_list, + match_ipv6_next_hop_prefix_list_cmd, + "match ipv6 next-hop prefix-list PREFIXLIST_NAME", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "Match entries by prefix-list\n" + "IPv6 prefix-list name\n") +{ + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-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_prefix_list, + no_match_ipv6_next_hop_prefix_list_cmd, + "no match ipv6 next-hop prefix-list [PREFIXLIST_NAME]", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "Match entries by prefix-list\n" + "IPv6 prefix-list name\n") +{ + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + DEFPY_YANG (match_ipv4_next_hop, match_ipv4_next_hop_cmd, "match ip next-hop address A.B.C.D", @@ -6566,6 +6656,9 @@ void bgp_route_map_init(void) route_map_match_ipv6_next_hop_type_hook(generic_match_add); route_map_no_match_ipv6_next_hop_type_hook(generic_match_delete); + route_map_match_ipv6_next_hop_prefix_list_hook(generic_match_add); + route_map_no_match_ipv6_next_hop_prefix_list_hook(generic_match_delete); + route_map_match_metric_hook(generic_match_add); route_map_no_match_metric_hook(generic_match_delete); @@ -6749,6 +6842,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_ipv6_next_hop_prefix_list_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); @@ -6759,8 +6853,10 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &match_ipv6_next_hop_cmd); install_element(RMAP_NODE, &match_ipv6_next_hop_address_cmd); + install_element(RMAP_NODE, &match_ipv6_next_hop_prefix_list_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, &no_match_ipv6_next_hop_prefix_list_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); diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index d99911dc02..01d3501333 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -160,6 +160,10 @@ Route Map Match Command This is a BGP specific match command. Matches the specified `ipv6_addr`. +.. clicmd:: match ipv6 next-hop prefix-list PREFIX_LIST + + Match the next-hop according to the given prefix-list. + .. clicmd:: match as-path AS_PATH Matches the specified `as_path`. diff --git a/lib/routemap.c b/lib/routemap.c index c4651f39a4..7f733c8114 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -282,6 +282,22 @@ void route_map_no_match_ipv6_next_hop_type_hook(int (*func)( rmap_match_set_hook.no_match_ipv6_next_hop_type = func; } +/* match ipv6 next-hop prefix-list */ +void route_map_match_ipv6_next_hop_prefix_list_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_prefix_list = func; +} + +/* no match ipv6 next-hop prefix-list */ +void route_map_no_match_ipv6_next_hop_prefix_list_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_prefix_list = func; +} + /* match metric */ void route_map_match_metric_hook(int (*func)( struct route_map_index *index, const char *command, diff --git a/lib/routemap.h b/lib/routemap.h index 675f89ba92..6c4916898a 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -252,6 +252,8 @@ DECLARE_QOBJ_TYPE(route_map); (strmatch(C, "frr-route-map:ipv6-prefix-list")) #define IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(C) \ (strmatch(C, "frr-route-map:ipv4-next-hop-prefix-list")) +#define IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(C) \ + (strmatch(C, "frr-route-map:ipv6-next-hop-prefix-list")) #define IS_MATCH_IPv4_NEXTHOP_TYPE(C) \ (strmatch(C, "frr-route-map:ipv4-next-hop-type")) #define IS_MATCH_IPv6_NEXTHOP_TYPE(C) \ @@ -617,6 +619,14 @@ extern void route_map_no_match_ipv6_next_hop_type_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 ipv6 next-hop prefix-list */ +extern void route_map_match_ipv6_next_hop_prefix_list_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 prefix-list */ +extern void route_map_no_match_ipv6_next_hop_prefix_list_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 metric */ extern void route_map_match_metric_hook(int (*func)( struct route_map_index *index, const char *command, @@ -764,6 +774,21 @@ struct route_map_match_set_hooks { route_map_event_t type, char *errmsg, size_t errmsg_len); + /* match ipv6 next hop prefix-list */ + int (*match_ipv6_next_hop_prefix_list)(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 prefix-list */ + int (*no_match_ipv6_next_hop_prefix_list)(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, diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 552ba565b4..52fcaaba53 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -575,6 +575,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, " match ip next-hop prefix-list %s\n", yang_dnode_get_string( dnode, "./rmap-match-condition/list-name")); + } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition)) { + vty_out(vty, " match ipv6 next-hop prefix-list %s\n", + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) { vty_out(vty, " match ipv6 address %s\n", yang_dnode_get_string( diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 7f7bc9f9c4..51b879959f 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -622,6 +622,16 @@ static int lib_route_map_entry_match_condition_list_name_modify( rhc->rhc_rmi, "ip next-hop prefix-list", acl, RMAP_EVENT_PLIST_ADDED, args->errmsg, args->errmsg_len); + } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition)) { + if (rmap_match_set_hook.match_ipv6_next_hop_prefix_list == NULL) + return NB_OK; + rhc->rhc_mhook = + rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list; + rhc->rhc_rule = "ipv6 next-hop prefix-list"; + rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; + rv = rmap_match_set_hook.match_ipv6_next_hop_prefix_list( + rhc->rhc_rmi, "ipv6 next-hop prefix-list", acl, + RMAP_EVENT_PLIST_ADDED, args->errmsg, args->errmsg_len); } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) { if (rmap_match_set_hook.match_ipv6_address == NULL) return NB_OK; diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/__init__.py b/tests/topotests/bgp_route_map_match_ipv6_nexthop/__init__.py index e69de29bb2..e69de29bb2 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/__init__.py +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/__init__.py diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r1/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf index 5f35d353f4..c2a49252d6 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r1/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf @@ -3,6 +3,8 @@ ipv6 access-list nh1 permit 2001:db8:1::/64 ipv6 access-list nh2 permit 2001:db8:2::/64 ipv6 access-list nh3 permit 2001:db8:3::/64 ! +ipv6 prefix-list nh4 permit 2001:db8:5::/64 le 128 +! router bgp 65001 bgp router-id 10.10.10.1 no bgp ebgp-requires-policy @@ -24,4 +26,7 @@ route-map r2 permit 30 route-map r2 permit 40 match ipv6 next-hop address 2001:db8:4::1 set community 65002:4 +route-map r2 permit 50 + match ipv6 next-hop prefix-list nh4 + set community 65002:5 ! diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r1/zebra.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/zebra.conf index 1d4374bd8f..1d4374bd8f 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r1/zebra.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/zebra.conf diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf index bca67c5363..19dcf3664b 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf @@ -13,6 +13,7 @@ ipv6 prefix-list p1 permit 2001:db8:1::1/128 ipv6 prefix-list p2 permit 2001:db8:2::1/128 ipv6 prefix-list p3 permit 2001:db8:3::1/128 ipv6 prefix-list p4 permit 2001:db8:4::1/128 +ipv6 prefix-list p5 permit 2001:db8:5::1/128 ! route-map r1 permit 10 match ipv6 address prefix-list p1 @@ -26,4 +27,7 @@ route-map r1 permit 30 route-map r1 permit 40 match ipv6 address prefix-list p4 set ipv6 next-hop global 2001:db8:4::1 +route-map r1 permit 50 + match ipv6 address prefix-list p5 + set ipv6 next-hop global 2001:db8:5::1 ! diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/zebra.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/zebra.conf index 9039f1dec1..e69345f4f6 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/zebra.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/zebra.conf @@ -4,6 +4,7 @@ int lo ipv6 address 2001:db8:2::1/128 ipv6 address 2001:db8:3::1/128 ipv6 address 2001:db8:4::1/128 + ipv6 address 2001:db8:5::1/128 ! int r2-eth0 ip address 2001:db8::2/64 diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/test_bgp_route_map_match_ipv6_nexthop_access_list.py b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py index 3efe1eca76..8c86526bf1 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/test_bgp_route_map_match_ipv6_nexthop_access_list.py +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py @@ -20,7 +20,7 @@ """ Test if we can match BGP prefixes by next-hop which is -specified by an IPv6 Access-list. +specified by an IPv6 Access-list, prefix-list or just an address. """ import os @@ -103,6 +103,11 @@ def test_bgp_route_map_match_ipv6_next_hop_access_list(): "communities": "65002:4", } ], + "2001:db8:5::1/128": [ + { + "communities": "65002:5", + } + ], } return topotest.json_cmp(output, expected) diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index fa55a8c7cb..1e8c04bc6f 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -112,6 +112,12 @@ module frr-route-map { "Match an IPv6 next-hop"; } + identity ipv6-next-hop-prefix-list { + base rmap-match-type; + description + "Match an IPv6 next-hop prefix list"; + } + identity ipv6-next-hop-type { base rmap-match-type; description @@ -207,6 +213,7 @@ module frr-route-map { + "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-next-hop-prefix-list') or " + "derived-from-or-self(../condition, 'ipv6-prefix-list')"; leaf list-name { type filter:access-list-name; |
