]>
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 We are not going to honour requests for sending part of
17 routing table. That would need to turn split horizon off,
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.
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.
28 FIXME: mj wants us to be able to format attributes:
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:
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.
39 Please update protocols generating dynamic attributes to provide
40 the attr_class and formatting hook.
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"
58 #define P ((struct rip_proto *) p)
59 #define P_CF ((struct rip_proto_config *)p->cf)
60 #define E ((struct rip_entry *) e)
62 #define TRACE(level, msg, args...) do { if (p->debug & level) { log(L_TRACE "%s: " msg, p->name , ## args); } } while(0)
64 static struct rip_interface
*new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
);
66 #define P_NAME p->name
73 rip_tx_err( sock
*s
, int err
)
75 struct rip_connection
*c
= s
->data
;
76 struct proto
*p
= c
->proto
;
77 log( L_ERR
"Unexpected error at rip transmit: %m" );
81 rip_tx_prepare(struct proto
*p
, ip_addr daddr
, struct rip_block
*b
, struct rip_entry
*e
, struct rip_interface
*rif
, int pos
)
84 b
->family
= htons( 2 ); /* AF_INET */
85 b
->tag
= htons( e
->tag
);
86 b
->network
= e
->n
.prefix
;
88 b
->netmask
= ipa_mkmask( e
->n
.pxlen
);
89 ipa_hton( b
->netmask
);
91 if (neigh_connected_to(p
, &e
->nexthop
, rif
->iface
))
92 b
->nexthop
= e
->nexthop
;
94 b
->nexthop
= IPA_NONE
;
95 ipa_hton( b
->nexthop
);
97 b
->pxlen
= e
->n
.pxlen
;
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
);
104 ipa_hton( b
->network
);
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
;
117 int maxi
, nullupdate
= 1;
119 DBG( "Sending to %I\n", s
->daddr
);
125 DBG( "Preparing packet to send: " );
127 packet
->heading
.command
= RIPCMD_RESPONSE
;
128 packet
->heading
.version
= RIP_V2
;
129 packet
->heading
.unused
= 0;
131 i
= !!P_CF
->authtype
;
133 maxi
= ((P_CF
->authtype
== AT_MD5
) ? PACKET_MD5_MAX
: PACKET_MAX
);
135 maxi
= 5; /* We need to have at least reserve of one at end of packet */
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))) {
143 i
= rip_tx_prepare( p
, s
->daddr
, packet
->block
+ i
, e
, rif
, i
);
145 FIB_ITERATE_PUT(&c
->iter
, z
);
149 } FIB_ITERATE_END(z
);
154 packetlen
= rip_outgoing_authentication(p
, (void *) &packet
->block
[0], packet
, i
);
156 DBG( ", sending %d blocks, ", i
);
158 DBG( "not sending NULL update\n" );
162 if (ipa_nonzero(c
->daddr
))
163 i
= sk_send_to( s
, packetlen
, c
->daddr
, c
->dport
);
165 i
= sk_send( s
, packetlen
);
167 DBG( "it wants more\n" );
171 if (i
<0) rip_tx_err( s
, i
);
176 DBG( "Looks like I'm" );
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
;
192 log (L_WARN
"Interface %s is much too slow, dropping request", iface
->name
);
195 c
= mb_alloc( p
->pool
, sizeof( struct rip_connection
));
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 TRACE(D_PACKETS
, "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 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 */
309 { debug( "IpV6 nexthop ignored" ); return; }
311 log( L_WARN
"Got metric %d from %I", metric
, whotoldme
);
315 advertise_entry( p
, block
, whotoldme
);
318 #define BAD( x ) { log( L_REMOTE "%s: " x, P_NAME ); return 1; }
321 rip_process_packet( struct proto
*p
, struct rip_packet
*packet
, int num
, ip_addr whotoldme
, int port
)
324 int native_class
= 0, authenticated
= 0;
326 switch( packet
->heading
.version
) {
327 case RIP_V1
: DBG( "Rip1: " ); break;
328 case RIP_V2
: DBG( "Rip2: " ); break;
329 default: BAD( "Unknown version" );
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" );
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" );
342 rip_sendto( p
, whotoldme
, port
, HEAD(P
->interfaces
) ); /* no broadcast */
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
);
350 log( L_REMOTE
"...ignoring" );
354 if (!neigh_find( p
, &whotoldme
, 0 )) {
355 log( L_REMOTE
"%I send me routing info but he is not my neighbour", whotoldme
);
359 log( L_REMOTE
"...ignoring" );
363 for (i
=0; i
<num
; i
++) {
364 struct rip_block
*block
= &packet
->block
[i
];
365 if (block
->family
== 0xffff) {
367 continue; /* md5 tail has this family */
368 if (rip_incoming_authentication(p
, (void *) block
, packet
, num
, whotoldme
))
369 BAD( "Authentication failed" );
373 if ((!authenticated
) && (P_CF
->authtype
!= AT_NONE
))
374 BAD( "Packet is not authenticated and it should be" );
375 ipa_ntoh( block
->network
);
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
);
382 process_block( p
, block
, whotoldme
);
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" );
395 rip_rx(sock
*s
, int size
)
397 struct rip_interface
*i
= s
->data
;
398 struct proto
*p
= i
->proto
;
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" );
409 rip_process_packet( p
, (struct rip_packet
*) s
->rbuf
, num
, s
->faddr
, s
->fport
);
414 * Interface to rest of bird
418 rip_dump_entry( struct rip_entry
*e
)
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]" );
429 struct proto
*p
= t
->data
;
430 struct rip_entry
*e
, *et
;
433 DBG( "RIP: tick tock\n" );
435 WALK_LIST_DELSAFE( e
, et
, P
->garbage
) {
437 rte
= SKIP_BACK( struct rte
, u
.rip
.garbage
, e
);
438 DBG( "Garbage: " ); rte_dump( rte
);
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
;
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
);
451 DBG( "RIP: Broadcasting routing tables\n" );
453 struct rip_interface
*rif
;
456 WALK_LIST( rif
, P
->interfaces
) {
457 struct iface
*iface
= rif
->iface
;
459 if (!iface
) continue;
460 if (rif
->patt
->mode
& IM_QUIET
) continue;
461 if (!(iface
->flags
& IF_UP
)) continue;
463 rif
->triggered
= (P
->tx_count
% 6);
464 rip_sendto( p
, IPA_NONE
, 0, rif
);
468 DBG( "RIP: tick tock done\n" );
472 rip_start(struct proto
*p
)
474 struct rip_interface
*rif
;
475 DBG( "RIP: starting instance...\n" );
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
);
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
);
492 rip_init_instance(p
);
494 DBG( "RIP: ...done\n");
498 static struct proto
*
499 rip_init(struct proto_config
*cfg
)
501 struct proto
*p
= proto_new(cfg
, sizeof(struct rip_proto
));
507 rip_dump(struct proto
*p
)
511 struct rip_interface
*rif
;
515 WALK_LIST( w
, P
->connections
) {
516 struct rip_connection
*n
= (void *) w
;
517 debug( "RIP: connection #%d: %I\n", n
->num
, n
->addr
);
520 FIB_WALK( &P
->rtable
, e
) {
521 debug( "RIP: entry #%d: ", i
++ );
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
);
531 rip_get_route_info(rte
*rte
, byte
*buf
)
533 buf
+= bsprintf(buf
, " (%d/%d)", rte
->pref
, rte
->u
.rip
.metric
);
534 bsprintf(buf
, " t%04x", rte
->u
.rip
.tag
);
538 rip_want_this_if(struct rip_interface
*iface
)
544 kill_iface(struct proto
*p
, struct rip_interface
*i
)
546 DBG( "RIP: Interface %s disappeared\n", i
->iface
->name
);
552 * new maybe null if we are creating initial send socket
554 static struct rip_interface
*
555 new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
)
557 struct rip_interface
*rif
;
559 rif
= mb_allocz(p
->pool
, sizeof( struct rip_interface
));
563 rif
->patt
= (struct rip_patt
*) 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 */
570 DBG( "Doing multicasts!\n" );
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
;
588 rif
->sock
->tos
= IP_PREC_INTERNET_CONTROL
;
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
) {
595 rif
->sock
->daddr
= ipa_from_u32(0xe0000009);
596 rif
->sock
->saddr
= ipa_from_u32(0xe0000009);
598 p_pton("FF02::9", &rif
->sock
->daddr
);
599 p_pton("FF02::9", &rif
->sock
->saddr
);
602 rif
->sock
->daddr
= new->addr
->brd
;
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)" );
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 :-) */
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
);
620 rip_real_if_add(struct object_lock
*lock
)
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
);
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
);
636 rip_if_notify(struct proto
*p
, unsigned c
, struct iface
*iface
)
638 DBG( "RIP: if notify\n" );
639 if (iface
->flags
& IF_IGNORE
)
641 if (c
& IF_CHANGE_DOWN
) {
642 struct rip_interface
*i
;
643 i
= find_interface(p
, iface
);
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
;
655 if (!k
) return; /* We are not interested in this interface */
657 lock
= olock_new( p
->pool
);
658 lock
->addr
= ipa_from_u32(0xe0000009);
659 lock
->port
= P_CF
->port
;
661 lock
->hook
= rip_real_if_add
;
663 lock
->type
= OBJLOCK_UDP
;
668 static struct ea_list
*
669 rip_gen_attrs(struct proto
*p
, struct linpool
*pool
, int metric
, u16 tag
)
671 struct ea_list
*l
= lp_alloc(pool
, sizeof(struct ea_list
) + 2*sizeof(eattr
));
674 l
->flags
= EALF_SORTED
;
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
;
688 rip_import_control(struct proto
*p
, struct rte
**rt
, struct ea_list
**attrs
, struct linpool
*pool
)
690 if ((*rt
)->attrs
->proto
== p
) /* My own must not be touched */
693 if ((*rt
)->attrs
->source
!= RTS_RIP
) {
694 struct ea_list
*new = rip_gen_attrs(p
, pool
, 1, 0);
701 static struct ea_list
*
702 rip_make_tmp_attrs(struct rte
*rt
, struct linpool
*pool
)
704 struct proto
*p
= rt
->attrs
->proto
;
705 return rip_gen_attrs(p
, pool
, rt
->u
.rip
.metric
, rt
->u
.rip
.tag
);
709 rip_store_tmp_attrs(struct rte
*rt
, struct ea_list
*attrs
)
711 struct proto
*p
= rt
->attrs
->proto
;
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
;
718 rip_rt_notify(struct proto
*p
, struct network
*net
, struct rte
*new, struct rte
*old
, struct ea_list
*attrs
)
723 struct rip_entry
*e
= fib_find( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
725 log( L_BUG
"Deleting nonexistent entry?!" );
726 fib_delete( &P
->rtable
, 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
);
735 e
->nexthop
= new->attrs
->gw
;
737 e
->whotoldme
= IPA_NONE
;
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
;
744 if (new->attrs
->proto
== p
)
745 e
->whotoldme
= new->attrs
->from
;
747 if (!e
->metric
) /* That's okay: this way user can set his own value for external
750 e
->updated
= e
->changed
= now
;
756 rip_rte_better(struct rte
*new, struct rte
*old
)
758 struct proto
*p
= new->attrs
->proto
;
760 if (ipa_equal(old
->attrs
->from
, new->attrs
->from
))
763 if (old
->u
.rip
.metric
< new->u
.rip
.metric
)
766 if (old
->u
.rip
.metric
> new->u
.rip
.metric
)
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 */
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)))
782 rip_rte_insert(net
*net
, rte
*rte
)
784 struct proto
*p
= rte
->attrs
->proto
;
785 rte
->u
.rip
.lastmodX
= now
;
786 add_head( &P
->garbage
, &rte
->u
.rip
.garbage
);
790 rip_rte_remove(net
*net
, rte
*rte
)
792 struct proto
*p
= rte
->attrs
->proto
;
793 rem_node( &rte
->u
.rip
.garbage
);
797 rip_init_instance(struct proto
*p
)
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
;
811 rip_init_config(struct rip_proto_config
*c
)
813 init_list(&c
->iface_list
);
817 c
->garbage_time
= 120+180;
818 c
->timeout_time
= 120;
820 c
->authtype
= AT_NONE
;
824 rip_preconfig(struct protocol
*x
, struct config
*c
)
826 DBG( "RIP: preconfig\n" );
829 struct protocol proto_rip
= {
833 preconfig
: rip_preconfig
,
834 get_route_info
: rip_get_route_info
,