rip.c 18.5 KB
Newer Older
1
2
3
/*
 *	Rest in pieces - RIP protocol
 *
4
 *	Copyright (c) 1998, 1999 Pavel Machek <pavel@ucw.cz>
5
6
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
7
 *
Pavel Machek's avatar
Pavel Machek committed
8
9
10
 	FIXME: IpV6 support: packet size
 	FIXME: IpV6 support: use right address for broadcasts
	FIXME: IpV6 support: receive "route using" blocks
11
	1 FIXME
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 */

#define LOCAL_DEBUG

#include <string.h>
#include <stdlib.h>

#include "nest/bird.h"
#include "nest/iface.h"
#include "nest/protocol.h"
#include "nest/route.h"
#include "lib/socket.h"
#include "lib/resource.h"
#include "lib/lists.h"
#include "lib/timer.h"

#include "rip.h"

30
31
32
33
#define P ((struct rip_proto *) p)
#define P_CF ((struct rip_proto_config *)p->cf)
#define E ((struct rip_entry *) e)

34
35
static struct rip_interface *new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_patt *patt);

36
37
38
static void
rip_reply(struct proto *p)
{
39
#if 0
40
41
  P->listen->tbuf = "ACK!";
  sk_send_to( P->listen, 5, P->listen->faddr, P->listen->fport );
42
#endif
43
44
}

45
#define P_NAME p->name
46

47
48
49
50
51
52
53
54
55
/*
 * Output processing
 */

static void
rip_tx_err( sock *s, int err )
{
  struct rip_connection *c = s->data;
  struct proto *p = c->proto;
56
  log( L_ERR "Unexpected error at rip transmit: %m" );
57
58
59
60
61
}

static void
rip_tx( sock *s )
{
62
63
  struct rip_interface *rif = s->data;
  struct rip_connection *c = rif->busy;
64
65
  struct proto *p = c->proto;
  struct rip_packet *packet = (void *) s->tbuf;
66
  int i;
67

68
  DBG( "Sending to %I\n", s->daddr );
69
  do {
70

71
72
73
74
75
76
77
    if (c->done) {
      DBG( "Looks like I'm" );
      c->rif->busy = NULL;
      rem_node(NODE c);
      mb_free(c);
      DBG( " done\n" );
      return;
78
    }
79

80
81
82
83
84
85
    DBG( "Preparing packet to send: " );

    packet->heading.command = RIPCMD_RESPONSE;
    packet->heading.version = RIP_V2;
    packet->heading.unused  = 0;

86
    i = !!P_CF->authtype;
87
88
89
90
    FIB_ITERATE_START(&P->rtable, &c->iter, z) {
      struct rip_entry *e = (struct rip_entry *) z;
      DBG( "." );
      packet->block[i].family  = htons( 2 ); /* AF_INET */
91
      packet->block[i].tag     = htons( e->tag );
92
      packet->block[i].network = e->n.prefix;
93
#ifndef IPV6
94
      packet->block[i].netmask = ipa_mkmask( e->n.pxlen );
95
      ipa_hton( packet->block[i].netmask );
96
97
98
      packet->block[i].nexthop = IPA_NONE;	
      {
	neighbor *n1, *n2;
99
	n1 = neigh_find( p, &s->daddr, 0 );	/* FIXME, mj: this is neccessary for responses, still it is too complicated for common case */
100
101
102
103
104
105
	n2 = neigh_find( p, &e->nexthop, 0 );
	if (n1->iface == n2->iface)
	  packet->block[i].nexthop = e->nexthop;
	else
	  packet->block[i].nexthop = IPA_NONE;	
      }
106
107
108
109
      ipa_hton( packet->block[i].nexthop );
#else
      packet->block[i].pxlen = e->n.pxlen;
#endif
110
      packet->block[i].metric  = htonl( e->metric );
111
112
      if (ipa_equal(e->whotoldme, s->daddr)) {
	DBG( "(split horizont)" );
113
	packet->block[i].metric = P_CF->infinity;
114
115
116
      }
      ipa_hton( packet->block[i].network );

117
      if (i++ == ((P_CF->authtype == AT_MD5) ? PACKET_MD5_MAX : PACKET_MAX)) {
118
119
120
	FIB_ITERATE_PUT(&c->iter, z);
	goto break_loop;
      }
121
    } FIB_ITERATE_END(z);
122
123
124
125
    c->done = 1;

  break_loop:

126
    if (P_CF->authtype)
127
      rip_outgoing_authentication(p, (void *) &packet->block[0], packet, i);
128

129
130
131
132
133
134
    DBG( ", sending %d blocks, ", i );

    if (ipa_nonzero(c->daddr))
      i = sk_send_to( s, sizeof( struct rip_packet_heading ) + i*sizeof( struct rip_block ), c->daddr, c->dport );
    else
      i = sk_send( s, sizeof( struct rip_packet_heading ) + i*sizeof( struct rip_block ) );
135

Pavel Machek's avatar
Pavel Machek committed
136
    DBG( "it wants more\n" );
137
  
138
139
140
  } while (i>0);
  
  if (i<0) rip_tx_err( s, i );
Pavel Machek's avatar
Pavel Machek committed
141
  DBG( "blocked\n" );
142
143
144
}

static void
145
rip_sendto( struct proto *p, ip_addr daddr, int dport, struct rip_interface *rif )
146
{
147
  struct iface *iface = rif->iface;
148
149
150
  struct rip_connection *c = mb_alloc( p->pool, sizeof( struct rip_connection ));
  static int num = 0;

151
  if (rif->busy) {
152
    log (L_WARN "Interface %s is much too slow, dropping request", iface->name);
153
154
155
    return;
  }
  rif->busy = c;
156
  
157
158
159
  c->addr = daddr;
  c->proto = p;
  c->num = num++;
160
  c->rif = rif;
161

162
163
164
  c->dport = dport;
  c->daddr = daddr;
  if (c->rif->sock->data != rif)
165
    bug("not enough send magic");
166
#if 0
167
  if (sk_open(c->send)<0) {
168
    log( L_ERR "Could not open socket for data send to %I:%d on %s", daddr, dport, rif->iface->name );
169
170
    return;
  }
171
#endif
172

173
174
  c->done = 0;
  fit_init( &c->iter, &P->rtable );
175
  add_head( &P->connections, NODE c );
176
  debug( "Sending my routing table to %I:%d on %s\n", daddr, dport, rif->iface->name );
177

178
  rip_tx(c->rif->sock);
179
180
}

181
static struct rip_interface*
182
183
184
find_interface(struct proto *p, struct iface *what)
{
  struct rip_interface *i;
Pavel Machek's avatar
Pavel Machek committed
185

186
187
188
189
190
191
  WALK_LIST (i, P->interfaces)
    if (i->iface == what)
      return i;
  return NULL;
}

192
193
194
195
/*
 * Input processing
 */

196
197
198
199
200
201
202
/* Let main routing table know about our new entry */
static void
advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme )
{
  rta *a, A;
  rte *r;
  net *n;
203
  neighbor *neighbor;
204
  struct rip_interface *rif;
205
  int pxlen;
206

207
208
209
210
211
212
213
  bzero(&A, sizeof(A));
  A.proto = p;
  A.source = RTS_RIP;
  A.scope = SCOPE_UNIVERSE;
  A.cast = RTC_UNICAST;
  A.dest = RTD_ROUTER;
  A.flags = 0;
214
#ifndef IPV6
215
  A.gw = ipa_nonzero(b->nexthop) ? b->nexthop : whotoldme;
216
217
218
219
220
  pxlen = ipa_mklen(b->netmask);
#else
  A.gw = whotoldme; /* FIXME: next hop is in other packet for v6 */
  pxlen = b->pxlen;
#endif
221
  A.from = whotoldme;
222

223
  /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */
224

225
226
  neighbor = neigh_find( p, &A.gw, 0 );
  if (!neighbor) {
227
    log( L_ERR "%I asked me to route %I/%d using not-neighbor %I.", A.from, b->network, pxlen, A.gw );
228
229
230
231
    return;
  }

  A.iface = neighbor->iface;
232
233
  if (!(rif = neighbor->data)) {
    rif = neighbor->data = find_interface(p, A.iface);
Pavel Machek's avatar
Pavel Machek committed
234
  }
235
236
237
238
239
  if (!rif) {
    bug("Route packet using unknown interface? No.");
    return;
  }
    
240
241
  /* set to: interface of nexthop */
  a = rta_lookup(&A);
242
243
  if (pxlen==-1)  {
    log( L_ERR "%I gave me invalid pxlen/netmask for %I.", A.from, b->network );
244
245
    return;
  }
246
  n = net_get( p->table, b->network, pxlen );
247
  r = rte_get_temp(a);
248
  r->u.rip.metric = ntohl(b->metric) + rif->patt->metric;
249
  if (r->u.rip.metric > P_CF->infinity) r->u.rip.metric = P_CF->infinity;
250
  r->u.rip.tag = ntohl(b->tag);
251
  r->net = n;
252
  r->pflags = 0; /* Here go my flags */
253
  rte_update( p->table, n, p, r );
Pavel Machek's avatar
Pavel Machek committed
254
  DBG( "done\n" );
255
}
256
257
258
259
260

static void
process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme )
{
  int metric = ntohl( block->metric );
261
  ip_addr network = block->network;
262
263

  CHK_MAGIC;
264
  if ((!metric) || (metric > P_CF->infinity)) {
265
    log( L_WARN "Got metric %d from %I", metric, whotoldme );
266
267
268
    return;
  }

269
  debug( "block: %I tells me: %I/??? available, metric %d... ", whotoldme, network, metric );
270

271
  advertise_entry( p, block, whotoldme );
272
273
}

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

static int
277
278
279
rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr whotoldme, int port )
{
  int i;
280
  int native_class = 0, authenticated = 0;
281
282

  switch( packet->heading.version ) {
Pavel Machek's avatar
Pavel Machek committed
283
284
  case RIP_V1: DBG( "Rip1: " ); break;
  case RIP_V2: DBG( "Rip2: " ); break;
285
286
287
288
  default: BAD( "Unknown version" );
  }

  switch( packet->heading.command ) {
Pavel Machek's avatar
Pavel Machek committed
289
  case RIPCMD_REQUEST: DBG( "Asked to send my routing table\n" ); 
290
291
292
293
294
295
296
297
298
	  if (P_CF->honour == HO_NEVER) {
	    log( L_WARN "They asked me to send routing table, but I was told not to do it\n" );
	    return 0;
	  }
	  if ((P_CF->honour == HO_NEIGHBOUR) && (!neigh_find( p, &whotoldme, 0 ))) {
	    log( L_WARN "They asked me to send routing table, but he is not my neighbour\n" );
	    return 0;
	  }
    	  rip_sendto( p, whotoldme, port, HEAD(P->interfaces) ); /* no broadcast */
299
          break;
Pavel Machek's avatar
Pavel Machek committed
300
  case RIPCMD_RESPONSE: DBG( "*** Rtable from %I\n", whotoldme ); 
301
          if (port != P_CF->port) {
302
	    log( L_ERR "%I send me routing info from port %d", whotoldme, port );
303
#if 0
304
	    return 0;
305
#else
306
	    log( L_ERR "...ignoring" );
307
#endif
308
309
310
	  }

	  if (!neigh_find( p, &whotoldme, 0 )) {
311
	    log( L_ERR "%I send me routing info but he is not my neighbour", whotoldme );
312
#if 0
313
	    return 0;
314
315
316
#else
	    log( L_ERR "...ignoring" );
#endif
317
318
319
320
321
322
	  }

          for (i=0; i<num; i++) {
	    struct rip_block *block = &packet->block[i];
	    if (block->family == 0xffff)
	      if (!i) {
323
		if (rip_incoming_authentication(p, (void *) block, packet, num))
324
		  BAD( "Authentication failed" );
325
		authenticated = 1;
326
	      } 
327
328
	    if ((!authenticated) && (P_CF->authtype != AT_NONE))
	      BAD( "Packet is not authenticated and it should be" );
329
	    ipa_ntoh( block->network );
330
#ifndef IPV6
331
332
	    ipa_ntoh( block->netmask );
	    ipa_ntoh( block->nexthop );
333
334
	    if (packet->heading.version == RIP_V1)
	      block->netmask = ipa_class_mask(block->network);
335
#endif
336
337
338
	    process_block( p, block, whotoldme );
	  }
          break;
339
  case RIPCMD_TRACEON:
340
341
  case RIPCMD_TRACEOFF: BAD( "I was asked for traceon/traceoff" );
  case 5: BAD( "Some Sun extension around here" );
342
343
344
345
  default: BAD( "Unknown command" );
  }

  rip_reply(p);
346
  return 0;
347
348
}

349
static int
350
351
rip_rx(sock *s, int size)
{
352
353
  struct rip_interface *i = s->data;
  struct proto *p = i->proto;
354
355
356
  int num;

  CHK_MAGIC;
Pavel Machek's avatar
Pavel Machek committed
357
  DBG( "RIP: message came: %d bytes\n", size );
358
359
360
361
362
363
364
  size -= sizeof( struct rip_packet_heading );
  if (size < 0) BAD( "Too small packet" );
  if (size % sizeof( struct rip_block )) BAD( "Odd sized packet" );
  num = size / sizeof( struct rip_block );
  if (num>25) BAD( "Too many blocks" );

  rip_process_packet( p, (struct rip_packet *) s->rbuf, num, s->faddr, s->fport );
365
  return 1;
366
367
}

368
369
370
371
/*
 * Interface to rest of bird
 */

372
373
374
static void
rip_dump_entry( struct rip_entry *e )
{
375
  debug( "%I told me %d/%d ago: to %I/%d go via %I, metric %d ", 
376
  e->whotoldme, e->updated-now, e->changed-now, e->n.prefix, e->n.pxlen, e->nexthop, e->metric );
377
378
  if (e->flags & RIP_F_EXTERNAL) debug( "[external]" );
  debug( "\n" );
379
380
381
382
383
384
385
386
387
}

static void
rip_timer(timer *t)
{
  struct proto *p = t->data;
  struct rip_entry *e, *et;

  CHK_MAGIC;
Pavel Machek's avatar
Pavel Machek committed
388
  DBG( "RIP: tick tock\n" );
389
390
391
392
  
  WALK_LIST_DELSAFE( e, et, P->garbage ) {
    rte *rte;
    rte = SKIP_BACK( struct rte, u.rip.garbage, e );
Pavel Machek's avatar
Pavel Machek committed
393
    DBG( "Garbage: " ); rte_dump( rte );
394

395
    if (now - rte->lastmod > P_CF->garbage_time) {
396
      debug( "RIP: entry is too old: " ); rte_dump( rte );
397
      rte_discard(p->table, rte);
398
    }
399
  }
400

Pavel Machek's avatar
Pavel Machek committed
401
  DBG( "RIP: Broadcasting routing tables\n" );
402
  {
403
    struct rip_interface *rif;
404

405
406
    WALK_LIST( rif, P->interfaces ) {
      struct iface *iface = rif->iface;
407

408
      if (!iface) continue;
409
      if (rif->patt->mode & IM_QUIET) continue;
410
411
      if (!(iface->flags & IF_UP)) continue;

412
      rip_sendto( p, IPA_NONE, 0, rif );
413
414
    }
  }
415

Pavel Machek's avatar
Pavel Machek committed
416
  DBG( "RIP: tick tock done\n" );
417
418
}

419
static int
420
421
rip_start(struct proto *p)
{
422
  struct rip_interface *rif;
Pavel Machek's avatar
Pavel Machek committed
423
  DBG( "RIP: starting instance...\n" );
424
425

  P->magic = RIP_MAGIC;
426
  fib_init( &P->rtable, p->pool, sizeof( struct rip_entry ), 0, NULL );
427
  init_list( &P->connections );
428
  init_list( &P->garbage );
429
  init_list( &P->interfaces );
430
431
432
  P->timer = tm_new( p->pool );
  P->timer->data = p;
  P->timer->randomize = 5;
433
  P->timer->recurrent = P_CF->period; 
434
  P->timer->hook = rip_timer;
435
  tm_start( P->timer, 5 );
436
  rif = new_iface(p, NULL, 0, NULL);	/* Initialize dummy interface */
437
  add_head( &P->interfaces, NODE rif );
Pavel Machek's avatar
Pavel Machek committed
438
  CHK_MAGIC;
439

440
441
  rip_init_instance(p);

Pavel Machek's avatar
Pavel Machek committed
442
  DBG( "RIP: ...done\n");
443
  return PS_UP;
444
445
}

446
447
static struct proto *
rip_init(struct proto_config *cfg)
448
{
449
  struct proto *p = proto_new(cfg, sizeof(struct rip_proto));
450
451

  return p;
452
453
454
455
456
457
458
}

static void
rip_dump(struct proto *p)
{
  int i;
  node *w, *e;
459
  struct rip_interface *rif;
460
  i = 0;
461
462

  CHK_MAGIC;
463
  WALK_LIST( w, P->connections ) {
464
465
    struct rip_connection *n = (void *) w;
    debug( "RIP: connection #%d: %I\n", n->num, n->addr );
466
467
  }
  i = 0;
468
  FIB_WALK( &P->rtable, e ) {
469
470
    debug( "RIP: entry #%d: ", i++ );
    rip_dump_entry( E );
471
  } FIB_WALK_END;
472
473
  i = 0;
  WALK_LIST( rif, P->interfaces ) {
474
    debug( "RIP: interface #%d: %s, %I, busy = %x\n", i++, rif->iface?rif->iface->name:"(dummy)", rif->sock->daddr, rif->busy );
475
476
477
478
479
480
481
482
483
484
485
486
  }
}

static int
rip_want_this_if(struct rip_interface *iface)
{
  return 1;
}

static void
kill_iface(struct proto *p, struct rip_interface *i)
{
Pavel Machek's avatar
Pavel Machek committed
487
  DBG( "RIP: Interface %s disappeared\n", i->iface->name);
488
489
490
491
  rfree(i->sock);
  mb_free(i);
}

492
493
494
/*
 * new maybe null if we are creating initial send socket 
 */
495
static struct rip_interface *
496
new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_patt *patt )
497
{
498
  struct rip_interface *rif;
499
  int want_multicast = 0;
500

Pavel Machek's avatar
Pavel Machek committed
501
  rif = mb_allocz(p->pool, sizeof( struct rip_interface ));
502
503
  rif->iface = new;
  rif->proto = p;
504
  rif->busy = NULL;
505
  rif->patt = (struct rip_patt *) patt;
506

507
508
509
  if (rif->patt)
    want_multicast = (!(rif->patt->mode & IM_BROADCAST)) && (flags & IF_MULTICAST);
  /* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
510

511
512
513
  if (want_multicast)
    DBG( "Doing multicasts!\n" );

514
515
  rif->sock = sk_new( p->pool );
  rif->sock->type = want_multicast?SK_UDP_MC:SK_UDP;
516
  rif->sock->sport = P_CF->port;
517
518
519
  rif->sock->rx_hook = rip_rx;
  rif->sock->data = rif;
  rif->sock->rbsize = 10240;
520
  rif->sock->iface = new;		/* Automagically works for dummy interface */
521
522
523
524
  rif->sock->tbuf = mb_alloc( p->pool, sizeof( struct rip_packet ));
  rif->sock->tx_hook = rip_tx;
  rif->sock->err_hook = rip_tx_err;
  rif->sock->daddr = IPA_NONE;
525
  rif->sock->dport = P_CF->port;
526
527
528
529
  if (new)
    rif->sock->ttl = 1;
  else
    rif->sock->ttl = 30;
530
  rif->sock->tos = IP_PREC_INTERNET_CONTROL;
531
532

  if (flags & IF_BROADCAST)
533
    rif->sock->daddr = new->addr->brd;
534
  if (flags & IF_UNNUMBERED) {
535
    rif->sock->daddr = new->addr->opposite;
536
537
    log( L_WARN "RIP/%s: rip is not defined over unnumbered links\n", P_NAME );
  }
538
539
540
541
  if (want_multicast) {
    rif->sock->daddr = ipa_from_u32(0xe0000009);
    rif->sock->saddr = ipa_from_u32(0xe0000009);
  }
542

543
544
545
546
  if (!ipa_nonzero(rif->sock->daddr)) {
    log( L_WARN "RIP/%s: interface %s is too strange for me", P_NAME, rif->iface ? rif->iface->name : "(dummy)" );
  } else
    if (!(rif->patt->mode & IM_NOLISTEN))
547
      if (sk_open(rif->sock)<0) {
548
549
	log( L_ERR "RIP/%s: could not listen on %s", P_NAME, rif->iface ? rif->iface->name : "(dummy)" );
	/* Don't try to transmit into this one? Well, why not? This should not happen, anyway :-) */
550
551
      }

552
  log( L_DEBUG "RIP/%s: listening on %s, port %d, mode %s (%I)", P_NAME, rif->iface ? rif->iface->name : "(dummy)", P_CF->port, want_multicast ? "multicast" : "broadcast", rif->sock->daddr );
553
  
554
  return rif;
555
556
}

557
static void
558
rip_if_notify(struct proto *p, unsigned c, struct iface *iface)
559
{
Pavel Machek's avatar
Pavel Machek committed
560
  DBG( "RIP: if notify\n" );
561
562
563
  if (iface->flags & IF_IGNORE)
    return;
  if (c & IF_CHANGE_DOWN) {
564
    struct rip_interface *i;
565
    i = find_interface(p, iface);
566
567
568
569
    if (i) {
      rem_node(NODE i);
      kill_iface(p, i);
    }
570
  }
571
  if (c & IF_CHANGE_UP) {
572
    struct rip_interface *rif;
573
    struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface);
574
575

    if (!k) return; /* We are not interested in this interface */
576
    DBG("adding interface %s\n", iface->name );
577
    rif = new_iface(p, iface, iface->flags, k);
578
    add_head( &P->interfaces, NODE rif );
579
  }
580
581
}

582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
static struct ea_list *
rip_gen_attrs(struct proto *p, struct linpool *pool, int metric, u16 tag)
{
  struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2*sizeof(eattr));

  l->next = NULL;
  l->flags = EALF_SORTED;
  l->count = 2;
  l->attrs[0].id = EA_RIP_TAG;
  l->attrs[0].flags = 0;
  l->attrs[0].type = EAF_TYPE_INT | EAF_INLINE;
  l->attrs[0].u.data = tag;
  l->attrs[1].id = EA_RIP_TAG;
  l->attrs[1].flags = 0;
  l->attrs[1].type = EAF_TYPE_INT | EAF_INLINE;
  l->attrs[1].u.data = metric;
  return l;
}

static int
rip_import_control(struct proto *p, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
{
  if ((*rt)->attrs->proto == p)	/* My own must not be touched */
    return 1;

  if ((*rt)->attrs->source != RTS_RIP) {
    struct ea_list *new = rip_gen_attrs(p, pool, 1, 0);
    new->next = *attrs;
    *attrs = new;
  }
  return 0;
}

static struct ea_list *
rip_make_tmp_attrs(struct rte *rt, struct linpool *pool)
{
  struct proto *p = rt->attrs->proto;
  return rip_gen_attrs(p, pool, rt->u.rip.metric, rt->u.rip.tag);
}

static void 
rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
{
  struct proto *p = rt->attrs->proto;

  rt->u.rip.tag = ea_find(attrs, EA_RIP_TAG)->u.data;
  rt->u.rip.metric = ea_find(attrs, EA_RIP_TAG)->u.data;
}

631
static void
632
rip_rt_notify(struct proto *p, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs)
633
{
Pavel Machek's avatar
Pavel Machek committed
634
  CHK_MAGIC;
635
636

  if (old) {
637
    struct rip_entry *e = fib_find( &P->rtable, &net->n.prefix, net->n.pxlen );
638
    if (!e)
639
640
      log( L_BUG "Deleting nonexistent entry?!" );
    fib_delete( &P->rtable, e );
641
642
643
  }

  if (new) {
644
645
646
647
    struct rip_entry *e;
    if (fib_find( &P->rtable, &net->n.prefix, net->n.pxlen ))
      log( L_BUG "Inserting entry which is already there?" );
    e = fib_get( &P->rtable, &net->n.prefix, net->n.pxlen );
648

649
    e->nexthop = new->attrs->gw;
650
651
652
653
654
655
    e->tag = ea_find(attrs, EA_RIP_TAG)->u.data;
    e->metric = ea_find(attrs, EA_RIP_TAG)->u.data;
    if (e->metric > P_CF->infinity)
      e->metric = P_CF->infinity;
    if (!e->metric)
      e->metric = 1;
656
    e->whotoldme = new->attrs->from;
657
    e->updated = e->changed = now;
658
    e->flags = 0;
659
660
661
  }
}

662
static int
663
664
665
666
667
668
669
670
rip_rte_better(struct rte *new, struct rte *old)
{
  if (old->u.rip.metric < new->u.rip.metric)
    return 0;

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

671
  /* FIXME */
672
673
674
675
676
677
678
#define old_metric_is_much_older_than_new_metric 0
  if ((old->u.rip.metric == new->u.rip.metric) && (old_metric_is_much_older_than_new_metric))
    return 1;

  return 0;
}

679
680
681
682
683
684
685
686
687
688
689
690
691
692
static void
rip_rte_insert(net *net, rte *rte)
{
  struct proto *p = rte->attrs->proto;
  add_head( &P->garbage, &rte->u.rip.garbage );
}

static void
rip_rte_remove(net *net, rte *rte)
{
  struct proto *p = rte->attrs->proto;
  rem_node( &rte->u.rip.garbage );
}

693
694
void
rip_init_instance(struct proto *p)
695
{
696
  p->preference = DEF_PREF_RIP;
697
  p->if_notify = rip_if_notify;
698
  p->rt_notify = rip_rt_notify;
699
  p->import_control = rip_import_control;
700
701
  p->make_tmp_attrs = rip_make_tmp_attrs;
  p->store_tmp_attrs = rip_store_tmp_attrs;
702
  p->rte_better = rip_rte_better;
703
704
  p->rte_insert = rip_rte_insert;
  p->rte_remove = rip_rte_remove;
705
}
706

707
708
709
710
711
712
713
714
void
rip_init_config(struct rip_proto_config *c)
{
  init_list(&c->iface_list);
  c->infinity	= 16;
  c->port	= 520;
  c->period	= 30;
  c->garbage_time = 120+180;
715
  c->passwords	= NULL;
716
  c->authtype	= AT_NONE;
717
718
}

719
static void
720
rip_preconfig(struct protocol *x, struct config *c)
721
{
Pavel Machek's avatar
Pavel Machek committed
722
  DBG( "RIP: preconfig\n" );
723
724
}

725
static void
726
rip_postconfig(struct proto_config *c)
727
728
729
730
{
}

struct protocol proto_rip = {
731
732
733
734
735
736
737
  name: "RIP",
  preconfig: rip_preconfig,
  postconfig: rip_postconfig,

  init: rip_init,
  dump: rip_dump,
  start: rip_start,
738
};