]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* BGP advertisement and adjacency |
2 | Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro | |
3 | ||
4 | This file is part of GNU Zebra. | |
5 | ||
6 | GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU General Public License as published by the | |
8 | Free Software Foundation; either version 2, or (at your option) any | |
9 | later version. | |
10 | ||
11 | GNU Zebra is distributed in the hope that it will be useful, but | |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU Zebra; see the file COPYING. If not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 | 02111-1307, USA. */ | |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "command.h" | |
24 | #include "memory.h" | |
25 | #include "prefix.h" | |
26 | #include "hash.h" | |
27 | #include "thread.h" | |
28 | ||
29 | #include "bgpd/bgpd.h" | |
30 | #include "bgpd/bgp_table.h" | |
31 | #include "bgpd/bgp_route.h" | |
32 | #include "bgpd/bgp_advertise.h" | |
33 | #include "bgpd/bgp_attr.h" | |
d889623f | 34 | #include "bgpd/bgp_debug.h" |
718e3744 | 35 | #include "bgpd/bgp_aspath.h" |
36 | #include "bgpd/bgp_packet.h" | |
37 | #include "bgpd/bgp_fsm.h" | |
38 | #include "bgpd/bgp_mplsvpn.h" | |
6b0655a2 | 39 | |
718e3744 | 40 | /* BGP advertise attribute is used for pack same attribute update into |
41 | one packet. To do that we maintain attribute hash in struct | |
42 | peer. */ | |
43 | static struct bgp_advertise_attr * | |
66e5cd87 | 44 | baa_new (void) |
718e3744 | 45 | { |
46 | return (struct bgp_advertise_attr *) | |
47 | XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr)); | |
48 | } | |
49 | ||
50 | static void | |
51 | baa_free (struct bgp_advertise_attr *baa) | |
52 | { | |
53 | XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa); | |
54 | } | |
55 | ||
56 | static void * | |
923de654 | 57 | baa_hash_alloc (void *p) |
718e3744 | 58 | { |
923de654 | 59 | struct bgp_advertise_attr * ref = (struct bgp_advertise_attr *) p; |
718e3744 | 60 | struct bgp_advertise_attr *baa; |
61 | ||
62 | baa = baa_new (); | |
63 | baa->attr = ref->attr; | |
64 | return baa; | |
65 | } | |
66 | ||
67 | static unsigned int | |
923de654 | 68 | baa_hash_key (void *p) |
718e3744 | 69 | { |
923de654 PJ |
70 | struct bgp_advertise_attr * baa = (struct bgp_advertise_attr *) p; |
71 | ||
718e3744 | 72 | return attrhash_key_make (baa->attr); |
73 | } | |
74 | ||
75 | static int | |
ffe11cfb | 76 | baa_hash_cmp (const void *p1, const void *p2) |
718e3744 | 77 | { |
ffe11cfb SH |
78 | const struct bgp_advertise_attr * baa1 = p1; |
79 | const struct bgp_advertise_attr * baa2 = p2; | |
923de654 | 80 | |
718e3744 | 81 | return attrhash_cmp (baa1->attr, baa2->attr); |
82 | } | |
6b0655a2 | 83 | |
718e3744 | 84 | /* BGP update and withdraw information is stored in BGP advertise |
85 | structure. This structure is referred from BGP adjacency | |
86 | information. */ | |
87 | static struct bgp_advertise * | |
66e5cd87 | 88 | bgp_advertise_new (void) |
718e3744 | 89 | { |
90 | return (struct bgp_advertise *) | |
91 | XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise)); | |
92 | } | |
93 | ||
94f2b392 | 94 | static void |
718e3744 | 95 | bgp_advertise_free (struct bgp_advertise *adv) |
96 | { | |
200df115 | 97 | if (adv->binfo) |
98 | bgp_info_unlock (adv->binfo); /* bgp_advertise bgp_info reference */ | |
718e3744 | 99 | XFREE (MTYPE_BGP_ADVERTISE, adv); |
100 | } | |
101 | ||
94f2b392 | 102 | static void |
718e3744 | 103 | bgp_advertise_add (struct bgp_advertise_attr *baa, |
104 | struct bgp_advertise *adv) | |
105 | { | |
106 | adv->next = baa->adv; | |
107 | if (baa->adv) | |
108 | baa->adv->prev = adv; | |
109 | baa->adv = adv; | |
110 | } | |
111 | ||
94f2b392 | 112 | static void |
718e3744 | 113 | bgp_advertise_delete (struct bgp_advertise_attr *baa, |
114 | struct bgp_advertise *adv) | |
115 | { | |
116 | if (adv->next) | |
117 | adv->next->prev = adv->prev; | |
118 | if (adv->prev) | |
119 | adv->prev->next = adv->next; | |
120 | else | |
121 | baa->adv = adv->next; | |
122 | } | |
123 | ||
124 | static struct bgp_advertise_attr * | |
125 | bgp_advertise_intern (struct hash *hash, struct attr *attr) | |
126 | { | |
127 | struct bgp_advertise_attr ref; | |
128 | struct bgp_advertise_attr *baa; | |
129 | ||
130 | ref.attr = bgp_attr_intern (attr); | |
131 | baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc); | |
132 | baa->refcnt++; | |
133 | ||
134 | return baa; | |
135 | } | |
136 | ||
94f2b392 | 137 | static void |
718e3744 | 138 | bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) |
139 | { | |
140 | if (baa->refcnt) | |
141 | baa->refcnt--; | |
142 | ||
143 | if (baa->refcnt && baa->attr) | |
f6f434b2 | 144 | bgp_attr_unintern (&baa->attr); |
718e3744 | 145 | else |
146 | { | |
147 | if (baa->attr) | |
148 | { | |
149 | hash_release (hash, baa); | |
f6f434b2 | 150 | bgp_attr_unintern (&baa->attr); |
718e3744 | 151 | } |
152 | baa_free (baa); | |
153 | } | |
154 | } | |
6b0655a2 | 155 | |
718e3744 | 156 | /* BGP adjacency keeps minimal advertisement information. */ |
94f2b392 | 157 | static void |
718e3744 | 158 | bgp_adj_out_free (struct bgp_adj_out *adj) |
159 | { | |
200df115 | 160 | peer_unlock (adj->peer); /* adj_out peer reference */ |
718e3744 | 161 | XFREE (MTYPE_BGP_ADJ_OUT, adj); |
162 | } | |
163 | ||
164 | int | |
165 | bgp_adj_out_lookup (struct peer *peer, struct prefix *p, | |
166 | afi_t afi, safi_t safi, struct bgp_node *rn) | |
167 | { | |
168 | struct bgp_adj_out *adj; | |
169 | ||
170 | for (adj = rn->adj_out; adj; adj = adj->next) | |
171 | if (adj->peer == peer) | |
172 | break; | |
173 | ||
174 | if (! adj) | |
175 | return 0; | |
176 | ||
177 | return (adj->adv | |
178 | ? (adj->adv->baa ? 1 : 0) | |
179 | : (adj->attr ? 1 : 0)); | |
180 | } | |
181 | ||
182 | struct bgp_advertise * | |
183 | bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj, | |
184 | afi_t afi, safi_t safi) | |
185 | { | |
186 | struct bgp_advertise *adv; | |
187 | struct bgp_advertise_attr *baa; | |
188 | struct bgp_advertise *next; | |
cdabb8b6 | 189 | struct bgp_advertise_fifo *fhead; |
718e3744 | 190 | |
191 | adv = adj->adv; | |
192 | baa = adv->baa; | |
193 | next = NULL; | |
cdabb8b6 | 194 | fhead = &peer->sync[afi][safi]->withdraw; |
718e3744 | 195 | |
196 | if (baa) | |
197 | { | |
198 | /* Unlink myself from advertise attribute FIFO. */ | |
199 | bgp_advertise_delete (baa, adv); | |
200 | ||
201 | /* Fetch next advertise candidate. */ | |
202 | next = baa->adv; | |
203 | ||
204 | /* Unintern BGP advertise attribute. */ | |
205 | bgp_advertise_unintern (peer->hash[afi][safi], baa); | |
cdabb8b6 DS |
206 | |
207 | fhead = &peer->sync[afi][safi]->update; | |
718e3744 | 208 | } |
209 | ||
210 | /* Unlink myself from advertisement FIFO. */ | |
cdabb8b6 | 211 | BGP_ADV_FIFO_DEL (fhead, adv); |
718e3744 | 212 | |
213 | /* Free memory. */ | |
214 | bgp_advertise_free (adj->adv); | |
215 | adj->adv = NULL; | |
216 | ||
217 | return next; | |
218 | } | |
219 | ||
220 | void | |
221 | bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p, | |
222 | struct attr *attr, afi_t afi, safi_t safi, | |
223 | struct bgp_info *binfo) | |
224 | { | |
225 | struct bgp_adj_out *adj = NULL; | |
226 | struct bgp_advertise *adv; | |
227 | ||
750e8146 PJ |
228 | if (DISABLE_BGP_ANNOUNCE) |
229 | return; | |
718e3744 | 230 | |
231 | /* Look for adjacency information. */ | |
232 | if (rn) | |
233 | { | |
234 | for (adj = rn->adj_out; adj; adj = adj->next) | |
235 | if (adj->peer == peer) | |
236 | break; | |
237 | } | |
238 | ||
239 | if (! adj) | |
240 | { | |
241 | adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out)); | |
200df115 | 242 | adj->peer = peer_lock (peer); /* adj_out peer reference */ |
243 | ||
718e3744 | 244 | if (rn) |
245 | { | |
246 | BGP_ADJ_OUT_ADD (rn, adj); | |
247 | bgp_lock_node (rn); | |
248 | } | |
249 | } | |
250 | ||
251 | if (adj->adv) | |
252 | bgp_advertise_clean (peer, adj, afi, safi); | |
200df115 | 253 | |
718e3744 | 254 | adj->adv = bgp_advertise_new (); |
255 | ||
256 | adv = adj->adv; | |
257 | adv->rn = rn; | |
200df115 | 258 | |
259 | assert (adv->binfo == NULL); | |
260 | adv->binfo = bgp_info_lock (binfo); /* bgp_info adj_out reference */ | |
261 | ||
718e3744 | 262 | if (attr) |
263 | adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr); | |
264 | else | |
265 | adv->baa = baa_new (); | |
266 | adv->adj = adj; | |
267 | ||
268 | /* Add new advertisement to advertisement attribute list. */ | |
269 | bgp_advertise_add (adv->baa, adv); | |
270 | ||
cdabb8b6 | 271 | BGP_ADV_FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo); |
d889623f DS |
272 | |
273 | /* | |
274 | * Schedule write thread (by triggering adjustment of MRAI timer) only if | |
275 | * update FIFO has grown. Otherwise, it will be done upon the work queue | |
276 | * being fully processed. Only adjust timer if needed. | |
277 | */ | |
278 | if (!BGP_ROUTE_ADV_HOLD(peer->bgp) && | |
279 | (BGP_ADV_FIFO_COUNT(&peer->sync[afi][safi]->update) >= | |
280 | peer->bgp->adv_quanta)) | |
281 | { | |
282 | if (!peer->radv_adjusted) | |
283 | { | |
16286195 | 284 | if (bgp_debug_update(peer, NULL, 0)) |
d889623f DS |
285 | zlog_debug("%s scheduling MRAI timer after adj_out_set", peer->host); |
286 | bgp_adjust_routeadv(peer); | |
287 | } | |
288 | } | |
718e3744 | 289 | } |
290 | ||
291 | void | |
292 | bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p, | |
293 | afi_t afi, safi_t safi) | |
294 | { | |
295 | struct bgp_adj_out *adj; | |
296 | struct bgp_advertise *adv; | |
297 | ||
750e8146 PJ |
298 | if (DISABLE_BGP_ANNOUNCE) |
299 | return; | |
718e3744 | 300 | |
301 | /* Lookup existing adjacency, if it is not there return immediately. */ | |
302 | for (adj = rn->adj_out; adj; adj = adj->next) | |
303 | if (adj->peer == peer) | |
304 | break; | |
305 | ||
306 | if (! adj) | |
307 | return; | |
308 | ||
309 | /* Clearn up previous advertisement. */ | |
310 | if (adj->adv) | |
311 | bgp_advertise_clean (peer, adj, afi, safi); | |
312 | ||
313 | if (adj->attr) | |
314 | { | |
315 | /* We need advertisement structure. */ | |
316 | adj->adv = bgp_advertise_new (); | |
317 | adv = adj->adv; | |
318 | adv->rn = rn; | |
319 | adv->adj = adj; | |
320 | ||
321 | /* Add to synchronization entry for withdraw announcement. */ | |
cdabb8b6 | 322 | BGP_ADV_FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); |
718e3744 | 323 | |
d889623f DS |
324 | /* |
325 | * Schedule write thread only if withdraw FIFO has grown. Otherwise, | |
326 | * it will be done upon the work queue being fully processed. | |
327 | */ | |
328 | if (!BGP_ROUTE_ADV_HOLD(peer->bgp) && | |
329 | (BGP_ADV_FIFO_COUNT(&peer->sync[afi][safi]->withdraw) >= | |
330 | peer->bgp->wd_quanta)) | |
331 | { | |
332 | if (!peer->t_write) | |
333 | { | |
16286195 | 334 | if (bgp_debug_update(peer, NULL, 0)) |
d889623f DS |
335 | zlog_debug("%s scheduling write thread after adj_out_unset", |
336 | peer->host); | |
337 | BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); | |
338 | } | |
339 | } | |
718e3744 | 340 | } |
341 | else | |
342 | { | |
343 | /* Remove myself from adjacency. */ | |
344 | BGP_ADJ_OUT_DEL (rn, adj); | |
345 | ||
346 | /* Free allocated information. */ | |
347 | bgp_adj_out_free (adj); | |
348 | ||
349 | bgp_unlock_node (rn); | |
350 | } | |
351 | } | |
352 | ||
353 | void | |
354 | bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj, | |
355 | struct peer *peer, afi_t afi, safi_t safi) | |
356 | { | |
357 | if (adj->attr) | |
f6f434b2 | 358 | bgp_attr_unintern (&adj->attr); |
718e3744 | 359 | |
360 | if (adj->adv) | |
361 | bgp_advertise_clean (peer, adj, afi, safi); | |
362 | ||
363 | BGP_ADJ_OUT_DEL (rn, adj); | |
364 | bgp_adj_out_free (adj); | |
365 | } | |
6b0655a2 | 366 | |
718e3744 | 367 | void |
368 | bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) | |
369 | { | |
370 | struct bgp_adj_in *adj; | |
371 | ||
372 | for (adj = rn->adj_in; adj; adj = adj->next) | |
373 | { | |
374 | if (adj->peer == peer) | |
375 | { | |
376 | if (adj->attr != attr) | |
377 | { | |
f6f434b2 | 378 | bgp_attr_unintern (&adj->attr); |
718e3744 | 379 | adj->attr = bgp_attr_intern (attr); |
380 | } | |
381 | return; | |
382 | } | |
383 | } | |
384 | adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in)); | |
200df115 | 385 | adj->peer = peer_lock (peer); /* adj_in peer reference */ |
718e3744 | 386 | adj->attr = bgp_attr_intern (attr); |
387 | BGP_ADJ_IN_ADD (rn, adj); | |
388 | bgp_lock_node (rn); | |
389 | } | |
390 | ||
391 | void | |
392 | bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) | |
393 | { | |
f6f434b2 | 394 | bgp_attr_unintern (&bai->attr); |
718e3744 | 395 | BGP_ADJ_IN_DEL (rn, bai); |
200df115 | 396 | peer_unlock (bai->peer); /* adj_in peer reference */ |
718e3744 | 397 | XFREE (MTYPE_BGP_ADJ_IN, bai); |
398 | } | |
399 | ||
400 | void | |
401 | bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) | |
402 | { | |
403 | struct bgp_adj_in *adj; | |
404 | ||
405 | for (adj = rn->adj_in; adj; adj = adj->next) | |
406 | if (adj->peer == peer) | |
407 | break; | |
408 | ||
409 | if (! adj) | |
410 | return; | |
411 | ||
412 | bgp_adj_in_remove (rn, adj); | |
413 | bgp_unlock_node (rn); | |
414 | } | |
6b0655a2 | 415 | |
718e3744 | 416 | void |
417 | bgp_sync_init (struct peer *peer) | |
418 | { | |
419 | afi_t afi; | |
420 | safi_t safi; | |
421 | struct bgp_synchronize *sync; | |
422 | ||
423 | for (afi = AFI_IP; afi < AFI_MAX; afi++) | |
424 | for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) | |
425 | { | |
b51f126e PJ |
426 | sync = XCALLOC (MTYPE_BGP_SYNCHRONISE, |
427 | sizeof (struct bgp_synchronize)); | |
cdabb8b6 DS |
428 | BGP_ADV_FIFO_INIT (&sync->update); |
429 | BGP_ADV_FIFO_INIT (&sync->withdraw); | |
430 | BGP_ADV_FIFO_INIT (&sync->withdraw_low); | |
718e3744 | 431 | peer->sync[afi][safi] = sync; |
432 | peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); | |
433 | } | |
434 | } | |
435 | ||
436 | void | |
437 | bgp_sync_delete (struct peer *peer) | |
438 | { | |
439 | afi_t afi; | |
440 | safi_t safi; | |
441 | ||
442 | for (afi = AFI_IP; afi < AFI_MAX; afi++) | |
443 | for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) | |
444 | { | |
445 | if (peer->sync[afi][safi]) | |
9f906c7c | 446 | XFREE (MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]); |
718e3744 | 447 | peer->sync[afi][safi] = NULL; |
200df115 | 448 | |
449 | if (peer->hash[afi][safi]) | |
450 | hash_free (peer->hash[afi][safi]); | |
9f906c7c | 451 | peer->hash[afi][safi] = NULL; |
718e3744 | 452 | } |
453 | } |