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