Line data Source code
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"
34 : #include "bgpd/bgp_aspath.h"
35 : #include "bgpd/bgp_packet.h"
36 : #include "bgpd/bgp_fsm.h"
37 : #include "bgpd/bgp_mplsvpn.h"
38 :
39 : /* BGP advertise attribute is used for pack same attribute update into
40 : one packet. To do that we maintain attribute hash in struct
41 : peer. */
42 : static struct bgp_advertise_attr *
43 0 : baa_new (void)
44 : {
45 0 : return (struct bgp_advertise_attr *)
46 : XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr));
47 : }
48 :
49 : static void
50 0 : baa_free (struct bgp_advertise_attr *baa)
51 : {
52 0 : XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa);
53 0 : }
54 :
55 : static void *
56 0 : baa_hash_alloc (void *p)
57 : {
58 0 : struct bgp_advertise_attr * ref = (struct bgp_advertise_attr *) p;
59 : struct bgp_advertise_attr *baa;
60 :
61 0 : baa = baa_new ();
62 0 : baa->attr = ref->attr;
63 0 : return baa;
64 : }
65 :
66 : static unsigned int
67 0 : baa_hash_key (void *p)
68 : {
69 0 : struct bgp_advertise_attr * baa = (struct bgp_advertise_attr *) p;
70 :
71 0 : return attrhash_key_make (baa->attr);
72 : }
73 :
74 : static int
75 0 : baa_hash_cmp (const void *p1, const void *p2)
76 : {
77 0 : const struct bgp_advertise_attr * baa1 = p1;
78 0 : const struct bgp_advertise_attr * baa2 = p2;
79 :
80 0 : return attrhash_cmp (baa1->attr, baa2->attr);
81 : }
82 :
83 : /* BGP update and withdraw information is stored in BGP advertise
84 : structure. This structure is referred from BGP adjacency
85 : information. */
86 : static struct bgp_advertise *
87 0 : bgp_advertise_new (void)
88 : {
89 0 : return (struct bgp_advertise *)
90 : XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise));
91 : }
92 :
93 : static void
94 0 : bgp_advertise_free (struct bgp_advertise *adv)
95 : {
96 0 : if (adv->binfo)
97 0 : bgp_info_unlock (adv->binfo); /* bgp_advertise bgp_info reference */
98 0 : XFREE (MTYPE_BGP_ADVERTISE, adv);
99 0 : }
100 :
101 : static void
102 0 : bgp_advertise_add (struct bgp_advertise_attr *baa,
103 : struct bgp_advertise *adv)
104 : {
105 0 : adv->next = baa->adv;
106 0 : if (baa->adv)
107 0 : baa->adv->prev = adv;
108 0 : baa->adv = adv;
109 0 : }
110 :
111 : static void
112 0 : bgp_advertise_delete (struct bgp_advertise_attr *baa,
113 : struct bgp_advertise *adv)
114 : {
115 0 : if (adv->next)
116 0 : adv->next->prev = adv->prev;
117 0 : if (adv->prev)
118 0 : adv->prev->next = adv->next;
119 : else
120 0 : baa->adv = adv->next;
121 0 : }
122 :
123 : static struct bgp_advertise_attr *
124 0 : bgp_advertise_intern (struct hash *hash, struct attr *attr)
125 : {
126 : struct bgp_advertise_attr ref;
127 : struct bgp_advertise_attr *baa;
128 :
129 0 : ref.attr = bgp_attr_intern (attr);
130 0 : baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc);
131 0 : baa->refcnt++;
132 :
133 0 : return baa;
134 : }
135 :
136 : static void
137 0 : bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa)
138 : {
139 0 : if (baa->refcnt)
140 0 : baa->refcnt--;
141 :
142 0 : if (baa->refcnt && baa->attr)
143 0 : bgp_attr_unintern (&baa->attr);
144 : else
145 : {
146 0 : if (baa->attr)
147 : {
148 0 : hash_release (hash, baa);
149 0 : bgp_attr_unintern (&baa->attr);
150 : }
151 0 : baa_free (baa);
152 : }
153 0 : }
154 :
155 : /* BGP adjacency keeps minimal advertisement information. */
156 : static void
157 0 : bgp_adj_out_free (struct bgp_adj_out *adj)
158 : {
159 0 : peer_unlock (adj->peer); /* adj_out peer reference */
160 0 : XFREE (MTYPE_BGP_ADJ_OUT, adj);
161 0 : }
162 :
163 : int
164 0 : bgp_adj_out_lookup (struct peer *peer, struct prefix *p,
165 : afi_t afi, safi_t safi, struct bgp_node *rn)
166 : {
167 : struct bgp_adj_out *adj;
168 :
169 0 : for (adj = rn->adj_out; adj; adj = adj->next)
170 0 : if (adj->peer == peer)
171 0 : break;
172 :
173 0 : if (! adj)
174 0 : return 0;
175 :
176 0 : return (adj->adv
177 0 : ? (adj->adv->baa ? 1 : 0)
178 0 : : (adj->attr ? 1 : 0));
179 : }
180 :
181 : struct bgp_advertise *
182 0 : bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj,
183 : afi_t afi, safi_t safi)
184 : {
185 : struct bgp_advertise *adv;
186 : struct bgp_advertise_attr *baa;
187 : struct bgp_advertise *next;
188 :
189 0 : adv = adj->adv;
190 0 : baa = adv->baa;
191 0 : next = NULL;
192 :
193 0 : if (baa)
194 : {
195 : /* Unlink myself from advertise attribute FIFO. */
196 0 : bgp_advertise_delete (baa, adv);
197 :
198 : /* Fetch next advertise candidate. */
199 0 : next = baa->adv;
200 :
201 : /* Unintern BGP advertise attribute. */
202 0 : bgp_advertise_unintern (peer->hash[afi][safi], baa);
203 : }
204 :
205 : /* Unlink myself from advertisement FIFO. */
206 0 : FIFO_DEL (adv);
207 :
208 : /* Free memory. */
209 0 : bgp_advertise_free (adj->adv);
210 0 : adj->adv = NULL;
211 :
212 0 : return next;
213 : }
214 :
215 : void
216 0 : bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p,
217 : struct attr *attr, afi_t afi, safi_t safi,
218 : struct bgp_info *binfo)
219 : {
220 0 : struct bgp_adj_out *adj = NULL;
221 : struct bgp_advertise *adv;
222 :
223 : if (DISABLE_BGP_ANNOUNCE)
224 : return;
225 :
226 : /* Look for adjacency information. */
227 0 : if (rn)
228 : {
229 0 : for (adj = rn->adj_out; adj; adj = adj->next)
230 0 : if (adj->peer == peer)
231 0 : break;
232 : }
233 :
234 0 : if (! adj)
235 : {
236 0 : adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out));
237 0 : adj->peer = peer_lock (peer); /* adj_out peer reference */
238 :
239 0 : if (rn)
240 : {
241 0 : BGP_ADJ_OUT_ADD (rn, adj);
242 0 : bgp_lock_node (rn);
243 : }
244 : }
245 :
246 0 : if (adj->adv)
247 0 : bgp_advertise_clean (peer, adj, afi, safi);
248 :
249 0 : adj->adv = bgp_advertise_new ();
250 :
251 0 : adv = adj->adv;
252 0 : adv->rn = rn;
253 :
254 0 : assert (adv->binfo == NULL);
255 0 : adv->binfo = bgp_info_lock (binfo); /* bgp_info adj_out reference */
256 :
257 0 : if (attr)
258 0 : adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr);
259 : else
260 0 : adv->baa = baa_new ();
261 0 : adv->adj = adj;
262 :
263 : /* Add new advertisement to advertisement attribute list. */
264 0 : bgp_advertise_add (adv->baa, adv);
265 :
266 0 : FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo);
267 : }
268 :
269 : void
270 0 : bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p,
271 : afi_t afi, safi_t safi)
272 : {
273 : struct bgp_adj_out *adj;
274 : struct bgp_advertise *adv;
275 :
276 : if (DISABLE_BGP_ANNOUNCE)
277 : return;
278 :
279 : /* Lookup existing adjacency, if it is not there return immediately. */
280 0 : for (adj = rn->adj_out; adj; adj = adj->next)
281 0 : if (adj->peer == peer)
282 0 : break;
283 :
284 0 : if (! adj)
285 0 : return;
286 :
287 : /* Clearn up previous advertisement. */
288 0 : if (adj->adv)
289 0 : bgp_advertise_clean (peer, adj, afi, safi);
290 :
291 0 : if (adj->attr)
292 : {
293 : /* We need advertisement structure. */
294 0 : adj->adv = bgp_advertise_new ();
295 0 : adv = adj->adv;
296 0 : adv->rn = rn;
297 0 : adv->adj = adj;
298 :
299 : /* Add to synchronization entry for withdraw announcement. */
300 0 : FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo);
301 :
302 : /* Schedule packet write. */
303 0 : BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
304 : }
305 : else
306 : {
307 : /* Remove myself from adjacency. */
308 0 : BGP_ADJ_OUT_DEL (rn, adj);
309 :
310 : /* Free allocated information. */
311 0 : bgp_adj_out_free (adj);
312 :
313 0 : bgp_unlock_node (rn);
314 : }
315 : }
316 :
317 : void
318 0 : bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,
319 : struct peer *peer, afi_t afi, safi_t safi)
320 : {
321 0 : if (adj->attr)
322 0 : bgp_attr_unintern (&adj->attr);
323 :
324 0 : if (adj->adv)
325 0 : bgp_advertise_clean (peer, adj, afi, safi);
326 :
327 0 : BGP_ADJ_OUT_DEL (rn, adj);
328 0 : bgp_adj_out_free (adj);
329 0 : }
330 :
331 : void
332 0 : bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)
333 : {
334 : struct bgp_adj_in *adj;
335 :
336 0 : for (adj = rn->adj_in; adj; adj = adj->next)
337 : {
338 0 : if (adj->peer == peer)
339 : {
340 0 : if (adj->attr != attr)
341 : {
342 0 : bgp_attr_unintern (&adj->attr);
343 0 : adj->attr = bgp_attr_intern (attr);
344 : }
345 0 : return;
346 : }
347 : }
348 0 : adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in));
349 0 : adj->peer = peer_lock (peer); /* adj_in peer reference */
350 0 : adj->attr = bgp_attr_intern (attr);
351 0 : BGP_ADJ_IN_ADD (rn, adj);
352 0 : bgp_lock_node (rn);
353 : }
354 :
355 : void
356 0 : bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai)
357 : {
358 0 : bgp_attr_unintern (&bai->attr);
359 0 : BGP_ADJ_IN_DEL (rn, bai);
360 0 : peer_unlock (bai->peer); /* adj_in peer reference */
361 0 : XFREE (MTYPE_BGP_ADJ_IN, bai);
362 0 : }
363 :
364 : void
365 0 : bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer)
366 : {
367 : struct bgp_adj_in *adj;
368 :
369 0 : for (adj = rn->adj_in; adj; adj = adj->next)
370 0 : if (adj->peer == peer)
371 0 : break;
372 :
373 0 : if (! adj)
374 0 : return;
375 :
376 0 : bgp_adj_in_remove (rn, adj);
377 0 : bgp_unlock_node (rn);
378 : }
379 :
380 : void
381 4 : bgp_sync_init (struct peer *peer)
382 : {
383 : afi_t afi;
384 : safi_t safi;
385 : struct bgp_synchronize *sync;
386 :
387 12 : for (afi = AFI_IP; afi < AFI_MAX; afi++)
388 40 : for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
389 : {
390 32 : sync = XCALLOC (MTYPE_BGP_SYNCHRONISE,
391 : sizeof (struct bgp_synchronize));
392 32 : FIFO_INIT (&sync->update);
393 32 : FIFO_INIT (&sync->withdraw);
394 32 : FIFO_INIT (&sync->withdraw_low);
395 32 : peer->sync[afi][safi] = sync;
396 32 : peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp);
397 : }
398 4 : }
399 :
400 : void
401 0 : bgp_sync_delete (struct peer *peer)
402 : {
403 : afi_t afi;
404 : safi_t safi;
405 :
406 0 : for (afi = AFI_IP; afi < AFI_MAX; afi++)
407 0 : for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
408 : {
409 0 : if (peer->sync[afi][safi])
410 0 : XFREE (MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
411 0 : peer->sync[afi][safi] = NULL;
412 :
413 0 : if (peer->hash[afi][safi])
414 0 : hash_free (peer->hash[afi][safi]);
415 0 : peer->hash[afi][safi] = NULL;
416 : }
417 0 : }
|