summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_advertise.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_advertise.c')
-rw-r--r--bgpd/bgp_advertise.c405
1 files changed, 405 insertions, 0 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
new file mode 100644
index 000000000..4778a9773
--- /dev/null
+++ b/bgpd/bgp_advertise.c
@@ -0,0 +1,405 @@
+/* BGP advertisement and adjacency
+ Copyright (C) 1996, 97, 98, 99, 2000 Kunihiro Ishiguro
+
+This file is part of GNU Zebra.
+
+GNU Zebra is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU Zebra is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Zebra; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "memory.h"
+#include "prefix.h"
+#include "hash.h"
+#include "thread.h"
+
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_table.h"
+#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_advertise.h"
+#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_packet.h"
+#include "bgpd/bgp_fsm.h"
+#include "bgpd/bgp_mplsvpn.h"
+
+/* BGP advertise attribute is used for pack same attribute update into
+ one packet. To do that we maintain attribute hash in struct
+ peer. */
+static struct bgp_advertise_attr *
+baa_new ()
+{
+ return (struct bgp_advertise_attr *)
+ XCALLOC (MTYPE_BGP_ADVERTISE_ATTR, sizeof (struct bgp_advertise_attr));
+}
+
+static void
+baa_free (struct bgp_advertise_attr *baa)
+{
+ XFREE (MTYPE_BGP_ADVERTISE_ATTR, baa);
+}
+
+static void *
+baa_hash_alloc (struct bgp_advertise_attr *ref)
+{
+ struct bgp_advertise_attr *baa;
+
+ baa = baa_new ();
+ baa->attr = ref->attr;
+ return baa;
+}
+
+static unsigned int
+baa_hash_key (struct bgp_advertise_attr *baa)
+{
+ return attrhash_key_make (baa->attr);
+}
+
+static int
+baa_hash_cmp (struct bgp_advertise_attr *baa1, struct bgp_advertise_attr *baa2)
+{
+ return attrhash_cmp (baa1->attr, baa2->attr);
+}
+
+/* BGP update and withdraw information is stored in BGP advertise
+ structure. This structure is referred from BGP adjacency
+ information. */
+static struct bgp_advertise *
+bgp_advertise_new ()
+{
+ return (struct bgp_advertise *)
+ XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise));
+}
+
+void
+bgp_advertise_free (struct bgp_advertise *adv)
+{
+ XFREE (MTYPE_BGP_ADVERTISE, adv);
+}
+
+void
+bgp_advertise_add (struct bgp_advertise_attr *baa,
+ struct bgp_advertise *adv)
+{
+ adv->next = baa->adv;
+ if (baa->adv)
+ baa->adv->prev = adv;
+ baa->adv = adv;
+}
+
+void
+bgp_advertise_delete (struct bgp_advertise_attr *baa,
+ struct bgp_advertise *adv)
+{
+ if (adv->next)
+ adv->next->prev = adv->prev;
+ if (adv->prev)
+ adv->prev->next = adv->next;
+ else
+ baa->adv = adv->next;
+}
+
+static struct bgp_advertise_attr *
+bgp_advertise_intern (struct hash *hash, struct attr *attr)
+{
+ struct bgp_advertise_attr ref;
+ struct bgp_advertise_attr *baa;
+
+ ref.attr = bgp_attr_intern (attr);
+ baa = (struct bgp_advertise_attr *) hash_get (hash, &ref, baa_hash_alloc);
+ baa->refcnt++;
+
+ return baa;
+}
+
+void
+bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa)
+{
+ if (baa->refcnt)
+ baa->refcnt--;
+
+ if (baa->refcnt && baa->attr)
+ bgp_attr_unintern (baa->attr);
+ else
+ {
+ if (baa->attr)
+ {
+ hash_release (hash, baa);
+ bgp_attr_unintern (baa->attr);
+ }
+ baa_free (baa);
+ }
+}
+
+/* BGP adjacency keeps minimal advertisement information. */
+void
+bgp_adj_out_free (struct bgp_adj_out *adj)
+{
+ XFREE (MTYPE_BGP_ADJ_OUT, adj);
+}
+
+int
+bgp_adj_out_lookup (struct peer *peer, struct prefix *p,
+ afi_t afi, safi_t safi, struct bgp_node *rn)
+{
+ struct bgp_adj_out *adj;
+
+ for (adj = rn->adj_out; adj; adj = adj->next)
+ if (adj->peer == peer)
+ break;
+
+ if (! adj)
+ return 0;
+
+ return (adj->adv
+ ? (adj->adv->baa ? 1 : 0)
+ : (adj->attr ? 1 : 0));
+}
+
+struct bgp_advertise *
+bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj,
+ afi_t afi, safi_t safi)
+{
+ struct bgp_advertise *adv;
+ struct bgp_advertise_attr *baa;
+ struct bgp_advertise *next;
+
+ adv = adj->adv;
+ baa = adv->baa;
+ next = NULL;
+
+ if (baa)
+ {
+ /* Unlink myself from advertise attribute FIFO. */
+ bgp_advertise_delete (baa, adv);
+
+ /* Fetch next advertise candidate. */
+ next = baa->adv;
+
+ /* Unintern BGP advertise attribute. */
+ bgp_advertise_unintern (peer->hash[afi][safi], baa);
+ adv->baa = NULL;
+ adv->rn = NULL;
+ }
+
+ /* Unlink myself from advertisement FIFO. */
+ FIFO_DEL (adv);
+
+ /* Free memory. */
+ bgp_advertise_free (adj->adv);
+ adj->adv = NULL;
+
+ return next;
+}
+
+void
+bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p,
+ struct attr *attr, afi_t afi, safi_t safi,
+ struct bgp_info *binfo)
+{
+ struct bgp_adj_out *adj = NULL;
+ struct bgp_advertise *adv;
+
+#ifdef DISABLE_BGP_ANNOUNCE
+ return;
+#endif /* DISABLE_BGP_ANNOUNCE */
+
+ /* Look for adjacency information. */
+ if (rn)
+ {
+ for (adj = rn->adj_out; adj; adj = adj->next)
+ if (adj->peer == peer)
+ break;
+ }
+
+ if (! adj)
+ {
+ adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out));
+
+ if (rn)
+ {
+ BGP_ADJ_OUT_ADD (rn, adj);
+ bgp_lock_node (rn);
+ }
+ }
+
+ if (adj->adv)
+ bgp_advertise_clean (peer, adj, afi, safi);
+
+ adj->peer = peer;
+ adj->adv = bgp_advertise_new ();
+
+ adv = adj->adv;
+ adv->rn = rn;
+ adv->binfo = binfo;
+ if (attr)
+ adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr);
+ else
+ adv->baa = baa_new ();
+ adv->adj = adj;
+
+ /* Add new advertisement to advertisement attribute list. */
+ bgp_advertise_add (adv->baa, adv);
+
+ FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo);
+}
+
+void
+bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p,
+ afi_t afi, safi_t safi)
+{
+ struct bgp_adj_out *adj;
+ struct bgp_advertise *adv;
+
+#ifdef DISABLE_BGP_ANNOUNCE
+ return;
+#endif /* DISABLE_BGP_ANNOUNCE */
+
+ /* Lookup existing adjacency, if it is not there return immediately. */
+ for (adj = rn->adj_out; adj; adj = adj->next)
+ if (adj->peer == peer)
+ break;
+
+ if (! adj)
+ return;
+
+ /* Clearn up previous advertisement. */
+ if (adj->adv)
+ bgp_advertise_clean (peer, adj, afi, safi);
+
+ if (adj->attr)
+ {
+ /* We need advertisement structure. */
+ adj->adv = bgp_advertise_new ();
+ adv = adj->adv;
+ adv->rn = rn;
+ adv->adj = adj;
+
+ /* Add to synchronization entry for withdraw announcement. */
+ FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo);
+
+ /* Schedule packet write. */
+ BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+ }
+ else
+ {
+ /* Remove myself from adjacency. */
+ BGP_ADJ_OUT_DEL (rn, adj);
+
+ /* Free allocated information. */
+ bgp_adj_out_free (adj);
+
+ bgp_unlock_node (rn);
+ }
+}
+
+void
+bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,
+ struct peer *peer, afi_t afi, safi_t safi)
+{
+ if (adj->attr)
+ bgp_attr_unintern (adj->attr);
+
+ if (adj->adv)
+ bgp_advertise_clean (peer, adj, afi, safi);
+
+ BGP_ADJ_OUT_DEL (rn, adj);
+ bgp_adj_out_free (adj);
+}
+
+void
+bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)
+{
+ struct bgp_adj_in *adj;
+
+ for (adj = rn->adj_in; adj; adj = adj->next)
+ {
+ if (adj->peer == peer)
+ {
+ if (adj->attr != attr)
+ {
+ bgp_attr_unintern (adj->attr);
+ adj->attr = bgp_attr_intern (attr);
+ }
+ return;
+ }
+ }
+ adj = XCALLOC (MTYPE_BGP_ADJ_IN, sizeof (struct bgp_adj_in));
+ adj->peer = peer;
+ adj->attr = bgp_attr_intern (attr);
+ BGP_ADJ_IN_ADD (rn, adj);
+ bgp_lock_node (rn);
+}
+
+void
+bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai)
+{
+ bgp_attr_unintern (bai->attr);
+ BGP_ADJ_IN_DEL (rn, bai);
+ XFREE (MTYPE_BGP_ADJ_IN, bai);
+}
+
+void
+bgp_adj_in_unset (struct bgp_node *rn, struct peer *peer)
+{
+ struct bgp_adj_in *adj;
+
+ for (adj = rn->adj_in; adj; adj = adj->next)
+ if (adj->peer == peer)
+ break;
+
+ if (! adj)
+ return;
+
+ bgp_adj_in_remove (rn, adj);
+ bgp_unlock_node (rn);
+}
+
+void
+bgp_sync_init (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_synchronize *sync;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ sync = XCALLOC (MTYPE_TMP, sizeof (struct bgp_synchronize));
+ FIFO_INIT (&sync->update);
+ FIFO_INIT (&sync->withdraw);
+ FIFO_INIT (&sync->withdraw_low);
+ peer->sync[afi][safi] = sync;
+ peer->hash[afi][safi] = hash_create (baa_hash_key, baa_hash_cmp);
+ }
+}
+
+void
+bgp_sync_delete (struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ {
+ if (peer->sync[afi][safi])
+ XFREE (MTYPE_TMP, peer->sync[afi][safi]);
+ peer->sync[afi][safi] = NULL;
+
+ hash_free (peer->hash[afi][safi]);
+ }
+}