]> git.ipfire.org Git - thirdparty/bird.git/blob - proto/rip/rip.c
Include "lib/string.h" instead of <string.h>. It should give us bzero()
[thirdparty/bird.git] / proto / rip / rip.c
1 /*
2 * Rest in pieces - RIP protocol
3 *
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 *
8 FIXME: IpV6 support: packet size
9 FIXME: IpV6 support: use right address for broadcasts
10 FIXME: IpV6 support: receive "route using" blocks
11
12 FIXME (nonurgent): fold rip_connection into rip_interface?
13
14 We are not going to honour requests for sending part of
15 routing table. That would need to turn split horizon off,
16 etc.
17
18 Triggered updates. When triggered update was sent, don't send
19 new one for something between 1 and 5 seconds (and send one
20 after that), says RFC. We do something else: once in 5 second
21 we look for any changed routes and broadcast them.
22
23 FIXME: (nonurgent) allow bigger frequencies than 1 regular update in 6 seconds (?)
24 FIXME: propagation of metric=infinity into main routing table may or may not be good idea.
25
26 */
27
28 #define LOCAL_DEBUG
29
30 #include <stdlib.h>
31 #include <stdio.h>
32
33 #include "nest/bird.h"
34 #include "nest/iface.h"
35 #include "nest/protocol.h"
36 #include "nest/route.h"
37 #include "lib/socket.h"
38 #include "lib/resource.h"
39 #include "lib/lists.h"
40 #include "lib/timer.h"
41 #include "lib/string.h"
42
43 #include "rip.h"
44
45 #define P ((struct rip_proto *) p)
46 #define P_CF ((struct rip_proto_config *)p->cf)
47 #define E ((struct rip_entry *) e)
48
49 #define TRACE(level, msg, args...) do { if (p->debug & level) { log(L_TRACE "%s: " msg, p->name , ## args); } } while(0)
50
51 static struct rip_interface *new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_patt *patt);
52
53 #define P_NAME p->name
54
55 /*
56 * Output processing
57 */
58
59 static void
60 rip_tx_err( sock *s, int err )
61 {
62 struct rip_connection *c = s->data;
63 struct proto *p = c->proto;
64 log( L_ERR "Unexpected error at rip transmit: %m" );
65 }
66
67 static void
68 rip_tx_prepare(struct proto *p, ip_addr daddr, struct rip_block *b, struct rip_entry *e, struct rip_interface *rif )
69 {
70 DBG( "." );
71 b->family = htons( 2 ); /* AF_INET */
72 b->tag = htons( e->tag );
73 b->network = e->n.prefix;
74 #ifndef IPV6
75 b->netmask = ipa_mkmask( e->n.pxlen );
76 ipa_hton( b->netmask );
77
78 if (neigh_connected_to(p, &e->nexthop, rif->iface))
79 b->nexthop = e->nexthop;
80 else
81 b->nexthop = IPA_NONE;
82 ipa_hton( b->nexthop );
83 #else
84 b->pxlen = e->n.pxlen;
85 #endif
86 b->metric = htonl( e->metric );
87 if (neigh_connected_to(p, &e->whotoldme, rif->iface)) {
88 DBG( "(split horizon)" );
89 b->metric = htonl( P_CF->infinity );
90 }
91 ipa_hton( b->network );
92 }
93
94 static void
95 rip_tx( sock *s )
96 {
97 struct rip_interface *rif = s->data;
98 struct rip_connection *c = rif->busy;
99 struct proto *p = c->proto;
100 struct rip_packet *packet = (void *) s->tbuf;
101 int i, packetlen;
102
103 DBG( "Sending to %I\n", s->daddr );
104 do {
105
106 if (c->done)
107 goto done;
108
109 DBG( "Preparing packet to send: " );
110
111 packet->heading.command = RIPCMD_RESPONSE;
112 packet->heading.version = RIP_V2;
113 packet->heading.unused = 0;
114
115 i = !!P_CF->authtype;
116 FIB_ITERATE_START(&P->rtable, &c->iter, z) {
117 struct rip_entry *e = (struct rip_entry *) z;
118
119 if (!rif->triggered || (!(e->updated < now-5))) {
120
121 rip_tx_prepare( p, s->daddr, packet->block + i, e, rif );
122 if (i++ == ((P_CF->authtype == AT_MD5) ? PACKET_MD5_MAX : PACKET_MAX)) {
123 FIB_ITERATE_PUT(&c->iter, z);
124 goto break_loop;
125 }
126 }
127 } FIB_ITERATE_END(z);
128 c->done = 1;
129
130 break_loop:
131
132 packetlen = rip_outgoing_authentication(p, (void *) &packet->block[0], packet, i);
133
134 DBG( ", sending %d blocks, ", i );
135 if (i == !!P_CF->authtype) {
136 DBG( "not sending NULL update\n" );
137 c->done = 1;
138 goto done;
139 }
140 if (ipa_nonzero(c->daddr))
141 i = sk_send_to( s, packetlen, c->daddr, c->dport );
142 else
143 i = sk_send( s, packetlen );
144
145 DBG( "it wants more\n" );
146
147 } while (i>0);
148
149 if (i<0) rip_tx_err( s, i );
150 DBG( "blocked\n" );
151 return;
152
153 done:
154 DBG( "Looks like I'm" );
155 c->rif->busy = NULL;
156 rem_node(NODE c);
157 mb_free(c);
158 DBG( " done\n" );
159 return;
160 }
161
162 static void
163 rip_sendto( struct proto *p, ip_addr daddr, int dport, struct rip_interface *rif )
164 {
165 struct iface *iface = rif->iface;
166 struct rip_connection *c;
167 static int num = 0;
168
169 if (rif->busy) {
170 log (L_WARN "Interface %s is much too slow, dropping request", iface->name);
171 return;
172 }
173 c = mb_alloc( p->pool, sizeof( struct rip_connection ));
174 rif->busy = c;
175
176 c->addr = daddr;
177 c->proto = p;
178 c->num = num++;
179 c->rif = rif;
180
181 c->dport = dport;
182 c->daddr = daddr;
183 if (c->rif->sock->data != rif)
184 bug("not enough send magic");
185 #if 0
186 if (sk_open(c->send)<0) {
187 log( L_ERR "Could not open socket for data send to %I:%d on %s", daddr, dport, rif->iface->name );
188 return;
189 }
190 #endif
191
192 c->done = 0;
193 fit_init( &c->iter, &P->rtable );
194 add_head( &P->connections, NODE c );
195 TRACE(D_PACKETS, "Sending my routing table to %I:%d on %s\n", daddr, dport, rif->iface->name );
196
197 rip_tx(c->rif->sock);
198 }
199
200 static struct rip_interface*
201 find_interface(struct proto *p, struct iface *what)
202 {
203 struct rip_interface *i;
204
205 WALK_LIST (i, P->interfaces)
206 if (i->iface == what)
207 return i;
208 return NULL;
209 }
210
211 /*
212 * Input processing
213 */
214
215 /* Let main routing table know about our new entry */
216 static void
217 advertise_entry( struct proto *p, struct rip_block *b, ip_addr whotoldme )
218 {
219 rta *a, A;
220 rte *r;
221 net *n;
222 neighbor *neighbor;
223 struct rip_interface *rif;
224 int pxlen;
225
226 bzero(&A, sizeof(A));
227 A.proto = p;
228 A.source = RTS_RIP;
229 A.scope = SCOPE_UNIVERSE;
230 A.cast = RTC_UNICAST;
231 A.dest = RTD_ROUTER;
232 A.flags = 0;
233 #ifndef IPV6
234 A.gw = ipa_nonzero(b->nexthop) ? b->nexthop : whotoldme;
235 pxlen = ipa_mklen(b->netmask);
236 #else
237 A.gw = whotoldme; /* FIXME: next hop is in other packet for v6 */
238 pxlen = b->pxlen;
239 #endif
240 A.from = whotoldme;
241
242 /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */
243
244 neighbor = neigh_find( p, &A.gw, 0 );
245 if (!neighbor) {
246 log( L_REMOTE "%I asked me to route %I/%d using not-neighbor %I.", A.from, b->network, pxlen, A.gw );
247 return;
248 }
249
250 A.iface = neighbor->iface;
251 if (!(rif = neighbor->data)) {
252 rif = neighbor->data = find_interface(p, A.iface);
253 }
254 if (!rif) {
255 bug("Route packet using unknown interface? No.");
256 return;
257 }
258
259 /* set to: interface of nexthop */
260 a = rta_lookup(&A);
261 if (pxlen==-1) {
262 log( L_REMOTE "%I gave me invalid pxlen/netmask for %I.", A.from, b->network );
263 return;
264 }
265 n = net_get( p->table, b->network, pxlen );
266 r = rte_get_temp(a);
267 r->u.rip.metric = ntohl(b->metric) + rif->patt->metric;
268 if (r->u.rip.metric > P_CF->infinity) r->u.rip.metric = P_CF->infinity;
269 r->u.rip.tag = ntohl(b->tag);
270 r->net = n;
271 r->pflags = 0; /* Here go my flags */
272 rte_update( p->table, n, p, r );
273 DBG( "done\n" );
274 }
275
276 static void
277 process_block( struct proto *p, struct rip_block *block, ip_addr whotoldme )
278 {
279 int metric = ntohl( block->metric );
280 ip_addr network = block->network;
281
282 CHK_MAGIC;
283 TRACE(D_ROUTES, "block: %I tells me: %I/??? available, metric %d... ", whotoldme, network, metric );
284 if ((!metric) || (metric > P_CF->infinity)) {
285 log( L_WARN "Got metric %d from %I", metric, whotoldme );
286 return;
287 }
288
289 advertise_entry( p, block, whotoldme );
290 }
291
292 #define BAD( x ) { log( L_REMOTE "%s: " x, P_NAME ); return 1; }
293
294 static int
295 rip_process_packet( struct proto *p, struct rip_packet *packet, int num, ip_addr whotoldme, int port )
296 {
297 int i;
298 int native_class = 0, authenticated = 0;
299
300 switch( packet->heading.version ) {
301 case RIP_V1: DBG( "Rip1: " ); break;
302 case RIP_V2: DBG( "Rip2: " ); break;
303 default: BAD( "Unknown version" );
304 }
305
306 switch( packet->heading.command ) {
307 case RIPCMD_REQUEST: DBG( "Asked to send my routing table\n" );
308 if (P_CF->honour == HO_NEVER) {
309 log( L_REMOTE "They asked me to send routing table, but I was told not to do it" );
310 return 0;
311 }
312 if ((P_CF->honour == HO_NEIGHBOUR) && (!neigh_find( p, &whotoldme, 0 ))) {
313 log( L_REMOTE "They asked me to send routing table, but he is not my neighbour" );
314 return 0;
315 }
316 rip_sendto( p, whotoldme, port, HEAD(P->interfaces) ); /* no broadcast */
317 break;
318 case RIPCMD_RESPONSE: DBG( "*** Rtable from %I\n", whotoldme );
319 if (port != P_CF->port) {
320 log( L_REMOTE "%I send me routing info from port %d", whotoldme, port );
321 #if 0
322 return 0;
323 #else
324 log( L_REMOTE "...ignoring" );
325 #endif
326 }
327
328 if (!neigh_find( p, &whotoldme, 0 )) {
329 log( L_REMOTE "%I send me routing info but he is not my neighbour", whotoldme );
330 #if 0
331 return 0;
332 #else
333 log( L_REMOTE "...ignoring" );
334 #endif
335 }
336
337 for (i=0; i<num; i++) {
338 struct rip_block *block = &packet->block[i];
339 if (block->family == 0xffff) {
340 if (i)
341 continue; /* md5 tail has this family */
342 if (rip_incoming_authentication(p, (void *) block, packet, num, whotoldme))
343 BAD( "Authentication failed" );
344 authenticated = 1;
345 continue;
346 }
347 if ((!authenticated) && (P_CF->authtype != AT_NONE))
348 BAD( "Packet is not authenticated and it should be" );
349 ipa_ntoh( block->network );
350 #ifndef IPV6
351 ipa_ntoh( block->netmask );
352 ipa_ntoh( block->nexthop );
353 if (packet->heading.version == RIP_V1) /* FIXME (nonurgent): switch to disable this? */
354 block->netmask = ipa_class_mask(block->network);
355 #endif
356 process_block( p, block, whotoldme );
357 }
358 break;
359 case RIPCMD_TRACEON:
360 case RIPCMD_TRACEOFF: BAD( "I was asked for traceon/traceoff" );
361 case 5: BAD( "Some Sun extension around here" );
362 default: BAD( "Unknown command" );
363 }
364
365 return 0;
366 }
367
368 static int
369 rip_rx(sock *s, int size)
370 {
371 struct rip_interface *i = s->data;
372 struct proto *p = i->proto;
373 int num;
374
375 CHK_MAGIC;
376 DBG( "RIP: message came: %d bytes\n", size );
377 size -= sizeof( struct rip_packet_heading );
378 if (size < 0) BAD( "Too small packet" );
379 if (size % sizeof( struct rip_block )) BAD( "Odd sized packet" );
380 num = size / sizeof( struct rip_block );
381 if (num>25) BAD( "Too many blocks" );
382
383 rip_process_packet( p, (struct rip_packet *) s->rbuf, num, s->faddr, s->fport );
384 return 1;
385 }
386
387 /*
388 * Interface to rest of bird
389 */
390
391 static void
392 rip_dump_entry( struct rip_entry *e )
393 {
394 debug( "%I told me %d/%d ago: to %I/%d go via %I, metric %d ",
395 e->whotoldme, e->updated-now, e->changed-now, e->n.prefix, e->n.pxlen, e->nexthop, e->metric );
396 if (e->flags & RIP_F_EXTERNAL) debug( "[external]" );
397 debug( "\n" );
398 }
399
400 static void
401 rip_timer(timer *t)
402 {
403 struct proto *p = t->data;
404 struct rip_entry *e, *et;
405
406 CHK_MAGIC;
407 DBG( "RIP: tick tock\n" );
408
409 WALK_LIST_DELSAFE( e, et, P->garbage ) {
410 rte *rte;
411 rte = SKIP_BACK( struct rte, u.rip.garbage, e );
412 DBG( "Garbage: " ); rte_dump( rte );
413
414 if (now - rte->u.rip.lastmodX > P_CF->timeout_time) {
415 TRACE(D_EVENTS, "RIP: entry is too old: %I", rte->net->n.prefix );
416 e->metric = P_CF->infinity;
417 }
418
419 if (now - rte->u.rip.lastmodX > P_CF->garbage_time) {
420 TRACE(D_EVENTS, "RIP: entry is much too old: %I", rte->net->n.prefix );
421 rte_discard(p->table, rte);
422 }
423 }
424
425 DBG( "RIP: Broadcasting routing tables\n" );
426 {
427 struct rip_interface *rif;
428 P->tx_count ++;
429
430 WALK_LIST( rif, P->interfaces ) {
431 struct iface *iface = rif->iface;
432
433 if (!iface) continue;
434 if (rif->patt->mode & IM_QUIET) continue;
435 if (!(iface->flags & IF_UP)) continue;
436
437 rif->triggered = (P->tx_count % 6);
438 rip_sendto( p, IPA_NONE, 0, rif );
439 }
440 }
441
442 DBG( "RIP: tick tock done\n" );
443 }
444
445 static int
446 rip_start(struct proto *p)
447 {
448 struct rip_interface *rif;
449 DBG( "RIP: starting instance...\n" );
450
451 P->magic = RIP_MAGIC;
452 fib_init( &P->rtable, p->pool, sizeof( struct rip_entry ), 0, NULL );
453 init_list( &P->connections );
454 init_list( &P->garbage );
455 init_list( &P->interfaces );
456 P->timer = tm_new( p->pool );
457 P->timer->data = p;
458 P->timer->randomize = 5;
459 P->timer->recurrent = (P_CF->period / 6)+1;
460 P->timer->hook = rip_timer;
461 tm_start( P->timer, 5 );
462 rif = new_iface(p, NULL, 0, NULL); /* Initialize dummy interface */
463 add_head( &P->interfaces, NODE rif );
464 CHK_MAGIC;
465
466 rip_init_instance(p);
467
468 DBG( "RIP: ...done\n");
469 return PS_UP;
470 }
471
472 static struct proto *
473 rip_init(struct proto_config *cfg)
474 {
475 struct proto *p = proto_new(cfg, sizeof(struct rip_proto));
476
477 return p;
478 }
479
480 static void
481 rip_dump(struct proto *p)
482 {
483 int i;
484 node *w, *e;
485 struct rip_interface *rif;
486 i = 0;
487
488 CHK_MAGIC;
489 WALK_LIST( w, P->connections ) {
490 struct rip_connection *n = (void *) w;
491 debug( "RIP: connection #%d: %I\n", n->num, n->addr );
492 }
493 i = 0;
494 FIB_WALK( &P->rtable, e ) {
495 debug( "RIP: entry #%d: ", i++ );
496 rip_dump_entry( E );
497 } FIB_WALK_END;
498 i = 0;
499 WALK_LIST( rif, P->interfaces ) {
500 debug( "RIP: interface #%d: %s, %I, busy = %x\n", i++, rif->iface?rif->iface->name:"(dummy)", rif->sock->daddr, rif->busy );
501 }
502 }
503
504 static void
505 rip_get_route_info(rte *rte, byte *buf)
506 {
507 buf += sprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric );
508 sprintf(buf, " t%04x", rte->u.rip.tag );
509 }
510
511 static int
512 rip_want_this_if(struct rip_interface *iface)
513 {
514 return 1;
515 }
516
517 static void
518 kill_iface(struct proto *p, struct rip_interface *i)
519 {
520 DBG( "RIP: Interface %s disappeared\n", i->iface->name);
521 rfree(i->sock);
522 mb_free(i);
523 }
524
525 /*
526 * new maybe null if we are creating initial send socket
527 */
528 static struct rip_interface *
529 new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_patt *patt )
530 {
531 struct rip_interface *rif;
532
533 rif = mb_allocz(p->pool, sizeof( struct rip_interface ));
534 rif->iface = new;
535 rif->proto = p;
536 rif->busy = NULL;
537 rif->patt = (struct rip_patt *) patt;
538
539 if (rif->patt)
540 rif->multicast = (!(rif->patt->mode & IM_BROADCAST)) && (flags & IF_MULTICAST);
541 /* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
542
543 if (rif->multicast)
544 DBG( "Doing multicasts!\n" );
545
546 rif->sock = sk_new( p->pool );
547 rif->sock->type = rif->multicast?SK_UDP_MC:SK_UDP;
548 rif->sock->sport = P_CF->port;
549 rif->sock->rx_hook = rip_rx;
550 rif->sock->data = rif;
551 rif->sock->rbsize = 10240;
552 rif->sock->iface = new; /* Automagically works for dummy interface */
553 rif->sock->tbuf = mb_alloc( p->pool, sizeof( struct rip_packet ));
554 rif->sock->tx_hook = rip_tx;
555 rif->sock->err_hook = rip_tx_err;
556 rif->sock->daddr = IPA_NONE;
557 rif->sock->dport = P_CF->port;
558 if (new)
559 rif->sock->ttl = 1;
560 else
561 rif->sock->ttl = 30;
562 rif->sock->tos = IP_PREC_INTERNET_CONTROL;
563
564 if (new) {
565 if (new->addr->flags & IA_UNNUMBERED)
566 log( L_WARN "%s: rip is not defined over unnumbered links", P_NAME );
567 if (rif->multicast) {
568 rif->sock->daddr = ipa_from_u32(0xe0000009);
569 rif->sock->saddr = ipa_from_u32(0xe0000009);
570 } else
571 rif->sock->daddr = new->addr->brd;
572 }
573
574 if (!ipa_nonzero(rif->sock->daddr)) {
575 log( L_WARN "%s: interface %s is too strange for me", P_NAME, rif->iface ? rif->iface->name : "(dummy)" );
576 } else
577 if (!(rif->patt->mode & IM_NOLISTEN))
578 if (sk_open(rif->sock)<0) {
579 log( L_ERR "%s: could not listen on %s", P_NAME, rif->iface ? rif->iface->name : "(dummy)" );
580 /* Don't try to transmit into this one? Well, why not? This should not happen, anyway :-) */
581 }
582
583 TRACE(D_EVENTS, "%s: listening on %s, port %d, mode %s (%I)", P_NAME, rif->iface ? rif->iface->name : "(dummy)", P_CF->port, rif->multicast ? "multicast" : "broadcast", rif->sock->daddr );
584
585 return rif;
586 }
587
588 static void
589 rip_real_if_add(struct object_lock *lock)
590 {
591 struct iface *iface = lock->iface;
592 struct proto *p = lock->data;
593 struct rip_interface *rif;
594 struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface);
595
596 if (!k)
597 bug("This can not happen! It existed few seconds ago!" );
598 DBG("adding interface %s\n", iface->name );
599 rif = new_iface(p, iface, iface->flags, k);
600 add_head( &P->interfaces, NODE rif );
601 rif->lock = lock;
602 }
603
604 static void
605 rip_if_notify(struct proto *p, unsigned c, struct iface *iface)
606 {
607 DBG( "RIP: if notify\n" );
608 if (iface->flags & IF_IGNORE)
609 return;
610 if (c & IF_CHANGE_DOWN) {
611 struct rip_interface *i;
612 i = find_interface(p, iface);
613 if (i) {
614 rem_node(NODE i);
615 kill_iface(p, i);
616 rfree(i->lock);
617 }
618 }
619 if (c & IF_CHANGE_UP) {
620 struct rip_interface *rif;
621 struct iface_patt *k = iface_patt_match(&P_CF->iface_list, iface);
622 struct object_lock *lock;
623
624 if (!k) return; /* We are not interested in this interface */
625
626 lock = olock_new( p->pool );
627 lock->addr = ipa_from_u32(0xe0000009);
628 lock->port = P_CF->port;
629 lock->iface = iface;
630 lock->hook = rip_real_if_add;
631 lock->data = p;
632 lock->type = OBJLOCK_UDP;
633 olock_acquire(lock);
634 }
635 }
636
637 static struct ea_list *
638 rip_gen_attrs(struct proto *p, struct linpool *pool, int metric, u16 tag)
639 {
640 struct ea_list *l = lp_alloc(pool, sizeof(struct ea_list) + 2*sizeof(eattr));
641
642 l->next = NULL;
643 l->flags = EALF_SORTED;
644 l->count = 2;
645 l->attrs[0].id = EA_RIP_TAG;
646 l->attrs[0].flags = 0;
647 l->attrs[0].type = EAF_TYPE_INT | EAF_TEMP;
648 l->attrs[0].u.data = tag;
649 l->attrs[1].id = EA_RIP_METRIC;
650 l->attrs[1].flags = 0;
651 l->attrs[1].type = EAF_TYPE_INT | EAF_TEMP;
652 l->attrs[1].u.data = metric;
653 return l;
654 }
655
656 static int
657 rip_import_control(struct proto *p, struct rte **rt, struct ea_list **attrs, struct linpool *pool)
658 {
659 if ((*rt)->attrs->proto == p) /* My own must not be touched */
660 return 1;
661
662 if ((*rt)->attrs->source != RTS_RIP) {
663 struct ea_list *new = rip_gen_attrs(p, pool, 1, 0);
664 new->next = *attrs;
665 *attrs = new;
666 }
667 return 0;
668 }
669
670 static struct ea_list *
671 rip_make_tmp_attrs(struct rte *rt, struct linpool *pool)
672 {
673 struct proto *p = rt->attrs->proto;
674 return rip_gen_attrs(p, pool, rt->u.rip.metric, rt->u.rip.tag);
675 }
676
677 static void
678 rip_store_tmp_attrs(struct rte *rt, struct ea_list *attrs)
679 {
680 struct proto *p = rt->attrs->proto;
681
682 rt->u.rip.tag = ea_find(attrs, EA_RIP_TAG)->u.data;
683 rt->u.rip.metric = ea_find(attrs, EA_RIP_METRIC)->u.data;
684 }
685
686 static void
687 rip_rt_notify(struct proto *p, struct network *net, struct rte *new, struct rte *old, struct ea_list *attrs)
688 {
689 CHK_MAGIC;
690
691 if (old) {
692 struct rip_entry *e = fib_find( &P->rtable, &net->n.prefix, net->n.pxlen );
693 if (!e)
694 log( L_BUG "Deleting nonexistent entry?!" );
695 fib_delete( &P->rtable, e );
696 }
697
698 if (new) {
699 struct rip_entry *e;
700 if (fib_find( &P->rtable, &net->n.prefix, net->n.pxlen ))
701 log( L_BUG "Inserting entry which is already there?" );
702 e = fib_get( &P->rtable, &net->n.prefix, net->n.pxlen );
703
704 e->nexthop = new->attrs->gw;
705 e->metric = 0;
706 e->whotoldme = IPA_NONE;
707
708 e->tag = ea_find(attrs, EA_RIP_TAG)->u.data;
709 e->metric = ea_find(attrs, EA_RIP_METRIC)->u.data;
710 if (e->metric > P_CF->infinity)
711 e->metric = P_CF->infinity;
712
713 if (new->attrs->proto == p)
714 e->whotoldme = new->attrs->from;
715
716 if (!e->metric) /* This is metric for external routes. Notice
717 that I do honour it even if it comes from other protocol than this
718 rip. That's okay: this way user can set his own value for external
719 routes in rip. */
720 e->metric = 5;
721 e->updated = e->changed = now;
722 e->flags = 0;
723 }
724 }
725
726 static int
727 rip_rte_better(struct rte *new, struct rte *old)
728 {
729 struct proto *p = new->attrs->proto;
730
731 if (ipa_equal(old->attrs->from, new->attrs->from))
732 return 1;
733
734 if (old->u.rip.metric < new->u.rip.metric)
735 return 0;
736
737 if (old->u.rip.metric > new->u.rip.metric)
738 return 1;
739
740 if ((old->u.rip.metric < 16) && (new->u.rip.metric == P_CF->infinity)) {
741 new->u.rip.lastmodX = now - P_CF->timeout_time; /* Check this: if new metric is 16, act as it was timed out */
742 }
743
744 if (old->attrs->proto == new->attrs->proto) /* This does not make much sense for different protocols */
745 if ((old->u.rip.metric == new->u.rip.metric) &&
746 ((now - old->u.rip.lastmodX) > (P_CF->timeout_time / 2)))
747 return 1;
748
749 return 0;
750 }
751
752 static void
753 rip_rte_insert(net *net, rte *rte)
754 {
755 struct proto *p = rte->attrs->proto;
756 rte->u.rip.lastmodX = now;
757 add_head( &P->garbage, &rte->u.rip.garbage );
758 }
759
760 static void
761 rip_rte_remove(net *net, rte *rte)
762 {
763 struct proto *p = rte->attrs->proto;
764 rem_node( &rte->u.rip.garbage );
765 }
766
767 void
768 rip_init_instance(struct proto *p)
769 {
770 p->preference = DEF_PREF_RIP;
771 p->if_notify = rip_if_notify;
772 p->rt_notify = rip_rt_notify;
773 p->import_control = rip_import_control;
774 p->make_tmp_attrs = rip_make_tmp_attrs;
775 p->store_tmp_attrs = rip_store_tmp_attrs;
776 p->rte_better = rip_rte_better;
777 p->rte_insert = rip_rte_insert;
778 p->rte_remove = rip_rte_remove;
779 }
780
781 void
782 rip_init_config(struct rip_proto_config *c)
783 {
784 init_list(&c->iface_list);
785 c->infinity = 16;
786 c->port = 520;
787 c->period = 30;
788 c->garbage_time = 120+180;
789 c->timeout_time = 120;
790 c->passwords = NULL;
791 c->authtype = AT_NONE;
792 }
793
794 static void
795 rip_preconfig(struct protocol *x, struct config *c)
796 {
797 DBG( "RIP: preconfig\n" );
798 }
799
800 struct protocol proto_rip = {
801 name: "RIP",
802 template: "rip%d",
803 preconfig: rip_preconfig,
804 get_route_info: rip_get_route_info,
805
806 init: rip_init,
807 dump: rip_dump,
808 start: rip_start,
809 };