summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_conditional_adv.c8
-rw-r--r--bgpd/bgp_evpn.c5
-rw-r--r--bgpd/bgp_route.c23
-rw-r--r--bgpd/bgp_route.h11
-rw-r--r--bgpd/bgp_routemap.c109
-rw-r--r--bgpd/bgp_routemap_nb.c21
-rw-r--r--bgpd/bgp_routemap_nb.h12
-rw-r--r--bgpd/bgp_routemap_nb_config.c156
-rw-r--r--doc/user/routemap.rst6
-rw-r--r--lib/routemap.h1
-rw-r--r--lib/routemap_cli.c12
-rw-r--r--tests/topotests/bgp_match_peer/r1/frr.conf6
-rw-r--r--tests/topotests/bgp_match_peer/test_bgp_match_peer.py23
-rw-r--r--yang/frr-bgp-route-map.yang37
14 files changed, 408 insertions, 22 deletions
diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c
index 2d96b444b6..a99d0201e7 100644
--- a/bgpd/bgp_conditional_adv.c
+++ b/bgpd/bgp_conditional_adv.c
@@ -30,8 +30,8 @@ bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table,
dummy_attr = *pi->attr;
/* Fill temp path_info */
- prep_for_rmap_apply(&path, &path_extra, dest, pi,
- pi->peer, &dummy_attr);
+ prep_for_rmap_apply(&path, &path_extra, dest, pi, pi->peer, NULL,
+ &dummy_attr);
RESET_FLAG(dummy_attr.rmap_change_flags);
@@ -99,8 +99,8 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
advmap_attr = *pi->attr;
/* Fill temp path_info */
- prep_for_rmap_apply(&path, &path_extra, dest, pi,
- pi->peer, &advmap_attr);
+ prep_for_rmap_apply(&path, &path_extra, dest, pi, pi->peer, NULL,
+ &advmap_attr);
RESET_FLAG(advmap_attr.rmap_change_flags);
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 0a8ce61548..ad29828ade 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -5392,9 +5392,8 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
tmp_attr = *pi->attr;
/* Fill temp path_info */
- prep_for_rmap_apply(&tmp_pi, &tmp_pie,
- dest, pi, pi->peer,
- &tmp_attr);
+ prep_for_rmap_apply(&tmp_pi, &tmp_pie, dest, pi, pi->peer,
+ NULL, &tmp_attr);
RESET_FLAG(tmp_attr.rmap_change_flags);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index ace4467536..9f44e7913a 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2512,8 +2512,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
struct attr dummy_attr = *attr;
/* Fill temp path_info */
- prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest,
- pi, peer, &dummy_attr);
+ prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest, pi, peer, NULL,
+ &dummy_attr);
struct route_map *amap =
route_map_lookup_by_name(filter->advmap.aname);
@@ -2537,9 +2537,13 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
struct bgp_path_info_extra dummy_rmap_path_extra = {0};
struct attr dummy_attr = {0};
- /* Fill temp path_info */
- prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest,
- pi, peer, attr);
+ /* Fill temp path_info.
+ * Inject the peer structure of the source peer (from).
+ * This is useful for e.g. `match peer ...` in outgoing
+ * direction.
+ */
+ prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest, pi, peer, from, attr);
+
/*
* The route reflector is not allowed to modify the attributes
* of the reflected IBGP routes unless explicitly allowed.
@@ -3426,9 +3430,8 @@ static void bgp_process_evpn_route_injection(struct bgp *bgp, afi_t afi,
dummy_attr = *new_select->attr;
/* Fill temp path_info */
- prep_for_rmap_apply(&rmap_path, &rmap_path_extra, dest,
- new_select, new_select->peer,
- &dummy_attr);
+ prep_for_rmap_apply(&rmap_path, &rmap_path_extra, dest, new_select,
+ new_select->peer, NULL, &dummy_attr);
RESET_FLAG(dummy_attr.rmap_change_flags);
@@ -11784,8 +11787,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa
dummy_attr = *pi->attr;
- prep_for_rmap_apply(&path, &extra, dest, pi,
- pi->peer, &dummy_attr);
+ prep_for_rmap_apply(&path, &extra, dest, pi, pi->peer, NULL,
+ &dummy_attr);
ret = route_map_apply(rmap, dest_p, &path);
bgp_attr_flush(&dummy_attr);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index d71bfd3ebc..1df0ffd300 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -284,6 +284,9 @@ struct bgp_path_info {
/* Peer structure. */
struct peer *peer;
+ /* From peer structure */
+ struct peer *from;
+
/* Attribute structure. */
struct attr *attr;
@@ -619,13 +622,13 @@ static inline bool is_pi_family_matching(struct bgp_path_info *pi,
}
static inline void prep_for_rmap_apply(struct bgp_path_info *dst_pi,
- struct bgp_path_info_extra *dst_pie,
- struct bgp_dest *dest,
- struct bgp_path_info *src_pi,
- struct peer *peer, struct attr *attr)
+ struct bgp_path_info_extra *dst_pie, struct bgp_dest *dest,
+ struct bgp_path_info *src_pi, struct peer *peer,
+ struct peer *from, struct attr *attr)
{
memset(dst_pi, 0, sizeof(struct bgp_path_info));
dst_pi->peer = peer;
+ dst_pi->from = from;
dst_pi->attr = attr;
dst_pi->net = dest;
dst_pi->flags = src_pi->flags;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 23e83f9bdd..e5d6992d1b 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -347,6 +347,66 @@ 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;
+
+ /* Fallback to destination (current) peer. This is mostly
+ * happens if `match src-peer ...` is used at incoming direction.
+ */
+ if (!peer)
+ peer = bpi->peer;
+
+ if (!peer)
+ return RMAP_NOMATCH;
+
+ 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 {
@@ -5287,6 +5347,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 <A.B.C.D$addrv4|X:X::X:X$addrv6|WORD$intf>",
+ 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 [<A.B.C.D|X:X::X:X|WORD>]",
+ 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,
@@ -7778,6 +7884,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
@@ -7845,6 +7952,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
@@ -110,6 +110,27 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
}
},
{
+ .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 = {
.modify = lib_route_map_entry_match_condition_rmap_match_condition_list_name_modify,
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
@@ -809,6 +809,162 @@ 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
+ */
+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
*/
int
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index 02a43bc980..60e458a28a 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -190,6 +190,12 @@ Route Map Match Command
do the exact matching of the communities, while ``any`` - can match any
community specified in COMMUNITY_LIST.
+.. clicmd:: match src-peer [IPV4_ADDR|IPV6_ADDR|INTERFACE_NAME|PEER_GROUP_NAME]
+
+ This is a BGP specific match command. Matches the source peer if the neighbor
+ was specified in this manner. Useful to announce the routes that was originated
+ by the source peer.
+
.. clicmd:: match peer IPV4_ADDR
This is a BGP specific match command. Matches the peer ip address
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 432805c8d5..69b942064b 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -756,6 +756,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/tests/topotests/bgp_match_peer/r1/frr.conf b/tests/topotests/bgp_match_peer/r1/frr.conf
index f30da3b896..02fb8ae518 100644
--- a/tests/topotests/bgp_match_peer/r1/frr.conf
+++ b/tests/topotests/bgp_match_peer/r1/frr.conf
@@ -17,6 +17,7 @@ router bgp 65001
neighbor 192.168.1.2 route-map all in
neighbor r3 route-map all in
neighbor r4 route-map all in
+ neighbor r4 route-map r4 out
exit-address-family
!
route-map all permit 5
@@ -24,7 +25,7 @@ route-map all permit 5
set metric 1
!
route-map all permit 10
- match peer 192.168.1.2
+ match src-peer 192.168.1.2
set metric 2
!
route-map all permit 15
@@ -35,3 +36,6 @@ route-map all permit 20
match peer r4
set metric 4
!
+route-map r4 permit 10
+ match src-peer r3
+!
diff --git a/tests/topotests/bgp_match_peer/test_bgp_match_peer.py b/tests/topotests/bgp_match_peer/test_bgp_match_peer.py
index 4eb7473df0..180dbcd08a 100644
--- a/tests/topotests/bgp_match_peer/test_bgp_match_peer.py
+++ b/tests/topotests/bgp_match_peer/test_bgp_match_peer.py
@@ -82,6 +82,29 @@ def test_bgp_match_peer():
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
assert result is None, "Can't converge"
+ def _bgp_show_advertised_routes():
+ output = json.loads(
+ r1.vtysh_cmd("show bgp ipv4 unicast neighbors r4 advertised-routes json")
+ )
+ expected = {
+ "advertisedRoutes": {
+ "10.0.0.3/32": {
+ "network": "10.0.0.3/32",
+ "nextHop": "192.168.1.3",
+ "path": "65003",
+ }
+ },
+ "totalPrefixCounter": 1,
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_show_advertised_routes,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't filter by source peer"
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
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 "