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 133 : struct bpacket *bpacket_alloc(void)
69 : {
70 133 : struct bpacket *pkt;
71 :
72 0 : pkt = XCALLOC(MTYPE_BGP_PACKET, sizeof(struct bpacket));
73 :
74 133 : return pkt;
75 : }
76 :
77 133 : void bpacket_free(struct bpacket *pkt)
78 : {
79 133 : if (pkt->buffer)
80 88 : stream_free(pkt->buffer);
81 133 : pkt->buffer = NULL;
82 133 : XFREE(MTYPE_BGP_PACKET, pkt);
83 133 : }
84 :
85 45 : void bpacket_queue_init(struct bpacket_queue *q)
86 : {
87 45 : TAILQ_INIT(&(q->pkts));
88 45 : }
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 133 : static void bpacket_queue_add_packet(struct bpacket_queue *q,
99 : struct bpacket *pkt)
100 : {
101 133 : struct bpacket *last_pkt;
102 :
103 133 : if (TAILQ_EMPTY(&(q->pkts)))
104 45 : TAILQ_INSERT_TAIL(&(q->pkts), pkt, pkt_train);
105 : else {
106 88 : last_pkt = bpacket_queue_last(q);
107 88 : TAILQ_INSERT_AFTER(&(q->pkts), last_pkt, pkt, pkt_train);
108 : }
109 133 : q->curr_count++;
110 133 : if (q->hwm_count < q->curr_count)
111 81 : q->hwm_count = q->curr_count;
112 133 : }
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 133 : struct bpacket *bpacket_queue_add(struct bpacket_queue *q, struct stream *s,
122 : struct bpacket_attr_vec_arr *vecarrp)
123 : {
124 133 : struct bpacket *pkt;
125 133 : struct bpacket *last_pkt;
126 :
127 :
128 133 : pkt = bpacket_alloc();
129 133 : if (TAILQ_EMPTY(&(q->pkts))) {
130 45 : pkt->ver = 1;
131 45 : pkt->buffer = s;
132 45 : if (vecarrp)
133 0 : memcpy(&pkt->arr, vecarrp,
134 : sizeof(struct bpacket_attr_vec_arr));
135 : else
136 90 : bpacket_attr_vec_arr_reset(&pkt->arr);
137 45 : bpacket_queue_add_packet(q, pkt);
138 45 : return pkt;
139 : }
140 :
141 : /*
142 : * Fill in the new information into the current sentinel and create a
143 : * new sentinel.
144 : */
145 88 : last_pkt = bpacket_queue_last(q);
146 0 : assert(last_pkt->buffer == NULL);
147 88 : last_pkt->buffer = s;
148 88 : if (vecarrp)
149 86 : memcpy(&last_pkt->arr, vecarrp,
150 : sizeof(struct bpacket_attr_vec_arr));
151 : else
152 90 : bpacket_attr_vec_arr_reset(&last_pkt->arr);
153 :
154 88 : pkt->ver = last_pkt->ver;
155 88 : pkt->ver++;
156 88 : bpacket_queue_add_packet(q, pkt);
157 :
158 88 : return last_pkt;
159 : }
160 :
161 626 : struct bpacket *bpacket_queue_first(struct bpacket_queue *q)
162 : {
163 626 : return (TAILQ_FIRST(&(q->pkts)));
164 : }
165 :
166 177 : struct bpacket *bpacket_queue_last(struct bpacket_queue *q)
167 : {
168 176 : return TAILQ_LAST(&(q->pkts), pkt_queue);
169 : }
170 :
171 178 : struct bpacket *bpacket_queue_remove(struct bpacket_queue *q)
172 : {
173 178 : struct bpacket *first;
174 :
175 178 : first = bpacket_queue_first(q);
176 178 : if (first) {
177 133 : TAILQ_REMOVE(&(q->pkts), first, pkt_train);
178 133 : q->curr_count--;
179 : }
180 178 : 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 1012 : bool bpacket_queue_is_full(struct bgp *bgp, struct bpacket_queue *q)
194 : {
195 288 : if (q->curr_count >= bgp->default_subgroup_pkt_queue_max)
196 0 : return true;
197 : return false;
198 : }
199 :
200 143 : void bpacket_add_peer(struct bpacket *pkt, struct peer_af *paf)
201 : {
202 143 : if (!pkt || !paf)
203 : return;
204 :
205 143 : LIST_INSERT_HEAD(&(pkt->peers), paf, pkt_train);
206 143 : paf->next_pkt_to_send = pkt;
207 : }
208 :
209 : /*
210 : * bpacket_queue_cleanup
211 : */
212 45 : void bpacket_queue_cleanup(struct bpacket_queue *q)
213 : {
214 45 : struct bpacket *pkt;
215 :
216 90 : while ((pkt = bpacket_queue_remove(q))) {
217 45 : bpacket_free(pkt);
218 : }
219 45 : }
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 143 : static int bpacket_queue_compact(struct bpacket_queue *q)
230 : {
231 143 : int num_deleted;
232 143 : struct bpacket *pkt, *removed_pkt;
233 :
234 143 : num_deleted = 0;
235 :
236 319 : while (1) {
237 319 : pkt = bpacket_queue_first(q);
238 231 : if (!pkt)
239 : break;
240 :
241 : /*
242 : * Don't delete the sentinel.
243 : */
244 231 : if (!pkt->buffer)
245 : break;
246 :
247 92 : if (!LIST_EMPTY(&(pkt->peers)))
248 : break;
249 :
250 88 : removed_pkt = bpacket_queue_remove(q);
251 88 : assert(pkt == removed_pkt);
252 88 : bpacket_free(removed_pkt);
253 :
254 88 : num_deleted++;
255 : }
256 :
257 143 : return num_deleted;
258 : }
259 :
260 92 : void bpacket_queue_advance_peer(struct peer_af *paf)
261 : {
262 92 : struct bpacket *pkt;
263 92 : struct bpacket *old_pkt;
264 :
265 92 : old_pkt = paf->next_pkt_to_send;
266 92 : if (old_pkt->buffer == NULL)
267 : /* Already at end of list */
268 : return;
269 :
270 92 : LIST_REMOVE(paf, pkt_train);
271 92 : pkt = TAILQ_NEXT(old_pkt, pkt_train);
272 92 : bpacket_add_peer(pkt, paf);
273 :
274 92 : 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 88 : 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 51 : void bpacket_queue_remove_peer(struct peer_af *paf)
291 : {
292 51 : struct bpacket_queue *q;
293 :
294 51 : q = PAF_PKTQ(paf);
295 51 : assert(q);
296 :
297 51 : LIST_REMOVE(paf, pkt_train);
298 51 : paf->next_pkt_to_send = NULL;
299 :
300 51 : bpacket_queue_compact(q);
301 51 : }
302 :
303 202 : unsigned int bpacket_queue_virtual_length(struct peer_af *paf)
304 : {
305 202 : struct bpacket *pkt;
306 202 : struct bpacket *last;
307 202 : struct bpacket_queue *q;
308 :
309 202 : pkt = paf->next_pkt_to_send;
310 202 : 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 92 : struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
348 : struct peer_af *paf)
349 : {
350 92 : struct stream *s = NULL;
351 92 : bpacket_attr_vec *vec;
352 92 : struct peer *peer;
353 92 : struct bgp_filter *filter;
354 :
355 92 : s = stream_dup(pkt->buffer);
356 92 : peer = PAF_PEER(paf);
357 :
358 92 : vec = &pkt->arr.entries[BGP_ATTR_VEC_NH];
359 :
360 92 : if (!CHECK_FLAG(vec->flags, BPKT_ATTRVEC_FLAGS_UPDATED))
361 : return s;
362 :
363 90 : uint8_t nhlen;
364 90 : afi_t nhafi;
365 90 : int route_map_sets_nh;
366 :
367 90 : nhlen = stream_getc_from(s, vec->offset);
368 90 : filter = &peer->filter[paf->afi][paf->safi];
369 :
370 90 : if (peer_cap_enhe(peer, paf->afi, paf->safi))
371 : nhafi = AFI_IP6;
372 : else
373 90 : nhafi = BGP_NEXTHOP_AFI_FROM_NHLEN(nhlen);
374 :
375 80 : if (nhafi == AFI_IP) {
376 80 : struct in_addr v4nh, *mod_v4nh;
377 80 : int nh_modified = 0;
378 80 : size_t offset_nh = vec->offset + 1;
379 :
380 80 : route_map_sets_nh =
381 : (CHECK_FLAG(vec->flags,
382 : BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED) ||
383 : CHECK_FLAG(vec->flags,
384 80 : BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED) ||
385 : CHECK_FLAG(vec->flags,
386 : BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS));
387 :
388 80 : 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 80 : stream_get_from(&v4nh, s, offset_nh, IPV4_MAX_BYTELEN);
405 80 : 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 80 : 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 80 : } else if (v4nh.s_addr == INADDR_ANY) {
434 74 : mod_v4nh = &peer->nexthop.v4;
435 74 : nh_modified = 1;
436 6 : } else if (peer->sort == BGP_PEER_EBGP
437 6 : && (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 74 : if (nh_modified) /* allow for VPN RD */
450 74 : stream_put_in_addr_at(s, offset_nh, mod_v4nh);
451 :
452 80 : if (bgp_debug_update(peer, NULL, NULL, 0))
453 80 : 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 10 : } else if (nhafi == AFI_IP6) {
460 10 : struct in6_addr v6nhglobal, *mod_v6nhg;
461 10 : struct in6_addr v6nhlocal, *mod_v6nhl;
462 10 : int gnh_modified, lnh_modified;
463 10 : size_t offset_nhglobal = vec->offset + 1;
464 10 : size_t offset_nhlocal = vec->offset + 1;
465 :
466 10 : gnh_modified = lnh_modified = 0;
467 10 : mod_v6nhg = &v6nhglobal;
468 10 : mod_v6nhl = &v6nhlocal;
469 :
470 10 : route_map_sets_nh =
471 : (CHECK_FLAG(vec->flags,
472 : BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED) ||
473 : CHECK_FLAG(
474 : vec->flags,
475 10 : 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 10 : switch (nhlen) {
486 : case BGP_ATTR_NHLEN_IPV6_GLOBAL:
487 : break;
488 10 : case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL:
489 10 : offset_nhlocal += IPV6_MAX_BYTELEN;
490 10 : 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 10 : 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 10 : 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 5 : } else if (IN6_IS_ADDR_UNSPECIFIED(&v6nhglobal)) {
526 5 : mod_v6nhg = &peer->nexthop.v6_global;
527 5 : 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 10 : 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 10 : if (IS_MAPPED_IPV6(&peer->nexthop.v6_global)) {
549 0 : mod_v6nhg = &peer->nexthop.v6_global;
550 0 : gnh_modified = 1;
551 : }
552 :
553 10 : if (nhlen == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL
554 10 : || nhlen == BGP_ATTR_NHLEN_VPNV6_GLOBAL_AND_LL) {
555 10 : stream_get_from(&v6nhlocal, s, offset_nhlocal,
556 : IPV6_MAX_BYTELEN);
557 10 : if (IN6_IS_ADDR_UNSPECIFIED(&v6nhlocal)) {
558 10 : mod_v6nhl = &peer->nexthop.v6_local;
559 10 : lnh_modified = 1;
560 : }
561 : }
562 :
563 10 : if (gnh_modified)
564 5 : stream_put_in6_addr_at(s, offset_nhglobal, mod_v6nhg);
565 10 : if (lnh_modified)
566 10 : stream_put_in6_addr_at(s, offset_nhlocal, mod_v6nhl);
567 :
568 10 : 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 10 : 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 10 : static void bpacket_attr_vec_arr_update(struct bpacket_attr_vec_arr *vecarr,
622 : size_t pos)
623 : {
624 10 : int i;
625 :
626 10 : if (!vecarr)
627 : return;
628 :
629 10 : for (i = 0; i < BGP_ATTR_VEC_MAX; i++)
630 10 : vecarr->entries[i].offset += pos;
631 : }
632 :
633 : /*
634 : * Return if there are packets to build for this subgroup.
635 : */
636 288 : bool subgroup_packets_to_build(struct update_subgroup *subgrp)
637 : {
638 288 : struct bgp_advertise *adv;
639 :
640 288 : if (!subgrp)
641 : return false;
642 :
643 288 : adv = bgp_adv_fifo_first(&subgrp->sync->withdraw);
644 0 : if (adv)
645 : return true;
646 :
647 288 : 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 362 : struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
656 : {
657 362 : struct bpacket_attr_vec_arr vecarr;
658 362 : struct bpacket *pkt;
659 362 : struct peer *peer;
660 362 : struct stream *s;
661 362 : struct stream *snlri;
662 362 : struct stream *packet;
663 362 : struct bgp_adj_out *adj;
664 362 : struct bgp_advertise *adv;
665 362 : struct bgp_dest *dest = NULL;
666 362 : struct bgp_path_info *path = NULL;
667 362 : bgp_size_t total_attr_len = 0;
668 362 : unsigned long attrlen_pos = 0;
669 362 : size_t mpattrlen_pos = 0;
670 362 : size_t mpattr_pos = 0;
671 362 : afi_t afi;
672 362 : safi_t safi;
673 362 : int space_remaining = 0;
674 362 : int space_needed = 0;
675 362 : char send_attr_str[BUFSIZ];
676 362 : int send_attr_printed = 0;
677 362 : int num_pfx = 0;
678 362 : bool addpath_capable = false;
679 362 : int addpath_overhead = 0;
680 362 : uint32_t addpath_tx_id = 0;
681 362 : struct prefix_rd *prd = NULL;
682 362 : mpls_label_t label = MPLS_INVALID_LABEL, *label_pnt = NULL;
683 362 : uint32_t num_labels = 0;
684 :
685 362 : if (!subgrp)
686 : return NULL;
687 :
688 640 : if (bpacket_queue_is_full(SUBGRP_INST(subgrp), SUBGRP_PKTQ(subgrp)))
689 : return NULL;
690 :
691 362 : peer = SUBGRP_PEER(subgrp);
692 362 : afi = SUBGRP_AFI(subgrp);
693 362 : safi = SUBGRP_SAFI(subgrp);
694 362 : s = subgrp->work;
695 362 : stream_reset(s);
696 362 : snlri = subgrp->scratch;
697 362 : stream_reset(snlri);
698 :
699 362 : bpacket_attr_vec_arr_reset(&vecarr);
700 :
701 724 : addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
702 362 : addpath_overhead = addpath_capable ? BGP_ADDPATH_ID_LEN : 0;
703 :
704 362 : adv = bgp_adv_fifo_first(&subgrp->sync->update);
705 472 : while (adv) {
706 110 : const struct prefix *dest_p;
707 :
708 110 : assert(adv->dest);
709 110 : dest = adv->dest;
710 110 : dest_p = bgp_dest_get_prefix(dest);
711 110 : adj = adv->adj;
712 110 : addpath_tx_id = adj->addpath_tx_id;
713 110 : path = adv->pathi;
714 :
715 110 : space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
716 110 : - BGP_MAX_PACKET_SIZE_OVERFLOW;
717 220 : space_needed =
718 : BGP_NLRI_LENGTH + addpath_overhead
719 110 : + bgp_packet_mpattr_prefix_size(afi, safi, dest_p);
720 :
721 : /* When remaining space can't include NLRI and it's length. */
722 110 : if (space_remaining < space_needed)
723 : break;
724 :
725 : /* If packet is empty, set attribute. */
726 110 : if (stream_empty(s)) {
727 84 : struct peer *from = NULL;
728 :
729 84 : if (path)
730 84 : 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 84 : bgp_packet_set_marker(s, BGP_MSG_UPDATE);
737 :
738 : /* 2: withdrawn routes length */
739 84 : stream_putw(s, 0);
740 :
741 : /* 3: total attributes length - attrlen_pos stores the
742 : * position */
743 84 : attrlen_pos = stream_get_endp(s);
744 84 : 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 84 : mpattr_pos = stream_get_endp(s);
753 :
754 : /* 5: Encode all the attributes, except MP_REACH_NLRI
755 : * attr. */
756 168 : total_attr_len = bgp_packet_attribute(
757 84 : NULL, peer, s, adv->baa->attr, &vecarr, NULL,
758 : afi, safi, from, NULL, NULL, 0, 0, 0, path);
759 :
760 84 : space_remaining =
761 84 : STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
762 84 : - BGP_MAX_PACKET_SIZE_OVERFLOW;
763 168 : space_needed = BGP_NLRI_LENGTH + addpath_overhead
764 84 : + 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 84 : 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 84 : if (BGP_DEBUG(update, UPDATE_OUT)
784 84 : || 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 110 : if ((afi == AFI_IP && safi == SAFI_UNICAST)
793 100 : && !peer_cap_enhe(peer, afi, safi))
794 100 : 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 10 : if (dest->pdest)
799 0 : prd = (struct prefix_rd *)bgp_dest_get_prefix(
800 0 : dest->pdest);
801 :
802 10 : 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 10 : } else if (path && path->extra) {
808 0 : label_pnt = &path->extra->label[0];
809 0 : num_labels = path->extra->num_labels;
810 : }
811 :
812 10 : if (stream_empty(snlri))
813 10 : mpattrlen_pos = bgp_packet_mpattr_start(
814 : snlri, peer, afi, safi, &vecarr,
815 10 : adv->baa->attr);
816 :
817 10 : bgp_packet_mpattr_prefix(snlri, afi, safi, dest_p, prd,
818 : label_pnt, num_labels,
819 : addpath_capable, addpath_tx_id,
820 10 : adv->baa->attr);
821 : }
822 :
823 110 : num_pfx++;
824 :
825 110 : 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 110 : if (adj->attr)
862 14 : bgp_attr_unintern(&adj->attr);
863 : else
864 96 : subgrp->scount++;
865 :
866 110 : adj->attr = bgp_attr_intern(adv->baa->attr);
867 110 : adv = bgp_advertise_clean_subgroup(subgrp, adj);
868 : }
869 :
870 362 : if (!stream_empty(s)) {
871 84 : if (!stream_empty(snlri)) {
872 10 : bgp_packet_mpattr_end(snlri, mpattrlen_pos);
873 10 : total_attr_len += stream_get_endp(snlri);
874 : }
875 :
876 : /* set the total attribute length correctly */
877 84 : stream_putw_at(s, attrlen_pos, total_attr_len);
878 :
879 84 : if (!stream_empty(snlri)) {
880 10 : packet = stream_dupcat(s, snlri, mpattr_pos);
881 10 : bpacket_attr_vec_arr_update(&vecarr, mpattr_pos);
882 : } else
883 74 : packet = stream_dup(s);
884 84 : bgp_packet_set_size(packet);
885 84 : 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 84 : pkt = bpacket_queue_add(SUBGRP_PKTQ(subgrp), packet, &vecarr);
894 84 : stream_reset(s);
895 84 : stream_reset(snlri);
896 84 : 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 362 : struct bpacket *subgroup_withdraw_packet(struct update_subgroup *subgrp)
912 : {
913 362 : struct bpacket *pkt;
914 362 : struct stream *s;
915 362 : struct bgp_adj_out *adj;
916 362 : struct bgp_advertise *adv;
917 362 : struct peer *peer;
918 362 : struct bgp_dest *dest;
919 362 : bgp_size_t unfeasible_len;
920 362 : bgp_size_t total_attr_len;
921 362 : size_t mp_start = 0;
922 362 : size_t attrlen_pos = 0;
923 362 : size_t mplen_pos = 0;
924 362 : uint8_t first_time = 1;
925 362 : afi_t afi;
926 362 : safi_t safi;
927 362 : int space_remaining = 0;
928 362 : int space_needed = 0;
929 362 : int num_pfx = 0;
930 362 : bool addpath_capable = false;
931 362 : int addpath_overhead = 0;
932 362 : uint32_t addpath_tx_id = 0;
933 362 : const struct prefix_rd *prd = NULL;
934 :
935 :
936 362 : if (!subgrp)
937 : return NULL;
938 :
939 724 : if (bpacket_queue_is_full(SUBGRP_INST(subgrp), SUBGRP_PKTQ(subgrp)))
940 : return NULL;
941 :
942 362 : peer = SUBGRP_PEER(subgrp);
943 362 : afi = SUBGRP_AFI(subgrp);
944 362 : safi = SUBGRP_SAFI(subgrp);
945 362 : s = subgrp->work;
946 362 : stream_reset(s);
947 362 : addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
948 362 : addpath_overhead = addpath_capable ? BGP_ADDPATH_ID_LEN : 0;
949 :
950 362 : 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 362 : 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 86 : 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 86 : 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 86 : 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 86 : 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 86 : 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 86 : 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 86 : 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 86 : 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 86 : 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 86 : }
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 411 : void bpacket_attr_vec_arr_reset(struct bpacket_attr_vec_arr *vecarr)
1309 : {
1310 411 : int i;
1311 :
1312 0 : if (!vecarr)
1313 : return;
1314 :
1315 : i = 0;
1316 0 : while (i < BGP_ATTR_VEC_MAX) {
1317 411 : vecarr->entries[i].flags = 0;
1318 411 : vecarr->entries[i].offset = 0;
1319 411 : i++;
1320 : }
1321 : }
1322 :
1323 : /* Setup a particular node entry in the vecarr */
1324 86 : 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 86 : if (!vecarr)
1329 : return;
1330 86 : assert(type < BGP_ATTR_VEC_MAX);
1331 :
1332 86 : SET_FLAG(vecarr->entries[type].flags, BPKT_ATTRVEC_FLAGS_UPDATED);
1333 86 : vecarr->entries[type].offset = stream_get_endp(s);
1334 86 : if (attr)
1335 86 : bpacket_vec_arr_inherit_attr_flags(vecarr, type, attr);
1336 : }
|