Statistics
| Branch: | Revision:

iof-bird-daemon / proto / bgp / bgp.c @ 72a6ef11

History | View | Annotate | Download (7.06 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
#define LOCAL_DEBUG
10

    
11
#include "nest/bird.h"
12
#include "nest/iface.h"
13
#include "nest/protocol.h"
14
#include "nest/route.h"
15
#include "nest/locks.h"
16
#include "conf/conf.h"
17
#include "lib/socket.h"
18

    
19
#include "bgp.h"
20

    
21
static sock *bgp_listen_sk;                /* Global listening socket */
22
static int bgp_counter;                        /* Number of protocol instances using the listening socket */
23
static list bgp_list;                        /* List of active BGP instances */
24

    
25
static void bgp_close_conn(struct bgp_conn *conn);
26
static void bgp_connect(struct bgp_proto *p);
27
static void bgp_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s);
28

    
29
static void
30
bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old, ea_list *tmpa)
31
{
32
}
33

    
34
static struct proto *
35
bgp_init(struct proto_config *C)
36
{
37
  struct bgp_config *c = (struct bgp_config *) C;
38
  struct proto *P = proto_new(C, sizeof(struct bgp_proto));
39
  struct bgp_proto *p = (struct bgp_proto *) P;
40

    
41
  P->rt_notify = bgp_rt_notify;
42
  p->cf = c;
43
  p->local_as = c->local_as;
44
  p->remote_as = c->remote_as;
45
  p->is_internal = (c->local_as == c->remote_as);
46
  p->conn.state = BS_IDLE;
47
  p->incoming_conn.state = BS_IDLE;
48
  p->local_id = C->global->router_id;
49
  return P;
50
}
51

    
52
static void
53
bgp_close(struct bgp_proto *p)
54
{
55
  rem_node(&p->bgp_node);
56
  ASSERT(bgp_counter);
57
  bgp_counter--;
58
  if (!bgp_counter)
59
    {
60
      rfree(bgp_listen_sk);
61
      bgp_listen_sk = NULL;
62
    }
63
  /* FIXME: Automatic restart after errors? */
64
}
65

    
66
static void
67
bgp_reset(struct bgp_proto *p)
68
{
69
  bgp_close(p);
70
  proto_notify_state(&p->p, PS_DOWN);
71
}
72

    
73
static void
74
bgp_start_timer(timer *t, int value)
75
{
76
  /* FIXME: Randomize properly */
77
  /* FIXME: Check if anybody uses tm_start directly */
78
  tm_start(t, value);
79
}
80

    
81
static void
82
bgp_send_open(struct bgp_conn *conn)
83
{
84
  DBG("BGP: Sending open\n");
85
  conn->sk->rx_hook = bgp_rx;
86
  tm_stop(conn->connect_retry_timer);
87
  bgp_schedule_packet(conn, PKT_OPEN);
88
  conn->state = BS_OPENSENT;
89
}
90

    
91
static int
92
bgp_connected(sock *sk, int dummy)
93
{
94
  struct bgp_conn *conn = sk->data;
95

    
96
  DBG("BGP: Connected\n");
97
  bgp_send_open(conn);
98
  return 0;
99
}
100

    
101
static void
102
bgp_connect_timeout(timer *t)
103
{
104
  struct bgp_proto *p = t->data;
105
  struct bgp_conn *conn = &p->conn;
106

    
107
  DBG("BGP: Connect timeout, retrying\n");
108
  bgp_close_conn(conn);
109
  bgp_connect(p);
110
}
111

    
112
static void
113
bgp_err(sock *sk, int err)
114
{
115
  struct bgp_conn *conn = sk->data;
116

    
117
  DBG("BGP: Socket error %d in state %d\n", err, conn->state);
118
  sk->type = SK_DELETED;                /* FIXME: Need to do this always! */
119
  switch (conn->state)
120
    {
121
    case BS_CONNECT:
122
    case BS_OPENSENT:
123
      conn->state = BS_ACTIVE;
124
      bgp_start_timer(conn->connect_retry_timer, conn->bgp->cf->connect_retry_time);
125
      break;
126
    case BS_OPENCONFIRM:
127
    case BS_ESTABLISHED:
128
      /* FIXME: Should close the connection and go to Idle state */
129
    default:
130
      bug("bgp_err called in invalid state %d", conn->state);
131
    }
132
}
133

    
134
static int
135
bgp_incoming_connection(sock *sk, int dummy)
136
{
137
  node *n;
138

    
139
  DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport);
140
  WALK_LIST(n, bgp_list)
141
    {
142
      struct bgp_proto *p = SKIP_BACK(struct bgp_proto, bgp_node, n);
143
      if (ipa_equal(p->cf->remote_ip, sk->daddr) && sk->dport == BGP_PORT)
144
        {
145
          DBG("BGP: Authorized\n");
146
          if (p->incoming_conn.sk)
147
            {
148
              DBG("BGP: But one incoming connection already exists, how is that possible?\n");
149
              break;
150
            }
151
          bgp_setup_sk(p, &p->incoming_conn, sk);
152
          bgp_send_open(&p->incoming_conn);
153
          return 0;
154
        }
155
    }
156
  DBG("BGP: Unauthorized\n");
157
  rfree(sk);
158
  return 0;
159
}
160

    
161
static void
162
bgp_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s)
163
{
164
  timer *t;
165

    
166
  s->data = conn;
167
  s->ttl = p->cf->multihop ? : 1;
168
  s->rbsize = BGP_RX_BUFFER_SIZE;
169
  s->tbsize = BGP_TX_BUFFER_SIZE;
170
  s->tx_hook = bgp_tx;
171
  s->err_hook = bgp_err;
172
  s->tos = IP_PREC_INTERNET_CONTROL;
173

    
174
  conn->bgp = p;
175
  conn->sk = s;
176
  conn->packets_to_send = 0;
177

    
178
  t = conn->connect_retry_timer = tm_new(p->p.pool);
179
  t->hook = bgp_connect_timeout;
180
  t->data = p;
181
#if 0
182
  t = p->hold_timer = tm_new(p->p.pool);
183
  t->hook = bgp_hold_timeout;
184
  t->data = p;
185
  t = p->keepalive_timer = tm_new(p->p.pool);
186
  t->hook = bgp_keepalive_timeout;
187
  t->data = p;
188
#endif
189
}
190

    
191
static void
192
bgp_close_conn(struct bgp_conn *conn)
193
{
194
  rfree(conn->connect_retry_timer);
195
  conn->connect_retry_timer = NULL;
196
  rfree(conn->keepalive_timer);
197
  conn->keepalive_timer = NULL;
198
  rfree(conn->hold_timer);
199
  conn->hold_timer = NULL;
200
  rfree(conn->sk);
201
  conn->sk = NULL;
202
  conn->state = BS_IDLE;
203
}
204

    
205
static void
206
bgp_connect(struct bgp_proto *p)        /* Enter Connect state and start establishing connection */
207
{
208
  sock *s;
209
  struct bgp_conn *conn = &p->conn;
210

    
211
  DBG("BGP: Connecting\n");
212
  s = sk_new(p->p.pool);
213
  s->type = SK_TCP_ACTIVE;
214
  s->saddr = _MI(0x3ea80001);                /* FIXME: Hack */
215
  s->daddr = p->cf->remote_ip;
216
#if 0
217
  s->sport =                                /* FIXME */
218
#endif
219
  s->dport = BGP_PORT;
220
  s->rx_hook = bgp_connected;
221
  bgp_setup_sk(p, conn, s);
222
  conn->state = BS_CONNECT;
223
  if (sk_open(s))
224
    {
225
      bgp_err(s, 0);
226
      return;
227
    }
228
  DBG("BGP: Waiting for connect success\n");
229
  bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
230
}
231

    
232
static void
233
bgp_start_locked(struct object_lock *lock)
234
{
235
  struct bgp_proto *p = lock->data;
236

    
237
  DBG("BGP: Got lock\n");
238
  if (!bgp_counter++)
239
    init_list(&bgp_list);
240
  if (!bgp_listen_sk)
241
    {
242
      sock *s = sk_new(&root_pool);
243
      DBG("BGP: Creating incoming socket\n");
244
      s->type = SK_TCP_PASSIVE;
245
      s->sport = BGP_PORT;
246
      s->tos = IP_PREC_INTERNET_CONTROL;
247
      s->ttl = 1;
248
      s->rbsize = BGP_RX_BUFFER_SIZE;
249
      s->rx_hook = bgp_incoming_connection;
250
      if (sk_open(s))
251
        {
252
          log(L_ERR "Unable to open incoming BGP socket");
253
          rfree(s);
254
        }
255
      else
256
        bgp_listen_sk = s;
257
    }
258
  add_tail(&bgp_list, &p->bgp_node);
259
  bgp_connect(p);                        /* FIXME: Use neighbor cache for fast up/down transitions? */
260
}
261

    
262
static int
263
bgp_start(struct proto *P)
264
{
265
  struct bgp_proto *p = (struct bgp_proto *) P;
266
  struct object_lock *lock;
267

    
268
  /*
269
   *  Before attempting to create the connection, we need to lock the
270
   *  port, so that are sure we're the only instance attempting to talk
271
   *  with that neighbor.
272
   */
273

    
274
  DBG("BGP: Startup. Acquiring lock.\n");
275
  lock = p->lock = olock_new(P->pool);
276
  lock->addr = p->cf->remote_ip;
277
  lock->type = OBJLOCK_TCP;
278
  lock->port = BGP_PORT;
279
  lock->iface = NULL;
280
  lock->hook = bgp_start_locked;
281
  lock->data = p;
282
  olock_acquire(lock);
283
  return PS_START;
284
}
285

    
286
static int
287
bgp_shutdown(struct proto *P)
288
{
289
  struct bgp_proto *p = (struct bgp_proto *) P;
290

    
291
  DBG("BGP: Explicit shutdown\n");
292

    
293
  bgp_close(p);
294
  return PS_DOWN;
295
}
296

    
297
void
298
bgp_check(struct bgp_config *c)
299
{
300
  if (!c->local_as)
301
    cf_error("Local AS number must be set");
302
  if (!c->remote_as)
303
    cf_error("Neighbor must be configured");
304
}
305

    
306
struct protocol proto_bgp = {
307
  name:                        "BGP",
308
  template:                "bgp%d",
309
  init:                        bgp_init,
310
  start:                bgp_start,
311
  shutdown:                bgp_shutdown,
312
#if 0
313
  dump:                        bgp_dump,
314
  get_status:                bgp_get_status,
315
  get_route_info:        bgp_get_route_info,
316
  show_route_data:        bgp_show_route_data
317
#endif
318
};