back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_updgrp_packet.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 426 619 68.8 %
Date: 2023-02-24 14:41:08 Functions: 22 27 81.5 %

          Line data    Source code
       1             : /**
       2             :  * bgp_updgrp_packet.c: BGP update group packet handling routines
       3             :  *
       4             :  * @copyright Copyright (C) 2014 Cumulus Networks, Inc.
       5             :  *
       6             :  * @author Avneesh Sachdev <avneesh@sproute.net>
       7             :  * @author Rajesh Varadarajan <rajesh@sproute.net>
       8             :  * @author Pradosh Mohapatra <pradosh@sproute.net>
       9             :  *
      10             :  * This file is part of GNU Zebra.
      11             :  *
      12             :  * GNU Zebra is free software; you can redistribute it and/or modify it
      13             :  * under the terms of the GNU General Public License as published by the
      14             :  * Free Software Foundation; either version 2, or (at your option) any
      15             :  * later version.
      16             :  *
      17             :  * GNU Zebra is distributed in the hope that it will be useful, but
      18             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      20             :  * General Public License for more details.
      21             :  *
      22             :  * You should have received a copy of the GNU General Public License along
      23             :  * with this program; see the file COPYING; if not, write to the Free Software
      24             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      25             :  */
      26             : 
      27             : #include <zebra.h>
      28             : 
      29             : #include "prefix.h"
      30             : #include "thread.h"
      31             : #include "buffer.h"
      32             : #include "stream.h"
      33             : #include "command.h"
      34             : #include "sockunion.h"
      35             : #include "network.h"
      36             : #include "memory.h"
      37             : #include "filter.h"
      38             : #include "routemap.h"
      39             : #include "log.h"
      40             : #include "plist.h"
      41             : #include "linklist.h"
      42             : #include "workqueue.h"
      43             : #include "hash.h"
      44             : #include "queue.h"
      45             : #include "mpls.h"
      46             : 
      47             : #include "bgpd/bgpd.h"
      48             : #include "bgpd/bgp_debug.h"
      49             : #include "bgpd/bgp_errors.h"
      50             : #include "bgpd/bgp_fsm.h"
      51             : #include "bgpd/bgp_route.h"
      52             : #include "bgpd/bgp_packet.h"
      53             : #include "bgpd/bgp_advertise.h"
      54             : #include "bgpd/bgp_updgrp.h"
      55             : #include "bgpd/bgp_nexthop.h"
      56             : #include "bgpd/bgp_nht.h"
      57             : #include "bgpd/bgp_mplsvpn.h"
      58             : #include "bgpd/bgp_label.h"
      59             : #include "bgpd/bgp_addpath.h"
      60             : 
      61             : /********************
      62             :  * PRIVATE FUNCTIONS
      63             :  ********************/
      64             : 
      65             : /********************
      66             :  * PUBLIC FUNCTIONS
      67             :  ********************/
      68         106 : struct bpacket *bpacket_alloc(void)
      69             : {
      70         106 :         struct bpacket *pkt;
      71             : 
      72           0 :         pkt = XCALLOC(MTYPE_BGP_PACKET, sizeof(struct bpacket));
      73             : 
      74         106 :         return pkt;
      75             : }
      76             : 
      77         106 : void bpacket_free(struct bpacket *pkt)
      78             : {
      79         106 :         if (pkt->buffer)
      80          74 :                 stream_free(pkt->buffer);
      81         106 :         pkt->buffer = NULL;
      82         106 :         XFREE(MTYPE_BGP_PACKET, pkt);
      83         106 : }
      84             : 
      85          32 : void bpacket_queue_init(struct bpacket_queue *q)
      86             : {
      87          32 :         TAILQ_INIT(&(q->pkts));
      88          32 : }
      89             : 
      90             : /*
      91             :  * bpacket_queue_add_packet
      92             :  *
      93             :  * Internal function of bpacket_queue - and adds a
      94             :  * packet entry to the end of the list.
      95             :  *
      96             :  * Users of bpacket_queue should use bpacket_queue_add instead.
      97             :  */
      98         106 : static void bpacket_queue_add_packet(struct bpacket_queue *q,
      99             :                                      struct bpacket *pkt)
     100             : {
     101         106 :         struct bpacket *last_pkt;
     102             : 
     103         106 :         if (TAILQ_EMPTY(&(q->pkts)))
     104          32 :                 TAILQ_INSERT_TAIL(&(q->pkts), pkt, pkt_train);
     105             :         else {
     106          74 :                 last_pkt = bpacket_queue_last(q);
     107          74 :                 TAILQ_INSERT_AFTER(&(q->pkts), last_pkt, pkt, pkt_train);
     108             :         }
     109         106 :         q->curr_count++;
     110         106 :         if (q->hwm_count < q->curr_count)
     111          56 :                 q->hwm_count = q->curr_count;
     112         106 : }
     113             : 
     114             : /*
     115             :  * Adds a packet to the bpacket_queue.
     116             :  *
     117             :  * The stream passed is consumed by this function. So, the caller should
     118             :  * not free or use the stream after
     119             :  * invoking this function.
     120             :  */
     121         106 : struct bpacket *bpacket_queue_add(struct bpacket_queue *q, struct stream *s,
     122             :                                   struct bpacket_attr_vec_arr *vecarrp)
     123             : {
     124         106 :         struct bpacket *pkt;
     125         106 :         struct bpacket *last_pkt;
     126             : 
     127             : 
     128         106 :         pkt = bpacket_alloc();
     129         106 :         if (TAILQ_EMPTY(&(q->pkts))) {
     130          32 :                 pkt->ver = 1;
     131          32 :                 pkt->buffer = s;
     132          32 :                 if (vecarrp)
     133           0 :                         memcpy(&pkt->arr, vecarrp,
     134             :                                sizeof(struct bpacket_attr_vec_arr));
     135             :                 else
     136          64 :                         bpacket_attr_vec_arr_reset(&pkt->arr);
     137          32 :                 bpacket_queue_add_packet(q, pkt);
     138          32 :                 return pkt;
     139             :         }
     140             : 
     141             :         /*
     142             :          * Fill in the new information into the current sentinel and create a
     143             :          * new sentinel.
     144             :          */
     145          74 :         last_pkt = bpacket_queue_last(q);
     146           0 :         assert(last_pkt->buffer == NULL);
     147          74 :         last_pkt->buffer = s;
     148          74 :         if (vecarrp)
     149          72 :                 memcpy(&last_pkt->arr, vecarrp,
     150             :                        sizeof(struct bpacket_attr_vec_arr));
     151             :         else
     152          76 :                 bpacket_attr_vec_arr_reset(&last_pkt->arr);
     153             : 
     154          74 :         pkt->ver = last_pkt->ver;
     155          74 :         pkt->ver++;
     156          74 :         bpacket_queue_add_packet(q, pkt);
     157             : 
     158          74 :         return last_pkt;
     159             : }
     160             : 
     161         490 : struct bpacket *bpacket_queue_first(struct bpacket_queue *q)
     162             : {
     163         490 :         return (TAILQ_FIRST(&(q->pkts)));
     164             : }
     165             : 
     166         149 : struct bpacket *bpacket_queue_last(struct bpacket_queue *q)
     167             : {
     168         148 :         return TAILQ_LAST(&(q->pkts), pkt_queue);
     169             : }
     170             : 
     171         138 : struct bpacket *bpacket_queue_remove(struct bpacket_queue *q)
     172             : {
     173         138 :         struct bpacket *first;
     174             : 
     175         138 :         first = bpacket_queue_first(q);
     176         138 :         if (first) {
     177         106 :                 TAILQ_REMOVE(&(q->pkts), first, pkt_train);
     178         106 :                 q->curr_count--;
     179             :         }
     180         138 :         return first;
     181             : }
     182             : 
     183           0 : unsigned int bpacket_queue_length(struct bpacket_queue *q)
     184             : {
     185           0 :         return q->curr_count - 1;
     186             : }
     187             : 
     188           0 : unsigned int bpacket_queue_hwm_length(struct bpacket_queue *q)
     189             : {
     190           0 :         return q->hwm_count - 1;
     191             : }
     192             : 
     193         775 : bool bpacket_queue_is_full(struct bgp *bgp, struct bpacket_queue *q)
     194             : {
     195         209 :         if (q->curr_count >= bgp->default_subgroup_pkt_queue_max)
     196           0 :                 return true;
     197             :         return false;
     198             : }
     199             : 
     200         112 : void bpacket_add_peer(struct bpacket *pkt, struct peer_af *paf)
     201             : {
     202         112 :         if (!pkt || !paf)
     203             :                 return;
     204             : 
     205         112 :         LIST_INSERT_HEAD(&(pkt->peers), paf, pkt_train);
     206         112 :         paf->next_pkt_to_send = pkt;
     207             : }
     208             : 
     209             : /*
     210             :  * bpacket_queue_cleanup
     211             :  */
     212          32 : void bpacket_queue_cleanup(struct bpacket_queue *q)
     213             : {
     214          32 :         struct bpacket *pkt;
     215             : 
     216          64 :         while ((pkt = bpacket_queue_remove(q))) {
     217          32 :                 bpacket_free(pkt);
     218             :         }
     219          32 : }
     220             : 
     221             : /*
     222             :  * bpacket_queue_compact
     223             :  *
     224             :  * Delete packets that do not need to be transmitted to any peer from
     225             :  * the queue.
     226             :  *
     227             :  * @return the number of packets deleted.
     228             :  */
     229         112 : static int bpacket_queue_compact(struct bpacket_queue *q)
     230             : {
     231         112 :         int num_deleted;
     232         112 :         struct bpacket *pkt, *removed_pkt;
     233             : 
     234         112 :         num_deleted = 0;
     235             : 
     236         260 :         while (1) {
     237         260 :                 pkt = bpacket_queue_first(q);
     238         186 :                 if (!pkt)
     239             :                         break;
     240             : 
     241             :                 /*
     242             :                  * Don't delete the sentinel.
     243             :                  */
     244         186 :                 if (!pkt->buffer)
     245             :                         break;
     246             : 
     247          76 :                 if (!LIST_EMPTY(&(pkt->peers)))
     248             :                         break;
     249             : 
     250          74 :                 removed_pkt = bpacket_queue_remove(q);
     251          74 :                 assert(pkt == removed_pkt);
     252          74 :                 bpacket_free(removed_pkt);
     253             : 
     254          74 :                 num_deleted++;
     255             :         }
     256             : 
     257         112 :         return num_deleted;
     258             : }
     259             : 
     260          76 : void bpacket_queue_advance_peer(struct peer_af *paf)
     261             : {
     262          76 :         struct bpacket *pkt;
     263          76 :         struct bpacket *old_pkt;
     264             : 
     265          76 :         old_pkt = paf->next_pkt_to_send;
     266          76 :         if (old_pkt->buffer == NULL)
     267             :                 /* Already at end of list */
     268             :                 return;
     269             : 
     270          76 :         LIST_REMOVE(paf, pkt_train);
     271          76 :         pkt = TAILQ_NEXT(old_pkt, pkt_train);
     272          76 :         bpacket_add_peer(pkt, paf);
     273             : 
     274          76 :         if (!bpacket_queue_compact(PAF_PKTQ(paf)))
     275             :                 return;
     276             : 
     277             :         /*
     278             :          * Deleted one or more packets. Check if we can now merge this
     279             :          * peer's subgroup into another subgroup.
     280             :          */
     281          74 :         update_subgroup_check_merge(paf->subgroup, "advanced peer in queue");
     282             : }
     283             : 
     284             : /*
     285             :  * bpacket_queue_remove_peer
     286             :  *
     287             :  * Remove the peer from the packet queue of the subgroup it belongs
     288             :  * to.
     289             :  */
     290          36 : void bpacket_queue_remove_peer(struct peer_af *paf)
     291             : {
     292          36 :         struct bpacket_queue *q;
     293             : 
     294          36 :         q = PAF_PKTQ(paf);
     295          36 :         assert(q);
     296             : 
     297          36 :         LIST_REMOVE(paf, pkt_train);
     298          36 :         paf->next_pkt_to_send = NULL;
     299             : 
     300          36 :         bpacket_queue_compact(q);
     301          36 : }
     302             : 
     303         162 : unsigned int bpacket_queue_virtual_length(struct peer_af *paf)
     304             : {
     305         162 :         struct bpacket *pkt;
     306         162 :         struct bpacket *last;
     307         162 :         struct bpacket_queue *q;
     308             : 
     309         162 :         pkt = paf->next_pkt_to_send;
     310         162 :         if (!pkt || (pkt->buffer == NULL))
     311             :                 /* Already at end of list */
     312             :                 return 0;
     313             : 
     314           0 :         q = PAF_PKTQ(paf);
     315           0 :         if (TAILQ_EMPTY(&(q->pkts)))
     316             :                 return 0;
     317             : 
     318           0 :         last = TAILQ_LAST(&(q->pkts), pkt_queue);
     319           0 :         if (last->ver >= pkt->ver)
     320           0 :                 return last->ver - pkt->ver;
     321             : 
     322             :         /* sequence # rolled over */
     323           0 :         return (UINT_MAX - pkt->ver + 1) + last->ver;
     324             : }
     325             : 
     326             : /*
     327             :  * Dump the bpacket queue
     328             :  */
     329           0 : void bpacket_queue_show_vty(struct bpacket_queue *q, struct vty *vty)
     330             : {
     331           0 :         struct bpacket *pkt;
     332           0 :         struct peer_af *paf;
     333             : 
     334           0 :         pkt = bpacket_queue_first(q);
     335           0 :         while (pkt) {
     336           0 :                 vty_out(vty, "  Packet %p ver %u buffer %p\n", pkt, pkt->ver,
     337             :                         pkt->buffer);
     338             : 
     339           0 :                 LIST_FOREACH (paf, &(pkt->peers), pkt_train) {
     340           0 :                         vty_out(vty, "      - %s\n", paf->peer->host);
     341             :                 }
     342           0 :                 pkt = bpacket_next(pkt);
     343             :         }
     344           0 :         return;
     345             : }
     346             : 
     347          76 : struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
     348             :                                          struct peer_af *paf)
     349             : {
     350          76 :         struct stream *s = NULL;
     351          76 :         bpacket_attr_vec *vec;
     352          76 :         struct peer *peer;
     353          76 :         struct bgp_filter *filter;
     354             : 
     355          76 :         s = stream_dup(pkt->buffer);
     356          76 :         peer = PAF_PEER(paf);
     357             : 
     358          76 :         vec = &pkt->arr.entries[BGP_ATTR_VEC_NH];
     359             : 
     360          76 :         if (!CHECK_FLAG(vec->flags, BPKT_ATTRVEC_FLAGS_UPDATED))
     361             :                 return s;
     362             : 
     363          74 :         uint8_t nhlen;
     364          74 :         afi_t nhafi;
     365          74 :         int route_map_sets_nh;
     366             : 
     367          74 :         nhlen = stream_getc_from(s, vec->offset);
     368          74 :         filter = &peer->filter[paf->afi][paf->safi];
     369             : 
     370          74 :         if (peer_cap_enhe(peer, paf->afi, paf->safi))
     371             :                 nhafi = AFI_IP6;
     372             :         else
     373          74 :                 nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen);
     374             : 
     375          59 :         if (nhafi == AFI_IP) {
     376          59 :                 struct in_addr v4nh, *mod_v4nh;
     377          59 :                 int nh_modified = 0;
     378          59 :                 size_t offset_nh = vec->offset + 1;
     379             : 
     380          59 :                 route_map_sets_nh =
     381             :                         (CHECK_FLAG(vec->flags,
     382             :                                     BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED) ||
     383             :                          CHECK_FLAG(vec->flags,
     384          59 :                                     BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED) ||
     385             :                          CHECK_FLAG(vec->flags,
     386             :                                     BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS));
     387             : 
     388          59 :                 switch (nhlen) {
     389             :                 case BGP_ATTR_NHLEN_IPV4:
     390             :                         break;
     391           0 :                 case BGP_ATTR_NHLEN_VPNV4:
     392           0 :                         offset_nh += 8;
     393           0 :                         break;
     394           0 :                 default:
     395             :                         /* TODO: handle IPv6 nexthops */
     396           0 :                         flog_warn(
     397             :                                 EC_BGP_INVALID_NEXTHOP_LENGTH,
     398             :                                 "%s: %s: invalid MP nexthop length (AFI IP): %u",
     399             :                                 __func__, peer->host, nhlen);
     400           0 :                         stream_free(s);
     401           0 :                         return NULL;
     402             :                 }
     403             : 
     404          59 :                 stream_get_from(&v4nh, s, offset_nh, IPV4_MAX_BYTELEN);
     405          59 :                 mod_v4nh = &v4nh;
     406             : 
     407             :                 /*
     408             :                  * If route-map has set the nexthop, that is normally
     409             :                  * used; if it is specified as peer-address, the peering
     410             :                  * address is picked up. Otherwise, if NH is unavailable
     411             :                  * from attribute, the peering addr is picked up; the
     412             :                  * "NH unavailable" case also covers next-hop-self and
     413             :                  * some other scenarios - see subgroup_announce_check().
     414             :                  * In all other cases, use the nexthop carried in the
     415             :                  * attribute unless it is EBGP non-multiaccess and there
     416             :                  * is no next-hop-unchanged setting or the peer is EBGP
     417             :                  * and the route-map that changed the next-hop value
     418             :                  * was applied inbound rather than outbound. Updates to
     419             :                  * an EBGP peer should only modify the next-hop if it
     420             :                  * was set in an outbound route-map to that peer.
     421             :                  * Note: It is assumed route-map cannot set the nexthop
     422             :                  * to an invalid value.
     423             :                  */
     424          59 :                 if (route_map_sets_nh
     425           0 :                     && ((peer->sort != BGP_PEER_EBGP)
     426           0 :                         || ROUTE_MAP_OUT(filter))) {
     427           0 :                         if (CHECK_FLAG(
     428             :                                     vec->flags,
     429             :                                     BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) {
     430           0 :                                 mod_v4nh = &peer->nexthop.v4;
     431           0 :                                 nh_modified = 1;
     432             :                         }
     433          59 :                 } else if (v4nh.s_addr == INADDR_ANY) {
     434          57 :                         mod_v4nh = &peer->nexthop.v4;
     435          57 :                         nh_modified = 1;
     436           2 :                 } else if (peer->sort == BGP_PEER_EBGP
     437           2 :                            && (bgp_multiaccess_check_v4(v4nh, peer) == 0)
     438           0 :                            && !CHECK_FLAG(vec->flags,
     439             :                                           BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED)
     440           0 :                            && !peer_af_flag_check(
     441             :                                    peer, paf->afi, paf->safi,
     442             :                                    PEER_FLAG_NEXTHOP_UNCHANGED)) {
     443             :                         /* NOTE: not handling case where NH has new AFI
     444             :                          */
     445           0 :                         mod_v4nh = &peer->nexthop.v4;
     446           0 :                         nh_modified = 1;
     447             :                 }
     448             : 
     449          57 :                 if (nh_modified) /* allow for VPN RD */
     450          57 :                         stream_put_in_addr_at(s, offset_nh, mod_v4nh);
     451             : 
     452          59 :                 if (bgp_debug_update(peer, NULL, NULL, 0))
     453          59 :                         zlog_debug("u%" PRIu64 ":s%" PRIu64
     454             :                                    " %s send UPDATE w/ nexthop %pI4%s",
     455             :                                    PAF_SUBGRP(paf)->update_group->id,
     456             :                                    PAF_SUBGRP(paf)->id, peer->host, mod_v4nh,
     457             :                                    (nhlen == BGP_ATTR_NHLEN_VPNV4 ? " and RD"
     458             :                                                                   : ""));
     459          15 :         } else if (nhafi == AFI_IP6) {
     460          15 :                 struct in6_addr v6nhglobal, *mod_v6nhg;
     461          15 :                 struct in6_addr v6nhlocal, *mod_v6nhl;
     462          15 :                 int gnh_modified, lnh_modified;
     463          15 :                 size_t offset_nhglobal = vec->offset + 1;
     464          15 :                 size_t offset_nhlocal = vec->offset + 1;
     465             : 
     466          15 :                 gnh_modified = lnh_modified = 0;
     467          15 :                 mod_v6nhg = &v6nhglobal;
     468          15 :                 mod_v6nhl = &v6nhlocal;
     469             : 
     470          15 :                 route_map_sets_nh =
     471             :                         (CHECK_FLAG(vec->flags,
     472             :                                     BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED) ||
     473             :                          CHECK_FLAG(
     474             :                                  vec->flags,
     475          15 :                                  BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED) ||
     476             :                          CHECK_FLAG(vec->flags,
     477             :                                     BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS));
     478             : 
     479             :                 /*
     480             :                  * The logic here is rather similar to that for IPv4, the
     481             :                  * additional work being to handle 1 or 2 nexthops.
     482             :                  * Also, 3rd party nexthop is not propagated for EBGP
     483             :                  * right now.
     484             :                  */
     485          15 :                 switch (nhlen) {
     486             :                 case BGP_ATTR_NHLEN_IPV6_GLOBAL:
     487             :                         break;
     488          15 :                 case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
     489          15 :                         offset_nhlocal += IPV6_MAX_BYTELEN;
     490          15 :                         break;
     491           0 :                 case BGP_ATTR_NHLEN_VPNV6_GLOBAL:
     492           0 :                         offset_nhglobal += 8;
     493           0 :                         break;
     494           0 :                 case BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL:
     495           0 :                         offset_nhglobal += 8;
     496           0 :                         offset_nhlocal += 8 * 2 + IPV6_MAX_BYTELEN;
     497           0 :                         break;
     498           0 :                 default:
     499             :                         /* TODO: handle IPv4 nexthops */
     500           0 :                         flog_warn(
     501             :                                 EC_BGP_INVALID_NEXTHOP_LENGTH,
     502             :                                 "%s: %s: invalid MP nexthop length (AFI IP6): %u",
     503             :                                 __func__, peer->host, nhlen);
     504           0 :                         stream_free(s);
     505           0 :                         return NULL;
     506             :                 }
     507             : 
     508          15 :                 stream_get_from(&v6nhglobal, s, offset_nhglobal,
     509             :                                 IPV6_MAX_BYTELEN);
     510             : 
     511             :                 /*
     512             :                  * Updates to an EBGP peer should only modify the
     513             :                  * next-hop if it was set in an outbound route-map
     514             :                  * to that peer.
     515             :                  */
     516          15 :                 if (route_map_sets_nh
     517           5 :                     && ((peer->sort != BGP_PEER_EBGP)
     518           5 :                         || ROUTE_MAP_OUT(filter))) {
     519           5 :                         if (CHECK_FLAG(
     520             :                                     vec->flags,
     521             :                                     BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS)) {
     522           0 :                                 mod_v6nhg = &peer->nexthop.v6_global;
     523           0 :                                 gnh_modified = 1;
     524             :                         }
     525          10 :                 } else if (IN6_IS_ADDR_UNSPECIFIED(&v6nhglobal)) {
     526          10 :                         mod_v6nhg = &peer->nexthop.v6_global;
     527          10 :                         gnh_modified = 1;
     528           0 :                 } else if ((peer->sort == BGP_PEER_EBGP)
     529           0 :                            && (!bgp_multiaccess_check_v6(v6nhglobal, peer))
     530           0 :                            && !CHECK_FLAG(vec->flags,
     531             :                                           BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED)
     532           0 :                            && !peer_af_flag_check(
     533             :                                    peer, paf->afi, paf->safi,
     534             :                                    PEER_FLAG_NEXTHOP_UNCHANGED)) {
     535             :                         /* NOTE: not handling case where NH has new AFI
     536             :                          */
     537           0 :                         mod_v6nhg = &peer->nexthop.v6_global;
     538           0 :                         gnh_modified = 1;
     539             :                 }
     540             : 
     541          15 :                 if (IN6_IS_ADDR_UNSPECIFIED(mod_v6nhg)) {
     542           0 :                         if (peer->nexthop.v4.s_addr != INADDR_ANY) {
     543           0 :                                 ipv4_to_ipv4_mapped_ipv6(mod_v6nhg,
     544             :                                                          peer->nexthop.v4);
     545             :                         }
     546             :                 }
     547             : 
     548          15 :                 if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) {
     549           0 :                         mod_v6nhg = &peer->nexthop.v6_global;
     550           0 :                         gnh_modified = 1;
     551             :                 }
     552             : 
     553          15 :                 if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
     554          15 :                     || nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
     555          15 :                         stream_get_from(&v6nhlocal, s, offset_nhlocal,
     556             :                                         IPV6_MAX_BYTELEN);
     557          15 :                         if (IN6_IS_ADDR_UNSPECIFIED(&v6nhlocal)) {
     558          15 :                                 mod_v6nhl = &peer->nexthop.v6_local;
     559          15 :                                 lnh_modified = 1;
     560             :                         }
     561             :                 }
     562             : 
     563          15 :                 if (gnh_modified)
     564          10 :                         stream_put_in6_addr_at(s, offset_nhglobal, mod_v6nhg);
     565          15 :                 if (lnh_modified)
     566          15 :                         stream_put_in6_addr_at(s, offset_nhlocal, mod_v6nhl);
     567             : 
     568          15 :                 if (bgp_debug_update(peer, NULL, NULL, 0)) {
     569           0 :                         if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
     570             :                             || nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL)
     571           0 :                                 zlog_debug(
     572             :                                         "u%" PRIu64 ":s%" PRIu64
     573             :                                         " %s send UPDATE w/ mp_nexthops %pI6, %pI6%s",
     574             :                                         PAF_SUBGRP(paf)->update_group->id,
     575             :                                         PAF_SUBGRP(paf)->id, peer->host,
     576             :                                         mod_v6nhg, mod_v6nhl,
     577             :                                         (nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL
     578             :                                                  ? " and RD"
     579             :                                                  : ""));
     580             :                         else
     581          15 :                                 zlog_debug(
     582             :                                         "u%" PRIu64 ":s%" PRIu64
     583             :                                         " %s send UPDATE w/ mp_nexthop %pI6%s",
     584             :                                         PAF_SUBGRP(paf)->update_group->id,
     585             :                                         PAF_SUBGRP(paf)->id, peer->host,
     586             :                                         mod_v6nhg,
     587             :                                         (nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL
     588             :                                                  ? " and RD"
     589             :                                                  : ""));
     590             :                 }
     591           0 :         } else if (paf->afi == AFI_L2VPN) {
     592           0 :                 struct in_addr v4nh, *mod_v4nh;
     593           0 :                 int nh_modified = 0;
     594             : 
     595           0 :                 stream_get_from(&v4nh, s, vec->offset + 1, 4);
     596           0 :                 mod_v4nh = &v4nh;
     597             : 
     598             :                 /* No route-map changes allowed for EVPN nexthops. */
     599           0 :                 if (v4nh.s_addr == INADDR_ANY) {
     600           0 :                         mod_v4nh = &peer->nexthop.v4;
     601           0 :                         nh_modified = 1;
     602             :                 }
     603             : 
     604           0 :                 if (nh_modified)
     605           0 :                         stream_put_in_addr_at(s, vec->offset + 1, mod_v4nh);
     606             : 
     607           0 :                 if (bgp_debug_update(peer, NULL, NULL, 0))
     608           0 :                         zlog_debug("u%" PRIu64 ":s%" PRIu64
     609             :                                    " %s send UPDATE w/ nexthop %pI4",
     610             :                                    PAF_SUBGRP(paf)->update_group->id,
     611             :                                    PAF_SUBGRP(paf)->id, peer->host, mod_v4nh);
     612             :         }
     613             : 
     614             :         return s;
     615             : }
     616             : 
     617             : /*
     618             :  * Update the vecarr offsets to go beyond 'pos' bytes, i.e. add 'pos'
     619             :  * to each offset.
     620             :  */
     621          15 : static void bpacket_attr_vec_arr_update(struct bpacket_attr_vec_arr *vecarr,
     622             :                                         size_t pos)
     623             : {
     624          15 :         int i;
     625             : 
     626          15 :         if (!vecarr)
     627             :                 return;
     628             : 
     629          15 :         for (i = 0; i < BGP_ATTR_VEC_MAX; i++)
     630          15 :                 vecarr->entries[i].offset += pos;
     631             : }
     632             : 
     633             : /*
     634             :  * Return if there are packets to build for this subgroup.
     635             :  */
     636         209 : bool subgroup_packets_to_build(struct update_subgroup *subgrp)
     637             : {
     638         209 :         struct bgp_advertise *adv;
     639             : 
     640         209 :         if (!subgrp)
     641             :                 return false;
     642             : 
     643         209 :         adv = bgp_adv_fifo_first(&subgrp->sync->withdraw);
     644           0 :         if (adv)
     645             :                 return true;
     646             : 
     647         209 :         adv = bgp_adv_fifo_first(&subgrp->sync->update);
     648           1 :         if (adv)
     649           1 :                 return true;
     650             : 
     651             :         return false;
     652             : }
     653             : 
     654             : /* Make BGP update packet.  */
     655         283 : struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
     656             : {
     657         283 :         struct bpacket_attr_vec_arr vecarr;
     658         283 :         struct bpacket *pkt;
     659         283 :         struct peer *peer;
     660         283 :         struct stream *s;
     661         283 :         struct stream *snlri;
     662         283 :         struct stream *packet;
     663         283 :         struct bgp_adj_out *adj;
     664         283 :         struct bgp_advertise *adv;
     665         283 :         struct bgp_dest *dest = NULL;
     666         283 :         struct bgp_path_info *path = NULL;
     667         283 :         bgp_size_t total_attr_len = 0;
     668         283 :         unsigned long attrlen_pos = 0;
     669         283 :         size_t mpattrlen_pos = 0;
     670         283 :         size_t mpattr_pos = 0;
     671         283 :         afi_t afi;
     672         283 :         safi_t safi;
     673         283 :         int space_remaining = 0;
     674         283 :         int space_needed = 0;
     675         283 :         char send_attr_str[BUFSIZ];
     676         283 :         int send_attr_printed = 0;
     677         283 :         int num_pfx = 0;
     678         283 :         bool addpath_capable = false;
     679         283 :         int addpath_overhead = 0;
     680         283 :         uint32_t addpath_tx_id = 0;
     681         283 :         struct prefix_rd *prd = NULL;
     682         283 :         mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL;
     683         283 :         uint32_t num_labels = 0;
     684             : 
     685         283 :         if (!subgrp)
     686             :                 return NULL;
     687             : 
     688         496 :         if (bpacket_queue_is_full(SUBGRP_INST(subgrp), SUBGRP_PKTQ(subgrp)))
     689             :                 return NULL;
     690             : 
     691         283 :         peer = SUBGRP_PEER(subgrp);
     692         283 :         afi = SUBGRP_AFI(subgrp);
     693         283 :         safi = SUBGRP_SAFI(subgrp);
     694         283 :         s = subgrp->work;
     695         283 :         stream_reset(s);
     696         283 :         snlri = subgrp->scratch;
     697         283 :         stream_reset(snlri);
     698             : 
     699         283 :         bpacket_attr_vec_arr_reset(&vecarr);
     700             : 
     701         566 :         addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
     702         283 :         addpath_overhead = addpath_capable ? BGP_ADDPATH_ID_LEN : 0;
     703             : 
     704         283 :         adv = bgp_adv_fifo_first(&subgrp->sync->update);
     705         371 :         while (adv) {
     706          88 :                 const struct prefix *dest_p;
     707             : 
     708          88 :                 assert(adv->dest);
     709          88 :                 dest = adv->dest;
     710          88 :                 dest_p = bgp_dest_get_prefix(dest);
     711          88 :                 adj = adv->adj;
     712          88 :                 addpath_tx_id = adj->addpath_tx_id;
     713          88 :                 path = adv->pathi;
     714             : 
     715          88 :                 space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
     716          88 :                                   - BGP_MAX_PACKET_SIZE_OVERFLOW;
     717         176 :                 space_needed =
     718             :                         BGP_NLRI_LENGTH + addpath_overhead
     719          88 :                         + bgp_packet_mpattr_prefix_size(afi, safi, dest_p);
     720             : 
     721             :                 /* When remaining space can't include NLRI and it's length.  */
     722          88 :                 if (space_remaining < space_needed)
     723             :                         break;
     724             : 
     725             :                 /* If packet is empty, set attribute. */
     726          88 :                 if (stream_empty(s)) {
     727          70 :                         struct peer *from = NULL;
     728             : 
     729          70 :                         if (path)
     730          70 :                                 from = path->peer;
     731             : 
     732             :                         /* 1: Write the BGP message header - 16 bytes marker, 2
     733             :                          * bytes length,
     734             :                          * one byte message type.
     735             :                          */
     736          70 :                         bgp_packet_set_marker(s, BGP_MSG_UPDATE);
     737             : 
     738             :                         /* 2: withdrawn routes length */
     739          70 :                         stream_putw(s, 0);
     740             : 
     741             :                         /* 3: total attributes length - attrlen_pos stores the
     742             :                          * position */
     743          70 :                         attrlen_pos = stream_get_endp(s);
     744          70 :                         stream_putw(s, 0);
     745             : 
     746             :                         /* 4: if there is MP_REACH_NLRI attribute, that should
     747             :                          * be the first
     748             :                          * attribute, according to
     749             :                          * draft-ietf-idr-error-handling. Save the
     750             :                          * position.
     751             :                          */
     752          70 :                         mpattr_pos = stream_get_endp(s);
     753             : 
     754             :                         /* 5: Encode all the attributes, except MP_REACH_NLRI
     755             :                          * attr. */
     756         140 :                         total_attr_len = bgp_packet_attribute(
     757          70 :                                 NULL, peer, s, adv->baa->attr, &vecarr, NULL,
     758             :                                 afi, safi, from, NULL, NULL, 0, 0, 0, path);
     759             : 
     760          70 :                         space_remaining =
     761          70 :                                 STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
     762          70 :                                 - BGP_MAX_PACKET_SIZE_OVERFLOW;
     763         140 :                         space_needed = BGP_NLRI_LENGTH + addpath_overhead
     764          70 :                                        + bgp_packet_mpattr_prefix_size(
     765             :                                                afi, safi, dest_p);
     766             : 
     767             :                         /* If the attributes alone do not leave any room for
     768             :                          * NLRI then
     769             :                          * return */
     770          70 :                         if (space_remaining < space_needed) {
     771           0 :                                 flog_err(
     772             :                                         EC_BGP_UPDGRP_ATTR_LEN,
     773             :                                         "u%" PRIu64 ":s%" PRIu64" attributes too long, cannot send UPDATE",
     774             :                                         subgrp->update_group->id, subgrp->id);
     775             : 
     776             :                                 /* Flush the FIFO update queue */
     777           0 :                                 while (adv)
     778           0 :                                         adv = bgp_advertise_clean_subgroup(
     779             :                                                 subgrp, adj);
     780             :                                 return NULL;
     781             :                         }
     782             : 
     783          70 :                         if (BGP_DEBUG(update, UPDATE_OUT)
     784          70 :                             || BGP_DEBUG(update, UPDATE_PREFIX)) {
     785           0 :                                 memset(send_attr_str, 0, BUFSIZ);
     786           0 :                                 send_attr_printed = 0;
     787           0 :                                 bgp_dump_attr(adv->baa->attr, send_attr_str,
     788             :                                               sizeof(send_attr_str));
     789             :                         }
     790             :                 }
     791             : 
     792          88 :                 if ((afi == AFI_IP && safi == SAFI_UNICAST)
     793          73 :                     && !peer_cap_enhe(peer, afi, safi))
     794          73 :                         stream_put_prefix_addpath(s, dest_p, addpath_capable,
     795             :                                                   addpath_tx_id);
     796             :                 else {
     797             :                         /* Encode the prefix in MP_REACH_NLRI attribute */
     798          15 :                         if (dest->pdest)
     799           0 :                                 prd = (struct prefix_rd *)bgp_dest_get_prefix(
     800           0 :                                         dest->pdest);
     801             : 
     802          15 :                         if (safi == SAFI_LABELED_UNICAST) {
     803           0 :                                 label = bgp_adv_label(dest, path, peer, afi,
     804             :                                                       safi);
     805           0 :                                 label_pnt = &label;
     806           0 :                                 num_labels = 1;
     807          15 :                         } else if (path && path->extra) {
     808           0 :                                 label_pnt = &path->extra->label[0];
     809           0 :                                 num_labels = path->extra->num_labels;
     810             :                         }
     811             : 
     812          15 :                         if (stream_empty(snlri))
     813          15 :                                 mpattrlen_pos = bgp_packet_mpattr_start(
     814             :                                         snlri, peer, afi, safi, &vecarr,
     815          15 :                                         adv->baa->attr);
     816             : 
     817          15 :                         bgp_packet_mpattr_prefix(snlri, afi, safi, dest_p, prd,
     818             :                                                  label_pnt, num_labels,
     819             :                                                  addpath_capable, addpath_tx_id,
     820          15 :                                                  adv->baa->attr);
     821             :                 }
     822             : 
     823          88 :                 num_pfx++;
     824             : 
     825          88 :                 if (bgp_debug_update(NULL, dest_p, subgrp->update_group, 0)) {
     826           0 :                         char pfx_buf[BGP_PRD_PATH_STRLEN];
     827             : 
     828           0 :                         if (!send_attr_printed) {
     829           0 :                                 zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE w/ attr: %s",
     830             :                                            subgrp->update_group->id, subgrp->id,
     831             :                                            send_attr_str);
     832           0 :                                 if (!stream_empty(snlri)) {
     833           0 :                                         iana_afi_t pkt_afi;
     834           0 :                                         iana_safi_t pkt_safi;
     835             : 
     836           0 :                                         pkt_afi = afi_int2iana(afi);
     837           0 :                                         pkt_safi = safi_int2iana(safi);
     838           0 :                                         zlog_debug(
     839             :                                                 "u%" PRIu64 ":s%" PRIu64
     840             :                                                 " send MP_REACH for afi/safi %s/%s",
     841             :                                                 subgrp->update_group->id,
     842             :                                                 subgrp->id,
     843             :                                                 iana_afi2str(pkt_afi),
     844             :                                                 iana_safi2str(pkt_safi));
     845             :                                 }
     846             : 
     847             :                                 send_attr_printed = 1;
     848             :                         }
     849             : 
     850           0 :                         bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p,
     851             :                                                 label_pnt, num_labels,
     852             :                                                 addpath_capable, addpath_tx_id,
     853           0 :                                                 &adv->baa->attr->evpn_overlay,
     854             :                                                 pfx_buf, sizeof(pfx_buf));
     855           0 :                         zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %s",
     856             :                                    subgrp->update_group->id, subgrp->id,
     857             :                                    pfx_buf);
     858             :                 }
     859             : 
     860             :                 /* Synchnorize attribute.  */
     861          88 :                 if (adj->attr)
     862          19 :                         bgp_attr_unintern(&adj->attr);
     863             :                 else
     864          69 :                         subgrp->scount++;
     865             : 
     866          88 :                 adj->attr = bgp_attr_intern(adv->baa->attr);
     867          88 :                 adv = bgp_advertise_clean_subgroup(subgrp, adj);
     868             :         }
     869             : 
     870         283 :         if (!stream_empty(s)) {
     871          70 :                 if (!stream_empty(snlri)) {
     872          15 :                         bgp_packet_mpattr_end(snlri, mpattrlen_pos);
     873          15 :                         total_attr_len += stream_get_endp(snlri);
     874             :                 }
     875             : 
     876             :                 /* set the total attribute length correctly */
     877          70 :                 stream_putw_at(s, attrlen_pos, total_attr_len);
     878             : 
     879          70 :                 if (!stream_empty(snlri)) {
     880          15 :                         packet = stream_dupcat(s, snlri, mpattr_pos);
     881          15 :                         bpacket_attr_vec_arr_update(&vecarr, mpattr_pos);
     882             :                 } else
     883          55 :                         packet = stream_dup(s);
     884          70 :                 bgp_packet_set_size(packet);
     885          70 :                 if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
     886           0 :                         zlog_debug(
     887             :                                 "u%" PRIu64 ":s%" PRIu64
     888             :                                 " send UPDATE len %zd (max message len: %hu) numpfx %d",
     889             :                                 subgrp->update_group->id, subgrp->id,
     890             :                                 (stream_get_endp(packet)
     891             :                                  - stream_get_getp(packet)),
     892             :                                 peer->max_packet_size, num_pfx);
     893          70 :                 pkt = bpacket_queue_add(SUBGRP_PKTQ(subgrp), packet, &vecarr);
     894          70 :                 stream_reset(s);
     895          70 :                 stream_reset(snlri);
     896          70 :                 return pkt;
     897             :         }
     898             :         return NULL;
     899             : }
     900             : 
     901             : /* Make BGP withdraw packet.  */
     902             : /* For ipv4 unicast:
     903             :    16-octet marker | 2-octet length | 1-octet type |
     904             :     2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0)
     905             : */
     906             : /* For other afi/safis:
     907             :    16-octet marker | 2-octet length | 1-octet type |
     908             :     2-octet withdrawn route length (=0) | 2-octet attrlen |
     909             :      mp_unreach attr type | attr len | afi | safi | withdrawn prefixes
     910             : */
     911         283 : struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
     912             : {
     913         283 :         struct bpacket *pkt;
     914         283 :         struct stream *s;
     915         283 :         struct bgp_adj_out *adj;
     916         283 :         struct bgp_advertise *adv;
     917         283 :         struct peer *peer;
     918         283 :         struct bgp_dest *dest;
     919         283 :         bgp_size_t unfeasible_len;
     920         283 :         bgp_size_t total_attr_len;
     921         283 :         size_t mp_start = 0;
     922         283 :         size_t attrlen_pos = 0;
     923         283 :         size_t mplen_pos = 0;
     924         283 :         uint8_t first_time = 1;
     925         283 :         afi_t afi;
     926         283 :         safi_t safi;
     927         283 :         int space_remaining = 0;
     928         283 :         int space_needed = 0;
     929         283 :         int num_pfx = 0;
     930         283 :         bool addpath_capable = false;
     931         283 :         int addpath_overhead = 0;
     932         283 :         uint32_t addpath_tx_id = 0;
     933         283 :         const struct prefix_rd *prd = NULL;
     934             : 
     935             : 
     936         283 :         if (!subgrp)
     937             :                 return NULL;
     938             : 
     939         566 :         if (bpacket_queue_is_full(SUBGRP_INST(subgrp), SUBGRP_PKTQ(subgrp)))
     940             :                 return NULL;
     941             : 
     942         283 :         peer = SUBGRP_PEER(subgrp);
     943         283 :         afi = SUBGRP_AFI(subgrp);
     944         283 :         safi = SUBGRP_SAFI(subgrp);
     945         283 :         s = subgrp->work;
     946         283 :         stream_reset(s);
     947         283 :         addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
     948         283 :         addpath_overhead = addpath_capable ? BGP_ADDPATH_ID_LEN : 0;
     949             : 
     950         283 :         while ((adv = bgp_adv_fifo_first(&subgrp->sync->withdraw)) != NULL) {
     951           0 :                 const struct prefix *dest_p;
     952             : 
     953           0 :                 assert(adv->dest);
     954           0 :                 adj = adv->adj;
     955           0 :                 dest = adv->dest;
     956           0 :                 dest_p = bgp_dest_get_prefix(dest);
     957           0 :                 addpath_tx_id = adj->addpath_tx_id;
     958             : 
     959           0 :                 space_remaining =
     960           0 :                         STREAM_WRITEABLE(s) - BGP_MAX_PACKET_SIZE_OVERFLOW;
     961           0 :                 space_needed =
     962             :                         BGP_NLRI_LENGTH + addpath_overhead + BGP_TOTAL_ATTR_LEN
     963           0 :                         + bgp_packet_mpattr_prefix_size(afi, safi, dest_p);
     964             : 
     965           0 :                 if (space_remaining < space_needed)
     966             :                         break;
     967             : 
     968           0 :                 if (stream_empty(s)) {
     969           0 :                         bgp_packet_set_marker(s, BGP_MSG_UPDATE);
     970           0 :                         stream_putw(s, 0); /* unfeasible routes length */
     971             :                 } else
     972             :                         first_time = 0;
     973             : 
     974           0 :                 if (afi == AFI_IP && safi == SAFI_UNICAST
     975           0 :                     && !peer_cap_enhe(peer, afi, safi))
     976           0 :                         stream_put_prefix_addpath(s, dest_p, addpath_capable,
     977             :                                                   addpath_tx_id);
     978             :                 else {
     979           0 :                         if (dest->pdest)
     980           0 :                                 prd = (struct prefix_rd *)bgp_dest_get_prefix(
     981           0 :                                         dest->pdest);
     982             : 
     983             :                         /* If first time, format the MP_UNREACH header
     984             :                          */
     985           0 :                         if (first_time) {
     986           0 :                                 iana_afi_t pkt_afi;
     987           0 :                                 iana_safi_t pkt_safi;
     988             : 
     989           0 :                                 pkt_afi = afi_int2iana(afi);
     990           0 :                                 pkt_safi = safi_int2iana(safi);
     991             : 
     992           0 :                                 attrlen_pos = stream_get_endp(s);
     993             :                                 /* total attr length = 0 for now.
     994             :                                  * reevaluate later */
     995           0 :                                 stream_putw(s, 0);
     996           0 :                                 mp_start = stream_get_endp(s);
     997           0 :                                 mplen_pos = bgp_packet_mpunreach_start(s, afi,
     998             :                                                                        safi);
     999           0 :                                 if (bgp_debug_update(NULL, NULL,
    1000             :                                                      subgrp->update_group, 0))
    1001           0 :                                         zlog_debug(
    1002             :                                                 "u%" PRIu64 ":s%" PRIu64
    1003             :                                                 " send MP_UNREACH for afi/safi %s/%s",
    1004             :                                                 subgrp->update_group->id,
    1005             :                                                 subgrp->id,
    1006             :                                                 iana_afi2str(pkt_afi),
    1007             :                                                 iana_safi2str(pkt_safi));
    1008             :                         }
    1009             : 
    1010           0 :                         bgp_packet_mpunreach_prefix(s, dest_p, afi, safi, prd,
    1011             :                                                     NULL, 0, addpath_capable,
    1012             :                                                     addpath_tx_id, NULL);
    1013             :                 }
    1014             : 
    1015           0 :                 num_pfx++;
    1016             : 
    1017           0 :                 if (bgp_debug_update(NULL, dest_p, subgrp->update_group, 0)) {
    1018           0 :                         char pfx_buf[BGP_PRD_PATH_STRLEN];
    1019             : 
    1020           0 :                         bgp_debug_rdpfxpath2str(afi, safi, prd, dest_p, NULL, 0,
    1021             :                                                 addpath_capable, addpath_tx_id,
    1022             :                                                 NULL, pfx_buf, sizeof(pfx_buf));
    1023           0 :                         zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE %s -- unreachable",
    1024             :                                    subgrp->update_group->id, subgrp->id,
    1025             :                                    pfx_buf);
    1026             :                 }
    1027             : 
    1028           0 :                 subgrp->scount--;
    1029             : 
    1030           0 :                 bgp_adj_out_remove_subgroup(dest, adj, subgrp);
    1031             :         }
    1032             : 
    1033         283 :         if (!stream_empty(s)) {
    1034           0 :                 if (afi == AFI_IP && safi == SAFI_UNICAST
    1035           0 :                     && !peer_cap_enhe(peer, afi, safi)) {
    1036           0 :                         unfeasible_len = stream_get_endp(s) - BGP_HEADER_SIZE
    1037           0 :                                          - BGP_UNFEASIBLE_LEN;
    1038           0 :                         stream_putw_at(s, BGP_HEADER_SIZE, unfeasible_len);
    1039           0 :                         stream_putw(s, 0);
    1040             :                 } else {
    1041             :                         /* Set the mp_unreach attr's length */
    1042           0 :                         bgp_packet_mpunreach_end(s, mplen_pos);
    1043             : 
    1044             :                         /* Set total path attribute length. */
    1045           0 :                         total_attr_len = stream_get_endp(s) - mp_start;
    1046           0 :                         stream_putw_at(s, attrlen_pos, total_attr_len);
    1047             :                 }
    1048           0 :                 bgp_packet_set_size(s);
    1049           0 :                 if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
    1050           0 :                         zlog_debug("u%" PRIu64 ":s%" PRIu64" send UPDATE (withdraw) len %zd numpfx %d",
    1051             :                                    subgrp->update_group->id, subgrp->id,
    1052             :                                    (stream_get_endp(s) - stream_get_getp(s)),
    1053             :                                    num_pfx);
    1054           0 :                 pkt = bpacket_queue_add(SUBGRP_PKTQ(subgrp), stream_dup(s),
    1055             :                                         NULL);
    1056           0 :                 stream_reset(s);
    1057           0 :                 return pkt;
    1058             :         }
    1059             : 
    1060             :         return NULL;
    1061             : }
    1062             : 
    1063           2 : void subgroup_default_update_packet(struct update_subgroup *subgrp,
    1064             :                                     struct attr *attr, struct peer *from)
    1065             : {
    1066           2 :         struct stream *s;
    1067           2 :         struct peer *peer;
    1068           2 :         struct prefix p;
    1069           2 :         unsigned long pos;
    1070           2 :         bgp_size_t total_attr_len;
    1071           2 :         afi_t afi;
    1072           2 :         safi_t safi;
    1073           2 :         struct bpacket_attr_vec_arr vecarr;
    1074           2 :         bool addpath_capable = false;
    1075           2 :         uint8_t default_originate_label[4] = {0x80, 0x00, 0x00};
    1076           2 :         mpls_label_t *label = NULL;
    1077           2 :         uint32_t num_labels = 0;
    1078             : 
    1079           2 :         if (DISABLE_BGP_ANNOUNCE)
    1080           0 :                 return;
    1081             : 
    1082           2 :         if (!subgrp)
    1083           0 :                 return;
    1084             : 
    1085           2 :         peer = SUBGRP_PEER(subgrp);
    1086           2 :         afi = SUBGRP_AFI(subgrp);
    1087           2 :         safi = SUBGRP_SAFI(subgrp);
    1088           2 :         bpacket_attr_vec_arr_reset(&vecarr);
    1089           4 :         addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
    1090             : 
    1091           2 :         if (safi == SAFI_LABELED_UNICAST) {
    1092           0 :                 label = (mpls_label_t *)default_originate_label;
    1093           0 :                 num_labels = 1;
    1094             :         }
    1095             : 
    1096           2 :         memset(&p, 0, sizeof(p));
    1097           2 :         p.family = afi2family(afi);
    1098           2 :         p.prefixlen = 0;
    1099             : 
    1100             :         /* Logging the attribute. */
    1101           2 :         if (bgp_debug_update(NULL, &p, subgrp->update_group, 0)) {
    1102           0 :                 char attrstr[BUFSIZ];
    1103             :                 /* ' with addpath ID '          17
    1104             :                  * max strlen of uint32       + 10
    1105             :                  * +/- (just in case)         +  1
    1106             :                  * null terminator            +  1
    1107             :                  * ============================ 29 */
    1108           0 :                 char tx_id_buf[30];
    1109             : 
    1110           0 :                 attrstr[0] = '\0';
    1111             : 
    1112           0 :                 bgp_dump_attr(attr, attrstr, sizeof(attrstr));
    1113             : 
    1114           0 :                 if (addpath_capable)
    1115           0 :                         snprintf(tx_id_buf, sizeof(tx_id_buf),
    1116             :                                  " with addpath ID %u",
    1117             :                                  BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
    1118             :                 else
    1119           0 :                         tx_id_buf[0] = '\0';
    1120             : 
    1121           0 :                 zlog_debug("u%" PRIu64 ":s%" PRIu64 " send UPDATE %pFX%s %s",
    1122             :                            (SUBGRP_UPDGRP(subgrp))->id, subgrp->id, &p,
    1123             :                            tx_id_buf, attrstr);
    1124             :         }
    1125             : 
    1126           2 :         s = stream_new(peer->max_packet_size);
    1127             : 
    1128             :         /* Make BGP update packet. */
    1129           2 :         bgp_packet_set_marker(s, BGP_MSG_UPDATE);
    1130             : 
    1131             :         /* Unfeasible Routes Length. */
    1132           2 :         stream_putw(s, 0);
    1133             : 
    1134             :         /* Make place for total attribute length.  */
    1135           2 :         pos = stream_get_endp(s);
    1136           2 :         stream_putw(s, 0);
    1137           2 :         total_attr_len = bgp_packet_attribute(
    1138             :                 NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, label,
    1139             :                 num_labels, addpath_capable,
    1140             :                 BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL);
    1141             : 
    1142             :         /* Set Total Path Attribute Length. */
    1143           2 :         stream_putw_at(s, pos, total_attr_len);
    1144             : 
    1145             :         /* NLRI set. */
    1146           2 :         if (p.family == AF_INET && safi == SAFI_UNICAST
    1147           2 :             && !peer_cap_enhe(peer, afi, safi))
    1148           2 :                 stream_put_prefix_addpath(
    1149             :                         s, &p, addpath_capable,
    1150             :                         BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
    1151             : 
    1152             :         /* Set size. */
    1153           2 :         bgp_packet_set_size(s);
    1154             : 
    1155           2 :         (void)bpacket_queue_add(SUBGRP_PKTQ(subgrp), s, &vecarr);
    1156           2 :         subgroup_trigger_write(subgrp);
    1157             : 
    1158           2 :         if (!CHECK_FLAG(subgrp->sflags,
    1159             :                         SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED)) {
    1160           2 :                 subgrp->scount++;
    1161           2 :                 SET_FLAG(subgrp->sflags, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED);
    1162             :         }
    1163             : }
    1164             : 
    1165           2 : void subgroup_default_withdraw_packet(struct update_subgroup *subgrp)
    1166             : {
    1167           2 :         struct peer *peer;
    1168           2 :         struct stream *s;
    1169           2 :         struct prefix p;
    1170           2 :         unsigned long attrlen_pos = 0;
    1171           2 :         unsigned long cp;
    1172           2 :         bgp_size_t unfeasible_len;
    1173           2 :         bgp_size_t total_attr_len = 0;
    1174           2 :         size_t mp_start = 0;
    1175           2 :         size_t mplen_pos = 0;
    1176           2 :         afi_t afi;
    1177           2 :         safi_t safi;
    1178           2 :         bool addpath_capable = false;
    1179             : 
    1180           2 :         if (DISABLE_BGP_ANNOUNCE)
    1181             :                 return;
    1182             : 
    1183           2 :         peer = SUBGRP_PEER(subgrp);
    1184           2 :         afi = SUBGRP_AFI(subgrp);
    1185           2 :         safi = SUBGRP_SAFI(subgrp);
    1186           2 :         addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
    1187             : 
    1188           2 :         memset(&p, 0, sizeof(p));
    1189           2 :         p.family = afi2family(afi);
    1190           2 :         p.prefixlen = 0;
    1191             : 
    1192           2 :         if (bgp_debug_update(NULL, &p, subgrp->update_group, 0)) {
    1193             :                 /* ' with addpath ID '          17
    1194             :                  * max strlen of uint32       + 10
    1195             :                  * +/- (just in case)         +  1
    1196             :                  * null terminator            +  1
    1197             :                  * ============================ 29 */
    1198           0 :                 char tx_id_buf[30];
    1199             : 
    1200           0 :                 if (addpath_capable)
    1201           0 :                         snprintf(tx_id_buf, sizeof(tx_id_buf),
    1202             :                                  " with addpath ID %u",
    1203             :                                  BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
    1204             : 
    1205           0 :                 zlog_debug("u%" PRIu64 ":s%" PRIu64
    1206             :                            " send UPDATE %pFX%s -- unreachable",
    1207             :                            (SUBGRP_UPDGRP(subgrp))->id, subgrp->id, &p,
    1208             :                            tx_id_buf);
    1209             :         }
    1210             : 
    1211           2 :         s = stream_new(peer->max_packet_size);
    1212             : 
    1213             :         /* Make BGP update packet. */
    1214           2 :         bgp_packet_set_marker(s, BGP_MSG_UPDATE);
    1215             : 
    1216           2 :         /* Unfeasible Routes Length. */;
    1217           2 :         cp = stream_get_endp(s);
    1218           2 :         stream_putw(s, 0);
    1219             : 
    1220             :         /* Withdrawn Routes. */
    1221           2 :         if (p.family == AF_INET && safi == SAFI_UNICAST
    1222           2 :             && !peer_cap_enhe(peer, afi, safi)) {
    1223           2 :                 stream_put_prefix_addpath(
    1224             :                         s, &p, addpath_capable,
    1225             :                         BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
    1226             : 
    1227           2 :                 unfeasible_len = stream_get_endp(s) - cp - 2;
    1228             : 
    1229             :                 /* Set unfeasible len.  */
    1230           2 :                 stream_putw_at(s, cp, unfeasible_len);
    1231             : 
    1232             :                 /* Set total path attribute length. */
    1233           2 :                 stream_putw(s, 0);
    1234             :         } else {
    1235           0 :                 attrlen_pos = stream_get_endp(s);
    1236           0 :                 stream_putw(s, 0);
    1237           0 :                 mp_start = stream_get_endp(s);
    1238           0 :                 mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
    1239           0 :                 bgp_packet_mpunreach_prefix(
    1240             :                         s, &p, afi, safi, NULL, NULL, 0, addpath_capable,
    1241             :                         BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE, NULL);
    1242             : 
    1243             :                 /* Set the mp_unreach attr's length */
    1244           0 :                 bgp_packet_mpunreach_end(s, mplen_pos);
    1245             : 
    1246             :                 /* Set total path attribute length. */
    1247           0 :                 total_attr_len = stream_get_endp(s) - mp_start;
    1248           0 :                 stream_putw_at(s, attrlen_pos, total_attr_len);
    1249             :         }
    1250             : 
    1251           2 :         bgp_packet_set_size(s);
    1252             : 
    1253           2 :         (void)bpacket_queue_add(SUBGRP_PKTQ(subgrp), s, NULL);
    1254           2 :         subgroup_trigger_write(subgrp);
    1255             : 
    1256           2 :         if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED)) {
    1257           0 :                 subgrp->scount--;
    1258           0 :                 UNSET_FLAG(subgrp->sflags,
    1259             :                            SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED);
    1260             :         }
    1261             : }
    1262             : 
    1263             : static void
    1264          72 : bpacket_vec_arr_inherit_attr_flags(struct bpacket_attr_vec_arr *vecarr,
    1265             :                                    enum bpacket_attr_vec_type type,
    1266             :                                    struct attr *attr)
    1267             : {
    1268          72 :         if (CHECK_FLAG(attr->rmap_change_flags,
    1269             :                        BATTR_RMAP_NEXTHOP_PEER_ADDRESS))
    1270           0 :                 SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
    1271             :                          BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS);
    1272             : 
    1273          72 :         if (CHECK_FLAG(attr->rmap_change_flags, BATTR_REFLECTED))
    1274           0 :                 SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
    1275             :                          BPKT_ATTRVEC_FLAGS_REFLECTED);
    1276             : 
    1277          72 :         if (CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_NEXTHOP_UNCHANGED))
    1278           0 :                 SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
    1279             :                          BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED);
    1280             : 
    1281          72 :         if (CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_IPV4_NHOP_CHANGED))
    1282           0 :                 SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
    1283             :                          BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED);
    1284             : 
    1285          72 :         if (CHECK_FLAG(attr->rmap_change_flags,
    1286             :                        BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED))
    1287           5 :                 SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
    1288             :                          BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED);
    1289             : 
    1290          72 :         if (CHECK_FLAG(attr->rmap_change_flags, BATTR_RMAP_VPNV4_NHOP_CHANGED))
    1291           0 :                 SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
    1292             :                          BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED);
    1293             : 
    1294          72 :         if (CHECK_FLAG(attr->rmap_change_flags,
    1295             :                        BATTR_RMAP_VPNV6_GLOBAL_NHOP_CHANGED))
    1296           0 :                 SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
    1297             :                          BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED);
    1298             : 
    1299          72 :         if (CHECK_FLAG(attr->rmap_change_flags,
    1300             :                        BATTR_RMAP_IPV6_LL_NHOP_CHANGED))
    1301           0 :                 SET_FLAG(vecarr->entries[BGP_ATTR_VEC_NH].flags,
    1302             :                          BPKT_ATTRVEC_FLAGS_RMAP_IPV6_LNH_CHANGED);
    1303          72 : }
    1304             : 
    1305             : /* Reset the Attributes vector array. The vector array is used to override
    1306             :  * certain output parameters in the packet for a particular peer
    1307             :  */
    1308         319 : void bpacket_attr_vec_arr_reset(struct bpacket_attr_vec_arr *vecarr)
    1309             : {
    1310         319 :         int i;
    1311             : 
    1312           0 :         if (!vecarr)
    1313             :                 return;
    1314             : 
    1315             :         i = 0;
    1316           0 :         while (i < BGP_ATTR_VEC_MAX) {
    1317         319 :                 vecarr->entries[i].flags = 0;
    1318         319 :                 vecarr->entries[i].offset = 0;
    1319         319 :                 i++;
    1320             :         }
    1321             : }
    1322             : 
    1323             : /* Setup a particular node entry in the vecarr */
    1324          72 : void bpacket_attr_vec_arr_set_vec(struct bpacket_attr_vec_arr *vecarr,
    1325             :                                   enum bpacket_attr_vec_type type,
    1326             :                                   struct stream *s, struct attr *attr)
    1327             : {
    1328          72 :         if (!vecarr)
    1329             :                 return;
    1330          72 :         assert(type < BGP_ATTR_VEC_MAX);
    1331             : 
    1332          72 :         SET_FLAG(vecarr->entries[type].flags, BPKT_ATTRVEC_FLAGS_UPDATED);
    1333          72 :         vecarr->entries[type].offset = stream_get_endp(s);
    1334          72 :         if (attr)
    1335          72 :                 bpacket_vec_arr_inherit_attr_flags(vecarr, type, attr);
    1336             : }

Generated by: LCOV version v1.16-topotato