X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=bgpd%2Fbgp_attr.c;h=fcfb1d64e0fd954bfe19200e06773474b56c8be8;hb=9a4bb5e469095636e1e0c90228bd9bbc3087b100;hp=f3848db072df765de6f1e149a85c824c6d7efb3b;hpb=7126fa3d6625075ad57f4c9a79d91b193d6e0252;p=mirror_frr.git diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index f3848db07..fcfb1d64e 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1,21 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* BGP attributes management routines. * Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro - * - * This file is part of GNU Zebra. - * - * GNU Zebra is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * GNU Zebra is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; see the file COPYING; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include @@ -33,6 +18,7 @@ #include "filter.h" #include "command.h" #include "srv6.h" +#include "frrstr.h" #include "bgpd/bgpd.h" #include "bgpd/bgp_attr.h" @@ -73,7 +59,6 @@ static const struct message attr_str[] = { {BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES"}, {BGP_ATTR_AS4_PATH, "AS4_PATH"}, {BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR"}, - {BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT"}, {BGP_ATTR_PMSI_TUNNEL, "PMSI_TUNNEL_ATTRIBUTE"}, {BGP_ATTR_ENCAP, "ENCAP"}, {BGP_ATTR_OTC, "OTC"}, @@ -1069,7 +1054,7 @@ struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp, attr->origin = origin; attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN); - attr->aspath = aspath_empty(); + attr->aspath = aspath_empty(bgp->asnotation); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); attr->weight = BGP_ATTR_DEFAULT_WEIGHT; attr->tag = 0; @@ -1107,7 +1092,7 @@ struct attr *bgp_attr_aggregate_intern( if (aspath) attr.aspath = aspath_intern(aspath); else - attr.aspath = aspath_empty(); + attr.aspath = aspath_empty(bgp->asnotation); attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); /* Next hop attribute. */ @@ -1605,15 +1590,19 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args) struct attr *const attr = args->attr; struct peer *const peer = args->peer; const bgp_size_t length = args->length; + enum asnotation_mode asnotation; + asnotation = bgp_get_asnotation( + args->peer && args->peer->bgp ? args->peer->bgp : NULL); /* * peer with AS4 => will get 4Byte ASnums * otherwise, will get 16 Bit */ - attr->aspath = aspath_parse( - peer->curr, length, - CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) - && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV)); + attr->aspath = + aspath_parse(peer->curr, length, + CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) && + CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV), + asnotation); /* In case of IBGP, length will be zero. */ if (!attr->aspath) { @@ -1629,7 +1618,8 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args) * such messages, conformant BGP speakers SHOULD use the "Treat-as- * withdraw" error handling behavior as per [RFC7606]. */ - if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) { + if (peer->bgp && peer->bgp->reject_as_sets && + aspath_check_as_sets(attr->aspath)) { flog_err(EC_BGP_ATTR_MAL_AS_PATH, "AS_SET and AS_CONFED_SET are deprecated from %pBP", peer); @@ -1705,8 +1695,11 @@ static int bgp_attr_as4_path(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; + enum asnotation_mode asnotation; + + asnotation = bgp_get_asnotation(peer->bgp); - *as4_path = aspath_parse(peer->curr, length, 1); + *as4_path = aspath_parse(peer->curr, length, 1, asnotation); /* In case of IBGP, length will be zero. */ if (!*as4_path) { @@ -1851,6 +1844,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; @@ -1863,10 +1857,18 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args) args->total); } + if (peer->discard_attrs[args->type] || peer->withdraw_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); + + return bgp_attr_ignore(peer, args->type); } /* Aggregator attribute */ @@ -1892,6 +1894,9 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args) args->total); } + if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type]) + goto aggregator_ignore; + if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) aggregator_as = stream_getl(peer->curr); else @@ -1918,6 +1923,11 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args) } return BGP_ATTR_PARSE_PROCEED; + +aggregator_ignore: + stream_forward_getp(peer->curr, length); + + return bgp_attr_ignore(peer, args->type); } /* New Aggregator attribute */ @@ -1938,6 +1948,9 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args, 0); } + if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type]) + goto as4_aggregator_ignore; + aggregator_as = stream_getl(peer->curr); *as4_aggregator_as = aggregator_as; @@ -1961,6 +1974,11 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args, } return BGP_ATTR_PARSE_PROCEED; + +as4_aggregator_ignore: + stream_forward_getp(peer->curr, length); + + return bgp_attr_ignore(peer, args->type); } /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH. @@ -2080,6 +2098,9 @@ bgp_attr_community(struct bgp_attr_parser_args *args) args->total); } + if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type]) + goto community_ignore; + bgp_attr_set_community( attr, community_parse((uint32_t *)stream_pnt(peer->curr), length)); @@ -2095,6 +2116,11 @@ bgp_attr_community(struct bgp_attr_parser_args *args) args->total); return BGP_ATTR_PARSE_PROCEED; + +community_ignore: + stream_forward_getp(peer->curr, length); + + return bgp_attr_ignore(peer, args->type); } /* Originator ID attribute. */ @@ -2118,11 +2144,19 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args) args->total); } + 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); attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID); return BGP_ATTR_PARSE_PROCEED; + +originator_id_ignore: + stream_forward_getp(peer->curr, length); + + return bgp_attr_ignore(peer, args->type); } /* Cluster list attribute. */ @@ -2145,6 +2179,9 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args) args->total); } + if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type]) + goto cluster_list_ignore; + bgp_attr_set_cluster( attr, cluster_parse((struct in_addr *)stream_pnt(peer->curr), length)); @@ -2155,6 +2192,11 @@ 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); + + return bgp_attr_ignore(peer, args->type); } /* Multiprotocol reachability information parse. */ @@ -2414,6 +2456,9 @@ bgp_attr_large_community(struct bgp_attr_parser_args *args) args->total); } + if (peer->discard_attrs[args->type] || peer->withdraw_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 */ @@ -2424,6 +2469,11 @@ 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); + + return bgp_attr_ignore(peer, args->type); } /* Extended Community attribute. */ @@ -2515,6 +2565,9 @@ bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args) args->total); } + if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type]) + goto ipv6_ext_community_ignore; + ipv6_ecomm = ecommunity_parse_ipv6( stream_pnt(peer->curr), length, CHECK_FLAG(peer->flags, @@ -2529,6 +2582,11 @@ 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); + + return bgp_attr_ignore(peer, args->type); } /* Parse Tunnel Encap attribute in an UPDATE */ @@ -3203,6 +3261,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] || peer->withdraw_attrs[args->type]) + goto aigp_ignore; + if (!bgp_attr_aigp_valid(s, length)) goto aigp_ignore; @@ -3213,7 +3274,7 @@ static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args) aigp_ignore: stream_forward_getp(peer->curr, length); - return BGP_ATTR_PARSE_PROCEED; + return bgp_attr_ignore(peer, args->type); } /* OTC attribute. */ @@ -3231,6 +3292,9 @@ static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args) args->total); } + if (peer->discard_attrs[args->type] || peer->withdraw_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"); @@ -3241,6 +3305,11 @@ 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); + + return bgp_attr_ignore(peer, args->type); } /* BGP unknown attribute treatment. */ @@ -3264,6 +3333,9 @@ 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] || 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 Attribute. The Data field contains the unrecognized attribute @@ -3904,23 +3976,21 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, } } break; case SAFI_MPLS_VPN: { - if (attr->mp_nexthop_len - == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - stream_putc(s, 48); - stream_putl(s, 0); /* RD = 0, per RFC */ - stream_putl(s, 0); - stream_put(s, &attr->mp_nexthop_global, - IPV6_MAX_BYTELEN); + if (attr->mp_nexthop_len == + BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) + stream_putc(s, attr->mp_nexthop_len); + else + stream_putc(s, BGP_ATTR_NHLEN_VPNV6_GLOBAL); + stream_putl(s, 0); /* RD = 0, per RFC */ + stream_putl(s, 0); + stream_put(s, &attr->mp_nexthop_global, + IPV6_MAX_BYTELEN); + if (attr->mp_nexthop_len == + BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) { stream_putl(s, 0); /* RD = 0, per RFC */ stream_putl(s, 0); stream_put(s, &attr->mp_nexthop_local, IPV6_MAX_BYTELEN); - } else { - stream_putc(s, 24); - stream_putl(s, 0); /* RD = 0, per RFC */ - stream_putl(s, 0); - stream_put(s, &attr->mp_nexthop_global, - IPV6_MAX_BYTELEN); } } break; case SAFI_ENCAP: @@ -4971,3 +5041,156 @@ 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, 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 (!discard_attrs) { + for (i = 0; i < BGP_ATTR_MAX; i++) + peer->discard_attrs[i] = false; + goto discard_soft_clear; + } + + if (discard_attrs) { + frrstr_split(discard_attrs, " ", &attributes, &num_attributes); + + if (set) + 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] = set; + } + XFREE(MTYPE_TMP, attributes); + discard_soft_clear: + /* 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); + } +} + +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; +}