diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index ec60e5db86..15373a0c37 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -333,6 +333,57 @@ static const struct route_map_rule_cmd route_match_peer_cmd = { route_match_peer_free }; +static enum route_map_cmd_result_t route_match_src_peer(void *rule, const struct prefix *prefix, + void *object) +{ + struct bgp_match_peer_compiled *pc; + union sockunion *su; + struct peer_group *group; + struct peer *peer; + struct listnode *node, *nnode; + struct bgp_path_info *bpi; + + pc = rule; + su = &pc->su; + bpi = object; + peer = bpi->from; + + if (pc->interface) { + if (!peer->conf_if && !peer->group) + return RMAP_NOMATCH; + + if (peer->conf_if && strcmp(peer->conf_if, pc->interface) == 0) + return RMAP_MATCH; + + if (peer->group && strcmp(peer->group->name, pc->interface) == 0) + return RMAP_MATCH; + + return RMAP_NOMATCH; + } + + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + if (sockunion_same(su, &peer->connection->su)) + return RMAP_MATCH; + + return RMAP_NOMATCH; + } + + group = peer->group; + for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { + if (sockunion_same(su, &peer->connection->su)) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +static const struct route_map_rule_cmd route_match_src_peer_cmd = { + "src-peer", + route_match_src_peer, + route_match_peer_compile, + route_match_peer_free +}; + #ifdef HAVE_SCRIPTING enum frrlua_rm_status { @@ -5274,6 +5325,52 @@ DEFUN_YANG (no_match_peer, return nb_cli_apply_changes(vty, NULL); } +DEFPY_YANG (match_src_peer, + match_src_peer_cmd, + "match src-peer ", + MATCH_STR + "Match source peer address\n" + "IP address of peer\n" + "IPv6 address of peer\n" + "Interface name of peer or peer group name\n") +{ + const char *xpath = "./match-condition[condition='frr-bgp-route-map:src-peer']"; + 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/frr-bgp-route-map:src-peer-ipv4-address", xpath); + nb_cli_enqueue_change(vty, xpath_value, addrv4_str ? NB_OP_MODIFY : NB_OP_DESTROY, + addrv4_str); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:src-peer-ipv6-address", xpath); + nb_cli_enqueue_change(vty, xpath_value, addrv6_str ? NB_OP_MODIFY : NB_OP_DESTROY, + addrv6_str); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:src-peer-interface", xpath); + nb_cli_enqueue_change(vty, xpath_value, intf ? NB_OP_MODIFY : NB_OP_DESTROY, intf); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_src_peer, + no_match_src_peer_cmd, + "no match src-peer []", + NO_STR + MATCH_STR + "Match peer address\n" + "IP address of peer\n" + "IPv6 address of peer\n" + "Interface name of peer\n") +{ + const char *xpath = "./match-condition[condition='frr-bgp-route-map:src-peer']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + #ifdef HAVE_SCRIPTING DEFUN_YANG (match_script, match_script_cmd, @@ -7841,6 +7938,7 @@ void bgp_route_map_init(void) route_map_no_set_tag_hook(generic_set_delete); route_map_install_match(&route_match_peer_cmd); + route_map_install_match(&route_match_src_peer_cmd); route_map_install_match(&route_match_alias_cmd); route_map_install_match(&route_match_local_pref_cmd); #ifdef HAVE_SCRIPTING @@ -7908,6 +8006,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &match_peer_cmd); install_element(RMAP_NODE, &match_peer_local_cmd); + install_element(RMAP_NODE, &match_src_peer_cmd); + install_element(RMAP_NODE, &no_match_src_peer_cmd); install_element(RMAP_NODE, &no_match_peer_cmd); install_element(RMAP_NODE, &match_ip_route_source_cmd); install_element(RMAP_NODE, &no_match_ip_route_source_cmd); diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index 096502aaa9..d8fdb4fbc4 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -109,6 +109,27 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .destroy = lib_route_map_entry_match_condition_rmap_match_condition_peer_local_destroy, } }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-ipv4-address", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-interface", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_destroy, + } + }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-ipv6-address", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_destroy, + } + }, { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:list-name", .cbs = { diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index d7f0cea30e..f59686f386 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -46,6 +46,18 @@ int lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_m int lib_route_map_entry_match_condition_rmap_match_condition_peer_ipv6_address_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_peer_local_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_peer_local_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_destroy( + struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_destroy( + struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_destroy( + struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_access_list_num_extended_modify(struct nb_cb_modify_args *args); diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 15c32eaa28..0dca196ed6 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -808,6 +808,162 @@ lib_route_map_entry_match_condition_rmap_match_condition_peer_local_destroy( return NB_OK; } +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-ipv4-address + */ +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "src-peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "src-peer", peer, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv4_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-interface + */ +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "src-peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "src-peer", peer, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_interface_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + +/* + * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:src-peer-ipv6-address + */ +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *peer; + enum rmap_compile_rets ret; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + /* Add configuration. */ + rhc = nb_running_get_entry(args->dnode, NULL, true); + peer = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "src-peer"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "src-peer", peer, RMAP_EVENT_MATCH_ADDED, + args->errmsg, args->errmsg_len); + + if (ret != RMAP_COMPILE_SUCCESS) { + rhc->rhc_mhook = NULL; + return NB_ERR_INCONSISTENCY; + } + } + + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_src_peer_ipv6_address_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + break; + case NB_EV_APPLY: + return lib_route_map_entry_match_destroy(args); + } + + return NB_OK; +} + /* * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:list-name */ diff --git a/lib/routemap.h b/lib/routemap.h index dfb84ced5b..ef9b3cb160 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -278,6 +278,7 @@ DECLARE_QOBJ_TYPE(route_map); #define IS_MATCH_SRC_VRF(C) \ (strmatch(C, "frr-bgp-route-map:source-vrf")) #define IS_MATCH_PEER(C) (strmatch(C, "frr-bgp-route-map:peer")) +#define IS_MATCH_SRC_PEER(C) (strmatch(C, "frr-bgp-route-map:src-peer")) #define IS_MATCH_AS_LIST(C) \ (strmatch(C, "frr-bgp-route-map:as-path-list")) #define IS_MATCH_MAC_LIST(C) \ diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index f22d588080..817ac7cbe0 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -688,6 +688,18 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, acl = "local"; vty_out(vty, " match peer %s\n", acl); + } else if (IS_MATCH_SRC_PEER(condition)) { + acl = NULL; + ln = yang_dnode_get(dnode, + "./rmap-match-condition/frr-bgp-route-map:src-peer-ipv4-address"); + if (!ln) + ln = yang_dnode_get(dnode, + "./rmap-match-condition/frr-bgp-route-map:src-peer-ipv6-address"); + if (!ln) + ln = yang_dnode_get(dnode, + "./rmap-match-condition/frr-bgp-route-map:src-peer-interface"); + acl = yang_dnode_get_string(ln, NULL); + vty_out(vty, " match src-peer %s\n", acl); } else if (IS_MATCH_AS_LIST(condition)) { vty_out(vty, " match as-path %s\n", yang_dnode_get_string( diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index 44058ab04e..4ed80d7d07 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -94,6 +94,12 @@ module frr-bgp-route-map { "Match peer address"; } + identity src-peer { + base frr-route-map:rmap-match-type; + description + "Match source peer address"; + } + identity mac-address-list { base frr-route-map:rmap-match-type; description @@ -688,6 +694,37 @@ identity set-extcommunity-color { } } + case src-peer { + when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:src-peer')"; + choice peer { + description + "Value of the peer"; + case src-peer-ipv4-address { + description + "IP address of peer"; + leaf src-peer-ipv4-address { + type inet:ipv4-address; + } + } + + case src-peer-interface { + description + "Interface name of peer"; + leaf src-peer-interface { + type string; + } + } + + case src-peer-ipv6-address { + description + "IPv6 address of peer"; + leaf src-peer-ipv6-address { + type inet:ipv6-address; + } + } + } + } + case access-list-name { when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:mac-address-list') or " + "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:as-path-list') or "