Line data Source code
1 : /**
2 : * bgp_updgrp.c: BGP update group structures
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 "jhash.h"
45 : #include "queue.h"
46 :
47 : #include "bgpd/bgpd.h"
48 : #include "bgpd/bgp_table.h"
49 : #include "bgpd/bgp_debug.h"
50 : #include "bgpd/bgp_errors.h"
51 : #include "bgpd/bgp_fsm.h"
52 : #include "bgpd/bgp_addpath.h"
53 : #include "bgpd/bgp_advertise.h"
54 : #include "bgpd/bgp_packet.h"
55 : #include "bgpd/bgp_updgrp.h"
56 : #include "bgpd/bgp_route.h"
57 : #include "bgpd/bgp_filter.h"
58 : #include "bgpd/bgp_io.h"
59 :
60 : /********************
61 : * PRIVATE FUNCTIONS
62 : ********************/
63 :
64 : /**
65 : * assign a unique ID to update group and subgroup. Mostly for display/
66 : * debugging purposes. It's a 64-bit space - used leisurely without a
67 : * worry about its wrapping and about filling gaps. While at it, timestamp
68 : * the creation.
69 : */
70 2 : static void update_group_checkin(struct update_group *updgrp)
71 : {
72 2 : updgrp->id = ++bm->updgrp_idspace;
73 2 : updgrp->uptime = monotime(NULL);
74 2 : }
75 :
76 2 : static void update_subgroup_checkin(struct update_subgroup *subgrp,
77 : struct update_group *updgrp)
78 : {
79 2 : subgrp->id = ++bm->subgrp_idspace;
80 2 : subgrp->uptime = monotime(NULL);
81 2 : }
82 :
83 2 : static void sync_init(struct update_subgroup *subgrp,
84 : struct update_group *updgrp)
85 : {
86 2 : struct peer *peer = UPDGRP_PEER(updgrp);
87 :
88 4 : subgrp->sync =
89 2 : XCALLOC(MTYPE_BGP_SYNCHRONISE, sizeof(struct bgp_synchronize));
90 2 : bgp_adv_fifo_init(&subgrp->sync->update);
91 2 : bgp_adv_fifo_init(&subgrp->sync->withdraw);
92 2 : bgp_adv_fifo_init(&subgrp->sync->withdraw_low);
93 4 : subgrp->hash =
94 2 : hash_create(bgp_advertise_attr_hash_key,
95 : bgp_advertise_attr_hash_cmp, "BGP SubGroup Hash");
96 :
97 : /* We use a larger buffer for subgrp->work in the event that:
98 : * - We RX a BGP_UPDATE where the attributes alone are just
99 : * under 4096 or 65535 (if Extended Message capability negotiated).
100 : * - The user configures an outbound route-map that does many as-path
101 : * prepends or adds many communities. At most they can have
102 : * CMD_ARGC_MAX
103 : * args in a route-map so there is a finite limit on how large they
104 : * can
105 : * make the attributes.
106 : *
107 : * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid
108 : * bounds
109 : * checking for every single attribute as we construct an UPDATE.
110 : */
111 4 : subgrp->work = stream_new(peer->max_packet_size
112 2 : + BGP_MAX_PACKET_SIZE_OVERFLOW);
113 2 : subgrp->scratch = stream_new(peer->max_packet_size);
114 2 : }
115 :
116 2 : static void sync_delete(struct update_subgroup *subgrp)
117 : {
118 2 : XFREE(MTYPE_BGP_SYNCHRONISE, subgrp->sync);
119 2 : if (subgrp->hash) {
120 2 : hash_clean(subgrp->hash,
121 : (void (*)(void *))bgp_advertise_attr_free);
122 2 : hash_free(subgrp->hash);
123 : }
124 2 : subgrp->hash = NULL;
125 2 : if (subgrp->work)
126 2 : stream_free(subgrp->work);
127 2 : subgrp->work = NULL;
128 2 : if (subgrp->scratch)
129 2 : stream_free(subgrp->scratch);
130 2 : subgrp->scratch = NULL;
131 2 : }
132 :
133 : /**
134 : * conf_copy
135 : *
136 : * copy only those fields that are relevant to update group match
137 : */
138 6 : static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
139 : safi_t safi)
140 : {
141 6 : struct bgp_filter *srcfilter;
142 6 : struct bgp_filter *dstfilter;
143 :
144 6 : srcfilter = &src->filter[afi][safi];
145 6 : dstfilter = &dst->filter[afi][safi];
146 :
147 6 : dst->bgp = src->bgp;
148 6 : dst->sort = src->sort;
149 6 : dst->as = src->as;
150 6 : dst->v_routeadv = src->v_routeadv;
151 6 : dst->flags = src->flags;
152 6 : dst->af_flags[afi][safi] = src->af_flags[afi][safi];
153 6 : dst->pmax_out[afi][safi] = src->pmax_out[afi][safi];
154 6 : dst->max_packet_size = src->max_packet_size;
155 6 : XFREE(MTYPE_BGP_PEER_HOST, dst->host);
156 :
157 6 : dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host);
158 6 : dst->cap = src->cap;
159 6 : dst->af_cap[afi][safi] = src->af_cap[afi][safi];
160 6 : dst->afc_nego[afi][safi] = src->afc_nego[afi][safi];
161 6 : dst->orf_plist[afi][safi] = src->orf_plist[afi][safi];
162 6 : dst->addpath_type[afi][safi] = src->addpath_type[afi][safi];
163 6 : dst->local_as = src->local_as;
164 6 : dst->change_local_as = src->change_local_as;
165 6 : dst->shared_network = src->shared_network;
166 6 : dst->local_role = src->local_role;
167 6 : dst->as_path_loop_detection = src->as_path_loop_detection;
168 :
169 6 : if (src->soo[afi][safi]) {
170 0 : ecommunity_free(&dst->soo[afi][safi]);
171 0 : dst->soo[afi][safi] = ecommunity_dup(src->soo[afi][safi]);
172 : }
173 :
174 6 : memcpy(&(dst->nexthop), &(src->nexthop), sizeof(struct bgp_nexthop));
175 :
176 6 : dst->group = src->group;
177 :
178 6 : if (src->default_rmap[afi][safi].name) {
179 0 : dst->default_rmap[afi][safi].name =
180 0 : XSTRDUP(MTYPE_ROUTE_MAP_NAME,
181 : src->default_rmap[afi][safi].name);
182 0 : dst->default_rmap[afi][safi].map =
183 0 : src->default_rmap[afi][safi].map;
184 : }
185 :
186 6 : if (DISTRIBUTE_OUT_NAME(srcfilter)) {
187 0 : DISTRIBUTE_OUT_NAME(dstfilter) = XSTRDUP(
188 : MTYPE_BGP_FILTER_NAME, DISTRIBUTE_OUT_NAME(srcfilter));
189 0 : DISTRIBUTE_OUT(dstfilter) = DISTRIBUTE_OUT(srcfilter);
190 : }
191 :
192 6 : if (PREFIX_LIST_OUT_NAME(srcfilter)) {
193 0 : PREFIX_LIST_OUT_NAME(dstfilter) = XSTRDUP(
194 : MTYPE_BGP_FILTER_NAME, PREFIX_LIST_OUT_NAME(srcfilter));
195 0 : PREFIX_LIST_OUT(dstfilter) = PREFIX_LIST_OUT(srcfilter);
196 : }
197 :
198 6 : if (FILTER_LIST_OUT_NAME(srcfilter)) {
199 0 : FILTER_LIST_OUT_NAME(dstfilter) = XSTRDUP(
200 : MTYPE_BGP_FILTER_NAME, FILTER_LIST_OUT_NAME(srcfilter));
201 0 : FILTER_LIST_OUT(dstfilter) = FILTER_LIST_OUT(srcfilter);
202 : }
203 :
204 6 : if (ROUTE_MAP_OUT_NAME(srcfilter)) {
205 0 : ROUTE_MAP_OUT_NAME(dstfilter) = XSTRDUP(
206 : MTYPE_BGP_FILTER_NAME, ROUTE_MAP_OUT_NAME(srcfilter));
207 0 : ROUTE_MAP_OUT(dstfilter) = ROUTE_MAP_OUT(srcfilter);
208 : }
209 :
210 6 : if (UNSUPPRESS_MAP_NAME(srcfilter)) {
211 0 : UNSUPPRESS_MAP_NAME(dstfilter) = XSTRDUP(
212 : MTYPE_BGP_FILTER_NAME, UNSUPPRESS_MAP_NAME(srcfilter));
213 0 : UNSUPPRESS_MAP(dstfilter) = UNSUPPRESS_MAP(srcfilter);
214 : }
215 :
216 6 : if (ADVERTISE_MAP_NAME(srcfilter)) {
217 0 : ADVERTISE_MAP_NAME(dstfilter) = XSTRDUP(
218 : MTYPE_BGP_FILTER_NAME, ADVERTISE_MAP_NAME(srcfilter));
219 0 : ADVERTISE_MAP(dstfilter) = ADVERTISE_MAP(srcfilter);
220 0 : ADVERTISE_CONDITION(dstfilter) = ADVERTISE_CONDITION(srcfilter);
221 : }
222 :
223 6 : if (CONDITION_MAP_NAME(srcfilter)) {
224 0 : CONDITION_MAP_NAME(dstfilter) = XSTRDUP(
225 : MTYPE_BGP_FILTER_NAME, CONDITION_MAP_NAME(srcfilter));
226 0 : CONDITION_MAP(dstfilter) = CONDITION_MAP(srcfilter);
227 : }
228 :
229 6 : dstfilter->advmap.update_type = srcfilter->advmap.update_type;
230 6 : }
231 :
232 : /**
233 : * since we did a bunch of XSTRDUP's in conf_copy, time to free them up
234 : */
235 6 : static void conf_release(struct peer *src, afi_t afi, safi_t safi)
236 : {
237 6 : struct bgp_filter *srcfilter;
238 :
239 6 : srcfilter = &src->filter[afi][safi];
240 :
241 6 : XFREE(MTYPE_ROUTE_MAP_NAME, src->default_rmap[afi][safi].name);
242 :
243 6 : XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->dlist[FILTER_OUT].name);
244 :
245 6 : XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->plist[FILTER_OUT].name);
246 :
247 6 : XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->aslist[FILTER_OUT].name);
248 :
249 6 : XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->map[RMAP_OUT].name);
250 :
251 6 : XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->usmap.name);
252 :
253 6 : XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.aname);
254 :
255 6 : XFREE(MTYPE_BGP_FILTER_NAME, srcfilter->advmap.cname);
256 :
257 6 : XFREE(MTYPE_BGP_PEER_HOST, src->host);
258 :
259 6 : ecommunity_free(&src->soo[afi][safi]);
260 6 : }
261 :
262 4 : static void peer2_updgrp_copy(struct update_group *updgrp, struct peer_af *paf)
263 : {
264 4 : struct peer *src;
265 4 : struct peer *dst;
266 :
267 4 : if (!updgrp || !paf)
268 : return;
269 :
270 4 : src = paf->peer;
271 4 : dst = updgrp->conf;
272 4 : if (!src || !dst)
273 : return;
274 :
275 4 : updgrp->afi = paf->afi;
276 4 : updgrp->safi = paf->safi;
277 4 : updgrp->afid = paf->afid;
278 4 : updgrp->bgp = src->bgp;
279 :
280 4 : conf_copy(dst, src, paf->afi, paf->safi);
281 : }
282 :
283 : /**
284 : * auxiliary functions to maintain the hash table.
285 : * - updgrp_hash_alloc - to create a new entry, passed to hash_get
286 : * - updgrp_hash_key_make - makes the key for update group search
287 : * - updgrp_hash_cmp - compare two update groups.
288 : */
289 2 : static void *updgrp_hash_alloc(void *p)
290 : {
291 2 : struct update_group *updgrp;
292 2 : const struct update_group *in;
293 :
294 2 : in = (const struct update_group *)p;
295 2 : updgrp = XCALLOC(MTYPE_BGP_UPDGRP, sizeof(struct update_group));
296 2 : memcpy(updgrp, in, sizeof(struct update_group));
297 2 : updgrp->conf = XCALLOC(MTYPE_BGP_PEER, sizeof(struct peer));
298 2 : conf_copy(updgrp->conf, in->conf, in->afi, in->safi);
299 2 : return updgrp;
300 : }
301 :
302 : /**
303 : * The hash value for a peer is computed from the following variables:
304 : * v = f(
305 : * 1. IBGP (1) or EBGP (2)
306 : * 2. FLAGS based on configuration:
307 : * LOCAL_AS_NO_PREPEND
308 : * LOCAL_AS_REPLACE_AS
309 : * 3. AF_FLAGS based on configuration:
310 : * Refer to definition in bgp_updgrp.h
311 : * 4. (AF-independent) Capability flags:
312 : * AS4_RCV capability
313 : * 5. (AF-dependent) Capability flags:
314 : * ORF_PREFIX_SM_RCV (peer can send prefix ORF)
315 : * 6. MRAI
316 : * 7. peer-group name
317 : * 8. Outbound route-map name (neighbor route-map <> out)
318 : * 9. Outbound distribute-list name (neighbor distribute-list <> out)
319 : * 10. Outbound prefix-list name (neighbor prefix-list <> out)
320 : * 11. Outbound as-list name (neighbor filter-list <> out)
321 : * 12. Unsuppress map name (neighbor unsuppress-map <>)
322 : * 13. default rmap name (neighbor default-originate route-map <>)
323 : * 14. encoding both global and link-local nexthop?
324 : * 15. If peer is configured to be a lonesoul, peer ip address
325 : * 16. Local-as should match, if configured.
326 : * 17. maximum-prefix-out
327 : * 18. Local-role should also match, if configured.
328 : * )
329 : */
330 4 : static unsigned int updgrp_hash_key_make(const void *p)
331 : {
332 4 : const struct update_group *updgrp;
333 4 : const struct peer *peer;
334 4 : const struct bgp_filter *filter;
335 4 : uint32_t flags;
336 4 : uint32_t key;
337 4 : afi_t afi;
338 4 : safi_t safi;
339 :
340 : #define SEED1 999331
341 : #define SEED2 2147483647
342 :
343 4 : updgrp = p;
344 4 : peer = updgrp->conf;
345 4 : afi = updgrp->afi;
346 4 : safi = updgrp->safi;
347 4 : flags = peer->af_flags[afi][safi];
348 4 : filter = &peer->filter[afi][safi];
349 :
350 4 : key = 0;
351 :
352 4 : key = jhash_1word(peer->sort, key); /* EBGP or IBGP */
353 4 : key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key);
354 4 : key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key);
355 4 : key = jhash_1word((uint32_t)peer->addpath_type[afi][safi], key);
356 4 : key = jhash_1word((peer->cap & PEER_UPDGRP_CAP_FLAGS), key);
357 4 : key = jhash_1word((peer->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS),
358 : key);
359 4 : key = jhash_1word(peer->v_routeadv, key);
360 4 : key = jhash_1word(peer->change_local_as, key);
361 4 : key = jhash_1word(peer->max_packet_size, key);
362 4 : key = jhash_1word(peer->pmax_out[afi][safi], key);
363 :
364 4 : if (peer->as_path_loop_detection)
365 0 : key = jhash_2words(peer->as, peer->as_path_loop_detection, key);
366 :
367 4 : if (peer->group)
368 0 : key = jhash_1word(jhash(peer->group->name,
369 0 : strlen(peer->group->name), SEED1),
370 : key);
371 :
372 4 : if (filter->map[RMAP_OUT].name)
373 0 : key = jhash_1word(jhash(filter->map[RMAP_OUT].name,
374 0 : strlen(filter->map[RMAP_OUT].name),
375 : SEED1),
376 : key);
377 :
378 4 : if (filter->dlist[FILTER_OUT].name)
379 0 : key = jhash_1word(jhash(filter->dlist[FILTER_OUT].name,
380 0 : strlen(filter->dlist[FILTER_OUT].name),
381 : SEED1),
382 : key);
383 :
384 4 : if (filter->plist[FILTER_OUT].name)
385 0 : key = jhash_1word(jhash(filter->plist[FILTER_OUT].name,
386 0 : strlen(filter->plist[FILTER_OUT].name),
387 : SEED1),
388 : key);
389 :
390 4 : if (filter->aslist[FILTER_OUT].name)
391 0 : key = jhash_1word(jhash(filter->aslist[FILTER_OUT].name,
392 0 : strlen(filter->aslist[FILTER_OUT].name),
393 : SEED1),
394 : key);
395 :
396 4 : if (filter->usmap.name)
397 0 : key = jhash_1word(jhash(filter->usmap.name,
398 0 : strlen(filter->usmap.name), SEED1),
399 : key);
400 :
401 4 : if (filter->advmap.aname)
402 0 : key = jhash_1word(jhash(filter->advmap.aname,
403 0 : strlen(filter->advmap.aname), SEED1),
404 : key);
405 :
406 4 : if (filter->advmap.update_type)
407 0 : key = jhash_1word(filter->advmap.update_type, key);
408 :
409 4 : if (peer->default_rmap[afi][safi].name)
410 0 : key = jhash_1word(
411 : jhash(peer->default_rmap[afi][safi].name,
412 0 : strlen(peer->default_rmap[afi][safi].name),
413 : SEED1),
414 : key);
415 :
416 : /* If peer is on a shared network and is exchanging IPv6 prefixes,
417 : * it needs to include link-local address. That's different from
418 : * non-shared-network peers (nexthop encoded with 32 bytes vs 16
419 : * bytes). We create different update groups to take care of that.
420 : */
421 4 : key = jhash_1word(
422 4 : (peer->shared_network && peer_afi_active_nego(peer, AFI_IP6)),
423 : key);
424 : /*
425 : * There are certain peers that must get their own update-group:
426 : * - lonesoul peers
427 : * - peers that negotiated ORF
428 : * - maximum-prefix-out is set
429 : */
430 4 : if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)
431 4 : || CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
432 4 : || CHECK_FLAG(peer->af_cap[afi][safi],
433 : PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
434 4 : || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT))
435 0 : key = jhash_1word(jhash(peer->host, strlen(peer->host), SEED2),
436 : key);
437 : /*
438 : * Multiple sessions with the same neighbor should get their own
439 : * update-group if they have different roles.
440 : */
441 4 : key = jhash_1word(peer->local_role, key);
442 :
443 : /* Neighbors configured with the AIGP attribute are put in a separate
444 : * update group from other neighbors.
445 : */
446 4 : key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key);
447 :
448 4 : if (peer->soo[afi][safi]) {
449 0 : char *soo_str = ecommunity_str(peer->soo[afi][safi]);
450 :
451 0 : key = jhash_1word(jhash(soo_str, strlen(soo_str), SEED1), key);
452 : }
453 :
454 4 : if (bgp_debug_neighbor_events(peer)) {
455 0 : zlog_debug(
456 : "%pBP Update Group Hash: sort: %d UpdGrpFlags: %ju UpdGrpAFFlags: %ju",
457 : peer, peer->sort,
458 : (intmax_t)CHECK_FLAG(peer->flags, PEER_UPDGRP_FLAGS),
459 : (intmax_t)CHECK_FLAG(flags, PEER_UPDGRP_AF_FLAGS));
460 0 : zlog_debug(
461 : "%pBP Update Group Hash: addpath: %u UpdGrpCapFlag: %u UpdGrpCapAFFlag: %u route_adv: %u change local as: %u, as_path_loop_detection: %d",
462 : peer, (uint32_t)peer->addpath_type[afi][safi],
463 : CHECK_FLAG(peer->cap, PEER_UPDGRP_CAP_FLAGS),
464 : CHECK_FLAG(peer->af_cap[afi][safi],
465 : PEER_UPDGRP_AF_CAP_FLAGS),
466 : peer->v_routeadv, peer->change_local_as,
467 : peer->as_path_loop_detection);
468 0 : zlog_debug(
469 : "%pBP Update Group Hash: max packet size: %u pmax_out: %u Peer Group: %s rmap out: %s",
470 : peer, peer->max_packet_size, peer->pmax_out[afi][safi],
471 : peer->group ? peer->group->name : "(NONE)",
472 : ROUTE_MAP_OUT_NAME(filter) ? ROUTE_MAP_OUT_NAME(filter)
473 : : "(NONE)");
474 0 : zlog_debug(
475 : "%pBP Update Group Hash: dlist out: %s plist out: %s aslist out: %s usmap out: %s advmap: %s",
476 : peer,
477 : DISTRIBUTE_OUT_NAME(filter)
478 : ? DISTRIBUTE_OUT_NAME(filter)
479 : : "(NONE)",
480 : PREFIX_LIST_OUT_NAME(filter)
481 : ? PREFIX_LIST_OUT_NAME(filter)
482 : : "(NONE)",
483 : FILTER_LIST_OUT_NAME(filter)
484 : ? FILTER_LIST_OUT_NAME(filter)
485 : : "(NONE)",
486 : UNSUPPRESS_MAP_NAME(filter)
487 : ? UNSUPPRESS_MAP_NAME(filter)
488 : : "(NONE)",
489 : ADVERTISE_MAP_NAME(filter) ? ADVERTISE_MAP_NAME(filter)
490 : : "(NONE)");
491 0 : zlog_debug(
492 : "%pBP Update Group Hash: default rmap: %s shared network and afi active network: %d",
493 : peer,
494 : peer->default_rmap[afi][safi].name
495 : ? peer->default_rmap[afi][safi].name
496 : : "(NONE)",
497 : peer->shared_network &&
498 : peer_afi_active_nego(peer, AFI_IP6));
499 0 : zlog_debug(
500 : "%pBP Update Group Hash: Lonesoul: %d ORF prefix: %u ORF old: %u max prefix out: %ju",
501 : peer, !!CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL),
502 : CHECK_FLAG(peer->af_cap[afi][safi],
503 : PEER_CAP_ORF_PREFIX_SM_RCV),
504 : CHECK_FLAG(peer->af_cap[afi][safi],
505 : PEER_CAP_ORF_PREFIX_SM_OLD_RCV),
506 : (intmax_t)CHECK_FLAG(peer->af_flags[afi][safi],
507 : PEER_FLAG_MAX_PREFIX_OUT));
508 0 : zlog_debug("%pBP Update Group Hash key: %u", peer, key);
509 : }
510 4 : return key;
511 : }
512 :
513 2 : static bool updgrp_hash_cmp(const void *p1, const void *p2)
514 : {
515 2 : const struct update_group *grp1;
516 2 : const struct update_group *grp2;
517 2 : const struct peer *pe1;
518 2 : const struct peer *pe2;
519 2 : uint32_t flags1;
520 2 : uint32_t flags2;
521 2 : const struct bgp_filter *fl1;
522 2 : const struct bgp_filter *fl2;
523 2 : afi_t afi;
524 2 : safi_t safi;
525 :
526 2 : if (!p1 || !p2)
527 : return false;
528 :
529 2 : grp1 = p1;
530 2 : grp2 = p2;
531 2 : pe1 = grp1->conf;
532 2 : pe2 = grp2->conf;
533 2 : afi = grp1->afi;
534 2 : safi = grp1->safi;
535 2 : flags1 = pe1->af_flags[afi][safi];
536 2 : flags2 = pe2->af_flags[afi][safi];
537 2 : fl1 = &pe1->filter[afi][safi];
538 2 : fl2 = &pe2->filter[afi][safi];
539 :
540 : /* put EBGP and IBGP peers in different update groups */
541 2 : if (pe1->sort != pe2->sort)
542 : return false;
543 :
544 : /* check peer flags */
545 2 : if ((pe1->flags & PEER_UPDGRP_FLAGS)
546 2 : != (pe2->flags & PEER_UPDGRP_FLAGS))
547 : return false;
548 :
549 : /* If there is 'local-as' configured, it should match. */
550 2 : if (pe1->change_local_as != pe2->change_local_as)
551 : return false;
552 :
553 2 : if (pe1->pmax_out[afi][safi] != pe2->pmax_out[afi][safi])
554 : return false;
555 :
556 : /* flags like route reflector client */
557 2 : if ((flags1 & PEER_UPDGRP_AF_FLAGS) != (flags2 & PEER_UPDGRP_AF_FLAGS))
558 : return false;
559 :
560 2 : if (pe1->addpath_type[afi][safi] != pe2->addpath_type[afi][safi])
561 : return false;
562 :
563 2 : if ((pe1->cap & PEER_UPDGRP_CAP_FLAGS)
564 2 : != (pe2->cap & PEER_UPDGRP_CAP_FLAGS))
565 : return false;
566 :
567 2 : if ((pe1->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS)
568 2 : != (pe2->af_cap[afi][safi] & PEER_UPDGRP_AF_CAP_FLAGS))
569 : return false;
570 :
571 2 : if (pe1->v_routeadv != pe2->v_routeadv)
572 : return false;
573 :
574 2 : if (pe1->group != pe2->group)
575 : return false;
576 :
577 : /* Roles can affect filtering */
578 2 : if (pe1->local_role != pe2->local_role)
579 : return false;
580 :
581 : /* route-map names should be the same */
582 2 : if ((fl1->map[RMAP_OUT].name && !fl2->map[RMAP_OUT].name)
583 2 : || (!fl1->map[RMAP_OUT].name && fl2->map[RMAP_OUT].name)
584 2 : || (fl1->map[RMAP_OUT].name && fl2->map[RMAP_OUT].name
585 0 : && strcmp(fl1->map[RMAP_OUT].name, fl2->map[RMAP_OUT].name)))
586 : return false;
587 :
588 2 : if ((fl1->dlist[FILTER_OUT].name && !fl2->dlist[FILTER_OUT].name)
589 2 : || (!fl1->dlist[FILTER_OUT].name && fl2->dlist[FILTER_OUT].name)
590 2 : || (fl1->dlist[FILTER_OUT].name && fl2->dlist[FILTER_OUT].name
591 0 : && strcmp(fl1->dlist[FILTER_OUT].name,
592 : fl2->dlist[FILTER_OUT].name)))
593 : return false;
594 :
595 2 : if ((fl1->plist[FILTER_OUT].name && !fl2->plist[FILTER_OUT].name)
596 2 : || (!fl1->plist[FILTER_OUT].name && fl2->plist[FILTER_OUT].name)
597 2 : || (fl1->plist[FILTER_OUT].name && fl2->plist[FILTER_OUT].name
598 0 : && strcmp(fl1->plist[FILTER_OUT].name,
599 : fl2->plist[FILTER_OUT].name)))
600 : return false;
601 :
602 2 : if ((fl1->aslist[FILTER_OUT].name && !fl2->aslist[FILTER_OUT].name)
603 2 : || (!fl1->aslist[FILTER_OUT].name && fl2->aslist[FILTER_OUT].name)
604 2 : || (fl1->aslist[FILTER_OUT].name && fl2->aslist[FILTER_OUT].name
605 0 : && strcmp(fl1->aslist[FILTER_OUT].name,
606 : fl2->aslist[FILTER_OUT].name)))
607 : return false;
608 :
609 2 : if ((fl1->usmap.name && !fl2->usmap.name)
610 2 : || (!fl1->usmap.name && fl2->usmap.name)
611 2 : || (fl1->usmap.name && fl2->usmap.name
612 0 : && strcmp(fl1->usmap.name, fl2->usmap.name)))
613 : return false;
614 :
615 2 : if ((fl1->advmap.aname && !fl2->advmap.aname)
616 2 : || (!fl1->advmap.aname && fl2->advmap.aname)
617 2 : || (fl1->advmap.aname && fl2->advmap.aname
618 0 : && strcmp(fl1->advmap.aname, fl2->advmap.aname)))
619 : return false;
620 :
621 2 : if (fl1->advmap.update_type != fl2->advmap.update_type)
622 : return false;
623 :
624 2 : if ((pe1->default_rmap[afi][safi].name
625 0 : && !pe2->default_rmap[afi][safi].name)
626 2 : || (!pe1->default_rmap[afi][safi].name
627 2 : && pe2->default_rmap[afi][safi].name)
628 2 : || (pe1->default_rmap[afi][safi].name
629 0 : && pe2->default_rmap[afi][safi].name
630 0 : && strcmp(pe1->default_rmap[afi][safi].name,
631 : pe2->default_rmap[afi][safi].name)))
632 : return false;
633 :
634 2 : if ((afi == AFI_IP6) && (pe1->shared_network != pe2->shared_network))
635 : return false;
636 :
637 2 : if ((CHECK_FLAG(pe1->flags, PEER_FLAG_LONESOUL)
638 2 : || CHECK_FLAG(pe1->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
639 2 : || CHECK_FLAG(pe1->af_cap[afi][safi],
640 : PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
641 0 : && !sockunion_same(&pe1->su, &pe2->su))
642 : return false;
643 :
644 : return true;
645 : }
646 :
647 0 : static void peer_lonesoul_or_not(struct peer *peer, int set)
648 : {
649 : /* no change in status? */
650 0 : if (set == (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL) > 0))
651 : return;
652 :
653 0 : if (set)
654 0 : SET_FLAG(peer->flags, PEER_FLAG_LONESOUL);
655 : else
656 0 : UNSET_FLAG(peer->flags, PEER_FLAG_LONESOUL);
657 :
658 0 : update_group_adjust_peer_afs(peer);
659 : }
660 :
661 : /*
662 : * subgroup_total_packets_enqueued
663 : *
664 : * Returns the total number of packets enqueued to a subgroup.
665 : */
666 : static unsigned int
667 0 : subgroup_total_packets_enqueued(struct update_subgroup *subgrp)
668 : {
669 0 : struct bpacket *pkt;
670 :
671 0 : pkt = bpacket_queue_last(SUBGRP_PKTQ(subgrp));
672 :
673 0 : return pkt->ver - 1;
674 : }
675 :
676 0 : static int update_group_show_walkcb(struct update_group *updgrp, void *arg)
677 : {
678 0 : struct updwalk_context *ctx = arg;
679 0 : struct vty *vty;
680 0 : struct update_subgroup *subgrp;
681 0 : struct peer_af *paf;
682 0 : struct bgp_filter *filter;
683 0 : struct peer *peer = UPDGRP_PEER(updgrp);
684 0 : int match = 0;
685 0 : json_object *json_updgrp = NULL;
686 0 : json_object *json_subgrps = NULL;
687 0 : json_object *json_subgrp = NULL;
688 0 : json_object *json_time = NULL;
689 0 : json_object *json_subgrp_time = NULL;
690 0 : json_object *json_subgrp_event = NULL;
691 0 : json_object *json_peers = NULL;
692 0 : json_object *json_pkt_info = NULL;
693 0 : time_t epoch_tbuf, tbuf;
694 :
695 0 : if (!ctx)
696 : return CMD_SUCCESS;
697 :
698 0 : if (ctx->subgrp_id) {
699 0 : UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
700 0 : if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
701 0 : continue;
702 : else {
703 : match = 1;
704 : break;
705 : }
706 : }
707 : } else {
708 : match = 1;
709 : }
710 :
711 0 : if (!match) {
712 : /* Since this routine is invoked from a walk, we cannot signal
713 : * any */
714 : /* error here, can only return. */
715 : return CMD_SUCCESS;
716 : }
717 :
718 0 : vty = ctx->vty;
719 :
720 0 : if (ctx->uj) {
721 0 : json_updgrp = json_object_new_object();
722 : /* Display json o/p */
723 0 : tbuf = monotime(NULL);
724 0 : tbuf -= updgrp->uptime;
725 0 : epoch_tbuf = time(NULL) - tbuf;
726 0 : json_time = json_object_new_object();
727 0 : json_object_int_add(json_time, "epoch", epoch_tbuf);
728 0 : json_object_string_add(json_time, "epochString",
729 0 : ctime(&epoch_tbuf));
730 0 : json_object_object_add(json_updgrp, "groupCreateTime",
731 : json_time);
732 0 : json_object_string_add(json_updgrp, "afi",
733 : afi2str(updgrp->afi));
734 0 : json_object_string_add(json_updgrp, "safi",
735 : safi2str(updgrp->safi));
736 : } else {
737 0 : vty_out(vty, "Update-group %" PRIu64 ":\n", updgrp->id);
738 0 : vty_out(vty, " Created: %s", timestamp_string(updgrp->uptime));
739 : }
740 :
741 0 : filter = &updgrp->conf->filter[updgrp->afi][updgrp->safi];
742 0 : if (filter->map[RMAP_OUT].name) {
743 0 : if (ctx->uj)
744 0 : json_object_string_add(json_updgrp, "outRouteMap",
745 : filter->map[RMAP_OUT].name);
746 : else
747 0 : vty_out(vty, " Outgoing route map: %s\n",
748 : filter->map[RMAP_OUT].name);
749 : }
750 :
751 0 : if (ctx->uj)
752 0 : json_object_int_add(json_updgrp, "minRouteAdvInt",
753 0 : updgrp->conf->v_routeadv);
754 : else
755 0 : vty_out(vty, " MRAI value (seconds): %d\n",
756 0 : updgrp->conf->v_routeadv);
757 :
758 0 : if (updgrp->conf->change_local_as) {
759 0 : if (ctx->uj) {
760 0 : json_object_int_add(json_updgrp, "localAs",
761 : updgrp->conf->change_local_as);
762 0 : json_object_boolean_add(
763 : json_updgrp, "noPrepend",
764 0 : CHECK_FLAG(updgrp->conf->flags,
765 : PEER_FLAG_LOCAL_AS_NO_PREPEND));
766 0 : json_object_boolean_add(
767 : json_updgrp, "replaceLocalAs",
768 0 : CHECK_FLAG(updgrp->conf->flags,
769 : PEER_FLAG_LOCAL_AS_REPLACE_AS));
770 : } else {
771 0 : vty_out(vty, " Local AS %u%s%s\n",
772 : updgrp->conf->change_local_as,
773 0 : CHECK_FLAG(updgrp->conf->flags,
774 : PEER_FLAG_LOCAL_AS_NO_PREPEND)
775 : ? " no-prepend"
776 : : "",
777 0 : CHECK_FLAG(updgrp->conf->flags,
778 : PEER_FLAG_LOCAL_AS_REPLACE_AS)
779 : ? " replace-as"
780 : : "");
781 : }
782 : }
783 0 : if (ctx->uj)
784 0 : json_subgrps = json_object_new_array();
785 0 : UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
786 0 : if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
787 0 : continue;
788 0 : if (ctx->uj) {
789 0 : json_subgrp = json_object_new_object();
790 0 : json_object_int_add(json_subgrp, "subGroupId",
791 0 : subgrp->id);
792 0 : tbuf = monotime(NULL);
793 0 : tbuf -= subgrp->uptime;
794 0 : epoch_tbuf = time(NULL) - tbuf;
795 0 : json_subgrp_time = json_object_new_object();
796 0 : json_object_int_add(json_subgrp_time, "epoch",
797 : epoch_tbuf);
798 0 : json_object_string_add(json_subgrp_time, "epochString",
799 0 : ctime(&epoch_tbuf));
800 0 : json_object_object_add(json_subgrp, "groupCreateTime",
801 : json_subgrp_time);
802 : } else {
803 0 : vty_out(vty, "\n");
804 0 : vty_out(vty, " Update-subgroup %" PRIu64 ":\n",
805 : subgrp->id);
806 0 : vty_out(vty, " Created: %s",
807 : timestamp_string(subgrp->uptime));
808 : }
809 :
810 0 : if (subgrp->split_from.update_group_id
811 0 : || subgrp->split_from.subgroup_id) {
812 0 : if (ctx->uj) {
813 0 : json_object_int_add(
814 : json_subgrp, "splitGroupId",
815 : subgrp->split_from.update_group_id);
816 0 : json_object_int_add(
817 : json_subgrp, "splitSubGroupId",
818 0 : subgrp->split_from.subgroup_id);
819 : } else {
820 0 : vty_out(vty,
821 : " Split from group id: %" PRIu64
822 : "\n",
823 : subgrp->split_from.update_group_id);
824 0 : vty_out(vty,
825 : " Split from subgroup id: %" PRIu64
826 : "\n",
827 : subgrp->split_from.subgroup_id);
828 : }
829 : }
830 :
831 0 : if (ctx->uj) {
832 0 : json_subgrp_event = json_object_new_object();
833 0 : json_object_int_add(json_subgrp_event, "joinEvents",
834 0 : subgrp->join_events);
835 0 : json_object_int_add(json_subgrp_event, "pruneEvents",
836 0 : subgrp->prune_events);
837 0 : json_object_int_add(json_subgrp_event, "mergeEvents",
838 0 : subgrp->merge_events);
839 0 : json_object_int_add(json_subgrp_event, "splitEvents",
840 0 : subgrp->split_events);
841 0 : json_object_int_add(json_subgrp_event, "switchEvents",
842 0 : subgrp->updgrp_switch_events);
843 0 : json_object_int_add(json_subgrp_event,
844 : "peerRefreshEvents",
845 0 : subgrp->peer_refreshes_combined);
846 0 : json_object_int_add(json_subgrp_event,
847 : "mergeCheckEvents",
848 0 : subgrp->merge_checks_triggered);
849 0 : json_object_object_add(json_subgrp, "statistics",
850 : json_subgrp_event);
851 0 : json_object_int_add(json_subgrp, "coalesceTime",
852 0 : (UPDGRP_INST(subgrp->update_group))
853 0 : ->coalesce_time);
854 0 : json_object_int_add(json_subgrp, "version",
855 0 : subgrp->version);
856 0 : json_pkt_info = json_object_new_object();
857 0 : json_object_int_add(
858 : json_pkt_info, "qeueueLen",
859 0 : bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
860 0 : json_object_int_add(
861 : json_pkt_info, "queuedTotal",
862 0 : subgroup_total_packets_enqueued(subgrp));
863 0 : json_object_int_add(
864 : json_pkt_info, "queueHwmLen",
865 0 : bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
866 0 : json_object_int_add(
867 : json_pkt_info, "totalEnqueued",
868 0 : subgroup_total_packets_enqueued(subgrp));
869 0 : json_object_object_add(json_subgrp, "packetQueueInfo",
870 : json_pkt_info);
871 0 : json_object_int_add(json_subgrp, "adjListCount",
872 0 : subgrp->adj_count);
873 0 : json_object_boolean_add(
874 : json_subgrp, "needsRefresh",
875 0 : CHECK_FLAG(subgrp->flags,
876 : SUBGRP_FLAG_NEEDS_REFRESH));
877 : } else {
878 0 : vty_out(vty, " Join events: %u\n",
879 : subgrp->join_events);
880 0 : vty_out(vty, " Prune events: %u\n",
881 : subgrp->prune_events);
882 0 : vty_out(vty, " Merge events: %u\n",
883 : subgrp->merge_events);
884 0 : vty_out(vty, " Split events: %u\n",
885 : subgrp->split_events);
886 0 : vty_out(vty, " Update group switch events: %u\n",
887 : subgrp->updgrp_switch_events);
888 0 : vty_out(vty, " Peer refreshes combined: %u\n",
889 : subgrp->peer_refreshes_combined);
890 0 : vty_out(vty, " Merge checks triggered: %u\n",
891 : subgrp->merge_checks_triggered);
892 0 : vty_out(vty, " Coalesce Time: %u%s\n",
893 0 : (UPDGRP_INST(subgrp->update_group))
894 : ->coalesce_time,
895 0 : subgrp->t_coalesce ? "(Running)" : "");
896 0 : vty_out(vty, " Version: %" PRIu64 "\n",
897 : subgrp->version);
898 0 : vty_out(vty, " Packet queue length: %d\n",
899 : bpacket_queue_length(SUBGRP_PKTQ(subgrp)));
900 0 : vty_out(vty, " Total packets enqueued: %u\n",
901 : subgroup_total_packets_enqueued(subgrp));
902 0 : vty_out(vty, " Packet queue high watermark: %d\n",
903 : bpacket_queue_hwm_length(SUBGRP_PKTQ(subgrp)));
904 0 : vty_out(vty, " Adj-out list count: %u\n",
905 : subgrp->adj_count);
906 0 : vty_out(vty, " Advertise list: %s\n",
907 0 : advertise_list_is_empty(subgrp) ? "empty"
908 : : "not empty");
909 0 : vty_out(vty, " Flags: %s\n",
910 0 : CHECK_FLAG(subgrp->flags,
911 : SUBGRP_FLAG_NEEDS_REFRESH)
912 : ? "R"
913 : : "");
914 0 : if (peer)
915 0 : vty_out(vty, " Max packet size: %d\n",
916 0 : peer->max_packet_size);
917 : }
918 0 : if (subgrp->peer_count > 0) {
919 0 : if (ctx->uj) {
920 0 : json_peers = json_object_new_array();
921 0 : SUBGRP_FOREACH_PEER (subgrp, paf) {
922 0 : json_object *peer =
923 0 : json_object_new_string(
924 0 : paf->peer->host);
925 0 : json_object_array_add(json_peers, peer);
926 : }
927 0 : json_object_object_add(json_subgrp, "peers",
928 : json_peers);
929 : } else {
930 0 : vty_out(vty, " Peers:\n");
931 0 : SUBGRP_FOREACH_PEER (subgrp, paf)
932 0 : vty_out(vty, " - %s\n",
933 0 : paf->peer->host);
934 : }
935 : }
936 :
937 0 : if (ctx->uj)
938 0 : json_object_array_add(json_subgrps, json_subgrp);
939 : }
940 :
941 0 : if (ctx->uj) {
942 0 : json_object_object_add(json_updgrp, "subGroup", json_subgrps);
943 0 : json_object_object_addf(ctx->json_updategrps, json_updgrp,
944 : "%" PRIu64, updgrp->id);
945 : }
946 :
947 : return UPDWALK_CONTINUE;
948 : }
949 :
950 : /*
951 : * Helper function to show the packet queue for each subgroup of update group.
952 : * Will be constrained to a particular subgroup id if id !=0
953 : */
954 0 : static int updgrp_show_packet_queue_walkcb(struct update_group *updgrp,
955 : void *arg)
956 : {
957 0 : struct updwalk_context *ctx = arg;
958 0 : struct update_subgroup *subgrp;
959 0 : struct vty *vty;
960 :
961 0 : vty = ctx->vty;
962 0 : UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
963 0 : if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
964 0 : continue;
965 0 : vty_out(vty, "update group %" PRIu64 ", subgroup %" PRIu64 "\n",
966 : updgrp->id, subgrp->id);
967 0 : bpacket_queue_show_vty(SUBGRP_PKTQ(subgrp), vty);
968 : }
969 0 : return UPDWALK_CONTINUE;
970 : }
971 :
972 : /*
973 : * Show the packet queue for each subgroup of update group. Will be
974 : * constrained to a particular subgroup id if id !=0
975 : */
976 0 : void update_group_show_packet_queue(struct bgp *bgp, afi_t afi, safi_t safi,
977 : struct vty *vty, uint64_t id)
978 : {
979 0 : struct updwalk_context ctx;
980 :
981 0 : memset(&ctx, 0, sizeof(ctx));
982 0 : ctx.vty = vty;
983 0 : ctx.subgrp_id = id;
984 0 : ctx.flags = 0;
985 0 : update_group_af_walk(bgp, afi, safi, updgrp_show_packet_queue_walkcb,
986 : &ctx);
987 0 : }
988 :
989 2 : static struct update_group *update_group_find(struct peer_af *paf)
990 : {
991 2 : struct update_group *updgrp;
992 2 : struct update_group tmp;
993 2 : struct peer tmp_conf;
994 :
995 2 : if (!peer_established(PAF_PEER(paf)))
996 : return NULL;
997 :
998 2 : memset(&tmp, 0, sizeof(tmp));
999 2 : memset(&tmp_conf, 0, sizeof(tmp_conf));
1000 2 : tmp.conf = &tmp_conf;
1001 2 : peer2_updgrp_copy(&tmp, paf);
1002 :
1003 2 : updgrp = hash_lookup(paf->peer->bgp->update_groups[paf->afid], &tmp);
1004 2 : conf_release(&tmp_conf, paf->afi, paf->safi);
1005 2 : return updgrp;
1006 : }
1007 :
1008 2 : static struct update_group *update_group_create(struct peer_af *paf)
1009 : {
1010 2 : struct update_group *updgrp;
1011 2 : struct update_group tmp;
1012 2 : struct peer tmp_conf;
1013 :
1014 2 : memset(&tmp, 0, sizeof(tmp));
1015 2 : memset(&tmp_conf, 0, sizeof(tmp_conf));
1016 2 : tmp.conf = &tmp_conf;
1017 2 : peer2_updgrp_copy(&tmp, paf);
1018 :
1019 2 : updgrp = hash_get(paf->peer->bgp->update_groups[paf->afid], &tmp,
1020 : updgrp_hash_alloc);
1021 2 : update_group_checkin(updgrp);
1022 :
1023 2 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1024 0 : zlog_debug("create update group %" PRIu64, updgrp->id);
1025 :
1026 2 : UPDGRP_GLOBAL_STAT(updgrp, updgrps_created) += 1;
1027 :
1028 2 : conf_release(&tmp_conf, paf->afi, paf->safi);
1029 2 : return updgrp;
1030 : }
1031 :
1032 2 : static void update_group_delete(struct update_group *updgrp)
1033 : {
1034 2 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1035 0 : zlog_debug("delete update group %" PRIu64, updgrp->id);
1036 :
1037 2 : UPDGRP_GLOBAL_STAT(updgrp, updgrps_deleted) += 1;
1038 :
1039 2 : hash_release(updgrp->bgp->update_groups[updgrp->afid], updgrp);
1040 2 : conf_release(updgrp->conf, updgrp->afi, updgrp->safi);
1041 :
1042 2 : XFREE(MTYPE_BGP_PEER_HOST, updgrp->conf->host);
1043 :
1044 2 : XFREE(MTYPE_BGP_PEER_IFNAME, updgrp->conf->ifname);
1045 :
1046 2 : XFREE(MTYPE_BGP_PEER, updgrp->conf);
1047 2 : XFREE(MTYPE_BGP_UPDGRP, updgrp);
1048 2 : }
1049 :
1050 2 : static void update_group_add_subgroup(struct update_group *updgrp,
1051 : struct update_subgroup *subgrp)
1052 : {
1053 2 : if (!updgrp || !subgrp)
1054 : return;
1055 :
1056 2 : LIST_INSERT_HEAD(&(updgrp->subgrps), subgrp, updgrp_train);
1057 2 : subgrp->update_group = updgrp;
1058 : }
1059 :
1060 2 : static void update_group_remove_subgroup(struct update_group *updgrp,
1061 : struct update_subgroup *subgrp)
1062 : {
1063 2 : if (!updgrp || !subgrp)
1064 : return;
1065 :
1066 2 : LIST_REMOVE(subgrp, updgrp_train);
1067 2 : subgrp->update_group = NULL;
1068 2 : if (LIST_EMPTY(&(updgrp->subgrps)))
1069 2 : update_group_delete(updgrp);
1070 : }
1071 :
1072 : static struct update_subgroup *
1073 2 : update_subgroup_create(struct update_group *updgrp)
1074 : {
1075 2 : struct update_subgroup *subgrp;
1076 :
1077 2 : subgrp = XCALLOC(MTYPE_BGP_UPD_SUBGRP, sizeof(struct update_subgroup));
1078 2 : update_subgroup_checkin(subgrp, updgrp);
1079 2 : subgrp->v_coalesce = (UPDGRP_INST(updgrp))->coalesce_time;
1080 2 : sync_init(subgrp, updgrp);
1081 2 : bpacket_queue_init(SUBGRP_PKTQ(subgrp));
1082 2 : bpacket_queue_add(SUBGRP_PKTQ(subgrp), NULL, NULL);
1083 2 : TAILQ_INIT(&(subgrp->adjq));
1084 2 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1085 0 : zlog_debug("create subgroup u%" PRIu64 ":s%" PRIu64, updgrp->id,
1086 : subgrp->id);
1087 :
1088 2 : update_group_add_subgroup(updgrp, subgrp);
1089 :
1090 2 : UPDGRP_INCR_STAT(updgrp, subgrps_created);
1091 :
1092 2 : return subgrp;
1093 : }
1094 :
1095 2 : static void update_subgroup_delete(struct update_subgroup *subgrp)
1096 : {
1097 2 : if (!subgrp)
1098 : return;
1099 :
1100 2 : if (subgrp->update_group)
1101 2 : UPDGRP_INCR_STAT(subgrp->update_group, subgrps_deleted);
1102 :
1103 2 : THREAD_OFF(subgrp->t_merge_check);
1104 2 : THREAD_OFF(subgrp->t_coalesce);
1105 :
1106 2 : bpacket_queue_cleanup(SUBGRP_PKTQ(subgrp));
1107 2 : subgroup_clear_table(subgrp);
1108 :
1109 2 : sync_delete(subgrp);
1110 :
1111 2 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS) && subgrp->update_group)
1112 0 : zlog_debug("delete subgroup u%" PRIu64 ":s%" PRIu64,
1113 : subgrp->update_group->id, subgrp->id);
1114 :
1115 2 : update_group_remove_subgroup(subgrp->update_group, subgrp);
1116 :
1117 2 : XFREE(MTYPE_BGP_UPD_SUBGRP, subgrp);
1118 : }
1119 :
1120 0 : void update_subgroup_inherit_info(struct update_subgroup *to,
1121 : struct update_subgroup *from)
1122 : {
1123 0 : if (!to || !from)
1124 : return;
1125 :
1126 0 : to->sflags = from->sflags;
1127 : }
1128 :
1129 : /*
1130 : * update_subgroup_check_delete
1131 : *
1132 : * Delete a subgroup if it is ready to be deleted.
1133 : *
1134 : * Returns true if the subgroup was deleted.
1135 : */
1136 2 : static bool update_subgroup_check_delete(struct update_subgroup *subgrp)
1137 : {
1138 2 : if (!subgrp)
1139 : return false;
1140 :
1141 2 : if (!LIST_EMPTY(&(subgrp->peers)))
1142 : return false;
1143 :
1144 2 : update_subgroup_delete(subgrp);
1145 :
1146 2 : return true;
1147 : }
1148 :
1149 : /*
1150 : * update_subgroup_add_peer
1151 : *
1152 : * @param send_enqueued_packets If true all currently enqueued packets will
1153 : * also be sent to the peer.
1154 : */
1155 2 : static void update_subgroup_add_peer(struct update_subgroup *subgrp,
1156 : struct peer_af *paf,
1157 : int send_enqueued_pkts)
1158 : {
1159 2 : struct bpacket *pkt;
1160 :
1161 2 : if (!subgrp || !paf)
1162 : return;
1163 :
1164 2 : LIST_INSERT_HEAD(&(subgrp->peers), paf, subgrp_train);
1165 2 : paf->subgroup = subgrp;
1166 2 : subgrp->peer_count++;
1167 :
1168 2 : if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
1169 0 : UPDGRP_PEER_DBG_EN(subgrp->update_group);
1170 : }
1171 :
1172 2 : SUBGRP_INCR_STAT(subgrp, join_events);
1173 :
1174 2 : if (send_enqueued_pkts) {
1175 2 : pkt = bpacket_queue_first(SUBGRP_PKTQ(subgrp));
1176 : } else {
1177 :
1178 : /*
1179 : * Hang the peer off of the last, placeholder, packet in the
1180 : * queue. This means it won't see any of the packets that are
1181 : * currently the queue.
1182 : */
1183 0 : pkt = bpacket_queue_last(SUBGRP_PKTQ(subgrp));
1184 0 : assert(pkt->buffer == NULL);
1185 : }
1186 :
1187 2 : bpacket_add_peer(pkt, paf);
1188 :
1189 2 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1190 0 : zlog_debug("peer %s added to subgroup s%" PRIu64,
1191 : paf->peer->host, subgrp->id);
1192 : }
1193 :
1194 : /*
1195 : * update_subgroup_remove_peer_internal
1196 : *
1197 : * Internal function that removes a peer from a subgroup, but does not
1198 : * delete the subgroup. A call to this function must almost always be
1199 : * followed by a call to update_subgroup_check_delete().
1200 : *
1201 : * @see update_subgroup_remove_peer
1202 : */
1203 2 : static void update_subgroup_remove_peer_internal(struct update_subgroup *subgrp,
1204 : struct peer_af *paf)
1205 : {
1206 2 : assert(subgrp && paf && subgrp->update_group);
1207 :
1208 2 : if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
1209 0 : UPDGRP_PEER_DBG_DIS(subgrp->update_group);
1210 : }
1211 :
1212 2 : bpacket_queue_remove_peer(paf);
1213 2 : LIST_REMOVE(paf, subgrp_train);
1214 2 : paf->subgroup = NULL;
1215 2 : subgrp->peer_count--;
1216 :
1217 2 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1218 0 : zlog_debug("peer %s deleted from subgroup s%"
1219 : PRIu64 " peer cnt %d",
1220 : paf->peer->host, subgrp->id, subgrp->peer_count);
1221 2 : SUBGRP_INCR_STAT(subgrp, prune_events);
1222 2 : }
1223 :
1224 : /*
1225 : * update_subgroup_remove_peer
1226 : */
1227 5 : void update_subgroup_remove_peer(struct update_subgroup *subgrp,
1228 : struct peer_af *paf)
1229 : {
1230 5 : if (!subgrp || !paf)
1231 : return;
1232 :
1233 2 : update_subgroup_remove_peer_internal(subgrp, paf);
1234 :
1235 2 : if (update_subgroup_check_delete(subgrp))
1236 : return;
1237 :
1238 : /*
1239 : * The deletion of the peer may have caused some packets to be
1240 : * deleted from the subgroup packet queue. Check if the subgroup can
1241 : * be merged now.
1242 : */
1243 0 : update_subgroup_check_merge(subgrp, "removed peer from subgroup");
1244 : }
1245 :
1246 2 : static struct update_subgroup *update_subgroup_find(struct update_group *updgrp,
1247 : struct peer_af *paf)
1248 : {
1249 2 : struct update_subgroup *subgrp = NULL;
1250 2 : uint64_t version;
1251 :
1252 2 : if (paf->subgroup) {
1253 0 : assert(0);
1254 : return NULL;
1255 : } else
1256 2 : version = 0;
1257 :
1258 2 : if (!peer_established(PAF_PEER(paf)))
1259 : return NULL;
1260 :
1261 2 : UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
1262 0 : if (subgrp->version != version
1263 0 : || CHECK_FLAG(subgrp->sflags,
1264 : SUBGRP_STATUS_DEFAULT_ORIGINATE))
1265 0 : continue;
1266 :
1267 : /*
1268 : * The version number is not meaningful on a subgroup that needs
1269 : * a refresh.
1270 : */
1271 0 : if (update_subgroup_needs_refresh(subgrp))
1272 0 : continue;
1273 :
1274 : break;
1275 : }
1276 :
1277 : return subgrp;
1278 : }
1279 :
1280 : /*
1281 : * update_subgroup_ready_for_merge
1282 : *
1283 : * Returns true if this subgroup is in a state that allows it to be
1284 : * merged into another subgroup.
1285 : */
1286 6 : static bool update_subgroup_ready_for_merge(struct update_subgroup *subgrp)
1287 : {
1288 :
1289 : /*
1290 : * Not ready if there are any encoded packets waiting to be written
1291 : * out to peers.
1292 : */
1293 6 : if (!bpacket_queue_is_empty(SUBGRP_PKTQ(subgrp)))
1294 : return false;
1295 :
1296 : /*
1297 : * Not ready if there enqueued updates waiting to be encoded.
1298 : */
1299 6 : if (!advertise_list_is_empty(subgrp))
1300 : return false;
1301 :
1302 : /*
1303 : * Don't attempt to merge a subgroup that needs a refresh. For one,
1304 : * we can't determine if the adj_out of such a group matches that of
1305 : * another group.
1306 : */
1307 4 : if (update_subgroup_needs_refresh(subgrp))
1308 0 : return false;
1309 :
1310 : return true;
1311 : }
1312 :
1313 : /*
1314 : * update_subgrp_can_merge_into
1315 : *
1316 : * Returns true if the first subgroup can merge into the second
1317 : * subgroup.
1318 : */
1319 3 : static int update_subgroup_can_merge_into(struct update_subgroup *subgrp,
1320 : struct update_subgroup *target)
1321 : {
1322 :
1323 3 : if (subgrp == target)
1324 : return 0;
1325 :
1326 : /*
1327 : * Both must have processed the BRIB to the same point in order to
1328 : * be merged.
1329 : */
1330 0 : if (subgrp->version != target->version)
1331 : return 0;
1332 :
1333 0 : if (CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)
1334 0 : != CHECK_FLAG(target->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
1335 : return 0;
1336 :
1337 0 : if (subgrp->adj_count != target->adj_count)
1338 : return 0;
1339 :
1340 0 : return update_subgroup_ready_for_merge(target);
1341 : }
1342 :
1343 : /*
1344 : * update_subgroup_merge
1345 : *
1346 : * Merge the first subgroup into the second one.
1347 : */
1348 0 : static void update_subgroup_merge(struct update_subgroup *subgrp,
1349 : struct update_subgroup *target,
1350 : const char *reason)
1351 : {
1352 0 : struct peer_af *paf;
1353 0 : int result;
1354 0 : int peer_count;
1355 :
1356 0 : assert(subgrp->adj_count == target->adj_count);
1357 :
1358 0 : peer_count = subgrp->peer_count;
1359 :
1360 0 : while (1) {
1361 0 : paf = LIST_FIRST(&subgrp->peers);
1362 0 : if (!paf)
1363 : break;
1364 :
1365 0 : update_subgroup_remove_peer_internal(subgrp, paf);
1366 :
1367 : /*
1368 : * Add the peer to the target subgroup, while making sure that
1369 : * any currently enqueued packets won't be sent to it. Enqueued
1370 : * packets could, for example, result in an unnecessary withdraw
1371 : * followed by an advertise.
1372 : */
1373 0 : update_subgroup_add_peer(target, paf, 0);
1374 : }
1375 :
1376 0 : SUBGRP_INCR_STAT(target, merge_events);
1377 :
1378 0 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1379 0 : zlog_debug("u%" PRIu64 ":s%" PRIu64" (%d peers) merged into u%" PRIu64 ":s%" PRIu64", trigger: %s",
1380 : subgrp->update_group->id, subgrp->id, peer_count,
1381 : target->update_group->id, target->id,
1382 : reason ? reason : "unknown");
1383 :
1384 0 : result = update_subgroup_check_delete(subgrp);
1385 0 : assert(result);
1386 0 : }
1387 :
1388 : /*
1389 : * update_subgroup_check_merge
1390 : *
1391 : * Merge this subgroup into another subgroup if possible.
1392 : *
1393 : * Returns true if the subgroup has been merged. The subgroup pointer
1394 : * should not be accessed in this case.
1395 : */
1396 4 : bool update_subgroup_check_merge(struct update_subgroup *subgrp,
1397 : const char *reason)
1398 : {
1399 4 : struct update_subgroup *target;
1400 :
1401 4 : if (!update_subgroup_ready_for_merge(subgrp))
1402 : return false;
1403 :
1404 : /*
1405 : * Look for a subgroup to merge into.
1406 : */
1407 6 : UPDGRP_FOREACH_SUBGRP (subgrp->update_group, target) {
1408 3 : if (update_subgroup_can_merge_into(subgrp, target))
1409 : break;
1410 : }
1411 :
1412 3 : if (!target)
1413 : return false;
1414 :
1415 0 : update_subgroup_merge(subgrp, target, reason);
1416 0 : return true;
1417 : }
1418 :
1419 : /*
1420 : * update_subgroup_merge_check_thread_cb
1421 : */
1422 1 : static void update_subgroup_merge_check_thread_cb(struct thread *thread)
1423 : {
1424 1 : struct update_subgroup *subgrp;
1425 :
1426 1 : subgrp = THREAD_ARG(thread);
1427 :
1428 1 : subgrp->t_merge_check = NULL;
1429 :
1430 1 : update_subgroup_check_merge(subgrp, "triggered merge check");
1431 1 : }
1432 :
1433 : /*
1434 : * update_subgroup_trigger_merge_check
1435 : *
1436 : * Triggers a call to update_subgroup_check_merge() on a clean context.
1437 : *
1438 : * @param force If true, the merge check will be triggered even if the
1439 : * subgroup doesn't currently look ready for a merge.
1440 : *
1441 : * Returns true if a merge check will be performed shortly.
1442 : */
1443 2 : bool update_subgroup_trigger_merge_check(struct update_subgroup *subgrp,
1444 : int force)
1445 : {
1446 2 : if (subgrp->t_merge_check)
1447 : return true;
1448 :
1449 2 : if (!force && !update_subgroup_ready_for_merge(subgrp))
1450 : return false;
1451 :
1452 1 : subgrp->t_merge_check = NULL;
1453 1 : thread_add_timer_msec(bm->master, update_subgroup_merge_check_thread_cb,
1454 : subgrp, 0, &subgrp->t_merge_check);
1455 :
1456 1 : SUBGRP_INCR_STAT(subgrp, merge_checks_triggered);
1457 :
1458 : return true;
1459 : }
1460 :
1461 : /*
1462 : * update_subgroup_copy_adj_out
1463 : *
1464 : * Helper function that clones the adj out (state about advertised
1465 : * routes) from one subgroup to another. It assumes that the adj out
1466 : * of the target subgroup is empty.
1467 : */
1468 0 : static void update_subgroup_copy_adj_out(struct update_subgroup *source,
1469 : struct update_subgroup *dest)
1470 : {
1471 0 : struct bgp_adj_out *aout, *aout_copy;
1472 :
1473 0 : SUBGRP_FOREACH_ADJ (source, aout) {
1474 : /*
1475 : * Copy the adj out.
1476 : */
1477 0 : aout_copy = bgp_adj_out_alloc(dest, aout->dest,
1478 : aout->addpath_tx_id);
1479 0 : aout_copy->attr =
1480 0 : aout->attr ? bgp_attr_intern(aout->attr) : NULL;
1481 : }
1482 :
1483 0 : dest->scount = source->scount;
1484 0 : }
1485 :
1486 : /*
1487 : * update_subgroup_copy_packets
1488 : *
1489 : * Copy packets after and including the given packet to the subgroup
1490 : * 'dest'.
1491 : *
1492 : * Returns the number of packets copied.
1493 : */
1494 0 : static int update_subgroup_copy_packets(struct update_subgroup *dest,
1495 : struct bpacket *pkt)
1496 : {
1497 0 : int count;
1498 :
1499 0 : count = 0;
1500 0 : while (pkt && pkt->buffer) {
1501 0 : bpacket_queue_add(SUBGRP_PKTQ(dest), stream_dup(pkt->buffer),
1502 0 : &pkt->arr);
1503 0 : count++;
1504 0 : pkt = bpacket_next(pkt);
1505 : }
1506 :
1507 0 : return count;
1508 : }
1509 :
1510 0 : static bool updgrp_prefix_list_update(struct update_group *updgrp,
1511 : const char *name)
1512 : {
1513 0 : struct peer *peer;
1514 0 : struct bgp_filter *filter;
1515 :
1516 0 : peer = UPDGRP_PEER(updgrp);
1517 0 : filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
1518 :
1519 0 : if (PREFIX_LIST_OUT_NAME(filter)
1520 0 : && (strcmp(name, PREFIX_LIST_OUT_NAME(filter)) == 0)) {
1521 0 : PREFIX_LIST_OUT(filter) = prefix_list_lookup(
1522 : UPDGRP_AFI(updgrp), PREFIX_LIST_OUT_NAME(filter));
1523 0 : return true;
1524 : }
1525 : return false;
1526 : }
1527 :
1528 0 : static bool updgrp_filter_list_update(struct update_group *updgrp,
1529 : const char *name)
1530 : {
1531 0 : struct peer *peer;
1532 0 : struct bgp_filter *filter;
1533 :
1534 0 : peer = UPDGRP_PEER(updgrp);
1535 0 : filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
1536 :
1537 0 : if (FILTER_LIST_OUT_NAME(filter)
1538 0 : && (strcmp(name, FILTER_LIST_OUT_NAME(filter)) == 0)) {
1539 0 : FILTER_LIST_OUT(filter) =
1540 0 : as_list_lookup(FILTER_LIST_OUT_NAME(filter));
1541 0 : return true;
1542 : }
1543 : return false;
1544 : }
1545 :
1546 0 : static bool updgrp_distribute_list_update(struct update_group *updgrp,
1547 : const char *name)
1548 : {
1549 0 : struct peer *peer;
1550 0 : struct bgp_filter *filter;
1551 :
1552 0 : peer = UPDGRP_PEER(updgrp);
1553 0 : filter = &peer->filter[UPDGRP_AFI(updgrp)][UPDGRP_SAFI(updgrp)];
1554 :
1555 0 : if (DISTRIBUTE_OUT_NAME(filter)
1556 0 : && (strcmp(name, DISTRIBUTE_OUT_NAME(filter)) == 0)) {
1557 0 : DISTRIBUTE_OUT(filter) = access_list_lookup(
1558 : UPDGRP_AFI(updgrp), DISTRIBUTE_OUT_NAME(filter));
1559 0 : return true;
1560 : }
1561 : return false;
1562 : }
1563 :
1564 0 : static int updgrp_route_map_update(struct update_group *updgrp,
1565 : const char *name, int *def_rmap_changed)
1566 : {
1567 0 : struct peer *peer;
1568 0 : struct bgp_filter *filter;
1569 0 : int changed = 0;
1570 0 : afi_t afi;
1571 0 : safi_t safi;
1572 :
1573 0 : peer = UPDGRP_PEER(updgrp);
1574 0 : afi = UPDGRP_AFI(updgrp);
1575 0 : safi = UPDGRP_SAFI(updgrp);
1576 0 : filter = &peer->filter[afi][safi];
1577 :
1578 0 : if (ROUTE_MAP_OUT_NAME(filter)
1579 0 : && (strcmp(name, ROUTE_MAP_OUT_NAME(filter)) == 0)) {
1580 0 : ROUTE_MAP_OUT(filter) = route_map_lookup_by_name(name);
1581 :
1582 0 : changed = 1;
1583 : }
1584 :
1585 0 : if (UNSUPPRESS_MAP_NAME(filter)
1586 0 : && (strcmp(name, UNSUPPRESS_MAP_NAME(filter)) == 0)) {
1587 0 : UNSUPPRESS_MAP(filter) = route_map_lookup_by_name(name);
1588 0 : changed = 1;
1589 : }
1590 :
1591 : /* process default-originate route-map */
1592 0 : if (peer->default_rmap[afi][safi].name
1593 0 : && (strcmp(name, peer->default_rmap[afi][safi].name) == 0)) {
1594 0 : peer->default_rmap[afi][safi].map =
1595 0 : route_map_lookup_by_name(name);
1596 0 : if (def_rmap_changed)
1597 0 : *def_rmap_changed = 1;
1598 : }
1599 0 : return changed;
1600 : }
1601 :
1602 : /*
1603 : * hash iteration callback function to process a policy change for an
1604 : * update group. Check if the changed policy matches the updgrp's
1605 : * outbound route-map or unsuppress-map or default-originate map or
1606 : * filter-list or prefix-list or distribute-list.
1607 : * Trigger update generation accordingly.
1608 : */
1609 0 : static int updgrp_policy_update_walkcb(struct update_group *updgrp, void *arg)
1610 : {
1611 0 : struct updwalk_context *ctx = arg;
1612 0 : struct update_subgroup *subgrp;
1613 0 : int changed = 0;
1614 0 : int def_changed = 0;
1615 :
1616 0 : if (!updgrp || !ctx || !ctx->policy_name)
1617 : return UPDWALK_CONTINUE;
1618 :
1619 0 : switch (ctx->policy_type) {
1620 0 : case BGP_POLICY_ROUTE_MAP:
1621 0 : changed = updgrp_route_map_update(updgrp, ctx->policy_name,
1622 : &def_changed);
1623 0 : break;
1624 0 : case BGP_POLICY_FILTER_LIST:
1625 0 : changed = updgrp_filter_list_update(updgrp, ctx->policy_name);
1626 0 : break;
1627 0 : case BGP_POLICY_PREFIX_LIST:
1628 0 : changed = updgrp_prefix_list_update(updgrp, ctx->policy_name);
1629 0 : break;
1630 0 : case BGP_POLICY_DISTRIBUTE_LIST:
1631 0 : changed =
1632 0 : updgrp_distribute_list_update(updgrp, ctx->policy_name);
1633 0 : break;
1634 : default:
1635 : break;
1636 : }
1637 :
1638 : /* If not doing route update, return after updating "config" */
1639 0 : if (!ctx->policy_route_update)
1640 : return UPDWALK_CONTINUE;
1641 :
1642 : /* If nothing has changed, return after updating "config" */
1643 0 : if (!changed && !def_changed)
1644 : return UPDWALK_CONTINUE;
1645 :
1646 : /*
1647 : * If something has changed, at the beginning of a route-map
1648 : * modification
1649 : * event, mark each subgroup's needs-refresh bit. For one, it signals to
1650 : * whoever that the subgroup needs a refresh. Second, it prevents
1651 : * premature
1652 : * merge of this subgroup with another before a complete (outbound)
1653 : * refresh.
1654 : */
1655 0 : if (ctx->policy_event_start_flag) {
1656 0 : UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
1657 0 : update_subgroup_set_needs_refresh(subgrp, 1);
1658 : }
1659 : return UPDWALK_CONTINUE;
1660 : }
1661 :
1662 0 : UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
1663 : /* Avoid supressing duplicate routes later
1664 : * when processing in subgroup_announce_table().
1665 : */
1666 0 : SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
1667 :
1668 0 : if (changed) {
1669 0 : if (bgp_debug_update(NULL, NULL, updgrp, 0))
1670 0 : zlog_debug(
1671 : "u%" PRIu64 ":s%" PRIu64" announcing routes upon policy %s (type %d) change",
1672 : updgrp->id, subgrp->id,
1673 : ctx->policy_name, ctx->policy_type);
1674 0 : subgroup_announce_route(subgrp);
1675 : }
1676 0 : if (def_changed) {
1677 0 : if (bgp_debug_update(NULL, NULL, updgrp, 0))
1678 0 : zlog_debug(
1679 : "u%" PRIu64 ":s%" PRIu64" announcing default upon default routemap %s change",
1680 : updgrp->id, subgrp->id,
1681 : ctx->policy_name);
1682 0 : if (route_map_lookup_by_name(ctx->policy_name)) {
1683 : /*
1684 : * When there is change in routemap, this flow
1685 : * is triggered. the routemap is still present
1686 : * in lib, hence its a update flow. The flag
1687 : * needs to be unset.
1688 : */
1689 0 : UNSET_FLAG(subgrp->sflags,
1690 : SUBGRP_STATUS_DEFAULT_ORIGINATE);
1691 0 : subgroup_default_originate(subgrp, 0);
1692 : } else {
1693 : /*
1694 : * This is a explicit withdraw, since the
1695 : * routemap is not present in routemap lib. need
1696 : * to pass 1 for withdraw arg.
1697 : */
1698 0 : subgroup_default_originate(subgrp, 1);
1699 : }
1700 : }
1701 0 : update_subgroup_set_needs_refresh(subgrp, 0);
1702 : }
1703 : return UPDWALK_CONTINUE;
1704 : }
1705 :
1706 2 : static int update_group_walkcb(struct hash_bucket *bucket, void *arg)
1707 : {
1708 2 : struct update_group *updgrp = bucket->data;
1709 2 : struct updwalk_context *wctx = arg;
1710 2 : int ret = (*wctx->cb)(updgrp, wctx->context);
1711 2 : return ret;
1712 : }
1713 :
1714 0 : static int update_group_periodic_merge_walkcb(struct update_group *updgrp,
1715 : void *arg)
1716 : {
1717 0 : struct update_subgroup *subgrp;
1718 0 : struct update_subgroup *tmp_subgrp;
1719 0 : const char *reason = arg;
1720 :
1721 0 : UPDGRP_FOREACH_SUBGRP_SAFE (updgrp, subgrp, tmp_subgrp)
1722 0 : update_subgroup_check_merge(subgrp, reason);
1723 0 : return UPDWALK_CONTINUE;
1724 : }
1725 :
1726 : /********************
1727 : * PUBLIC FUNCTIONS
1728 : ********************/
1729 :
1730 : /*
1731 : * trigger function when a policy (route-map/filter-list/prefix-list/
1732 : * distribute-list etc.) content changes. Go through all the
1733 : * update groups and process the change.
1734 : *
1735 : * bgp: the bgp instance
1736 : * ptype: the type of policy that got modified, see bgpd.h
1737 : * pname: name of the policy
1738 : * route_update: flag to control if an automatic update generation should
1739 : * occur
1740 : * start_event: flag that indicates if it's the beginning of the change.
1741 : * Esp. when the user is changing the content interactively
1742 : * over multiple statements. Useful to set dirty flag on
1743 : * update groups.
1744 : */
1745 0 : void update_group_policy_update(struct bgp *bgp, enum bgp_policy_type ptype,
1746 : const char *pname, bool route_update,
1747 : int start_event)
1748 : {
1749 0 : struct updwalk_context ctx;
1750 :
1751 0 : memset(&ctx, 0, sizeof(ctx));
1752 0 : ctx.policy_type = ptype;
1753 0 : ctx.policy_name = pname;
1754 0 : ctx.policy_route_update = route_update;
1755 0 : ctx.policy_event_start_flag = start_event;
1756 0 : ctx.flags = 0;
1757 :
1758 0 : update_group_walk(bgp, updgrp_policy_update_walkcb, &ctx);
1759 0 : }
1760 :
1761 : /*
1762 : * update_subgroup_split_peer
1763 : *
1764 : * Ensure that the given peer is in a subgroup of its own in the
1765 : * specified update group.
1766 : */
1767 0 : void update_subgroup_split_peer(struct peer_af *paf,
1768 : struct update_group *updgrp)
1769 : {
1770 0 : struct update_subgroup *old_subgrp, *subgrp;
1771 0 : uint64_t old_id;
1772 :
1773 :
1774 0 : old_subgrp = paf->subgroup;
1775 :
1776 0 : if (!updgrp)
1777 0 : updgrp = old_subgrp->update_group;
1778 :
1779 : /*
1780 : * If the peer is alone in its subgroup, reuse the existing
1781 : * subgroup.
1782 : */
1783 0 : if (old_subgrp->peer_count == 1) {
1784 0 : if (updgrp == old_subgrp->update_group)
1785 : return;
1786 :
1787 0 : subgrp = old_subgrp;
1788 0 : old_id = old_subgrp->update_group->id;
1789 :
1790 0 : if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
1791 0 : UPDGRP_PEER_DBG_DIS(old_subgrp->update_group);
1792 : }
1793 :
1794 0 : update_group_remove_subgroup(old_subgrp->update_group,
1795 : old_subgrp);
1796 0 : update_group_add_subgroup(updgrp, subgrp);
1797 :
1798 0 : if (bgp_debug_peer_updout_enabled(paf->peer->host)) {
1799 0 : UPDGRP_PEER_DBG_EN(updgrp);
1800 : }
1801 0 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1802 0 : zlog_debug("u%" PRIu64 ":s%" PRIu64" peer %s moved to u%" PRIu64 ":s%" PRIu64,
1803 : old_id, subgrp->id, paf->peer->host,
1804 : updgrp->id, subgrp->id);
1805 :
1806 : /*
1807 : * The state of the subgroup (adj_out, advs, packet queue etc)
1808 : * is consistent internally, but may not be identical to other
1809 : * subgroups in the new update group even if the version number
1810 : * matches up. Make sure a full refresh is done before the
1811 : * subgroup is merged with another.
1812 : */
1813 0 : update_subgroup_set_needs_refresh(subgrp, 1);
1814 :
1815 0 : SUBGRP_INCR_STAT(subgrp, updgrp_switch_events);
1816 0 : return;
1817 : }
1818 :
1819 : /*
1820 : * Create a new subgroup under the specified update group, and copy
1821 : * over relevant state to it.
1822 : */
1823 0 : subgrp = update_subgroup_create(updgrp);
1824 0 : update_subgroup_inherit_info(subgrp, old_subgrp);
1825 :
1826 0 : subgrp->split_from.update_group_id = old_subgrp->update_group->id;
1827 0 : subgrp->split_from.subgroup_id = old_subgrp->id;
1828 :
1829 : /*
1830 : * Copy out relevant state from the old subgroup.
1831 : */
1832 0 : update_subgroup_copy_adj_out(paf->subgroup, subgrp);
1833 0 : update_subgroup_copy_packets(subgrp, paf->next_pkt_to_send);
1834 :
1835 0 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
1836 0 : zlog_debug("u%" PRIu64 ":s%" PRIu64" peer %s split and moved into u%" PRIu64":s%" PRIu64,
1837 : paf->subgroup->update_group->id, paf->subgroup->id,
1838 : paf->peer->host, updgrp->id, subgrp->id);
1839 :
1840 0 : SUBGRP_INCR_STAT(paf->subgroup, split_events);
1841 :
1842 : /*
1843 : * Since queued advs were left behind, this new subgroup needs a
1844 : * refresh.
1845 : */
1846 0 : update_subgroup_set_needs_refresh(subgrp, 1);
1847 :
1848 : /*
1849 : * Remove peer from old subgroup, and add it to the new one.
1850 : */
1851 0 : update_subgroup_remove_peer(paf->subgroup, paf);
1852 :
1853 0 : update_subgroup_add_peer(subgrp, paf, 1);
1854 : }
1855 :
1856 2 : void update_bgp_group_init(struct bgp *bgp)
1857 : {
1858 2 : int afid;
1859 :
1860 28 : AF_FOREACH (afid)
1861 26 : bgp->update_groups[afid] =
1862 26 : hash_create(updgrp_hash_key_make, updgrp_hash_cmp,
1863 : "BGP Update Group Hash");
1864 2 : }
1865 :
1866 2 : void update_bgp_group_free(struct bgp *bgp)
1867 : {
1868 2 : int afid;
1869 :
1870 28 : AF_FOREACH (afid) {
1871 26 : if (bgp->update_groups[afid]) {
1872 26 : hash_free(bgp->update_groups[afid]);
1873 26 : bgp->update_groups[afid] = NULL;
1874 : }
1875 : }
1876 2 : }
1877 :
1878 0 : void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty,
1879 : uint64_t subgrp_id, bool uj)
1880 : {
1881 0 : struct updwalk_context ctx;
1882 0 : json_object *json_vrf_obj = NULL;
1883 :
1884 0 : memset(&ctx, 0, sizeof(ctx));
1885 0 : ctx.vty = vty;
1886 0 : ctx.subgrp_id = subgrp_id;
1887 0 : ctx.uj = uj;
1888 :
1889 0 : if (uj) {
1890 0 : ctx.json_updategrps = json_object_new_object();
1891 0 : json_vrf_obj = json_object_new_object();
1892 : }
1893 :
1894 0 : update_group_af_walk(bgp, afi, safi, update_group_show_walkcb, &ctx);
1895 :
1896 0 : if (uj) {
1897 0 : const char *vname;
1898 :
1899 0 : if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
1900 0 : vname = VRF_DEFAULT_NAME;
1901 : else
1902 0 : vname = bgp->name;
1903 0 : json_object_object_add(json_vrf_obj, vname,
1904 0 : ctx.json_updategrps);
1905 0 : vty_json(vty, json_vrf_obj);
1906 : }
1907 0 : }
1908 :
1909 : /*
1910 : * update_group_show_stats
1911 : *
1912 : * Show global statistics about update groups.
1913 : */
1914 0 : void update_group_show_stats(struct bgp *bgp, struct vty *vty)
1915 : {
1916 0 : vty_out(vty, "Update groups created: %u\n",
1917 : bgp->update_group_stats.updgrps_created);
1918 0 : vty_out(vty, "Update groups deleted: %u\n",
1919 : bgp->update_group_stats.updgrps_deleted);
1920 0 : vty_out(vty, "Update subgroups created: %u\n",
1921 : bgp->update_group_stats.subgrps_created);
1922 0 : vty_out(vty, "Update subgroups deleted: %u\n",
1923 : bgp->update_group_stats.subgrps_deleted);
1924 0 : vty_out(vty, "Join events: %u\n", bgp->update_group_stats.join_events);
1925 0 : vty_out(vty, "Prune events: %u\n",
1926 : bgp->update_group_stats.prune_events);
1927 0 : vty_out(vty, "Merge events: %u\n",
1928 : bgp->update_group_stats.merge_events);
1929 0 : vty_out(vty, "Split events: %u\n",
1930 : bgp->update_group_stats.split_events);
1931 0 : vty_out(vty, "Update group switch events: %u\n",
1932 : bgp->update_group_stats.updgrp_switch_events);
1933 0 : vty_out(vty, "Peer route refreshes combined: %u\n",
1934 : bgp->update_group_stats.peer_refreshes_combined);
1935 0 : vty_out(vty, "Merge checks triggered: %u\n",
1936 : bgp->update_group_stats.merge_checks_triggered);
1937 0 : }
1938 :
1939 : /*
1940 : * update_group_adjust_peer
1941 : */
1942 2 : void update_group_adjust_peer(struct peer_af *paf)
1943 : {
1944 2 : struct update_group *updgrp;
1945 2 : struct update_subgroup *subgrp, *old_subgrp;
1946 2 : struct peer *peer;
1947 :
1948 2 : if (!paf)
1949 : return;
1950 :
1951 2 : peer = PAF_PEER(paf);
1952 2 : if (!peer_established(peer)) {
1953 : return;
1954 : }
1955 :
1956 2 : if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) {
1957 : return;
1958 : }
1959 :
1960 2 : if (!peer->afc_nego[paf->afi][paf->safi]) {
1961 : return;
1962 : }
1963 :
1964 2 : updgrp = update_group_find(paf);
1965 2 : if (!updgrp) {
1966 2 : updgrp = update_group_create(paf);
1967 2 : if (!updgrp) {
1968 0 : flog_err(EC_BGP_UPDGRP_CREATE,
1969 : "couldn't create update group for peer %s",
1970 : paf->peer->host);
1971 0 : return;
1972 : }
1973 : }
1974 :
1975 2 : old_subgrp = paf->subgroup;
1976 :
1977 2 : if (old_subgrp) {
1978 :
1979 : /*
1980 : * If the update group of the peer is unchanged, the peer can
1981 : * stay
1982 : * in its existing subgroup and we're done.
1983 : */
1984 0 : if (old_subgrp->update_group == updgrp)
1985 : return;
1986 :
1987 : /*
1988 : * The peer is switching between update groups. Put it in its
1989 : * own subgroup under the new update group.
1990 : */
1991 0 : update_subgroup_split_peer(paf, updgrp);
1992 0 : return;
1993 : }
1994 :
1995 2 : subgrp = update_subgroup_find(updgrp, paf);
1996 2 : if (!subgrp) {
1997 2 : subgrp = update_subgroup_create(updgrp);
1998 2 : if (!subgrp)
1999 : return;
2000 : }
2001 :
2002 2 : update_subgroup_add_peer(subgrp, paf, 1);
2003 2 : if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
2004 0 : zlog_debug("u%" PRIu64 ":s%" PRIu64 " add peer %s", updgrp->id,
2005 : subgrp->id, paf->peer->host);
2006 :
2007 : return;
2008 : }
2009 :
2010 0 : int update_group_adjust_soloness(struct peer *peer, int set)
2011 : {
2012 0 : struct peer_group *group;
2013 0 : struct listnode *node, *nnode;
2014 :
2015 0 : if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
2016 0 : peer_lonesoul_or_not(peer, set);
2017 0 : if (peer_established(peer))
2018 0 : bgp_announce_route_all(peer);
2019 : } else {
2020 0 : group = peer->group;
2021 0 : for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
2022 0 : peer_lonesoul_or_not(peer, set);
2023 0 : if (peer_established(peer))
2024 0 : bgp_announce_route_all(peer);
2025 : }
2026 : }
2027 0 : return 0;
2028 : }
2029 :
2030 : /*
2031 : * update_subgroup_rib
2032 : */
2033 0 : struct bgp_table *update_subgroup_rib(struct update_subgroup *subgrp)
2034 : {
2035 0 : struct bgp *bgp;
2036 :
2037 0 : bgp = SUBGRP_INST(subgrp);
2038 0 : if (!bgp)
2039 : return NULL;
2040 :
2041 0 : return bgp->rib[SUBGRP_AFI(subgrp)][SUBGRP_SAFI(subgrp)];
2042 : }
2043 :
2044 8 : void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi,
2045 : updgrp_walkcb cb, void *ctx)
2046 : {
2047 8 : struct updwalk_context wctx;
2048 8 : int afid;
2049 :
2050 8 : if (!bgp)
2051 0 : return;
2052 8 : afid = afindex(afi, safi);
2053 8 : if (afid >= BGP_AF_MAX)
2054 : return;
2055 :
2056 8 : memset(&wctx, 0, sizeof(wctx));
2057 8 : wctx.cb = cb;
2058 8 : wctx.context = ctx;
2059 :
2060 8 : if (bgp->update_groups[afid])
2061 8 : hash_walk(bgp->update_groups[afid], update_group_walkcb, &wctx);
2062 : }
2063 :
2064 0 : void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx)
2065 : {
2066 0 : afi_t afi;
2067 0 : safi_t safi;
2068 :
2069 0 : FOREACH_AFI_SAFI (afi, safi) {
2070 0 : update_group_af_walk(bgp, afi, safi, cb, ctx);
2071 : }
2072 0 : }
2073 :
2074 0 : void update_group_periodic_merge(struct bgp *bgp)
2075 : {
2076 0 : char reason[] = "periodic merge check";
2077 :
2078 0 : update_group_walk(bgp, update_group_periodic_merge_walkcb,
2079 : (void *)reason);
2080 0 : }
2081 :
2082 : static int
2083 0 : update_group_default_originate_route_map_walkcb(struct update_group *updgrp,
2084 : void *arg)
2085 : {
2086 0 : struct update_subgroup *subgrp;
2087 0 : struct peer *peer;
2088 0 : afi_t afi;
2089 0 : safi_t safi;
2090 :
2091 0 : UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
2092 0 : peer = SUBGRP_PEER(subgrp);
2093 0 : afi = SUBGRP_AFI(subgrp);
2094 0 : safi = SUBGRP_SAFI(subgrp);
2095 :
2096 0 : if (peer->default_rmap[afi][safi].name) {
2097 : /*
2098 : * When there is change in routemap this flow will
2099 : * be triggered. We need to unset the Flag to ensure
2100 : * the update flow gets triggered.
2101 : */
2102 0 : UNSET_FLAG(subgrp->sflags,
2103 : SUBGRP_STATUS_DEFAULT_ORIGINATE);
2104 0 : subgroup_default_originate(subgrp, 0);
2105 : }
2106 : }
2107 :
2108 0 : return UPDWALK_CONTINUE;
2109 : }
2110 :
2111 0 : void update_group_refresh_default_originate_route_map(struct thread *thread)
2112 : {
2113 0 : struct bgp *bgp;
2114 0 : char reason[] = "refresh default-originate route-map";
2115 :
2116 0 : bgp = THREAD_ARG(thread);
2117 0 : update_group_walk(bgp, update_group_default_originate_route_map_walkcb,
2118 : reason);
2119 0 : THREAD_OFF(bgp->t_rmap_def_originate_eval);
2120 0 : bgp_unlock(bgp);
2121 0 : }
2122 :
2123 : /*
2124 : * peer_af_announce_route
2125 : *
2126 : * Refreshes routes out to a peer_af immediately.
2127 : *
2128 : * If the combine parameter is true, then this function will try to
2129 : * gather other peers in the subgroup for which a route announcement
2130 : * is pending and efficently announce routes to all of them.
2131 : *
2132 : * For now, the 'combine' option has an effect only if all peers in
2133 : * the subgroup have a route announcement pending.
2134 : */
2135 0 : void peer_af_announce_route(struct peer_af *paf, int combine)
2136 : {
2137 0 : struct update_subgroup *subgrp;
2138 0 : struct peer_af *cur_paf;
2139 0 : int all_pending;
2140 :
2141 0 : subgrp = paf->subgroup;
2142 0 : all_pending = 0;
2143 :
2144 0 : if (combine) {
2145 : /*
2146 : * If there are other peers in the old subgroup that also need
2147 : * routes to be announced, pull them into the peer's new
2148 : * subgroup.
2149 : * Combine route announcement with other peers if possible.
2150 : *
2151 : * For now, we combine only if all peers in the subgroup have an
2152 : * announcement pending.
2153 : */
2154 0 : all_pending = 1;
2155 :
2156 0 : SUBGRP_FOREACH_PEER (subgrp, cur_paf) {
2157 0 : if (cur_paf == paf)
2158 0 : continue;
2159 :
2160 0 : if (cur_paf->t_announce_route)
2161 0 : continue;
2162 :
2163 : all_pending = 0;
2164 : break;
2165 : }
2166 : }
2167 : /*
2168 : * Announce to the peer alone if we were not asked to combine peers,
2169 : * or if some peers don't have a route annoucement pending.
2170 : */
2171 0 : if (!combine || !all_pending) {
2172 0 : update_subgroup_split_peer(paf, NULL);
2173 0 : subgrp = paf->subgroup;
2174 :
2175 0 : assert(subgrp && subgrp->update_group);
2176 0 : if (bgp_debug_update(paf->peer, NULL, subgrp->update_group, 0))
2177 0 : zlog_debug("u%" PRIu64 ":s%" PRIu64" %s announcing routes",
2178 : subgrp->update_group->id, subgrp->id,
2179 : paf->peer->host);
2180 :
2181 0 : subgroup_announce_route(paf->subgroup);
2182 0 : return;
2183 : }
2184 :
2185 : /*
2186 : * We will announce routes the entire subgroup.
2187 : *
2188 : * First stop refresh timers on all the other peers.
2189 : */
2190 0 : SUBGRP_FOREACH_PEER (subgrp, cur_paf) {
2191 0 : if (cur_paf == paf)
2192 0 : continue;
2193 :
2194 0 : bgp_stop_announce_route_timer(cur_paf);
2195 : }
2196 :
2197 0 : if (bgp_debug_update(paf->peer, NULL, subgrp->update_group, 0))
2198 0 : zlog_debug("u%" PRIu64 ":s%" PRIu64" announcing routes to %s, combined into %d peers",
2199 : subgrp->update_group->id, subgrp->id,
2200 : paf->peer->host, subgrp->peer_count);
2201 :
2202 0 : subgroup_announce_route(subgrp);
2203 :
2204 0 : SUBGRP_INCR_STAT_BY(subgrp, peer_refreshes_combined,
2205 : subgrp->peer_count - 1);
2206 : }
2207 :
2208 0 : void subgroup_trigger_write(struct update_subgroup *subgrp)
2209 : {
2210 0 : struct peer_af *paf;
2211 :
2212 : /*
2213 : * For each peer in the subgroup, schedule a job to pull packets from
2214 : * the subgroup output queue into their own output queue. This action
2215 : * will trigger a write job on the I/O thread.
2216 : */
2217 0 : SUBGRP_FOREACH_PEER (subgrp, paf)
2218 0 : if (peer_established(paf->peer))
2219 0 : thread_add_timer_msec(
2220 : bm->master, bgp_generate_updgrp_packets,
2221 : paf->peer, 0,
2222 : &paf->peer->t_generate_updgrp_packets);
2223 0 : }
2224 :
2225 0 : int update_group_clear_update_dbg(struct update_group *updgrp, void *arg)
2226 : {
2227 0 : UPDGRP_PEER_DBG_OFF(updgrp);
2228 0 : return UPDWALK_CONTINUE;
2229 : }
2230 :
2231 : /* Return true if we should addpath encode NLRI to this peer */
2232 28 : bool bgp_addpath_encode_tx(struct peer *peer, afi_t afi, safi_t safi)
2233 : {
2234 28 : return (CHECK_FLAG(peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_ADV)
2235 28 : && CHECK_FLAG(peer->af_cap[afi][safi],
2236 : PEER_CAP_ADDPATH_AF_RX_RCV));
2237 : }
2238 :
2239 0 : bool bgp_addpath_capable(struct bgp_path_info *bpi, struct peer *peer,
2240 : afi_t afi, safi_t safi)
2241 : {
2242 0 : return (bgp_addpath_tx_path(peer->addpath_type[afi][safi], bpi) ||
2243 0 : (safi == SAFI_LABELED_UNICAST &&
2244 0 : bgp_addpath_tx_path(peer->addpath_type[afi][SAFI_UNICAST],
2245 : bpi)));
2246 : }
2247 :
2248 2 : bool bgp_check_selected(struct bgp_path_info *bpi, struct peer *peer,
2249 : bool addpath_capable, afi_t afi, safi_t safi)
2250 : {
2251 2 : return (CHECK_FLAG(bpi->flags, BGP_PATH_SELECTED) ||
2252 0 : (addpath_capable && bgp_addpath_capable(bpi, peer, afi, safi)));
2253 : }
|