]>
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: 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.
30 #include "nest/bird.h"
31 #include "nest/iface.h"
32 #include "nest/protocol.h"
33 #include "nest/route.h"
34 #include "lib/socket.h"
35 #include "lib/resource.h"
36 #include "lib/lists.h"
37 #include "lib/timer.h"
41 #define P ((struct rip_proto *) p)
42 #define P_CF ((struct rip_proto_config *)p->cf)
43 #define E ((struct rip_entry *) e)
45 static struct rip_interface
* new_iface ( struct proto
* p
, struct iface
* new , unsigned long flags
, struct iface_patt
* patt
);
48 rip_reply ( struct proto
* p
)
51 P
-> listen
-> tbuf
= "ACK!" ;
52 sk_send_to ( P
-> listen
, 5 , P
-> listen
-> faddr
, P
-> listen
-> fport
);
56 #define P_NAME p->name
63 rip_tx_err ( sock
* s
, int err
)
65 struct rip_connection
* c
= s
-> data
;
66 struct proto
* p
= c
-> proto
;
67 log ( L_ERR
"Unexpected error at rip transmit: %m" );
71 rip_tx_prepare ( struct proto
* p
, ip_addr daddr
, struct rip_block
* b
, struct rip_entry
* e
)
74 b
-> family
= htons ( 2 ); /* AF_INET */
75 b
-> tag
= htons ( e
-> tag
);
76 b
-> network
= e
-> n
. prefix
;
78 b
-> netmask
= ipa_mkmask ( e
-> n
. pxlen
);
79 ipa_hton ( b
-> netmask
);
80 b
-> nexthop
= IPA_NONE
;
83 * FIXME: This DOESN'T work. The s->daddr will be typically
84 * a broadcast or multicast address which will be of course
85 * rejected by the neighbor cache. I've #ifdef'd out the whole
86 * test to avoid dereferencing NULL pointer. --mj
90 n1
= neigh_find ( p
, & daddr
, 0 ); /* FIXME, mj: this is neccessary for responses, still it is too complicated for common case */
91 n2
= neigh_find ( p
, & e
-> nexthop
, 0 );
92 if ( n1
-> iface
== n2
-> iface
)
93 b
-> nexthop
= e
-> nexthop
;
96 b
-> nexthop
= IPA_NONE
;
98 ipa_hton ( b
-> nexthop
);
100 b
-> pxlen
= e
-> n
. pxlen
;
102 b
-> metric
= htonl ( e
-> metric
);
103 if ( ipa_equal ( e
-> whotoldme
, daddr
)) { /* FIXME: ouch, daddr is some kind of broadcast address. How am I expected to do split horizont?!?!? */
104 DBG ( "(split horizont)" );
105 b
-> metric
= P_CF
-> infinity
;
107 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
;
119 DBG ( "Sending to %I \n " , s
-> daddr
);
123 DBG ( "Looks like I'm" );
131 DBG ( "Preparing packet to send: " );
133 packet
-> heading
. command
= RIPCMD_RESPONSE
;
134 packet
-> heading
. version
= RIP_V2
;
135 packet
-> heading
. unused
= 0 ;
137 i
= !! P_CF
-> authtype
;
138 FIB_ITERATE_START (& P
-> rtable
, & c
-> iter
, z
) {
139 struct rip_entry
* e
= ( struct rip_entry
*) z
;
141 if ( rif
-> triggered
&& (!( e
-> updated
< now
- 5 )))
144 rip_tx_prepare ( p
, s
-> daddr
, packet
-> block
+ i
, e
);
145 if ( i
++ == (( P_CF
-> authtype
== AT_MD5
) ? PACKET_MD5_MAX
: PACKET_MAX
)) {
146 FIB_ITERATE_PUT (& c
-> iter
, z
);
149 } FIB_ITERATE_END ( z
);
155 rip_outgoing_authentication ( p
, ( void *) & packet
-> block
[ 0 ], packet
, i
);
157 DBG ( ", sending %d blocks, " , i
);
161 if ( ipa_nonzero ( c
-> daddr
))
162 i
= sk_send_to ( s
, sizeof ( struct rip_packet_heading
) + i
* sizeof ( struct rip_block
), c
-> daddr
, c
-> dport
);
164 i
= sk_send ( s
, sizeof ( struct rip_packet_heading
) + i
* sizeof ( struct rip_block
) );
166 DBG ( "it wants more \n " );
170 if ( i
< 0 ) rip_tx_err ( s
, i
);
177 rip_sendto ( struct proto
* p
, ip_addr daddr
, int dport
, struct rip_interface
* rif
)
179 struct iface
* iface
= rif
-> iface
;
180 struct rip_connection
* c
= mb_alloc ( p
-> pool
, sizeof ( struct rip_connection
));
184 log ( L_WARN
"Interface %s is much too slow, dropping request" , iface
-> name
);
185 /* FIXME: memory leak */
197 if ( c
-> rif
-> sock
-> data
!= rif
)
198 bug ( "not enough send magic" );
200 if ( sk_open ( c
-> send
)< 0 ) {
201 log ( L_ERR
"Could not open socket for data send to %I:%d on %s" , daddr
, dport
, rif
-> iface
-> name
);
207 fit_init ( & c
-> iter
, & P
-> rtable
);
208 add_head ( & P
-> connections
, NODE c
);
209 debug ( "Sending my routing table to %I:%d on %s \n " , daddr
, dport
, rif
-> iface
-> name
);
211 rip_tx ( c
-> rif
-> sock
);
214 static struct rip_interface
*
215 find_interface ( struct proto
* p
, struct iface
* what
)
217 struct rip_interface
* i
;
219 WALK_LIST ( i
, P
-> interfaces
)
220 if ( i
-> iface
== what
)
229 /* Let main routing table know about our new entry */
231 advertise_entry ( struct proto
* p
, struct rip_block
* b
, ip_addr whotoldme
)
237 struct rip_interface
* rif
;
240 bzero (& A
, sizeof ( A
));
243 A
. scope
= SCOPE_UNIVERSE
;
244 A
. cast
= RTC_UNICAST
;
248 A
. gw
= ipa_nonzero ( b
-> nexthop
) ? b
-> nexthop
: whotoldme
;
249 pxlen
= ipa_mklen ( b
-> netmask
);
251 A
. gw
= whotoldme
; /* FIXME: next hop is in other packet for v6 */
256 /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */
258 neighbor
= neigh_find ( p
, & A
. gw
, 0 );
260 log ( L_ERR
"%I asked me to route %I/%d using not-neighbor %I." , A
. from
, b
-> network
, pxlen
, A
. gw
);
264 A
. iface
= neighbor
-> iface
;
265 if (!( rif
= neighbor
-> data
)) {
266 rif
= neighbor
-> data
= find_interface ( p
, A
. iface
);
269 bug ( "Route packet using unknown interface? No." );
273 /* set to: interface of nexthop */
276 log ( L_ERR
"%I gave me invalid pxlen/netmask for %I." , A
. from
, b
-> network
);
279 n
= net_get ( p
-> table
, b
-> network
, pxlen
);
281 r
-> u
. rip
. metric
= ntohl ( b
-> metric
) + rif
-> patt
-> metric
;
282 if ( r
-> u
. rip
. metric
> P_CF
-> infinity
) r
-> u
. rip
. metric
= P_CF
-> infinity
;
283 r
-> u
. rip
. tag
= ntohl ( b
-> tag
);
285 r
-> pflags
= 0 ; /* Here go my flags */
286 rte_update ( p
-> table
, n
, p
, r
);
291 process_block ( struct proto
* p
, struct rip_block
* block
, ip_addr whotoldme
)
293 int metric
= ntohl ( block
-> metric
);
294 ip_addr network
= block
-> network
;
297 if ((! metric
) || ( metric
> P_CF
-> infinity
)) {
298 log ( L_WARN
"Got metric %d from %I" , metric
, whotoldme
);
302 debug ( "block: %I tells me: %I/??? available, metric %d... " , whotoldme
, network
, metric
);
304 advertise_entry ( p
, block
, whotoldme
);
307 #define BAD( x ) { log( L_WARN "RIP/%s: " x, P_NAME ); return 1; }
310 rip_process_packet ( struct proto
* p
, struct rip_packet
* packet
, int num
, ip_addr whotoldme
, int port
)
313 int native_class
= 0 , authenticated
= 0 ;
315 switch ( packet
-> heading
. version
) {
316 case RIP_V1
: DBG ( "Rip1: " ); break ;
317 case RIP_V2
: DBG ( "Rip2: " ); break ;
318 default : BAD ( "Unknown version" );
321 switch ( packet
-> heading
. command
) {
322 case RIPCMD_REQUEST
: DBG ( "Asked to send my routing table \n " );
323 if ( P_CF
-> honour
== HO_NEVER
) {
324 log ( L_WARN
"They asked me to send routing table, but I was told not to do it \n " );
327 if (( P_CF
-> honour
== HO_NEIGHBOUR
) && (! neigh_find ( p
, & whotoldme
, 0 ))) {
328 log ( L_WARN
"They asked me to send routing table, but he is not my neighbour \n " );
331 rip_sendto ( p
, whotoldme
, port
, HEAD ( P
-> interfaces
) ); /* no broadcast */
333 case RIPCMD_RESPONSE
: DBG ( "*** Rtable from %I \n " , whotoldme
);
334 if ( port
!= P_CF
-> port
) {
335 log ( L_ERR
"%I send me routing info from port %d" , whotoldme
, port
);
339 log ( L_ERR
"...ignoring" );
343 if (! neigh_find ( p
, & whotoldme
, 0 )) {
344 log ( L_ERR
"%I send me routing info but he is not my neighbour" , whotoldme
);
348 log ( L_ERR
"...ignoring" );
352 for ( i
= 0 ; i
< num
; i
++) {
353 struct rip_block
* block
= & packet
-> block
[ i
];
354 if ( block
-> family
== 0xffff )
356 if ( rip_incoming_authentication ( p
, ( void *) block
, packet
, num
))
357 BAD ( "Authentication failed" );
360 if ((! authenticated
) && ( P_CF
-> authtype
!= AT_NONE
))
361 BAD ( "Packet is not authenticated and it should be" );
362 ipa_ntoh ( block
-> network
);
364 ipa_ntoh ( block
-> netmask
);
365 ipa_ntoh ( block
-> nexthop
);
366 if ( packet
-> heading
. version
== RIP_V1
)
367 block
-> netmask
= ipa_class_mask ( block
-> network
);
369 process_block ( p
, block
, whotoldme
);
373 case RIPCMD_TRACEOFF
: BAD ( "I was asked for traceon/traceoff" );
374 case 5 : BAD ( "Some Sun extension around here" );
375 default : BAD ( "Unknown command" );
383 rip_rx ( sock
* s
, int size
)
385 struct rip_interface
* i
= s
-> data
;
386 struct proto
* p
= i
-> proto
;
390 DBG ( "RIP: message came: %d bytes \n " , size
);
391 size
-= sizeof ( struct rip_packet_heading
);
392 if ( size
< 0 ) BAD ( "Too small packet" );
393 if ( size
% sizeof ( struct rip_block
)) BAD ( "Odd sized packet" );
394 num
= size
/ sizeof ( struct rip_block
);
395 if ( num
> 25 ) BAD ( "Too many blocks" );
397 rip_process_packet ( p
, ( struct rip_packet
*) s
-> rbuf
, num
, s
-> faddr
, s
-> fport
);
402 * Interface to rest of bird
406 rip_dump_entry ( struct rip_entry
* e
)
408 debug ( "%I told me %d/%d ago: to %I/%d go via %I, metric %d " ,
409 e
-> whotoldme
, e
-> updated
- now
, e
-> changed
- now
, e
-> n
. prefix
, e
-> n
. pxlen
, e
-> nexthop
, e
-> metric
);
410 if ( e
-> flags
& RIP_F_EXTERNAL
) debug ( "[external]" );
417 struct proto
* p
= t
-> data
;
418 struct rip_entry
* e
, * et
;
421 DBG ( "RIP: tick tock \n " );
423 WALK_LIST_DELSAFE ( e
, et
, P
-> garbage
) {
425 rte
= SKIP_BACK ( struct rte
, u
. rip
. garbage
, e
);
426 DBG ( "Garbage: " ); rte_dump ( rte
);
428 if ( now
- rte
-> u
. rip
. lastmodX
> P_CF
-> timeout_time
) {
429 debug ( "RIP: entry is too old: " ); rte_dump ( rte
);
430 e
-> metric
= P_CF
-> infinity
;
433 if ( now
- rte
-> u
. rip
. lastmodX
> P_CF
-> garbage_time
) {
434 debug ( "RIP: entry is much too old: " ); rte_dump ( rte
);
435 rte_discard ( p
-> table
, rte
);
439 /* FIXME: we need to do triggered updates */
441 DBG ( "RIP: Broadcasting routing tables \n " );
443 struct rip_interface
* rif
;
446 WALK_LIST ( rif
, P
-> interfaces
) {
447 struct iface
* iface
= rif
-> iface
;
449 if (! iface
) continue ;
450 if ( rif
-> patt
-> mode
& IM_QUIET
) continue ;
451 if (!( iface
-> flags
& IF_UP
)) continue ;
453 rif
-> triggered
= ( P
-> tx_count
% 6 );
454 rip_sendto ( p
, IPA_NONE
, 0 , rif
);
458 DBG ( "RIP: tick tock done \n " );
462 rip_start ( struct proto
* p
)
464 struct rip_interface
* rif
;
465 DBG ( "RIP: starting instance... \n " );
467 P
-> magic
= RIP_MAGIC
;
468 fib_init ( & P
-> rtable
, p
-> pool
, sizeof ( struct rip_entry
), 0 , NULL
);
469 init_list ( & P
-> connections
);
470 init_list ( & P
-> garbage
);
471 init_list ( & P
-> interfaces
);
472 P
-> timer
= tm_new ( p
-> pool
);
474 P
-> timer
-> randomize
= 5 ;
475 P
-> timer
-> recurrent
= P_CF
-> period
;
476 P
-> timer
-> hook
= rip_timer
;
477 tm_start ( P
-> timer
, 5 );
478 rif
= new_iface ( p
, NULL
, 0 , NULL
); /* Initialize dummy interface */
479 add_head ( & P
-> interfaces
, NODE rif
);
482 rip_init_instance ( p
);
484 DBG ( "RIP: ...done \n " );
488 static struct proto
*
489 rip_init ( struct proto_config
* cfg
)
491 struct proto
* p
= proto_new ( cfg
, sizeof ( struct rip_proto
));
497 rip_dump ( struct proto
* p
)
501 struct rip_interface
* rif
;
505 WALK_LIST ( w
, P
-> connections
) {
506 struct rip_connection
* n
= ( void *) w
;
507 debug ( "RIP: connection #%d: %I \n " , n
-> num
, n
-> addr
);
510 FIB_WALK ( & P
-> rtable
, e
) {
511 debug ( "RIP: entry #%d: " , i
++ );
515 WALK_LIST ( rif
, P
-> interfaces
) {
516 debug ( "RIP: interface #%d: %s, %I, busy = %x \n " , i
++, rif
-> iface
? rif
-> iface
-> name
: "(dummy)" , rif
-> sock
-> daddr
, rif
-> busy
);
521 rip_want_this_if ( struct rip_interface
* iface
)
527 kill_iface ( struct proto
* p
, struct rip_interface
* i
)
529 DBG ( "RIP: Interface %s disappeared \n " , i
-> iface
-> name
);
535 * new maybe null if we are creating initial send socket
537 static struct rip_interface
*
538 new_iface ( struct proto
* p
, struct iface
* new , unsigned long flags
, struct iface_patt
* patt
)
540 struct rip_interface
* rif
;
541 int want_multicast
= 0 ;
543 rif
= mb_allocz ( p
-> pool
, sizeof ( struct rip_interface
));
547 rif
-> patt
= ( struct rip_patt
*) patt
;
550 want_multicast
= (!( rif
-> patt
-> mode
& IM_BROADCAST
)) && ( flags
& IF_MULTICAST
);
551 /* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
554 DBG ( "Doing multicasts! \n " );
556 rif
-> sock
= sk_new ( p
-> pool
);
557 rif
-> sock
-> type
= want_multicast
? SK_UDP_MC
: SK_UDP
;
558 rif
-> sock
-> sport
= P_CF
-> port
;
559 rif
-> sock
-> rx_hook
= rip_rx
;
560 rif
-> sock
-> data
= rif
;
561 rif
-> sock
-> rbsize
= 10240 ;
562 rif
-> sock
-> iface
= new ; /* Automagically works for dummy interface */
563 rif
-> sock
-> tbuf
= mb_alloc ( p
-> pool
, sizeof ( struct rip_packet
));
564 rif
-> sock
-> tx_hook
= rip_tx
;
565 rif
-> sock
-> err_hook
= rip_tx_err
;
566 rif
-> sock
-> daddr
= IPA_NONE
;
567 rif
-> sock
-> dport
= P_CF
-> port
;
572 rif
-> sock
-> tos
= IP_PREC_INTERNET_CONTROL
;
574 if ( flags
& IF_BROADCAST
)
575 rif
-> sock
-> daddr
= new -> addr
-> brd
;
576 if ( flags
& IF_UNNUMBERED
) {
577 rif
-> sock
-> daddr
= new -> addr
-> opposite
;
578 log ( L_WARN
"RIP/%s: rip is not defined over unnumbered links \n " , P_NAME
);
580 if ( want_multicast
) {
581 rif
-> sock
-> daddr
= ipa_from_u32 ( 0xe0000009 );
582 rif
-> sock
-> saddr
= ipa_from_u32 ( 0xe0000009 );
585 if (! ipa_nonzero ( rif
-> sock
-> daddr
)) {
586 log ( L_WARN
"RIP/%s: interface %s is too strange for me" , P_NAME
, rif
-> iface
? rif
-> iface
-> name
: "(dummy)" );
588 if (!( rif
-> patt
-> mode
& IM_NOLISTEN
))
589 if ( sk_open ( rif
-> sock
)< 0 ) {
590 log ( L_ERR
"RIP/%s: could not listen on %s" , P_NAME
, rif
-> iface
? rif
-> iface
-> name
: "(dummy)" );
591 /* Don't try to transmit into this one? Well, why not? This should not happen, anyway :-) */
594 log ( L_DEBUG
"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
);
600 rip_if_notify ( struct proto
* p
, unsigned c
, struct iface
* iface
)
602 DBG ( "RIP: if notify \n " );
603 if ( iface
-> flags
& IF_IGNORE
)
605 if ( c
& IF_CHANGE_DOWN
) {
606 struct rip_interface
* i
;
607 i
= find_interface ( p
, iface
);
613 if ( c
& IF_CHANGE_UP
) {
614 struct rip_interface
* rif
;
615 struct iface_patt
* k
= iface_patt_match (& P_CF
-> iface_list
, iface
);
617 if (! k
) return ; /* We are not interested in this interface */
618 DBG ( "adding interface %s \n " , iface
-> name
);
619 rif
= new_iface ( p
, iface
, iface
-> flags
, k
);
620 add_head ( & P
-> interfaces
, NODE rif
);
624 static struct ea_list
*
625 rip_gen_attrs ( struct proto
* p
, struct linpool
* pool
, int metric
, u16 tag
)
627 struct ea_list
* l
= lp_alloc ( pool
, sizeof ( struct ea_list
) + 2 * sizeof ( eattr
));
630 l
-> flags
= EALF_SORTED
;
632 l
-> attrs
[ 0 ]. id
= EA_RIP_TAG
;
633 l
-> attrs
[ 0 ]. flags
= 0 ;
634 l
-> attrs
[ 0 ]. type
= EAF_TYPE_INT
| EAF_INLINE
;
635 l
-> attrs
[ 0 ]. u
. data
= tag
;
636 l
-> attrs
[ 1 ]. id
= EA_RIP_TAG
;
637 l
-> attrs
[ 1 ]. flags
= 0 ;
638 l
-> attrs
[ 1 ]. type
= EAF_TYPE_INT
| EAF_INLINE
;
639 l
-> attrs
[ 1 ]. u
. data
= metric
;
644 rip_import_control ( struct proto
* p
, struct rte
** rt
, struct ea_list
** attrs
, struct linpool
* pool
)
646 if ((* rt
)-> attrs
-> proto
== p
) /* My own must not be touched */
649 if ((* rt
)-> attrs
-> source
!= RTS_RIP
) {
650 struct ea_list
* new = rip_gen_attrs ( p
, pool
, 1 , 0 );
657 static struct ea_list
*
658 rip_make_tmp_attrs ( struct rte
* rt
, struct linpool
* pool
)
660 struct proto
* p
= rt
-> attrs
-> proto
;
661 return rip_gen_attrs ( p
, pool
, rt
-> u
. rip
. metric
, rt
-> u
. rip
. tag
);
665 rip_store_tmp_attrs ( struct rte
* rt
, struct ea_list
* attrs
)
667 struct proto
* p
= rt
-> attrs
-> proto
;
669 rt
-> u
. rip
. tag
= ea_find ( attrs
, EA_RIP_TAG
)-> u
. data
;
670 rt
-> u
. rip
. metric
= ea_find ( attrs
, EA_RIP_TAG
)-> u
. data
;
674 rip_rt_notify ( struct proto
* p
, struct network
* net
, struct rte
* new , struct rte
* old
, struct ea_list
* attrs
)
679 struct rip_entry
* e
= fib_find ( & P
-> rtable
, & net
-> n
. prefix
, net
-> n
. pxlen
);
681 log ( L_BUG
"Deleting nonexistent entry?!" );
682 fib_delete ( & P
-> rtable
, e
);
687 if ( fib_find ( & P
-> rtable
, & net
-> n
. prefix
, net
-> n
. pxlen
))
688 log ( L_BUG
"Inserting entry which is already there?" );
689 e
= fib_get ( & P
-> rtable
, & net
-> n
. prefix
, net
-> n
. pxlen
);
691 e
-> nexthop
= new -> attrs
-> gw
;
692 e
-> tag
= ea_find ( attrs
, EA_RIP_TAG
)-> u
. data
;
693 e
-> metric
= ea_find ( attrs
, EA_RIP_TAG
)-> u
. data
;
694 if ( e
-> metric
> P_CF
-> infinity
)
695 e
-> metric
= P_CF
-> infinity
;
698 e
-> whotoldme
= new -> attrs
-> from
;
699 e
-> updated
= e
-> changed
= now
;
705 rip_rte_better ( struct rte
* new , struct rte
* old
)
707 if ( ipa_equal ( old
-> attrs
-> from
, new -> attrs
-> from
))
710 if ( old
-> u
. rip
. metric
< new -> u
. rip
. metric
)
713 if ( old
-> u
. rip
. metric
> new -> u
. rip
. metric
)
716 if (( old
-> u
. rip
. metric
!= 16 ) && ( new -> u
. rip
. metric
== 16 )) {
717 struct proto
* p
= new -> attrs
-> proto
;
718 new -> u
. rip
. lastmodX
= now
- P_CF
-> timeout_time
; /* Check this: if new metric is 16, act as it was timed out */
721 if (( old
-> u
. rip
. metric
== new -> u
. rip
. metric
) &&
722 (( 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 */
729 rip_rte_insert ( net
* net
, rte
* rte
)
731 struct proto
* p
= rte
-> attrs
-> proto
;
732 rte
-> u
. rip
. lastmodX
= now
;
733 add_head ( & P
-> garbage
, & rte
-> u
. rip
. garbage
);
737 rip_rte_remove ( net
* net
, rte
* rte
)
739 struct proto
* p
= rte
-> attrs
-> proto
;
740 rem_node ( & rte
-> u
. rip
. garbage
);
744 rip_init_instance ( struct proto
* p
)
746 p
-> preference
= DEF_PREF_RIP
;
747 p
-> if_notify
= rip_if_notify
;
748 p
-> rt_notify
= rip_rt_notify
;
749 p
-> import_control
= rip_import_control
;
750 p
-> make_tmp_attrs
= rip_make_tmp_attrs
;
751 p
-> store_tmp_attrs
= rip_store_tmp_attrs
;
752 p
-> rte_better
= rip_rte_better
;
753 p
-> rte_insert
= rip_rte_insert
;
754 p
-> rte_remove
= rip_rte_remove
;
758 rip_init_config ( struct rip_proto_config
* c
)
760 init_list (& c
-> iface_list
);
764 c
-> garbage_time
= 120 + 180 ;
765 c
-> timeout_time
= 120 ;
767 c
-> authtype
= AT_NONE
;
771 rip_preconfig ( struct protocol
* x
, struct config
* c
)
773 DBG ( "RIP: preconfig \n " );
777 rip_postconfig ( struct proto_config
* c
)
781 struct protocol proto_rip
= {
783 preconfig
: rip_preconfig
,
784 postconfig
: rip_postconfig
,