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