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