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