]>
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>
5 * 2004 Ondrej Filip <feela@network.cz>
7 * Can be freely distributed and used under the terms of the GNU GPL.
9 FIXME: IPv6 support: packet size
10 FIXME: (nonurgent) IPv6 support: receive "route using" blocks
11 FIXME: (nonurgent) IPv6 support: generate "nexthop" blocks
12 next hops are only advisory, and they are pretty ugly in IPv6.
13 I suggest just forgetting about them.
15 FIXME: (nonurgent): fold rip_connection into rip_interface?
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_rt_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.
51 #include "nest/bird.h"
52 #include "nest/iface.h"
53 #include "nest/protocol.h"
54 #include "nest/route.h"
55 #include "lib/socket.h"
56 #include "lib/resource.h"
57 #include "lib/lists.h"
58 #include "lib/timer.h"
59 #include "lib/string.h"
63 #define P ((struct rip_proto *) p)
64 #define P_CF ((struct rip_proto_config *)p->cf)
66 #define TRACE(level, msg, args...) do { if (p->debug & level) { log(L_TRACE "%s: " msg, p->name , ## args); } } while(0)
68 static struct rip_interface
*new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
);
73 * This part is responsible for getting packets out to the network.
77 rip_tx_err( sock
*s
, int err
)
79 struct rip_connection
*c
= ((struct rip_interface
*)(s
->data
))->busy
;
80 struct proto
*p
= c
->proto
;
81 log( L_ERR
"%s: Unexpected error at rip transmit: %M", p
->name
, err
);
86 * @e: rip entry that needs to be translated to form suitable for network
87 * @b: block to be filled
89 * Fill one rip block with info that needs to go to the network. Handle
90 * nexthop and split horizont correctly. (Next hop is ignored for IPv6,
91 * that could be fixed but it is not real problem).
94 rip_tx_prepare(struct proto
*p
, struct rip_block
*b
, struct rip_entry
*e
, struct rip_interface
*rif
, int pos
)
98 b
->tag
= htons( e
->tag
);
99 b
->network
= e
->n
.prefix
;
101 if (neigh_connected_to(p
, &e
->whotoldme
, rif
->iface
)) {
102 DBG( "(split horizon)" );
103 metric
= P_CF
->infinity
;
106 b
->family
= htons( 2 ); /* AF_INET */
107 b
->netmask
= ipa_mkmask( e
->n
.pxlen
);
108 ipa_hton( b
->netmask
);
110 if (neigh_connected_to(p
, &e
->nexthop
, rif
->iface
))
111 b
->nexthop
= e
->nexthop
;
113 b
->nexthop
= IPA_NONE
;
114 ipa_hton( b
->nexthop
);
115 b
->metric
= htonl( metric
);
117 b
->pxlen
= e
->n
.pxlen
;
118 b
->metric
= metric
; /* it is u8 */
121 ipa_hton( b
->network
);
127 * rip_tx - send one rip packet to the network
132 struct rip_interface
*rif
= s
->data
;
133 struct rip_connection
*c
= rif
->busy
;
134 struct proto
*p
= c
->proto
;
135 struct rip_packet
*packet
= (void *) s
->tbuf
;
137 int maxi
, nullupdate
= 1;
139 DBG( "Sending to %I\n", s
->daddr
);
145 DBG( "Preparing packet to send: " );
147 packet
->heading
.command
= RIPCMD_RESPONSE
;
149 packet
->heading
.version
= RIP_V2
;
151 packet
->heading
.version
= RIP_NG
;
153 packet
->heading
.unused
= 0;
155 i
= !!P_CF
->authtype
;
157 maxi
= ((P_CF
->authtype
== AT_MD5
) ? PACKET_MD5_MAX
: PACKET_MAX
);
159 maxi
= 5; /* We need to have at least reserve of one at end of packet */
162 FIB_ITERATE_START(&P
->rtable
, &c
->iter
, z
) {
163 struct rip_entry
*e
= (struct rip_entry
*) z
;
165 if (!rif
->triggered
|| (!(e
->updated
< now
-2))) { /* FIXME: Should be probably 1 or some different algorithm */
167 i
= rip_tx_prepare( p
, packet
->block
+ i
, e
, rif
, i
);
169 FIB_ITERATE_PUT(&c
->iter
, z
);
173 } FIB_ITERATE_END(z
);
178 packetlen
= rip_outgoing_authentication(p
, (void *) &packet
->block
[0], packet
, i
);
180 DBG( ", sending %d blocks, ", i
);
182 DBG( "not sending NULL update\n" );
186 if (ipa_nonzero(c
->daddr
))
187 i
= sk_send_to( s
, packetlen
, c
->daddr
, c
->dport
);
189 i
= sk_send( s
, packetlen
);
191 DBG( "it wants more\n" );
195 if (i
<0) rip_tx_err( s
, i
);
200 DBG( "Looks like I'm" );
209 * rip_sendto - send whole routing table to selected destination
210 * @rif: interface to use. Notice that we lock interface so that at
211 * most one send to one interface is done.
214 rip_sendto( struct proto
*p
, ip_addr daddr
, int dport
, struct rip_interface
*rif
)
216 struct iface
*iface
= rif
->iface
;
217 struct rip_connection
*c
;
221 log (L_WARN
"%s: Interface %s is much too slow, dropping request", p
->name
, iface
->name
);
224 c
= mb_alloc( p
->pool
, sizeof( struct rip_connection
));
234 if (c
->rif
->sock
->data
!= rif
)
235 bug("not enough send magic");
238 FIB_ITERATE_INIT( &c
->iter
, &P
->rtable
);
239 add_head( &P
->connections
, NODE c
);
240 if (ipa_nonzero(daddr
))
241 TRACE(D_PACKETS
, "Sending my routing table to %I:%d on %s", daddr
, dport
, rif
->iface
->name
);
243 TRACE(D_PACKETS
, "Broadcasting routing table to %s", rif
->iface
->name
);
245 rip_tx(c
->rif
->sock
);
248 static struct rip_interface
*
249 find_interface(struct proto
*p
, struct iface
*what
)
251 struct rip_interface
*i
;
253 WALK_LIST (i
, P
->interfaces
)
254 if (i
->iface
== what
)
262 * This part is responsible for any updates that come from network
266 rip_rte_update_if_better(rtable
*tab
, net
*net
, struct proto
*p
, rte
*new)
270 old
= rte_find(net
, p
);
271 if (!old
|| p
->rte_better(new, old
) ||
272 (ipa_equal(old
->attrs
->from
, new->attrs
->from
) &&
273 (old
->u
.rip
.metric
!= new->u
.rip
.metric
)) )
274 rte_update(tab
, net
, p
, p
, new);
280 * advertise_entry - let main routing table know about our new entry
281 * @b: entry in network format
283 * This basically translates @b to format used by bird core and feeds
284 * bird core with this route.
287 advertise_entry( struct proto
*p
, struct rip_block
*b
, ip_addr whotoldme
, struct iface
*iface
)
293 struct rip_interface
*rif
;
296 bzero(&A
, sizeof(A
));
299 A
.scope
= SCOPE_UNIVERSE
;
300 A
.cast
= RTC_UNICAST
;
304 A
.gw
= ipa_nonzero(b
->nexthop
) ? b
->nexthop
: whotoldme
;
305 pxlen
= ipa_mklen(b
->netmask
);
307 /* FIXME: next hop is in other packet for v6 */
313 /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */
315 neighbor
= neigh_find2( p
, &A
.gw
, iface
, 0 );
317 log( L_REMOTE
"%s: %I asked me to route %I/%d using not-neighbor %I.", p
->name
, A
.from
, b
->network
, pxlen
, A
.gw
);
320 if (neighbor
->scope
== SCOPE_HOST
) {
321 DBG("Self-destined route, ignoring.\n");
325 A
.iface
= neighbor
->iface
;
326 if (!(rif
= neighbor
->data
)) {
327 rif
= neighbor
->data
= find_interface(p
, A
.iface
);
330 bug("Route packet using unknown interface? No.");
332 /* set to: interface of nexthop */
335 log( L_REMOTE
"%s: %I gave me invalid pxlen/netmask for %I.", p
->name
, A
.from
, b
->network
);
338 n
= net_get( p
->table
, b
->network
, pxlen
);
341 r
->u
.rip
.metric
= ntohl(b
->metric
) + rif
->metric
;
343 r
->u
.rip
.metric
= b
->metric
+ rif
->metric
;
346 r
->u
.rip
.entry
= NULL
;
347 if (r
->u
.rip
.metric
> P_CF
->infinity
) r
->u
.rip
.metric
= P_CF
->infinity
;
348 r
->u
.rip
.tag
= ntohl(b
->tag
);
350 r
->pflags
= 0; /* Here go my flags */
351 rip_rte_update_if_better( p
->table
, n
, p
, r
);
356 * process_block - do some basic check and pass block to advertise_entry
359 process_block( struct proto
*p
, struct rip_block
*block
, ip_addr whotoldme
, struct iface
*iface
)
364 metric
= ntohl( block
->metric
);
365 pxlen
= ipa_mklen(block
->netmask
);
367 metric
= block
->metric
;
368 pxlen
= block
->pxlen
;
370 ip_addr network
= block
->network
;
374 TRACE(D_ROUTES
, "block: %I tells me: %I/%d available, metric %d... ",
375 whotoldme
, network
, pxlen
, metric
);
377 if ((!metric
) || (metric
> P_CF
->infinity
)) {
378 #ifdef IPV6 /* Someone is sending us nexthop and we are ignoring it */
380 { DBG( "IPv6 nexthop ignored" ); return; }
382 log( L_WARN
"%s: Got metric %d from %I", p
->name
, metric
, whotoldme
);
386 advertise_entry( p
, block
, whotoldme
, iface
);
389 #define BAD( x ) { log( L_REMOTE "%s: " x, p->name ); return 1; }
392 * rip_process_packet - this is main routine for incoming packets.
395 rip_process_packet( struct proto
*p
, struct rip_packet
*packet
, int num
, ip_addr whotoldme
, int port
, struct iface
*iface
)
398 int authenticated
= 0;
401 switch( packet
->heading
.version
) {
402 case RIP_V1
: DBG( "Rip1: " ); break;
403 case RIP_V2
: DBG( "Rip2: " ); break;
404 default: BAD( "Unknown version" );
407 switch( packet
->heading
.command
) {
408 case RIPCMD_REQUEST
: DBG( "Asked to send my routing table\n" );
409 if (P_CF
->honor
== HO_NEVER
)
410 BAD( "They asked me to send routing table, but I was told not to do it" );
412 if ((P_CF
->honor
== HO_NEIGHBOR
) && (!neigh_find2( p
, &whotoldme
, iface
, 0 )))
413 BAD( "They asked me to send routing table, but he is not my neighbor" );
414 rip_sendto( p
, whotoldme
, port
, HEAD(P
->interfaces
) ); /* no broadcast */
416 case RIPCMD_RESPONSE
: DBG( "*** Rtable from %I\n", whotoldme
);
417 if (port
!= P_CF
->port
) {
418 log( L_REMOTE
"%s: %I send me routing info from port %d", p
->name
, whotoldme
, port
);
422 if (!(neighbor
= neigh_find2( p
, &whotoldme
, iface
, 0 )) || neighbor
->scope
== SCOPE_HOST
) {
423 log( L_REMOTE
"%s: %I send me routing info but he is not my neighbor", p
->name
, whotoldme
);
427 for (i
=0; i
<num
; i
++) {
428 struct rip_block
*block
= &packet
->block
[i
];
430 /* Authentication is not defined for v6 */
431 if (block
->family
== 0xffff) {
433 continue; /* md5 tail has this family */
434 if (rip_incoming_authentication(p
, (void *) block
, packet
, num
, whotoldme
))
435 BAD( "Authentication failed" );
440 if ((!authenticated
) && (P_CF
->authtype
!= AT_NONE
))
441 BAD( "Packet is not authenticated and it should be" );
442 ipa_ntoh( block
->network
);
444 ipa_ntoh( block
->netmask
);
445 ipa_ntoh( block
->nexthop
);
446 if (packet
->heading
.version
== RIP_V1
) /* FIXME (nonurgent): switch to disable this? */
447 block
->netmask
= ipa_class_mask(block
->network
);
449 process_block( p
, block
, whotoldme
, iface
);
453 case RIPCMD_TRACEOFF
: BAD( "I was asked for traceon/traceoff" );
454 case 5: BAD( "Some Sun extension around here" );
455 default: BAD( "Unknown command" );
462 * rip_rx - Receive hook: do basic checks and pass packet to rip_process_packet
465 rip_rx(sock
*s
, int size
)
467 struct rip_interface
*i
= s
->data
;
468 struct proto
*p
= i
->proto
;
469 struct iface
*iface
= NULL
;
472 /* In non-listening mode, just ignore packet */
473 if (i
->mode
& IM_NOLISTEN
)
477 if (! i
->iface
|| s
->lifindex
!= i
->iface
->index
)
484 DBG( "RIP: message came: %d bytes from %I via %s\n", size
, s
->faddr
, i
->iface
? i
->iface
->name
: "(dummy)" );
485 size
-= sizeof( struct rip_packet_heading
);
486 if (size
< 0) BAD( "Too small packet" );
487 if (size
% sizeof( struct rip_block
)) BAD( "Odd sized packet" );
488 num
= size
/ sizeof( struct rip_block
);
489 if (num
>PACKET_MAX
) BAD( "Too many blocks" );
491 if (ipa_equal(i
->iface
->addr
->ip
, s
->faddr
)) {
492 DBG("My own packet\n");
496 rip_process_packet( p
, (struct rip_packet
*) s
->rbuf
, num
, s
->faddr
, s
->fport
, iface
);
501 * Interface to BIRD core
505 rip_dump_entry( struct rip_entry
*e
)
507 debug( "%I told me %d/%d ago: to %I/%d go via %I, metric %d ",
508 e
->whotoldme
, e
->updated
-now
, e
->changed
-now
, e
->n
.prefix
, e
->n
.pxlen
, e
->nexthop
, e
->metric
);
516 * Broadcast routing tables periodically (using rip_tx) and kill
517 * routes that are too old. RIP keeps a list of its own entries present
518 * in the core table by a linked list (functions rip_rte_insert() and
519 * rip_rte_delete() are responsible for that), it walks this list in the timer
520 * and in case an entry is too old, it is discarded.
526 struct proto
*p
= t
->data
;
527 struct fib_node
*e
, *et
;
530 DBG( "RIP: tick tock\n" );
532 WALK_LIST_DELSAFE( e
, et
, P
->garbage
) {
534 rte
= SKIP_BACK( struct rte
, u
.rip
.garbage
, e
);
538 DBG( "Garbage: (%p)", rte
); rte_dump( rte
);
540 if (now
- rte
->lastmod
> P_CF
->timeout_time
) {
541 TRACE(D_EVENTS
, "entry is too old: %I", rte
->net
->n
.prefix
);
542 if (rte
->u
.rip
.entry
) {
543 rte
->u
.rip
.entry
->metric
= P_CF
->infinity
;
544 rte
->u
.rip
.metric
= P_CF
->infinity
;
548 if (now
- rte
->lastmod
> P_CF
->garbage_time
) {
549 TRACE(D_EVENTS
, "entry is much too old: %I", rte
->net
->n
.prefix
);
550 rte_discard(p
->table
, rte
);
554 DBG( "RIP: Broadcasting routing tables\n" );
556 struct rip_interface
*rif
;
558 if ( P_CF
->period
> 2 ) { /* Bring some randomness into sending times */
559 if (! (P
->tx_count
% P_CF
->period
)) P
->rnd_count
= random_u32() % 2;
560 } else P
->rnd_count
= P
->tx_count
% P_CF
->period
;
562 WALK_LIST( rif
, P
->interfaces
) {
563 struct iface
*iface
= rif
->iface
;
565 if (!iface
) continue;
566 if (rif
->mode
& IM_QUIET
) continue;
567 if (!(iface
->flags
& IF_UP
)) continue;
568 rif
->triggered
= P
->rnd_count
;
570 rip_sendto( p
, IPA_NONE
, 0, rif
);
576 DBG( "RIP: tick tock done\n" );
580 * rip_start - initialize instance of rip
583 rip_start(struct proto
*p
)
585 struct rip_interface
*rif
;
586 DBG( "RIP: starting instance...\n" );
588 ASSERT(sizeof(struct rip_packet_heading
) == 4);
589 ASSERT(sizeof(struct rip_block
) == 20);
590 ASSERT(sizeof(struct rip_block_auth
) == 20);
593 P
->magic
= RIP_MAGIC
;
595 fib_init( &P
->rtable
, p
->pool
, sizeof( struct rip_entry
), 0, NULL
);
596 init_list( &P
->connections
);
597 init_list( &P
->garbage
);
598 init_list( &P
->interfaces
);
599 P
->timer
= tm_new( p
->pool
);
601 P
->timer
->recurrent
= 1;
602 P
->timer
->hook
= rip_timer
;
603 tm_start( P
->timer
, 2 );
604 rif
= new_iface(p
, NULL
, 0, NULL
); /* Initialize dummy interface */
605 add_head( &P
->interfaces
, NODE rif
);
608 rip_init_instance(p
);
610 DBG( "RIP: ...done\n");
614 static struct proto
*
615 rip_init(struct proto_config
*cfg
)
617 struct proto
*p
= proto_new(cfg
, sizeof(struct rip_proto
));
623 rip_dump(struct proto
*p
)
627 struct rip_interface
*rif
;
630 WALK_LIST( w
, P
->connections
) {
631 struct rip_connection
*n
= (void *) w
;
632 debug( "RIP: connection #%d: %I\n", n
->num
, n
->addr
);
635 FIB_WALK( &P
->rtable
, e
) {
636 debug( "RIP: entry #%d: ", i
++ );
637 rip_dump_entry( (struct rip_entry
*)e
);
640 WALK_LIST( rif
, P
->interfaces
) {
641 debug( "RIP: interface #%d: %s, %I, busy = %x\n", i
++, rif
->iface
?rif
->iface
->name
:"(dummy)", rif
->sock
->daddr
, rif
->busy
);
646 rip_get_route_info(rte
*rte
, byte
*buf
, ea_list
*attrs
)
648 eattr
*metric
= ea_find(attrs
, EA_RIP_METRIC
);
649 eattr
*tag
= ea_find(attrs
, EA_RIP_TAG
);
651 buf
+= bsprintf(buf
, " (%d/%d)", rte
->pref
, metric
? metric
->u
.data
: 0);
652 if (tag
&& tag
->u
.data
)
653 bsprintf(buf
, " t%04x", tag
->u
.data
);
657 kill_iface(struct rip_interface
*i
)
659 DBG( "RIP: Interface %s disappeared\n", i
->iface
->name
);
667 * @new: interface to be created or %NULL if we are creating a magic
668 * socket. The magic socket is used for listening and also for
669 * sending requested responses.
670 * @flags: interface flags
671 * @patt: pattern this interface matched, used for access to config options
673 * Create an interface structure and start listening on the interface.
675 static struct rip_interface
*
676 new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
)
678 struct rip_interface
*rif
;
679 struct rip_patt
*PATT
= (struct rip_patt
*) patt
;
681 rif
= mb_allocz(p
->pool
, sizeof( struct rip_interface
));
686 rif
->mode
= PATT
->mode
;
687 rif
->metric
= PATT
->metric
;
688 rif
->multicast
= (!(PATT
->mode
& IM_BROADCAST
)) && (flags
& IF_MULTICAST
);
690 /* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
693 DBG( "Doing multicasts!\n" );
695 rif
->sock
= sk_new( p
->pool
);
696 rif
->sock
->type
= SK_UDP
;
697 rif
->sock
->sport
= P_CF
->port
;
698 rif
->sock
->rx_hook
= rip_rx
;
699 rif
->sock
->data
= rif
;
700 rif
->sock
->rbsize
= 10240;
701 rif
->sock
->iface
= new; /* Automagically works for dummy interface */
702 rif
->sock
->tbuf
= mb_alloc( p
->pool
, sizeof( struct rip_packet
));
703 rif
->sock
->tx_hook
= rip_tx
;
704 rif
->sock
->err_hook
= rip_tx_err
;
705 rif
->sock
->daddr
= IPA_NONE
;
706 rif
->sock
->dport
= P_CF
->port
;
710 rif
->sock
->tos
= IP_PREC_INTERNET_CONTROL
;
711 rif
->sock
->flags
= SKF_LADDR_RX
;
715 if (new->addr
->flags
& IA_PEER
)
716 log( L_WARN
"%s: rip is not defined over unnumbered links", p
->name
);
717 rif
->sock
->saddr
= IPA_NONE
;
718 if (rif
->multicast
) {
720 rif
->sock
->daddr
= ipa_from_u32(0xe0000009);
722 rif
->sock
->daddr
= ipa_build(0xff020000, 0, 0, 9);
725 rif
->sock
->daddr
= new->addr
->brd
;
729 if (!ipa_nonzero(rif
->sock
->daddr
)) {
731 log( L_WARN
"%s: interface %s is too strange for me", p
->name
, rif
->iface
->name
);
734 if (sk_open(rif
->sock
)<0)
739 if (sk_setup_multicast(rif
->sock
) < 0)
741 if (sk_join_group(rif
->sock
, rif
->sock
->daddr
) < 0)
746 if (sk_set_broadcast(rif
->sock
, 1) < 0)
751 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
);
756 log( L_ERR
"%s: could not create socket for %s", p
->name
, rif
->iface
? rif
->iface
->name
: "(dummy)" );
762 /* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */
767 rip_real_if_add(struct object_lock
*lock
)
769 struct iface
*iface
= lock
->iface
;
770 struct proto
*p
= lock
->data
;
771 struct rip_interface
*rif
;
772 struct iface_patt
*k
= iface_patt_find(&P_CF
->iface_list
, iface
, iface
->addr
);
775 bug("This can not happen! It existed few seconds ago!" );
776 DBG("adding interface %s\n", iface
->name
);
777 rif
= new_iface(p
, iface
, iface
->flags
, k
);
779 add_head( &P
->interfaces
, NODE rif
);
780 DBG("Adding object lock of %p for %p\n", lock
, rif
);
782 } else { rfree(lock
); }
786 rip_if_notify(struct proto
*p
, unsigned c
, struct iface
*iface
)
788 DBG( "RIP: if notify\n" );
789 if (iface
->flags
& IF_IGNORE
)
791 if (c
& IF_CHANGE_DOWN
) {
792 struct rip_interface
*i
;
793 i
= find_interface(p
, iface
);
800 if (c
& IF_CHANGE_UP
) {
801 struct iface_patt
*k
= iface_patt_find(&P_CF
->iface_list
, iface
, iface
->addr
);
802 struct object_lock
*lock
;
803 struct rip_patt
*PATT
= (struct rip_patt
*) k
;
805 if (!k
) return; /* We are not interested in this interface */
807 lock
= olock_new( p
->pool
);
808 if (!(PATT
->mode
& IM_BROADCAST
) && (iface
->flags
& IF_MULTICAST
))
810 lock
->addr
= ipa_from_u32(0xe0000009);
812 ip_pton("FF02::9", &lock
->addr
);
815 lock
->addr
= iface
->addr
->brd
;
816 lock
->port
= P_CF
->port
;
818 lock
->hook
= rip_real_if_add
;
820 lock
->type
= OBJLOCK_UDP
;
825 static struct ea_list
*
826 rip_gen_attrs(struct linpool
*pool
, int metric
, u16 tag
)
828 struct ea_list
*l
= lp_alloc(pool
, sizeof(struct ea_list
) + 2*sizeof(eattr
));
831 l
->flags
= EALF_SORTED
;
833 l
->attrs
[0].id
= EA_RIP_TAG
;
834 l
->attrs
[0].flags
= 0;
835 l
->attrs
[0].type
= EAF_TYPE_INT
| EAF_TEMP
;
836 l
->attrs
[0].u
.data
= tag
;
837 l
->attrs
[1].id
= EA_RIP_METRIC
;
838 l
->attrs
[1].flags
= 0;
839 l
->attrs
[1].type
= EAF_TYPE_INT
| EAF_TEMP
;
840 l
->attrs
[1].u
.data
= metric
;
845 rip_import_control(struct proto
*p
, struct rte
**rt
, struct ea_list
**attrs
, struct linpool
*pool
)
847 if ((*rt
)->attrs
->proto
== p
) /* My own must not be touched */
850 if ((*rt
)->attrs
->source
!= RTS_RIP
) {
851 struct ea_list
*new = rip_gen_attrs(pool
, 1, 0);
858 static struct ea_list
*
859 rip_make_tmp_attrs(struct rte
*rt
, struct linpool
*pool
)
861 return rip_gen_attrs(pool
, rt
->u
.rip
.metric
, rt
->u
.rip
.tag
);
865 rip_store_tmp_attrs(struct rte
*rt
, struct ea_list
*attrs
)
867 rt
->u
.rip
.tag
= ea_get_int(attrs
, EA_RIP_TAG
, 0);
868 rt
->u
.rip
.metric
= ea_get_int(attrs
, EA_RIP_METRIC
, 1);
872 * rip_rt_notify - core tells us about new route (possibly our
873 * own), so store it into our data structures.
876 rip_rt_notify(struct proto
*p
, struct rtable
*table UNUSED
, struct network
*net
,
877 struct rte
*new, struct rte
*old UNUSED
, struct ea_list
*attrs
)
882 e
= fib_find( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
884 fib_delete( &P
->rtable
, e
);
887 e
= fib_get( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
889 e
->nexthop
= new->attrs
->gw
;
891 e
->whotoldme
= IPA_NONE
;
892 new->u
.rip
.entry
= e
;
894 e
->tag
= ea_get_int(attrs
, EA_RIP_TAG
, 0);
895 e
->metric
= ea_get_int(attrs
, EA_RIP_METRIC
, 1);
896 if (e
->metric
> P_CF
->infinity
)
897 e
->metric
= P_CF
->infinity
;
899 if (new->attrs
->proto
== p
)
900 e
->whotoldme
= new->attrs
->from
;
902 if (!e
->metric
) /* That's okay: this way user can set his own value for external
905 e
->updated
= e
->changed
= now
;
911 rip_rte_same(struct rte
*new, struct rte
*old
)
913 /* new->attrs == old->attrs always */
914 return new->u
.rip
.metric
== old
->u
.rip
.metric
;
919 rip_rte_better(struct rte
*new, struct rte
*old
)
921 struct proto
*p
= new->attrs
->proto
;
923 if (ipa_equal(old
->attrs
->from
, new->attrs
->from
))
926 if (old
->u
.rip
.metric
< new->u
.rip
.metric
)
929 if (old
->u
.rip
.metric
> new->u
.rip
.metric
)
932 if (old
->attrs
->proto
== new->attrs
->proto
) /* This does not make much sense for different protocols */
933 if ((old
->u
.rip
.metric
== new->u
.rip
.metric
) &&
934 ((now
- old
->lastmod
) > (P_CF
->timeout_time
/ 2)))
941 * rip_rte_insert - we maintain linked list of "our" entries in main
942 * routing table, so that we can timeout them correctly. rip_timer()
946 rip_rte_insert(net
*net UNUSED
, rte
*rte
)
948 struct proto
*p
= rte
->attrs
->proto
;
950 DBG( "rip_rte_insert: %p\n", rte
);
951 add_head( &P
->garbage
, &rte
->u
.rip
.garbage
);
955 * rip_rte_remove - link list maintenance
958 rip_rte_remove(net
*net UNUSED
, rte
*rte
)
961 struct proto
*p
= rte
->attrs
->proto
;
963 DBG( "rip_rte_remove: %p\n", rte
);
965 rem_node( &rte
->u
.rip
.garbage
);
969 rip_init_instance(struct proto
*p
)
971 p
->accept_ra_types
= RA_OPTIMAL
;
972 p
->if_notify
= rip_if_notify
;
973 p
->rt_notify
= rip_rt_notify
;
974 p
->import_control
= rip_import_control
;
975 p
->make_tmp_attrs
= rip_make_tmp_attrs
;
976 p
->store_tmp_attrs
= rip_store_tmp_attrs
;
977 p
->rte_better
= rip_rte_better
;
978 p
->rte_same
= rip_rte_same
;
979 p
->rte_insert
= rip_rte_insert
;
980 p
->rte_remove
= rip_rte_remove
;
984 rip_init_config(struct rip_proto_config
*c
)
986 init_list(&c
->iface_list
);
990 c
->garbage_time
= 120+180;
991 c
->timeout_time
= 120;
993 c
->authtype
= AT_NONE
;
997 rip_get_attr(eattr
*a
, byte
*buf
, int buflen UNUSED
)
1000 case EA_RIP_METRIC
: bsprintf( buf
, "metric: %d", a
->u
.data
); return GA_FULL
;
1001 case EA_RIP_TAG
: bsprintf( buf
, "tag: %d", a
->u
.data
); return GA_FULL
;
1002 default: return GA_UNKNOWN
;
1007 rip_pat_compare(struct rip_patt
*a
, struct rip_patt
*b
)
1009 return ((a
->metric
== b
->metric
) &&
1010 (a
->mode
== b
->mode
));
1014 rip_reconfigure(struct proto
*p
, struct proto_config
*c
)
1016 struct rip_proto_config
*new = (struct rip_proto_config
*) c
;
1017 int generic
= sizeof(struct proto_config
) + sizeof(list
) /* + sizeof(struct password_item *) */;
1019 if (!iface_patts_equal(&P_CF
->iface_list
, &new->iface_list
, (void *) rip_pat_compare
))
1021 return !memcmp(((byte
*) P_CF
) + generic
,
1022 ((byte
*) new) + generic
,
1023 sizeof(struct rip_proto_config
) - generic
);
1027 rip_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
1029 /* Shallow copy of everything */
1030 proto_copy_rest(dest
, src
, sizeof(struct rip_proto_config
));
1032 /* We clean up iface_list, ifaces are non-sharable */
1033 init_list(&((struct rip_proto_config
*) dest
)->iface_list
);
1035 /* Copy of passwords is OK, it just will be replaced in dest when used */
1039 struct protocol proto_rip
= {
1042 attr_class
: EAP_RIP
,
1043 preference
: DEF_PREF_RIP
,
1044 get_route_info
: rip_get_route_info
,
1045 get_attr
: rip_get_attr
,
1050 reconfigure
: rip_reconfigure
,
1051 copy_config
: rip_copy_config