Statistics
| Branch: | Revision:

iof-bird-daemon / proto / rip / rip.c @ 9a158361

History | View | Annotate | Download (15.6 KB)

1
/*
2
 *        Rest in pieces - RIP protocol
3
 *
4
 *        Copyright (c) 1998 Pavel Machek <pavel@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 <string.h>
12
#include <stdlib.h>
13

    
14
#include "nest/bird.h"
15
#include "nest/iface.h"
16
#include "nest/protocol.h"
17
#include "nest/route.h"
18
#include "lib/socket.h"
19
#include "lib/resource.h"
20
#include "lib/lists.h"
21
#include "lib/timer.h"
22

    
23
#include "rip.h"
24

    
25
#define P ((struct rip_proto *) p)
26
#define P_CF ((struct rip_proto_config *)p->cf)
27
#define E ((struct rip_entry *) e)
28

    
29
static void
30
rip_reply(struct proto *p)
31
{
32
#if 0
33
  P->listen->tbuf = "ACK!";
34
  sk_send_to( P->listen, 5, P->listen->faddr, P->listen->fport );
35
#endif
36
}
37

    
38
#define P_NAME p->name
39

    
40
/*
41
 * Output processing
42
 */
43

    
44
static void
45
rip_tx_err( sock *s, int err )
46
{
47
  struct rip_connection *c = s->data;
48
  struct proto *p = c->proto;
49
  log( L_ERR "Unexpected error at rip transmit: %m" );
50
}
51

    
52
static void
53
rip_tx( sock *s )
54
{
55
  struct rip_interface *rif = s->data;
56
  struct rip_connection *c = rif->busy;
57
  struct proto *p = c->proto;
58
  struct rip_packet *packet = (void *) s->tbuf;
59
  int i;
60

    
61
  do {
62

    
63
    if (c->done) {
64
      DBG( "Looks like I'm" );
65
      c->rif->busy = NULL;
66
      rem_node(NODE c);
67
      mb_free(c);
68
      DBG( " done\n" );
69
      return;
70
    }
71

    
72
    DBG( "Preparing packet to send: " );
73

    
74
    packet->heading.command = RIPCMD_RESPONSE;
75
    packet->heading.version = RIP_V2;
76
    packet->heading.unused  = 0;
77

    
78
    i = 0;
79
    FIB_ITERATE_START(&P->rtable, &c->iter, z) {
80
      struct rip_entry *e = (struct rip_entry *) z;
81
      DBG( "." );
82
      packet->block[i].family  = htons( 2 ); /* AF_INET */
83
      packet->block[i].tag     = htons( 0 ); /* FIXME: What should I set it to? */
84
      packet->block[i].network = e->n.prefix;
85
      packet->block[i].netmask = ipa_mkmask( e->n.pxlen );
86
      packet->block[i].nexthop = IPA_NONE; /* FIXME: How should I set it? My own IP address? */
87
      packet->block[i].metric  = htonl( 1+ (e->metric?:1) );        /* FIXME: is this right? I already ++ metric at input side */
88
      if (ipa_equal(e->whotoldme, s->daddr)) {
89
        DBG( "(split horizont)" );
90
        /* FIXME: should we do it in all cases? */
91
        packet->block[i].metric = P_CF->infinity;
92
      }
93
      ipa_hton( packet->block[i].network );
94
      ipa_hton( packet->block[i].netmask );
95
      ipa_hton( packet->block[i].nexthop );
96

    
97
      if (i++ == 25) {
98
        FIB_ITERATE_PUT(&c->iter, z);
99
        goto break_loop;
100
      }
101
    } FIB_ITERATE_END(z);
102
    c->done = 1;
103

    
104
  break_loop:
105

    
106
    DBG( ", sending %d blocks, ", i );
107

    
108
    if (ipa_nonzero(c->daddr))
109
      i = sk_send_to( s, sizeof( struct rip_packet_heading ) + i*sizeof( struct rip_block ), c->daddr, c->dport );
110
    else
111
      i = sk_send( s, sizeof( struct rip_packet_heading ) + i*sizeof( struct rip_block ) );
112

    
113
    DBG( "it wants more\n" );
114
  
115
  } while (i>0);
116
  
117
  if (i<0) rip_tx_err( s, i );
118
  DBG( "blocked\n" );
119
}
120

    
121
static void
122
rip_sendto( struct proto *p, ip_addr daddr, int dport, struct rip_interface *rif )
123
{
124
  struct iface *iface = rif->iface;
125
  struct rip_connection *c = mb_alloc( p->pool, sizeof( struct rip_connection ));
126
  static int num = 0;
127

    
128
  if (rif->busy) {
129
    log (L_WARN "Interface %s is much too slow, dropping request", iface->name);
130
    return;
131
  }
132
  rif->busy = c;
133
  
134
  c->addr = daddr;
135
  c->proto = p;
136
  c->num = num++;
137
  c->rif = rif;
138

    
139
  c->dport = dport;
140
  c->daddr = daddr;
141
  if (c->rif->sock->data != rif)
142
    bug("not enough send magic");
143
#if 0
144
  if (sk_open(c->send)<0) {
145
    log( L_ERR "Could not open socket for data send to %I:%d on %s", daddr, dport, rif->iface->name );
146
    return;
147
  }
148
#endif
149

    
150
  c->done = 0;
151
  fit_init( &c->iter, &P->rtable );
152
  add_head( &P->connections, NODE c );
153
  debug( "Sending my routing table to %I:%d on %s\n", daddr, dport, rif->iface->name );
154

    
155
  rip_tx(c->rif->sock);
156
}
157

    
158
static struct rip_interface*
159
find_interface(struct proto *p, struct iface *what)
160
{
161
  struct rip_interface *i;
162

    
163
  WALK_LIST (i, P->interfaces)
164
    if (i->iface == what)
165
      return i;
166
  return NULL;
167
}
168

    
169
/*
170
 * Input processing
171
 */
172

    
173
static int
174
process_authentication( struct proto *p, struct rip_block *block )
175
{
176
  /* FIXME: Should do md5 authentication */
177
  return 0;
178
}
179

    
180
/* Let main routing table know about our new entry */
181
static void
182
advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme )
183
{
184
  rta *a, A;
185
  rte *r;
186
  net *n;
187
  neighbor *neighbor;
188
  struct rip_interface *rif;
189

    
190
  bzero(&A, sizeof(A));
191
  A.proto = p;
192
  A.source = RTS_RIP;
193
  A.scope = SCOPE_UNIVERSE;
194
  A.cast = RTC_UNICAST;
195
  A.dest = RTD_ROUTER;
196
  A.flags = 0;
197
  A.gw = ipa_nonzero(b->nexthop) ? b->nexthop : whotoldme;
198
  A.from = whotoldme;
199

    
200
  /* FIXME: Check if destination looks valid - ie not net 0 or 127 */
201

    
202
  neighbor = neigh_find( p, &A.gw, 0 );
203
  if (!neighbor) {
204
    log( L_ERR "%I asked me to route %I/%I using not-neighbor %I.", A.from, b->network, b->netmask, A.gw );
205
    return;
206
  }
207

    
208
  A.iface = neighbor->iface;
209
  if (!(rif = neighbor->data)) {
210
    rif = neighbor->data = find_interface(p, A.iface);
211
  }
212
  if (!rif) {
213
    bug("Route packet using unknown interface? No.");
214
    return;
215
  }
216
    
217
  /* set to: interface of nexthop */
218
  a = rta_lookup(&A);
219
  if (ipa_mklen(b->netmask)==-1)  {
220
    log( L_ERR "%I asked me to route %I/%I, but that is not valid netmask.", A.from, b->network, b->netmask );
221
    return;
222
  }
223
  n = net_get( p->table, b->network, ipa_mklen( b->netmask ));
224
  r = rte_get_temp(a);
225
  r->u.rip.metric = ntohl(b->metric) + rif->metric;
226
  if (r->u.rip.metric > P_CF->infinity) r->u.rip.metric = P_CF->infinity;
227
  r->u.rip.tag = ntohl(b->tag);
228
  r->net = n;
229
  r->pflags = 0; /* Here go my flags */
230
  rte_update( n, p, r );
231
  DBG( "done\n" );
232
}
233

    
234
static void
235
process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme )
236
{
237
  struct rip_entry *e;
238
  int metric = ntohl( block->metric );
239
  ip_addr network = block->network;
240

    
241
  CHK_MAGIC;
242
  if ((!metric) || (metric > P_CF->infinity)) {
243
    log( L_WARN "Got metric %d from %I", metric, whotoldme );
244
    return;
245
  }
246

    
247
  debug( "block: %I tells me: %I/%I available, metric %d... ", whotoldme, network, block->netmask, metric );
248

    
249
  advertise_entry( p, block, whotoldme );
250
}
251

    
252
#define BAD( x ) { log( L_WARN "RIP/%s: " x, P_NAME ); return 1; }
253

    
254
static int
255
rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr whotoldme, int port )
256
{
257
  int i;
258
  int native_class = 0;
259

    
260
  switch( packet->heading.version ) {
261
  case RIP_V1: DBG( "Rip1: " ); break;
262
  case RIP_V2: DBG( "Rip2: " ); break;
263
  default: BAD( "Unknown version" );
264
  }
265

    
266
  switch( packet->heading.command ) {
267
  case RIPCMD_REQUEST: DBG( "Asked to send my routing table\n" ); 
268
    /* FIXME: should have configurable: ignore always, honour to neighbours, honour always. FIXME: use one global socket for these. FIXME: synchronization - if two ask me at same time */
269
              rip_sendto( p, whotoldme, port, NULL ); /* no broadcast */
270
          break;
271
  case RIPCMD_RESPONSE: DBG( "*** Rtable from %I\n", whotoldme ); 
272
          if (port != P_CF->port) {
273
            log( L_ERR "%I send me routing info from port %d", whotoldme, port );
274
#if 0
275
            return 0;
276
#else
277
            log( L_ERR "...ignoring" );
278
#endif
279
          }
280

    
281
          if (!neigh_find( p, &whotoldme, 0 )) {
282
            log( L_ERR "%I send me routing info but he is not my neighbour", whotoldme );
283
            return 0;
284
          }
285

    
286
          /* FIXME: Should check if it is not my own packet */
287

    
288
          for (i=0; i<num; i++) {
289
            struct rip_block *block = &packet->block[i];
290
            if (block->family == 0xffff)
291
              if (!i) {
292
                if (process_authentication(p, block))
293
                  BAD( "Authentication failed" );
294
              } else BAD( "Authentication is not the first!" );
295
            ipa_ntoh( block->network );
296
            ipa_ntoh( block->netmask );
297
            ipa_ntoh( block->nexthop );
298
            if (packet->heading.version == RIP_V1) {
299
              block->netmask = block->network; /* MJ: why are macros like this?! */
300
              ipa_class_mask( block->netmask );
301
            }
302
            process_block( p, block, whotoldme );
303
          }
304
          break;
305
  case RIPCMD_TRACEON:
306
  case RIPCMD_TRACEOFF: BAD( "I was asked for traceon/traceoff" );
307
  case 5: BAD( "Some Sun extension around here" );
308
  default: BAD( "Unknown command" );
309
  }
310

    
311
  rip_reply(p);
312
  return 0;
313
}
314

    
315
static int
316
rip_rx(sock *s, int size)
317
{
318
  struct rip_interface *i = s->data;
319
  struct proto *p = i->proto;
320
  int num;
321

    
322
  CHK_MAGIC;
323
  DBG( "RIP: message came: %d bytes\n", size );
324
  size -= sizeof( struct rip_packet_heading );
325
  if (size < 0) BAD( "Too small packet" );
326
  if (size % sizeof( struct rip_block )) BAD( "Odd sized packet" );
327
  num = size / sizeof( struct rip_block );
328
  if (num>25) BAD( "Too many blocks" );
329

    
330
  rip_process_packet( p, (struct rip_packet *) s->rbuf, num, s->faddr, s->fport );
331
  return 1;
332
}
333

    
334
/*
335
 * Interface to rest of bird
336
 */
337

    
338
static void
339
rip_dump_entry( struct rip_entry *e )
340
{
341
  debug( "%I told me %d/%d ago: to %I/%d go via %I, metric %d ", 
342
  e->whotoldme, e->updated-now, e->changed-now, e->n.prefix, e->n.pxlen, e->nexthop, e->metric );
343
  if (e->flags & RIP_F_EXTERNAL) debug( "[external]" );
344
  debug( "\n" );
345
}
346

    
347
static void
348
rip_timer(timer *t)
349
{
350
  struct proto *p = t->data;
351
  struct rip_entry *e, *et;
352

    
353
  CHK_MAGIC;
354
  DBG( "RIP: tick tock\n" );
355
  
356
  WALK_LIST_DELSAFE( e, et, P->garbage ) {
357
    rte *rte;
358
    rte = SKIP_BACK( struct rte, u.rip.garbage, e );
359
    DBG( "Garbage: " ); rte_dump( rte );
360

    
361
    if (now - rte->lastmod > P_CF->garbage_time) {
362
      debug( "RIP: entry is too old: " ); rte_dump( rte );
363
      rte_discard(rte);
364
    }
365
  }
366

    
367
  DBG( "RIP: Broadcasting routing tables\n" );
368
  {
369
    struct rip_interface *rif;
370

    
371
    WALK_LIST( rif, P->interfaces ) {
372
      struct iface *iface = rif->iface;
373

    
374
      if (!iface) continue;
375
      if (rif->patt->mode == IM_QUIET) continue;
376
      if (!(iface->flags & IF_UP)) continue;
377
      if (iface->flags & (IF_IGNORE | IF_LOOPBACK)) continue;
378

    
379
      rip_sendto( p, IPA_NONE, 0, rif );
380
    }
381
  }
382

    
383
  DBG( "RIP: tick tock done\n" );
384
}
385

    
386
static int
387
rip_start(struct proto *p)
388
{
389
  struct rip_interface *rif;
390
  DBG( "RIP: starting instance...\n" );
391

    
392
  P->magic = RIP_MAGIC;
393
  fib_init( &P->rtable, p->pool, sizeof( struct rip_entry ), 0, NULL );
394
  init_list( &P->connections );
395
  init_list( &P->garbage );
396
  init_list( &P->interfaces );
397
  P->timer = tm_new( p->pool );
398
  P->timer->data = p;
399
  P->timer->randomize = 5;
400
  P->timer->recurrent = P_CF->period; 
401
  P->timer->hook = rip_timer;
402
  tm_start( P->timer, 5 );
403
  rif = new_iface(p, NULL, 0);        /* Initialize dummy interface */
404
  add_head( &P->interfaces, NODE rif );
405
  CHK_MAGIC;
406

    
407
  rip_init_instance(p);
408

    
409
  DBG( "RIP: ...done\n");
410
  return PS_UP;
411
}
412

    
413
static struct proto *
414
rip_init(struct proto_config *cfg)
415
{
416
  struct proto *p = proto_new(cfg, sizeof(struct rip_proto));
417

    
418
  return p;
419
}
420

    
421
static void
422
rip_dump(struct proto *p)
423
{
424
  int i;
425
  node *w, *e;
426
  struct rip_interface *rif;
427
  i = 0;
428

    
429
  CHK_MAGIC;
430
  WALK_LIST( w, P->connections ) {
431
    struct rip_connection *n = (void *) w;
432
    debug( "RIP: connection #%d: %I\n", n->num, n->addr );
433
  }
434
  i = 0;
435
  FIB_WALK( &P->rtable, e ) {
436
    debug( "RIP: entry #%d: ", i++ );
437
    rip_dump_entry( E );
438
  } FIB_WALK_END;
439
  i = 0;
440
  WALK_LIST( rif, P->interfaces ) {
441
    debug( "RIP: interface #%d: %s, %I, busy = %x\n", i++, rif->iface?rif->iface->name:"(dummy)", rif->sock->daddr, rif->busy );
442
  }
443
}
444

    
445
static int
446
rip_want_this_if(struct rip_interface *iface)
447
{
448
  return 1;
449
}
450

    
451
static void
452
kill_iface(struct proto *p, struct rip_interface *i)
453
{
454
  DBG( "RIP: Interface %s disappeared\n", i->iface->name);
455
  rfree(i->sock);
456
  mb_free(i);
457
}
458

    
459
/*
460
 * new maybe null if we are creating initial send socket 
461
 */
462
struct rip_interface *
463
new_iface(struct proto *p, struct iface *new, unsigned long flags)
464
{
465
  struct rip_interface *rif;
466
  int want_multicast;
467

    
468
  rif = mb_alloc(p->pool, sizeof( struct rip_interface ));
469
  rif->iface = new;
470
  rif->proto = p;
471
  rif->busy = NULL;
472

    
473
  want_multicast = 0 && (flags & IF_MULTICAST);
474
  /* FIXME: should have config option to disable this one */
475
  /* FIXME: lookup multicasts over unnumbered links */
476

    
477
  rif->sock = sk_new( p->pool );
478
  rif->sock->type = want_multicast?SK_UDP_MC:SK_UDP;
479
  rif->sock->sport = P_CF->port;
480
  rif->sock->rx_hook = rip_rx;
481
  rif->sock->data = rif;
482
  rif->sock->rbsize = 10240;
483
  rif->sock->iface = new;                /* Automagically works for dummy interface */
484
  rif->sock->tbuf = mb_alloc( p->pool, sizeof( struct rip_packet ));
485
  rif->sock->tx_hook = rip_tx;
486
  rif->sock->err_hook = rip_tx_err;
487
  rif->sock->daddr = IPA_NONE;
488
  rif->sock->dport = P_CF->port;
489
  rif->sock->ttl = 1; /* FIXME: care must be taken not to send requested responses from this socket */
490

    
491
  if (want_multicast)
492
    rif->sock->daddr = ipa_from_u32(0x7f000001); /* FIXME: must lookup address in rfc's */
493
  if (flags & IF_BROADCAST)
494
    rif->sock->daddr = new->addr->brd;
495
  if (flags & IF_UNNUMBERED)
496
    rif->sock->daddr = new->addr->opposite;
497

    
498
  if (!ipa_nonzero(rif->sock->daddr))
499
    log( L_WARN "RIP: interface %s is too strange for me", rif->iface ? rif->iface->name : "(dummy)" );
500
  /* FIXME: Should ignore the interface instead of blindly trying to bind on it */
501

    
502
  if (sk_open(rif->sock)<0)
503
    die( "RIP/%s: could not listen on %s", P_NAME, rif->iface ? rif->iface->name : "(dummy)" );
504
  /* FIXME: Should not be fatal, since the interface might have gone */
505
  
506
  return rif;
507
}
508

    
509
static void
510
rip_if_notify(struct proto *p, unsigned c, struct iface *iface)
511
{
512
  DBG( "RIP: if notify\n" );
513
  if (iface->flags & IF_IGNORE)
514
    return;
515
  if (c & IF_CHANGE_DOWN) {
516
    struct rip_interface *i;
517
    i = find_interface(p, iface);
518
    if (i) {
519
      rem_node(NODE i);
520
      kill_iface(p, i);
521
    }
522
  }
523
  if (c & IF_CHANGE_UP) {
524
    struct rip_interface *rif;
525
    struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface);
526

    
527
    if (!k) return; /* We are not interested in this interface */
528
    DBG("adding interface %s\n", iface->name );
529
    rif = new_iface(p, iface, iface->flags);
530
    rif->patt = (void *) k;
531
    add_head( &P->interfaces, NODE rif );
532
  }
533
}
534

    
535
static void
536
rip_rt_notify(struct proto *p, struct network *net, struct rte *new, struct rte *old)
537
{
538
  CHK_MAGIC;
539

    
540
  if (old) {
541
    struct rip_entry *e = fib_find( &P->rtable, &net->n.prefix, net->n.pxlen );
542
    if (!e)
543
      log( L_BUG "Deleting nonexistent entry?!" );
544
    fib_delete( &P->rtable, e );
545
  }
546

    
547
  if (new) {
548
    struct rip_entry *e;
549
    if (fib_find( &P->rtable, &net->n.prefix, net->n.pxlen ))
550
      log( L_BUG "Inserting entry which is already there?" );
551
    e = fib_get( &P->rtable, &net->n.prefix, net->n.pxlen );
552

    
553
    e->nexthop = new->attrs->gw;
554
    e->tag = new->u.rip.tag;
555
    e->metric = new->u.rip.metric;
556
    e->whotoldme = new->attrs->from;
557
    e->updated = e->changed = now;
558
    e->flags = 0;
559
  }
560
}
561

    
562
static int
563
rip_rte_better(struct rte *new, struct rte *old)
564
{
565
  if (old->u.rip.metric < new->u.rip.metric)
566
    return 0;
567

    
568
  if (old->u.rip.metric > new->u.rip.metric)
569
    return 1;
570

    
571
#define old_metric_is_much_older_than_new_metric 0
572
  if ((old->u.rip.metric == new->u.rip.metric) && (old_metric_is_much_older_than_new_metric))
573
    return 1;
574

    
575
  return 0;
576
}
577

    
578
static void
579
rip_rte_insert(net *net, rte *rte)
580
{
581
  struct proto *p = rte->attrs->proto;
582
  add_head( &P->garbage, &rte->u.rip.garbage );
583
}
584

    
585
static void
586
rip_rte_remove(net *net, rte *rte)
587
{
588
  struct proto *p = rte->attrs->proto;
589
  rem_node( &rte->u.rip.garbage );
590
}
591

    
592
void
593
rip_init_instance(struct proto *p)
594
{
595
  p->preference = DEF_PREF_RIP;
596
  p->if_notify = rip_if_notify;
597
  p->rt_notify = rip_rt_notify;
598
  p->rte_better = rip_rte_better;
599
  p->rte_insert = rip_rte_insert;
600
  p->rte_remove = rip_rte_remove;
601
}
602

    
603
void
604
rip_init_config(struct rip_proto_config *c)
605
{
606
  init_list(&c->iface_list);
607
  c->infinity        = 16;
608
  c->port        = 520;
609
  c->period        = 30;
610
  c->garbage_time = 120+180;
611
}
612

    
613
static void
614
rip_preconfig(struct protocol *x, struct config *c)
615
{
616
  DBG( "RIP: preconfig\n" );
617
}
618

    
619
static void
620
rip_postconfig(struct proto_config *c)
621
{
622
}
623

    
624
struct protocol proto_rip = {
625
  name: "RIP",
626
  preconfig: rip_preconfig,
627
  postconfig: rip_postconfig,
628

    
629
  init: rip_init,
630
  dump: rip_dump,
631
  start: rip_start,
632
};