]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_attr.c
bgpd: Add `neighbor path-attribute discard` command
[mirror_frr.git] / bgpd / bgp_attr.c
index 908c024e9d31ee20ffe19f4136a8eadf81681451..4306d3bd121451f6a406e7d24354d63b86ea2dfc 100644 (file)
@@ -33,6 +33,7 @@
 #include "filter.h"
 #include "command.h"
 #include "srv6.h"
+#include "frrstr.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_attr.h"
@@ -1850,6 +1851,7 @@ stream_failure:
 /* Atomic aggregate. */
 static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
 {
+       struct peer *const peer = args->peer;
        struct attr *const attr = args->attr;
        const bgp_size_t length = args->length;
 
@@ -1862,10 +1864,22 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto atomic_ignore;
+
        /* Set atomic aggregate flag. */
        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* Aggregator attribute */
@@ -1891,6 +1905,9 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto aggregator_ignore;
+
        if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV))
                aggregator_as = stream_getl(peer->curr);
        else
@@ -1917,6 +1934,15 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
        }
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* New Aggregator attribute */
@@ -1937,6 +1963,9 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
                                          0);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto as4_aggregator_ignore;
+
        aggregator_as = stream_getl(peer->curr);
 
        *as4_aggregator_as = aggregator_as;
@@ -1960,6 +1989,15 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
        }
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
@@ -2079,6 +2117,9 @@ bgp_attr_community(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto community_ignore;
+
        bgp_attr_set_community(
                attr,
                community_parse((uint32_t *)stream_pnt(peer->curr), length));
@@ -2094,6 +2135,15 @@ bgp_attr_community(struct bgp_attr_parser_args *args)
                                          args->total);
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* Originator ID attribute. */
@@ -2117,11 +2167,23 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto originator_id_ignore;
+
        attr->originator_id.s_addr = stream_get_ipv4(peer->curr);
 
        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID);
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* Cluster list attribute. */
@@ -2144,6 +2206,9 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto cluster_list_ignore;
+
        bgp_attr_set_cluster(
                attr, cluster_parse((struct in_addr *)stream_pnt(peer->curr),
                                    length));
@@ -2154,6 +2219,15 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST);
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* Multiprotocol reachability information parse. */
@@ -2413,6 +2487,9 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto large_community_ignore;
+
        bgp_attr_set_lcommunity(
                attr, lcommunity_parse(stream_pnt(peer->curr), length));
        /* XXX: fix ecommunity_parse to use stream API */
@@ -2423,6 +2500,15 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args)
                                          args->total);
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* Extended Community attribute. */
@@ -2514,6 +2600,9 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto ipv6_ext_community_ignore;
+
        ipv6_ecomm = ecommunity_parse_ipv6(
                stream_pnt(peer->curr), length,
                CHECK_FLAG(peer->flags,
@@ -2528,6 +2617,15 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
                                          args->total);
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* Parse Tunnel Encap attribute in an UPDATE */
@@ -3202,6 +3300,9 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
                goto aigp_ignore;
        }
 
+       if (peer->discard_attrs[args->type])
+               goto aigp_ignore;
+
        if (!bgp_attr_aigp_valid(s, length))
                goto aigp_ignore;
 
@@ -3212,6 +3313,10 @@ 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;
 }
 
@@ -3230,6 +3335,9 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
                                          args->total);
        }
 
+       if (peer->discard_attrs[args->type])
+               goto otc_ignore;
+
        attr->otc = stream_getl(peer->curr);
        if (!attr->otc) {
                flog_err(EC_BGP_ATTR_MAL_AS_PATH, "OTC attribute value is 0");
@@ -3240,6 +3348,15 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
        attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC);
 
        return BGP_ATTR_PARSE_PROCEED;
+
+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;
 }
 
 /* BGP unknown attribute treatment. */
@@ -3263,6 +3380,14 @@ 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 any of the mandatory well-known attributes are not recognized,
           then the Error Subcode is set to Unrecognized Well-known
           Attribute.  The Data field contains the unrecognized attribute
@@ -4970,3 +5095,62 @@ void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
        len = stream_get_endp(s) - cp - 2;
        stream_putw_at(s, cp, len);
 }
+
+void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer,
+                                   const char *discard_attrs)
+{
+       int i, num_attributes;
+       char **attributes;
+       afi_t afi;
+       safi_t safi;
+
+       if (discard_attrs) {
+               frrstr_split(discard_attrs, " ", &attributes, &num_attributes);
+
+               for (i = 0; i < BGP_ATTR_MAX; i++)
+                       peer->discard_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 discard 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 discard path-attribute %s only for eBGP, ignoring.\n",
+                                       lookup_msg(attr_str, attr_num, NULL));
+                               continue;
+                       }
+
+                       peer->discard_attrs[attr_num] = true;
+               }
+               XFREE(MTYPE_TMP, attributes);
+
+               /* Configuring path attributes to be discarded 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);
+       }
+}