]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: Add `neighbor path-attribute treat-as-withdraw` command
authorDonatas Abraitis <donatas@opensourcerouting.org>
Tue, 24 Jan 2023 09:02:24 +0000 (11:02 +0200)
committerDonatas Abraitis <donatas@opensourcerouting.org>
Wed, 1 Feb 2023 20:57:34 +0000 (22:57 +0200)
To filter out routes with unwanted prefixes.

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h

index 392b558805272259d42cb1433ff4a99164bc7577..572475f06856a5e4258c64506860ae849c9268b0 100644 (file)
@@ -1864,7 +1864,7 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto atomic_ignore;
 
        /* Set atomic aggregate flag. */
@@ -1875,11 +1875,7 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
 atomic_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* Aggregator attribute */
@@ -1905,7 +1901,7 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto aggregator_ignore;
 
        if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV))
@@ -1938,11 +1934,7 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
 aggregator_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* New Aggregator attribute */
@@ -1963,7 +1955,7 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
                                          0);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto as4_aggregator_ignore;
 
        aggregator_as = stream_getl(peer->curr);
@@ -1993,11 +1985,7 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
 as4_aggregator_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
@@ -2117,7 +2105,7 @@ bgp_attr_community(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto community_ignore;
 
        bgp_attr_set_community(
@@ -2139,11 +2127,7 @@ bgp_attr_community(struct bgp_attr_parser_args *args)
 community_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* Originator ID attribute. */
@@ -2167,7 +2151,7 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto originator_id_ignore;
 
        attr->originator_id.s_addr = stream_get_ipv4(peer->curr);
@@ -2179,11 +2163,7 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args)
 originator_id_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* Cluster list attribute. */
@@ -2206,7 +2186,7 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto cluster_list_ignore;
 
        bgp_attr_set_cluster(
@@ -2223,11 +2203,7 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
 cluster_list_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* Multiprotocol reachability information parse. */
@@ -2487,7 +2463,7 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto large_community_ignore;
 
        bgp_attr_set_lcommunity(
@@ -2504,11 +2480,7 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args)
 large_community_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* Extended Community attribute. */
@@ -2600,7 +2572,7 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto ipv6_ext_community_ignore;
 
        ipv6_ecomm = ecommunity_parse_ipv6(
@@ -2621,11 +2593,7 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
 ipv6_ext_community_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* Parse Tunnel Encap attribute in an UPDATE */
@@ -3300,7 +3268,7 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
                goto aigp_ignore;
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto aigp_ignore;
 
        if (!bgp_attr_aigp_valid(s, length))
@@ -3313,11 +3281,7 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
 aigp_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* OTC attribute. */
@@ -3335,7 +3299,7 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
-       if (peer->discard_attrs[args->type])
+       if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
                goto otc_ignore;
 
        attr->otc = stream_getl(peer->curr);
@@ -3352,11 +3316,7 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
 otc_ignore:
        stream_forward_getp(peer->curr, length);
 
-       if (bgp_debug_update(peer, NULL, NULL, 1))
-               zlog_debug("%pBP: Ignoring attribute %s", peer,
-                          lookup_msg(attr_str, args->type, NULL));
-
-       return BGP_ATTR_PARSE_PROCEED;
+       return bgp_attr_ignore(peer, args->type);
 }
 
 /* BGP unknown attribute treatment. */
@@ -3380,13 +3340,8 @@ bgp_attr_unknown(struct bgp_attr_parser_args *args)
        /* Forward read pointer of input stream. */
        stream_forward_getp(peer->curr, length);
 
-       if (peer->discard_attrs[type]) {
-               if (bgp_debug_update(peer, NULL, NULL, 1))
-                       zlog_debug("%pBP: Ignoring attribute %s", peer,
-                                  lookup_msg(attr_str, args->type, NULL));
-
-               return BGP_ATTR_PARSE_PROCEED;
-       }
+       if (peer->discard_attrs[type] || peer->withdraw_attrs[type])
+               return bgp_attr_ignore(peer, type);
 
        /* If any of the mandatory well-known attributes are not recognized,
           then the Error Subcode is set to Unrecognized Well-known
@@ -5165,3 +5120,86 @@ void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer,
                        peer_clear_soft(peer, afi, safi, BGP_CLEAR_SOFT_IN);
        }
 }
+
+void bgp_path_attribute_withdraw_vty(struct vty *vty, struct peer *peer,
+                                    const char *withdraw_attrs, bool set)
+{
+       int i, num_attributes;
+       char **attributes;
+       afi_t afi;
+       safi_t safi;
+
+       /* If `no` command specified without arbitrary attributes,
+        * then flush all.
+        */
+       if (!withdraw_attrs) {
+               for (i = 0; i < BGP_ATTR_MAX; i++)
+                       peer->withdraw_attrs[i] = false;
+               goto withdraw_soft_clear;
+       }
+
+       if (withdraw_attrs) {
+               frrstr_split(withdraw_attrs, " ", &attributes, &num_attributes);
+
+               if (set)
+                       for (i = 0; i < BGP_ATTR_MAX; i++)
+                               peer->withdraw_attrs[i] = false;
+
+               for (i = 0; i < num_attributes; i++) {
+                       uint8_t attr_num = strtoul(attributes[i], NULL, 10);
+
+                       XFREE(MTYPE_TMP, attributes[i]);
+
+                       /* Some of the attributes, just can't be ignored. */
+                       if (attr_num == BGP_ATTR_ORIGIN ||
+                           attr_num == BGP_ATTR_AS_PATH ||
+                           attr_num == BGP_ATTR_NEXT_HOP ||
+                           attr_num == BGP_ATTR_MULTI_EXIT_DISC ||
+                           attr_num == BGP_ATTR_MP_REACH_NLRI ||
+                           attr_num == BGP_ATTR_MP_UNREACH_NLRI ||
+                           attr_num == BGP_ATTR_EXT_COMMUNITIES) {
+                               vty_out(vty,
+                                       "%% Can't treat-as-withdraw path-attribute %s, ignoring.\n",
+                                       lookup_msg(attr_str, attr_num, NULL));
+                               continue;
+                       }
+
+                       /* Ignore local-pref, originator-id, cluster-list only
+                        * for eBGP.
+                        */
+                       if (peer->sort != BGP_PEER_EBGP &&
+                           (attr_num == BGP_ATTR_LOCAL_PREF ||
+                            attr_num == BGP_ATTR_ORIGINATOR_ID ||
+                            attr_num == BGP_ATTR_CLUSTER_LIST)) {
+                               vty_out(vty,
+                                       "%% Can treat-as-withdraw path-attribute %s only for eBGP, ignoring.\n",
+                                       lookup_msg(attr_str, attr_num, NULL));
+                               continue;
+                       }
+
+                       peer->withdraw_attrs[attr_num] = set;
+               }
+               XFREE(MTYPE_TMP, attributes);
+       withdraw_soft_clear:
+               /* Configuring path attributes to be treated as withdraw will
+                * trigger
+                * an inbound Route Refresh to ensure that the routing table
+                * is up to date.
+                */
+               FOREACH_AFI_SAFI (afi, safi)
+                       peer_clear_soft(peer, afi, safi, BGP_CLEAR_SOFT_IN);
+       }
+}
+
+enum bgp_attr_parse_ret bgp_attr_ignore(struct peer *peer, uint8_t type)
+{
+       bool discard = peer->discard_attrs[type];
+       bool withdraw = peer->withdraw_attrs[type];
+
+       if (bgp_debug_update(peer, NULL, NULL, 1) && (discard || withdraw))
+               zlog_debug("%pBP: Ignoring attribute %s (%s)", peer,
+                          lookup_msg(attr_str, type, NULL),
+                          withdraw ? "treat-as-withdraw" : "discard");
+
+       return withdraw ? BGP_ATTR_PARSE_WITHDRAW : BGP_ATTR_PARSE_PROCEED;
+}
index 33283f4bf6d12d2c9a3a8d1b94e52f596f31d828..e3499079d5ef25d9936ed826194ff295b291d1c5 100644 (file)
@@ -416,6 +416,10 @@ extern unsigned long int attr_count(void);
 extern unsigned long int attr_unknown_count(void);
 extern void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer,
                                           const char *discard_attrs, bool set);
+extern void bgp_path_attribute_withdraw_vty(struct vty *vty, struct peer *peer,
+                                           const char *withdraw_attrs,
+                                           bool set);
+extern enum bgp_attr_parse_ret bgp_attr_ignore(struct peer *peer, uint8_t type);
 
 /* Cluster list prototypes. */
 extern bool cluster_loop_check(struct cluster_list *cluster,
index d837601f3264dbabc80838a25de0853230cf7837..0ba3c760c32c17ae388a338d172d9d3a59bd797c 100644 (file)
@@ -8819,6 +8819,59 @@ DEFPY(no_neighbor_path_attribute_discard,
        return CMD_SUCCESS;
 }
 
+DEFPY(neighbor_path_attribute_treat_as_withdraw,
+      neighbor_path_attribute_treat_as_withdraw_cmd,
+      "neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor path-attribute treat-as-withdraw (1-255)...",
+      NEIGHBOR_STR
+      NEIGHBOR_ADDR_STR2
+      "Manipulate path attributes from incoming UPDATE messages\n"
+      "Treat-as-withdraw any incoming BGP UPDATE messages that contain the specified attribute\n"
+      "Attribute number\n")
+{
+       struct peer *peer;
+       int idx = 0;
+       const char *withdraw_attrs = NULL;
+
+       peer = peer_and_group_lookup_vty(vty, neighbor);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       argv_find(argv, argc, "(1-255)", &idx);
+       if (idx)
+               withdraw_attrs = argv_concat(argv, argc, idx);
+
+       bgp_path_attribute_withdraw_vty(vty, peer, withdraw_attrs, true);
+
+       return CMD_SUCCESS;
+}
+
+DEFPY(no_neighbor_path_attribute_treat_as_withdraw,
+      no_neighbor_path_attribute_treat_as_withdraw_cmd,
+      "no neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor path-attribute treat-as-withdraw (1-255)...",
+      NO_STR
+      NEIGHBOR_STR
+      NEIGHBOR_ADDR_STR2
+      "Manipulate path attributes from incoming UPDATE messages\n"
+      "Treat-as-withdraw any incoming BGP UPDATE messages that contain the specified attribute\n"
+      "Attribute number\n")
+{
+       struct peer *peer;
+       int idx = 0;
+       const char *withdraw_attrs = NULL;
+
+       peer = peer_and_group_lookup_vty(vty, neighbor);
+       if (!peer)
+               return CMD_WARNING_CONFIG_FAILED;
+
+       argv_find(argv, argc, "(1-255)", &idx);
+       if (idx)
+               withdraw_attrs = argv_concat(argv, argc, idx);
+
+       bgp_path_attribute_withdraw_vty(vty, peer, withdraw_attrs, false);
+
+       return CMD_SUCCESS;
+}
+
 static int set_ecom_list(struct vty *vty, int argc, struct cmd_token **argv,
                         struct ecommunity **list, bool is_rt6)
 {
@@ -17459,6 +17512,16 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
                vty_out(vty, " neighbor %s path-attribute discard %s\n", addr,
                        discard_attrs_str);
 
+       /* path-attribute treat-as-withdraw */
+       char withdraw_attrs_str[BUFSIZ] = {0};
+       bool withdraw_attrs = bgp_path_attribute_treat_as_withdraw(
+               peer, withdraw_attrs_str, sizeof(withdraw_attrs_str));
+
+       if (withdraw_attrs)
+               vty_out(vty,
+                       " neighbor %s path-attribute treat-as-withdraw %s\n",
+                       addr, withdraw_attrs_str);
+
        if (!CHECK_FLAG(peer->peer_gr_new_status_flag,
                        PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) {
 
@@ -19570,6 +19633,12 @@ void bgp_vty_init(void)
        install_element(BGP_NODE, &neighbor_path_attribute_discard_cmd);
        install_element(BGP_NODE, &no_neighbor_path_attribute_discard_cmd);
 
+       /* "neighbor path-attribute treat-as-withdraw" commands. */
+       install_element(BGP_NODE,
+                       &neighbor_path_attribute_treat_as_withdraw_cmd);
+       install_element(BGP_NODE,
+                       &no_neighbor_path_attribute_treat_as_withdraw_cmd);
+
        /* "neighbor passive" commands. */
        install_element(BGP_NODE, &neighbor_passive_cmd);
        install_element(BGP_NODE, &no_neighbor_passive_cmd);
index 39010e76f9d1bd164336aa29564af93b72fe9221..f4e823e21286da553286eb205c5c5a6f82a16172 100644 (file)
@@ -4213,6 +4213,26 @@ bool bgp_path_attribute_discard(struct peer *peer, char *buf, size_t size)
        return false;
 }
 
+bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf,
+                                         size_t size)
+{
+       if (!buf)
+               return false;
+
+       buf[0] = '\0';
+
+       for (unsigned int i = 0; i < BGP_ATTR_MAX; i++) {
+               if (peer->withdraw_attrs[i])
+                       snprintf(buf + strlen(buf), size - strlen(buf), "%s%d",
+                                (strlen(buf) > 0) ? " " : "", i);
+       }
+
+       if (strlen(buf) > 0)
+               return true;
+
+       return false;
+}
+
 /* If peer is configured at least one address family return 1. */
 bool peer_active(struct peer *peer)
 {
index 4c4c81f997a0e18a68f517499c7d70365bbcc78e..8f7040dce6e85b4e4f09313d6cfbeb039878817d 100644 (file)
@@ -1768,6 +1768,9 @@ struct peer {
        /* Path attributes discard */
        bool discard_attrs[BGP_ATTR_MAX];
 
+       /* Path attributes treat-as-withdraw */
+       bool withdraw_attrs[BGP_ATTR_MAX];
+
        QOBJ_FIELDS;
 };
 DECLARE_QOBJ_TYPE(peer);
@@ -2620,6 +2623,8 @@ extern void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
                                  int outbound);
 extern bool bgp_path_attribute_discard(struct peer *peer, char *buf,
                                       size_t size);
+extern bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf,
+                                                size_t size);
 #ifdef _FRR_ATTRIBUTE_PRINTFRR
 /* clang-format off */
 #pragma FRR printfrr_ext "%pBP" (struct peer *)