1/* BGP advertisement and adjacency 2 Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro 3 4This file is part of GNU Zebra. 5 6GNU Zebra is free software; you can redistribute it and/or modify it 7under the terms of the GNU General Public License as published by the 8Free Software Foundation; either version 2, or (at your option) any 9later version. 10 11GNU Zebra is distributed in the hope that it will be useful, but 12WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with GNU Zebra; see the file COPYING. If not, write to the Free 18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 1902111-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. */ 42static struct bgp_advertise_attr * 43baa_new (void) 44{ 45 return (struct bgp_advertise_attr *) 46 XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr)); 47} 48 49static void 50baa_free (struct bgp_advertise_attr *baa) 51{ 52 XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa); 53} 54 55static void * 56baa_hash_alloc (void *p) 57{ 58 struct bgp_advertise_attr * ref = (struct bgp_advertise_attr *) p; 59 struct bgp_advertise_attr *baa; 60 61 baa = baa_new (); 62 baa->attr = ref->attr; 63 return baa; 64} 65 66static unsigned int 67baa_hash_key (void *p) 68{ 69 struct bgp_advertise_attr * baa = (struct bgp_advertise_attr *) p; 70 71 return attrhash_key_make (baa->attr); 72} 73 74static int 75baa_hash_cmp (const void *p1, const void *p2) 76{ 77 const struct bgp_advertise_attr * baa1 = p1; 78 const struct bgp_advertise_attr * baa2 = p2; 79 80 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. */ 86static struct bgp_advertise * 87bgp_advertise_new (void) 88{ 89 return (struct bgp_advertise *) 90 XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise)); 91} 92 93static void 94bgp_advertise_free (struct bgp_advertise *adv) 95{ 96 if (adv->binfo) 97 bgp_info_unlock (adv->binfo); /* bgp_advertise bgp_info reference */ 98 XFREE (MTYPE_BGP_ADVERTISE, adv); 99} 100 101static void 102bgp_advertise_add (struct bgp_advertise_attr *baa, 103 struct bgp_advertise *adv) 104{ 105 adv->next = baa->adv; 106 if (baa->adv) 107 baa->adv->prev = adv; 108 baa->adv = adv; 109} 110 111static void 112bgp_advertise_delete (struct bgp_advertise_attr *baa, 113 struct bgp_advertise *adv) 114{ 115 if (adv->next) 116 adv->next->prev = adv->prev; 117 if (adv->prev) 118 adv->prev->next = adv->next; 119 else 120 baa->adv = adv->next; 121} 122 123static struct bgp_advertise_attr * 124bgp_advertise_intern (struct hash *hash, struct attr *attr) 125{ 126 struct bgp_advertise_attr ref; 127 struct bgp_advertise_attr *baa; 128 129 ref.attr = bgp_attr_intern (attr); 130 baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc); 131 baa->refcnt++; 132 133 return baa; 134} 135 136static void 137bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) 138{ 139 if (baa->refcnt) 140 baa->refcnt--; 141 142 if (baa->refcnt && baa->attr) 143 bgp_attr_unintern (&baa->attr); 144 else 145 { 146 if (baa->attr) 147 { 148 hash_release (hash, baa); 149 bgp_attr_unintern (&baa->attr); 150 } 151 baa_free (baa); 152 } 153} 154 155/* BGP adjacency keeps minimal advertisement information. */ 156static void 157bgp_adj_out_free (struct bgp_adj_out *adj) 158{ 159 peer_unlock (adj->peer); /* adj_out peer reference */ 160 XFREE (MTYPE_BGP_ADJ_OUT, adj); 161} 162 163int 164bgp_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 for (adj = rn->adj_out; adj; adj = adj->next) 170 if (adj->peer == peer) 171 break; 172 173 if (! adj) 174 return 0; 175 176 return (adj->adv 177 ? (adj->adv->baa ? 1 : 0) 178 : (adj->attr ? 1 : 0)); 179} 180 181struct bgp_advertise * 182bgp_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 adv = adj->adv; 190 baa = adv->baa; 191 next = NULL; 192 193 if (baa) 194 { 195 /* Unlink myself from advertise attribute FIFO. */ 196 bgp_advertise_delete (baa, adv); 197 198 /* Fetch next advertise candidate. */ 199 next = baa->adv; 200 201 /* Unintern BGP advertise attribute. */ 202 bgp_advertise_unintern (peer->hash[afi][safi], baa); 203 } 204 205 /* Unlink myself from advertisement FIFO. */ 206 FIFO_DEL (adv); 207 208 /* Free memory. */ 209 bgp_advertise_free (adj->adv); 210 adj->adv = NULL; 211 212 return next; 213} 214 215void 216bgp_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 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 if (rn) 228 { 229 for (adj = rn->adj_out; adj; adj = adj->next) 230 if (adj->peer == peer) 231 break; 232 } 233 234 if (! adj) 235 { 236 adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out)); 237 adj->peer = peer_lock (peer); /* adj_out peer reference */ 238 239 if (rn) 240 { 241 BGP_ADJ_OUT_ADD (rn, adj); 242 bgp_lock_node (rn); 243 } 244 } 245 246 if (adj->adv) 247 bgp_advertise_clean (peer, adj, afi, safi); 248 249 adj->adv = bgp_advertise_new (); 250 251 adv = adj->adv; 252 adv->rn = rn; 253 254 assert (adv->binfo == NULL); 255 adv->binfo = bgp_info_lock (binfo); /* bgp_info adj_out reference */ 256 257 if (attr) 258 adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr); 259 else 260 adv->baa = baa_new (); 261 adv->adj = adj; 262 263 /* Add new advertisement to advertisement attribute list. */ 264 bgp_advertise_add (adv->baa, adv); 265 266 FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo); 267} 268 269void 270bgp_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 for (adj = rn->adj_out; adj; adj = adj->next) 281 if (adj->peer == peer) 282 break; 283 284 if (! adj) 285 return; 286 287 /* Clearn up previous advertisement. */ 288 if (adj->adv) 289 bgp_advertise_clean (peer, adj, afi, safi); 290 291 if (adj->attr) 292 { 293 /* We need advertisement structure. */ 294 adj->adv = bgp_advertise_new (); 295 adv = adj->adv; 296 adv->rn = rn; 297 adv->adj = adj; 298 299 /* Add to synchronization entry for withdraw announcement. */ 300 FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo); 301 302 /* Schedule packet write. */ 303 BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); 304 } 305 else 306 { 307 /* Remove myself from adjacency. */ 308 BGP_ADJ_OUT_DEL (rn, adj); 309 310 /* Free allocated information. */ 311 bgp_adj_out_free (adj); 312 313 bgp_unlock_node (rn); 314 } 315} 316 317void 318bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj, 319 struct peer *peer, afi_t afi, safi_t safi) 320{ 321 if (adj->attr) 322 bgp_attr_unintern (&adj->attr); 323 324 if (adj->adv) 325 bgp_advertise_clean (peer, adj, afi, safi); 326 327 BGP_ADJ_OUT_DEL (rn, adj); 328 bgp_adj_out_free (adj); 329} 330 331void 332bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr) 333{ 334 struct bgp_adj_in *adj; 335 336 for (adj = rn->adj_in; adj; adj = adj->next) 337 { 338 if (adj->peer == peer) 339 { 340 if (adj->attr != attr) 341 { 342 bgp_attr_unintern (&adj->attr); 343 adj->attr = bgp_attr_intern (attr); 344 } 345 return; 346 } 347 } 348 adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in)); 349 adj->peer = peer_lock (peer); /* adj_in peer reference */ 350 adj->attr = bgp_attr_intern (attr); 351 BGP_ADJ_IN_ADD (rn, adj); 352 bgp_lock_node (rn); 353} 354 355void 356bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai) 357{ 358 bgp_attr_unintern (&bai->attr); 359 BGP_ADJ_IN_DEL (rn, bai); 360 peer_unlock (bai->peer); /* adj_in peer reference */ 361 XFREE (MTYPE_BGP_ADJ_IN, bai); 362} 363 364void 365bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer) 366{ 367 struct bgp_adj_in *adj; 368 369 for (adj = rn->adj_in; adj; adj = adj->next) 370 if (adj->peer == peer) 371 break; 372 373 if (! adj) 374 return; 375 376 bgp_adj_in_remove (rn, adj); 377 bgp_unlock_node (rn); 378} 379 380void 381bgp_sync_init (struct peer *peer) 382{ 383 afi_t afi; 384 safi_t safi; 385 struct bgp_synchronize *sync; 386 387 for (afi = AFI_IP; afi < AFI_MAX; afi++) 388 for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) 389 { 390 sync = XCALLOC (MTYPE_BGP_SYNCHRONISE, 391 sizeof (struct bgp_synchronize)); 392 FIFO_INIT (&sync->update); 393 FIFO_INIT (&sync->withdraw); 394 FIFO_INIT (&sync->withdraw_low); 395 peer->sync[afi][safi] = sync; 396 peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp); 397 } 398} 399 400void 401bgp_sync_delete (struct peer *peer) 402{ 403 afi_t afi; 404 safi_t safi; 405 406 for (afi = AFI_IP; afi < AFI_MAX; afi++) 407 for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) 408 { 409 if (peer->sync[afi][safi]) 410 XFREE (MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]); 411 peer->sync[afi][safi] = NULL; 412 413 if (peer->hash[afi][safi]) 414 hash_free (peer->hash[afi][safi]); 415 peer->hash[afi][safi] = NULL; 416 } 417} 418