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