]>
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: IpV6 support: use right address for broadcasts
10 FIXME: IpV6 support: receive "route using" blocks
12 FIXME (nonurgent): fold rip_connection into rip_interface?
14 We are not going to honour requests for sending part of
15 routing table. That would need to turn split horizont off,
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.
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.
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"
45 #define P ((struct rip_proto *) p)
46 #define P_CF ((struct rip_proto_config *)p->cf)
47 #define E ((struct rip_entry *) e)
49 static struct rip_interface
* new_iface ( struct proto
* p
, struct iface
* new , unsigned long flags
, struct iface_patt
* patt
);
52 rip_reply ( struct proto
* p
)
55 P
-> listen
-> tbuf
= "ACK!" ;
56 sk_send_to ( P
-> listen
, 5 , P
-> listen
-> faddr
, P
-> listen
-> fport
);
60 #define P_NAME p->name
67 rip_tx_err ( sock
* s
, int err
)
69 struct rip_connection
* c
= s
-> data
;
70 struct proto
* p
= c
-> proto
;
71 log ( L_ERR
"Unexpected error at rip transmit: %m" );
75 rip_tx_prepare ( struct proto
* p
, ip_addr daddr
, struct rip_block
* b
, struct rip_entry
* e
)
78 b
-> family
= htons ( 2 ); /* AF_INET */
79 b
-> tag
= htons ( e
-> tag
);
80 b
-> network
= e
-> n
. prefix
;
82 b
-> netmask
= ipa_mkmask ( e
-> n
. pxlen
);
83 ipa_hton ( b
-> netmask
);
84 b
-> nexthop
= IPA_NONE
;
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
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
;
100 b
-> nexthop
= IPA_NONE
;
102 ipa_hton ( b
-> nexthop
);
104 b
-> pxlen
= e
-> n
. pxlen
;
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
);
111 ipa_hton ( b
-> network
);
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
;
123 DBG ( "Sending to %I \n " , s
-> daddr
);
127 DBG ( "Looks like I'm" );
135 DBG ( "Preparing packet to send: " );
137 packet
-> heading
. command
= RIPCMD_RESPONSE
;
138 packet
-> heading
. version
= RIP_V2
;
139 packet
-> heading
. unused
= 0 ;
141 i
= !! P_CF
-> authtype
;
142 FIB_ITERATE_START (& P
-> rtable
, & c
-> iter
, z
) {
143 struct rip_entry
* e
= ( struct rip_entry
*) z
;
145 if (! rif
-> triggered
|| (!( e
-> updated
< now
- 5 ))) {
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
);
153 } FIB_ITERATE_END ( z
);
158 packetlen
= rip_outgoing_authentication ( p
, ( void *) & packet
-> block
[ 0 ], packet
, i
);
160 DBG ( ", sending %d blocks, " , i
);
161 #if 0 /* FIXME: enable this for production! */
162 if ( i
== !! P_CF
-> authtype
)
166 DBG ( "not sending NULL update \n " );
168 if ( ipa_nonzero ( c
-> daddr
))
169 i
= sk_send_to ( s
, packetlen
, c
-> daddr
, c
-> dport
);
171 i
= sk_send ( s
, packetlen
);
174 DBG ( "it wants more \n " );
178 if ( i
< 0 ) rip_tx_err ( s
, i
);
185 rip_sendto ( struct proto
* p
, ip_addr daddr
, int dport
, struct rip_interface
* rif
)
187 struct iface
* iface
= rif
-> iface
;
188 struct rip_connection
* c
= mb_alloc ( p
-> pool
, sizeof ( struct rip_connection
));
192 log ( L_WARN
"Interface %s is much too slow, dropping request" , iface
-> name
);
193 /* FIXME: memory leak */
205 if ( c
-> rif
-> sock
-> data
!= rif
)
206 bug ( "not enough send magic" );
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
);
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
);
219 rip_tx ( c
-> rif
-> sock
);
222 static struct rip_interface
*
223 find_interface ( struct proto
* p
, struct iface
* what
)
225 struct rip_interface
* i
;
227 WALK_LIST ( i
, P
-> interfaces
)
228 if ( i
-> iface
== what
)
237 /* Let main routing table know about our new entry */
239 advertise_entry ( struct proto
* p
, struct rip_block
* b
, ip_addr whotoldme
)
245 struct rip_interface
* rif
;
248 bzero (& A
, sizeof ( A
));
251 A
. scope
= SCOPE_UNIVERSE
;
252 A
. cast
= RTC_UNICAST
;
256 A
. gw
= ipa_nonzero ( b
-> nexthop
) ? b
-> nexthop
: whotoldme
;
257 pxlen
= ipa_mklen ( b
-> netmask
);
259 A
. gw
= whotoldme
; /* FIXME: next hop is in other packet for v6 */
264 /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */
266 neighbor
= neigh_find ( p
, & A
. gw
, 0 );
268 log ( L_REMOTE
"%I asked me to route %I/%d using not-neighbor %I." , A
. from
, b
-> network
, pxlen
, A
. gw
);
272 A
. iface
= neighbor
-> iface
;
273 if (!( rif
= neighbor
-> data
)) {
274 rif
= neighbor
-> data
= find_interface ( p
, A
. iface
);
277 bug ( "Route packet using unknown interface? No." );
281 /* set to: interface of nexthop */
284 log ( L_REMOTE
"%I gave me invalid pxlen/netmask for %I." , A
. from
, b
-> network
);
287 n
= net_get ( p
-> table
, b
-> network
, pxlen
);
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
);
293 r
-> pflags
= 0 ; /* Here go my flags */
294 rte_update ( p
-> table
, n
, p
, r
);
299 process_block ( struct proto
* p
, struct rip_block
* block
, ip_addr whotoldme
)
301 int metric
= ntohl ( block
-> metric
);
302 ip_addr network
= block
-> network
;
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
);
311 advertise_entry ( p
, block
, whotoldme
);
314 #define BAD( x ) { log( L_WARN "RIP/%s: " x, P_NAME ); return 1; }
317 rip_process_packet ( struct proto
* p
, struct rip_packet
* packet
, int num
, ip_addr whotoldme
, int port
)
320 int native_class
= 0 , authenticated
= 0 ;
322 switch ( packet
-> heading
. version
) {
323 case RIP_V1
: DBG ( "Rip1: " ); break ;
324 case RIP_V2
: DBG ( "Rip2: " ); break ;
325 default : BAD ( "Unknown version" );
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 " );
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 " );
338 rip_sendto ( p
, whotoldme
, port
, HEAD ( P
-> interfaces
) ); /* no broadcast */
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
);
346 log ( L_REMOTE
"...ignoring" );
350 if (! neigh_find ( p
, & whotoldme
, 0 )) {
351 log ( L_REMOTE
"%I send me routing info but he is not my neighbour" , whotoldme
);
355 log ( L_REMOTE
"...ignoring" );
359 for ( i
= 0 ; i
< num
; i
++) {
360 struct rip_block
* block
= & packet
-> block
[ i
];
361 if ( block
-> family
== 0xffff ) {
363 continue ; /* md5 tail has this family */
364 if ( rip_incoming_authentication ( p
, ( void *) block
, packet
, num
, whotoldme
))
365 BAD ( "Authentication failed" );
369 if ((! authenticated
) && ( P_CF
-> authtype
!= AT_NONE
))
370 BAD ( "Packet is not authenticated and it should be" );
371 ipa_ntoh ( block
-> network
);
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
);
378 process_block ( p
, block
, whotoldme
);
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" );
392 rip_rx ( sock
* s
, int size
)
394 struct rip_interface
* i
= s
-> data
;
395 struct proto
* p
= i
-> proto
;
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" );
406 rip_process_packet ( p
, ( struct rip_packet
*) s
-> rbuf
, num
, s
-> faddr
, s
-> fport
);
411 * Interface to rest of bird
415 rip_dump_entry ( struct rip_entry
* e
)
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]" );
426 struct proto
* p
= t
-> data
;
427 struct rip_entry
* e
, * et
;
430 DBG ( "RIP: tick tock \n " );
432 WALK_LIST_DELSAFE ( e
, et
, P
-> garbage
) {
434 rte
= SKIP_BACK ( struct rte
, u
. rip
. garbage
, e
);
435 DBG ( "Garbage: " ); rte_dump ( rte
);
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
;
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
);
448 DBG ( "RIP: Broadcasting routing tables \n " );
450 struct rip_interface
* rif
;
453 WALK_LIST ( rif
, P
-> interfaces
) {
454 struct iface
* iface
= rif
-> iface
;
456 if (! iface
) continue ;
457 if ( rif
-> patt
-> mode
& IM_QUIET
) continue ;
458 if (!( iface
-> flags
& IF_UP
)) continue ;
460 rif
-> triggered
= ( P
-> tx_count
% 6 );
461 rip_sendto ( p
, IPA_NONE
, 0 , rif
);
465 DBG ( "RIP: tick tock done \n " );
469 rip_start ( struct proto
* p
)
471 struct rip_interface
* rif
;
472 DBG ( "RIP: starting instance... \n " );
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
);
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
);
489 rip_init_instance ( p
);
491 DBG ( "RIP: ...done \n " );
495 static struct proto
*
496 rip_init ( struct proto_config
* cfg
)
498 struct proto
* p
= proto_new ( cfg
, sizeof ( struct rip_proto
));
504 rip_dump ( struct proto
* p
)
508 struct rip_interface
* rif
;
512 WALK_LIST ( w
, P
-> connections
) {
513 struct rip_connection
* n
= ( void *) w
;
514 debug ( "RIP: connection #%d: %I \n " , n
-> num
, n
-> addr
);
517 FIB_WALK ( & P
-> rtable
, e
) {
518 debug ( "RIP: entry #%d: " , i
++ );
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
);
528 rip_get_route_info ( rte
* rte
, byte
* buf
)
530 buf
+= sprintf ( buf
, " (%d/%d)" , rte
-> pref
, rte
-> u
. rip
. metric
);
531 sprintf ( buf
, " t%04x" , rte
-> u
. rip
. tag
);
535 rip_want_this_if ( struct rip_interface
* iface
)
541 kill_iface ( struct proto
* p
, struct rip_interface
* i
)
543 DBG ( "RIP: Interface %s disappeared \n " , i
-> iface
-> name
);
549 * new maybe null if we are creating initial send socket
551 static struct rip_interface
*
552 new_iface ( struct proto
* p
, struct iface
* new , unsigned long flags
, struct iface_patt
* patt
)
554 struct rip_interface
* rif
;
555 int want_multicast
= 0 ;
557 rif
= mb_allocz ( p
-> pool
, sizeof ( struct rip_interface
));
561 rif
-> patt
= ( struct rip_patt
*) 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 */
568 DBG ( "Doing multicasts! \n " );
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
;
586 rif
-> sock
-> tos
= IP_PREC_INTERNET_CONTROL
;
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 );
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)" );
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 :-) */
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
);
611 rip_if_notify ( struct proto
* p
, unsigned c
, struct iface
* iface
)
613 DBG ( "RIP: if notify \n " );
614 if ( iface
-> flags
& IF_IGNORE
)
616 if ( c
& IF_CHANGE_DOWN
) {
617 struct rip_interface
* i
;
618 i
= find_interface ( p
, iface
);
624 if ( c
& IF_CHANGE_UP
) {
625 struct rip_interface
* rif
;
626 struct iface_patt
* k
= iface_patt_match (& P_CF
-> iface_list
, iface
);
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
);
635 static struct ea_list
*
636 rip_gen_attrs ( struct proto
* p
, struct linpool
* pool
, int metric
, u16 tag
)
638 struct ea_list
* l
= lp_alloc ( pool
, sizeof ( struct ea_list
) + 2 * sizeof ( eattr
));
641 l
-> flags
= EALF_SORTED
;
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
;
655 rip_import_control ( struct proto
* p
, struct rte
** rt
, struct ea_list
** attrs
, struct linpool
* pool
)
657 if ((* rt
)-> attrs
-> proto
== p
) /* My own must not be touched */
660 if ((* rt
)-> attrs
-> source
!= RTS_RIP
) {
661 struct ea_list
* new = rip_gen_attrs ( p
, pool
, 1 , 0 );
668 static struct ea_list
*
669 rip_make_tmp_attrs ( struct rte
* rt
, struct linpool
* pool
)
671 struct proto
* p
= rt
-> attrs
-> proto
;
672 return rip_gen_attrs ( p
, pool
, rt
-> u
. rip
. metric
, rt
-> u
. rip
. tag
);
676 rip_store_tmp_attrs ( struct rte
* rt
, struct ea_list
* attrs
)
678 struct proto
* p
= rt
-> attrs
-> proto
;
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
;
685 rip_rt_notify ( struct proto
* p
, struct network
* net
, struct rte
* new , struct rte
* old
, struct ea_list
* attrs
)
690 struct rip_entry
* e
= fib_find ( & P
-> rtable
, & net
-> n
. prefix
, net
-> n
. pxlen
);
692 log ( L_BUG
"Deleting nonexistent entry?!" );
693 fib_delete ( & P
-> rtable
, 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
);
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? */
709 e
-> whotoldme
= new -> attrs
-> from
;
710 e
-> updated
= e
-> changed
= now
;
716 rip_rte_better ( struct rte
* new , struct rte
* old
)
718 if ( ipa_equal ( old
-> attrs
-> from
, new -> attrs
-> from
))
721 if ( old
-> u
. rip
. metric
< new -> u
. rip
. metric
)
724 if ( old
-> u
. rip
. metric
> new -> u
. rip
. metric
)
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 */
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 */
740 rip_rte_insert ( net
* net
, rte
* rte
)
742 struct proto
* p
= rte
-> attrs
-> proto
;
743 rte
-> u
. rip
. lastmodX
= now
;
744 add_head ( & P
-> garbage
, & rte
-> u
. rip
. garbage
);
748 rip_rte_remove ( net
* net
, rte
* rte
)
750 struct proto
* p
= rte
-> attrs
-> proto
;
751 rem_node ( & rte
-> u
. rip
. garbage
);
755 rip_init_instance ( struct proto
* p
)
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
;
769 rip_init_config ( struct rip_proto_config
* c
)
771 init_list (& c
-> iface_list
);
775 c
-> garbage_time
= 120 + 180 ;
776 c
-> timeout_time
= 120 ;
778 c
-> authtype
= AT_NONE
;
782 rip_preconfig ( struct protocol
* x
, struct config
* c
)
784 DBG ( "RIP: preconfig \n " );
788 rip_postconfig ( struct proto_config
* c
)
792 struct protocol proto_rip
= {
795 preconfig
: rip_preconfig
,
796 postconfig
: rip_postconfig
,
797 get_route_info
: rip_get_route_info
,