]>
Commit | Line | Data |
---|---|---|
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 | ********************/ | |
67 | struct bpacket * | |
68 | bpacket_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 | ||
78 | void | |
79 | bpacket_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 | ||
87 | void | |
88 | bpacket_queue_init (struct bpacket_queue *q) | |
89 | { | |
90 | TAILQ_INIT (&(q->pkts)); | |
91 | } | |
92 | ||
93 | /* | |
94 | * bpacket_queue_sanity_check | |
95 | */ | |
96 | void | |
97 | bpacket_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 | */ | |
134 | static void | |
135 | bpacket_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 | */ | |
158 | struct bpacket * | |
159 | bpacket_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 | ||
201 | struct bpacket * | |
202 | bpacket_queue_first (struct bpacket_queue *q) | |
203 | { | |
204 | return (TAILQ_FIRST (&(q->pkts))); | |
205 | } | |
206 | ||
207 | struct bpacket * | |
208 | bpacket_queue_last (struct bpacket_queue *q) | |
209 | { | |
210 | return TAILQ_LAST (&(q->pkts), pkt_queue); | |
211 | } | |
212 | ||
213 | struct bpacket * | |
214 | bpacket_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 | ||
227 | unsigned int | |
228 | bpacket_queue_length (struct bpacket_queue *q) | |
229 | { | |
230 | return q->curr_count - 1; | |
231 | } | |
232 | ||
233 | unsigned int | |
234 | bpacket_queue_hwm_length (struct bpacket_queue *q) | |
235 | { | |
236 | return q->hwm_count - 1; | |
237 | } | |
238 | ||
239 | int | |
240 | bpacket_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 | ||
247 | void | |
248 | bpacket_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 | */ | |
260 | void | |
261 | bpacket_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 | */ | |
279 | static int | |
280 | bpacket_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 | ||
313 | void | |
314 | bpacket_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 | */ | |
344 | void | |
345 | bpacket_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 | ||
360 | unsigned int | |
361 | bpacket_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 | */ | |
387 | void | |
388 | bpacket_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 | ||
408 | struct stream * | |
409 | bpacket_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 | */ | |
585 | static void | |
586 | bpacket_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 | */ | |
600 | int | |
601 | subgroup_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 |
619 | static void |
620 | bgp_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. */ |
631 | struct bpacket * | |
632 | subgroup_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 | */ | |
864 | struct bpacket * | |
865 | subgroup_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 | ||
1007 | void | |
1008 | subgroup_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 | ||
1085 | void | |
1086 | subgroup_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 | ||
1173 | static void | |
1174 | bpacket_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 | */ | |
1211 | void | |
1212 | bpacket_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 */ | |
1229 | void | |
1230 | bpacket_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 | } |