]>
git.ipfire.org Git - thirdparty/bird.git/blob - proto/rip/rip.c
2 * Rest in pieces - RIP protocol
4 * Copyright (c) 1998, 1999 Pavel Machek <pavel@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
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.
14 FIXME (nonurgent): fold rip_connection into rip_interface?
16 FIXME: (nonurgent) allow bigger frequencies than 1 regular update in 6 seconds (?)
17 FIXME: propagation of metric=infinity into main routing table may or may not be good idea.
22 * DOC: Routing information protocol
24 * Rip is pretty simple protocol so half of this code is interface
25 * with core. We maintain our own linklist of &rip_entry - it serves
26 * as our small routing table. Within rip_tx(), this list is
27 * walked, and packet is generated using rip_tx_prepare(). This gets
28 * tricky because we may need to send more than one packet to one
29 * destination. Struct &rip_connection is used to hold info such as how
30 * many of &rip_entry ies we already send, and is also used to protect
31 * from two concurrent sends to one destination. Each &rip_interface has
32 * at most one &rip_connection.
34 * We are not going to honor requests for sending part of
35 * routing table. That would need to turn split horizon off,
38 * Triggered updates. RFC says: when triggered update was sent, don't send
39 * new one for something between 1 and 5 seconds (and send one
40 * after that). We do something else: once in 5 second
41 * we look for any changed routes and broadcast them.
47 #include "nest/bird.h"
48 #include "nest/iface.h"
49 #include "nest/protocol.h"
50 #include "nest/route.h"
51 #include "lib/socket.h"
52 #include "lib/resource.h"
53 #include "lib/lists.h"
54 #include "lib/timer.h"
55 #include "lib/string.h"
59 #define P ((struct rip_proto *) p)
60 #define P_CF ((struct rip_proto_config *)p->cf)
61 #define E ((struct rip_entry *) e)
63 #define TRACE(level, msg, args...) do { if (p->debug & level) { log(L_TRACE "%s: " msg, p->name , ## args); } } while(0)
65 static struct rip_interface
*new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
);
67 #define P_NAME p->name
74 rip_tx_err( sock
*s
, int err
)
76 struct rip_connection
*c
= s
->data
;
77 struct proto
*p
= c
->proto
;
78 log( L_ERR
"Unexpected error at rip transmit: %M", err
);
82 rip_tx_prepare(struct proto
*p
, ip_addr daddr
, struct rip_block
*b
, struct rip_entry
*e
, struct rip_interface
*rif
, int pos
)
85 b
->tag
= htons( e
->tag
);
86 b
->network
= e
->n
.prefix
;
88 b
->family
= htons( 2 ); /* AF_INET */
89 b
->netmask
= ipa_mkmask( e
->n
.pxlen
);
90 ipa_hton( b
->netmask
);
92 if (neigh_connected_to(p
, &e
->nexthop
, rif
->iface
))
93 b
->nexthop
= e
->nexthop
;
95 b
->nexthop
= IPA_NONE
;
96 ipa_hton( b
->nexthop
);
98 b
->pxlen
= e
->n
.pxlen
;
100 b
->metric
= htonl( e
->metric
);
101 if (neigh_connected_to(p
, &e
->whotoldme
, rif
->iface
)) {
102 DBG( "(split horizon)" );
103 b
->metric
= htonl( P_CF
->infinity
);
105 ipa_hton( b
->network
);
113 struct rip_interface
*rif
= s
->data
;
114 struct rip_connection
*c
= rif
->busy
;
115 struct proto
*p
= c
->proto
;
116 struct rip_packet
*packet
= (void *) s
->tbuf
;
118 int maxi
, nullupdate
= 1;
120 DBG( "Sending to %I\n", s
->daddr
);
126 DBG( "Preparing packet to send: " );
128 packet
->heading
.command
= RIPCMD_RESPONSE
;
129 packet
->heading
.version
= RIP_V2
;
130 packet
->heading
.unused
= 0;
132 i
= !!P_CF
->authtype
;
134 maxi
= ((P_CF
->authtype
== AT_MD5
) ? PACKET_MD5_MAX
: PACKET_MAX
);
136 maxi
= 5; /* We need to have at least reserve of one at end of packet */
139 FIB_ITERATE_START(&P
->rtable
, &c
->iter
, z
) {
140 struct rip_entry
*e
= (struct rip_entry
*) z
;
142 if (!rif
->triggered
|| (!(e
->updated
< now
-5))) {
144 i
= rip_tx_prepare( p
, s
->daddr
, packet
->block
+ i
, e
, rif
, i
);
146 FIB_ITERATE_PUT(&c
->iter
, z
);
150 } FIB_ITERATE_END(z
);
155 packetlen
= rip_outgoing_authentication(p
, (void *) &packet
->block
[0], packet
, i
);
157 DBG( ", sending %d blocks, ", i
);
159 DBG( "not sending NULL update\n" );
163 if (ipa_nonzero(c
->daddr
))
164 i
= sk_send_to( s
, packetlen
, c
->daddr
, c
->dport
);
166 i
= sk_send( s
, packetlen
);
168 DBG( "it wants more\n" );
172 if (i
<0) rip_tx_err( s
, i
);
177 DBG( "Looks like I'm" );
186 rip_sendto( struct proto
*p
, ip_addr daddr
, int dport
, struct rip_interface
*rif
)
188 struct iface
*iface
= rif
->iface
;
189 struct rip_connection
*c
;
193 log (L_WARN
"Interface %s is much too slow, dropping request", iface
->name
);
196 c
= mb_alloc( p
->pool
, sizeof( struct rip_connection
));
206 if (c
->rif
->sock
->data
!= rif
)
207 bug("not enough send magic");
209 if (sk_open(c
->send
)<0) {
210 log( L_ERR
"Could not open socket for data send to %I:%d on %s", daddr
, dport
, rif
->iface
->name
);
216 fit_init( &c
->iter
, &P
->rtable
);
217 add_head( &P
->connections
, NODE c
);
218 TRACE(D_PACKETS
, "Sending my routing table to %I:%d on %s\n", daddr
, dport
, rif
->iface
->name
);
220 rip_tx(c
->rif
->sock
);
223 static struct rip_interface
*
224 find_interface(struct proto
*p
, struct iface
*what
)
226 struct rip_interface
*i
;
228 WALK_LIST (i
, P
->interfaces
)
229 if (i
->iface
== what
)
238 /* Let main routing table know about our new entry */
240 advertise_entry( struct proto
*p
, struct rip_block
*b
, ip_addr whotoldme
)
246 struct rip_interface
*rif
;
249 bzero(&A
, sizeof(A
));
252 A
.scope
= SCOPE_UNIVERSE
;
253 A
.cast
= RTC_UNICAST
;
257 A
.gw
= ipa_nonzero(b
->nexthop
) ? b
->nexthop
: whotoldme
;
258 pxlen
= ipa_mklen(b
->netmask
);
260 A
.gw
= whotoldme
; /* FIXME: next hop is in other packet for v6 */
265 /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */
267 neighbor
= neigh_find( p
, &A
.gw
, 0 );
269 log( L_REMOTE
"%I asked me to route %I/%d using not-neighbor %I.", A
.from
, b
->network
, pxlen
, A
.gw
);
273 A
.iface
= neighbor
->iface
;
274 if (!(rif
= neighbor
->data
)) {
275 rif
= neighbor
->data
= find_interface(p
, A
.iface
);
278 bug("Route packet using unknown interface? No.");
282 /* set to: interface of nexthop */
285 log( L_REMOTE
"%I gave me invalid pxlen/netmask for %I.", A
.from
, b
->network
);
288 n
= net_get( p
->table
, b
->network
, pxlen
);
290 r
->u
.rip
.metric
= ntohl(b
->metric
) + rif
->patt
->metric
;
291 if (r
->u
.rip
.metric
> P_CF
->infinity
) r
->u
.rip
.metric
= P_CF
->infinity
;
292 r
->u
.rip
.tag
= ntohl(b
->tag
);
294 r
->pflags
= 0; /* Here go my flags */
295 rte_update( p
->table
, n
, p
, r
);
300 process_block( struct proto
*p
, struct rip_block
*block
, ip_addr whotoldme
)
302 int metric
= ntohl( block
->metric
);
303 ip_addr network
= block
->network
;
306 TRACE(D_ROUTES
, "block: %I tells me: %I/??? available, metric %d... ", whotoldme
, network
, metric
);
307 if ((!metric
) || (metric
> P_CF
->infinity
)) {
308 #ifdef IPV6 /* Someone is sedning us nexthop and we are ignoring it */
310 { debug( "IpV6 nexthop ignored" ); return; }
312 log( L_WARN
"Got metric %d from %I", metric
, whotoldme
);
316 advertise_entry( p
, block
, whotoldme
);
319 #define BAD( x ) { log( L_REMOTE "%s: " x, P_NAME ); return 1; }
322 rip_process_packet( struct proto
*p
, struct rip_packet
*packet
, int num
, ip_addr whotoldme
, int port
)
325 int native_class
= 0, authenticated
= 0;
327 switch( packet
->heading
.version
) {
328 case RIP_V1
: DBG( "Rip1: " ); break;
329 case RIP_V2
: DBG( "Rip2: " ); break;
330 default: BAD( "Unknown version" );
333 switch( packet
->heading
.command
) {
334 case RIPCMD_REQUEST
: DBG( "Asked to send my routing table\n" );
335 if (P_CF
->honor
== HO_NEVER
) {
336 log( L_REMOTE
"They asked me to send routing table, but I was told not to do it" );
339 if ((P_CF
->honor
== HO_NEIGHBOR
) && (!neigh_find( p
, &whotoldme
, 0 ))) {
340 log( L_REMOTE
"They asked me to send routing table, but he is not my neighbor" );
343 rip_sendto( p
, whotoldme
, port
, HEAD(P
->interfaces
) ); /* no broadcast */
345 case RIPCMD_RESPONSE
: DBG( "*** Rtable from %I\n", whotoldme
);
346 if (port
!= P_CF
->port
) {
347 log( L_REMOTE
"%I send me routing info from port %d", whotoldme
, port
);
351 log( L_REMOTE
"...ignoring" );
355 if (!neigh_find( p
, &whotoldme
, 0 )) {
356 log( L_REMOTE
"%I send me routing info but he is not my neighbor", whotoldme
);
360 log( L_REMOTE
"...ignoring" );
364 for (i
=0; i
<num
; i
++) {
365 struct rip_block
*block
= &packet
->block
[i
];
367 /* Authentication is not defined for v6 */
368 if (block
->family
== 0xffff) {
370 continue; /* md5 tail has this family */
371 if (rip_incoming_authentication(p
, (void *) block
, packet
, num
, whotoldme
))
372 BAD( "Authentication failed" );
377 if ((!authenticated
) && (P_CF
->authtype
!= AT_NONE
))
378 BAD( "Packet is not authenticated and it should be" );
379 ipa_ntoh( block
->network
);
381 ipa_ntoh( block
->netmask
);
382 ipa_ntoh( block
->nexthop
);
383 if (packet
->heading
.version
== RIP_V1
) /* FIXME (nonurgent): switch to disable this? */
384 block
->netmask
= ipa_class_mask(block
->network
);
386 process_block( p
, block
, whotoldme
);
390 case RIPCMD_TRACEOFF
: BAD( "I was asked for traceon/traceoff" );
391 case 5: BAD( "Some Sun extension around here" );
392 default: BAD( "Unknown command" );
399 rip_rx(sock
*s
, int size
)
401 struct rip_interface
*i
= s
->data
;
402 struct proto
*p
= i
->proto
;
406 DBG( "RIP: message came: %d bytes\n", size
);
407 size
-= sizeof( struct rip_packet_heading
);
408 if (size
< 0) BAD( "Too small packet" );
409 if (size
% sizeof( struct rip_block
)) BAD( "Odd sized packet" );
410 num
= size
/ sizeof( struct rip_block
);
411 if (num
>PACKET_MAX
) BAD( "Too many blocks" );
413 rip_process_packet( p
, (struct rip_packet
*) s
->rbuf
, num
, s
->faddr
, s
->fport
);
418 * Interface to rest of bird
422 rip_dump_entry( struct rip_entry
*e
)
424 debug( "%I told me %d/%d ago: to %I/%d go via %I, metric %d ",
425 e
->whotoldme
, e
->updated
-now
, e
->changed
-now
, e
->n
.prefix
, e
->n
.pxlen
, e
->nexthop
, e
->metric
);
426 if (e
->flags
& RIP_F_EXTERNAL
) debug( "[external]" );
433 struct proto
*p
= t
->data
;
434 struct rip_entry
*e
, *et
;
437 DBG( "RIP: tick tock\n" );
439 WALK_LIST_DELSAFE( e
, et
, P
->garbage
) {
441 rte
= SKIP_BACK( struct rte
, u
.rip
.garbage
, e
);
442 DBG( "Garbage: " ); rte_dump( rte
);
444 if (now
- rte
->u
.rip
.lastmodX
> P_CF
->timeout_time
) {
445 TRACE(D_EVENTS
, "RIP: entry is too old: %I", rte
->net
->n
.prefix
);
446 e
->metric
= P_CF
->infinity
;
449 if (now
- rte
->u
.rip
.lastmodX
> P_CF
->garbage_time
) {
450 TRACE(D_EVENTS
, "RIP: entry is much too old: %I", rte
->net
->n
.prefix
);
451 rte_discard(p
->table
, rte
);
455 DBG( "RIP: Broadcasting routing tables\n" );
457 struct rip_interface
*rif
;
460 WALK_LIST( rif
, P
->interfaces
) {
461 struct iface
*iface
= rif
->iface
;
463 if (!iface
) continue;
464 if (rif
->patt
->mode
& IM_QUIET
) continue;
465 if (!(iface
->flags
& IF_UP
)) continue;
467 rif
->triggered
= (P
->tx_count
% 6);
468 rip_sendto( p
, IPA_NONE
, 0, rif
);
472 DBG( "RIP: tick tock done\n" );
476 * rip_start - initialize instance of rip
479 rip_start(struct proto
*p
)
481 struct rip_interface
*rif
;
482 DBG( "RIP: starting instance...\n" );
484 P
->magic
= RIP_MAGIC
;
485 fib_init( &P
->rtable
, p
->pool
, sizeof( struct rip_entry
), 0, NULL
);
486 init_list( &P
->connections
);
487 init_list( &P
->garbage
);
488 init_list( &P
->interfaces
);
489 P
->timer
= tm_new( p
->pool
);
491 P
->timer
->randomize
= 5;
492 P
->timer
->recurrent
= (P_CF
->period
/ 6)+1;
493 P
->timer
->hook
= rip_timer
;
494 tm_start( P
->timer
, 5 );
495 rif
= new_iface(p
, NULL
, 0, NULL
); /* Initialize dummy interface */
496 add_head( &P
->interfaces
, NODE rif
);
499 rip_init_instance(p
);
501 DBG( "RIP: ...done\n");
505 static struct proto
*
506 rip_init(struct proto_config
*cfg
)
508 struct proto
*p
= proto_new(cfg
, sizeof(struct rip_proto
));
514 rip_dump(struct proto
*p
)
518 struct rip_interface
*rif
;
522 WALK_LIST( w
, P
->connections
) {
523 struct rip_connection
*n
= (void *) w
;
524 debug( "RIP: connection #%d: %I\n", n
->num
, n
->addr
);
527 FIB_WALK( &P
->rtable
, e
) {
528 debug( "RIP: entry #%d: ", i
++ );
532 WALK_LIST( rif
, P
->interfaces
) {
533 debug( "RIP: interface #%d: %s, %I, busy = %x\n", i
++, rif
->iface
?rif
->iface
->name
:"(dummy)", rif
->sock
->daddr
, rif
->busy
);
538 rip_get_route_info(rte
*rte
, byte
*buf
)
540 buf
+= bsprintf(buf
, " (%d/%d)", rte
->pref
, rte
->u
.rip
.metric
);
541 bsprintf(buf
, " t%04x", rte
->u
.rip
.tag
);
545 rip_want_this_if(struct rip_interface
*iface
)
551 kill_iface(struct proto
*p
, struct rip_interface
*i
)
553 DBG( "RIP: Interface %s disappeared\n", i
->iface
->name
);
559 * new_iface - actually create struct interface and start listening to it
560 * @new: interface to be created or %NULL if we are creating magic
561 * socket. Magic socket is used for listening, and is also used for
562 * sending requested responses.
564 static struct rip_interface
*
565 new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
)
567 struct rip_interface
*rif
;
569 rif
= mb_allocz(p
->pool
, sizeof( struct rip_interface
));
573 rif
->patt
= (struct rip_patt
*) patt
;
576 rif
->multicast
= (!(rif
->patt
->mode
& IM_BROADCAST
)) && (flags
& IF_MULTICAST
);
577 /* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
580 DBG( "Doing multicasts!\n" );
582 rif
->sock
= sk_new( p
->pool
);
583 rif
->sock
->type
= rif
->multicast
?SK_UDP_MC
:SK_UDP
;
584 rif
->sock
->sport
= P_CF
->port
;
585 rif
->sock
->rx_hook
= rip_rx
;
586 rif
->sock
->data
= rif
;
587 rif
->sock
->rbsize
= 10240;
588 rif
->sock
->iface
= new; /* Automagically works for dummy interface */
589 rif
->sock
->tbuf
= mb_alloc( p
->pool
, sizeof( struct rip_packet
));
590 rif
->sock
->tx_hook
= rip_tx
;
591 rif
->sock
->err_hook
= rip_tx_err
;
592 rif
->sock
->daddr
= IPA_NONE
;
593 rif
->sock
->dport
= P_CF
->port
;
598 rif
->sock
->tos
= IP_PREC_INTERNET_CONTROL
;
601 if (new->addr
->flags
& IA_UNNUMBERED
)
602 log( L_WARN
"%s: rip is not defined over unnumbered links", P_NAME
);
603 if (rif
->multicast
) {
605 rif
->sock
->daddr
= ipa_from_u32(0xe0000009);
606 rif
->sock
->saddr
= ipa_from_u32(0xe0000009);
608 ip_pton("FF02::9", &rif
->sock
->daddr
);
609 ip_pton("FF02::9", &rif
->sock
->saddr
);
612 rif
->sock
->daddr
= new->addr
->brd
;
615 if (!ipa_nonzero(rif
->sock
->daddr
)) {
616 log( L_WARN
"%s: interface %s is too strange for me", P_NAME
, rif
->iface
? rif
->iface
->name
: "(dummy)" );
618 if (!(rif
->patt
->mode
& IM_NOLISTEN
))
619 if (sk_open(rif
->sock
)<0) {
620 log( L_ERR
"%s: could not listen on %s", P_NAME
, rif
->iface
? rif
->iface
->name
: "(dummy)" );
621 /* Don't try to transmit into this one? Well, why not? This should not happen, anyway :-) */
624 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
);
630 rip_real_if_add(struct object_lock
*lock
)
632 struct iface
*iface
= lock
->iface
;
633 struct proto
*p
= lock
->data
;
634 struct rip_interface
*rif
;
635 struct iface_patt
*k
= iface_patt_match(&P_CF
->iface_list
, iface
);
638 bug("This can not happen! It existed few seconds ago!" );
639 DBG("adding interface %s\n", iface
->name
);
640 rif
= new_iface(p
, iface
, iface
->flags
, k
);
641 add_head( &P
->interfaces
, NODE rif
);
646 rip_if_notify(struct proto
*p
, unsigned c
, struct iface
*iface
)
648 DBG( "RIP: if notify\n" );
649 if (iface
->flags
& IF_IGNORE
)
651 if (c
& IF_CHANGE_DOWN
) {
652 struct rip_interface
*i
;
653 i
= find_interface(p
, iface
);
660 if (c
& IF_CHANGE_UP
) {
661 struct rip_interface
*rif
;
662 struct iface_patt
*k
= iface_patt_match(&P_CF
->iface_list
, iface
);
663 struct object_lock
*lock
;
665 if (!k
) return; /* We are not interested in this interface */
667 lock
= olock_new( p
->pool
);
669 lock
->addr
= ipa_from_u32(0xe0000009); /* This is okay: we
676 ip_pton("FF02::9", &lock
->addr
);
678 lock
->port
= P_CF
->port
;
680 lock
->hook
= rip_real_if_add
;
682 lock
->type
= OBJLOCK_UDP
;
687 static struct ea_list
*
688 rip_gen_attrs(struct proto
*p
, struct linpool
*pool
, int metric
, u16 tag
)
690 struct ea_list
*l
= lp_alloc(pool
, sizeof(struct ea_list
) + 2*sizeof(eattr
));
693 l
->flags
= EALF_SORTED
;
695 l
->attrs
[0].id
= EA_RIP_TAG
;
696 l
->attrs
[0].flags
= 0;
697 l
->attrs
[0].type
= EAF_TYPE_INT
| EAF_TEMP
;
698 l
->attrs
[0].u
.data
= tag
;
699 l
->attrs
[1].id
= EA_RIP_METRIC
;
700 l
->attrs
[1].flags
= 0;
701 l
->attrs
[1].type
= EAF_TYPE_INT
| EAF_TEMP
;
702 l
->attrs
[1].u
.data
= metric
;
707 rip_import_control(struct proto
*p
, struct rte
**rt
, struct ea_list
**attrs
, struct linpool
*pool
)
709 if ((*rt
)->attrs
->proto
== p
) /* My own must not be touched */
712 if ((*rt
)->attrs
->source
!= RTS_RIP
) {
713 struct ea_list
*new = rip_gen_attrs(p
, pool
, 1, 0);
720 static struct ea_list
*
721 rip_make_tmp_attrs(struct rte
*rt
, struct linpool
*pool
)
723 struct proto
*p
= rt
->attrs
->proto
;
724 return rip_gen_attrs(p
, pool
, rt
->u
.rip
.metric
, rt
->u
.rip
.tag
);
728 rip_store_tmp_attrs(struct rte
*rt
, struct ea_list
*attrs
)
730 struct proto
*p
= rt
->attrs
->proto
;
732 rt
->u
.rip
.tag
= ea_find(attrs
, EA_RIP_TAG
)->u
.data
;
733 rt
->u
.rip
.metric
= ea_find(attrs
, EA_RIP_METRIC
)->u
.data
;
737 rip_rt_notify(struct proto
*p
, struct network
*net
, struct rte
*new, struct rte
*old
, struct ea_list
*attrs
)
742 struct rip_entry
*e
= fib_find( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
744 log( L_BUG
"Deleting nonexistent entry?!" );
745 fib_delete( &P
->rtable
, e
);
750 if (fib_find( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
))
751 log( L_BUG
"Inserting entry which is already there?" );
752 e
= fib_get( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
754 e
->nexthop
= new->attrs
->gw
;
756 e
->whotoldme
= IPA_NONE
;
758 e
->tag
= ea_find(attrs
, EA_RIP_TAG
)->u
.data
;
759 e
->metric
= ea_find(attrs
, EA_RIP_METRIC
)->u
.data
;
760 if (e
->metric
> P_CF
->infinity
)
761 e
->metric
= P_CF
->infinity
;
763 if (new->attrs
->proto
== p
)
764 e
->whotoldme
= new->attrs
->from
;
766 if (!e
->metric
) /* That's okay: this way user can set his own value for external
769 e
->updated
= e
->changed
= now
;
775 rip_rte_better(struct rte
*new, struct rte
*old
)
777 struct proto
*p
= new->attrs
->proto
;
779 if (ipa_equal(old
->attrs
->from
, new->attrs
->from
))
782 if (old
->u
.rip
.metric
< new->u
.rip
.metric
)
785 if (old
->u
.rip
.metric
> new->u
.rip
.metric
)
788 if ((old
->u
.rip
.metric
< 16) && (new->u
.rip
.metric
== P_CF
->infinity
)) {
789 new->u
.rip
.lastmodX
= now
- P_CF
->timeout_time
; /* Check this: if new metric is 16, act as it was timed out */
792 if (old
->attrs
->proto
== new->attrs
->proto
) /* This does not make much sense for different protocols */
793 if ((old
->u
.rip
.metric
== new->u
.rip
.metric
) &&
794 ((now
- old
->u
.rip
.lastmodX
) > (P_CF
->timeout_time
/ 2)))
801 rip_rte_insert(net
*net
, rte
*rte
)
803 struct proto
*p
= rte
->attrs
->proto
;
804 rte
->u
.rip
.lastmodX
= now
;
805 add_head( &P
->garbage
, &rte
->u
.rip
.garbage
);
809 rip_rte_remove(net
*net
, rte
*rte
)
811 struct proto
*p
= rte
->attrs
->proto
;
812 rem_node( &rte
->u
.rip
.garbage
);
816 rip_init_instance(struct proto
*p
)
818 p
->preference
= DEF_PREF_RIP
;
819 p
->if_notify
= rip_if_notify
;
820 p
->rt_notify
= rip_rt_notify
;
821 p
->import_control
= rip_import_control
;
822 p
->make_tmp_attrs
= rip_make_tmp_attrs
;
823 p
->store_tmp_attrs
= rip_store_tmp_attrs
;
824 p
->rte_better
= rip_rte_better
;
825 p
->rte_insert
= rip_rte_insert
;
826 p
->rte_remove
= rip_rte_remove
;
830 rip_init_config(struct rip_proto_config
*c
)
832 init_list(&c
->iface_list
);
836 c
->garbage_time
= 120+180;
837 c
->timeout_time
= 120;
839 c
->authtype
= AT_NONE
;
843 rip_preconfig(struct protocol
*x
, struct config
*c
)
845 DBG( "RIP: preconfig\n" );
849 rip_get_attr(eattr
*a
, byte
*buf
)
851 unsigned int i
= EA_ID(a
->id
);
855 case EA_RIP_METRIC
: buf
+= bsprintf( buf
, "metric: %d", a
->u
.data
); return GA_FULL
;
856 case EA_RIP_TAG
: buf
+= bsprintf( buf
, "tag: %d", a
->u
.data
); return GA_FULL
;
857 default: return GA_UNKNOWN
;
861 struct protocol proto_rip
= {
865 preconfig
: rip_preconfig
,
866 get_route_info
: rip_get_route_info
,
867 get_attr
: rip_get_attr
,