Statistics
| Branch: | Revision:

iof-bird-daemon / proto / bgp / bgp.c @ 4847a894

History | View | Annotate | Download (18.8 KB)

1
/*
2
 *        BIRD -- The Border Gateway Protocol
3
 *
4
 *        (c) 2000 Martin Mares <mj@ucw.cz>
5
 *
6
 *        Can be freely distributed and used under the terms of the GNU GPL.
7
 */
8

    
9
/**
10
 * DOC: Border Gateway Protocol
11
 *
12
 * The BGP protocol is implemented in three parts: |bgp.c| which takes care of the
13
 * connection and most of the interface with BIRD core, |packets.c| handling
14
 * both incoming and outgoing BGP packets and |attrs.c| containing functions for
15
 * manipulation with BGP attribute lists.
16
 *
17
 * As opposed to the other existing routing daemons, BIRD has a sophisticated core
18
 * architecture which is able to keep all the information needed by BGP in the
19
 * primary routing table, therefore no complex data structures like a central
20
 * BGP table are needed. This increases memory footprint of a BGP router with
21
 * many connections, but not too much and, which is more important, it makes
22
 * BGP much easier to implement.
23
 *
24
 * Each instance of BGP (corresponding to a single BGP peer) is described by a &bgp_proto
25
 * structure to which are attached individual connections represented by &bgp_connection
26
 * (usually, there exists only one connection, but during BGP session setup, there
27
 * can be more of them). The connections are handled according to the BGP state machine
28
 * defined in the RFC with all the timers and all the parameters configurable.
29
 *
30
 * In incoming direction, we listen on the connection's socket and each time we receive
31
 * some input, we pass it to bgp_rx(). It decodes packet headers and the markers and
32
 * passes complete packets to bgp_rx_packet() which distributes the packet according
33
 * to its type.
34
 *
35
 * In outgoing direction, we gather all the routing updates and sort them to buckets
36
 * (&bgp_bucket) according to their attributes (we keep a hash table for fast comparison
37
 * of &rta's and a &fib which helps us to find if we already have another route for
38
 * the same destination queued for sending, so that we can replace it with the new one
39
 * immediately instead of sending both updates). There also exists a special bucket holding
40
 * all the route withdrawals which cannot be queued anywhere else as they don't have any
41
 * attributes. If we have any packet to send (due to either new routes or the connection
42
 * tracking code wanting to send a Open, Keepalive or Notification message), we call
43
 * bgp_schedule_packet() which sets the corresponding bit in a @packet_to_send
44
 * bit field in &bgp_conn and as soon as the transmit socket buffer becomes empty,
45
 * we call bgp_fire_tx(). It inspects state of all the packet type bits and calls
46
 * the corresponding bgp_create_xx() functions, eventually rescheduling the same packet
47
 * type if we have more data of the same type to send.
48
 *
49
 * The processing of attributes consists of two functions: bgp_decode_attrs() for checking
50
 * of the attribute blocks and translating them to the language of BIRD's extended attributes
51
 * and bgp_encode_attrs() which does the converse. Both functions are built around a
52
 * @bgp_attr_table array describing all important characteristics of all known attributes.
53
 * Unknown transitive attributes are attached to the route as %EAF_TYPE_OPAQUE byte streams.
54
 */
55

    
56
#undef LOCAL_DEBUG
57

    
58
#include "nest/bird.h"
59
#include "nest/iface.h"
60
#include "nest/protocol.h"
61
#include "nest/route.h"
62
#include "nest/locks.h"
63
#include "conf/conf.h"
64
#include "lib/socket.h"
65
#include "lib/resource.h"
66
#include "lib/string.h"
67

    
68
#include "bgp.h"
69

    
70
struct linpool *bgp_linpool;                /* Global temporary pool */
71
static sock *bgp_listen_sk;                /* Global listening socket */
72
static int bgp_counter;                        /* Number of protocol instances using the listening socket */
73
static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established" };
74

    
75
static void bgp_connect(struct bgp_proto *p);
76
static void bgp_initiate(struct bgp_proto *p);
77
static void bgp_setup_listen_sk(void);
78

    
79

    
80
static void
81
bgp_close(struct bgp_proto *p)
82
{
83
  ASSERT(bgp_counter);
84
  bgp_counter--;
85

    
86
  if (p->cf->password)
87
    sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, NULL);
88

    
89
  if (!bgp_counter)
90
    {
91
      rfree(bgp_listen_sk);
92
      bgp_listen_sk = NULL;
93
      rfree(bgp_linpool);
94
      bgp_linpool = NULL;
95
    }
96
}
97

    
98
/**
99
 * bgp_start_timer - start a BGP timer
100
 * @t: timer
101
 * @value: time to fire (0 to disable the timer)
102
 *
103
 * This functions calls tm_start() on @t with time @value and the
104
 * amount of randomization suggested by the BGP standard. Please use
105
 * it for all BGP timers.
106
 */
107
void
108
bgp_start_timer(timer *t, int value)
109
{
110
  if (value)
111
    {
112
      /* The randomization procedure is specified in RFC 1771: 9.2.3.3 */
113
      t->randomize = value / 4;
114
      tm_start(t, value - t->randomize);
115
    }
116
  else
117
    tm_stop(t);
118
}
119

    
120
/**
121
 * bgp_close_conn - close a BGP connection
122
 * @conn: connection to close
123
 *
124
 * This function takes a connection described by the &bgp_conn structure,
125
 * closes its socket and frees all resources associated with it.
126
 *
127
 * If the connection is being closed due to a protocol error, adjust
128
 * the connection restart timer as well according to the error recovery
129
 * policy set in the configuration.
130
 *
131
 * If the connection was marked as primary, it shuts down the protocol as well.
132
 */
133
void
134
bgp_close_conn(struct bgp_conn *conn)
135
{
136
  struct bgp_proto *p = conn->bgp;
137
  struct bgp_config *cf = p->cf;
138

    
139
  DBG("BGP: Closing connection\n");
140
  conn->packets_to_send = 0;
141
  rfree(conn->connect_retry_timer);
142
  conn->connect_retry_timer = NULL;
143
  rfree(conn->keepalive_timer);
144
  conn->keepalive_timer = NULL;
145
  rfree(conn->hold_timer);
146
  conn->hold_timer = NULL;
147
  rfree(conn->sk);
148
  conn->sk = NULL;
149
  conn->state = BS_IDLE;
150
  if (conn->error_flag > 1)
151
    {
152
      if (cf->disable_after_error)
153
        p->p.disabled = 1;
154
      if (p->last_connect && (bird_clock_t)(p->last_connect + cf->error_amnesia_time) < now)
155
        p->startup_delay = 0;
156
      if (!p->startup_delay)
157
        p->startup_delay = cf->error_delay_time_min;
158
      else
159
        {
160
          p->startup_delay *= 2;
161
          if (p->startup_delay > cf->error_delay_time_max)
162
            p->startup_delay = cf->error_delay_time_max;
163
        }
164
    }
165
  if (conn->primary)
166
    {
167
      bgp_close(p);
168
      p->conn = NULL;
169
      proto_notify_state(&p->p, PS_DOWN);
170
    }
171
  else if (conn->error_flag > 1)
172
    bgp_initiate(p);
173
}
174

    
175
static int
176
bgp_graceful_close_conn(struct bgp_conn *c)
177
{
178
  switch (c->state)
179
    {
180
    case BS_IDLE:
181
      return 0;
182
    case BS_CONNECT:
183
    case BS_ACTIVE:
184
      bgp_close_conn(c);
185
      return 1;
186
    case BS_OPENSENT:
187
    case BS_OPENCONFIRM:
188
    case BS_ESTABLISHED:
189
      bgp_error(c, 6, 0, NULL, 0);
190
      return 1;
191
    default:
192
      bug("bgp_graceful_close_conn: Unknown state %d", c->state);
193
    }
194
}
195

    
196
static void
197
bgp_send_open(struct bgp_conn *conn)
198
{
199
  DBG("BGP: Sending open\n");
200
  conn->sk->rx_hook = bgp_rx;
201
  conn->sk->tx_hook = bgp_tx;
202
  tm_stop(conn->connect_retry_timer);
203
  bgp_schedule_packet(conn, PKT_OPEN);
204
  conn->state = BS_OPENSENT;
205
  bgp_start_timer(conn->hold_timer, conn->bgp->cf->initial_hold_time);
206
}
207

    
208
static void
209
bgp_connected(sock *sk)
210
{
211
  struct bgp_conn *conn = sk->data;
212
  struct bgp_proto *p = conn->bgp;
213

    
214
  BGP_TRACE(D_EVENTS, "Connected");
215
  bgp_send_open(conn);
216
}
217

    
218
static void
219
bgp_connect_timeout(timer *t)
220
{
221
  struct bgp_conn *conn = t->data;
222
  struct bgp_proto *p = conn->bgp;
223

    
224
  DBG("BGP: connect_timeout\n");
225
  bgp_close_conn(conn);
226
  bgp_connect(p);
227
}
228

    
229
static void
230
bgp_sock_err(sock *sk, int err)
231
{
232
  struct bgp_conn *conn = sk->data;
233
  struct bgp_proto *p = conn->bgp;
234

    
235
  if (err)
236
    BGP_TRACE(D_EVENTS, "Connection lost (%M)", err);
237
  else
238
    BGP_TRACE(D_EVENTS, "Connection closed");
239
  switch (conn->state)
240
    {
241
    case BS_CONNECT:
242
    case BS_OPENSENT:
243
      rfree(conn->sk);
244
      conn->sk = NULL;
245
      conn->state = BS_ACTIVE;
246
      bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
247
      break;
248
    case BS_OPENCONFIRM:
249
    case BS_ESTABLISHED:
250
      bgp_close_conn(conn);
251
      break;
252
    default:
253
      bug("bgp_sock_err called in invalid state %d", conn->state);
254
    }
255
}
256

    
257
static void
258
bgp_hold_timeout(timer *t)
259
{
260
  struct bgp_conn *conn = t->data;
261

    
262
  DBG("BGP: Hold timeout, closing connection\n");
263
  bgp_error(conn, 4, 0, NULL, 0);
264
}
265

    
266
static void
267
bgp_keepalive_timeout(timer *t)
268
{
269
  struct bgp_conn *conn = t->data;
270

    
271
  DBG("BGP: Keepalive timer\n");
272
  bgp_schedule_packet(conn, PKT_KEEPALIVE);
273
}
274

    
275
static void
276
bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
277
{
278
  timer *t;
279

    
280
  conn->sk = NULL;
281
  conn->bgp = p;
282
  conn->packets_to_send = 0;
283
  conn->error_flag = 0;
284
  conn->primary = 0;
285

    
286
  t = conn->connect_retry_timer = tm_new(p->p.pool);
287
  t->hook = bgp_connect_timeout;
288
  t->data = conn;
289
  t = conn->hold_timer = tm_new(p->p.pool);
290
  t->hook = bgp_hold_timeout;
291
  t->data = conn;
292
  t = conn->keepalive_timer = tm_new(p->p.pool);
293
  t->hook = bgp_keepalive_timeout;
294
  t->data = conn;
295
}
296

    
297
static void
298
bgp_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s)
299
{
300
  s->data = conn;
301
  s->ttl = p->cf->multihop ? : 1;
302
  s->rbsize = BGP_RX_BUFFER_SIZE;
303
  s->tbsize = BGP_TX_BUFFER_SIZE;
304
  s->err_hook = bgp_sock_err;
305
  s->tos = IP_PREC_INTERNET_CONTROL;
306
  conn->sk = s;
307
}
308

    
309
/**
310
 * bgp_connect - initiate an outgoing connection
311
 * @p: BGP instance
312
 *
313
 * The bgp_connect() function creates a new &bgp_conn and initiates
314
 * a TCP connection to the peer. The rest of connection setup is governed
315
 * by the BGP state machine as described in the standard.
316
 */
317
static void
318
bgp_connect(struct bgp_proto *p)        /* Enter Connect state and start establishing connection */
319
{
320
  sock *s;
321
  struct bgp_conn *conn = &p->outgoing_conn;
322

    
323
  DBG("BGP: Connecting\n");
324
  p->last_connect = now;
325
  s = sk_new(p->p.pool);
326
  s->type = SK_TCP_ACTIVE;
327
  if (ipa_nonzero(p->cf->source_addr))
328
    s->saddr = p->cf->source_addr;
329
  else
330
    s->saddr = p->local_addr;
331
  s->daddr = p->cf->remote_ip;
332
  s->dport = BGP_PORT;
333
  BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr);
334
  bgp_setup_conn(p, conn);
335
  bgp_setup_sk(p, conn, s);
336
  s->tx_hook = bgp_connected;
337
  s->password = p->cf->password;
338
  conn->state = BS_CONNECT;
339
  if (sk_open(s))
340
    {
341
      bgp_sock_err(s, 0);
342
      return;
343
    }
344
  DBG("BGP: Waiting for connect success\n");
345
  bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
346
}
347

    
348
static void
349
bgp_initiate(struct bgp_proto *p)
350
{
351
  unsigned delay;
352

    
353
  delay = p->cf->start_delay_time;
354
  if (p->startup_delay > delay)
355
    delay = p->startup_delay;
356
  if (delay)
357
    {
358
      BGP_TRACE(D_EVENTS, "Connect delayed by %d seconds", delay);
359
      bgp_setup_conn(p, &p->outgoing_conn);
360
      bgp_start_timer(p->outgoing_conn.connect_retry_timer, delay);
361
    }
362
  else
363
    bgp_connect(p);
364
}
365

    
366
/**
367
 * bgp_incoming_connection - handle an incoming connection
368
 * @sk: TCP socket
369
 * @dummy: unused
370
 *
371
 * This function serves as a socket hook for accepting of new BGP
372
 * connections. It searches a BGP instance corresponding to the peer
373
 * which has connected and if such an instance exists, it creates a
374
 * &bgp_conn structure, attaches it to the instance and either sends
375
 * an Open message or (if there already is an active connection) it
376
 * closes the new connection by sending a Notification message.
377
 */
378
static int
379
bgp_incoming_connection(sock *sk, int dummy UNUSED)
380
{
381
  struct proto_config *pc;
382
  int match = 0;
383

    
384
  DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport);
385
  WALK_LIST(pc, config->protos)
386
    if (pc->protocol == &proto_bgp && pc->proto)
387
      {
388
        struct bgp_proto *p = (struct bgp_proto *) pc->proto;
389
        if (ipa_equal(p->cf->remote_ip, sk->daddr))
390
          {
391
            match = 1;
392
            if ((p->p.proto_state == PS_START || p->p.proto_state == PS_UP) && p->neigh && p->neigh->iface)
393
              {
394
                BGP_TRACE(D_EVENTS, "Incoming connection from %I port %d", sk->daddr, sk->dport);
395
                if (p->incoming_conn.sk)
396
                  {
397
                    DBG("BGP: But one incoming connection already exists, how is that possible?\n");
398
                    break;
399
                  }
400
                bgp_setup_conn(p, &p->incoming_conn);
401
                bgp_setup_sk(p, &p->incoming_conn, sk);
402
                bgp_send_open(&p->incoming_conn);
403
                return 0;
404
              }
405
          }
406
      }
407
  if (!match)
408
    log(L_AUTH "BGP: Unauthorized connect from %I port %d", sk->daddr, sk->dport);
409
  rfree(sk);
410
  return 0;
411
}
412

    
413
static void
414
bgp_setup_listen_sk(void)
415
{
416
  if (!bgp_listen_sk)
417
    {
418
      sock *s = sk_new(&root_pool);
419
      DBG("BGP: Creating incoming socket\n");
420
      s->type = SK_TCP_PASSIVE;
421
      s->sport = BGP_PORT;
422
      s->tos = IP_PREC_INTERNET_CONTROL;
423
      s->ttl = 1;
424
      s->rbsize = BGP_RX_BUFFER_SIZE;
425
      s->tbsize = BGP_TX_BUFFER_SIZE;
426
      s->rx_hook = bgp_incoming_connection;
427
      if (sk_open(s))
428
        {
429
          log(L_ERR "Unable to open incoming BGP socket");
430
          rfree(s);
431
        }
432
      else
433
        bgp_listen_sk = s;
434
    }
435
}
436

    
437
static void
438
bgp_start_neighbor(struct bgp_proto *p)
439
{
440
  p->local_addr = p->neigh->iface->addr->ip;
441
  DBG("BGP: local=%I remote=%I\n", p->local_addr, p->next_hop);
442
#ifdef IPV6
443
  {
444
    struct ifa *a;
445
    p->local_link = ipa_or(ipa_build(0xfe80,0,0,0), ipa_and(p->local_addr, ipa_build(0,0,~0,~0)));
446
    WALK_LIST(a, p->neigh->iface->addrs)
447
      if (a->scope == SCOPE_LINK)
448
        {
449
          p->local_link = a->ip;
450
          break;
451
        }
452
    DBG("BGP: Selected link-level address %I\n", p->local_link);
453
  }
454
#endif
455
  bgp_initiate(p);
456
}
457

    
458
static void
459
bgp_neigh_notify(neighbor *n)
460
{
461
  struct bgp_proto *p = (struct bgp_proto *) n->proto;
462

    
463
  if (n->iface)
464
    {
465
      BGP_TRACE(D_EVENTS, "Neighbor found");
466
      bgp_start_neighbor(p);
467
    }
468
  else
469
    {
470
      BGP_TRACE(D_EVENTS, "Neighbor lost");
471
      /* Send cease packets, but don't wait for them to be delivered */
472
      bgp_graceful_close_conn(&p->outgoing_conn);
473
      bgp_graceful_close_conn(&p->incoming_conn);
474
      proto_notify_state(&p->p, PS_DOWN);
475
    }
476
}
477

    
478
static void
479
bgp_start_locked(struct object_lock *lock)
480
{
481
  struct bgp_proto *p = lock->data;
482
  struct bgp_config *cf = p->cf;
483

    
484
  DBG("BGP: Got lock\n");
485
  p->local_id = cf->c.global->router_id;
486
  p->next_hop = cf->multihop ? cf->multihop_via : cf->remote_ip;
487
  p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY);
488

    
489
  if (cf->rr_client)
490
    {
491
      p->rr_cluster_id = cf->rr_cluster_id ? cf->rr_cluster_id : p->local_id;
492
      p->rr_client = cf->rr_client;
493
    }
494

    
495
  if (!p->neigh)
496
    {
497
      log(L_ERR "%s: Invalid next hop %I", p->p.name, p->next_hop);
498
      p->p.disabled = 1;
499
      proto_notify_state(&p->p, PS_DOWN);
500
    }
501
  else if (p->neigh->iface)
502
    bgp_start_neighbor(p);
503
  else
504
    BGP_TRACE(D_EVENTS, "Waiting for %I to become my neighbor", p->next_hop);
505
}
506

    
507
static int
508
bgp_start(struct proto *P)
509
{
510
  struct bgp_proto *p = (struct bgp_proto *) P;
511
  struct object_lock *lock;
512

    
513
  DBG("BGP: Startup.\n");
514
  p->outgoing_conn.state = BS_IDLE;
515
  p->incoming_conn.state = BS_IDLE;
516
  p->startup_delay = 0;
517
  p->neigh = NULL;
518

    
519
  bgp_counter++;
520
  bgp_setup_listen_sk();
521

    
522
  if (!bgp_linpool)
523
    bgp_linpool = lp_new(&root_pool, 4080);
524

    
525
  /*
526
   *  Before attempting to create the connection, we need to lock the
527
   *  port, so that are sure we're the only instance attempting to talk
528
   *  with that neighbor.
529
   */
530

    
531
  lock = p->lock = olock_new(P->pool);
532
  lock->addr = p->cf->remote_ip;
533
  lock->type = OBJLOCK_TCP;
534
  lock->port = BGP_PORT;
535
  lock->iface = NULL;
536
  lock->hook = bgp_start_locked;
537
  lock->data = p;
538
  olock_acquire(lock);
539

    
540
  /* We should create security association after we get a lock not to 
541
   * break existing connections.
542
   */
543
  if (p->cf->password)
544
    {
545
      int rv = sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->password);
546
      if (rv < 0)
547
        return PS_STOP;
548
    }
549

    
550
  return PS_START;
551
}
552

    
553
static int
554
bgp_shutdown(struct proto *P)
555
{
556
  struct bgp_proto *p = (struct bgp_proto *) P;
557

    
558
  BGP_TRACE(D_EVENTS, "Shutdown requested");
559

    
560
  /*
561
   *  We want to send the Cease notification message to all connections
562
   *  we have open, but we don't want to wait for all of them to complete.
563
   *  We are willing to handle the primary connection carefully, but for
564
   *  the others we just try to send the packet and if there is no buffer
565
   *  space free, we'll gracefully finish.
566
   */
567

    
568
  proto_notify_state(&p->p, PS_STOP);
569
  if (!p->conn)
570
    {
571
      if (p->outgoing_conn.state != BS_IDLE)
572
        p->outgoing_conn.primary = 1;        /* Shuts protocol down after connection close */
573
      else if (p->incoming_conn.state != BS_IDLE)
574
        p->incoming_conn.primary = 1;
575
    }
576
  if (bgp_graceful_close_conn(&p->outgoing_conn) || bgp_graceful_close_conn(&p->incoming_conn))
577
    return p->p.proto_state;
578
  else
579
    {
580
      /* No connections open, shutdown automatically */
581
      bgp_close(p);
582
      return PS_DOWN;
583
    }
584
}
585

    
586
static struct proto *
587
bgp_init(struct proto_config *C)
588
{
589
  struct bgp_config *c = (struct bgp_config *) C;
590
  struct proto *P = proto_new(C, sizeof(struct bgp_proto));
591
  struct bgp_proto *p = (struct bgp_proto *) P;
592

    
593
  P->rt_notify = bgp_rt_notify;
594
  P->rte_better = bgp_rte_better;
595
  P->import_control = bgp_import_control;
596
  P->neigh_notify = bgp_neigh_notify;
597
  p->cf = c;
598
  p->local_as = c->local_as;
599
  p->remote_as = c->remote_as;
600
  p->is_internal = (c->local_as == c->remote_as);
601
  return P;
602
}
603

    
604
/**
605
 * bgp_error - report a protocol error
606
 * @c: connection
607
 * @code: error code (according to the RFC)
608
 * @subcode: error sub-code
609
 * @data: data to be passed in the Notification message
610
 * @len: length of the data
611
 *
612
 * bgp_error() sends a notification packet to tell the other side that a protocol
613
 * error has occurred (including the data considered erroneous if possible) and
614
 * closes the connection.
615
 */
616
void
617
bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len)
618
{
619
  if (c->error_flag)
620
    return;
621
  bgp_log_error(c->bgp, "Error", code, subcode, data, (len > 0) ? len : -len);
622
  c->error_flag = 1 + (code != 6);
623
  c->notify_code = code;
624
  c->notify_subcode = subcode;
625
  c->notify_data = data;
626
  c->notify_size = (len > 0) ? len : 0;
627
  if (c->primary)
628
    proto_notify_state(&c->bgp->p, PS_STOP);
629
  bgp_schedule_packet(c, PKT_NOTIFICATION);
630
}
631

    
632
void
633
bgp_check(struct bgp_config *c)
634
{
635
  if (!c->local_as)
636
    cf_error("Local AS number must be set");
637
  if (!c->remote_as)
638
    cf_error("Neighbor must be configured");
639
  if (!bgp_as4_support && (c->local_as > 0xFFFF))
640
    cf_error("Local AS number out of range");
641
  if (!bgp_as4_support && (c->remote_as > 0xFFFF))
642
    cf_error("Neighbor AS number out of range");
643
  if ((c->local_as != c->remote_as) && (c->rr_client))
644
    cf_error("Only internal neighbor can be RR client");
645
}
646

    
647
static void
648
bgp_get_status(struct proto *P, byte *buf)
649
{
650
  struct bgp_proto *p = (struct bgp_proto *) P;
651

    
652
  if (P->proto_state == PS_DOWN)
653
    buf[0] = 0;
654
  else
655
    strcpy(buf, bgp_state_names[MAX(p->incoming_conn.state, p->outgoing_conn.state)]);
656
}
657

    
658
static int
659
bgp_reconfigure(struct proto *P, struct proto_config *C)
660
{
661
  struct bgp_config *new = (struct bgp_config *) C;
662
  struct bgp_proto *p = (struct bgp_proto *) P;
663
  struct bgp_config *old = p->cf;
664

    
665
  return !memcmp(((byte *) old) + sizeof(struct proto_config),
666
                 ((byte *) new) + sizeof(struct proto_config),
667
                 sizeof(struct bgp_config) - sizeof(struct proto_config));
668
}
669

    
670
struct protocol proto_bgp = {
671
  name:                        "BGP",
672
  template:                "bgp%d",
673
  attr_class:                EAP_BGP,
674
  init:                        bgp_init,
675
  start:                bgp_start,
676
  shutdown:                bgp_shutdown,
677
  get_status:                bgp_get_status,
678
  get_attr:                bgp_get_attr,
679
  reconfigure:                bgp_reconfigure,
680
  get_route_info:        bgp_get_route_info,
681
};