]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: Implement `match source-protocol` for route-maps
authorDonatas Abraitis <donatas@opensourcerouting.org>
Wed, 10 May 2023 20:37:47 +0000 (23:37 +0300)
committerDonatas Abraitis <donatas@opensourcerouting.org>
Thu, 11 May 2023 08:39:23 +0000 (11:39 +0300)
The main idea is to filter routes by matching source (originating) protocol
for outgoing direction. For instance, filter outgoing routes to an arbitrary
router that are static only. Or filter out only routes learned from RIP.

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
bgpd/bgp_routemap.c
bgpd/bgp_routemap_nb.c
bgpd/bgp_routemap_nb.h
bgpd/bgp_routemap_nb_config.c
lib/routemap.h
lib/routemap_cli.c
yang/frr-bgp-route-map.yang

index 10fc3ecda4455abb5e9ed8f4f3566dd950baf4de..7db110be933900ad3d16b8c9d15a3817eb2367cc 100644 (file)
@@ -872,6 +872,46 @@ static const struct route_map_rule_cmd
        route_match_ip_next_hop_type_free
 };
 
+/* `match source-protocol` */
+static enum route_map_cmd_result_t
+route_match_source_protocol(void *rule, const struct prefix *prefix,
+                           void *object)
+{
+       struct bgp_path_info *path = object;
+       int *protocol = rule;
+
+       if (!path)
+               return RMAP_NOMATCH;
+
+       if (path->type == *protocol)
+               return RMAP_MATCH;
+
+       return RMAP_NOMATCH;
+}
+
+static void *route_match_source_protocol_compile(const char *arg)
+{
+       int *protocol;
+
+       protocol = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*protocol));
+       *protocol = proto_name2num(arg);
+
+       return protocol;
+}
+
+static void route_match_source_protocol_free(void *rule)
+{
+       XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static const struct route_map_rule_cmd route_match_source_protocol_cmd = {
+       "source-protocol",
+       route_match_source_protocol,
+       route_match_source_protocol_compile,
+       route_match_source_protocol_free
+};
+
+
 /* `match ip route-source prefix-list PREFIX_LIST' */
 
 static enum route_map_cmd_result_t
@@ -7177,6 +7217,42 @@ DEFPY_YANG (match_rpki_extcommunity,
        return nb_cli_apply_changes(vty, NULL);
 }
 
+DEFPY_YANG (match_source_protocol,
+            match_source_protocol_cmd,
+           "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto",
+           MATCH_STR
+           "Match protocol via which the route was learnt\n"
+           FRR_REDIST_HELP_STR_ZEBRA)
+{
+       const char *xpath =
+               "./match-condition[condition='frr-bgp-route-map:source-protocol']";
+       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:source-protocol",
+                xpath);
+       nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG (no_match_source_protocol,
+            no_match_source_protocol_cmd,
+           "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]",
+           NO_STR
+           MATCH_STR
+           "Match protocol via which the route was learnt\n"
+           FRR_REDIST_HELP_STR_ZEBRA)
+{
+       const char *xpath =
+               "./match-condition[condition='frr-bgp-route-map:source-protocol']";
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+       return nb_cli_apply_changes(vty, NULL);
+}
+
 /* Initialization of route map. */
 void bgp_route_map_init(void)
 {
@@ -7252,6 +7328,7 @@ void bgp_route_map_init(void)
        route_map_install_match(&route_match_ip_address_prefix_list_cmd);
        route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
        route_map_install_match(&route_match_ip_next_hop_type_cmd);
+       route_map_install_match(&route_match_source_protocol_cmd);
        route_map_install_match(&route_match_ip_route_source_prefix_list_cmd);
        route_map_install_match(&route_match_aspath_cmd);
        route_map_install_match(&route_match_community_cmd);
@@ -7441,6 +7518,8 @@ void bgp_route_map_init(void)
        install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd);
        install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd);
        install_element(RMAP_NODE, &match_rpki_extcommunity_cmd);
+       install_element(RMAP_NODE, &match_source_protocol_cmd);
+       install_element(RMAP_NODE, &no_match_source_protocol_cmd);
 #ifdef HAVE_SCRIPTING
        install_element(RMAP_NODE, &match_script_cmd);
 #endif
index 6e8439cc26cfe991649d83292aa613db9fbaafc5..282ebe9116a6651a276c8a2b8abf7431d35c0eee 100644 (file)
@@ -74,6 +74,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
                                .destroy = lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_destroy,
                        }
                },
+           {
+                       .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:source-protocol",
+                       .cbs = {
+                               .modify = lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify,
+                               .destroy = lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-ipv4-address",
                        .cbs = {
index bcd1e837e852c3cb3fa759ffcf63b807fd86c563..7066fdb4195cabd2f8bcd1b716ddb7cad3f85ba6 100644 (file)
@@ -30,6 +30,10 @@ int lib_route_map_entry_match_condition_rmap_match_condition_rpki_extcommunity_m
        struct nb_cb_modify_args *args);
 int lib_route_map_entry_match_condition_rmap_match_condition_rpki_extcommunity_destroy(
        struct nb_cb_destroy_args *args);
+int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify(
+       struct nb_cb_modify_args *args);
+int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_destroy(
+       struct nb_cb_destroy_args *args);
 int lib_route_map_entry_match_condition_rmap_match_condition_probability_modify(struct nb_cb_modify_args *args);
 int lib_route_map_entry_match_condition_rmap_match_condition_probability_destroy(struct nb_cb_destroy_args *args);
 int lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_modify(struct nb_cb_modify_args *args);
index 938a5ec31b7c662fea9466b15aa9abdb6ec6b78b..02564b00041025c76d8a8725ab9829d639bc4ced 100644 (file)
@@ -367,6 +367,60 @@ lib_route_map_entry_match_condition_rmap_match_condition_rpki_destroy(
        return NB_OK;
 }
 
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:source-protocol
+ */
+int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify(
+       struct nb_cb_modify_args *args)
+{
+       struct routemap_hook_context *rhc;
+       enum rmap_compile_rets ret;
+       const char *proto;
+
+       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);
+               proto = yang_dnode_get_string(args->dnode, NULL);
+
+               /* Set destroy information. */
+               rhc->rhc_mhook = bgp_route_match_delete;
+               rhc->rhc_rule = "source-protocol";
+               rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+               ret = bgp_route_match_add(rhc->rhc_rmi, "source-protocol",
+                                         proto, 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_source_protocol_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:rpki-extcommunity
index 9b2e18b4a780a65cefa9fcd279ddb85f45c8a5d8..7277744dc5b96d0ae310c860f0045b10f3e1cd23 100644 (file)
@@ -259,6 +259,8 @@ DECLARE_QOBJ_TYPE(route_map);
        (strmatch(C, "frr-zebra-route-map:ipv4-next-hop-prefix-length"))
 #define IS_MATCH_SRC_PROTO(C)                                                  \
        (strmatch(C, "frr-zebra-route-map:source-protocol"))
+#define IS_MATCH_BGP_SRC_PROTO(C)                                              \
+       (strmatch(C, "frr-bgp-route-map:source-protocol"))
 #define IS_MATCH_SRC_INSTANCE(C)                                               \
        (strmatch(C, "frr-zebra-route-map:source-instance"))
 /* BGP route-map match conditions */
index 419086c4c6bb92d03fc3f004cb548ca406bf50ec..0ccc78e8380fecbbf6f1756c97b48579f15543a1 100644 (file)
@@ -599,11 +599,14 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
                        yang_dnode_get_string(
                                dnode,
                                "./rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length"));
-       } else if (IS_MATCH_SRC_PROTO(condition)) {
+       } else if (IS_MATCH_SRC_PROTO(condition) ||
+                  IS_MATCH_BGP_SRC_PROTO(condition)) {
                vty_out(vty, " match source-protocol %s\n",
                        yang_dnode_get_string(
                                dnode,
-                               "./rmap-match-condition/frr-zebra-route-map:source-protocol"));
+                               IS_MATCH_SRC_PROTO(condition)
+                                       ? "./rmap-match-condition/frr-zebra-route-map:source-protocol"
+                                       : "./rmap-match-condition/frr-bgp-route-map:source-protocol"));
        } else if (IS_MATCH_SRC_INSTANCE(condition)) {
                vty_out(vty, " match source-instance %s\n",
                        yang_dnode_get_string(
index 23e5b0227ca9d4692fd95bac08473d250d9c9fc7..b557cabb22ae4770a7ae9bf00fae037fc358c3e0 100644 (file)
@@ -23,6 +23,10 @@ module frr-bgp-route-map {
     prefix rt-types;
   }
 
+  import frr-route-types {
+    prefix frr-route-types;
+  }
+
   organization
     "Free Range Routing";
   contact
@@ -168,6 +172,12 @@ module frr-bgp-route-map {
       "Match IPv6 next hop address";
   }
 
+  identity source-protocol {
+    base frr-route-map:rmap-match-type;
+    description
+      "Match protocol via which the route was learnt";
+  }
+
   identity distance {
     base frr-route-map:rmap-set-type;
     description
@@ -759,6 +769,13 @@ module frr-bgp-route-map {
           "IPv6 address";
       }
     }
+
+    case source-protocol {
+      when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:source-protocol')";
+      leaf source-protocol {
+        type frr-route-types:frr-route-types;
+      }
+    }
   }
 
   augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" {