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