]>
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.
21 * DOC: Routing Information Protocol
23 * RIP is a pretty simple protocol, so about a half of its code is interface
26 * We maintain our own linked list of &rip_entry structures -- it serves
27 * as our small routing table. RIP never adds to this linked list upon
28 * packet reception; instead, it lets the core know about data from the packet
29 * and waits for the core to call rip_rte_notify().
31 * Within rip_tx(), the list is
32 * walked and a packet is generated using rip_tx_prepare(). This gets
33 * tricky because we may need to send more than one packet to one
34 * destination. Struct &rip_connection is used to hold context information such as how
35 * many of &rip_entry's we have already sent and it's also used to protect
36 * against two concurrent sends to one destination. Each &rip_interface has
37 * at most one &rip_connection.
39 * We are not going to honor requests for sending part of
40 * routing table. That would need to turn split horizon off etc.
42 * About triggered updates, RFC says: when a triggered update was sent,
43 * don't send a new one for something between 1 and 5 seconds (and send one
44 * after that). We do something else: each 5 seconds,
45 * we look for any changed routes and broadcast them.
50 #include "nest/bird.h"
51 #include "nest/iface.h"
52 #include "nest/protocol.h"
53 #include "nest/route.h"
54 #include "lib/socket.h"
55 #include "lib/resource.h"
56 #include "lib/lists.h"
57 #include "lib/timer.h"
58 #include "lib/string.h"
63 #define P ((struct rip_proto *) p)
64 #define P_CF ((struct rip_proto_config *)p->cf)
65 #define E ((struct rip_entry *) e)
67 #define TRACE(level, msg, args...) do { if (p->debug & level) { log(L_TRACE "%s: " msg, p->name , ## args); } } while(0)
69 static struct rip_interface
*new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
);
71 #define P_NAME p->name
76 * This part is responsible for getting packets out to the network.
80 rip_tx_err( sock
*s
, int err
)
82 struct rip_connection
*c
= ((struct rip_interface
*)(s
->data
))->busy
;
83 struct proto
*p
= c
->proto
;
84 log( L_ERR
"%s: Unexpected error at rip transmit: %M", P_NAME
, err
);
89 * @e: rip entry that needs to be translated to form suitable for network
90 * @b: block to be filled
92 * Fill one rip block with info that needs to go to the network. Handle
93 * nexthop and split horizont correctly. (Next hop is ignored for IPv6,
94 * that could be fixed but it is not real problem).
97 rip_tx_prepare(struct proto
*p
, struct rip_block
*b
, struct rip_entry
*e
, struct rip_interface
*rif
, int pos
)
101 b
->tag
= htons( e
->tag
);
102 b
->network
= e
->n
.prefix
;
104 if (neigh_connected_to(p
, &e
->whotoldme
, rif
->iface
)) {
105 DBG( "(split horizon)" );
106 metric
= P_CF
->infinity
;
109 b
->family
= htons( 2 ); /* AF_INET */
110 b
->netmask
= ipa_mkmask( e
->n
.pxlen
);
111 ipa_hton( b
->netmask
);
113 if (neigh_connected_to(p
, &e
->nexthop
, rif
->iface
))
114 b
->nexthop
= e
->nexthop
;
116 b
->nexthop
= IPA_NONE
;
117 ipa_hton( b
->nexthop
);
118 b
->metric
= htonl( metric
);
120 b
->pxlen
= e
->n
.pxlen
;
121 b
->metric
= metric
; /* it is u8 */
124 ipa_hton( b
->network
);
130 * rip_tx - send one rip packet to the network
135 struct rip_interface
*rif
= s
->data
;
136 struct rip_connection
*c
= rif
->busy
;
137 struct proto
*p
= c
->proto
;
138 struct rip_packet
*packet
= (void *) s
->tbuf
;
140 int maxi
, nullupdate
= 1;
142 DBG( "Sending to %I\n", s
->daddr
);
148 DBG( "Preparing packet to send: " );
150 packet
->heading
.command
= RIPCMD_RESPONSE
;
151 packet
->heading
.version
= RIP_V2
;
152 packet
->heading
.unused
= 0;
154 i
= !!P_CF
->authtype
;
156 maxi
= ((P_CF
->authtype
== AT_MD5
) ? PACKET_MD5_MAX
: PACKET_MAX
);
158 maxi
= 5; /* We need to have at least reserve of one at end of packet */
161 FIB_ITERATE_START(&P
->rtable
, &c
->iter
, z
) {
162 struct rip_entry
*e
= (struct rip_entry
*) z
;
164 if (!rif
->triggered
|| (!(e
->updated
< now
-5))) {
166 i
= rip_tx_prepare( p
, packet
->block
+ i
, e
, rif
, i
);
168 FIB_ITERATE_PUT(&c
->iter
, z
);
172 } FIB_ITERATE_END(z
);
177 packetlen
= rip_outgoing_authentication(p
, (void *) &packet
->block
[0], packet
, i
);
179 DBG( ", sending %d blocks, ", i
);
181 DBG( "not sending NULL update\n" );
185 if (ipa_nonzero(c
->daddr
))
186 i
= sk_send_to( s
, packetlen
, c
->daddr
, c
->dport
);
188 i
= sk_send( s
, packetlen
);
190 DBG( "it wants more\n" );
194 if (i
<0) rip_tx_err( s
, i
);
199 DBG( "Looks like I'm" );
208 * rip_sendto - send whole routing table to selected destination
209 * @rif: interface to use. Notice that we lock interface so that at
210 * most one send to one interface is done.
213 rip_sendto( struct proto
*p
, ip_addr daddr
, int dport
, struct rip_interface
*rif
)
215 struct iface
*iface
= rif
->iface
;
216 struct rip_connection
*c
;
220 log (L_WARN
"%s: Interface %s is much too slow, dropping request", P_NAME
, iface
->name
);
223 c
= mb_alloc( p
->pool
, sizeof( struct rip_connection
));
233 if (c
->rif
->sock
->data
!= rif
)
234 bug("not enough send magic");
237 FIB_ITERATE_INIT( &c
->iter
, &P
->rtable
);
238 add_head( &P
->connections
, NODE c
);
239 if (ipa_nonzero(daddr
))
240 TRACE(D_PACKETS
, "Sending my routing table to %I:%d on %s", daddr
, dport
, rif
->iface
->name
);
242 TRACE(D_PACKETS
, "Broadcasting routing table to %s", rif
->iface
->name
);
244 rip_tx(c
->rif
->sock
);
247 static struct rip_interface
*
248 find_interface(struct proto
*p
, struct iface
*what
)
250 struct rip_interface
*i
;
252 WALK_LIST (i
, P
->interfaces
)
253 if (i
->iface
== what
)
261 * This part is responsible for any updates that come from network
265 rip_rte_update_if_better(rtable
*tab
, net
*net
, struct proto
*p
, rte
*new)
269 old
= rte_find(net
, p
);
270 if (!old
|| p
->rte_better(new, old
))
271 rte_update(tab
, net
, p
, new);
275 * advertise_entry - let main routing table know about our new entry
276 * @b: entry in network format
278 * This basically translates @b to format used by bird core and feeds
279 * bird core with this route.
282 advertise_entry( struct proto
*p
, struct rip_block
*b
, ip_addr whotoldme
)
288 struct rip_interface
*rif
;
291 bzero(&A
, sizeof(A
));
294 A
.scope
= SCOPE_UNIVERSE
;
295 A
.cast
= RTC_UNICAST
;
299 A
.gw
= ipa_nonzero(b
->nexthop
) ? b
->nexthop
: whotoldme
;
300 pxlen
= ipa_mklen(b
->netmask
);
302 /* FIXME: next hop is in other packet for v6 */
308 /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */
310 neighbor
= neigh_find( p
, &A
.gw
, 0 );
312 log( L_REMOTE
"%s: %I asked me to route %I/%d using not-neighbor %I.", p
->name
, A
.from
, b
->network
, pxlen
, A
.gw
);
315 if (neighbor
->scope
== SCOPE_HOST
) {
316 DBG("Self-destined route, ignoring.\n");
320 A
.iface
= neighbor
->iface
;
321 if (!(rif
= neighbor
->data
)) {
322 rif
= neighbor
->data
= find_interface(p
, A
.iface
);
325 bug("Route packet using unknown interface? No.");
327 /* set to: interface of nexthop */
330 log( L_REMOTE
"%s: %I gave me invalid pxlen/netmask for %I.", p
->name
, A
.from
, b
->network
);
333 n
= net_get( p
->table
, b
->network
, pxlen
);
336 r
->u
.rip
.metric
= ntohl(b
->metric
) + rif
->metric
;
338 r
->u
.rip
.metric
= b
->metric
+ rif
->metric
;
341 r
->u
.rip
.entry
= NULL
;
342 if (r
->u
.rip
.metric
> P_CF
->infinity
) r
->u
.rip
.metric
= P_CF
->infinity
;
343 r
->u
.rip
.tag
= ntohl(b
->tag
);
345 r
->pflags
= 0; /* Here go my flags */
346 rip_rte_update_if_better( p
->table
, n
, p
, r
);
351 * process_block - do some basic check and pass block to advertise_entry
354 process_block( struct proto
*p
, struct rip_block
*block
, ip_addr whotoldme
)
357 int metric
= ntohl( block
->metric
);
359 int metric
= block
->metric
;
361 ip_addr network
= block
->network
;
364 TRACE(D_ROUTES
, "block: %I tells me: %I/??? available, metric %d... ", whotoldme
, network
, metric
);
365 /* FIXME: Why `???'? If prefix is unknown, just don't print it. [mj] */
366 if ((!metric
) || (metric
> P_CF
->infinity
)) {
367 #ifdef IPV6 /* Someone is sedning us nexthop and we are ignoring it */
369 { DBG( "IpV6 nexthop ignored" ); return; }
371 log( L_WARN
"%s: Got metric %d from %I", P_NAME
, metric
, whotoldme
);
375 advertise_entry( p
, block
, whotoldme
);
378 #define BAD( x ) { log( L_REMOTE "%s: " x, P_NAME ); return 1; }
381 * rip_process_packet - this is main routine for incoming packets.
384 rip_process_packet( struct proto
*p
, struct rip_packet
*packet
, int num
, ip_addr whotoldme
, int port
)
387 int authenticated
= 0;
390 switch( packet
->heading
.version
) {
391 case RIP_V1
: DBG( "Rip1: " ); break;
392 case RIP_V2
: DBG( "Rip2: " ); break;
393 default: BAD( "Unknown version" );
396 switch( packet
->heading
.command
) {
397 case RIPCMD_REQUEST
: DBG( "Asked to send my routing table\n" );
398 if (P_CF
->honor
== HO_NEVER
)
399 BAD( "They asked me to send routing table, but I was told not to do it" );
401 if ((P_CF
->honor
== HO_NEIGHBOR
) && (!neigh_find( p
, &whotoldme
, 0 )))
402 BAD( "They asked me to send routing table, but he is not my neighbor" );
403 rip_sendto( p
, whotoldme
, port
, HEAD(P
->interfaces
) ); /* no broadcast */
405 case RIPCMD_RESPONSE
: DBG( "*** Rtable from %I\n", whotoldme
);
406 if (port
!= P_CF
->port
) {
407 log( L_REMOTE
"%s: %I send me routing info from port %d", P_NAME
, whotoldme
, port
);
411 if (!(neighbor
= neigh_find( p
, &whotoldme
, 0 )) || neighbor
->scope
== SCOPE_HOST
) {
412 log( L_REMOTE
"%s: %I send me routing info but he is not my neighbor", P_NAME
, whotoldme
);
416 for (i
=0; i
<num
; i
++) {
417 struct rip_block
*block
= &packet
->block
[i
];
419 /* Authentication is not defined for v6 */
420 if (block
->family
== 0xffff) {
422 continue; /* md5 tail has this family */
423 if (rip_incoming_authentication(p
, (void *) block
, packet
, num
, whotoldme
))
424 BAD( "Authentication failed" );
429 if ((!authenticated
) && (P_CF
->authtype
!= AT_NONE
))
430 BAD( "Packet is not authenticated and it should be" );
431 ipa_ntoh( block
->network
);
433 ipa_ntoh( block
->netmask
);
434 ipa_ntoh( block
->nexthop
);
435 if (packet
->heading
.version
== RIP_V1
) /* FIXME (nonurgent): switch to disable this? */
436 block
->netmask
= ipa_class_mask(block
->network
);
438 process_block( p
, block
, whotoldme
);
442 case RIPCMD_TRACEOFF
: BAD( "I was asked for traceon/traceoff" );
443 case 5: BAD( "Some Sun extension around here" );
444 default: BAD( "Unknown command" );
451 * rip_rx - Receive hook: do basic checks and pass packet to rip_process_packet
454 rip_rx(sock
*s
, int size
)
456 struct rip_interface
*i
= s
->data
;
457 struct proto
*p
= i
->proto
;
460 /* In non-listening mode, just ignore packet */
461 if (i
->mode
& IM_NOLISTEN
)
465 DBG( "RIP: message came: %d bytes from %I via %s\n", size
, s
->faddr
, i
->iface
? i
->iface
->name
: "(dummy)" );
466 size
-= sizeof( struct rip_packet_heading
);
467 if (size
< 0) BAD( "Too small packet" );
468 if (size
% sizeof( struct rip_block
)) BAD( "Odd sized packet" );
469 num
= size
/ sizeof( struct rip_block
);
470 if (num
>PACKET_MAX
) BAD( "Too many blocks" );
473 /* Try to absolutize link scope addresses */
474 ipa_absolutize(&s
->faddr
, &i
->iface
->addr
->ip
);
477 if (ipa_equal(i
->iface
->addr
->ip
, s
->faddr
)) {
478 DBG("My own packet\n");
482 rip_process_packet( p
, (struct rip_packet
*) s
->rbuf
, num
, s
->faddr
, s
->fport
);
487 * Interface to BIRD core
491 rip_dump_entry( struct rip_entry
*e
)
493 debug( "%I told me %d/%d ago: to %I/%d go via %I, metric %d ",
494 e
->whotoldme
, e
->updated
-now
, e
->changed
-now
, e
->n
.prefix
, e
->n
.pxlen
, e
->nexthop
, e
->metric
);
502 * Broadcast routing tables periodically (using rip_tx) and kill
503 * routes that are too old. RIP keeps a list of its own entries present
504 * in the core table by a linked list (functions rip_rte_insert() and
505 * rip_rte_delete() are responsible for that), it walks this list in the timer
506 * and in case an entry is too old, it is discarded.
512 struct proto
*p
= t
->data
;
513 struct fib_node
*e
, *et
;
516 DBG( "RIP: tick tock\n" );
518 WALK_LIST_DELSAFE( e
, et
, P
->garbage
) {
520 rte
= SKIP_BACK( struct rte
, u
.rip
.garbage
, e
);
523 struct proto
*p
= rte
->attrs
->proto
;
526 DBG( "Garbage: (%p)", rte
); rte_dump( rte
);
529 if (now
- rte
->lastmod
> P_CF
->timeout_time
) {
530 TRACE(D_EVENTS
, "entry is too old: %I", rte
->net
->n
.prefix
);
531 if (rte
->u
.rip
.entry
) {
532 rte
->u
.rip
.entry
->metric
= P_CF
->infinity
;
533 rte
->u
.rip
.metric
= P_CF
->infinity
;
537 if (now
- rte
->lastmod
> P_CF
->garbage_time
) {
538 TRACE(D_EVENTS
, "entry is much too old: %I", rte
->net
->n
.prefix
);
539 rte_discard(p
->table
, rte
);
543 DBG( "RIP: Broadcasting routing tables\n" );
545 struct rip_interface
*rif
;
546 WALK_LIST( rif
, P
->interfaces
) {
547 struct iface
*iface
= rif
->iface
;
549 if (!iface
) continue;
550 if (rif
->mode
& IM_QUIET
) continue;
551 if (!(iface
->flags
& IF_UP
)) continue;
553 rif
->triggered
= (P
->tx_count
% 6);
554 rip_sendto( p
, IPA_NONE
, 0, rif
);
559 DBG( "RIP: tick tock done\n" );
563 * rip_start - initialize instance of rip
566 rip_start(struct proto
*p
)
568 struct rip_interface
*rif
;
569 DBG( "RIP: starting instance...\n" );
571 assert( sizeof(struct rip_packet_heading
) == 4);
572 assert( sizeof(struct rip_block
) == 20);
573 assert( sizeof(struct rip_block_auth
) == 20);
576 P
->magic
= RIP_MAGIC
;
577 fib_init( &P
->rtable
, p
->pool
, sizeof( struct rip_entry
), 0, NULL
);
578 init_list( &P
->connections
);
579 init_list( &P
->garbage
);
580 init_list( &P
->interfaces
);
581 P
->timer
= tm_new( p
->pool
);
583 P
->timer
->randomize
= 5;
584 P
->timer
->recurrent
= (P_CF
->period
/ 6)+1;
585 P
->timer
->hook
= rip_timer
;
586 tm_start( P
->timer
, 5 );
587 rif
= new_iface(p
, NULL
, 0, NULL
); /* Initialize dummy interface */
588 add_head( &P
->interfaces
, NODE rif
);
591 rip_init_instance(p
);
593 DBG( "RIP: ...done\n");
597 static struct proto
*
598 rip_init(struct proto_config
*cfg
)
600 struct proto
*p
= proto_new(cfg
, sizeof(struct rip_proto
));
606 rip_dump(struct proto
*p
)
610 struct rip_interface
*rif
;
614 WALK_LIST( w
, P
->connections
) {
615 struct rip_connection
*n
= (void *) w
;
616 debug( "RIP: connection #%d: %I\n", n
->num
, n
->addr
);
619 FIB_WALK( &P
->rtable
, e
) {
620 debug( "RIP: entry #%d: ", i
++ );
624 WALK_LIST( rif
, P
->interfaces
) {
625 debug( "RIP: interface #%d: %s, %I, busy = %x\n", i
++, rif
->iface
?rif
->iface
->name
:"(dummy)", rif
->sock
->daddr
, rif
->busy
);
630 rip_get_route_info(rte
*rte
, byte
*buf
, ea_list
*attrs
)
632 eattr
*metric
= ea_find(attrs
, EA_RIP_METRIC
);
633 eattr
*tag
= ea_find(attrs
, EA_RIP_TAG
);
635 buf
+= bsprintf(buf
, " (%d/%d)", rte
->pref
, metric
? metric
->u
.data
: 0);
636 if (tag
&& tag
->u
.data
)
637 bsprintf(buf
, " t%04x", tag
->u
.data
);
641 kill_iface(struct rip_interface
*i
)
643 DBG( "RIP: Interface %s disappeared\n", i
->iface
->name
);
651 * @new: interface to be created or %NULL if we are creating a magic
652 * socket. The magic socket is used for listening and also for
653 * sending requested responses.
654 * @flags: interface flags
655 * @patt: pattern this interface matched, used for access to config options
657 * Create an interface structure and start listening on the interface.
659 static struct rip_interface
*
660 new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
)
662 struct rip_interface
*rif
;
663 struct rip_patt
*PATT
= (struct rip_patt
*) patt
;
665 rif
= mb_allocz(p
->pool
, sizeof( struct rip_interface
));
670 rif
->mode
= PATT
->mode
;
671 rif
->metric
= PATT
->metric
;
672 rif
->multicast
= (!(PATT
->mode
& IM_BROADCAST
)) && (flags
& IF_MULTICAST
);
674 /* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
677 DBG( "Doing multicasts!\n" );
679 rif
->sock
= sk_new( p
->pool
);
680 rif
->sock
->type
= rif
->multicast
?SK_UDP_MC
:SK_UDP
;
681 rif
->sock
->sport
= P_CF
->port
;
682 rif
->sock
->rx_hook
= rip_rx
;
683 rif
->sock
->data
= rif
;
684 rif
->sock
->rbsize
= 10240;
685 rif
->sock
->iface
= new; /* Automagically works for dummy interface */
686 rif
->sock
->tbuf
= mb_alloc( p
->pool
, sizeof( struct rip_packet
));
687 rif
->sock
->tx_hook
= rip_tx
;
688 rif
->sock
->err_hook
= rip_tx_err
;
689 rif
->sock
->daddr
= IPA_NONE
;
690 rif
->sock
->dport
= P_CF
->port
;
694 rif
->sock
->tos
= IP_PREC_INTERNET_CONTROL
;
698 if (new->addr
->flags
& IA_UNNUMBERED
)
699 log( L_WARN
"%s: rip is not defined over unnumbered links", P_NAME
);
700 if (rif
->multicast
) {
702 rif
->sock
->daddr
= ipa_from_u32(0xe0000009);
703 rif
->sock
->saddr
= ipa_from_u32(0xe0000009);
705 rif
->sock
->daddr
= ipa_build(0xff020000, 0, 0, 9);
706 rif
->sock
->saddr
= new->addr
->ip
;
709 rif
->sock
->daddr
= new->addr
->brd
;
710 rif
->sock
->saddr
= new->addr
->brd
;
714 if (!ipa_nonzero(rif
->sock
->daddr
)) {
716 log( L_WARN
"%s: interface %s is too strange for me", P_NAME
, rif
->iface
->name
);
717 } else if (sk_open(rif
->sock
)<0) {
718 log( L_ERR
"%s: could not create socket for %s", P_NAME
, rif
->iface
? rif
->iface
->name
: "(dummy)" );
724 /* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */
727 TRACE(D_EVENTS
, "Listening on %s, port %d, mode %s (%I)", rif
->iface
? rif
->iface
->name
: "(dummy)", P_CF
->port
, rif
->multicast
? "multicast" : "broadcast", rif
->sock
->daddr
);
733 rip_real_if_add(struct object_lock
*lock
)
735 struct iface
*iface
= lock
->iface
;
736 struct proto
*p
= lock
->data
;
737 struct rip_interface
*rif
;
738 struct iface_patt
*k
= iface_patt_match(&P_CF
->iface_list
, iface
);
741 bug("This can not happen! It existed few seconds ago!" );
742 DBG("adding interface %s\n", iface
->name
);
743 rif
= new_iface(p
, iface
, iface
->flags
, k
);
745 add_head( &P
->interfaces
, NODE rif
);
746 DBG("Adding object lock of %p for %p\n", lock
, rif
);
748 } else { rfree(lock
); }
752 rip_if_notify(struct proto
*p
, unsigned c
, struct iface
*iface
)
754 DBG( "RIP: if notify\n" );
755 if (iface
->flags
& IF_IGNORE
)
757 if (c
& IF_CHANGE_DOWN
) {
758 struct rip_interface
*i
;
759 i
= find_interface(p
, iface
);
766 if (c
& IF_CHANGE_UP
) {
767 struct iface_patt
*k
= iface_patt_match(&P_CF
->iface_list
, iface
);
768 struct object_lock
*lock
;
769 struct rip_patt
*PATT
= (struct rip_patt
*) k
;
771 if (!k
) return; /* We are not interested in this interface */
773 lock
= olock_new( p
->pool
);
774 if (!(PATT
->mode
& IM_BROADCAST
) && (iface
->flags
& IF_MULTICAST
))
776 lock
->addr
= ipa_from_u32(0xe0000009);
778 ip_pton("FF02::9", &lock
->addr
);
781 lock
->addr
= iface
->addr
->brd
;
782 lock
->port
= P_CF
->port
;
784 lock
->hook
= rip_real_if_add
;
786 lock
->type
= OBJLOCK_UDP
;
791 static struct ea_list
*
792 rip_gen_attrs(struct linpool
*pool
, int metric
, u16 tag
)
794 struct ea_list
*l
= lp_alloc(pool
, sizeof(struct ea_list
) + 2*sizeof(eattr
));
797 l
->flags
= EALF_SORTED
;
799 l
->attrs
[0].id
= EA_RIP_TAG
;
800 l
->attrs
[0].flags
= 0;
801 l
->attrs
[0].type
= EAF_TYPE_INT
| EAF_TEMP
;
802 l
->attrs
[0].u
.data
= tag
;
803 l
->attrs
[1].id
= EA_RIP_METRIC
;
804 l
->attrs
[1].flags
= 0;
805 l
->attrs
[1].type
= EAF_TYPE_INT
| EAF_TEMP
;
806 l
->attrs
[1].u
.data
= metric
;
811 rip_import_control(struct proto
*p
, struct rte
**rt
, struct ea_list
**attrs
, struct linpool
*pool
)
813 if ((*rt
)->attrs
->proto
== p
) /* My own must not be touched */
816 if ((*rt
)->attrs
->source
!= RTS_RIP
) {
817 struct ea_list
*new = rip_gen_attrs(pool
, 1, 0);
824 static struct ea_list
*
825 rip_make_tmp_attrs(struct rte
*rt
, struct linpool
*pool
)
827 return rip_gen_attrs(pool
, rt
->u
.rip
.metric
, rt
->u
.rip
.tag
);
831 rip_store_tmp_attrs(struct rte
*rt
, struct ea_list
*attrs
)
833 rt
->u
.rip
.tag
= ea_get_int(attrs
, EA_RIP_TAG
, 0);
834 rt
->u
.rip
.metric
= ea_get_int(attrs
, EA_RIP_METRIC
, 1);
838 * rip_rt_notify - core tells us about new route (possibly our
839 * own), so store it into our data structures.
842 rip_rt_notify(struct proto
*p
, struct network
*net
, struct rte
*new, struct rte
*old
, struct ea_list
*attrs
)
847 struct rip_entry
*e
= fib_find( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
849 log( L_BUG
"%s: Deleting nonexistent entry?!", P_NAME
);
850 fib_delete( &P
->rtable
, e
);
856 /* This can happen since feeding of protocols is asynchronous */
857 if (fib_find( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
))
858 log( L_BUG
"%s: Inserting entry which is already there?", P_NAME
);
860 e
= fib_get( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
862 e
->nexthop
= new->attrs
->gw
;
864 e
->whotoldme
= IPA_NONE
;
865 new->u
.rip
.entry
= e
;
867 e
->tag
= ea_get_int(attrs
, EA_RIP_TAG
, 0);
868 e
->metric
= ea_get_int(attrs
, EA_RIP_METRIC
, 1);
869 if (e
->metric
> P_CF
->infinity
)
870 e
->metric
= P_CF
->infinity
;
872 if (new->attrs
->proto
== p
)
873 e
->whotoldme
= new->attrs
->from
;
875 if (!e
->metric
) /* That's okay: this way user can set his own value for external
878 e
->updated
= e
->changed
= now
;
884 rip_rte_better(struct rte
*new, struct rte
*old
)
886 struct proto
*p
= new->attrs
->proto
;
888 if (ipa_equal(old
->attrs
->from
, new->attrs
->from
))
891 if (old
->u
.rip
.metric
< new->u
.rip
.metric
)
894 if (old
->u
.rip
.metric
> new->u
.rip
.metric
)
897 if (old
->attrs
->proto
== new->attrs
->proto
) /* This does not make much sense for different protocols */
898 if ((old
->u
.rip
.metric
== new->u
.rip
.metric
) &&
899 ((now
- old
->lastmod
) > (P_CF
->timeout_time
/ 2)))
906 * rip_rte_insert - we maintain linked list of "our" entries in main
907 * routing table, so that we can timeout them correctly. rip_timer()
911 rip_rte_insert(net
*net UNUSED
, rte
*rte
)
913 struct proto
*p
= rte
->attrs
->proto
;
915 DBG( "rip_rte_insert: %p\n", rte
);
916 add_head( &P
->garbage
, &rte
->u
.rip
.garbage
);
920 * rip_rte_remove - link list maintenance
923 rip_rte_remove(net
*net UNUSED
, rte
*rte
)
925 struct proto
*p
= rte
->attrs
->proto
;
927 DBG( "rip_rte_remove: %p\n", rte
);
928 rem_node( &rte
->u
.rip
.garbage
);
932 rip_init_instance(struct proto
*p
)
934 p
->if_notify
= rip_if_notify
;
935 p
->rt_notify
= rip_rt_notify
;
936 p
->import_control
= rip_import_control
;
937 p
->make_tmp_attrs
= rip_make_tmp_attrs
;
938 p
->store_tmp_attrs
= rip_store_tmp_attrs
;
939 p
->rte_better
= rip_rte_better
;
940 p
->rte_insert
= rip_rte_insert
;
941 p
->rte_remove
= rip_rte_remove
;
945 rip_init_config(struct rip_proto_config
*c
)
947 init_list(&c
->iface_list
);
948 c
->c
.preference
= DEF_PREF_RIP
;
952 c
->garbage_time
= 120+180;
953 c
->timeout_time
= 120;
955 c
->authtype
= AT_NONE
;
959 rip_get_attr(eattr
*a
, byte
*buf
)
962 case EA_RIP_METRIC
: buf
+= bsprintf( buf
, "metric: %d", a
->u
.data
); return GA_FULL
;
963 case EA_RIP_TAG
: buf
+= bsprintf( buf
, "tag: %d", a
->u
.data
); return GA_FULL
;
964 default: return GA_UNKNOWN
;
969 rip_pat_compare(struct rip_patt
*a
, struct rip_patt
*b
)
971 return ((a
->metric
== b
->metric
) &&
972 (a
->mode
== b
->mode
));
976 rip_reconfigure(struct proto
*p
, struct proto_config
*c
)
978 struct rip_proto_config
*new = (struct rip_proto_config
*) c
;
979 int generic
= sizeof(struct proto_config
) + sizeof(list
) /* + sizeof(struct password_item *) */;
981 if (!iface_patts_equal(&P_CF
->iface_list
, &new->iface_list
, (void *) rip_pat_compare
))
983 if (!password_same(P_CF
->passwords
,
986 return !memcmp(((byte
*) P_CF
) + generic
,
987 ((byte
*) new) + generic
,
988 sizeof(struct rip_proto_config
) - generic
);
991 struct protocol proto_rip
= {
995 get_route_info
: rip_get_route_info
,
996 get_attr
: rip_get_attr
,
1001 reconfigure
: rip_reconfigure
,