back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_attr.c (source / functions) Hit Total Coverage
Test: test_exabgp_demo.py::ExaBGPDemo Lines: 395 2454 16.1 %
Date: 2023-02-24 18:37:55 Functions: 31 114 27.2 %

          Line data    Source code
       1             : /* BGP attributes management routines.
       2             :  * Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "linklist.h"
      24             : #include "prefix.h"
      25             : #include "memory.h"
      26             : #include "vector.h"
      27             : #include "stream.h"
      28             : #include "log.h"
      29             : #include "hash.h"
      30             : #include "jhash.h"
      31             : #include "queue.h"
      32             : #include "table.h"
      33             : #include "filter.h"
      34             : #include "command.h"
      35             : #include "srv6.h"
      36             : #include "frrstr.h"
      37             : 
      38             : #include "bgpd/bgpd.h"
      39             : #include "bgpd/bgp_attr.h"
      40             : #include "bgpd/bgp_route.h"
      41             : #include "bgpd/bgp_aspath.h"
      42             : #include "bgpd/bgp_community.h"
      43             : #include "bgpd/bgp_debug.h"
      44             : #include "bgpd/bgp_errors.h"
      45             : #include "bgpd/bgp_label.h"
      46             : #include "bgpd/bgp_packet.h"
      47             : #include "bgpd/bgp_ecommunity.h"
      48             : #include "bgpd/bgp_lcommunity.h"
      49             : #include "bgpd/bgp_updgrp.h"
      50             : #include "bgpd/bgp_encap_types.h"
      51             : #ifdef ENABLE_BGP_VNC
      52             : #include "bgpd/rfapi/bgp_rfapi_cfg.h"
      53             : #include "bgp_encap_types.h"
      54             : #include "bgp_vnc_types.h"
      55             : #endif
      56             : #include "bgp_evpn.h"
      57             : #include "bgp_flowspec_private.h"
      58             : #include "bgp_mac.h"
      59             : 
      60             : /* Attribute strings for logging. */
      61             : static const struct message attr_str[] = {
      62             :         {BGP_ATTR_ORIGIN, "ORIGIN"},
      63             :         {BGP_ATTR_AS_PATH, "AS_PATH"},
      64             :         {BGP_ATTR_NEXT_HOP, "NEXT_HOP"},
      65             :         {BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC"},
      66             :         {BGP_ATTR_LOCAL_PREF, "LOCAL_PREF"},
      67             :         {BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE"},
      68             :         {BGP_ATTR_AGGREGATOR, "AGGREGATOR"},
      69             :         {BGP_ATTR_COMMUNITIES, "COMMUNITY"},
      70             :         {BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID"},
      71             :         {BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST"},
      72             :         {BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI"},
      73             :         {BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI"},
      74             :         {BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES"},
      75             :         {BGP_ATTR_AS4_PATH, "AS4_PATH"},
      76             :         {BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR"},
      77             :         {BGP_ATTR_PMSI_TUNNEL, "PMSI_TUNNEL_ATTRIBUTE"},
      78             :         {BGP_ATTR_ENCAP, "ENCAP"},
      79             :         {BGP_ATTR_OTC, "OTC"},
      80             : #ifdef ENABLE_BGP_VNC_ATTR
      81             :         {BGP_ATTR_VNC, "VNC"},
      82             : #endif
      83             :         {BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"},
      84             :         {BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
      85             :         {BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"},
      86             :         {BGP_ATTR_AIGP, "AIGP"},
      87             :         {0}};
      88             : 
      89             : static const struct message attr_flag_str[] = {
      90             :         {BGP_ATTR_FLAG_OPTIONAL, "Optional"},
      91             :         {BGP_ATTR_FLAG_TRANS, "Transitive"},
      92             :         {BGP_ATTR_FLAG_PARTIAL, "Partial"},
      93             :         /* bgp_attr_flags_diagnose() relies on this bit being last in
      94             :            this list */
      95             :         {BGP_ATTR_FLAG_EXTLEN, "Extended Length"},
      96             :         {0}};
      97             : 
      98             : static struct hash *cluster_hash;
      99             : 
     100           0 : static void *cluster_hash_alloc(void *p)
     101             : {
     102           0 :         const struct cluster_list *val = (const struct cluster_list *)p;
     103           0 :         struct cluster_list *cluster;
     104             : 
     105           0 :         cluster = XMALLOC(MTYPE_CLUSTER, sizeof(struct cluster_list));
     106           0 :         cluster->length = val->length;
     107             : 
     108           0 :         if (cluster->length) {
     109           0 :                 cluster->list = XMALLOC(MTYPE_CLUSTER_VAL, val->length);
     110           0 :                 memcpy(cluster->list, val->list, val->length);
     111             :         } else
     112           0 :                 cluster->list = NULL;
     113             : 
     114           0 :         cluster->refcnt = 0;
     115             : 
     116           0 :         return cluster;
     117             : }
     118             : 
     119             : /* Cluster list related functions. */
     120           0 : static struct cluster_list *cluster_parse(struct in_addr *pnt, int length)
     121             : {
     122           0 :         struct cluster_list tmp = {};
     123           0 :         struct cluster_list *cluster;
     124             : 
     125           0 :         tmp.length = length;
     126           0 :         tmp.list = length == 0 ? NULL : pnt;
     127             : 
     128           0 :         cluster = hash_get(cluster_hash, &tmp, cluster_hash_alloc);
     129           0 :         cluster->refcnt++;
     130           0 :         return cluster;
     131             : }
     132             : 
     133           0 : bool cluster_loop_check(struct cluster_list *cluster, struct in_addr originator)
     134             : {
     135           0 :         int i;
     136             : 
     137           0 :         for (i = 0; i < cluster->length / 4; i++)
     138           0 :                 if (cluster->list[i].s_addr == originator.s_addr)
     139             :                         return true;
     140             :         return false;
     141             : }
     142             : 
     143           0 : static unsigned int cluster_hash_key_make(const void *p)
     144             : {
     145           0 :         const struct cluster_list *cluster = p;
     146             : 
     147           0 :         return jhash(cluster->list, cluster->length, 0);
     148             : }
     149             : 
     150           0 : static bool cluster_hash_cmp(const void *p1, const void *p2)
     151             : {
     152           0 :         const struct cluster_list *cluster1 = p1;
     153           0 :         const struct cluster_list *cluster2 = p2;
     154             : 
     155           0 :         if (cluster1->list == cluster2->list)
     156             :                 return true;
     157             : 
     158           0 :         if (!cluster1->list || !cluster2->list)
     159             :                 return false;
     160             : 
     161           0 :         if (cluster1->length != cluster2->length)
     162             :                 return false;
     163             : 
     164           0 :         return (memcmp(cluster1->list, cluster2->list, cluster1->length) == 0);
     165             : }
     166             : 
     167           0 : static void cluster_free(struct cluster_list *cluster)
     168             : {
     169           0 :         XFREE(MTYPE_CLUSTER_VAL, cluster->list);
     170           0 :         XFREE(MTYPE_CLUSTER, cluster);
     171           0 : }
     172             : 
     173           0 : static struct cluster_list *cluster_intern(struct cluster_list *cluster)
     174             : {
     175           0 :         struct cluster_list *find;
     176             : 
     177           0 :         find = hash_get(cluster_hash, cluster, cluster_hash_alloc);
     178           0 :         find->refcnt++;
     179             : 
     180           0 :         return find;
     181             : }
     182             : 
     183           0 : static void cluster_unintern(struct cluster_list **cluster)
     184             : {
     185           0 :         if ((*cluster)->refcnt)
     186           0 :                 (*cluster)->refcnt--;
     187             : 
     188           0 :         if ((*cluster)->refcnt == 0) {
     189           0 :                 void *p = hash_release(cluster_hash, *cluster);
     190           0 :                 assert(p == *cluster);
     191           0 :                 cluster_free(*cluster);
     192           0 :                 *cluster = NULL;
     193             :         }
     194           0 : }
     195             : 
     196           3 : static void cluster_init(void)
     197             : {
     198           3 :         cluster_hash = hash_create(cluster_hash_key_make, cluster_hash_cmp,
     199             :                                    "BGP Cluster");
     200           3 : }
     201             : 
     202           3 : static void cluster_finish(void)
     203             : {
     204           3 :         hash_clean(cluster_hash, (void (*)(void *))cluster_free);
     205           3 :         hash_free(cluster_hash);
     206           3 :         cluster_hash = NULL;
     207           3 : }
     208             : 
     209             : static struct hash *encap_hash = NULL;
     210             : #ifdef ENABLE_BGP_VNC
     211             : static struct hash *vnc_hash = NULL;
     212             : #endif
     213             : static struct hash *srv6_l3vpn_hash;
     214             : static struct hash *srv6_vpn_hash;
     215             : 
     216           0 : struct bgp_attr_encap_subtlv *encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
     217             : {
     218           0 :         struct bgp_attr_encap_subtlv *new;
     219           0 :         struct bgp_attr_encap_subtlv *tail;
     220           0 :         struct bgp_attr_encap_subtlv *p;
     221             : 
     222           0 :         for (p = orig, tail = new = NULL; p; p = p->next) {
     223           0 :                 int size = sizeof(struct bgp_attr_encap_subtlv) + p->length;
     224           0 :                 if (tail) {
     225           0 :                         tail->next = XCALLOC(MTYPE_ENCAP_TLV, size);
     226           0 :                         tail = tail->next;
     227             :                 } else {
     228           0 :                         tail = new = XCALLOC(MTYPE_ENCAP_TLV, size);
     229             :                 }
     230           0 :                 assert(tail);
     231           0 :                 memcpy(tail, p, size);
     232           0 :                 tail->next = NULL;
     233             :         }
     234             : 
     235           0 :         return new;
     236             : }
     237             : 
     238           0 : static void encap_free(struct bgp_attr_encap_subtlv *p)
     239             : {
     240           0 :         struct bgp_attr_encap_subtlv *next;
     241           0 :         while (p) {
     242           0 :                 next = p->next;
     243           0 :                 p->next = NULL;
     244           0 :                 XFREE(MTYPE_ENCAP_TLV, p);
     245           0 :                 p = next;
     246             :         }
     247           0 : }
     248             : 
     249           0 : void bgp_attr_flush_encap(struct attr *attr)
     250             : {
     251           0 :         if (!attr)
     252             :                 return;
     253             : 
     254           0 :         if (attr->encap_subtlvs) {
     255           0 :                 encap_free(attr->encap_subtlvs);
     256           0 :                 attr->encap_subtlvs = NULL;
     257             :         }
     258             : #ifdef ENABLE_BGP_VNC
     259           0 :         struct bgp_attr_encap_subtlv *vnc_subtlvs =
     260           0 :                 bgp_attr_get_vnc_subtlvs(attr);
     261             : 
     262           0 :         if (vnc_subtlvs) {
     263           0 :                 encap_free(vnc_subtlvs);
     264           0 :                 bgp_attr_set_vnc_subtlvs(attr, NULL);
     265             :         }
     266             : #endif
     267             : }
     268             : 
     269             : /*
     270             :  * Compare encap sub-tlv chains
     271             :  *
     272             :  *      1 = equivalent
     273             :  *      0 = not equivalent
     274             :  *
     275             :  * This algorithm could be made faster if needed
     276             :  */
     277           2 : static bool encap_same(const struct bgp_attr_encap_subtlv *h1,
     278             :                        const struct bgp_attr_encap_subtlv *h2)
     279             : {
     280           2 :         const struct bgp_attr_encap_subtlv *p;
     281           2 :         const struct bgp_attr_encap_subtlv *q;
     282             : 
     283           2 :         if (h1 == h2)
     284             :                 return true;
     285           0 :         if (h1 == NULL || h2 == NULL)
     286             :                 return false;
     287             : 
     288           0 :         for (p = h1; p; p = p->next) {
     289           0 :                 for (q = h2; q; q = q->next) {
     290           0 :                         if ((p->type == q->type) && (p->length == q->length)
     291           0 :                             && !memcmp(p->value, q->value, p->length)) {
     292             : 
     293             :                                 break;
     294             :                         }
     295             :                 }
     296           0 :                 if (!q)
     297             :                         return false;
     298             :         }
     299             : 
     300           0 :         for (p = h2; p; p = p->next) {
     301           0 :                 for (q = h1; q; q = q->next) {
     302           0 :                         if ((p->type == q->type) && (p->length == q->length)
     303           0 :                             && !memcmp(p->value, q->value, p->length)) {
     304             : 
     305             :                                 break;
     306             :                         }
     307             :                 }
     308           0 :                 if (!q)
     309             :                         return false;
     310             :         }
     311             : 
     312             :         return true;
     313             : }
     314             : 
     315           0 : static void *encap_hash_alloc(void *p)
     316             : {
     317             :         /* Encap structure is already allocated.  */
     318           0 :         return p;
     319             : }
     320             : 
     321             : typedef enum {
     322             :         ENCAP_SUBTLV_TYPE,
     323             : #ifdef ENABLE_BGP_VNC
     324             :         VNC_SUBTLV_TYPE
     325             : #endif
     326             : } encap_subtlv_type;
     327             : 
     328             : static struct bgp_attr_encap_subtlv *
     329           0 : encap_intern(struct bgp_attr_encap_subtlv *encap, encap_subtlv_type type)
     330             : {
     331           0 :         struct bgp_attr_encap_subtlv *find;
     332           0 :         struct hash *hash = encap_hash;
     333             : #ifdef ENABLE_BGP_VNC
     334           0 :         if (type == VNC_SUBTLV_TYPE)
     335           0 :                 hash = vnc_hash;
     336             : #endif
     337             : 
     338           0 :         find = hash_get(hash, encap, encap_hash_alloc);
     339           0 :         if (find != encap)
     340           0 :                 encap_free(encap);
     341           0 :         find->refcnt++;
     342             : 
     343           0 :         return find;
     344             : }
     345             : 
     346           0 : static void encap_unintern(struct bgp_attr_encap_subtlv **encapp,
     347             :                            encap_subtlv_type type)
     348             : {
     349           0 :         struct bgp_attr_encap_subtlv *encap = *encapp;
     350           0 :         if (encap->refcnt)
     351           0 :                 encap->refcnt--;
     352             : 
     353           0 :         if (encap->refcnt == 0) {
     354           0 :                 struct hash *hash = encap_hash;
     355             : #ifdef ENABLE_BGP_VNC
     356           0 :                 if (type == VNC_SUBTLV_TYPE)
     357           0 :                         hash = vnc_hash;
     358             : #endif
     359           0 :                 hash_release(hash, encap);
     360           0 :                 encap_free(encap);
     361           0 :                 *encapp = NULL;
     362             :         }
     363           0 : }
     364             : 
     365           0 : static unsigned int encap_hash_key_make(const void *p)
     366             : {
     367           0 :         const struct bgp_attr_encap_subtlv *encap = p;
     368             : 
     369           0 :         return jhash(encap->value, encap->length, 0);
     370             : }
     371             : 
     372           0 : static bool encap_hash_cmp(const void *p1, const void *p2)
     373             : {
     374           0 :         return encap_same((const struct bgp_attr_encap_subtlv *)p1,
     375             :                           (const struct bgp_attr_encap_subtlv *)p2);
     376             : }
     377             : 
     378           3 : static void encap_init(void)
     379             : {
     380           3 :         encap_hash = hash_create(encap_hash_key_make, encap_hash_cmp,
     381             :                                  "BGP Encap Hash");
     382             : #ifdef ENABLE_BGP_VNC
     383           3 :         vnc_hash = hash_create(encap_hash_key_make, encap_hash_cmp,
     384             :                                "BGP VNC Hash");
     385             : #endif
     386           3 : }
     387             : 
     388           3 : static void encap_finish(void)
     389             : {
     390           3 :         hash_clean(encap_hash, (void (*)(void *))encap_free);
     391           3 :         hash_free(encap_hash);
     392           3 :         encap_hash = NULL;
     393             : #ifdef ENABLE_BGP_VNC
     394           3 :         hash_clean(vnc_hash, (void (*)(void *))encap_free);
     395           3 :         hash_free(vnc_hash);
     396           3 :         vnc_hash = NULL;
     397             : #endif
     398           3 : }
     399             : 
     400           1 : static bool overlay_index_same(const struct attr *a1, const struct attr *a2)
     401             : {
     402           1 :         if (!a1 && a2)
     403             :                 return false;
     404           1 :         if (!a2 && a1)
     405             :                 return false;
     406           1 :         if (!a1 && !a2)
     407             :                 return true;
     408             : 
     409           1 :         return bgp_route_evpn_same(bgp_attr_get_evpn_overlay(a1),
     410             :                                    bgp_attr_get_evpn_overlay(a2));
     411             : }
     412             : 
     413             : /* Unknown transit attribute. */
     414             : static struct hash *transit_hash;
     415             : 
     416           0 : static void transit_free(struct transit *transit)
     417             : {
     418           0 :         XFREE(MTYPE_TRANSIT_VAL, transit->val);
     419           0 :         XFREE(MTYPE_TRANSIT, transit);
     420           0 : }
     421             : 
     422           0 : static void *transit_hash_alloc(void *p)
     423             : {
     424             :         /* Transit structure is already allocated.  */
     425           0 :         return p;
     426             : }
     427             : 
     428           0 : static struct transit *transit_intern(struct transit *transit)
     429             : {
     430           0 :         struct transit *find;
     431             : 
     432           0 :         find = hash_get(transit_hash, transit, transit_hash_alloc);
     433           0 :         if (find != transit)
     434           0 :                 transit_free(transit);
     435           0 :         find->refcnt++;
     436             : 
     437           0 :         return find;
     438             : }
     439             : 
     440           0 : static void transit_unintern(struct transit **transit)
     441             : {
     442           0 :         if ((*transit)->refcnt)
     443           0 :                 (*transit)->refcnt--;
     444             : 
     445           0 :         if ((*transit)->refcnt == 0) {
     446           0 :                 hash_release(transit_hash, *transit);
     447           0 :                 transit_free(*transit);
     448           0 :                 *transit = NULL;
     449             :         }
     450           0 : }
     451             : 
     452           0 : static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length,
     453             :                                          uint64_t *aigp)
     454             : {
     455           0 :         uint8_t *data = pnt;
     456           0 :         uint8_t tlv_type;
     457           0 :         uint16_t tlv_length;
     458             : 
     459           0 :         while (length) {
     460           0 :                 tlv_type = *data;
     461           0 :                 ptr_get_be16(data + 1, &tlv_length);
     462           0 :                 (void)data;
     463             : 
     464             :                 /* The value field of the AIGP TLV is always 8 octets
     465             :                  * long and its value is interpreted as an unsigned 64-bit
     466             :                  * integer.
     467             :                  */
     468           0 :                 if (tlv_type == BGP_AIGP_TLV_METRIC) {
     469           0 :                         (void)ptr_get_be64(data + 3, aigp);
     470             : 
     471             :                         /* If an AIGP attribute is received and its first AIGP
     472             :                          * TLV contains the maximum value 0xffffffffffffffff,
     473             :                          * the attribute SHOULD be considered to be malformed
     474             :                          * and SHOULD be discarded as specified in this section.
     475             :                          */
     476           0 :                         if (*aigp == BGP_AIGP_TLV_METRIC_MAX) {
     477           0 :                                 zlog_err("Bad AIGP TLV (%s) length: %llu",
     478             :                                          BGP_AIGP_TLV_METRIC_DESC,
     479             :                                          BGP_AIGP_TLV_METRIC_MAX);
     480           0 :                                 return false;
     481             :                         }
     482             : 
     483             :                         return true;
     484             :                 }
     485             : 
     486           0 :                 data += tlv_length;
     487           0 :                 length -= tlv_length;
     488             :         }
     489             : 
     490             :         return false;
     491             : }
     492             : 
     493           0 : static uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi)
     494             : {
     495           0 :         uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr);
     496             : 
     497           0 :         if (bpi->nexthop)
     498           0 :                 return aigp + bpi->nexthop->metric;
     499             :         else
     500             :                 return aigp;
     501             : }
     502             : 
     503           0 : static void stream_put_bgp_aigp_tlv_metric(struct stream *s,
     504             :                                            struct bgp_path_info *bpi)
     505             : {
     506           0 :         stream_putc(s, BGP_AIGP_TLV_METRIC);
     507           0 :         stream_putw(s, BGP_AIGP_TLV_METRIC_LEN);
     508           0 :         stream_putq(s, bgp_aigp_metric_total(bpi));
     509           0 : }
     510             : 
     511           0 : static bool bgp_attr_aigp_valid(uint8_t *pnt, int length)
     512             : {
     513           0 :         uint8_t *data = pnt;
     514           0 :         uint8_t tlv_type;
     515           0 :         uint16_t tlv_length;
     516             : 
     517           0 :         if (length < 3) {
     518           0 :                 zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u",
     519             :                          length);
     520           0 :                 return false;
     521             :         }
     522             : 
     523           0 :         while (length) {
     524           0 :                 tlv_type = *data;
     525           0 :                 ptr_get_be16(data + 1, &tlv_length);
     526           0 :                 (void)data;
     527             : 
     528           0 :                 if (length < tlv_length) {
     529           0 :                         zlog_err(
     530             :                                 "Bad AIGP attribute length: %u, but TLV length: %u",
     531             :                                 length, tlv_length);
     532           0 :                         return false;
     533             :                 }
     534             : 
     535           0 :                 if (tlv_length < 3) {
     536           0 :                         zlog_err("Bad AIGP TLV length (MUST be minimum 3): %u",
     537             :                                  tlv_length);
     538           0 :                         return false;
     539             :                 }
     540             : 
     541             :                 /* AIGP TLV, Length: 11 */
     542           0 :                 if (tlv_type == BGP_AIGP_TLV_METRIC &&
     543             :                     tlv_length != BGP_AIGP_TLV_METRIC_LEN) {
     544           0 :                         zlog_err("Bad AIGP TLV (%s) length: %u",
     545             :                                  BGP_AIGP_TLV_METRIC_DESC, tlv_length);
     546           0 :                         return false;
     547             :                 }
     548             : 
     549           0 :                 data += tlv_length;
     550           0 :                 length -= tlv_length;
     551             :         }
     552             : 
     553             :         return true;
     554             : }
     555             : 
     556           0 : static void *srv6_l3vpn_hash_alloc(void *p)
     557             : {
     558           0 :         return p;
     559             : }
     560             : 
     561           0 : static void srv6_l3vpn_free(struct bgp_attr_srv6_l3vpn *l3vpn)
     562             : {
     563           0 :         XFREE(MTYPE_BGP_SRV6_L3VPN, l3vpn);
     564           0 : }
     565             : 
     566             : static struct bgp_attr_srv6_l3vpn *
     567           0 : srv6_l3vpn_intern(struct bgp_attr_srv6_l3vpn *l3vpn)
     568             : {
     569           0 :         struct bgp_attr_srv6_l3vpn *find;
     570             : 
     571           0 :         find = hash_get(srv6_l3vpn_hash, l3vpn, srv6_l3vpn_hash_alloc);
     572           0 :         if (find != l3vpn)
     573           0 :                 srv6_l3vpn_free(l3vpn);
     574           0 :         find->refcnt++;
     575           0 :         return find;
     576             : }
     577             : 
     578           0 : static void srv6_l3vpn_unintern(struct bgp_attr_srv6_l3vpn **l3vpnp)
     579             : {
     580           0 :         struct bgp_attr_srv6_l3vpn *l3vpn = *l3vpnp;
     581             : 
     582           0 :         if (l3vpn->refcnt)
     583           0 :                 l3vpn->refcnt--;
     584             : 
     585           0 :         if (l3vpn->refcnt == 0) {
     586           0 :                 hash_release(srv6_l3vpn_hash, l3vpn);
     587           0 :                 srv6_l3vpn_free(l3vpn);
     588           0 :                 *l3vpnp = NULL;
     589             :         }
     590           0 : }
     591             : 
     592           0 : static void *srv6_vpn_hash_alloc(void *p)
     593             : {
     594           0 :         return p;
     595             : }
     596             : 
     597           0 : static void srv6_vpn_free(struct bgp_attr_srv6_vpn *vpn)
     598             : {
     599           0 :         XFREE(MTYPE_BGP_SRV6_VPN, vpn);
     600           0 : }
     601             : 
     602           0 : static struct bgp_attr_srv6_vpn *srv6_vpn_intern(struct bgp_attr_srv6_vpn *vpn)
     603             : {
     604           0 :         struct bgp_attr_srv6_vpn *find;
     605             : 
     606           0 :         find = hash_get(srv6_vpn_hash, vpn, srv6_vpn_hash_alloc);
     607           0 :         if (find != vpn)
     608           0 :                 srv6_vpn_free(vpn);
     609           0 :         find->refcnt++;
     610           0 :         return find;
     611             : }
     612             : 
     613           0 : static void srv6_vpn_unintern(struct bgp_attr_srv6_vpn **vpnp)
     614             : {
     615           0 :         struct bgp_attr_srv6_vpn *vpn = *vpnp;
     616             : 
     617           0 :         if (vpn->refcnt)
     618           0 :                 vpn->refcnt--;
     619             : 
     620           0 :         if (vpn->refcnt == 0) {
     621           0 :                 hash_release(srv6_vpn_hash, vpn);
     622           0 :                 srv6_vpn_free(vpn);
     623           0 :                 *vpnp = NULL;
     624             :         }
     625           0 : }
     626             : 
     627           0 : static uint32_t srv6_l3vpn_hash_key_make(const void *p)
     628             : {
     629           0 :         const struct bgp_attr_srv6_l3vpn *l3vpn = p;
     630           0 :         uint32_t key = 0;
     631             : 
     632           0 :         key = jhash(&l3vpn->sid, 16, key);
     633           0 :         key = jhash_1word(l3vpn->sid_flags, key);
     634           0 :         key = jhash_1word(l3vpn->endpoint_behavior, key);
     635           0 :         key = jhash_1word(l3vpn->loc_block_len, key);
     636           0 :         key = jhash_1word(l3vpn->loc_node_len, key);
     637           0 :         key = jhash_1word(l3vpn->func_len, key);
     638           0 :         key = jhash_1word(l3vpn->arg_len, key);
     639           0 :         key = jhash_1word(l3vpn->transposition_len, key);
     640           0 :         key = jhash_1word(l3vpn->transposition_offset, key);
     641           0 :         return key;
     642             : }
     643             : 
     644           0 : static bool srv6_l3vpn_hash_cmp(const void *p1, const void *p2)
     645             : {
     646           0 :         const struct bgp_attr_srv6_l3vpn *l3vpn1 = p1;
     647           0 :         const struct bgp_attr_srv6_l3vpn *l3vpn2 = p2;
     648             : 
     649           0 :         return sid_same(&l3vpn1->sid, &l3vpn2->sid)
     650             :                && l3vpn1->sid_flags == l3vpn2->sid_flags
     651           0 :                && l3vpn1->endpoint_behavior == l3vpn2->endpoint_behavior
     652             :                && l3vpn1->loc_block_len == l3vpn2->loc_block_len
     653             :                && l3vpn1->loc_node_len == l3vpn2->loc_node_len
     654             :                && l3vpn1->func_len == l3vpn2->func_len
     655           0 :                && l3vpn1->arg_len == l3vpn2->arg_len
     656             :                && l3vpn1->transposition_len == l3vpn2->transposition_len
     657           0 :                && l3vpn1->transposition_offset == l3vpn2->transposition_offset;
     658             : }
     659             : 
     660           1 : static bool srv6_l3vpn_same(const struct bgp_attr_srv6_l3vpn *h1,
     661             :                             const struct bgp_attr_srv6_l3vpn *h2)
     662             : {
     663           1 :         if (h1 == h2)
     664             :                 return true;
     665           0 :         else if (h1 == NULL || h2 == NULL)
     666             :                 return false;
     667             :         else
     668           0 :                 return srv6_l3vpn_hash_cmp((const void *)h1, (const void *)h2);
     669             : }
     670             : 
     671           0 : static unsigned int srv6_vpn_hash_key_make(const void *p)
     672             : {
     673           0 :         const struct bgp_attr_srv6_vpn *vpn = p;
     674           0 :         uint32_t key = 0;
     675             : 
     676           0 :         key = jhash(&vpn->sid, 16, key);
     677           0 :         key = jhash_1word(vpn->sid_flags, key);
     678           0 :         return key;
     679             : }
     680             : 
     681           0 : static bool srv6_vpn_hash_cmp(const void *p1, const void *p2)
     682             : {
     683           0 :         const struct bgp_attr_srv6_vpn *vpn1 = p1;
     684           0 :         const struct bgp_attr_srv6_vpn *vpn2 = p2;
     685             : 
     686           0 :         return sid_same(&vpn1->sid, &vpn2->sid)
     687           0 :                && vpn1->sid_flags == vpn2->sid_flags;
     688             : }
     689             : 
     690           1 : static bool srv6_vpn_same(const struct bgp_attr_srv6_vpn *h1,
     691             :                           const struct bgp_attr_srv6_vpn *h2)
     692             : {
     693           1 :         if (h1 == h2)
     694             :                 return true;
     695           0 :         else if (h1 == NULL || h2 == NULL)
     696             :                 return false;
     697             :         else
     698           0 :                 return srv6_vpn_hash_cmp((const void *)h1, (const void *)h2);
     699             : }
     700             : 
     701           3 : static void srv6_init(void)
     702             : {
     703           6 :         srv6_l3vpn_hash =
     704           3 :                 hash_create(srv6_l3vpn_hash_key_make, srv6_l3vpn_hash_cmp,
     705             :                             "BGP Prefix-SID SRv6-L3VPN-Service-TLV");
     706           3 :         srv6_vpn_hash = hash_create(srv6_vpn_hash_key_make, srv6_vpn_hash_cmp,
     707             :                                     "BGP Prefix-SID SRv6-VPN-Service-TLV");
     708           3 : }
     709             : 
     710           3 : static void srv6_finish(void)
     711             : {
     712           3 :         hash_clean(srv6_l3vpn_hash, (void (*)(void *))srv6_l3vpn_free);
     713           3 :         hash_free(srv6_l3vpn_hash);
     714           3 :         srv6_l3vpn_hash = NULL;
     715           3 :         hash_clean(srv6_vpn_hash, (void (*)(void *))srv6_vpn_free);
     716           3 :         hash_free(srv6_vpn_hash);
     717           3 :         srv6_vpn_hash = NULL;
     718           3 : }
     719             : 
     720           0 : static unsigned int transit_hash_key_make(const void *p)
     721             : {
     722           0 :         const struct transit *transit = p;
     723             : 
     724           0 :         return jhash(transit->val, transit->length, 0);
     725             : }
     726             : 
     727           0 : static bool transit_hash_cmp(const void *p1, const void *p2)
     728             : {
     729           0 :         const struct transit *transit1 = p1;
     730           0 :         const struct transit *transit2 = p2;
     731             : 
     732           0 :         return (transit1->length == transit2->length
     733           0 :                 && memcmp(transit1->val, transit2->val, transit1->length) == 0);
     734             : }
     735             : 
     736           3 : static void transit_init(void)
     737             : {
     738           3 :         transit_hash = hash_create(transit_hash_key_make, transit_hash_cmp,
     739             :                                    "BGP Transit Hash");
     740           3 : }
     741             : 
     742           3 : static void transit_finish(void)
     743             : {
     744           3 :         hash_clean(transit_hash, (void (*)(void *))transit_free);
     745           3 :         hash_free(transit_hash);
     746           3 :         transit_hash = NULL;
     747           3 : }
     748             : 
     749             : /* Attribute hash routines. */
     750             : static struct hash *attrhash;
     751             : 
     752           0 : unsigned long int attr_count(void)
     753             : {
     754           0 :         return attrhash->count;
     755             : }
     756             : 
     757           0 : unsigned long int attr_unknown_count(void)
     758             : {
     759           0 :         return transit_hash->count;
     760             : }
     761             : 
     762           2 : unsigned int attrhash_key_make(const void *p)
     763             : {
     764           2 :         const struct attr *attr = (struct attr *)p;
     765           2 :         uint32_t key = 0;
     766             : #define MIX(val)        key = jhash_1word(val, key)
     767             : #define MIX3(a, b, c)   key = jhash_3words((a), (b), (c), key)
     768             : 
     769           2 :         MIX3(attr->origin, attr->nexthop.s_addr, attr->med);
     770           2 :         MIX3(attr->local_pref, attr->aggregator_as,
     771             :              attr->aggregator_addr.s_addr);
     772           2 :         MIX3(attr->weight, attr->mp_nexthop_global_in.s_addr,
     773             :              attr->originator_id.s_addr);
     774           2 :         MIX3(attr->tag, attr->label, attr->label_index);
     775             : 
     776           2 :         if (attr->aspath)
     777           2 :                 MIX(aspath_key_make(attr->aspath));
     778           2 :         if (bgp_attr_get_community(attr))
     779           0 :                 MIX(community_hash_make(bgp_attr_get_community(attr)));
     780           2 :         if (bgp_attr_get_lcommunity(attr))
     781           0 :                 MIX(lcommunity_hash_make(bgp_attr_get_lcommunity(attr)));
     782           2 :         if (bgp_attr_get_ecommunity(attr))
     783           0 :                 MIX(ecommunity_hash_make(bgp_attr_get_ecommunity(attr)));
     784           2 :         if (bgp_attr_get_ipv6_ecommunity(attr))
     785           0 :                 MIX(ecommunity_hash_make(bgp_attr_get_ipv6_ecommunity(attr)));
     786           2 :         if (bgp_attr_get_cluster(attr))
     787           0 :                 MIX(cluster_hash_key_make(bgp_attr_get_cluster(attr)));
     788           2 :         if (bgp_attr_get_transit(attr))
     789           0 :                 MIX(transit_hash_key_make(bgp_attr_get_transit(attr)));
     790           2 :         if (attr->encap_subtlvs)
     791           0 :                 MIX(encap_hash_key_make(attr->encap_subtlvs));
     792           2 :         if (attr->srv6_l3vpn)
     793           0 :                 MIX(srv6_l3vpn_hash_key_make(attr->srv6_l3vpn));
     794           2 :         if (attr->srv6_vpn)
     795           0 :                 MIX(srv6_vpn_hash_key_make(attr->srv6_vpn));
     796             : #ifdef ENABLE_BGP_VNC
     797           2 :         struct bgp_attr_encap_subtlv *vnc_subtlvs =
     798           2 :                 bgp_attr_get_vnc_subtlvs(attr);
     799           2 :         if (vnc_subtlvs)
     800           0 :                 MIX(encap_hash_key_make(vnc_subtlvs));
     801             : #endif
     802           2 :         MIX(attr->mp_nexthop_len);
     803           2 :         key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key);
     804           2 :         key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key);
     805           2 :         MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance);
     806           2 :         MIX(attr->rmap_table_id);
     807           2 :         MIX(attr->nh_type);
     808           2 :         MIX(attr->bh_type);
     809           2 :         MIX(attr->otc);
     810           2 :         MIX(bgp_attr_get_aigp_metric(attr));
     811             : 
     812           2 :         return key;
     813             : }
     814             : 
     815           1 : bool attrhash_cmp(const void *p1, const void *p2)
     816             : {
     817           1 :         const struct attr *attr1 = p1;
     818           1 :         const struct attr *attr2 = p2;
     819             : 
     820           1 :         if (attr1->flag == attr2->flag && attr1->origin == attr2->origin
     821           1 :             && attr1->nexthop.s_addr == attr2->nexthop.s_addr
     822           1 :             && attr1->aspath == attr2->aspath
     823           1 :             && bgp_attr_get_community(attr1)
     824           1 :                                 == bgp_attr_get_community(attr2)
     825           1 :                 && attr1->med == attr2->med
     826           1 :             && attr1->local_pref == attr2->local_pref
     827           1 :             && attr1->rmap_change_flags == attr2->rmap_change_flags) {
     828           1 :                 if (attr1->aggregator_as == attr2->aggregator_as
     829           1 :                     && attr1->aggregator_addr.s_addr
     830           1 :                                == attr2->aggregator_addr.s_addr
     831           1 :                     && attr1->weight == attr2->weight
     832           1 :                     && attr1->tag == attr2->tag
     833           1 :                     && attr1->label_index == attr2->label_index
     834           1 :                     && attr1->mp_nexthop_len == attr2->mp_nexthop_len
     835           1 :                     && bgp_attr_get_ecommunity(attr1)
     836           1 :                                == bgp_attr_get_ecommunity(attr2)
     837           1 :                     && bgp_attr_get_ipv6_ecommunity(attr1)
     838           1 :                                == bgp_attr_get_ipv6_ecommunity(attr2)
     839           1 :                     && bgp_attr_get_lcommunity(attr1)
     840           1 :                                    == bgp_attr_get_lcommunity(attr2)
     841           1 :                     && bgp_attr_get_cluster(attr1)
     842           1 :                                == bgp_attr_get_cluster(attr2)
     843           1 :                     && bgp_attr_get_transit(attr1)
     844           1 :                                == bgp_attr_get_transit(attr2)
     845           1 :                     && bgp_attr_get_aigp_metric(attr1)
     846           1 :                                == bgp_attr_get_aigp_metric(attr2)
     847           1 :                     && attr1->rmap_table_id == attr2->rmap_table_id
     848           1 :                     && (attr1->encap_tunneltype == attr2->encap_tunneltype)
     849           1 :                     && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
     850             : #ifdef ENABLE_BGP_VNC
     851           1 :                     && encap_same(bgp_attr_get_vnc_subtlvs(attr1),
     852           1 :                                   bgp_attr_get_vnc_subtlvs(attr2))
     853             : #endif
     854           1 :                     && IPV6_ADDR_SAME(&attr1->mp_nexthop_global,
     855             :                                       &attr2->mp_nexthop_global)
     856           1 :                     && IPV6_ADDR_SAME(&attr1->mp_nexthop_local,
     857             :                                       &attr2->mp_nexthop_local)
     858           1 :                     && IPV4_ADDR_SAME(&attr1->mp_nexthop_global_in,
     859             :                                       &attr2->mp_nexthop_global_in)
     860           1 :                     && IPV4_ADDR_SAME(&attr1->originator_id,
     861             :                                       &attr2->originator_id)
     862           1 :                     && overlay_index_same(attr1, attr2)
     863           1 :                     && !memcmp(&attr1->esi, &attr2->esi, sizeof(esi_t))
     864           1 :                     && attr1->es_flags == attr2->es_flags
     865           1 :                     && attr1->mm_sync_seqnum == attr2->mm_sync_seqnum
     866             :                     && attr1->df_pref == attr2->df_pref
     867           1 :                     && attr1->df_alg == attr2->df_alg
     868           1 :                     && attr1->nh_ifindex == attr2->nh_ifindex
     869           1 :                     && attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
     870           1 :                     && attr1->distance == attr2->distance
     871           1 :                     && srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn)
     872           1 :                     && srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn)
     873           1 :                     && attr1->srte_color == attr2->srte_color
     874             :                     && attr1->nh_type == attr2->nh_type
     875           1 :                     && attr1->bh_type == attr2->bh_type
     876           1 :                     && attr1->otc == attr2->otc)
     877             :                         return true;
     878             :         }
     879             : 
     880             :         return false;
     881             : }
     882             : 
     883           3 : static void attrhash_init(void)
     884             : {
     885           6 :         attrhash =
     886           3 :                 hash_create(attrhash_key_make, attrhash_cmp, "BGP Attributes");
     887           3 : }
     888             : 
     889             : /*
     890             :  * special for hash_clean below
     891             :  */
     892           0 : static void attr_vfree(void *attr)
     893             : {
     894           0 :         XFREE(MTYPE_ATTR, attr);
     895           0 : }
     896             : 
     897           3 : static void attrhash_finish(void)
     898             : {
     899           3 :         hash_clean(attrhash, attr_vfree);
     900           3 :         hash_free(attrhash);
     901           3 :         attrhash = NULL;
     902           3 : }
     903             : 
     904           0 : static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
     905             : {
     906           0 :         struct attr *attr = bucket->data;
     907           0 :         struct in6_addr *sid = NULL;
     908             : 
     909           0 :         if (attr->srv6_l3vpn)
     910           0 :                 sid = &attr->srv6_l3vpn->sid;
     911           0 :         else if (attr->srv6_vpn)
     912           0 :                 sid = &attr->srv6_vpn->sid;
     913             : 
     914           0 :         vty_out(vty, "attr[%ld] nexthop %pI4\n", attr->refcnt, &attr->nexthop);
     915             : 
     916           0 :         vty_out(vty,
     917             :                 "\tflags: %" PRIu64
     918             :                 " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
     919           0 :                 attr->flag, attr->distance, attr->med, attr->local_pref,
     920           0 :                 attr->origin, attr->weight, attr->label, sid);
     921           0 : }
     922             : 
     923           0 : void attr_show_all(struct vty *vty)
     924             : {
     925           0 :         hash_iterate(attrhash, (void (*)(struct hash_bucket *,
     926             :                                          void *))attr_show_all_iterator,
     927             :                      vty);
     928           0 : }
     929             : 
     930           1 : static void *bgp_attr_hash_alloc(void *p)
     931             : {
     932           1 :         struct attr *val = (struct attr *)p;
     933           1 :         struct attr *attr;
     934             : 
     935           1 :         attr = XMALLOC(MTYPE_ATTR, sizeof(struct attr));
     936           1 :         *attr = *val;
     937           1 :         if (val->encap_subtlvs) {
     938           0 :                 val->encap_subtlvs = NULL;
     939             :         }
     940             : #ifdef ENABLE_BGP_VNC
     941           1 :         struct bgp_attr_encap_subtlv *vnc_subtlvs =
     942           1 :                 bgp_attr_get_vnc_subtlvs(val);
     943             : 
     944           1 :         if (vnc_subtlvs)
     945           0 :                 bgp_attr_set_vnc_subtlvs(val, NULL);
     946             : #endif
     947             : 
     948           1 :         attr->refcnt = 0;
     949           1 :         return attr;
     950             : }
     951             : 
     952             : /* Internet argument attribute. */
     953           1 : struct attr *bgp_attr_intern(struct attr *attr)
     954             : {
     955           1 :         struct attr *find;
     956           1 :         struct ecommunity *ecomm = NULL;
     957           1 :         struct ecommunity *ipv6_ecomm = NULL;
     958           1 :         struct lcommunity *lcomm = NULL;
     959           1 :         struct community *comm = NULL;
     960             : 
     961             :         /* Intern referenced structure. */
     962           1 :         if (attr->aspath) {
     963           1 :                 if (!attr->aspath->refcnt)
     964           0 :                         attr->aspath = aspath_intern(attr->aspath);
     965             :                 else
     966           1 :                         attr->aspath->refcnt++;
     967             :         }
     968             : 
     969           1 :         comm = bgp_attr_get_community(attr);
     970           1 :         if (comm) {
     971           0 :                 if (!comm->refcnt)
     972           0 :                         bgp_attr_set_community(attr, community_intern(comm));
     973             :                 else
     974           0 :                         comm->refcnt++;
     975             :         }
     976             : 
     977           1 :         ecomm = bgp_attr_get_ecommunity(attr);
     978           1 :         if (ecomm) {
     979           0 :                 if (!ecomm->refcnt)
     980           0 :                         bgp_attr_set_ecommunity(attr, ecommunity_intern(ecomm));
     981             :                 else
     982           0 :                         ecomm->refcnt++;
     983             :         }
     984             : 
     985           1 :         ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr);
     986           1 :         if (ipv6_ecomm) {
     987           0 :                 if (!ipv6_ecomm->refcnt)
     988           0 :                         bgp_attr_set_ipv6_ecommunity(
     989             :                                 attr, ecommunity_intern(ipv6_ecomm));
     990             :                 else
     991           0 :                         ipv6_ecomm->refcnt++;
     992             :         }
     993             : 
     994           1 :         lcomm = bgp_attr_get_lcommunity(attr);
     995           1 :         if (lcomm) {
     996           0 :                 if (!lcomm->refcnt)
     997           0 :                         bgp_attr_set_lcommunity(attr, lcommunity_intern(lcomm));
     998             :                 else
     999           0 :                         lcomm->refcnt++;
    1000             :         }
    1001             : 
    1002           1 :         struct cluster_list *cluster = bgp_attr_get_cluster(attr);
    1003             : 
    1004           1 :         if (cluster) {
    1005           0 :                 if (!cluster->refcnt)
    1006           0 :                         bgp_attr_set_cluster(attr, cluster_intern(cluster));
    1007             :                 else
    1008           0 :                         cluster->refcnt++;
    1009             :         }
    1010             : 
    1011           1 :         struct transit *transit = bgp_attr_get_transit(attr);
    1012             : 
    1013           1 :         if (transit) {
    1014           0 :                 if (!transit->refcnt)
    1015           0 :                         bgp_attr_set_transit(attr, transit_intern(transit));
    1016             :                 else
    1017           0 :                         transit->refcnt++;
    1018             :         }
    1019           1 :         if (attr->encap_subtlvs) {
    1020           0 :                 if (!attr->encap_subtlvs->refcnt)
    1021           0 :                         attr->encap_subtlvs = encap_intern(attr->encap_subtlvs,
    1022             :                                                            ENCAP_SUBTLV_TYPE);
    1023             :                 else
    1024           0 :                         attr->encap_subtlvs->refcnt++;
    1025             :         }
    1026           1 :         if (attr->srv6_l3vpn) {
    1027           0 :                 if (!attr->srv6_l3vpn->refcnt)
    1028           0 :                         attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
    1029             :                 else
    1030           0 :                         attr->srv6_l3vpn->refcnt++;
    1031             :         }
    1032           1 :         if (attr->srv6_vpn) {
    1033           0 :                 if (!attr->srv6_vpn->refcnt)
    1034           0 :                         attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
    1035             :                 else
    1036           0 :                         attr->srv6_vpn->refcnt++;
    1037             :         }
    1038             : #ifdef ENABLE_BGP_VNC
    1039           1 :         struct bgp_attr_encap_subtlv *vnc_subtlvs =
    1040           1 :                 bgp_attr_get_vnc_subtlvs(attr);
    1041             : 
    1042           1 :         if (vnc_subtlvs) {
    1043           0 :                 if (!vnc_subtlvs->refcnt)
    1044           0 :                         bgp_attr_set_vnc_subtlvs(
    1045             :                                 attr,
    1046             :                                 encap_intern(vnc_subtlvs, VNC_SUBTLV_TYPE));
    1047             :                 else
    1048           0 :                         vnc_subtlvs->refcnt++;
    1049             :         }
    1050             : #endif
    1051             : 
    1052             :         /* At this point, attr only contains intern'd pointers.  that means
    1053             :          * if we find it in attrhash, it has all the same pointers and we
    1054             :          * correctly updated the refcounts on these.
    1055             :          * If we don't find it, we need to allocate a one because in all
    1056             :          * cases this returns a new reference to a hashed attr, but the input
    1057             :          * wasn't on hash. */
    1058           1 :         find = (struct attr *)hash_get(attrhash, attr, bgp_attr_hash_alloc);
    1059           1 :         find->refcnt++;
    1060             : 
    1061           1 :         return find;
    1062             : }
    1063             : 
    1064             : /* Make network statement's attribute. */
    1065           0 : struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp,
    1066             :                                   uint8_t origin)
    1067             : {
    1068           0 :         memset(attr, 0, sizeof(struct attr));
    1069             : 
    1070           0 :         attr->origin = origin;
    1071           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
    1072           0 :         attr->aspath = aspath_empty();
    1073           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
    1074           0 :         attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
    1075           0 :         attr->tag = 0;
    1076           0 :         attr->label_index = BGP_INVALID_LABEL_INDEX;
    1077           0 :         attr->label = MPLS_INVALID_LABEL;
    1078           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
    1079           0 :         attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
    1080           0 :         attr->local_pref = bgp->default_local_pref;
    1081             : 
    1082           0 :         return attr;
    1083             : }
    1084             : 
    1085             : /* Create the attributes for an aggregate */
    1086           0 : struct attr *bgp_attr_aggregate_intern(
    1087             :         struct bgp *bgp, uint8_t origin, struct aspath *aspath,
    1088             :         struct community *community, struct ecommunity *ecommunity,
    1089             :         struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
    1090             :         uint8_t atomic_aggregate, const struct prefix *p)
    1091             : {
    1092           0 :         struct attr attr;
    1093           0 :         struct attr *new;
    1094           0 :         route_map_result_t ret;
    1095             : 
    1096           0 :         memset(&attr, 0, sizeof(attr));
    1097             : 
    1098             :         /* Origin attribute. */
    1099           0 :         attr.origin = origin;
    1100           0 :         attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
    1101             : 
    1102             :         /* MED */
    1103           0 :         attr.med = 0;
    1104           0 :         attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
    1105             : 
    1106             :         /* AS path attribute. */
    1107           0 :         if (aspath)
    1108           0 :                 attr.aspath = aspath_intern(aspath);
    1109             :         else
    1110           0 :                 attr.aspath = aspath_empty();
    1111           0 :         attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
    1112             : 
    1113             :         /* Next hop attribute.  */
    1114           0 :         attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
    1115             : 
    1116           0 :         if (community) {
    1117           0 :                 uint32_t gshut = COMMUNITY_GSHUT;
    1118             : 
    1119             :                 /* If we are not shutting down ourselves and we are
    1120             :                  * aggregating a route that contains the GSHUT community we
    1121             :                  * need to remove that community when creating the aggregate */
    1122           0 :                 if (!bgp_in_graceful_shutdown(bgp)
    1123           0 :                     && community_include(community, gshut)) {
    1124           0 :                         community_del_val(community, &gshut);
    1125             :                 }
    1126             : 
    1127           0 :                 bgp_attr_set_community(&attr, community);
    1128             :         }
    1129             : 
    1130           0 :         if (ecommunity)
    1131           0 :                 bgp_attr_set_ecommunity(&attr, ecommunity);
    1132             : 
    1133           0 :         if (lcommunity)
    1134           0 :                 bgp_attr_set_lcommunity(&attr, lcommunity);
    1135             : 
    1136           0 :         if (bgp_in_graceful_shutdown(bgp))
    1137           0 :                 bgp_attr_add_gshut_community(&attr);
    1138             : 
    1139           0 :         attr.label_index = BGP_INVALID_LABEL_INDEX;
    1140           0 :         attr.label = MPLS_INVALID_LABEL;
    1141           0 :         attr.weight = BGP_ATTR_DEFAULT_WEIGHT;
    1142           0 :         attr.mp_nexthop_len = IPV6_MAX_BYTELEN;
    1143           0 :         if (!aggregate->as_set || atomic_aggregate)
    1144           0 :                 attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
    1145           0 :         attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
    1146           0 :         if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
    1147           0 :                 attr.aggregator_as = bgp->confed_id;
    1148             :         else
    1149           0 :                 attr.aggregator_as = bgp->as;
    1150           0 :         attr.aggregator_addr = bgp->router_id;
    1151             : 
    1152             :         /* Apply route-map */
    1153           0 :         if (aggregate->rmap.name) {
    1154           0 :                 struct attr attr_tmp = attr;
    1155           0 :                 struct bgp_path_info rmap_path;
    1156             : 
    1157           0 :                 memset(&rmap_path, 0, sizeof(rmap_path));
    1158           0 :                 rmap_path.peer = bgp->peer_self;
    1159           0 :                 rmap_path.attr = &attr_tmp;
    1160             : 
    1161           0 :                 SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_AGGREGATE);
    1162             : 
    1163           0 :                 ret = route_map_apply(aggregate->rmap.map, p, &rmap_path);
    1164             : 
    1165           0 :                 bgp->peer_self->rmap_type = 0;
    1166             : 
    1167           0 :                 if (ret == RMAP_DENYMATCH) {
    1168             :                         /* Free uninterned attribute. */
    1169           0 :                         bgp_attr_flush(&attr_tmp);
    1170             : 
    1171             :                         /* Unintern original. */
    1172           0 :                         aspath_unintern(&attr.aspath);
    1173           0 :                         return NULL;
    1174             :                 }
    1175             : 
    1176           0 :                 if (bgp_in_graceful_shutdown(bgp))
    1177           0 :                         bgp_attr_add_gshut_community(&attr_tmp);
    1178             : 
    1179           0 :                 new = bgp_attr_intern(&attr_tmp);
    1180             :         } else {
    1181             : 
    1182           0 :                 if (bgp_in_graceful_shutdown(bgp))
    1183           0 :                         bgp_attr_add_gshut_community(&attr);
    1184             : 
    1185           0 :                 new = bgp_attr_intern(&attr);
    1186             :         }
    1187             : 
    1188             :         /* Always release the 'intern()'ed AS Path. */
    1189           0 :         aspath_unintern(&attr.aspath);
    1190             : 
    1191           0 :         return new;
    1192             : }
    1193             : 
    1194             : /* Unintern just the sub-components of the attr, but not the attr */
    1195           4 : void bgp_attr_unintern_sub(struct attr *attr)
    1196             : {
    1197           4 :         struct ecommunity *ecomm = NULL;
    1198           4 :         struct ecommunity *ipv6_ecomm = NULL;
    1199           4 :         struct cluster_list *cluster;
    1200           4 :         struct lcommunity *lcomm = NULL;
    1201           4 :         struct community *comm = NULL;
    1202             : 
    1203             :         /* aspath refcount shoud be decrement. */
    1204           4 :         aspath_unintern(&attr->aspath);
    1205           4 :         UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH));
    1206             : 
    1207           4 :         comm = bgp_attr_get_community(attr);
    1208           4 :         community_unintern(&comm);
    1209           4 :         bgp_attr_set_community(attr, NULL);
    1210             : 
    1211           4 :         ecomm = bgp_attr_get_ecommunity(attr);
    1212           4 :         ecommunity_unintern(&ecomm);
    1213           4 :         bgp_attr_set_ecommunity(attr, NULL);
    1214             : 
    1215           4 :         ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr);
    1216           4 :         ecommunity_unintern(&ipv6_ecomm);
    1217           4 :         bgp_attr_set_ipv6_ecommunity(attr, NULL);
    1218             : 
    1219           4 :         lcomm = bgp_attr_get_lcommunity(attr);
    1220           4 :         lcommunity_unintern(&lcomm);
    1221           4 :         bgp_attr_set_lcommunity(attr, NULL);
    1222             : 
    1223           4 :         cluster = bgp_attr_get_cluster(attr);
    1224           4 :         if (cluster) {
    1225           0 :                 cluster_unintern(&cluster);
    1226           0 :                 bgp_attr_set_cluster(attr, cluster);
    1227             :         }
    1228           4 :         UNSET_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST));
    1229             : 
    1230           4 :         struct transit *transit = bgp_attr_get_transit(attr);
    1231             : 
    1232           4 :         if (transit) {
    1233           0 :                 transit_unintern(&transit);
    1234           0 :                 bgp_attr_set_transit(attr, transit);
    1235             :         }
    1236             : 
    1237           4 :         if (attr->encap_subtlvs)
    1238           0 :                 encap_unintern(&attr->encap_subtlvs, ENCAP_SUBTLV_TYPE);
    1239             : 
    1240             : #ifdef ENABLE_BGP_VNC
    1241           4 :         struct bgp_attr_encap_subtlv *vnc_subtlvs =
    1242           4 :                 bgp_attr_get_vnc_subtlvs(attr);
    1243             : 
    1244           4 :         if (vnc_subtlvs) {
    1245           0 :                 encap_unintern(&vnc_subtlvs, VNC_SUBTLV_TYPE);
    1246           0 :                 bgp_attr_set_vnc_subtlvs(attr, vnc_subtlvs);
    1247             :         }
    1248             : #endif
    1249             : 
    1250           4 :         if (attr->srv6_l3vpn)
    1251           0 :                 srv6_l3vpn_unintern(&attr->srv6_l3vpn);
    1252             : 
    1253           4 :         if (attr->srv6_vpn)
    1254           0 :                 srv6_vpn_unintern(&attr->srv6_vpn);
    1255           4 : }
    1256             : 
    1257             : /* Free bgp attribute and aspath. */
    1258           1 : void bgp_attr_unintern(struct attr **pattr)
    1259             : {
    1260           1 :         struct attr *attr = *pattr;
    1261           1 :         struct attr *ret;
    1262           1 :         struct attr tmp;
    1263             : 
    1264             :         /* Decrement attribute reference. */
    1265           1 :         attr->refcnt--;
    1266             : 
    1267           1 :         tmp = *attr;
    1268             : 
    1269             :         /* If reference becomes zero then free attribute object. */
    1270           1 :         if (attr->refcnt == 0) {
    1271           1 :                 ret = hash_release(attrhash, attr);
    1272           1 :                 assert(ret != NULL);
    1273           1 :                 XFREE(MTYPE_ATTR, attr);
    1274           1 :                 *pattr = NULL;
    1275             :         }
    1276             : 
    1277           1 :         bgp_attr_unintern_sub(&tmp);
    1278           1 : }
    1279             : 
    1280           0 : void bgp_attr_flush(struct attr *attr)
    1281             : {
    1282           0 :         struct ecommunity *ecomm;
    1283           0 :         struct ecommunity *ipv6_ecomm;
    1284           0 :         struct cluster_list *cluster;
    1285           0 :         struct lcommunity *lcomm;
    1286           0 :         struct community *comm;
    1287             : 
    1288           0 :         if (attr->aspath && !attr->aspath->refcnt) {
    1289           0 :                 aspath_free(attr->aspath);
    1290           0 :                 attr->aspath = NULL;
    1291             :         }
    1292           0 :         comm = bgp_attr_get_community(attr);
    1293           0 :         if (comm && !comm->refcnt)
    1294           0 :                 community_free(&comm);
    1295           0 :         bgp_attr_set_community(attr, NULL);
    1296             : 
    1297           0 :         ecomm = bgp_attr_get_ecommunity(attr);
    1298           0 :         if (ecomm && !ecomm->refcnt)
    1299           0 :                 ecommunity_free(&ecomm);
    1300           0 :         bgp_attr_set_ecommunity(attr, NULL);
    1301             : 
    1302           0 :         ipv6_ecomm = bgp_attr_get_ipv6_ecommunity(attr);
    1303           0 :         if (ipv6_ecomm && !ipv6_ecomm->refcnt)
    1304           0 :                 ecommunity_free(&ipv6_ecomm);
    1305           0 :         bgp_attr_set_ipv6_ecommunity(attr, NULL);
    1306             : 
    1307           0 :         lcomm = bgp_attr_get_lcommunity(attr);
    1308           0 :         if (lcomm && !lcomm->refcnt)
    1309           0 :                 lcommunity_free(&lcomm);
    1310           0 :         bgp_attr_set_lcommunity(attr, NULL);
    1311             : 
    1312           0 :         cluster = bgp_attr_get_cluster(attr);
    1313           0 :         if (cluster && !cluster->refcnt) {
    1314           0 :                 cluster_free(cluster);
    1315           0 :                 bgp_attr_set_cluster(attr, NULL);
    1316             :         }
    1317             : 
    1318           0 :         struct transit *transit = bgp_attr_get_transit(attr);
    1319             : 
    1320           0 :         if (transit && !transit->refcnt) {
    1321           0 :                 transit_free(transit);
    1322           0 :                 bgp_attr_set_transit(attr, NULL);
    1323             :         }
    1324           0 :         if (attr->encap_subtlvs && !attr->encap_subtlvs->refcnt) {
    1325           0 :                 encap_free(attr->encap_subtlvs);
    1326           0 :                 attr->encap_subtlvs = NULL;
    1327             :         }
    1328           0 :         if (attr->srv6_l3vpn && !attr->srv6_l3vpn->refcnt) {
    1329           0 :                 srv6_l3vpn_free(attr->srv6_l3vpn);
    1330           0 :                 attr->srv6_l3vpn = NULL;
    1331             :         }
    1332           0 :         if (attr->srv6_vpn && !attr->srv6_vpn->refcnt) {
    1333           0 :                 srv6_vpn_free(attr->srv6_vpn);
    1334           0 :                 attr->srv6_vpn = NULL;
    1335             :         }
    1336             : #ifdef ENABLE_BGP_VNC
    1337           0 :         struct bgp_attr_encap_subtlv *vnc_subtlvs =
    1338           0 :                 bgp_attr_get_vnc_subtlvs(attr);
    1339             : 
    1340           0 :         if (vnc_subtlvs && !vnc_subtlvs->refcnt) {
    1341           0 :                 encap_free(vnc_subtlvs);
    1342           0 :                 bgp_attr_set_vnc_subtlvs(attr, NULL);
    1343             :         }
    1344             : #endif
    1345           0 : }
    1346             : 
    1347             : /* Implement draft-scudder-idr-optional-transitive behaviour and
    1348             :  * avoid resetting sessions for malformed attributes which are
    1349             :  * are partial/optional and hence where the error likely was not
    1350             :  * introduced by the sending neighbour.
    1351             :  */
    1352             : static enum bgp_attr_parse_ret
    1353           0 : bgp_attr_malformed(struct bgp_attr_parser_args *args, uint8_t subcode,
    1354             :                    bgp_size_t length)
    1355             : {
    1356           0 :         struct peer *const peer = args->peer;
    1357           0 :         struct attr *const attr = args->attr;
    1358           0 :         const uint8_t flags = args->flags;
    1359             :         /* startp and length must be special-cased, as whether or not to
    1360             :          * send the attribute data with the NOTIFY depends on the error,
    1361             :          * the caller therefore signals this with the seperate length argument
    1362             :          */
    1363           0 :         uint8_t *notify_datap = (length > 0 ? args->startp : NULL);
    1364             : 
    1365           0 :         if (bgp_debug_update(peer, NULL, NULL, 1)) {
    1366           0 :                 char attr_str[BUFSIZ] = {0};
    1367             : 
    1368           0 :                 bgp_dump_attr(attr, attr_str, sizeof(attr_str));
    1369             : 
    1370           0 :                 zlog_debug("%s: attributes: %s", __func__, attr_str);
    1371             :         }
    1372             : 
    1373             :         /* Only relax error handling for eBGP peers */
    1374           0 :         if (peer->sort != BGP_PEER_EBGP) {
    1375           0 :                 bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode,
    1376             :                                           notify_datap, length);
    1377           0 :                 return BGP_ATTR_PARSE_ERROR;
    1378             :         }
    1379             : 
    1380             :         /* Adjust the stream getp to the end of the attribute, in case we can
    1381             :          * still proceed but the caller hasn't read all the attribute.
    1382             :          */
    1383           0 :         stream_set_getp(BGP_INPUT(peer),
    1384           0 :                         (args->startp - STREAM_DATA(BGP_INPUT(peer)))
    1385           0 :                                 + args->total);
    1386             : 
    1387           0 :         switch (args->type) {
    1388             :         /* where an attribute is relatively inconsequential, e.g. it does not
    1389             :          * affect route selection, and can be safely ignored, then any such
    1390             :          * attributes which are malformed should just be ignored and the route
    1391             :          * processed as normal.
    1392             :          */
    1393             :         case BGP_ATTR_AS4_AGGREGATOR:
    1394             :         case BGP_ATTR_AGGREGATOR:
    1395             :         case BGP_ATTR_ATOMIC_AGGREGATE:
    1396             :                 return BGP_ATTR_PARSE_PROCEED;
    1397             : 
    1398             :         /* Core attributes, particularly ones which may influence route
    1399             :          * selection, should be treat-as-withdraw.
    1400             :          */
    1401             :         case BGP_ATTR_ORIGIN:
    1402             :         case BGP_ATTR_AS_PATH:
    1403             :         case BGP_ATTR_NEXT_HOP:
    1404             :         case BGP_ATTR_MULTI_EXIT_DISC:
    1405             :         case BGP_ATTR_LOCAL_PREF:
    1406             :         case BGP_ATTR_COMMUNITIES:
    1407             :         case BGP_ATTR_EXT_COMMUNITIES:
    1408             :         case BGP_ATTR_IPV6_EXT_COMMUNITIES:
    1409             :         case BGP_ATTR_LARGE_COMMUNITIES:
    1410             :         case BGP_ATTR_ORIGINATOR_ID:
    1411             :         case BGP_ATTR_CLUSTER_LIST:
    1412             :         case BGP_ATTR_OTC:
    1413             :                 return BGP_ATTR_PARSE_WITHDRAW;
    1414           0 :         case BGP_ATTR_MP_REACH_NLRI:
    1415             :         case BGP_ATTR_MP_UNREACH_NLRI:
    1416           0 :                 bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR, subcode,
    1417             :                                           notify_datap, length);
    1418           0 :                 return BGP_ATTR_PARSE_ERROR;
    1419             :         }
    1420             : 
    1421             :         /* Partial optional attributes that are malformed should not cause
    1422             :          * the whole session to be reset. Instead treat it as a withdrawal
    1423             :          * of the routes, if possible.
    1424             :          */
    1425           0 :         if (CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS)
    1426           0 :             && CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
    1427           0 :             && CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL))
    1428             :                 return BGP_ATTR_PARSE_WITHDRAW;
    1429             : 
    1430             :         /* default to reset */
    1431             :         return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
    1432             : }
    1433             : 
    1434             : /* Find out what is wrong with the path attribute flag bits and log the error.
    1435             :    "Flag bits" here stand for Optional, Transitive and Partial, but not for
    1436             :    Extended Length. Checking O/T/P bits at once implies, that the attribute
    1437             :    being diagnosed is defined by RFC as either a "well-known" or an "optional,
    1438             :    non-transitive" attribute. */
    1439             : static void
    1440           0 : bgp_attr_flags_diagnose(struct bgp_attr_parser_args *args,
    1441             :                         uint8_t desired_flags /* how RFC says it must be */
    1442             : )
    1443             : {
    1444           0 :         uint8_t seen = 0, i;
    1445           0 :         uint8_t real_flags = args->flags;
    1446           0 :         const uint8_t attr_code = args->type;
    1447             : 
    1448           0 :         desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
    1449           0 :         real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
    1450           0 :         for (i = 0; i <= 2; i++) /* O,T,P, but not E */
    1451           0 :                 if (CHECK_FLAG(desired_flags, attr_flag_str[i].key)
    1452           0 :                     != CHECK_FLAG(real_flags, attr_flag_str[i].key)) {
    1453           0 :                         flog_err(EC_BGP_ATTR_FLAG,
    1454             :                                  "%s attribute must%s be flagged as \"%s\"",
    1455             :                                  lookup_msg(attr_str, attr_code, NULL),
    1456             :                                  CHECK_FLAG(desired_flags, attr_flag_str[i].key)
    1457             :                                          ? ""
    1458             :                                          : " not",
    1459             :                                  attr_flag_str[i].str);
    1460           0 :                         seen = 1;
    1461             :                 }
    1462           0 :         if (!seen) {
    1463           0 :                 zlog_debug(
    1464             :                         "Strange, %s called for attr %s, but no problem found with flags (real flags 0x%x, desired 0x%x)",
    1465             :                         __func__, lookup_msg(attr_str, attr_code, NULL),
    1466             :                         real_flags, desired_flags);
    1467             :         }
    1468           0 : }
    1469             : 
    1470             : /* Required flags for attributes. EXTLEN will be masked off when testing,
    1471             :  * as will PARTIAL for optional+transitive attributes.
    1472             :  */
    1473             : const uint8_t attr_flags_values[] = {
    1474             :         [BGP_ATTR_ORIGIN] = BGP_ATTR_FLAG_TRANS,
    1475             :         [BGP_ATTR_AS_PATH] = BGP_ATTR_FLAG_TRANS,
    1476             :         [BGP_ATTR_NEXT_HOP] = BGP_ATTR_FLAG_TRANS,
    1477             :         [BGP_ATTR_MULTI_EXIT_DISC] = BGP_ATTR_FLAG_OPTIONAL,
    1478             :         [BGP_ATTR_LOCAL_PREF] = BGP_ATTR_FLAG_TRANS,
    1479             :         [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
    1480             :         [BGP_ATTR_AGGREGATOR] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
    1481             :         [BGP_ATTR_COMMUNITIES] = BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
    1482             :         [BGP_ATTR_ORIGINATOR_ID] = BGP_ATTR_FLAG_OPTIONAL,
    1483             :         [BGP_ATTR_CLUSTER_LIST] = BGP_ATTR_FLAG_OPTIONAL,
    1484             :         [BGP_ATTR_MP_REACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
    1485             :         [BGP_ATTR_MP_UNREACH_NLRI] = BGP_ATTR_FLAG_OPTIONAL,
    1486             :         [BGP_ATTR_EXT_COMMUNITIES] =
    1487             :                 BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1488             :         [BGP_ATTR_AS4_PATH] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1489             :         [BGP_ATTR_AS4_AGGREGATOR] =
    1490             :                 BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1491             :         [BGP_ATTR_PMSI_TUNNEL] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1492             :         [BGP_ATTR_LARGE_COMMUNITIES] =
    1493             :                 BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1494             :         [BGP_ATTR_OTC] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1495             :         [BGP_ATTR_PREFIX_SID] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1496             :         [BGP_ATTR_IPV6_EXT_COMMUNITIES] =
    1497             :                 BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1498             :         [BGP_ATTR_AIGP] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
    1499             : };
    1500             : static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
    1501             : 
    1502           3 : static bool bgp_attr_flag_invalid(struct bgp_attr_parser_args *args)
    1503             : {
    1504           3 :         uint8_t mask = BGP_ATTR_FLAG_EXTLEN;
    1505           3 :         const uint8_t flags = args->flags;
    1506           3 :         const uint8_t attr_code = args->type;
    1507             : 
    1508             :         /* there may be attributes we don't know about */
    1509           3 :         if (attr_code > attr_flags_values_max)
    1510             :                 return false;
    1511           3 :         if (attr_flags_values[attr_code] == 0)
    1512             :                 return false;
    1513             : 
    1514             :         /* RFC4271, "For well-known attributes, the Transitive bit MUST be set
    1515             :          * to
    1516             :          * 1."
    1517             :          */
    1518           3 :         if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL, flags)
    1519           3 :             && !CHECK_FLAG(BGP_ATTR_FLAG_TRANS, flags)) {
    1520           0 :                 flog_err(
    1521             :                         EC_BGP_ATTR_FLAG,
    1522             :                         "%s well-known attributes must have transitive flag set (%x)",
    1523             :                         lookup_msg(attr_str, attr_code, NULL), flags);
    1524           0 :                 return true;
    1525             :         }
    1526             : 
    1527             :         /* "For well-known attributes and for optional non-transitive
    1528             :          * attributes,
    1529             :          *  the Partial bit MUST be set to 0."
    1530             :          */
    1531           3 :         if (CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL)) {
    1532           0 :                 if (!CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)) {
    1533           0 :                         flog_err(EC_BGP_ATTR_FLAG,
    1534             :                                  "%s well-known attribute must NOT have the partial flag set (%x)",
    1535             :                                  lookup_msg(attr_str, attr_code, NULL), flags);
    1536           0 :                         return true;
    1537             :                 }
    1538           0 :                 if (CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
    1539           0 :                     && !CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS)) {
    1540           0 :                         flog_err(EC_BGP_ATTR_FLAG,
    1541             :                                  "%s optional + transitive attribute must NOT have the partial flag set (%x)",
    1542             :                                  lookup_msg(attr_str, attr_code, NULL), flags);
    1543           0 :                         return true;
    1544             :                 }
    1545             :         }
    1546             : 
    1547             :         /* Optional transitive attributes may go through speakers that don't
    1548             :          * reocgnise them and set the Partial bit.
    1549             :          */
    1550           3 :         if (CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
    1551           0 :             && CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS))
    1552           3 :                 SET_FLAG(mask, BGP_ATTR_FLAG_PARTIAL);
    1553             : 
    1554           3 :         if ((flags & ~mask) == attr_flags_values[attr_code])
    1555             :                 return false;
    1556             : 
    1557           0 :         bgp_attr_flags_diagnose(args, attr_flags_values[attr_code]);
    1558           0 :         return true;
    1559             : }
    1560             : 
    1561             : /* Get origin attribute of the update message. */
    1562             : static enum bgp_attr_parse_ret
    1563           1 : bgp_attr_origin(struct bgp_attr_parser_args *args)
    1564             : {
    1565           1 :         struct peer *const peer = args->peer;
    1566           1 :         struct attr *const attr = args->attr;
    1567           1 :         const bgp_size_t length = args->length;
    1568             : 
    1569             :         /* If any recognized attribute has Attribute Length that conflicts
    1570             :            with the expected length (based on the attribute type code), then
    1571             :            the Error Subcode is set to Attribute Length Error.  The Data
    1572             :            field contains the erroneous attribute (type, length and
    1573             :            value). */
    1574           1 :         if (length != 1) {
    1575           0 :                 flog_err(EC_BGP_ATTR_LEN,
    1576             :                          "Origin attribute length is not one %d", length);
    1577           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    1578           0 :                                           args->total);
    1579             :         }
    1580             : 
    1581             :         /* Fetch origin attribute. */
    1582           1 :         attr->origin = stream_getc(BGP_INPUT(peer));
    1583             : 
    1584             :         /* If the ORIGIN attribute has an undefined value, then the Error
    1585             :            Subcode is set to Invalid Origin Attribute.  The Data field
    1586             :            contains the unrecognized attribute (type, length and value). */
    1587           1 :         if ((attr->origin != BGP_ORIGIN_IGP) && (attr->origin != BGP_ORIGIN_EGP)
    1588             :             && (attr->origin != BGP_ORIGIN_INCOMPLETE)) {
    1589           0 :                 flog_err(EC_BGP_ATTR_ORIGIN,
    1590             :                          "Origin attribute value is invalid %d", attr->origin);
    1591           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
    1592           0 :                                           args->total);
    1593             :         }
    1594             : 
    1595             :         /* Set oring attribute flag. */
    1596           1 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGIN);
    1597             : 
    1598           1 :         return 0;
    1599             : }
    1600             : 
    1601             : /* Parse AS path information.  This function is wrapper of
    1602             :    aspath_parse. */
    1603           1 : static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
    1604             : {
    1605           1 :         struct attr *const attr = args->attr;
    1606           1 :         struct peer *const peer = args->peer;
    1607           1 :         const bgp_size_t length = args->length;
    1608             : 
    1609             :         /*
    1610             :          * peer with AS4 => will get 4Byte ASnums
    1611             :          * otherwise, will get 16 Bit
    1612             :          */
    1613           2 :         attr->aspath = aspath_parse(
    1614             :                 peer->curr, length,
    1615             :                 CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
    1616           1 :                         && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV));
    1617             : 
    1618             :         /* In case of IBGP, length will be zero. */
    1619           1 :         if (!attr->aspath) {
    1620           0 :                 flog_err(EC_BGP_ATTR_MAL_AS_PATH,
    1621             :                          "Malformed AS path from %s, length is %d", peer->host,
    1622             :                          length);
    1623           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
    1624             :                                           0);
    1625             :         }
    1626             : 
    1627             :         /* Conformant BGP speakers SHOULD NOT send BGP
    1628             :          * UPDATE messages containing AS_SET or AS_CONFED_SET.  Upon receipt of
    1629             :          * such messages, conformant BGP speakers SHOULD use the "Treat-as-
    1630             :          * withdraw" error handling behavior as per [RFC7606].
    1631             :          */
    1632           1 :         if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
    1633           0 :                 flog_err(EC_BGP_ATTR_MAL_AS_PATH,
    1634             :                          "AS_SET and AS_CONFED_SET are deprecated from %pBP",
    1635             :                          peer);
    1636           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
    1637             :                                           0);
    1638             :         }
    1639             : 
    1640             :         /* Set aspath attribute flag. */
    1641           1 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
    1642             : 
    1643           1 :         return BGP_ATTR_PARSE_PROCEED;
    1644             : }
    1645             : 
    1646           1 : static enum bgp_attr_parse_ret bgp_attr_aspath_check(struct peer *const peer,
    1647             :                                                      struct attr *const attr)
    1648             : {
    1649             :         /* These checks were part of bgp_attr_aspath, but with
    1650             :          * as4 we should to check aspath things when
    1651             :          * aspath synthesizing with as4_path has already taken place.
    1652             :          * Otherwise we check ASPATH and use the synthesized thing, and that is
    1653             :          * not right.
    1654             :          * So do the checks later, i.e. here
    1655             :          */
    1656           1 :         struct aspath *aspath;
    1657             : 
    1658             :         /* Confederation sanity check. */
    1659           1 :         if ((peer->sort == BGP_PEER_CONFED
    1660           0 :              && !aspath_left_confed_check(attr->aspath))
    1661           1 :             || (peer->sort == BGP_PEER_EBGP
    1662           1 :                 && aspath_confed_check(attr->aspath))) {
    1663           0 :                 flog_err(EC_BGP_ATTR_MAL_AS_PATH, "Malformed AS path from %s",
    1664             :                          peer->host);
    1665           0 :                 return BGP_ATTR_PARSE_WITHDRAW;
    1666             :         }
    1667             : 
    1668             :         /* First AS check for EBGP. */
    1669           1 :         if (CHECK_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS)) {
    1670           0 :                 if (peer->sort == BGP_PEER_EBGP
    1671           0 :                     && !aspath_firstas_check(attr->aspath, peer->as)) {
    1672           0 :                         flog_err(EC_BGP_ATTR_FIRST_AS,
    1673             :                                  "%s incorrect first AS (must be %u)",
    1674             :                                  peer->host, peer->as);
    1675           0 :                         return BGP_ATTR_PARSE_WITHDRAW;
    1676             :                 }
    1677             :         }
    1678             : 
    1679             :         /* Codification of AS 0 Processing */
    1680           1 :         if (peer->sort == BGP_PEER_EBGP && aspath_check_as_zero(attr->aspath)) {
    1681           0 :                 flog_err(
    1682             :                         EC_BGP_ATTR_MAL_AS_PATH,
    1683             :                         "Malformed AS path, AS number is 0 in the path from %s",
    1684             :                         peer->host);
    1685           0 :                 return BGP_ATTR_PARSE_WITHDRAW;
    1686             :         }
    1687             : 
    1688             :         /* local-as prepend */
    1689           1 :         if (peer->change_local_as
    1690           0 :             && !CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)) {
    1691           0 :                 aspath = aspath_dup(attr->aspath);
    1692           0 :                 aspath = aspath_add_seq(aspath, peer->change_local_as);
    1693           0 :                 aspath_unintern(&attr->aspath);
    1694           0 :                 attr->aspath = aspath_intern(aspath);
    1695             :         }
    1696             : 
    1697             :         return BGP_ATTR_PARSE_PROCEED;
    1698             : }
    1699             : 
    1700             : /* Parse AS4 path information.  This function is another wrapper of
    1701             :    aspath_parse. */
    1702           0 : static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
    1703             :                              struct aspath **as4_path)
    1704             : {
    1705           0 :         struct peer *const peer = args->peer;
    1706           0 :         struct attr *const attr = args->attr;
    1707           0 :         const bgp_size_t length = args->length;
    1708             : 
    1709           0 :         *as4_path = aspath_parse(peer->curr, length, 1);
    1710             : 
    1711             :         /* In case of IBGP, length will be zero. */
    1712           0 :         if (!*as4_path) {
    1713           0 :                 flog_err(EC_BGP_ATTR_MAL_AS_PATH,
    1714             :                          "Malformed AS4 path from %s, length is %d", peer->host,
    1715             :                          length);
    1716           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
    1717             :                                           0);
    1718             :         }
    1719             : 
    1720             :         /* Conformant BGP speakers SHOULD NOT send BGP
    1721             :          * UPDATE messages containing AS_SET or AS_CONFED_SET.  Upon receipt of
    1722             :          * such messages, conformant BGP speakers SHOULD use the "Treat-as-
    1723             :          * withdraw" error handling behavior as per [RFC7606].
    1724             :          */
    1725           0 :         if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) {
    1726           0 :                 flog_err(EC_BGP_ATTR_MAL_AS_PATH,
    1727             :                          "AS_SET and AS_CONFED_SET are deprecated from %pBP",
    1728             :                          peer);
    1729           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
    1730             :                                           0);
    1731             :         }
    1732             : 
    1733             :         /* Set aspath attribute flag. */
    1734           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH);
    1735             : 
    1736           0 :         return BGP_ATTR_PARSE_PROCEED;
    1737             : }
    1738             : 
    1739             : /*
    1740             :  * Check that the nexthop attribute is valid.
    1741             :  */
    1742           1 : enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer,
    1743             :                                                struct attr *attr)
    1744             : {
    1745           1 :         struct bgp *bgp = peer->bgp;
    1746             : 
    1747           1 :         if (ipv4_martian(&attr->nexthop) && !bgp->allow_martian) {
    1748           0 :                 uint8_t data[7]; /* type(2) + length(1) + nhop(4) */
    1749             : 
    1750           0 :                 flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %pI4",
    1751             :                          &attr->nexthop);
    1752           0 :                 data[0] = BGP_ATTR_FLAG_TRANS;
    1753           0 :                 data[1] = BGP_ATTR_NEXT_HOP;
    1754           0 :                 data[2] = BGP_ATTR_NHLEN_IPV4;
    1755           0 :                 memcpy(&data[3], &attr->nexthop.s_addr, BGP_ATTR_NHLEN_IPV4);
    1756           0 :                 bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
    1757             :                                           BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
    1758             :                                           data, 7);
    1759           0 :                 return BGP_ATTR_PARSE_ERROR;
    1760             :         }
    1761             : 
    1762             :         return BGP_ATTR_PARSE_PROCEED;
    1763             : }
    1764             : 
    1765             : /* Nexthop attribute. */
    1766             : static enum bgp_attr_parse_ret
    1767           1 : bgp_attr_nexthop(struct bgp_attr_parser_args *args)
    1768             : {
    1769           1 :         struct peer *const peer = args->peer;
    1770           1 :         struct attr *const attr = args->attr;
    1771           1 :         const bgp_size_t length = args->length;
    1772             : 
    1773             :         /* Check nexthop attribute length. */
    1774           1 :         if (length != 4) {
    1775           0 :                 flog_err(EC_BGP_ATTR_LEN,
    1776             :                          "Nexthop attribute length isn't four [%d]", length);
    1777             : 
    1778           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    1779           0 :                                           args->total);
    1780             :         }
    1781             : 
    1782           1 :         attr->nexthop.s_addr = stream_get_ipv4(peer->curr);
    1783           1 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
    1784             : 
    1785           1 :         return BGP_ATTR_PARSE_PROCEED;
    1786             : }
    1787             : 
    1788             : /* MED atrribute. */
    1789           0 : static enum bgp_attr_parse_ret bgp_attr_med(struct bgp_attr_parser_args *args)
    1790             : {
    1791           0 :         struct peer *const peer = args->peer;
    1792           0 :         struct attr *const attr = args->attr;
    1793           0 :         const bgp_size_t length = args->length;
    1794             : 
    1795             :         /* Length check. */
    1796           0 :         if (length != 4) {
    1797           0 :                 flog_err(EC_BGP_ATTR_LEN,
    1798             :                          "MED attribute length isn't four [%d]", length);
    1799             : 
    1800           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    1801           0 :                                           args->total);
    1802             :         }
    1803             : 
    1804           0 :         attr->med = stream_getl(peer->curr);
    1805             : 
    1806           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
    1807             : 
    1808           0 :         return BGP_ATTR_PARSE_PROCEED;
    1809             : }
    1810             : 
    1811             : /* Local preference attribute. */
    1812             : static enum bgp_attr_parse_ret
    1813           0 : bgp_attr_local_pref(struct bgp_attr_parser_args *args)
    1814             : {
    1815           0 :         struct peer *const peer = args->peer;
    1816           0 :         struct attr *const attr = args->attr;
    1817           0 :         const bgp_size_t length = args->length;
    1818             : 
    1819             :         /* if received from an internal neighbor, it SHALL be considered
    1820             :          * malformed if its length is not equal to 4. If malformed, the
    1821             :          * UPDATE message SHALL be handled using the approach of "treat-as-
    1822             :          * withdraw".
    1823             :          */
    1824           0 :         if (peer->sort == BGP_PEER_IBGP && length != 4) {
    1825           0 :                 flog_err(EC_BGP_ATTR_LEN,
    1826             :                          "LOCAL_PREF attribute length isn't 4 [%u]", length);
    1827           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    1828           0 :                                           args->total);
    1829             :         }
    1830             : 
    1831             :         /* If it is contained in an UPDATE message that is received from an
    1832             :            external peer, then this attribute MUST be ignored by the
    1833             :            receiving speaker. */
    1834           0 :         if (peer->sort == BGP_PEER_EBGP) {
    1835           0 :                 STREAM_FORWARD_GETP(peer->curr, length);
    1836             :                 return BGP_ATTR_PARSE_PROCEED;
    1837             :         }
    1838             : 
    1839           0 :         STREAM_GETL(peer->curr, attr->local_pref);
    1840             : 
    1841             :         /* Set the local-pref flag. */
    1842           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
    1843             : 
    1844           0 :         return BGP_ATTR_PARSE_PROCEED;
    1845             : 
    1846           0 : stream_failure:
    1847           0 :         return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    1848           0 :                                   args->total);
    1849             : }
    1850             : 
    1851             : /* Atomic aggregate. */
    1852           0 : static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
    1853             : {
    1854           0 :         struct peer *const peer = args->peer;
    1855           0 :         struct attr *const attr = args->attr;
    1856           0 :         const bgp_size_t length = args->length;
    1857             : 
    1858             :         /* Length check. */
    1859           0 :         if (length != 0) {
    1860           0 :                 flog_err(EC_BGP_ATTR_LEN,
    1861             :                          "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
    1862             :                          length);
    1863           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    1864           0 :                                           args->total);
    1865             :         }
    1866             : 
    1867           0 :         if (peer->discard_attrs[args->type])
    1868           0 :                 goto atomic_ignore;
    1869             : 
    1870             :         /* Set atomic aggregate flag. */
    1871           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
    1872             : 
    1873           0 :         return BGP_ATTR_PARSE_PROCEED;
    1874             : 
    1875           0 : atomic_ignore:
    1876           0 :         stream_forward_getp(peer->curr, length);
    1877             : 
    1878           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    1879           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    1880             :                            lookup_msg(attr_str, args->type, NULL));
    1881             : 
    1882             :         return BGP_ATTR_PARSE_PROCEED;
    1883             : }
    1884             : 
    1885             : /* Aggregator attribute */
    1886           0 : static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
    1887             : {
    1888           0 :         struct peer *const peer = args->peer;
    1889           0 :         struct attr *const attr = args->attr;
    1890           0 :         const bgp_size_t length = args->length;
    1891           0 :         as_t aggregator_as;
    1892             : 
    1893           0 :         int wantedlen = 6;
    1894             : 
    1895             :         /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
    1896           0 :         if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
    1897           0 :             && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV))
    1898           0 :                 wantedlen = 8;
    1899             : 
    1900           0 :         if (length != wantedlen) {
    1901           0 :                 flog_err(EC_BGP_ATTR_LEN,
    1902             :                          "AGGREGATOR attribute length isn't %u [%u]", wantedlen,
    1903             :                          length);
    1904           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    1905           0 :                                           args->total);
    1906             :         }
    1907             : 
    1908           0 :         if (peer->discard_attrs[args->type])
    1909           0 :                 goto aggregator_ignore;
    1910             : 
    1911           0 :         if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV))
    1912           0 :                 aggregator_as = stream_getl(peer->curr);
    1913             :         else
    1914           0 :                 aggregator_as = stream_getw(peer->curr);
    1915             : 
    1916           0 :         attr->aggregator_as = aggregator_as;
    1917           0 :         attr->aggregator_addr.s_addr = stream_get_ipv4(peer->curr);
    1918             : 
    1919             :         /* Codification of AS 0 Processing */
    1920           0 :         if (aggregator_as == BGP_AS_ZERO) {
    1921           0 :                 flog_err(EC_BGP_ATTR_LEN,
    1922             :                          "%s: AGGREGATOR AS number is 0 for aspath: %s",
    1923             :                          peer->host, aspath_print(attr->aspath));
    1924             : 
    1925           0 :                 if (bgp_debug_update(peer, NULL, NULL, 1)) {
    1926           0 :                         char attr_str[BUFSIZ] = {0};
    1927             : 
    1928           0 :                         bgp_dump_attr(attr, attr_str, sizeof(attr_str));
    1929             : 
    1930           0 :                         zlog_debug("%s: attributes: %s", __func__, attr_str);
    1931             :                 }
    1932             :         } else {
    1933           0 :                 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR);
    1934             :         }
    1935             : 
    1936             :         return BGP_ATTR_PARSE_PROCEED;
    1937             : 
    1938           0 : aggregator_ignore:
    1939           0 :         stream_forward_getp(peer->curr, length);
    1940             : 
    1941           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    1942           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    1943             :                            lookup_msg(attr_str, args->type, NULL));
    1944             : 
    1945             :         return BGP_ATTR_PARSE_PROCEED;
    1946             : }
    1947             : 
    1948             : /* New Aggregator attribute */
    1949             : static enum bgp_attr_parse_ret
    1950           0 : bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
    1951             :                         as_t *as4_aggregator_as,
    1952             :                         struct in_addr *as4_aggregator_addr)
    1953             : {
    1954           0 :         struct peer *const peer = args->peer;
    1955           0 :         struct attr *const attr = args->attr;
    1956           0 :         const bgp_size_t length = args->length;
    1957           0 :         as_t aggregator_as;
    1958             : 
    1959           0 :         if (length != 8) {
    1960           0 :                 flog_err(EC_BGP_ATTR_LEN, "New Aggregator length is not 8 [%d]",
    1961             :                          length);
    1962           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    1963             :                                           0);
    1964             :         }
    1965             : 
    1966           0 :         if (peer->discard_attrs[args->type])
    1967           0 :                 goto as4_aggregator_ignore;
    1968             : 
    1969           0 :         aggregator_as = stream_getl(peer->curr);
    1970             : 
    1971           0 :         *as4_aggregator_as = aggregator_as;
    1972           0 :         as4_aggregator_addr->s_addr = stream_get_ipv4(peer->curr);
    1973             : 
    1974             :         /* Codification of AS 0 Processing */
    1975           0 :         if (aggregator_as == BGP_AS_ZERO) {
    1976           0 :                 flog_err(EC_BGP_ATTR_LEN,
    1977             :                          "%s: AS4_AGGREGATOR AS number is 0 for aspath: %s",
    1978             :                          peer->host, aspath_print(attr->aspath));
    1979             : 
    1980           0 :                 if (bgp_debug_update(peer, NULL, NULL, 1)) {
    1981           0 :                         char attr_str[BUFSIZ] = {0};
    1982             : 
    1983           0 :                         bgp_dump_attr(attr, attr_str, sizeof(attr_str));
    1984             : 
    1985           0 :                         zlog_debug("%s: attributes: %s", __func__, attr_str);
    1986             :                 }
    1987             :         } else {
    1988           0 :                 attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR);
    1989             :         }
    1990             : 
    1991             :         return BGP_ATTR_PARSE_PROCEED;
    1992             : 
    1993           0 : as4_aggregator_ignore:
    1994           0 :         stream_forward_getp(peer->curr, length);
    1995             : 
    1996           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    1997           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    1998             :                            lookup_msg(attr_str, args->type, NULL));
    1999             : 
    2000             :         return BGP_ATTR_PARSE_PROCEED;
    2001             : }
    2002             : 
    2003             : /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
    2004             :  */
    2005             : static enum bgp_attr_parse_ret
    2006           1 : bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
    2007             :                          struct aspath *as4_path, as_t as4_aggregator,
    2008             :                          struct in_addr *as4_aggregator_addr)
    2009             : {
    2010           1 :         int ignore_as4_path = 0;
    2011           1 :         struct aspath *newpath;
    2012             : 
    2013           1 :         if (!attr->aspath) {
    2014             :                 /* NULL aspath shouldn't be possible as bgp_attr_parse should
    2015             :                  * have
    2016             :                  * checked that all well-known, mandatory attributes were
    2017             :                  * present.
    2018             :                  *
    2019             :                  * Can only be a problem with peer itself - hard error
    2020             :                  */
    2021             :                 return BGP_ATTR_PARSE_ERROR;
    2022             :         }
    2023             : 
    2024           1 :         if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)) {
    2025             :                 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
    2026             :                  * if given.
    2027             :                  * It is worth a warning though, because the peer really
    2028             :                  * should not send them
    2029             :                  */
    2030           1 :                 if (BGP_DEBUG(as4, AS4)) {
    2031           0 :                         if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
    2032           0 :                                 zlog_debug("[AS4] %s %s AS4_PATH", peer->host,
    2033             :                                            "AS4 capable peer, yet it sent");
    2034             : 
    2035           0 :                         if (attr->flag
    2036           0 :                             & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
    2037           0 :                                 zlog_debug("[AS4] %s %s AS4_AGGREGATOR",
    2038             :                                            peer->host,
    2039             :                                            "AS4 capable peer, yet it sent");
    2040             :                 }
    2041             : 
    2042           1 :                 return BGP_ATTR_PARSE_PROCEED;
    2043             :         }
    2044             : 
    2045             :         /* We have a asn16 peer.  First, look for AS4_AGGREGATOR
    2046             :          * because that may override AS4_PATH
    2047             :          */
    2048           0 :         if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR))) {
    2049           0 :                 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
    2050             :                         /* received both.
    2051             :                          * if the as_number in aggregator is not AS_TRANS,
    2052             :                          *  then AS4_AGGREGATOR and AS4_PATH shall be ignored
    2053             :                          *        and the Aggregator shall be taken as
    2054             :                          *        info on the aggregating node, and the AS_PATH
    2055             :                          *        shall be taken as the AS_PATH
    2056             :                          *  otherwise
    2057             :                          *        the Aggregator shall be ignored and the
    2058             :                          *        AS4_AGGREGATOR shall be taken as the
    2059             :                          *        Aggregating node and the AS_PATH is to be
    2060             :                          *        constructed "as in all other cases"
    2061             :                          */
    2062           0 :                         if (attr->aggregator_as != BGP_AS_TRANS) {
    2063             :                                 /* ignore */
    2064           0 :                                 if (BGP_DEBUG(as4, AS4))
    2065           0 :                                         zlog_debug(
    2066             :                                                 "[AS4] %s BGP not AS4 capable peer send AGGREGATOR != AS_TRANS and AS4_AGGREGATOR, so ignore AS4_AGGREGATOR and AS4_PATH",
    2067             :                                                 peer->host);
    2068             :                                 ignore_as4_path = 1;
    2069             :                         } else {
    2070             :                                 /* "New_aggregator shall be taken as aggregator"
    2071             :                                  */
    2072           0 :                                 attr->aggregator_as = as4_aggregator;
    2073           0 :                                 attr->aggregator_addr.s_addr =
    2074           0 :                                         as4_aggregator_addr->s_addr;
    2075             :                         }
    2076             :                 } else {
    2077             :                         /* We received a AS4_AGGREGATOR but no AGGREGATOR.
    2078             :                          * That is bogus - but reading the conditions
    2079             :                          * we have to handle AS4_AGGREGATOR as if it were
    2080             :                          * AGGREGATOR in that case
    2081             :                          */
    2082           0 :                         if (BGP_DEBUG(as4, AS4))
    2083           0 :                                 zlog_debug(
    2084             :                                         "[AS4] %s BGP not AS4 capable peer send AS4_AGGREGATOR but no AGGREGATOR, will take it as if AGGREGATOR with AS_TRANS had been there",
    2085             :                                         peer->host);
    2086           0 :                         attr->aggregator_as = as4_aggregator;
    2087             :                         /* sweep it under the carpet and simulate a "good"
    2088             :                          * AGGREGATOR */
    2089           0 :                         attr->flag |= (ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR));
    2090             :                 }
    2091             :         }
    2092             : 
    2093             :         /* need to reconcile NEW_AS_PATH and AS_PATH */
    2094           0 :         if (!ignore_as4_path
    2095           0 :             && (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
    2096           0 :                 newpath = aspath_reconcile_as4(attr->aspath, as4_path);
    2097           0 :                 if (!newpath)
    2098             :                         return BGP_ATTR_PARSE_ERROR;
    2099             : 
    2100           0 :                 aspath_unintern(&attr->aspath);
    2101           0 :                 attr->aspath = aspath_intern(newpath);
    2102             :         }
    2103             :         return BGP_ATTR_PARSE_PROCEED;
    2104             : }
    2105             : 
    2106             : /* Community attribute. */
    2107             : static enum bgp_attr_parse_ret
    2108           0 : bgp_attr_community(struct bgp_attr_parser_args *args)
    2109             : {
    2110           0 :         struct peer *const peer = args->peer;
    2111           0 :         struct attr *const attr = args->attr;
    2112           0 :         const bgp_size_t length = args->length;
    2113             : 
    2114           0 :         if (length == 0) {
    2115           0 :                 bgp_attr_set_community(attr, NULL);
    2116           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2117           0 :                                           args->total);
    2118             :         }
    2119             : 
    2120           0 :         if (peer->discard_attrs[args->type])
    2121           0 :                 goto community_ignore;
    2122             : 
    2123           0 :         bgp_attr_set_community(
    2124             :                 attr,
    2125           0 :                 community_parse((uint32_t *)stream_pnt(peer->curr), length));
    2126             : 
    2127             :         /* XXX: fix community_parse to use stream API and remove this */
    2128           0 :         stream_forward_getp(peer->curr, length);
    2129             : 
    2130             :         /* The Community attribute SHALL be considered malformed if its
    2131             :          * length is not a non-zero multiple of 4.
    2132             :          */
    2133           0 :         if (!bgp_attr_get_community(attr))
    2134           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2135           0 :                                           args->total);
    2136             : 
    2137             :         return BGP_ATTR_PARSE_PROCEED;
    2138             : 
    2139           0 : community_ignore:
    2140           0 :         stream_forward_getp(peer->curr, length);
    2141             : 
    2142           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    2143           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    2144             :                            lookup_msg(attr_str, args->type, NULL));
    2145             : 
    2146             :         return BGP_ATTR_PARSE_PROCEED;
    2147             : }
    2148             : 
    2149             : /* Originator ID attribute. */
    2150             : static enum bgp_attr_parse_ret
    2151           0 : bgp_attr_originator_id(struct bgp_attr_parser_args *args)
    2152             : {
    2153           0 :         struct peer *const peer = args->peer;
    2154           0 :         struct attr *const attr = args->attr;
    2155           0 :         const bgp_size_t length = args->length;
    2156             : 
    2157             :         /* if received from an internal neighbor, it SHALL be considered
    2158             :          * malformed if its length is not equal to 4. If malformed, the
    2159             :          * UPDATE message SHALL be handled using the approach of "treat-as-
    2160             :          * withdraw".
    2161             :          */
    2162           0 :         if (length != 4) {
    2163           0 :                 flog_err(EC_BGP_ATTR_LEN, "Bad originator ID length %d",
    2164             :                          length);
    2165             : 
    2166           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2167           0 :                                           args->total);
    2168             :         }
    2169             : 
    2170           0 :         if (peer->discard_attrs[args->type])
    2171           0 :                 goto originator_id_ignore;
    2172             : 
    2173           0 :         attr->originator_id.s_addr = stream_get_ipv4(peer->curr);
    2174             : 
    2175           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID);
    2176             : 
    2177           0 :         return BGP_ATTR_PARSE_PROCEED;
    2178             : 
    2179           0 : originator_id_ignore:
    2180           0 :         stream_forward_getp(peer->curr, length);
    2181             : 
    2182           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    2183           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    2184             :                            lookup_msg(attr_str, args->type, NULL));
    2185             : 
    2186             :         return BGP_ATTR_PARSE_PROCEED;
    2187             : }
    2188             : 
    2189             : /* Cluster list attribute. */
    2190             : static enum bgp_attr_parse_ret
    2191           0 : bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
    2192             : {
    2193           0 :         struct peer *const peer = args->peer;
    2194           0 :         struct attr *const attr = args->attr;
    2195           0 :         const bgp_size_t length = args->length;
    2196             : 
    2197             :         /* if received from an internal neighbor, it SHALL be considered
    2198             :          * malformed if its length is not a non-zero multiple of 4.  If
    2199             :          * malformed, the UPDATE message SHALL be handled using the approach
    2200             :          * of "treat-as-withdraw".
    2201             :          */
    2202           0 :         if (length == 0 || length % 4) {
    2203           0 :                 flog_err(EC_BGP_ATTR_LEN, "Bad cluster list length %d", length);
    2204             : 
    2205           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2206           0 :                                           args->total);
    2207             :         }
    2208             : 
    2209           0 :         if (peer->discard_attrs[args->type])
    2210           0 :                 goto cluster_list_ignore;
    2211             : 
    2212           0 :         bgp_attr_set_cluster(
    2213           0 :                 attr, cluster_parse((struct in_addr *)stream_pnt(peer->curr),
    2214             :                                     length));
    2215             : 
    2216             :         /* XXX: Fix cluster_parse to use stream API and then remove this */
    2217           0 :         stream_forward_getp(peer->curr, length);
    2218             : 
    2219           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_CLUSTER_LIST);
    2220             : 
    2221           0 :         return BGP_ATTR_PARSE_PROCEED;
    2222             : 
    2223           0 : cluster_list_ignore:
    2224           0 :         stream_forward_getp(peer->curr, length);
    2225             : 
    2226           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    2227           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    2228             :                            lookup_msg(attr_str, args->type, NULL));
    2229             : 
    2230             :         return BGP_ATTR_PARSE_PROCEED;
    2231             : }
    2232             : 
    2233             : /* Multiprotocol reachability information parse. */
    2234           0 : int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
    2235             :                        struct bgp_nlri *mp_update)
    2236             : {
    2237           0 :         iana_afi_t pkt_afi;
    2238           0 :         afi_t afi;
    2239           0 :         iana_safi_t pkt_safi;
    2240           0 :         safi_t safi;
    2241           0 :         bgp_size_t nlri_len;
    2242           0 :         size_t start;
    2243           0 :         struct stream *s;
    2244           0 :         struct peer *const peer = args->peer;
    2245           0 :         struct attr *const attr = args->attr;
    2246           0 :         const bgp_size_t length = args->length;
    2247             : 
    2248             :         /* Set end of packet. */
    2249           0 :         s = BGP_INPUT(peer);
    2250           0 :         start = stream_get_getp(s);
    2251             : 
    2252             : /* safe to read statically sized header? */
    2253             : #define BGP_MP_REACH_MIN_SIZE 5
    2254             : #define LEN_LEFT        (length - (stream_get_getp(s) - start))
    2255           0 :         if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE)) {
    2256           0 :                 zlog_info("%s: %s sent invalid length, %lu, of MP_REACH_NLRI",
    2257             :                           __func__, peer->host, (unsigned long)length);
    2258           0 :                 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
    2259             :         }
    2260             : 
    2261             :         /* Load AFI, SAFI. */
    2262           0 :         pkt_afi = stream_getw(s);
    2263           0 :         pkt_safi = stream_getc(s);
    2264             : 
    2265             :         /* Convert AFI, SAFI to internal values, check. */
    2266           0 :         if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
    2267             :                 /* Log if AFI or SAFI is unrecognized. This is not an error
    2268             :                  * unless
    2269             :                  * the attribute is otherwise malformed.
    2270             :                  */
    2271           0 :                 if (bgp_debug_update(peer, NULL, NULL, 0))
    2272           0 :                         zlog_debug(
    2273             :                                 "%s sent unrecognizable AFI, %s or, SAFI, %s, of MP_REACH_NLRI",
    2274             :                                 peer->host, iana_afi2str(pkt_afi),
    2275             :                                 iana_safi2str(pkt_safi));
    2276           0 :                 return BGP_ATTR_PARSE_ERROR;
    2277             :         }
    2278             : 
    2279             :         /* Get nexthop length. */
    2280           0 :         attr->mp_nexthop_len = stream_getc(s);
    2281             : 
    2282           0 :         if (LEN_LEFT < attr->mp_nexthop_len) {
    2283           0 :                 zlog_info(
    2284             :                         "%s: %s sent next-hop length, %u, in MP_REACH_NLRI which goes past the end of attribute",
    2285             :                         __func__, peer->host, attr->mp_nexthop_len);
    2286           0 :                 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
    2287             :         }
    2288             : 
    2289             :         /* Nexthop length check. */
    2290           0 :         switch (attr->mp_nexthop_len) {
    2291           0 :         case 0:
    2292           0 :                 if (safi != SAFI_FLOWSPEC) {
    2293           0 :                         zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
    2294             :                                   __func__, peer->host, attr->mp_nexthop_len);
    2295           0 :                         return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
    2296             :                 }
    2297             :                 break;
    2298           0 :         case BGP_ATTR_NHLEN_VPNV4:
    2299           0 :                 stream_getl(s); /* RD high */
    2300           0 :                 stream_getl(s); /* RD low */
    2301             :                                 /*
    2302             :                                  * NOTE: intentional fall through
    2303             :                                  * - for consistency in rx processing
    2304             :                                  *
    2305             :                                  * The following comment is to signal GCC this intention
    2306             :                                  * and suppress the warning
    2307             :                                  */
    2308             :         /* FALLTHRU */
    2309           0 :         case BGP_ATTR_NHLEN_IPV4:
    2310           0 :                 stream_get(&attr->mp_nexthop_global_in, s, IPV4_MAX_BYTELEN);
    2311             :                 /* Probably needed for RFC 2283 */
    2312           0 :                 if (attr->nexthop.s_addr == INADDR_ANY)
    2313           0 :                         memcpy(&attr->nexthop.s_addr,
    2314             :                                &attr->mp_nexthop_global_in, IPV4_MAX_BYTELEN);
    2315             :                 break;
    2316           0 :         case BGP_ATTR_NHLEN_IPV6_GLOBAL:
    2317             :         case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
    2318           0 :                 if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV6_GLOBAL) {
    2319           0 :                         stream_getl(s); /* RD high */
    2320           0 :                         stream_getl(s); /* RD low */
    2321             :                 }
    2322           0 :                 stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
    2323           0 :                 if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
    2324           0 :                         if (!peer->nexthop.ifp) {
    2325           0 :                                 zlog_warn("%s sent a v6 global attribute but address is a V6 LL and there's no peer interface information. Hence, withdrawing",
    2326             :                                           peer->host);
    2327           0 :                                 return BGP_ATTR_PARSE_WITHDRAW;
    2328             :                         }
    2329           0 :                         attr->nh_ifindex = peer->nexthop.ifp->ifindex;
    2330             :                 }
    2331             :                 break;
    2332           0 :         case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
    2333             :         case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL:
    2334           0 :                 if (attr->mp_nexthop_len
    2335             :                     == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
    2336           0 :                         stream_getl(s); /* RD high */
    2337           0 :                         stream_getl(s); /* RD low */
    2338             :                 }
    2339           0 :                 stream_get(&attr->mp_nexthop_global, s, IPV6_MAX_BYTELEN);
    2340           0 :                 if (IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_global)) {
    2341           0 :                         if (!peer->nexthop.ifp) {
    2342           0 :                                 zlog_warn("%s sent a v6 global and LL attribute but global address is a V6 LL and there's no peer interface information. Hence, withdrawing",
    2343             :                                           peer->host);
    2344           0 :                                 return BGP_ATTR_PARSE_WITHDRAW;
    2345             :                         }
    2346           0 :                         attr->nh_ifindex = peer->nexthop.ifp->ifindex;
    2347             :                 }
    2348           0 :                 if (attr->mp_nexthop_len
    2349             :                     == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
    2350           0 :                         stream_getl(s); /* RD high */
    2351           0 :                         stream_getl(s); /* RD low */
    2352             :                 }
    2353           0 :                 stream_get(&attr->mp_nexthop_local, s, IPV6_MAX_BYTELEN);
    2354           0 :                 if (!IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) {
    2355           0 :                         if (bgp_debug_update(peer, NULL, NULL, 1))
    2356           0 :                                 zlog_debug(
    2357             :                                         "%s sent next-hops %pI6 and %pI6. Ignoring non-LL value",
    2358             :                                         peer->host, &attr->mp_nexthop_global,
    2359             :                                         &attr->mp_nexthop_local);
    2360             : 
    2361           0 :                         attr->mp_nexthop_len = IPV6_MAX_BYTELEN;
    2362             :                 }
    2363           0 :                 if (!peer->nexthop.ifp) {
    2364           0 :                         zlog_warn("%s sent a v6 LL next-hop and there's no peer interface information. Hence, withdrawing",
    2365             :                                   peer->host);
    2366           0 :                         return BGP_ATTR_PARSE_WITHDRAW;
    2367             :                 }
    2368           0 :                 attr->nh_lla_ifindex = peer->nexthop.ifp->ifindex;
    2369           0 :                 break;
    2370           0 :         default:
    2371           0 :                 zlog_info("%s: %s sent wrong next-hop length, %d, in MP_REACH_NLRI",
    2372             :                           __func__, peer->host, attr->mp_nexthop_len);
    2373           0 :                 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
    2374             :         }
    2375             : 
    2376           0 :         if (!LEN_LEFT) {
    2377           0 :                 zlog_info("%s: %s sent SNPA which couldn't be read",
    2378             :                           __func__, peer->host);
    2379           0 :                 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
    2380             :         }
    2381             : 
    2382             :         {
    2383           0 :                 uint8_t val;
    2384           0 :                 if ((val = stream_getc(s)))
    2385           0 :                         flog_warn(
    2386             :                                 EC_BGP_DEFUNCT_SNPA_LEN,
    2387             :                                 "%s sent non-zero value, %u, for defunct SNPA-length field",
    2388             :                                 peer->host, val);
    2389             :         }
    2390             : 
    2391             :         /* must have nrli_len, what is left of the attribute */
    2392           0 :         nlri_len = LEN_LEFT;
    2393           0 :         if (nlri_len > STREAM_READABLE(s)) {
    2394           0 :                 zlog_info("%s: %s sent MP_REACH_NLRI which couldn't be read",
    2395             :                           __func__, peer->host);
    2396           0 :                 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
    2397             :         }
    2398             : 
    2399           0 :         if (!nlri_len) {
    2400           0 :                 zlog_info("%s: %s sent a zero-length NLRI. Hence, treating as a EOR marker",
    2401             :                           __func__, peer->host);
    2402             : 
    2403           0 :                 mp_update->afi = afi;
    2404           0 :                 mp_update->safi = safi;
    2405           0 :                 return BGP_ATTR_PARSE_EOR;
    2406             :         }
    2407             : 
    2408           0 :         mp_update->afi = afi;
    2409           0 :         mp_update->safi = safi;
    2410           0 :         mp_update->nlri = stream_pnt(s);
    2411           0 :         mp_update->length = nlri_len;
    2412             : 
    2413           0 :         stream_forward_getp(s, nlri_len);
    2414             : 
    2415           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI);
    2416             : 
    2417           0 :         return BGP_ATTR_PARSE_PROCEED;
    2418             : #undef LEN_LEFT
    2419             : }
    2420             : 
    2421             : /* Multiprotocol unreachable parse */
    2422           0 : int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
    2423             :                          struct bgp_nlri *mp_withdraw)
    2424             : {
    2425           0 :         struct stream *s;
    2426           0 :         iana_afi_t pkt_afi;
    2427           0 :         afi_t afi;
    2428           0 :         iana_safi_t pkt_safi;
    2429           0 :         safi_t safi;
    2430           0 :         uint16_t withdraw_len;
    2431           0 :         struct peer *const peer = args->peer;
    2432           0 :         struct attr *const attr = args->attr;
    2433           0 :         const bgp_size_t length = args->length;
    2434             : 
    2435           0 :         s = peer->curr;
    2436             : 
    2437             : #define BGP_MP_UNREACH_MIN_SIZE 3
    2438           0 :         if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
    2439             :                 return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
    2440             : 
    2441           0 :         pkt_afi = stream_getw(s);
    2442           0 :         pkt_safi = stream_getc(s);
    2443             : 
    2444             :         /* Convert AFI, SAFI to internal values, check. */
    2445           0 :         if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
    2446             :                 /* Log if AFI or SAFI is unrecognized. This is not an error
    2447             :                  * unless
    2448             :                  * the attribute is otherwise malformed.
    2449             :                  */
    2450           0 :                 if (bgp_debug_update(peer, NULL, NULL, 0))
    2451           0 :                         zlog_debug(
    2452             :                                 "%s: MP_UNREACH received AFI %s or SAFI %s is unrecognized",
    2453             :                                 peer->host, iana_afi2str(pkt_afi),
    2454             :                                 iana_safi2str(pkt_safi));
    2455           0 :                 return BGP_ATTR_PARSE_ERROR;
    2456             :         }
    2457             : 
    2458           0 :         withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
    2459             : 
    2460           0 :         mp_withdraw->afi = afi;
    2461           0 :         mp_withdraw->safi = safi;
    2462           0 :         mp_withdraw->nlri = stream_pnt(s);
    2463           0 :         mp_withdraw->length = withdraw_len;
    2464             : 
    2465           0 :         stream_forward_getp(s, withdraw_len);
    2466             : 
    2467           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI);
    2468             : 
    2469           0 :         return BGP_ATTR_PARSE_PROCEED;
    2470             : }
    2471             : 
    2472             : /* Large Community attribute. */
    2473             : static enum bgp_attr_parse_ret
    2474           0 : bgp_attr_large_community(struct bgp_attr_parser_args *args)
    2475             : {
    2476           0 :         struct peer *const peer = args->peer;
    2477           0 :         struct attr *const attr = args->attr;
    2478           0 :         const bgp_size_t length = args->length;
    2479             : 
    2480             :         /*
    2481             :          * Large community follows new attribute format.
    2482             :          */
    2483           0 :         if (length == 0) {
    2484           0 :                 bgp_attr_set_lcommunity(attr, NULL);
    2485             :                 /* Empty extcomm doesn't seem to be invalid per se */
    2486           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2487           0 :                                           args->total);
    2488             :         }
    2489             : 
    2490           0 :         if (peer->discard_attrs[args->type])
    2491           0 :                 goto large_community_ignore;
    2492             : 
    2493           0 :         bgp_attr_set_lcommunity(
    2494             :                 attr, lcommunity_parse(stream_pnt(peer->curr), length));
    2495             :         /* XXX: fix ecommunity_parse to use stream API */
    2496           0 :         stream_forward_getp(peer->curr, length);
    2497             : 
    2498           0 :         if (!bgp_attr_get_lcommunity(attr))
    2499           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2500           0 :                                           args->total);
    2501             : 
    2502             :         return BGP_ATTR_PARSE_PROCEED;
    2503             : 
    2504           0 : large_community_ignore:
    2505           0 :         stream_forward_getp(peer->curr, length);
    2506             : 
    2507           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    2508           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    2509             :                            lookup_msg(attr_str, args->type, NULL));
    2510             : 
    2511             :         return BGP_ATTR_PARSE_PROCEED;
    2512             : }
    2513             : 
    2514             : /* Extended Community attribute. */
    2515             : static enum bgp_attr_parse_ret
    2516           0 : bgp_attr_ext_communities(struct bgp_attr_parser_args *args)
    2517             : {
    2518           0 :         struct peer *const peer = args->peer;
    2519           0 :         struct attr *const attr = args->attr;
    2520           0 :         const bgp_size_t length = args->length;
    2521           0 :         uint8_t sticky = 0;
    2522           0 :         bool proxy = false;
    2523           0 :         struct ecommunity *ecomm;
    2524             : 
    2525           0 :         if (length == 0) {
    2526           0 :                 bgp_attr_set_ecommunity(attr, NULL);
    2527             :                 /* Empty extcomm doesn't seem to be invalid per se */
    2528           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2529           0 :                                           args->total);
    2530             :         }
    2531             : 
    2532           0 :         ecomm = ecommunity_parse(
    2533             :                 stream_pnt(peer->curr), length,
    2534           0 :                 CHECK_FLAG(peer->flags,
    2535             :                            PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
    2536           0 :         bgp_attr_set_ecommunity(attr, ecomm);
    2537             :         /* XXX: fix ecommunity_parse to use stream API */
    2538           0 :         stream_forward_getp(peer->curr, length);
    2539             : 
    2540             :         /* The Extended Community attribute SHALL be considered malformed if
    2541             :          * its length is not a non-zero multiple of 8.
    2542             :          */
    2543           0 :         if (!bgp_attr_get_ecommunity(attr))
    2544           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2545           0 :                                           args->total);
    2546             : 
    2547             :         /* Extract DF election preference and  mobility sequence number */
    2548           0 :         attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg);
    2549             : 
    2550             :         /* Extract MAC mobility sequence number, if any. */
    2551           0 :         attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky);
    2552           0 :         attr->sticky = sticky;
    2553             : 
    2554             :         /* Check if this is a Gateway MAC-IP advertisement */
    2555           0 :         attr->default_gw = bgp_attr_default_gw(attr);
    2556             : 
    2557             :         /* Handle scenario where router flag ecommunity is not
    2558             :          * set but default gw ext community is present.
    2559             :          * Use default gateway, set and propogate R-bit.
    2560             :          */
    2561           0 :         if (attr->default_gw)
    2562           0 :                 attr->router_flag = 1;
    2563             : 
    2564             :         /* Check EVPN Neighbor advertisement flags, R-bit */
    2565           0 :         bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy);
    2566           0 :         if (proxy)
    2567           0 :                 attr->es_flags |= ATTR_ES_PROXY_ADVERT;
    2568             : 
    2569             :         /* Extract the Rmac, if any */
    2570           0 :         if (bgp_attr_rmac(attr, &attr->rmac)) {
    2571           0 :                 if (bgp_debug_update(peer, NULL, NULL, 1)
    2572           0 :                     && bgp_mac_exist(&attr->rmac))
    2573           0 :                         zlog_debug("%s: router mac %pEA is self mac", __func__,
    2574             :                                    &attr->rmac);
    2575             :         }
    2576             : 
    2577             :         /* Get the tunnel type from encap extended community */
    2578           0 :         bgp_attr_extcom_tunnel_type(attr,
    2579           0 :                 (bgp_encap_types *)&attr->encap_tunneltype);
    2580             : 
    2581             :         /* Extract link bandwidth, if any. */
    2582           0 :         (void)ecommunity_linkbw_present(bgp_attr_get_ecommunity(attr),
    2583             :                                         &attr->link_bw);
    2584             : 
    2585           0 :         return BGP_ATTR_PARSE_PROCEED;
    2586             : }
    2587             : 
    2588             : /* IPv6 Extended Community attribute. */
    2589             : static enum bgp_attr_parse_ret
    2590           0 : bgp_attr_ipv6_ext_communities(struct bgp_attr_parser_args *args)
    2591             : {
    2592           0 :         struct peer *const peer = args->peer;
    2593           0 :         struct attr *const attr = args->attr;
    2594           0 :         const bgp_size_t length = args->length;
    2595           0 :         struct ecommunity *ipv6_ecomm = NULL;
    2596             : 
    2597           0 :         if (length == 0) {
    2598           0 :                 bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
    2599           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2600           0 :                                           args->total);
    2601             :         }
    2602             : 
    2603           0 :         if (peer->discard_attrs[args->type])
    2604           0 :                 goto ipv6_ext_community_ignore;
    2605             : 
    2606           0 :         ipv6_ecomm = ecommunity_parse_ipv6(
    2607             :                 stream_pnt(peer->curr), length,
    2608           0 :                 CHECK_FLAG(peer->flags,
    2609             :                            PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE));
    2610           0 :         bgp_attr_set_ipv6_ecommunity(attr, ipv6_ecomm);
    2611             : 
    2612             :         /* XXX: fix ecommunity_parse to use stream API */
    2613           0 :         stream_forward_getp(peer->curr, length);
    2614             : 
    2615           0 :         if (!ipv6_ecomm)
    2616           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2617           0 :                                           args->total);
    2618             : 
    2619             :         return BGP_ATTR_PARSE_PROCEED;
    2620             : 
    2621           0 : ipv6_ext_community_ignore:
    2622           0 :         stream_forward_getp(peer->curr, length);
    2623             : 
    2624           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    2625           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    2626             :                            lookup_msg(attr_str, args->type, NULL));
    2627             : 
    2628             :         return BGP_ATTR_PARSE_PROCEED;
    2629             : }
    2630             : 
    2631             : /* Parse Tunnel Encap attribute in an UPDATE */
    2632           0 : static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
    2633             :                           bgp_size_t length, /* IN: attr's length field */
    2634             :                           struct attr *attr, /* IN: caller already allocated */
    2635             :                           uint8_t flag,      /* IN: attr's flags field */
    2636             :                           uint8_t *startp)
    2637             : {
    2638           0 :         bgp_size_t total;
    2639           0 :         uint16_t tunneltype = 0;
    2640             : 
    2641           0 :         total = length + (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
    2642             : 
    2643           0 :         if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
    2644           0 :             || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
    2645           0 :                 zlog_info(
    2646             :                         "Tunnel Encap attribute flag isn't optional and transitive %d",
    2647             :                         flag);
    2648           0 :                 bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
    2649             :                                           BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
    2650             :                                           startp, total);
    2651           0 :                 return -1;
    2652             :         }
    2653             : 
    2654           0 :         if (BGP_ATTR_ENCAP == type) {
    2655             :                 /* read outer TLV type and length */
    2656           0 :                 uint16_t tlv_length;
    2657             : 
    2658           0 :                 if (length < 4) {
    2659           0 :                         zlog_info(
    2660             :                                 "Tunnel Encap attribute not long enough to contain outer T,L");
    2661           0 :                         bgp_notify_send_with_data(
    2662             :                                 peer, BGP_NOTIFY_UPDATE_ERR,
    2663             :                                 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total);
    2664           0 :                         return -1;
    2665             :                 }
    2666           0 :                 tunneltype = stream_getw(BGP_INPUT(peer));
    2667           0 :                 tlv_length = stream_getw(BGP_INPUT(peer));
    2668           0 :                 length -= 4;
    2669             : 
    2670           0 :                 if (tlv_length != length) {
    2671           0 :                         zlog_info("%s: tlv_length(%d) != length(%d)",
    2672             :                                   __func__, tlv_length, length);
    2673             :                 }
    2674             :         }
    2675             : 
    2676           0 :         while (length >= 4) {
    2677           0 :                 uint16_t subtype = 0;
    2678           0 :                 uint16_t sublength = 0;
    2679           0 :                 struct bgp_attr_encap_subtlv *tlv;
    2680             : 
    2681           0 :                 if (BGP_ATTR_ENCAP == type) {
    2682           0 :                         subtype = stream_getc(BGP_INPUT(peer));
    2683           0 :                         sublength = stream_getc(BGP_INPUT(peer));
    2684           0 :                         length -= 2;
    2685             : #ifdef ENABLE_BGP_VNC
    2686             :                 } else {
    2687           0 :                         subtype = stream_getw(BGP_INPUT(peer));
    2688           0 :                         sublength = stream_getw(BGP_INPUT(peer));
    2689           0 :                         length -= 4;
    2690             : #endif
    2691             :                 }
    2692             : 
    2693           0 :                 if (sublength > length) {
    2694           0 :                         zlog_info(
    2695             :                                 "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
    2696             :                                 sublength, length);
    2697           0 :                         bgp_notify_send_with_data(
    2698             :                                 peer, BGP_NOTIFY_UPDATE_ERR,
    2699             :                                 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, startp, total);
    2700           0 :                         return -1;
    2701             :                 }
    2702             : 
    2703             :                 /* alloc and copy sub-tlv */
    2704             :                 /* TBD make sure these are freed when attributes are released */
    2705           0 :                 tlv = XCALLOC(MTYPE_ENCAP_TLV,
    2706             :                               sizeof(struct bgp_attr_encap_subtlv) + sublength);
    2707           0 :                 tlv->type = subtype;
    2708           0 :                 tlv->length = sublength;
    2709           0 :                 stream_get(tlv->value, peer->curr, sublength);
    2710           0 :                 length -= sublength;
    2711             : 
    2712             :                 /* attach tlv to encap chain */
    2713           0 :                 if (BGP_ATTR_ENCAP == type) {
    2714           0 :                         struct bgp_attr_encap_subtlv *stlv_last;
    2715           0 :                         for (stlv_last = attr->encap_subtlvs;
    2716           0 :                              stlv_last && stlv_last->next;
    2717             :                              stlv_last = stlv_last->next)
    2718             :                                 ;
    2719           0 :                         if (stlv_last) {
    2720           0 :                                 stlv_last->next = tlv;
    2721             :                         } else {
    2722           0 :                                 attr->encap_subtlvs = tlv;
    2723             :                         }
    2724             : #ifdef ENABLE_BGP_VNC
    2725             :                 } else {
    2726           0 :                         struct bgp_attr_encap_subtlv *stlv_last;
    2727           0 :                         struct bgp_attr_encap_subtlv *vnc_subtlvs =
    2728           0 :                                 bgp_attr_get_vnc_subtlvs(attr);
    2729             : 
    2730           0 :                         for (stlv_last = vnc_subtlvs;
    2731           0 :                              stlv_last && stlv_last->next;
    2732             :                              stlv_last = stlv_last->next)
    2733             :                                 ;
    2734           0 :                         if (stlv_last)
    2735           0 :                                 stlv_last->next = tlv;
    2736             :                         else
    2737           0 :                                 bgp_attr_set_vnc_subtlvs(attr, tlv);
    2738             : #endif
    2739             :                 }
    2740             :         }
    2741             : 
    2742           0 :         if (BGP_ATTR_ENCAP == type) {
    2743           0 :                 attr->encap_tunneltype = tunneltype;
    2744             :         }
    2745             : 
    2746           0 :         if (length) {
    2747             :                 /* spurious leftover data */
    2748           0 :                 zlog_info(
    2749             :                         "Tunnel Encap attribute length is bad: %d leftover octets",
    2750             :                         length);
    2751           0 :                 bgp_notify_send_with_data(peer, BGP_NOTIFY_UPDATE_ERR,
    2752             :                                           BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2753             :                                           startp, total);
    2754           0 :                 return -1;
    2755             :         }
    2756             : 
    2757             :         return 0;
    2758             : }
    2759             : 
    2760             : 
    2761             : /* SRv6 Service Data Sub-Sub-TLV attribute
    2762             :  * draft-ietf-bess-srv6-services-07
    2763             :  */
    2764             : static enum bgp_attr_parse_ret
    2765           0 : bgp_attr_srv6_service_data(struct bgp_attr_parser_args *args)
    2766             : {
    2767           0 :         struct peer *const peer = args->peer;
    2768           0 :         struct attr *const attr = args->attr;
    2769           0 :         uint8_t type, loc_block_len, loc_node_len, func_len, arg_len,
    2770             :                 transposition_len, transposition_offset;
    2771           0 :         uint16_t length;
    2772           0 :         size_t headersz = sizeof(type) + sizeof(length);
    2773             : 
    2774           0 :         if (STREAM_READABLE(peer->curr) < headersz) {
    2775           0 :                 flog_err(
    2776             :                         EC_BGP_ATTR_LEN,
    2777             :                         "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
    2778             :                         headersz, STREAM_READABLE(peer->curr));
    2779           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2780           0 :                                           args->total);
    2781             :         }
    2782             : 
    2783           0 :         type = stream_getc(peer->curr);
    2784           0 :         length = stream_getw(peer->curr);
    2785             : 
    2786           0 :         if (STREAM_READABLE(peer->curr) < length) {
    2787           0 :                 flog_err(
    2788             :                         EC_BGP_ATTR_LEN,
    2789             :                         "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
    2790             :                         length, STREAM_READABLE(peer->curr));
    2791           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2792           0 :                                           args->total);
    2793             :         }
    2794             : 
    2795           0 :         if (length < BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH) {
    2796           0 :                 flog_err(
    2797             :                         EC_BGP_ATTR_LEN,
    2798             :                         "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %hu remaining in UPDATE)",
    2799             :                         BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH,
    2800             :                         length);
    2801           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2802           0 :                                           args->total);
    2803             :         }
    2804             : 
    2805           0 :         if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE) {
    2806           0 :                 if (STREAM_READABLE(peer->curr) <
    2807             :                     BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH) {
    2808           0 :                         flog_err(
    2809             :                                 EC_BGP_ATTR_LEN,
    2810             :                                 "Malformed SRv6 Service Data Sub-Sub-TLV attribute - insufficient data (need %u, have %zu remaining in UPDATE)",
    2811             :                                 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH,
    2812             :                                 STREAM_READABLE(peer->curr));
    2813           0 :                         return bgp_attr_malformed(
    2814             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2815           0 :                                 args->total);
    2816             :                 }
    2817             : 
    2818           0 :                 loc_block_len = stream_getc(peer->curr);
    2819           0 :                 loc_node_len = stream_getc(peer->curr);
    2820           0 :                 func_len = stream_getc(peer->curr);
    2821           0 :                 arg_len = stream_getc(peer->curr);
    2822           0 :                 transposition_len = stream_getc(peer->curr);
    2823           0 :                 transposition_offset = stream_getc(peer->curr);
    2824             : 
    2825             :                 /* Log SRv6 Service Data Sub-Sub-TLV */
    2826           0 :                 if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
    2827           0 :                         zlog_debug(
    2828             :                                 "%s: srv6-l3-srv-data loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u, transposition-len=%u, transposition-offset=%u",
    2829             :                                 __func__, loc_block_len, loc_node_len, func_len,
    2830             :                                 arg_len, transposition_len,
    2831             :                                 transposition_offset);
    2832             :                 }
    2833             : 
    2834           0 :                 attr->srv6_l3vpn->loc_block_len = loc_block_len;
    2835           0 :                 attr->srv6_l3vpn->loc_node_len = loc_node_len;
    2836           0 :                 attr->srv6_l3vpn->func_len = func_len;
    2837           0 :                 attr->srv6_l3vpn->arg_len = arg_len;
    2838           0 :                 attr->srv6_l3vpn->transposition_len = transposition_len;
    2839           0 :                 attr->srv6_l3vpn->transposition_offset = transposition_offset;
    2840             :         }
    2841             : 
    2842             :         else {
    2843           0 :                 if (bgp_debug_update(peer, NULL, NULL, 1))
    2844           0 :                         zlog_debug(
    2845             :                                 "%s attr SRv6 Service Data Sub-Sub-TLV sub-sub-type=%u is not supported, skipped",
    2846             :                                 peer->host, type);
    2847             : 
    2848           0 :                 stream_forward_getp(peer->curr, length);
    2849             :         }
    2850             : 
    2851             :         return BGP_ATTR_PARSE_PROCEED;
    2852             : }
    2853             : 
    2854             : /* SRv6 Service Sub-TLV attribute
    2855             :  * draft-ietf-bess-srv6-services-07
    2856             :  */
    2857             : static enum bgp_attr_parse_ret
    2858           0 : bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
    2859             : {
    2860           0 :         struct peer *const peer = args->peer;
    2861           0 :         struct attr *const attr = args->attr;
    2862           0 :         struct in6_addr ipv6_sid;
    2863           0 :         uint8_t type, sid_flags;
    2864           0 :         uint16_t length, endpoint_behavior;
    2865           0 :         size_t headersz = sizeof(type) + sizeof(length);
    2866           0 :         enum bgp_attr_parse_ret err;
    2867             : 
    2868           0 :         if (STREAM_READABLE(peer->curr) < headersz) {
    2869           0 :                 flog_err(
    2870             :                         EC_BGP_ATTR_LEN,
    2871             :                         "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
    2872             :                         headersz, STREAM_READABLE(peer->curr));
    2873           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2874           0 :                                           args->total);
    2875             :         }
    2876             : 
    2877           0 :         type = stream_getc(peer->curr);
    2878           0 :         length = stream_getw(peer->curr);
    2879             : 
    2880           0 :         if (STREAM_READABLE(peer->curr) < length) {
    2881           0 :                 flog_err(
    2882             :                         EC_BGP_ATTR_LEN,
    2883             :                         "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %hu for attribute data, have %zu remaining in UPDATE)",
    2884             :                         length, STREAM_READABLE(peer->curr));
    2885           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2886           0 :                                           args->total);
    2887             :         }
    2888             : 
    2889           0 :         if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO) {
    2890           0 :                 if (STREAM_READABLE(peer->curr) <
    2891             :                     BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
    2892           0 :                         flog_err(
    2893             :                                 EC_BGP_ATTR_LEN,
    2894             :                                 "Malformed SRv6 Service Sub-TLV attribute - insufficent data (need %d for attribute data, have %zu remaining in UPDATE)",
    2895             :                                 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH,
    2896             :                                 STREAM_READABLE(peer->curr));
    2897           0 :                         return bgp_attr_malformed(
    2898             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2899           0 :                                 args->total);
    2900             :                 }
    2901           0 :                 stream_getc(peer->curr);
    2902           0 :                 stream_get(&ipv6_sid, peer->curr, sizeof(ipv6_sid));
    2903           0 :                 sid_flags = stream_getc(peer->curr);
    2904           0 :                 endpoint_behavior = stream_getw(peer->curr);
    2905           0 :                 stream_getc(peer->curr);
    2906             : 
    2907             :                 /* Log SRv6 Service Sub-TLV */
    2908           0 :                 if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
    2909           0 :                         zlog_debug(
    2910             :                                 "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
    2911             :                                 __func__, &ipv6_sid, sid_flags,
    2912             :                                 endpoint_behavior);
    2913             : 
    2914             :                 /* Configure from Info */
    2915           0 :                 if (attr->srv6_l3vpn) {
    2916           0 :                         flog_err(EC_BGP_ATTRIBUTE_REPEATED,
    2917             :                                  "Prefix SID SRv6 L3VPN field repeated");
    2918           0 :                         return bgp_attr_malformed(
    2919           0 :                                 args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
    2920             :                 }
    2921           0 :                 attr->srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
    2922             :                                            sizeof(struct bgp_attr_srv6_l3vpn));
    2923           0 :                 sid_copy(&attr->srv6_l3vpn->sid, &ipv6_sid);
    2924           0 :                 attr->srv6_l3vpn->sid_flags = sid_flags;
    2925           0 :                 attr->srv6_l3vpn->endpoint_behavior = endpoint_behavior;
    2926           0 :                 attr->srv6_l3vpn->loc_block_len = 0;
    2927           0 :                 attr->srv6_l3vpn->loc_node_len = 0;
    2928           0 :                 attr->srv6_l3vpn->func_len = 0;
    2929           0 :                 attr->srv6_l3vpn->arg_len = 0;
    2930           0 :                 attr->srv6_l3vpn->transposition_len = 0;
    2931           0 :                 attr->srv6_l3vpn->transposition_offset = 0;
    2932             : 
    2933             :                 // Sub-Sub-TLV found
    2934           0 :                 if (length > BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH) {
    2935           0 :                         err = bgp_attr_srv6_service_data(args);
    2936             : 
    2937           0 :                         if (err != BGP_ATTR_PARSE_PROCEED)
    2938             :                                 return err;
    2939             :                 }
    2940             : 
    2941           0 :                 attr->srv6_l3vpn = srv6_l3vpn_intern(attr->srv6_l3vpn);
    2942             :         }
    2943             : 
    2944             :         /* Placeholder code for unsupported type */
    2945             :         else {
    2946           0 :                 if (bgp_debug_update(peer, NULL, NULL, 1))
    2947           0 :                         zlog_debug(
    2948             :                                 "%s attr SRv6 Service Sub-TLV sub-type=%u is not supported, skipped",
    2949             :                                 peer->host, type);
    2950             : 
    2951           0 :                 stream_forward_getp(peer->curr, length);
    2952             :         }
    2953             : 
    2954             :         return BGP_ATTR_PARSE_PROCEED;
    2955             : }
    2956             : 
    2957             : /*
    2958             :  * Read an individual SID value returning how much data we have read
    2959             :  * Returns 0 if there was an error that needs to be passed up the stack
    2960             :  */
    2961             : static enum bgp_attr_parse_ret
    2962           0 : bgp_attr_psid_sub(uint8_t type, uint16_t length,
    2963             :                   struct bgp_attr_parser_args *args)
    2964             : {
    2965           0 :         struct peer *const peer = args->peer;
    2966           0 :         struct attr *const attr = args->attr;
    2967           0 :         uint32_t label_index;
    2968           0 :         struct in6_addr ipv6_sid;
    2969           0 :         uint32_t srgb_base;
    2970           0 :         uint32_t srgb_range;
    2971           0 :         int srgb_count;
    2972           0 :         uint8_t sid_type, sid_flags;
    2973             : 
    2974           0 :         if (type == BGP_PREFIX_SID_LABEL_INDEX) {
    2975           0 :                 if (STREAM_READABLE(peer->curr) < length
    2976           0 :                     || length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) {
    2977           0 :                         flog_err(EC_BGP_ATTR_LEN,
    2978             :                                  "Prefix SID label index length is %hu instead of %u",
    2979             :                                  length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
    2980           0 :                         return bgp_attr_malformed(args,
    2981             :                                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    2982           0 :                                                   args->total);
    2983             :                 }
    2984             : 
    2985             :                 /* Ignore flags and reserved */
    2986           0 :                 stream_getc(peer->curr);
    2987           0 :                 stream_getw(peer->curr);
    2988             : 
    2989             :                 /* Fetch the label index and see if it is valid. */
    2990           0 :                 label_index = stream_getl(peer->curr);
    2991           0 :                 if (label_index == BGP_INVALID_LABEL_INDEX)
    2992           0 :                         return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    2993           0 :                                                   args->total);
    2994             : 
    2995             :                 /* Store label index; subsequently, we'll check on
    2996             :                  * address-family */
    2997           0 :                 attr->label_index = label_index;
    2998             :         }
    2999             : 
    3000             :         /* Placeholder code for the IPv6 SID type */
    3001           0 :         else if (type == BGP_PREFIX_SID_IPV6) {
    3002           0 :                 if (STREAM_READABLE(peer->curr) < length
    3003           0 :                     || length != BGP_PREFIX_SID_IPV6_LENGTH) {
    3004           0 :                         flog_err(EC_BGP_ATTR_LEN,
    3005             :                                  "Prefix SID IPv6 length is %hu instead of %u",
    3006             :                                  length, BGP_PREFIX_SID_IPV6_LENGTH);
    3007           0 :                         return bgp_attr_malformed(args,
    3008             :                                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3009           0 :                                                   args->total);
    3010             :                 }
    3011             : 
    3012             :                 /* Ignore reserved */
    3013           0 :                 stream_getc(peer->curr);
    3014           0 :                 stream_getw(peer->curr);
    3015             : 
    3016           0 :                 stream_get(&ipv6_sid, peer->curr, 16);
    3017             :         }
    3018             : 
    3019             :         /* Placeholder code for the Originator SRGB type */
    3020           0 :         else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB) {
    3021             :                 /*
    3022             :                  * ietf-idr-bgp-prefix-sid-05:
    3023             :                  *     Length is the total length of the value portion of the
    3024             :                  *     TLV: 2 + multiple of 6.
    3025             :                  *
    3026             :                  * peer->curr stream readp should be at the beginning of the 16
    3027             :                  * bit flag field at this point in the code.
    3028             :                  */
    3029             : 
    3030             :                 /*
    3031             :                  * Check that the TLV length field is sane: at least 2 bytes of
    3032             :                  * flag, and at least 1 SRGB (these are 6 bytes each)
    3033             :                  */
    3034           0 :                 if (length < (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH)) {
    3035           0 :                         flog_err(
    3036             :                                 EC_BGP_ATTR_LEN,
    3037             :                                 "Prefix SID Originator SRGB length field claims length of %hu bytes, but the minimum for this TLV type is %u",
    3038             :                                 length,
    3039             :                                 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
    3040           0 :                         return bgp_attr_malformed(
    3041             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3042           0 :                                 args->total);
    3043             :                 }
    3044             : 
    3045             :                 /*
    3046             :                  * Check that we actually have at least as much data as
    3047             :                  * specified by the length field
    3048             :                  */
    3049           0 :                 if (STREAM_READABLE(peer->curr) < length) {
    3050           0 :                         flog_err(EC_BGP_ATTR_LEN,
    3051             :                                  "Prefix SID Originator SRGB specifies length %hu, but only %zu bytes remain",
    3052             :                                  length, STREAM_READABLE(peer->curr));
    3053           0 :                         return bgp_attr_malformed(
    3054             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3055           0 :                                 args->total);
    3056             :                 }
    3057             : 
    3058             :                 /*
    3059             :                  * Check that the portion of the TLV containing the sequence of
    3060             :                  * SRGBs corresponds to a multiple of the SRGB size; to get
    3061             :                  * that length, we skip the 16 bit flags field
    3062             :                  */
    3063           0 :                 stream_getw(peer->curr);
    3064           0 :                 length -= 2;
    3065           0 :                 if (length % BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH) {
    3066           0 :                         flog_err(
    3067             :                                 EC_BGP_ATTR_LEN,
    3068             :                                 "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %hubytes, but it must be a multiple of %u",
    3069             :                                 length, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
    3070           0 :                         return bgp_attr_malformed(
    3071             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3072           0 :                                 args->total);
    3073             :                 }
    3074             : 
    3075           0 :                 srgb_count = length / BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH;
    3076             : 
    3077           0 :                 for (int i = 0; i < srgb_count; i++) {
    3078           0 :                         stream_get(&srgb_base, peer->curr, 3);
    3079           0 :                         stream_get(&srgb_range, peer->curr, 3);
    3080             :                 }
    3081             :         }
    3082             : 
    3083             :         /* Placeholder code for the VPN-SID Service type */
    3084           0 :         else if (type == BGP_PREFIX_SID_VPN_SID) {
    3085           0 :                 if (STREAM_READABLE(peer->curr) < length
    3086           0 :                     || length != BGP_PREFIX_SID_VPN_SID_LENGTH) {
    3087           0 :                         flog_err(EC_BGP_ATTR_LEN,
    3088             :                                  "Prefix SID VPN SID length is %hu instead of %u",
    3089             :                                  length, BGP_PREFIX_SID_VPN_SID_LENGTH);
    3090           0 :                         return bgp_attr_malformed(args,
    3091             :                                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3092           0 :                                                   args->total);
    3093             :                 }
    3094             : 
    3095             :                 /* Parse VPN-SID Sub-TLV */
    3096           0 :                 stream_getc(peer->curr);               /* reserved  */
    3097           0 :                 sid_type = stream_getc(peer->curr);    /* sid_type  */
    3098           0 :                 sid_flags = stream_getc(peer->curr);   /* sid_flags */
    3099           0 :                 stream_get(&ipv6_sid, peer->curr,
    3100             :                            sizeof(ipv6_sid)); /* sid_value */
    3101             : 
    3102             :                 /* Log VPN-SID Sub-TLV */
    3103           0 :                 if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
    3104           0 :                         zlog_debug(
    3105             :                                 "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
    3106             :                                 __func__, &ipv6_sid, sid_type, sid_flags);
    3107             : 
    3108             :                 /* Configure from Info */
    3109           0 :                 if (attr->srv6_vpn) {
    3110           0 :                         flog_err(EC_BGP_ATTRIBUTE_REPEATED,
    3111             :                                  "Prefix SID SRv6 VPN field repeated");
    3112           0 :                         return bgp_attr_malformed(
    3113           0 :                                 args, BGP_NOTIFY_UPDATE_MAL_ATTR, args->total);
    3114             :                 }
    3115           0 :                 attr->srv6_vpn = XCALLOC(MTYPE_BGP_SRV6_VPN,
    3116             :                                          sizeof(struct bgp_attr_srv6_vpn));
    3117           0 :                 attr->srv6_vpn->sid_flags = sid_flags;
    3118           0 :                 sid_copy(&attr->srv6_vpn->sid, &ipv6_sid);
    3119           0 :                 attr->srv6_vpn = srv6_vpn_intern(attr->srv6_vpn);
    3120             :         }
    3121             : 
    3122             :         /* Placeholder code for the SRv6 L3 Service type */
    3123           0 :         else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE) {
    3124           0 :                 if (STREAM_READABLE(peer->curr) < length) {
    3125           0 :                         flog_err(
    3126             :                                 EC_BGP_ATTR_LEN,
    3127             :                                 "Prefix SID SRv6 L3-Service length is %hu, but only %zu bytes remain",
    3128             :                                 length, STREAM_READABLE(peer->curr));
    3129           0 :                         return bgp_attr_malformed(args,
    3130             :                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3131           0 :                                  args->total);
    3132             :                 }
    3133             : 
    3134             :                 /* ignore reserved */
    3135           0 :                 stream_getc(peer->curr);
    3136             : 
    3137           0 :                 return bgp_attr_srv6_service(args);
    3138             :         }
    3139             : 
    3140             :         /* Placeholder code for Unsupported TLV */
    3141             :         else {
    3142             : 
    3143           0 :                 if (STREAM_READABLE(peer->curr) < length) {
    3144           0 :                         flog_err(
    3145             :                                 EC_BGP_ATTR_LEN,
    3146             :                                 "Prefix SID SRv6 length is %hu - too long, only %zu remaining in this UPDATE",
    3147             :                                 length, STREAM_READABLE(peer->curr));
    3148           0 :                         return bgp_attr_malformed(
    3149             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3150           0 :                                 args->total);
    3151             :                 }
    3152             : 
    3153           0 :                 if (bgp_debug_update(peer, NULL, NULL, 1))
    3154           0 :                         zlog_debug(
    3155             :                                 "%s attr Prefix-SID sub-type=%u is not supported, skipped",
    3156             :                                 peer->host, type);
    3157             : 
    3158           0 :                 stream_forward_getp(peer->curr, length);
    3159             :         }
    3160             : 
    3161             :         return BGP_ATTR_PARSE_PROCEED;
    3162             : }
    3163             : 
    3164             : /* Prefix SID attribute
    3165             :  * draft-ietf-idr-bgp-prefix-sid-05
    3166             :  */
    3167           0 : enum bgp_attr_parse_ret bgp_attr_prefix_sid(struct bgp_attr_parser_args *args)
    3168             : {
    3169           0 :         struct peer *const peer = args->peer;
    3170           0 :         struct attr *const attr = args->attr;
    3171           0 :         enum bgp_attr_parse_ret ret;
    3172             : 
    3173           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID);
    3174             : 
    3175           0 :         uint8_t type;
    3176           0 :         uint16_t length;
    3177           0 :         size_t headersz = sizeof(type) + sizeof(length);
    3178           0 :         size_t psid_parsed_length = 0;
    3179             : 
    3180           0 :         while (STREAM_READABLE(peer->curr) > 0
    3181           0 :                && psid_parsed_length < args->length) {
    3182             : 
    3183           0 :                 if (STREAM_READABLE(peer->curr) < headersz) {
    3184           0 :                         flog_err(
    3185             :                                 EC_BGP_ATTR_LEN,
    3186             :                                 "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
    3187             :                                 headersz, STREAM_READABLE(peer->curr));
    3188           0 :                         return bgp_attr_malformed(
    3189             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3190           0 :                                 args->total);
    3191             :                 }
    3192             : 
    3193           0 :                 type = stream_getc(peer->curr);
    3194           0 :                 length = stream_getw(peer->curr);
    3195             : 
    3196           0 :                 if (STREAM_READABLE(peer->curr) < length) {
    3197           0 :                         flog_err(
    3198             :                                 EC_BGP_ATTR_LEN,
    3199             :                                 "Malformed Prefix SID attribute - insufficient data (need %hu for attribute body, have %zu remaining in UPDATE)",
    3200             :                                 length, STREAM_READABLE(peer->curr));
    3201           0 :                         return bgp_attr_malformed(args,
    3202             :                                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3203           0 :                                                   args->total);
    3204             :                 }
    3205             : 
    3206           0 :                 ret = bgp_attr_psid_sub(type, length, args);
    3207             : 
    3208           0 :                 if (ret != BGP_ATTR_PARSE_PROCEED)
    3209           0 :                         return ret;
    3210             : 
    3211           0 :                 psid_parsed_length += length + headersz;
    3212             : 
    3213           0 :                 if (psid_parsed_length > args->length) {
    3214           0 :                         flog_err(
    3215             :                                 EC_BGP_ATTR_LEN,
    3216             :                                 "Malformed Prefix SID attribute - TLV overflow by attribute (need %zu for TLV length, have %zu overflowed in UPDATE)",
    3217             :                                 length + headersz, psid_parsed_length - (length + headersz));
    3218           0 :                         return bgp_attr_malformed(
    3219             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3220           0 :                                 args->total);
    3221             :                 }
    3222             :         }
    3223             : 
    3224             :         return BGP_ATTR_PARSE_PROCEED;
    3225             : }
    3226             : 
    3227             : /* PMSI tunnel attribute (RFC 6514)
    3228             :  * Basic validation checks done here.
    3229             :  */
    3230             : static enum bgp_attr_parse_ret
    3231           0 : bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
    3232             : {
    3233           0 :         struct peer *const peer = args->peer;
    3234           0 :         struct attr *const attr = args->attr;
    3235           0 :         const bgp_size_t length = args->length;
    3236           0 :         uint8_t tnl_type;
    3237           0 :         int attr_parse_len = 2 + BGP_LABEL_BYTES;
    3238             : 
    3239             :         /* Verify that the receiver is expecting "ingress replication" as we
    3240             :          * can only support that.
    3241             :          */
    3242           0 :         if (length < attr_parse_len) {
    3243           0 :                 flog_err(EC_BGP_ATTR_LEN, "Bad PMSI tunnel attribute length %d",
    3244             :                          length);
    3245           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3246           0 :                                           args->total);
    3247             :         }
    3248           0 :         stream_getc(peer->curr); /* Flags */
    3249           0 :         tnl_type = stream_getc(peer->curr);
    3250           0 :         if (tnl_type > PMSI_TNLTYPE_MAX) {
    3251           0 :                 flog_err(EC_BGP_ATTR_PMSI_TYPE,
    3252             :                          "Invalid PMSI tunnel attribute type %d", tnl_type);
    3253           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
    3254           0 :                                           args->total);
    3255             :         }
    3256           0 :         if (tnl_type == PMSI_TNLTYPE_INGR_REPL) {
    3257           0 :                 if (length != 9) {
    3258           0 :                         flog_err(EC_BGP_ATTR_PMSI_LEN,
    3259             :                                  "Bad PMSI tunnel attribute length %d for IR",
    3260             :                                  length);
    3261           0 :                         return bgp_attr_malformed(
    3262             :                                 args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3263           0 :                                 args->total);
    3264             :                 }
    3265             :         }
    3266             : 
    3267           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
    3268           0 :         bgp_attr_set_pmsi_tnl_type(attr, tnl_type);
    3269           0 :         stream_get(&attr->label, peer->curr, BGP_LABEL_BYTES);
    3270             : 
    3271             :         /* Forward read pointer of input stream. */
    3272           0 :         stream_forward_getp(peer->curr, length - attr_parse_len);
    3273             : 
    3274           0 :         return BGP_ATTR_PARSE_PROCEED;
    3275             : }
    3276             : 
    3277             : /* AIGP attribute (rfc7311) */
    3278           0 : static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
    3279             : {
    3280           0 :         struct peer *const peer = args->peer;
    3281           0 :         struct attr *const attr = args->attr;
    3282           0 :         const bgp_size_t length = args->length;
    3283           0 :         uint8_t *s = stream_pnt(peer->curr);
    3284           0 :         uint64_t aigp = 0;
    3285             : 
    3286             :         /* If an AIGP attribute is received on a BGP session for which
    3287             :          * AIGP_SESSION is disabled, the attribute MUST be treated exactly
    3288             :          * as if it were an unrecognized non-transitive attribute.
    3289             :          * That is, it "MUST be quietly ignored and not passed along to
    3290             :          * other BGP peers".
    3291             :          * For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
    3292             :          * sessions between members of the same BGP Confederation,
    3293             :          * the default value of AIGP_SESSION SHOULD be "enabled".
    3294             :          */
    3295           0 :         if (peer->sort == BGP_PEER_EBGP &&
    3296           0 :             !CHECK_FLAG(peer->flags, PEER_FLAG_AIGP)) {
    3297           0 :                 zlog_warn(
    3298             :                         "%pBP received AIGP attribute, but eBGP peer do not support it",
    3299             :                         peer);
    3300           0 :                 goto aigp_ignore;
    3301             :         }
    3302             : 
    3303           0 :         if (peer->discard_attrs[args->type])
    3304           0 :                 goto aigp_ignore;
    3305             : 
    3306           0 :         if (!bgp_attr_aigp_valid(s, length))
    3307           0 :                 goto aigp_ignore;
    3308             : 
    3309             :         /* Extract AIGP Metric TLV */
    3310           0 :         if (bgp_attr_aigp_get_tlv_metric(s, length, &aigp))
    3311           0 :                 bgp_attr_set_aigp_metric(attr, aigp);
    3312             : 
    3313           0 : aigp_ignore:
    3314           0 :         stream_forward_getp(peer->curr, length);
    3315             : 
    3316           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    3317           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    3318             :                            lookup_msg(attr_str, args->type, NULL));
    3319             : 
    3320           0 :         return BGP_ATTR_PARSE_PROCEED;
    3321             : }
    3322             : 
    3323             : /* OTC attribute. */
    3324           0 : static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
    3325             : {
    3326           0 :         struct peer *const peer = args->peer;
    3327           0 :         struct attr *const attr = args->attr;
    3328           0 :         const bgp_size_t length = args->length;
    3329             : 
    3330             :         /* Length check. */
    3331           0 :         if (length != 4) {
    3332           0 :                 flog_err(EC_BGP_ATTR_LEN, "OTC attribute length isn't 4 [%u]",
    3333             :                          length);
    3334           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
    3335           0 :                                           args->total);
    3336             :         }
    3337             : 
    3338           0 :         if (peer->discard_attrs[args->type])
    3339           0 :                 goto otc_ignore;
    3340             : 
    3341           0 :         attr->otc = stream_getl(peer->curr);
    3342           0 :         if (!attr->otc) {
    3343           0 :                 flog_err(EC_BGP_ATTR_MAL_AS_PATH, "OTC attribute value is 0");
    3344           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
    3345           0 :                                           args->total);
    3346             :         }
    3347             : 
    3348           0 :         attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_OTC);
    3349             : 
    3350           0 :         return BGP_ATTR_PARSE_PROCEED;
    3351             : 
    3352           0 : otc_ignore:
    3353           0 :         stream_forward_getp(peer->curr, length);
    3354             : 
    3355           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    3356           0 :                 zlog_debug("%pBP: Ignoring attribute %s", peer,
    3357             :                            lookup_msg(attr_str, args->type, NULL));
    3358             : 
    3359             :         return BGP_ATTR_PARSE_PROCEED;
    3360             : }
    3361             : 
    3362             : /* BGP unknown attribute treatment. */
    3363             : static enum bgp_attr_parse_ret
    3364           0 : bgp_attr_unknown(struct bgp_attr_parser_args *args)
    3365             : {
    3366           0 :         bgp_size_t total = args->total;
    3367           0 :         struct transit *transit;
    3368           0 :         struct peer *const peer = args->peer;
    3369           0 :         struct attr *const attr = args->attr;
    3370           0 :         uint8_t *const startp = args->startp;
    3371           0 :         const uint8_t type = args->type;
    3372           0 :         const uint8_t flag = args->flags;
    3373           0 :         const bgp_size_t length = args->length;
    3374             : 
    3375           0 :         if (bgp_debug_update(peer, NULL, NULL, 1))
    3376           0 :                 zlog_debug(
    3377             :                         "%s Unknown attribute is received (type %d, length %d)",
    3378             :                         peer->host, type, length);
    3379             : 
    3380             :         /* Forward read pointer of input stream. */
    3381           0 :         stream_forward_getp(peer->curr, length);
    3382             : 
    3383           0 :         if (peer->discard_attrs[type]) {
    3384           0 :                 if (bgp_debug_update(peer, NULL, NULL, 1))
    3385           0 :                         zlog_debug("%pBP: Ignoring attribute %s", peer,
    3386             :                                    lookup_msg(attr_str, args->type, NULL));
    3387             : 
    3388           0 :                 return BGP_ATTR_PARSE_PROCEED;
    3389             :         }
    3390             : 
    3391             :         /* If any of the mandatory well-known attributes are not recognized,
    3392             :            then the Error Subcode is set to Unrecognized Well-known
    3393             :            Attribute.  The Data field contains the unrecognized attribute
    3394             :            (type, length and value). */
    3395           0 :         if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) {
    3396           0 :                 return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_UNREC_ATTR,
    3397           0 :                                           args->total);
    3398             :         }
    3399             : 
    3400             :         /* Unrecognized non-transitive optional attributes must be quietly
    3401             :            ignored and not passed along to other BGP peers. */
    3402           0 :         if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
    3403             :                 return BGP_ATTR_PARSE_PROCEED;
    3404             : 
    3405             :         /* If a path with recognized transitive optional attribute is
    3406             :            accepted and passed along to other BGP peers and the Partial bit
    3407             :            in the Attribute Flags octet is set to 1 by some previous AS, it
    3408             :            is not set back to 0 by the current AS. */
    3409           0 :         SET_FLAG(*startp, BGP_ATTR_FLAG_PARTIAL);
    3410             : 
    3411             :         /* Store transitive attribute to the end of attr->transit. */
    3412           0 :         transit = bgp_attr_get_transit(attr);
    3413           0 :         if (!transit)
    3414           0 :                 transit = XCALLOC(MTYPE_TRANSIT, sizeof(struct transit));
    3415             : 
    3416           0 :         transit->val = XREALLOC(MTYPE_TRANSIT_VAL, transit->val,
    3417             :                                 transit->length + total);
    3418             : 
    3419           0 :         memcpy(transit->val + transit->length, startp, total);
    3420           0 :         transit->length += total;
    3421           0 :         bgp_attr_set_transit(attr, transit);
    3422             : 
    3423           0 :         return BGP_ATTR_PARSE_PROCEED;
    3424             : }
    3425             : 
    3426             : /* Well-known attribute check. */
    3427           1 : static int bgp_attr_check(struct peer *peer, struct attr *attr)
    3428             : {
    3429           1 :         uint8_t type = 0;
    3430             : 
    3431             :         /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
    3432             :          * empty UPDATE.  */
    3433           1 :         if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
    3434             :                 return BGP_ATTR_PARSE_PROCEED;
    3435             : 
    3436             :         /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
    3437             :            to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
    3438             :            are present, it should.  Check for any other attribute being present
    3439             :            instead.
    3440             :          */
    3441           1 :         if ((!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)) &&
    3442             :              CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_UNREACH_NLRI))))
    3443             :                 return BGP_ATTR_PARSE_PROCEED;
    3444             : 
    3445           1 :         if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGIN)))
    3446           0 :                 type = BGP_ATTR_ORIGIN;
    3447             : 
    3448           1 :         if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
    3449           0 :                 type = BGP_ATTR_AS_PATH;
    3450             : 
    3451             :         /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present
    3452             :          * and
    3453             :          * NLRI is empty. We can't easily check NLRI empty here though.
    3454             :          */
    3455           1 :         if (!CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
    3456           1 :             && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI)))
    3457           0 :                 type = BGP_ATTR_NEXT_HOP;
    3458             : 
    3459           1 :         if (peer->sort == BGP_PEER_IBGP
    3460           0 :             && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)))
    3461             :                 type = BGP_ATTR_LOCAL_PREF;
    3462             : 
    3463             :         /* If any of the well-known mandatory attributes are not present
    3464             :          * in an UPDATE message, then "treat-as-withdraw" MUST be used.
    3465             :          */
    3466           1 :         if (type) {
    3467           0 :                 flog_warn(EC_BGP_MISSING_ATTRIBUTE,
    3468             :                           "%s Missing well-known attribute %s.", peer->host,
    3469             :                           lookup_msg(attr_str, type, NULL));
    3470           0 :                 return BGP_ATTR_PARSE_WITHDRAW;
    3471             :         }
    3472             :         return BGP_ATTR_PARSE_PROCEED;
    3473             : }
    3474             : 
    3475             : /* Read attribute of update packet.  This function is called from
    3476             :    bgp_update_receive() in bgp_packet.c.  */
    3477           1 : enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
    3478             :                                        bgp_size_t size,
    3479             :                                        struct bgp_nlri *mp_update,
    3480             :                                        struct bgp_nlri *mp_withdraw)
    3481             : {
    3482           1 :         enum bgp_attr_parse_ret ret;
    3483           1 :         uint8_t flag = 0;
    3484           1 :         uint8_t type = 0;
    3485           1 :         bgp_size_t length;
    3486           1 :         uint8_t *startp, *endp;
    3487           1 :         uint8_t *attr_endp;
    3488           1 :         uint8_t seen[BGP_ATTR_BITMAP_SIZE];
    3489             :         /* we need the as4_path only until we have synthesized the as_path with
    3490             :          * it */
    3491             :         /* same goes for as4_aggregator */
    3492           1 :         struct aspath *as4_path = NULL;
    3493           1 :         as_t as4_aggregator = 0;
    3494           1 :         struct in_addr as4_aggregator_addr = {.s_addr = 0};
    3495           1 :         struct transit *transit;
    3496             : 
    3497             :         /* Initialize bitmap. */
    3498           1 :         memset(seen, 0, BGP_ATTR_BITMAP_SIZE);
    3499             : 
    3500             :         /* End pointer of BGP attribute. */
    3501           1 :         endp = BGP_INPUT_PNT(peer) + size;
    3502             : 
    3503             :         /* Get attributes to the end of attribute length. */
    3504           4 :         while (BGP_INPUT_PNT(peer) < endp) {
    3505             :                 /* Check remaining length check.*/
    3506           3 :                 if (endp - BGP_INPUT_PNT(peer) < BGP_ATTR_MIN_LEN) {
    3507             :                         /* XXX warning: long int format, int arg (arg 5) */
    3508           0 :                         flog_warn(
    3509             :                                 EC_BGP_ATTRIBUTE_TOO_SMALL,
    3510             :                                 "%s: error BGP attribute length %lu is smaller than min len",
    3511             :                                 peer->host,
    3512             :                                 (unsigned long)(endp
    3513             :                                                 - stream_pnt(BGP_INPUT(peer))));
    3514             : 
    3515           0 :                         bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
    3516             :                                         BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
    3517           0 :                         ret = BGP_ATTR_PARSE_ERROR;
    3518           0 :                         goto done;
    3519             :                 }
    3520             : 
    3521             :                 /* Fetch attribute flag and type. */
    3522           3 :                 startp = BGP_INPUT_PNT(peer);
    3523             :                 /* "The lower-order four bits of the Attribute Flags octet are
    3524             :                    unused.  They MUST be zero when sent and MUST be ignored when
    3525             :                    received." */
    3526           3 :                 flag = 0xF0 & stream_getc(BGP_INPUT(peer));
    3527           3 :                 type = stream_getc(BGP_INPUT(peer));
    3528             : 
    3529             :                 /* Check whether Extended-Length applies and is in bounds */
    3530           3 :                 if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN)
    3531           0 :                     && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1))) {
    3532           0 :                         flog_warn(
    3533             :                                 EC_BGP_EXT_ATTRIBUTE_TOO_SMALL,
    3534             :                                 "%s: Extended length set, but just %lu bytes of attr header",
    3535             :                                 peer->host,
    3536             :                                 (unsigned long)(endp
    3537             :                                                 - stream_pnt(BGP_INPUT(peer))));
    3538             : 
    3539           0 :                         bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
    3540             :                                         BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
    3541           0 :                         ret = BGP_ATTR_PARSE_ERROR;
    3542           0 :                         goto done;
    3543             :                 }
    3544             : 
    3545             :                 /* Check extended attribue length bit. */
    3546           3 :                 if (CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN))
    3547           0 :                         length = stream_getw(BGP_INPUT(peer));
    3548             :                 else
    3549           3 :                         length = stream_getc(BGP_INPUT(peer));
    3550             : 
    3551             :                 /* If any attribute appears more than once in the UPDATE
    3552             :                    message, then the Error Subcode is set to Malformed Attribute
    3553             :                    List. */
    3554             : 
    3555           3 :                 if (CHECK_BITMAP(seen, type)) {
    3556           0 :                         flog_warn(
    3557             :                                 EC_BGP_ATTRIBUTE_REPEATED,
    3558             :                                 "%s: error BGP attribute type %d appears twice in a message",
    3559             :                                 peer->host, type);
    3560             : 
    3561           0 :                         bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
    3562             :                                         BGP_NOTIFY_UPDATE_MAL_ATTR);
    3563           0 :                         ret = BGP_ATTR_PARSE_ERROR;
    3564           0 :                         goto done;
    3565             :                 }
    3566             : 
    3567             :                 /* Set type to bitmap to check duplicate attribute.  `type' is
    3568             :                    unsigned char so it never overflow bitmap range. */
    3569             : 
    3570           3 :                 SET_BITMAP(seen, type);
    3571             : 
    3572             :                 /* Overflow check. */
    3573           3 :                 attr_endp = BGP_INPUT_PNT(peer) + length;
    3574             : 
    3575           3 :                 if (attr_endp > endp) {
    3576           0 :                         flog_warn(
    3577             :                                 EC_BGP_ATTRIBUTE_TOO_LARGE,
    3578             :                                 "%s: BGP type %d length %d is too large, attribute total length is %d.  attr_endp is %p.  endp is %p",
    3579             :                                 peer->host, type, length, size, attr_endp,
    3580             :                                 endp);
    3581             :                         /*
    3582             :                          * RFC 4271 6.3
    3583             :                          * If any recognized attribute has an Attribute
    3584             :                          * Length that conflicts with the expected length
    3585             :                          * (based on the attribute type code), then the
    3586             :                          * Error Subcode MUST be set to Attribute Length
    3587             :                          * Error.  The Data field MUST contain the erroneous
    3588             :                          * attribute (type, length, and value).
    3589             :                          * ----------
    3590             :                          * We do not currently have a good way to determine the
    3591             :                          * length of the attribute independent of the length
    3592             :                          * received in the message. Instead we send the
    3593             :                          * minimum between the amount of data we have and the
    3594             :                          * amount specified by the attribute length field.
    3595             :                          *
    3596             :                          * Instead of directly passing in the packet buffer and
    3597             :                          * offset we use the stream_get* functions to read into
    3598             :                          * a stack buffer, since they perform bounds checking
    3599             :                          * and we are working with untrusted data.
    3600             :                          */
    3601           0 :                         unsigned char ndata[peer->max_packet_size];
    3602           0 :                         memset(ndata, 0x00, sizeof(ndata));
    3603           0 :                         size_t lfl =
    3604           0 :                                 CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1;
    3605             :                         /* Rewind to end of flag field */
    3606           0 :                         stream_rewind_getp(BGP_INPUT(peer), (1 + lfl));
    3607             :                         /* Type */
    3608           0 :                         stream_get(&ndata[0], BGP_INPUT(peer), 1);
    3609             :                         /* Length */
    3610           0 :                         stream_get(&ndata[1], BGP_INPUT(peer), lfl);
    3611             :                         /* Value */
    3612           0 :                         size_t atl = attr_endp - startp;
    3613           0 :                         size_t ndl = MIN(atl, STREAM_READABLE(BGP_INPUT(peer)));
    3614           0 :                         stream_get(&ndata[lfl + 1], BGP_INPUT(peer), ndl);
    3615             : 
    3616           0 :                         bgp_notify_send_with_data(
    3617             :                                 peer, BGP_NOTIFY_UPDATE_ERR,
    3618             :                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata,
    3619           0 :                                 ndl + lfl + 1);
    3620             : 
    3621           0 :                         ret = BGP_ATTR_PARSE_ERROR;
    3622           0 :                         goto done;
    3623             :                 }
    3624             : 
    3625           3 :                 struct bgp_attr_parser_args attr_args = {
    3626             :                         .peer = peer,
    3627             :                         .length = length,
    3628             :                         .attr = attr,
    3629             :                         .type = type,
    3630             :                         .flags = flag,
    3631             :                         .startp = startp,
    3632           3 :                         .total = attr_endp - startp,
    3633             :                 };
    3634             : 
    3635             : 
    3636             :                 /* If any recognized attribute has Attribute Flags that conflict
    3637             :                    with the Attribute Type Code, then the Error Subcode is set
    3638             :                    to
    3639             :                    Attribute Flags Error.  The Data field contains the erroneous
    3640             :                    attribute (type, length and value). */
    3641           3 :                 if (bgp_attr_flag_invalid(&attr_args)) {
    3642           0 :                         ret = bgp_attr_malformed(
    3643             :                                 &attr_args, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
    3644             :                                 attr_args.total);
    3645           0 :                         if (ret == BGP_ATTR_PARSE_PROCEED)
    3646           0 :                                 continue;
    3647           0 :                         goto done;
    3648             :                 }
    3649             : 
    3650             :                 /* OK check attribute and store it's value. */
    3651           3 :                 switch (type) {
    3652           1 :                 case BGP_ATTR_ORIGIN:
    3653           1 :                         ret = bgp_attr_origin(&attr_args);
    3654           1 :                         break;
    3655           1 :                 case BGP_ATTR_AS_PATH:
    3656           1 :                         ret = bgp_attr_aspath(&attr_args);
    3657           1 :                         break;
    3658           0 :                 case BGP_ATTR_AS4_PATH:
    3659           0 :                         ret = bgp_attr_as4_path(&attr_args, &as4_path);
    3660           0 :                         break;
    3661           1 :                 case BGP_ATTR_NEXT_HOP:
    3662           1 :                         ret = bgp_attr_nexthop(&attr_args);
    3663           1 :                         break;
    3664           0 :                 case BGP_ATTR_MULTI_EXIT_DISC:
    3665           0 :                         ret = bgp_attr_med(&attr_args);
    3666           0 :                         break;
    3667           0 :                 case BGP_ATTR_LOCAL_PREF:
    3668           0 :                         ret = bgp_attr_local_pref(&attr_args);
    3669           0 :                         break;
    3670           0 :                 case BGP_ATTR_ATOMIC_AGGREGATE:
    3671           0 :                         ret = bgp_attr_atomic(&attr_args);
    3672           0 :                         break;
    3673           0 :                 case BGP_ATTR_AGGREGATOR:
    3674           0 :                         ret = bgp_attr_aggregator(&attr_args);
    3675           0 :                         break;
    3676           0 :                 case BGP_ATTR_AS4_AGGREGATOR:
    3677           0 :                         ret = bgp_attr_as4_aggregator(&attr_args,
    3678             :                                                       &as4_aggregator,
    3679             :                                                       &as4_aggregator_addr);
    3680           0 :                         break;
    3681           0 :                 case BGP_ATTR_COMMUNITIES:
    3682           0 :                         ret = bgp_attr_community(&attr_args);
    3683           0 :                         break;
    3684           0 :                 case BGP_ATTR_LARGE_COMMUNITIES:
    3685           0 :                         ret = bgp_attr_large_community(&attr_args);
    3686           0 :                         break;
    3687           0 :                 case BGP_ATTR_ORIGINATOR_ID:
    3688           0 :                         ret = bgp_attr_originator_id(&attr_args);
    3689           0 :                         break;
    3690           0 :                 case BGP_ATTR_CLUSTER_LIST:
    3691           0 :                         ret = bgp_attr_cluster_list(&attr_args);
    3692           0 :                         break;
    3693           0 :                 case BGP_ATTR_MP_REACH_NLRI:
    3694           0 :                         ret = bgp_mp_reach_parse(&attr_args, mp_update);
    3695           0 :                         break;
    3696           0 :                 case BGP_ATTR_MP_UNREACH_NLRI:
    3697           0 :                         ret = bgp_mp_unreach_parse(&attr_args, mp_withdraw);
    3698           0 :                         break;
    3699           0 :                 case BGP_ATTR_EXT_COMMUNITIES:
    3700           0 :                         ret = bgp_attr_ext_communities(&attr_args);
    3701           0 :                         break;
    3702             : #ifdef ENABLE_BGP_VNC_ATTR
    3703             :                 case BGP_ATTR_VNC:
    3704             : #endif
    3705           0 :                 case BGP_ATTR_ENCAP:
    3706           0 :                         ret = bgp_attr_encap(type, peer, length, attr, flag,
    3707             :                                              startp);
    3708           0 :                         break;
    3709           0 :                 case BGP_ATTR_PREFIX_SID:
    3710           0 :                         ret = bgp_attr_prefix_sid(&attr_args);
    3711           0 :                         break;
    3712           0 :                 case BGP_ATTR_PMSI_TUNNEL:
    3713           0 :                         ret = bgp_attr_pmsi_tunnel(&attr_args);
    3714           0 :                         break;
    3715           0 :                 case BGP_ATTR_IPV6_EXT_COMMUNITIES:
    3716           0 :                         ret = bgp_attr_ipv6_ext_communities(&attr_args);
    3717           0 :                         break;
    3718           0 :                 case BGP_ATTR_OTC:
    3719           0 :                         ret = bgp_attr_otc(&attr_args);
    3720           0 :                         break;
    3721           0 :                 case BGP_ATTR_AIGP:
    3722           0 :                         ret = bgp_attr_aigp(&attr_args);
    3723           0 :                         break;
    3724           0 :                 default:
    3725           0 :                         ret = bgp_attr_unknown(&attr_args);
    3726           0 :                         break;
    3727             :                 }
    3728             : 
    3729           3 :                 if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS) {
    3730           0 :                         bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
    3731             :                                         BGP_NOTIFY_UPDATE_MAL_ATTR);
    3732           0 :                         ret = BGP_ATTR_PARSE_ERROR;
    3733           0 :                         goto done;
    3734             :                 }
    3735             : 
    3736           3 :                 if (ret == BGP_ATTR_PARSE_EOR) {
    3737           0 :                         goto done;
    3738             :                 }
    3739             : 
    3740           3 :                 if (ret == BGP_ATTR_PARSE_ERROR) {
    3741           0 :                         flog_warn(EC_BGP_ATTRIBUTE_PARSE_ERROR,
    3742             :                                   "%s: Attribute %s, parse error", peer->host,
    3743             :                                   lookup_msg(attr_str, type, NULL));
    3744           0 :                         goto done;
    3745             :                 }
    3746           3 :                 if (ret == BGP_ATTR_PARSE_WITHDRAW) {
    3747           0 :                         flog_warn(
    3748             :                                 EC_BGP_ATTRIBUTE_PARSE_WITHDRAW,
    3749             :                                 "%s: Attribute %s, parse error - treating as withdrawal",
    3750             :                                 peer->host, lookup_msg(attr_str, type, NULL));
    3751           0 :                         goto done;
    3752             :                 }
    3753             : 
    3754             :                 /* Check the fetched length. */
    3755           3 :                 if (BGP_INPUT_PNT(peer) != attr_endp) {
    3756           0 :                         flog_warn(EC_BGP_ATTRIBUTE_FETCH_ERROR,
    3757             :                                   "%s: BGP attribute %s, fetch error",
    3758             :                                   peer->host, lookup_msg(attr_str, type, NULL));
    3759           0 :                         bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
    3760             :                                         BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
    3761           0 :                         ret = BGP_ATTR_PARSE_ERROR;
    3762           0 :                         goto done;
    3763             :                 }
    3764             :         }
    3765             : 
    3766             :         /*
    3767             :          * draft-ietf-idr-bgp-prefix-sid-27#section-3:
    3768             :          * About Prefix-SID path attribute,
    3769             :          * Label-Index TLV(type1) and The Originator SRGB TLV(type-3)
    3770             :          * may only appear in a BGP Prefix-SID attribute attached to
    3771             :          * IPv4/IPv6 Labeled Unicast prefixes ([RFC8277]).
    3772             :          * It MUST be ignored when received for other BGP AFI/SAFI combinations.
    3773             :          */
    3774           1 :         if (!attr->mp_nexthop_len || mp_update->safi != SAFI_LABELED_UNICAST)
    3775           1 :                 attr->label_index = BGP_INVALID_LABEL_INDEX;
    3776             : 
    3777             :         /* Check final read pointer is same as end pointer. */
    3778           1 :         if (BGP_INPUT_PNT(peer) != endp) {
    3779           0 :                 flog_warn(EC_BGP_ATTRIBUTES_MISMATCH,
    3780             :                           "%s: BGP attribute %s, length mismatch", peer->host,
    3781             :                           lookup_msg(attr_str, type, NULL));
    3782           0 :                 bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
    3783             :                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
    3784             : 
    3785           0 :                 ret = BGP_ATTR_PARSE_ERROR;
    3786           0 :                 goto done;
    3787             :         }
    3788             : 
    3789             :         /*
    3790             :          * RFC4271: If the NEXT_HOP attribute field is syntactically incorrect,
    3791             :          * then the Error Subcode MUST be set to Invalid NEXT_HOP Attribute.
    3792             :          * This is implemented below and will result in a NOTIFICATION. If the
    3793             :          * NEXT_HOP attribute is semantically incorrect, the error SHOULD be
    3794             :          * logged, and the route SHOULD be ignored. In this case, a NOTIFICATION
    3795             :          * message SHOULD NOT be sent. This is implemented elsewhere.
    3796             :          *
    3797             :          * RFC4760: An UPDATE message that carries no NLRI, other than the one
    3798             :          * encoded in the MP_REACH_NLRI attribute, SHOULD NOT carry the NEXT_HOP
    3799             :          * attribute. If such a message contains the NEXT_HOP attribute, the BGP
    3800             :          * speaker that receives the message SHOULD ignore this attribute.
    3801             :          */
    3802           1 :         if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))
    3803           1 :             && !CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MP_REACH_NLRI))) {
    3804           1 :                 if (bgp_attr_nexthop_valid(peer, attr) < 0) {
    3805           0 :                         ret = BGP_ATTR_PARSE_ERROR;
    3806           0 :                         goto done;
    3807             :                 }
    3808             :         }
    3809             : 
    3810             :         /* Check all mandatory well-known attributes are present */
    3811           1 :         ret = bgp_attr_check(peer, attr);
    3812           1 :         if (ret < 0)
    3813           0 :                 goto done;
    3814             : 
    3815             :         /*
    3816             :          * At this place we can see whether we got AS4_PATH and/or
    3817             :          * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
    3818             :          * We can not do this before we've read all attributes because
    3819             :          * the as4 handling does not say whether AS4_PATH has to be sent
    3820             :          * after AS_PATH or not - and when AS4_AGGREGATOR will be send
    3821             :          * in relationship to AGGREGATOR.
    3822             :          * So, to be defensive, we are not relying on any order and read
    3823             :          * all attributes first, including these 32bit ones, and now,
    3824             :          * afterwards, we look what and if something is to be done for as4.
    3825             :          *
    3826             :          * It is possible to not have AS_PATH, e.g. GR EoR and sole
    3827             :          * MP_UNREACH_NLRI.
    3828             :          */
    3829             :         /* actually... this doesn't ever return failure currently, but
    3830             :          * better safe than sorry */
    3831           1 :         if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))
    3832           1 :             && bgp_attr_munge_as4_attrs(peer, attr, as4_path, as4_aggregator,
    3833             :                                         &as4_aggregator_addr)) {
    3834           0 :                 bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
    3835             :                                 BGP_NOTIFY_UPDATE_MAL_ATTR);
    3836           0 :                 ret = BGP_ATTR_PARSE_ERROR;
    3837           0 :                 goto done;
    3838             :         }
    3839             : 
    3840             :         /*
    3841             :          * Finally do the checks on the aspath we did not do yet
    3842             :          * because we waited for a potentially synthesized aspath.
    3843             :          */
    3844           1 :         if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH))) {
    3845           1 :                 ret = bgp_attr_aspath_check(peer, attr);
    3846           1 :                 if (ret != BGP_ATTR_PARSE_PROCEED)
    3847           0 :                         goto done;
    3848             :         }
    3849             : 
    3850             :         ret = BGP_ATTR_PARSE_PROCEED;
    3851           1 : done:
    3852             : 
    3853             :         /*
    3854             :          * At this stage, we have done all fiddling with as4, and the
    3855             :          * resulting info is in attr->aggregator resp. attr->aspath so
    3856             :          * we can chuck as4_aggregator and as4_path alltogether in order
    3857             :          * to save memory
    3858             :          */
    3859             :         /*
    3860             :          * unintern - it is in the hash
    3861             :          * The flag that we got this is still there, but that
    3862             :          * does not do any trouble
    3863             :          */
    3864           1 :         aspath_unintern(&as4_path);
    3865             : 
    3866           1 :         transit = bgp_attr_get_transit(attr);
    3867           1 :         if (ret != BGP_ATTR_PARSE_ERROR) {
    3868             :                 /* Finally intern unknown attribute. */
    3869           1 :                 if (transit)
    3870           0 :                         bgp_attr_set_transit(attr, transit_intern(transit));
    3871           1 :                 if (attr->encap_subtlvs)
    3872           0 :                         attr->encap_subtlvs = encap_intern(attr->encap_subtlvs,
    3873             :                                                            ENCAP_SUBTLV_TYPE);
    3874             : #ifdef ENABLE_BGP_VNC
    3875           1 :                 struct bgp_attr_encap_subtlv *vnc_subtlvs =
    3876           1 :                         bgp_attr_get_vnc_subtlvs(attr);
    3877             : 
    3878           1 :                 if (vnc_subtlvs)
    3879           0 :                         bgp_attr_set_vnc_subtlvs(
    3880             :                                 attr,
    3881             :                                 encap_intern(vnc_subtlvs, VNC_SUBTLV_TYPE));
    3882             : #endif
    3883             :         } else {
    3884           0 :                 if (transit) {
    3885           0 :                         transit_free(transit);
    3886           0 :                         bgp_attr_set_transit(attr, NULL);
    3887             :                 }
    3888             : 
    3889           0 :                 bgp_attr_flush_encap(attr);
    3890           1 :         };
    3891             : 
    3892             :         /* Sanity checks */
    3893           1 :         transit = bgp_attr_get_transit(attr);
    3894           1 :         if (transit)
    3895           0 :                 assert(transit->refcnt > 0);
    3896           1 :         if (attr->encap_subtlvs)
    3897           0 :                 assert(attr->encap_subtlvs->refcnt > 0);
    3898             : #ifdef ENABLE_BGP_VNC
    3899           1 :         struct bgp_attr_encap_subtlv *vnc_subtlvs =
    3900           1 :                 bgp_attr_get_vnc_subtlvs(attr);
    3901             : 
    3902           1 :         if (vnc_subtlvs)
    3903           0 :                 assert(vnc_subtlvs->refcnt > 0);
    3904             : #endif
    3905             : 
    3906           1 :         return ret;
    3907             : }
    3908             : 
    3909             : /*
    3910             :  * Extract the tunnel type from extended community
    3911             :  */
    3912           0 : void bgp_attr_extcom_tunnel_type(struct attr *attr,
    3913             :                                  bgp_encap_types *tunnel_type)
    3914             : {
    3915           0 :         struct ecommunity *ecom;
    3916           0 :         uint32_t i;
    3917             : 
    3918           0 :         if (!attr)
    3919             :                 return;
    3920             : 
    3921           0 :         ecom = bgp_attr_get_ecommunity(attr);
    3922           0 :         if (!ecom || !ecom->size)
    3923             :                 return;
    3924             : 
    3925           0 :         for (i = 0; i < ecom->size; i++) {
    3926           0 :                 uint8_t *pnt;
    3927           0 :                 uint8_t type, sub_type;
    3928             : 
    3929           0 :                 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
    3930           0 :                 type = pnt[0];
    3931           0 :                 sub_type = pnt[1];
    3932           0 :                 if (!(type == ECOMMUNITY_ENCODE_OPAQUE &&
    3933           0 :                       sub_type == ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP))
    3934           0 :                         continue;
    3935           0 :                 *tunnel_type = ((pnt[6] << 8) | pnt[7]);
    3936           0 :                 return;
    3937             :         }
    3938             : 
    3939             :         return;
    3940             : }
    3941             : 
    3942           0 : size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
    3943             :                                safi_t safi, struct bpacket_attr_vec_arr *vecarr,
    3944             :                                struct attr *attr)
    3945             : {
    3946           0 :         size_t sizep;
    3947           0 :         iana_afi_t pkt_afi = IANA_AFI_IPV4;
    3948           0 :         iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
    3949           0 :         afi_t nh_afi;
    3950             : 
    3951             :         /* Set extended bit always to encode the attribute length as 2 bytes */
    3952           0 :         stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
    3953           0 :         stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
    3954           0 :         sizep = stream_get_endp(s);
    3955           0 :         stream_putw(s, 0); /* Marker: Attribute length. */
    3956             : 
    3957             : 
    3958             :         /* Convert AFI, SAFI to values for packet. */
    3959           0 :         bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
    3960             : 
    3961           0 :         stream_putw(s, pkt_afi);  /* AFI */
    3962           0 :         stream_putc(s, pkt_safi); /* SAFI */
    3963             : 
    3964             :         /* Nexthop AFI */
    3965           0 :         if (afi == AFI_IP
    3966           0 :             && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST
    3967           0 :                 || safi == SAFI_MPLS_VPN || safi == SAFI_MULTICAST))
    3968           0 :                 nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
    3969           0 :         else if (safi == SAFI_FLOWSPEC)
    3970             :                 nh_afi = afi;
    3971             :         else
    3972           0 :                 nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
    3973             : 
    3974             :         /* Nexthop */
    3975           0 :         bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s, attr);
    3976           0 :         switch (nh_afi) {
    3977           0 :         case AFI_IP:
    3978           0 :                 switch (safi) {
    3979           0 :                 case SAFI_UNICAST:
    3980             :                 case SAFI_MULTICAST:
    3981             :                 case SAFI_LABELED_UNICAST:
    3982           0 :                         stream_putc(s, 4);
    3983           0 :                         stream_put_ipv4(s, attr->nexthop.s_addr);
    3984           0 :                         break;
    3985           0 :                 case SAFI_MPLS_VPN:
    3986           0 :                         stream_putc(s, 12);
    3987           0 :                         stream_putl(s, 0); /* RD = 0, per RFC */
    3988           0 :                         stream_putl(s, 0);
    3989           0 :                         stream_put(s, &attr->mp_nexthop_global_in, 4);
    3990           0 :                         break;
    3991           0 :                 case SAFI_ENCAP:
    3992             :                 case SAFI_EVPN:
    3993           0 :                         stream_putc(s, 4);
    3994           0 :                         stream_put(s, &attr->mp_nexthop_global_in, 4);
    3995           0 :                         break;
    3996           0 :                 case SAFI_FLOWSPEC:
    3997           0 :                         if (attr->mp_nexthop_len == 0)
    3998           0 :                                 stream_putc(s, 0); /* no nexthop for flowspec */
    3999             :                         else {
    4000           0 :                                 stream_putc(s, attr->mp_nexthop_len);
    4001           0 :                                 stream_put_ipv4(s, attr->nexthop.s_addr);
    4002             :                         }
    4003             :                         break;
    4004             :                 case SAFI_UNSPEC:
    4005             :                 case SAFI_MAX:
    4006           0 :                         assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
    4007             :                         break;
    4008             :                 }
    4009             :                 break;
    4010           0 :         case AFI_IP6:
    4011           0 :                 switch (safi) {
    4012           0 :                 case SAFI_UNICAST:
    4013             :                 case SAFI_MULTICAST:
    4014             :                 case SAFI_LABELED_UNICAST:
    4015             :                 case SAFI_EVPN: {
    4016           0 :                         if (attr->mp_nexthop_len
    4017             :                             == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) {
    4018           0 :                                 stream_putc(s,
    4019             :                                             BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL);
    4020           0 :                                 stream_put(s, &attr->mp_nexthop_global,
    4021             :                                            IPV6_MAX_BYTELEN);
    4022           0 :                                 stream_put(s, &attr->mp_nexthop_local,
    4023             :                                            IPV6_MAX_BYTELEN);
    4024             :                         } else {
    4025           0 :                                 stream_putc(s, IPV6_MAX_BYTELEN);
    4026           0 :                                 stream_put(s, &attr->mp_nexthop_global,
    4027             :                                            IPV6_MAX_BYTELEN);
    4028             :                         }
    4029             :                 } break;
    4030           0 :                 case SAFI_MPLS_VPN: {
    4031           0 :                         if (attr->mp_nexthop_len ==
    4032             :                             BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
    4033           0 :                                 stream_putc(s, 48);
    4034           0 :                                 stream_putl(s, 0); /* RD = 0, per RFC */
    4035           0 :                                 stream_putl(s, 0);
    4036           0 :                                 stream_put(s, &attr->mp_nexthop_global,
    4037             :                                            IPV6_MAX_BYTELEN);
    4038           0 :                                 stream_putl(s, 0); /* RD = 0, per RFC */
    4039           0 :                                 stream_putl(s, 0);
    4040           0 :                                 stream_put(s, &attr->mp_nexthop_local,
    4041             :                                            IPV6_MAX_BYTELEN);
    4042             :                         } else {
    4043           0 :                                 stream_putc(s, 24);
    4044           0 :                                 stream_putl(s, 0); /* RD = 0, per RFC */
    4045           0 :                                 stream_putl(s, 0);
    4046           0 :                                 stream_put(s, &attr->mp_nexthop_global,
    4047             :                                            IPV6_MAX_BYTELEN);
    4048             :                         }
    4049             :                 } break;
    4050           0 :                 case SAFI_ENCAP:
    4051           0 :                         stream_putc(s, IPV6_MAX_BYTELEN);
    4052           0 :                         stream_put(s, &attr->mp_nexthop_global,
    4053             :                                    IPV6_MAX_BYTELEN);
    4054           0 :                         break;
    4055           0 :                 case SAFI_FLOWSPEC:
    4056           0 :                         stream_putc(s, 0); /* no nexthop for flowspec */
    4057           0 :                         break;
    4058             :                 case SAFI_UNSPEC:
    4059             :                 case SAFI_MAX:
    4060           0 :                         assert(!"SAFI's UNSPEC or MAX being specified are a DEV ESCAPE");
    4061             :                         break;
    4062             :                 }
    4063             :                 break;
    4064           0 :         case AFI_L2VPN:
    4065           0 :                 if (safi != SAFI_FLOWSPEC)
    4066           0 :                         flog_err(
    4067             :                                 EC_BGP_ATTR_NH_SEND_LEN,
    4068             :                                 "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
    4069             :                                 peer->host, afi, safi, attr->mp_nexthop_len);
    4070             :                 break;
    4071             :         case AFI_UNSPEC:
    4072             :         case AFI_MAX:
    4073           0 :                 assert(!"DEV ESCAPE: AFI_UNSPEC or AFI_MAX should not be used here");
    4074             :                 break;
    4075             :         }
    4076             : 
    4077             :         /* SNPA */
    4078           0 :         stream_putc(s, 0);
    4079           0 :         return sizep;
    4080             : }
    4081             : 
    4082           0 : void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
    4083             :                               const struct prefix *p,
    4084             :                               const struct prefix_rd *prd, mpls_label_t *label,
    4085             :                               uint32_t num_labels, bool addpath_capable,
    4086             :                               uint32_t addpath_tx_id, struct attr *attr)
    4087             : {
    4088           0 :         switch (safi) {
    4089             :         case SAFI_UNSPEC:
    4090             :         case SAFI_MAX:
    4091           0 :                 assert(!"Dev escape usage of SAFI_UNSPEC or MAX");
    4092             :                 break;
    4093           0 :         case SAFI_MPLS_VPN:
    4094           0 :                 if (addpath_capable)
    4095           0 :                         stream_putl(s, addpath_tx_id);
    4096             :                 /* Label, RD, Prefix write. */
    4097           0 :                 stream_putc(s, p->prefixlen + 88);
    4098           0 :                 stream_put(s, label, BGP_LABEL_BYTES);
    4099           0 :                 stream_put(s, prd->val, 8);
    4100           0 :                 stream_put(s, &p->u.prefix, PSIZE(p->prefixlen));
    4101           0 :                 break;
    4102           0 :         case SAFI_EVPN:
    4103           0 :                 if (afi == AFI_L2VPN)
    4104             :                         /* EVPN prefix - contents depend on type */
    4105           0 :                         bgp_evpn_encode_prefix(s, p, prd, label, num_labels,
    4106             :                                                attr, addpath_capable,
    4107             :                                                addpath_tx_id);
    4108             :                 else
    4109           0 :                         assert(!"Add encoding bits here for other AFI's");
    4110           0 :                 break;
    4111           0 :         case SAFI_LABELED_UNICAST:
    4112             :                 /* Prefix write with label. */
    4113           0 :                 stream_put_labeled_prefix(s, p, label, addpath_capable,
    4114             :                                           addpath_tx_id);
    4115           0 :                 break;
    4116           0 :         case SAFI_FLOWSPEC:
    4117           0 :                 stream_putc(s, p->u.prefix_flowspec.prefixlen);
    4118           0 :                 stream_put(s, (const void *)p->u.prefix_flowspec.ptr,
    4119           0 :                            p->u.prefix_flowspec.prefixlen);
    4120           0 :                 break;
    4121             : 
    4122           0 :         case SAFI_UNICAST:
    4123             :         case SAFI_MULTICAST:
    4124           0 :                 stream_put_prefix_addpath(s, p, addpath_capable, addpath_tx_id);
    4125           0 :                 break;
    4126             :         case SAFI_ENCAP:
    4127           0 :                 assert(!"Please add proper encoding of SAFI_ENCAP");
    4128             :                 break;
    4129             :         }
    4130           0 : }
    4131             : 
    4132           0 : size_t bgp_packet_mpattr_prefix_size(afi_t afi, safi_t safi,
    4133             :                                      const struct prefix *p)
    4134             : {
    4135           0 :         int size = PSIZE(p->prefixlen);
    4136             : 
    4137           0 :         switch (safi) {
    4138             :         case SAFI_UNSPEC:
    4139             :         case SAFI_MAX:
    4140           0 :                 assert(!"Attempting to figure size for a SAFI_UNSPEC/SAFI_MAX this is a DEV ESCAPE");
    4141             :                 break;
    4142             :         case SAFI_UNICAST:
    4143             :         case SAFI_MULTICAST:
    4144             :                 break;
    4145           0 :         case SAFI_MPLS_VPN:
    4146           0 :                 size += 88;
    4147           0 :                 break;
    4148             :         case SAFI_ENCAP:
    4149             :                 /* This has to be wrong, but I don't know what to put here */
    4150           0 :                 assert(!"Do we try to use this?");
    4151             :                 break;
    4152           0 :         case SAFI_LABELED_UNICAST:
    4153           0 :                 size += BGP_LABEL_BYTES;
    4154           0 :                 break;
    4155           0 :         case SAFI_EVPN:
    4156             :                 /*
    4157             :                  * TODO: Maximum possible for type-2, type-3 and type-5
    4158             :                  */
    4159           0 :                 if (afi == AFI_L2VPN)
    4160           0 :                         size += 232;
    4161             :                 else
    4162           0 :                         assert(!"Attempting to figure size for SAFI_EVPN and !AFI_L2VPN and FRR will not have the proper values");
    4163           0 :                 break;
    4164           0 :         case SAFI_FLOWSPEC:
    4165           0 :                 size = ((struct prefix_fs *)p)->prefix.prefixlen;
    4166           0 :                 break;
    4167             :         }
    4168             : 
    4169           0 :         return size;
    4170             : }
    4171             : 
    4172             : /*
    4173             :  * Encodes the tunnel encapsulation attribute,
    4174             :  * and with ENABLE_BGP_VNC the VNC attribute which uses
    4175             :  * almost the same TLV format
    4176             :  */
    4177           0 : static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
    4178             :                                   struct stream *s, struct attr *attr,
    4179             :                                   uint8_t attrtype)
    4180             : {
    4181           0 :         unsigned int attrlenfield = 0;
    4182           0 :         unsigned int attrhdrlen = 0;
    4183           0 :         struct bgp_attr_encap_subtlv *subtlvs;
    4184           0 :         struct bgp_attr_encap_subtlv *st;
    4185           0 :         const char *attrname;
    4186             : 
    4187           0 :         if (!attr || (attrtype == BGP_ATTR_ENCAP
    4188           0 :                       && (!attr->encap_tunneltype
    4189           0 :                           || attr->encap_tunneltype == BGP_ENCAP_TYPE_MPLS)))
    4190             :                 return;
    4191             : 
    4192           0 :         switch (attrtype) {
    4193             :         case BGP_ATTR_ENCAP:
    4194           0 :                 attrname = "Tunnel Encap";
    4195           0 :                 subtlvs = attr->encap_subtlvs;
    4196           0 :                 if (subtlvs == NULL) /* nothing to do */
    4197             :                         return;
    4198             :                 /*
    4199             :                  * The tunnel encap attr has an "outer" tlv.
    4200             :                  * T = tunneltype,
    4201             :                  * L = total length of subtlvs,
    4202             :                  * V = concatenated subtlvs.
    4203             :                  */
    4204             :                 attrlenfield = 2 + 2; /* T + L */
    4205           0 :                 attrhdrlen = 1 + 1;   /* subTLV T + L */
    4206             :                 break;
    4207             : 
    4208             : #ifdef ENABLE_BGP_VNC_ATTR
    4209             :         case BGP_ATTR_VNC:
    4210             :                 attrname = "VNC";
    4211             :                 subtlvs = bgp_attr_get_vnc_subtlvs(attr);
    4212             :                 if (subtlvs == NULL) /* nothing to do */
    4213             :                         return;
    4214             :                 attrlenfield = 0;   /* no outer T + L */
    4215             :                 attrhdrlen = 2 + 2; /* subTLV T + L */
    4216             :                 break;
    4217             : #endif
    4218             : 
    4219             :         default:
    4220           0 :                 assert(0);
    4221             :         }
    4222             : 
    4223             :         /* compute attr length */
    4224           0 :         for (st = subtlvs; st; st = st->next) {
    4225           0 :                 attrlenfield += (attrhdrlen + st->length);
    4226             :         }
    4227             : 
    4228           0 :         if (attrlenfield > 0xffff) {
    4229           0 :                 zlog_info("%s attribute is too long (length=%d), can't send it",
    4230             :                           attrname, attrlenfield);
    4231           0 :                 return;
    4232             :         }
    4233             : 
    4234           0 :         if (attrlenfield > 0xff) {
    4235             :                 /* 2-octet length field */
    4236           0 :                 stream_putc(s,
    4237             :                             BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
    4238             :                                     | BGP_ATTR_FLAG_EXTLEN);
    4239           0 :                 stream_putc(s, attrtype);
    4240           0 :                 stream_putw(s, attrlenfield & 0xffff);
    4241             :         } else {
    4242             :                 /* 1-octet length field */
    4243           0 :                 stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL);
    4244           0 :                 stream_putc(s, attrtype);
    4245           0 :                 stream_putc(s, attrlenfield & 0xff);
    4246             :         }
    4247             : 
    4248           0 :         if (attrtype == BGP_ATTR_ENCAP) {
    4249             :                 /* write outer T+L */
    4250           0 :                 stream_putw(s, attr->encap_tunneltype);
    4251           0 :                 stream_putw(s, attrlenfield - 4);
    4252             :         }
    4253             : 
    4254             :         /* write each sub-tlv */
    4255           0 :         for (st = subtlvs; st; st = st->next) {
    4256           0 :                 if (attrtype == BGP_ATTR_ENCAP) {
    4257           0 :                         stream_putc(s, st->type);
    4258           0 :                         stream_putc(s, st->length);
    4259             : #ifdef ENABLE_BGP_VNC
    4260             :                 } else {
    4261             :                         stream_putw(s, st->type);
    4262             :                         stream_putw(s, st->length);
    4263             : #endif
    4264             :                 }
    4265           0 :                 stream_put(s, st->value, st->length);
    4266             :         }
    4267             : }
    4268             : 
    4269           0 : void bgp_packet_mpattr_end(struct stream *s, size_t sizep)
    4270             : {
    4271             :         /* Set MP attribute length. Don't count the (2) bytes used to encode
    4272             :            the attr length */
    4273           0 :         stream_putw_at(s, sizep, (stream_get_endp(s) - sizep) - 2);
    4274           0 : }
    4275             : 
    4276           0 : static bool bgp_append_local_as(struct peer *peer, afi_t afi, safi_t safi)
    4277             : {
    4278           0 :         if (!BGP_AS_IS_PRIVATE(peer->local_as)
    4279           0 :             || (BGP_AS_IS_PRIVATE(peer->local_as)
    4280           0 :                 && !CHECK_FLAG(peer->af_flags[afi][safi],
    4281             :                                PEER_FLAG_REMOVE_PRIVATE_AS)
    4282           0 :                 && !CHECK_FLAG(peer->af_flags[afi][safi],
    4283             :                                PEER_FLAG_REMOVE_PRIVATE_AS_ALL)
    4284           0 :                 && !CHECK_FLAG(peer->af_flags[afi][safi],
    4285             :                                PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)
    4286           0 :                 && !CHECK_FLAG(peer->af_flags[afi][safi],
    4287             :                                PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)))
    4288           0 :                 return true;
    4289             :         return false;
    4290             : }
    4291             : 
    4292             : /* Make attribute packet. */
    4293           0 : bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
    4294             :                                 struct stream *s, struct attr *attr,
    4295             :                                 struct bpacket_attr_vec_arr *vecarr,
    4296             :                                 struct prefix *p, afi_t afi, safi_t safi,
    4297             :                                 struct peer *from, struct prefix_rd *prd,
    4298             :                                 mpls_label_t *label, uint32_t num_labels,
    4299             :                                 bool addpath_capable, uint32_t addpath_tx_id,
    4300             :                                 struct bgp_path_info *bpi)
    4301             : {
    4302           0 :         size_t cp;
    4303           0 :         size_t aspath_sizep;
    4304           0 :         struct aspath *aspath;
    4305           0 :         int send_as4_path = 0;
    4306           0 :         int send_as4_aggregator = 0;
    4307           0 :         bool use32bit = CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
    4308           0 :                         && CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV);
    4309             : 
    4310           0 :         if (!bgp)
    4311           0 :                 bgp = peer->bgp;
    4312             : 
    4313             :         /* Remember current pointer. */
    4314           0 :         cp = stream_get_endp(s);
    4315             : 
    4316           0 :         if (p
    4317           0 :             && !((afi == AFI_IP && safi == SAFI_UNICAST)
    4318           0 :                  && !peer_cap_enhe(peer, afi, safi))) {
    4319           0 :                 size_t mpattrlen_pos = 0;
    4320             : 
    4321           0 :                 mpattrlen_pos = bgp_packet_mpattr_start(s, peer, afi, safi,
    4322             :                                                         vecarr, attr);
    4323           0 :                 bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label,
    4324             :                                          num_labels, addpath_capable,
    4325             :                                          addpath_tx_id, attr);
    4326           0 :                 bgp_packet_mpattr_end(s, mpattrlen_pos);
    4327             :         }
    4328             : 
    4329             :         /* Origin attribute. */
    4330           0 :         stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4331           0 :         stream_putc(s, BGP_ATTR_ORIGIN);
    4332           0 :         stream_putc(s, 1);
    4333           0 :         stream_putc(s, attr->origin);
    4334             : 
    4335             :         /* AS path attribute. */
    4336             : 
    4337             :         /* If remote-peer is EBGP */
    4338           0 :         if (peer->sort == BGP_PEER_EBGP
    4339           0 :             && (!CHECK_FLAG(peer->af_flags[afi][safi],
    4340             :                             PEER_FLAG_AS_PATH_UNCHANGED)
    4341           0 :                 || attr->aspath->segments == NULL)
    4342           0 :             && (!CHECK_FLAG(peer->af_flags[afi][safi],
    4343             :                             PEER_FLAG_RSERVER_CLIENT))) {
    4344           0 :                 aspath = aspath_dup(attr->aspath);
    4345             : 
    4346             :                 /* Even though we may not be configured for confederations we
    4347             :                  * may have
    4348             :                  * RXed an AS_PATH with AS_CONFED_SEQUENCE or AS_CONFED_SET */
    4349           0 :                 aspath = aspath_delete_confed_seq(aspath);
    4350             : 
    4351           0 :                 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
    4352             :                         /* Stuff our path CONFED_ID on the front */
    4353           0 :                         aspath = aspath_add_seq(aspath, bgp->confed_id);
    4354             :                 } else {
    4355           0 :                         if (peer->change_local_as) {
    4356             :                                 /* If replace-as is specified, we only use the
    4357             :                                    change_local_as when
    4358             :                                    advertising routes. */
    4359           0 :                                 if (!CHECK_FLAG(peer->flags,
    4360             :                                                 PEER_FLAG_LOCAL_AS_REPLACE_AS))
    4361           0 :                                         if (bgp_append_local_as(peer, afi,
    4362             :                                                                 safi))
    4363           0 :                                                 aspath = aspath_add_seq(
    4364             :                                                         aspath, peer->local_as);
    4365           0 :                                 aspath = aspath_add_seq(aspath,
    4366             :                                                         peer->change_local_as);
    4367             :                         } else {
    4368           0 :                                 aspath = aspath_add_seq(aspath, peer->local_as);
    4369             :                         }
    4370             :                 }
    4371           0 :         } else if (peer->sort == BGP_PEER_CONFED) {
    4372             :                 /* A confed member, so we need to do the AS_CONFED_SEQUENCE
    4373             :                  * thing */
    4374           0 :                 aspath = aspath_dup(attr->aspath);
    4375           0 :                 aspath = aspath_add_confed_seq(aspath, peer->local_as);
    4376             :         } else
    4377           0 :                 aspath = attr->aspath;
    4378             : 
    4379             :         /* If peer is not AS4 capable, then:
    4380             :          * - send the created AS_PATH out as AS4_PATH (optional, transitive),
    4381             :          *   but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path
    4382             :          * segment
    4383             :          *   types are in it (i.e. exclude them if they are there)
    4384             :          *   AND do this only if there is at least one asnum > 65535 in the
    4385             :          * path!
    4386             :          * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and
    4387             :          * change
    4388             :          *   all ASnums > 65535 to BGP_AS_TRANS
    4389             :          */
    4390             : 
    4391           0 :         stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
    4392           0 :         stream_putc(s, BGP_ATTR_AS_PATH);
    4393           0 :         aspath_sizep = stream_get_endp(s);
    4394           0 :         stream_putw(s, 0);
    4395           0 :         stream_putw_at(s, aspath_sizep, aspath_put(s, aspath, use32bit));
    4396             : 
    4397             :         /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
    4398             :          * in the path
    4399             :          */
    4400           0 :         if (!use32bit && aspath_has_as4(aspath))
    4401           0 :                 send_as4_path =
    4402             :                         1; /* we'll do this later, at the correct place */
    4403             : 
    4404             :         /* Nexthop attribute. */
    4405           0 :         if (afi == AFI_IP && safi == SAFI_UNICAST
    4406           0 :             && !peer_cap_enhe(peer, afi, safi)) {
    4407           0 :                 afi_t nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
    4408             : 
    4409           0 :                 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) {
    4410           0 :                         stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4411           0 :                         stream_putc(s, BGP_ATTR_NEXT_HOP);
    4412           0 :                         bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
    4413             :                                                      attr);
    4414           0 :                         stream_putc(s, 4);
    4415           0 :                         stream_put_ipv4(s, attr->nexthop.s_addr);
    4416           0 :                 } else if (peer_cap_enhe(from, afi, safi)
    4417           0 :                            || (nh_afi == AFI_IP6)) {
    4418             :                         /*
    4419             :                          * Likely this is the case when an IPv4 prefix was
    4420             :                          * received with Extended Next-hop capability in this
    4421             :                          * or another vrf and is now being advertised to
    4422             :                          * non-ENHE peers. Since peer_cap_enhe only checks
    4423             :                          * peers in this vrf, also check the nh_afi to catch
    4424             :                          * the case where the originator was in another vrf.
    4425             :                          * Setting the mandatory (ipv4) next-hop attribute here
    4426             :                          * to enable implicit next-hop self with correct A-F
    4427             :                          * (ipv4 address family).
    4428             :                          */
    4429           0 :                         stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4430           0 :                         stream_putc(s, BGP_ATTR_NEXT_HOP);
    4431           0 :                         bpacket_attr_vec_arr_set_vec(vecarr, BGP_ATTR_VEC_NH, s,
    4432             :                                                      NULL);
    4433           0 :                         stream_putc(s, 4);
    4434           0 :                         stream_put_ipv4(s, 0);
    4435             :                 }
    4436             :         }
    4437             : 
    4438             :         /* MED attribute. */
    4439           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)
    4440           0 :             || bgp->maxmed_active) {
    4441           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
    4442           0 :                 stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
    4443           0 :                 stream_putc(s, 4);
    4444           0 :                 stream_putl(s, (bgp->maxmed_active ? bgp->maxmed_value
    4445             :                                                    : attr->med));
    4446             :         }
    4447             : 
    4448             :         /* Local preference. */
    4449           0 :         if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) {
    4450           0 :                 stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4451           0 :                 stream_putc(s, BGP_ATTR_LOCAL_PREF);
    4452           0 :                 stream_putc(s, 4);
    4453           0 :                 stream_putl(s, attr->local_pref);
    4454             :         }
    4455             : 
    4456             :         /* Atomic aggregate. */
    4457           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
    4458           0 :                 stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4459           0 :                 stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
    4460           0 :                 stream_putc(s, 0);
    4461             :         }
    4462             : 
    4463             :         /* Aggregator. */
    4464           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
    4465             :                 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
    4466           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
    4467           0 :                 stream_putc(s, BGP_ATTR_AGGREGATOR);
    4468             : 
    4469           0 :                 if (use32bit) {
    4470             :                         /* AS4 capable peer */
    4471           0 :                         stream_putc(s, 8);
    4472           0 :                         stream_putl(s, attr->aggregator_as);
    4473             :                 } else {
    4474             :                         /* 2-byte AS peer */
    4475           0 :                         stream_putc(s, 6);
    4476             : 
    4477             :                         /* Is ASN representable in 2-bytes? Or must AS_TRANS be
    4478             :                          * used? */
    4479           0 :                         if (attr->aggregator_as > UINT16_MAX) {
    4480           0 :                                 stream_putw(s, BGP_AS_TRANS);
    4481             : 
    4482             :                                 /* we have to send AS4_AGGREGATOR, too.
    4483             :                                  * we'll do that later in order to send
    4484             :                                  * attributes in ascending
    4485             :                                  * order.
    4486             :                                  */
    4487           0 :                                 send_as4_aggregator = 1;
    4488             :                         } else
    4489           0 :                                 stream_putw(s, (uint16_t)attr->aggregator_as);
    4490             :                 }
    4491           0 :                 stream_put_ipv4(s, attr->aggregator_addr.s_addr);
    4492             :         }
    4493             : 
    4494             :         /* Community attribute. */
    4495           0 :         if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
    4496           0 :             && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
    4497           0 :                 struct community *comm = NULL;
    4498             : 
    4499           0 :                 comm = bgp_attr_get_community(attr);
    4500           0 :                 if (comm->size * 4 > 255) {
    4501           0 :                         stream_putc(s,
    4502             :                                     BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
    4503             :                                             | BGP_ATTR_FLAG_EXTLEN);
    4504           0 :                         stream_putc(s, BGP_ATTR_COMMUNITIES);
    4505           0 :                         stream_putw(s, comm->size * 4);
    4506             :                 } else {
    4507           0 :                         stream_putc(s,
    4508             :                                     BGP_ATTR_FLAG_OPTIONAL
    4509             :                                             | BGP_ATTR_FLAG_TRANS);
    4510           0 :                         stream_putc(s, BGP_ATTR_COMMUNITIES);
    4511           0 :                         stream_putc(s, comm->size * 4);
    4512             :                 }
    4513           0 :                 stream_put(s, comm->val, comm->size * 4);
    4514             :         }
    4515             : 
    4516             :         /*
    4517             :          * Large Community attribute.
    4518             :          */
    4519           0 :         if (CHECK_FLAG(peer->af_flags[afi][safi],
    4520             :                        PEER_FLAG_SEND_LARGE_COMMUNITY)
    4521           0 :             && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
    4522           0 :                 if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
    4523           0 :                         stream_putc(s,
    4524             :                                     BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
    4525             :                                             | BGP_ATTR_FLAG_EXTLEN);
    4526           0 :                         stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
    4527           0 :                         stream_putw(s,
    4528           0 :                                     lcom_length(bgp_attr_get_lcommunity(attr)));
    4529             :                 } else {
    4530           0 :                         stream_putc(s,
    4531             :                                     BGP_ATTR_FLAG_OPTIONAL
    4532             :                                             | BGP_ATTR_FLAG_TRANS);
    4533           0 :                         stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
    4534           0 :                         stream_putc(s,
    4535           0 :                                     lcom_length(bgp_attr_get_lcommunity(attr)));
    4536             :                 }
    4537           0 :                 stream_put(s, bgp_attr_get_lcommunity(attr)->val,
    4538           0 :                            lcom_length(bgp_attr_get_lcommunity(attr)));
    4539             :         }
    4540             : 
    4541             :         /* Route Reflector. */
    4542           0 :         if (peer->sort == BGP_PEER_IBGP && from
    4543           0 :             && from->sort == BGP_PEER_IBGP) {
    4544           0 :                 struct cluster_list *cluster = bgp_attr_get_cluster(attr);
    4545             : 
    4546             :                 /* Originator ID. */
    4547           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
    4548           0 :                 stream_putc(s, BGP_ATTR_ORIGINATOR_ID);
    4549           0 :                 stream_putc(s, 4);
    4550             : 
    4551           0 :                 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
    4552           0 :                         stream_put_in_addr(s, &attr->originator_id);
    4553             :                 else
    4554           0 :                         stream_put_in_addr(s, &from->remote_id);
    4555             : 
    4556             :                 /* Cluster list. */
    4557           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
    4558           0 :                 stream_putc(s, BGP_ATTR_CLUSTER_LIST);
    4559             : 
    4560           0 :                 if (cluster) {
    4561           0 :                         stream_putc(s, cluster->length + 4);
    4562             :                         /* If this peer configuration's parent BGP has
    4563             :                          * cluster_id. */
    4564           0 :                         if (bgp->config & BGP_CONFIG_CLUSTER_ID)
    4565           0 :                                 stream_put_in_addr(s, &bgp->cluster_id);
    4566             :                         else
    4567           0 :                                 stream_put_in_addr(s, &bgp->router_id);
    4568           0 :                         stream_put(s, cluster->list, cluster->length);
    4569             :                 } else {
    4570           0 :                         stream_putc(s, 4);
    4571             :                         /* If this peer configuration's parent BGP has
    4572             :                          * cluster_id. */
    4573           0 :                         if (bgp->config & BGP_CONFIG_CLUSTER_ID)
    4574           0 :                                 stream_put_in_addr(s, &bgp->cluster_id);
    4575             :                         else
    4576           0 :                                 stream_put_in_addr(s, &bgp->router_id);
    4577             :                 }
    4578             :         }
    4579             : 
    4580             :         /* Extended Communities attribute. */
    4581           0 :         if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
    4582           0 :             && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) {
    4583           0 :                 struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
    4584           0 :                 bool transparent = CHECK_FLAG(peer->af_flags[afi][safi],
    4585           0 :                                               PEER_FLAG_RSERVER_CLIENT) &&
    4586           0 :                                    from &&
    4587           0 :                                    CHECK_FLAG(from->af_flags[afi][safi],
    4588             :                                               PEER_FLAG_RSERVER_CLIENT);
    4589             : 
    4590           0 :                 if (peer->sort == BGP_PEER_IBGP ||
    4591           0 :                     peer->sort == BGP_PEER_CONFED || transparent) {
    4592           0 :                         if (ecomm->size * 8 > 255) {
    4593           0 :                                 stream_putc(s,
    4594             :                                             BGP_ATTR_FLAG_OPTIONAL
    4595             :                                                     | BGP_ATTR_FLAG_TRANS
    4596             :                                                     | BGP_ATTR_FLAG_EXTLEN);
    4597           0 :                                 stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
    4598           0 :                                 stream_putw(s, ecomm->size * 8);
    4599             :                         } else {
    4600           0 :                                 stream_putc(s,
    4601             :                                             BGP_ATTR_FLAG_OPTIONAL
    4602             :                                                     | BGP_ATTR_FLAG_TRANS);
    4603           0 :                                 stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
    4604           0 :                                 stream_putc(s, ecomm->size * 8);
    4605             :                         }
    4606           0 :                         stream_put(s, ecomm->val, ecomm->size * 8);
    4607             :                 } else {
    4608             :                         uint8_t *pnt;
    4609             :                         int tbit;
    4610             :                         int ecom_tr_size = 0;
    4611             :                         uint32_t i;
    4612             : 
    4613           0 :                         for (i = 0; i < ecomm->size; i++) {
    4614           0 :                                 pnt = ecomm->val + (i * 8);
    4615           0 :                                 tbit = *pnt;
    4616             : 
    4617           0 :                                 if (CHECK_FLAG(tbit,
    4618             :                                                ECOMMUNITY_FLAG_NON_TRANSITIVE))
    4619           0 :                                         continue;
    4620             : 
    4621           0 :                                 ecom_tr_size++;
    4622             :                         }
    4623             : 
    4624           0 :                         if (ecom_tr_size) {
    4625           0 :                                 if (ecom_tr_size * 8 > 255) {
    4626           0 :                                         stream_putc(
    4627             :                                                 s,
    4628             :                                                 BGP_ATTR_FLAG_OPTIONAL
    4629             :                                                         | BGP_ATTR_FLAG_TRANS
    4630             :                                                         | BGP_ATTR_FLAG_EXTLEN);
    4631           0 :                                         stream_putc(s,
    4632             :                                                     BGP_ATTR_EXT_COMMUNITIES);
    4633           0 :                                         stream_putw(s, ecom_tr_size * 8);
    4634             :                                 } else {
    4635           0 :                                         stream_putc(
    4636             :                                                 s,
    4637             :                                                 BGP_ATTR_FLAG_OPTIONAL
    4638             :                                                         | BGP_ATTR_FLAG_TRANS);
    4639           0 :                                         stream_putc(s,
    4640             :                                                     BGP_ATTR_EXT_COMMUNITIES);
    4641           0 :                                         stream_putc(s, ecom_tr_size * 8);
    4642             :                                 }
    4643             : 
    4644           0 :                                 for (i = 0; i < ecomm->size; i++) {
    4645           0 :                                         pnt = ecomm->val + (i * 8);
    4646           0 :                                         tbit = *pnt;
    4647             : 
    4648           0 :                                         if (CHECK_FLAG(
    4649             :                                                     tbit,
    4650             :                                                     ECOMMUNITY_FLAG_NON_TRANSITIVE))
    4651           0 :                                                 continue;
    4652             : 
    4653           0 :                                         stream_put(s, pnt, 8);
    4654             :                                 }
    4655             :                         }
    4656             :                 }
    4657             :         }
    4658             : 
    4659             :         /* Label index attribute. */
    4660           0 :         if (safi == SAFI_LABELED_UNICAST) {
    4661           0 :                 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
    4662           0 :                         uint32_t label_index;
    4663             : 
    4664           0 :                         label_index = attr->label_index;
    4665             : 
    4666           0 :                         if (label_index != BGP_INVALID_LABEL_INDEX) {
    4667           0 :                                 stream_putc(s,
    4668             :                                             BGP_ATTR_FLAG_OPTIONAL
    4669             :                                                     | BGP_ATTR_FLAG_TRANS);
    4670           0 :                                 stream_putc(s, BGP_ATTR_PREFIX_SID);
    4671           0 :                                 stream_putc(s, 10);
    4672           0 :                                 stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
    4673           0 :                                 stream_putw(s,
    4674             :                                             BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
    4675           0 :                                 stream_putc(s, 0); // reserved
    4676           0 :                                 stream_putw(s, 0); // flags
    4677           0 :                                 stream_putl(s, label_index);
    4678             :                         }
    4679             :                 }
    4680             :         }
    4681             : 
    4682             :         /* SRv6 Service Information Attribute. */
    4683           0 :         if ((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_MPLS_VPN) {
    4684           0 :                 if (attr->srv6_l3vpn) {
    4685           0 :                         uint8_t subtlv_len =
    4686             :                                 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH
    4687             :                                 + BGP_ATTR_MIN_LEN
    4688             :                                 + BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO_LENGTH;
    4689           0 :                         uint8_t tlv_len = subtlv_len + BGP_ATTR_MIN_LEN + 1;
    4690           0 :                         uint8_t attr_len = tlv_len + BGP_ATTR_MIN_LEN;
    4691           0 :                         stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
    4692             :                                                | BGP_ATTR_FLAG_TRANS);
    4693           0 :                         stream_putc(s, BGP_ATTR_PREFIX_SID);
    4694           0 :                         stream_putc(s, attr_len);
    4695           0 :                         stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE);
    4696           0 :                         stream_putw(s, tlv_len);
    4697           0 :                         stream_putc(s, 0); /* reserved */
    4698           0 :                         stream_putc(s, BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_INFO);
    4699           0 :                         stream_putw(s, subtlv_len);
    4700           0 :                         stream_putc(s, 0);      /* reserved */
    4701           0 :                         stream_put(s, &attr->srv6_l3vpn->sid,
    4702             :                                    sizeof(attr->srv6_l3vpn->sid)); /* sid */
    4703           0 :                         stream_putc(s, 0);      /* sid_flags */
    4704           0 :                         stream_putw(s,
    4705           0 :                                     attr->srv6_l3vpn
    4706           0 :                                             ->endpoint_behavior); /* endpoint */
    4707           0 :                         stream_putc(s, 0);      /* reserved */
    4708           0 :                         stream_putc(
    4709             :                                 s,
    4710             :                                 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE);
    4711           0 :                         stream_putw(
    4712             :                                 s,
    4713             :                                 BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH);
    4714           0 :                         stream_putc(s, attr->srv6_l3vpn->loc_block_len);
    4715           0 :                         stream_putc(s, attr->srv6_l3vpn->loc_node_len);
    4716           0 :                         stream_putc(s, attr->srv6_l3vpn->func_len);
    4717           0 :                         stream_putc(s, attr->srv6_l3vpn->arg_len);
    4718           0 :                         stream_putc(s, attr->srv6_l3vpn->transposition_len);
    4719           0 :                         stream_putc(s, attr->srv6_l3vpn->transposition_offset);
    4720           0 :                 } else if (attr->srv6_vpn) {
    4721           0 :                         stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
    4722             :                                                | BGP_ATTR_FLAG_TRANS);
    4723           0 :                         stream_putc(s, BGP_ATTR_PREFIX_SID);
    4724           0 :                         stream_putc(s, 22);     /* tlv len */
    4725           0 :                         stream_putc(s, BGP_PREFIX_SID_VPN_SID);
    4726           0 :                         stream_putw(s, 0x13);   /* tlv len */
    4727           0 :                         stream_putc(s, 0x00);   /* reserved */
    4728           0 :                         stream_putc(s, 0x01);   /* sid_type */
    4729           0 :                         stream_putc(s, 0x00);   /* sif_flags */
    4730           0 :                         stream_put(s, &attr->srv6_vpn->sid,
    4731             :                                    sizeof(attr->srv6_vpn->sid)); /* sid */
    4732             :                 }
    4733             :         }
    4734             : 
    4735           0 :         if (send_as4_path) {
    4736             :                 /* If the peer is NOT As4 capable, AND */
    4737             :                 /* there are ASnums > 65535 in path  THEN
    4738             :                  * give out AS4_PATH */
    4739             : 
    4740             :                 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
    4741             :                  * path segments!
    4742             :                  * Hm, I wonder...  confederation things *should* only be at
    4743             :                  * the beginning of an aspath, right?  Then we should use
    4744             :                  * aspath_delete_confed_seq for this, because it is already
    4745             :                  * there! (JK)
    4746             :                  * Folks, talk to me: what is reasonable here!?
    4747             :                  */
    4748           0 :                 aspath = aspath_delete_confed_seq(aspath);
    4749             : 
    4750           0 :                 stream_putc(s,
    4751             :                             BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
    4752             :                                     | BGP_ATTR_FLAG_EXTLEN);
    4753           0 :                 stream_putc(s, BGP_ATTR_AS4_PATH);
    4754           0 :                 aspath_sizep = stream_get_endp(s);
    4755           0 :                 stream_putw(s, 0);
    4756           0 :                 stream_putw_at(s, aspath_sizep, aspath_put(s, aspath, 1));
    4757             :         }
    4758             : 
    4759           0 :         if (aspath != attr->aspath)
    4760           0 :                 aspath_free(aspath);
    4761             : 
    4762           0 :         if (send_as4_aggregator) {
    4763             :                 /* send AS4_AGGREGATOR, at this place */
    4764             :                 /* this section of code moved here in order to ensure the
    4765             :                  * correct
    4766             :                  * *ascending* order of attributes
    4767             :                  */
    4768           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
    4769           0 :                 stream_putc(s, BGP_ATTR_AS4_AGGREGATOR);
    4770           0 :                 stream_putc(s, 8);
    4771           0 :                 stream_putl(s, attr->aggregator_as);
    4772           0 :                 stream_put_ipv4(s, attr->aggregator_addr.s_addr);
    4773             :         }
    4774             : 
    4775           0 :         if (((afi == AFI_IP || afi == AFI_IP6)
    4776           0 :              && (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
    4777           0 :             || (afi == AFI_L2VPN && safi == SAFI_EVPN)) {
    4778             :                 /* Tunnel Encap attribute */
    4779           0 :                 bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
    4780             : 
    4781             : #ifdef ENABLE_BGP_VNC_ATTR
    4782             :                 /* VNC attribute */
    4783             :                 bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_VNC);
    4784             : #endif
    4785             :         }
    4786             : 
    4787             :         /* PMSI Tunnel */
    4788           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL)) {
    4789           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
    4790           0 :                 stream_putc(s, BGP_ATTR_PMSI_TUNNEL);
    4791           0 :                 stream_putc(s, 9); // Length
    4792           0 :                 stream_putc(s, 0); // Flags
    4793           0 :                 stream_putc(s, bgp_attr_get_pmsi_tnl_type(attr));
    4794           0 :                 stream_put(s, &(attr->label),
    4795             :                            BGP_LABEL_BYTES); // MPLS Label / VXLAN VNI
    4796           0 :                 stream_put_ipv4(s, attr->nexthop.s_addr);
    4797             :                 // Unicast tunnel endpoint IP address
    4798             :         }
    4799             : 
    4800             :         /* OTC */
    4801           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) {
    4802           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
    4803           0 :                 stream_putc(s, BGP_ATTR_OTC);
    4804           0 :                 stream_putc(s, 4);
    4805           0 :                 stream_putl(s, attr->otc);
    4806             :         }
    4807             : 
    4808             :         /* AIGP */
    4809           0 :         if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
    4810           0 :             (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
    4811           0 :              peer->sort != BGP_PEER_EBGP)) {
    4812             :                 /* At the moment only AIGP Metric TLV exists for AIGP
    4813             :                  * attribute. If more comes in, do not forget to update
    4814             :                  * attr_len variable to include new ones.
    4815             :                  */
    4816           0 :                 uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
    4817             : 
    4818           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
    4819           0 :                 stream_putc(s, BGP_ATTR_AIGP);
    4820           0 :                 stream_putc(s, attr_len);
    4821           0 :                 stream_put_bgp_aigp_tlv_metric(s, bpi);
    4822             :         }
    4823             : 
    4824             :         /* Unknown transit attribute. */
    4825           0 :         struct transit *transit = bgp_attr_get_transit(attr);
    4826             : 
    4827           0 :         if (transit)
    4828           0 :                 stream_put(s, transit->val, transit->length);
    4829             : 
    4830             :         /* Return total size of attribute. */
    4831           0 :         return stream_get_endp(s) - cp;
    4832             : }
    4833             : 
    4834           0 : size_t bgp_packet_mpunreach_start(struct stream *s, afi_t afi, safi_t safi)
    4835             : {
    4836           0 :         unsigned long attrlen_pnt;
    4837           0 :         iana_afi_t pkt_afi = IANA_AFI_IPV4;
    4838           0 :         iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
    4839             : 
    4840             :         /* Set extended bit always to encode the attribute length as 2 bytes */
    4841           0 :         stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
    4842           0 :         stream_putc(s, BGP_ATTR_MP_UNREACH_NLRI);
    4843             : 
    4844           0 :         attrlen_pnt = stream_get_endp(s);
    4845           0 :         stream_putw(s, 0); /* Length of this attribute. */
    4846             : 
    4847             :         /* Convert AFI, SAFI to values for packet. */
    4848           0 :         bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
    4849             : 
    4850           0 :         stream_putw(s, pkt_afi);
    4851           0 :         stream_putc(s, pkt_safi);
    4852             : 
    4853           0 :         return attrlen_pnt;
    4854             : }
    4855             : 
    4856           0 : void bgp_packet_mpunreach_prefix(struct stream *s, const struct prefix *p,
    4857             :                                  afi_t afi, safi_t safi,
    4858             :                                  const struct prefix_rd *prd,
    4859             :                                  mpls_label_t *label, uint32_t num_labels,
    4860             :                                  bool addpath_capable, uint32_t addpath_tx_id,
    4861             :                                  struct attr *attr)
    4862             : {
    4863           0 :         uint8_t wlabel[4] = {0x80, 0x00, 0x00};
    4864             : 
    4865           0 :         if (safi == SAFI_LABELED_UNICAST) {
    4866           0 :                 label = (mpls_label_t *)wlabel;
    4867           0 :                 num_labels = 1;
    4868             :         }
    4869             : 
    4870           0 :         bgp_packet_mpattr_prefix(s, afi, safi, p, prd, label, num_labels,
    4871             :                                  addpath_capable, addpath_tx_id, attr);
    4872           0 : }
    4873             : 
    4874           0 : void bgp_packet_mpunreach_end(struct stream *s, size_t attrlen_pnt)
    4875             : {
    4876           0 :         bgp_packet_mpattr_end(s, attrlen_pnt);
    4877           0 : }
    4878             : 
    4879             : /* Initialization of attribute. */
    4880           3 : void bgp_attr_init(void)
    4881             : {
    4882           3 :         aspath_init();
    4883           3 :         attrhash_init();
    4884           3 :         community_init();
    4885           3 :         ecommunity_init();
    4886           3 :         lcommunity_init();
    4887           3 :         cluster_init();
    4888           3 :         transit_init();
    4889           3 :         encap_init();
    4890           3 :         srv6_init();
    4891           3 : }
    4892             : 
    4893           3 : void bgp_attr_finish(void)
    4894             : {
    4895           3 :         aspath_finish();
    4896           3 :         attrhash_finish();
    4897           3 :         community_finish();
    4898           3 :         ecommunity_finish();
    4899           3 :         lcommunity_finish();
    4900           3 :         cluster_finish();
    4901           3 :         transit_finish();
    4902           3 :         encap_finish();
    4903           3 :         srv6_finish();
    4904           3 : }
    4905             : 
    4906             : /* Make attribute packet. */
    4907           0 : void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
    4908             :                           const struct prefix *prefix)
    4909             : {
    4910           0 :         unsigned long cp;
    4911           0 :         unsigned long len;
    4912           0 :         size_t aspath_lenp;
    4913           0 :         struct aspath *aspath;
    4914           0 :         bool addpath_capable = false;
    4915           0 :         uint32_t addpath_tx_id = 0;
    4916           0 :         struct attr *attr = bpi->attr;
    4917             : 
    4918             :         /* Remember current pointer. */
    4919           0 :         cp = stream_get_endp(s);
    4920             : 
    4921             :         /* Place holder of length. */
    4922           0 :         stream_putw(s, 0);
    4923             : 
    4924             :         /* Origin attribute. */
    4925           0 :         stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4926           0 :         stream_putc(s, BGP_ATTR_ORIGIN);
    4927           0 :         stream_putc(s, 1);
    4928           0 :         stream_putc(s, attr->origin);
    4929             : 
    4930           0 :         aspath = attr->aspath;
    4931             : 
    4932           0 :         stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
    4933           0 :         stream_putc(s, BGP_ATTR_AS_PATH);
    4934           0 :         aspath_lenp = stream_get_endp(s);
    4935           0 :         stream_putw(s, 0);
    4936             : 
    4937           0 :         stream_putw_at(s, aspath_lenp, aspath_put(s, aspath, 1));
    4938             : 
    4939             :         /* Nexthop attribute. */
    4940             :         /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
    4941           0 :         if (prefix != NULL && prefix->family != AF_INET6) {
    4942           0 :                 stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4943           0 :                 stream_putc(s, BGP_ATTR_NEXT_HOP);
    4944           0 :                 stream_putc(s, 4);
    4945           0 :                 stream_put_ipv4(s, attr->nexthop.s_addr);
    4946             :         }
    4947             : 
    4948             :         /* MED attribute. */
    4949           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)) {
    4950           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
    4951           0 :                 stream_putc(s, BGP_ATTR_MULTI_EXIT_DISC);
    4952           0 :                 stream_putc(s, 4);
    4953           0 :                 stream_putl(s, attr->med);
    4954             :         }
    4955             : 
    4956             :         /* Local preference. */
    4957           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)) {
    4958           0 :                 stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4959           0 :                 stream_putc(s, BGP_ATTR_LOCAL_PREF);
    4960           0 :                 stream_putc(s, 4);
    4961           0 :                 stream_putl(s, attr->local_pref);
    4962             :         }
    4963             : 
    4964             :         /* Atomic aggregate. */
    4965           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE)) {
    4966           0 :                 stream_putc(s, BGP_ATTR_FLAG_TRANS);
    4967           0 :                 stream_putc(s, BGP_ATTR_ATOMIC_AGGREGATE);
    4968           0 :                 stream_putc(s, 0);
    4969             :         }
    4970             : 
    4971             :         /* Aggregator. */
    4972           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR)) {
    4973           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
    4974           0 :                 stream_putc(s, BGP_ATTR_AGGREGATOR);
    4975           0 :                 stream_putc(s, 8);
    4976           0 :                 stream_putl(s, attr->aggregator_as);
    4977           0 :                 stream_put_ipv4(s, attr->aggregator_addr.s_addr);
    4978             :         }
    4979             : 
    4980             :         /* Community attribute. */
    4981           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
    4982           0 :                 struct community *comm = NULL;
    4983             : 
    4984           0 :                 comm = bgp_attr_get_community(attr);
    4985           0 :                 if (comm->size * 4 > 255) {
    4986           0 :                         stream_putc(s,
    4987             :                                     BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
    4988             :                                             | BGP_ATTR_FLAG_EXTLEN);
    4989           0 :                         stream_putc(s, BGP_ATTR_COMMUNITIES);
    4990           0 :                         stream_putw(s, comm->size * 4);
    4991             :                 } else {
    4992           0 :                         stream_putc(s,
    4993             :                                     BGP_ATTR_FLAG_OPTIONAL
    4994             :                                             | BGP_ATTR_FLAG_TRANS);
    4995           0 :                         stream_putc(s, BGP_ATTR_COMMUNITIES);
    4996           0 :                         stream_putc(s, comm->size * 4);
    4997             :                 }
    4998           0 :                 stream_put(s, comm->val, comm->size * 4);
    4999             :         }
    5000             : 
    5001             :         /* Large Community attribute. */
    5002           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
    5003           0 :                 if (lcom_length(bgp_attr_get_lcommunity(attr)) > 255) {
    5004           0 :                         stream_putc(s,
    5005             :                                     BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
    5006             :                                             | BGP_ATTR_FLAG_EXTLEN);
    5007           0 :                         stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
    5008           0 :                         stream_putw(s,
    5009           0 :                                     lcom_length(bgp_attr_get_lcommunity(attr)));
    5010             :                 } else {
    5011           0 :                         stream_putc(s,
    5012             :                                     BGP_ATTR_FLAG_OPTIONAL
    5013             :                                             | BGP_ATTR_FLAG_TRANS);
    5014           0 :                         stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
    5015           0 :                         stream_putc(s,
    5016           0 :                                     lcom_length(bgp_attr_get_lcommunity(attr)));
    5017             :                 }
    5018             : 
    5019           0 :                 stream_put(s, bgp_attr_get_lcommunity(attr)->val,
    5020           0 :                            lcom_length(bgp_attr_get_lcommunity(attr)));
    5021             :         }
    5022             : 
    5023             :         /* Add a MP_NLRI attribute to dump the IPv6 next hop */
    5024           0 :         if (prefix != NULL && prefix->family == AF_INET6
    5025           0 :             && (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
    5026           0 :                 || attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)) {
    5027           0 :                 int sizep;
    5028             : 
    5029           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
    5030           0 :                 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
    5031           0 :                 sizep = stream_get_endp(s);
    5032             : 
    5033             :                 /* MP header */
    5034           0 :                 stream_putc(s, 0);          /* Marker: Attribute length. */
    5035           0 :                 stream_putw(s, AFI_IP6);      /* AFI */
    5036           0 :                 stream_putc(s, SAFI_UNICAST); /* SAFI */
    5037             : 
    5038             :                 /* Next hop */
    5039           0 :                 stream_putc(s, attr->mp_nexthop_len);
    5040           0 :                 stream_put(s, &attr->mp_nexthop_global, IPV6_MAX_BYTELEN);
    5041           0 :                 if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
    5042           0 :                         stream_put(s, &attr->mp_nexthop_local,
    5043             :                                    IPV6_MAX_BYTELEN);
    5044             : 
    5045             :                 /* SNPA */
    5046           0 :                 stream_putc(s, 0);
    5047             : 
    5048             :                 /* Prefix */
    5049           0 :                 stream_put_prefix_addpath(s, prefix, addpath_capable,
    5050             :                                           addpath_tx_id);
    5051             : 
    5052             :                 /* Set MP attribute length. */
    5053           0 :                 stream_putc_at(s, sizep, (stream_get_endp(s) - sizep) - 1);
    5054             :         }
    5055             : 
    5056             :         /* Prefix SID */
    5057           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
    5058           0 :                 if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
    5059           0 :                         stream_putc(s,
    5060             :                                     BGP_ATTR_FLAG_OPTIONAL
    5061             :                                             | BGP_ATTR_FLAG_TRANS);
    5062           0 :                         stream_putc(s, BGP_ATTR_PREFIX_SID);
    5063           0 :                         stream_putc(s, 10);
    5064           0 :                         stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
    5065           0 :                         stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
    5066           0 :                         stream_putc(s, 0); // reserved
    5067           0 :                         stream_putw(s, 0); // flags
    5068           0 :                         stream_putl(s, attr->label_index);
    5069             :                 }
    5070             :         }
    5071             : 
    5072             :         /* OTC */
    5073           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_OTC)) {
    5074           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
    5075           0 :                 stream_putc(s, BGP_ATTR_OTC);
    5076           0 :                 stream_putc(s, 4);
    5077           0 :                 stream_putl(s, attr->otc);
    5078             :         }
    5079             : 
    5080             :         /* AIGP */
    5081           0 :         if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) {
    5082             :                 /* At the moment only AIGP Metric TLV exists for AIGP
    5083             :                  * attribute. If more comes in, do not forget to update
    5084             :                  * attr_len variable to include new ones.
    5085             :                  */
    5086           0 :                 uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
    5087             : 
    5088           0 :                 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
    5089           0 :                 stream_putc(s, BGP_ATTR_AIGP);
    5090           0 :                 stream_putc(s, attr_len);
    5091           0 :                 stream_put_bgp_aigp_tlv_metric(s, bpi);
    5092             :         }
    5093             : 
    5094             :         /* Return total size of attribute. */
    5095           0 :         len = stream_get_endp(s) - cp - 2;
    5096           0 :         stream_putw_at(s, cp, len);
    5097           0 : }
    5098             : 
    5099           0 : void bgp_path_attribute_discard_vty(struct vty *vty, struct peer *peer,
    5100             :                                     const char *discard_attrs, bool set)
    5101             : {
    5102           0 :         int i, num_attributes;
    5103           0 :         char **attributes;
    5104           0 :         afi_t afi;
    5105           0 :         safi_t safi;
    5106             : 
    5107             : 
    5108             :         /* If `no` command specified without arbitrary attributes,
    5109             :          * then flush all.
    5110             :          */
    5111           0 :         if (!discard_attrs) {
    5112           0 :                 for (i = 0; i < BGP_ATTR_MAX; i++)
    5113           0 :                         peer->discard_attrs[i] = false;
    5114           0 :                 goto discard_soft_clear;
    5115             :         }
    5116             : 
    5117           0 :         if (discard_attrs) {
    5118           0 :                 frrstr_split(discard_attrs, " ", &attributes, &num_attributes);
    5119             : 
    5120           0 :                 if (set)
    5121           0 :                         for (i = 0; i < BGP_ATTR_MAX; i++)
    5122           0 :                                 peer->discard_attrs[i] = false;
    5123             : 
    5124           0 :                 for (i = 0; i < num_attributes; i++) {
    5125           0 :                         uint8_t attr_num = strtoul(attributes[i], NULL, 10);
    5126             : 
    5127           0 :                         XFREE(MTYPE_TMP, attributes[i]);
    5128             : 
    5129             :                         /* Some of the attributes, just can't be ignored. */
    5130           0 :                         if (attr_num == BGP_ATTR_ORIGIN ||
    5131             :                             attr_num == BGP_ATTR_AS_PATH ||
    5132           0 :                             attr_num == BGP_ATTR_NEXT_HOP ||
    5133           0 :                             attr_num == BGP_ATTR_MULTI_EXIT_DISC ||
    5134           0 :                             attr_num == BGP_ATTR_MP_REACH_NLRI ||
    5135           0 :                             attr_num == BGP_ATTR_MP_UNREACH_NLRI ||
    5136             :                             attr_num == BGP_ATTR_EXT_COMMUNITIES) {
    5137           0 :                                 vty_out(vty,
    5138             :                                         "%% Can't discard path-attribute %s, ignoring.\n",
    5139             :                                         lookup_msg(attr_str, attr_num, NULL));
    5140           0 :                                 continue;
    5141             :                         }
    5142             : 
    5143             :                         /* Ignore local-pref, originator-id, cluster-list only
    5144             :                          * for eBGP.
    5145             :                          */
    5146           0 :                         if (peer->sort != BGP_PEER_EBGP &&
    5147           0 :                             (attr_num == BGP_ATTR_LOCAL_PREF ||
    5148           0 :                              attr_num == BGP_ATTR_ORIGINATOR_ID ||
    5149             :                              attr_num == BGP_ATTR_CLUSTER_LIST)) {
    5150           0 :                                 vty_out(vty,
    5151             :                                         "%% Can discard path-attribute %s only for eBGP, ignoring.\n",
    5152             :                                         lookup_msg(attr_str, attr_num, NULL));
    5153           0 :                                 continue;
    5154             :                         }
    5155             : 
    5156           0 :                         peer->discard_attrs[attr_num] = set;
    5157             :                 }
    5158           0 :                 XFREE(MTYPE_TMP, attributes);
    5159             :         discard_soft_clear:
    5160             :                 /* Configuring path attributes to be discarded will trigger
    5161             :                  * an inbound Route Refresh to ensure that the routing table
    5162             :                  * is up to date.
    5163             :                  */
    5164           0 :                 FOREACH_AFI_SAFI (afi, safi)
    5165           0 :                         peer_clear_soft(peer, afi, safi, BGP_CLEAR_SOFT_IN);
    5166             :         }
    5167           0 : }

Generated by: LCOV version v1.16-topotato