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