]>
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: (nonurgent) allow bigger frequencies than 1 regular update in 6 seconds (?)
18 FIXME: propagation of metric=infinity into main routing table may or may not be good idea.
22 * DOC: Routing Information Protocol
24 * RIP is a pretty simple protocol, so about a half of its code is interface
27 * We maintain our own linked list of &rip_entry structures -- it serves
28 * as our small routing table. RIP never adds to this linked list upon
29 * packet reception; instead, it lets the core know about data from the packet
30 * and waits for the core to call rip_rt_notify().
32 * Within rip_tx(), the list is
33 * walked and a packet is generated using rip_tx_prepare(). This gets
34 * tricky because we may need to send more than one packet to one
35 * destination. Struct &rip_connection is used to hold context information such as how
36 * many of &rip_entry's we have already sent and it's also used to protect
37 * against two concurrent sends to one destination. Each &rip_interface has
38 * at most one &rip_connection.
40 * We are not going to honor requests for sending part of
41 * routing table. That would need to turn split horizon off etc.
43 * About triggered updates, RFC says: when a triggered update was sent,
44 * don't send a new one for something between 1 and 5 seconds (and send one
45 * after that). We do something else: each 5 seconds,
46 * 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"
64 #define P ((struct rip_proto *) p)
65 #define P_CF ((struct rip_proto_config *)p->cf)
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
);
74 * This part is responsible for getting packets out to the network.
78 rip_tx_err( sock
*s
, int err
)
80 struct rip_connection
*c
= ((struct rip_interface
*)(s
->data
))->busy
;
81 struct proto
*p
= c
->proto
;
82 log( L_ERR
"%s: Unexpected error at rip transmit: %M", p
->name
, err
);
87 * @e: rip entry that needs to be translated to form suitable for network
88 * @b: block to be filled
90 * Fill one rip block with info that needs to go to the network. Handle
91 * nexthop and split horizont correctly. (Next hop is ignored for IPv6,
92 * that could be fixed but it is not real problem).
95 rip_tx_prepare(struct proto
*p
, struct rip_block
*b
, struct rip_entry
*e
, struct rip_interface
*rif
, int pos
)
99 b
->tag
= htons( e
->tag
);
100 b
->network
= e
->n
.prefix
;
102 if (neigh_connected_to(p
, &e
->whotoldme
, rif
->iface
)) {
103 DBG( "(split horizon)" );
104 metric
= P_CF
->infinity
;
107 b
->family
= htons( 2 ); /* AF_INET */
108 b
->netmask
= ipa_mkmask( e
->n
.pxlen
);
109 ipa_hton( b
->netmask
);
111 if (neigh_connected_to(p
, &e
->nexthop
, rif
->iface
))
112 b
->nexthop
= e
->nexthop
;
114 b
->nexthop
= IPA_NONE
;
115 ipa_hton( b
->nexthop
);
116 b
->metric
= htonl( metric
);
118 b
->pxlen
= e
->n
.pxlen
;
119 b
->metric
= metric
; /* it is u8 */
122 ipa_hton( b
->network
);
128 * rip_tx - send one rip packet to the network
133 struct rip_interface
*rif
= s
->data
;
134 struct rip_connection
*c
= rif
->busy
;
135 struct proto
*p
= c
->proto
;
136 struct rip_packet
*packet
= (void *) s
->tbuf
;
138 int maxi
, nullupdate
= 1;
140 DBG( "Sending to %I\n", s
->daddr
);
146 DBG( "Preparing packet to send: " );
148 packet
->heading
.command
= RIPCMD_RESPONSE
;
150 packet
->heading
.version
= RIP_V2
;
152 packet
->heading
.version
= RIP_NG
;
154 packet
->heading
.unused
= 0;
156 i
= !!P_CF
->authtype
;
158 maxi
= ((P_CF
->authtype
== AT_MD5
) ? PACKET_MD5_MAX
: PACKET_MAX
);
160 maxi
= 5; /* We need to have at least reserve of one at end of packet */
163 FIB_ITERATE_START(&P
->rtable
, &c
->iter
, z
) {
164 struct rip_entry
*e
= (struct rip_entry
*) z
;
166 if (!rif
->triggered
|| (!(e
->updated
< now
-5))) {
168 i
= rip_tx_prepare( p
, packet
->block
+ i
, e
, rif
, i
);
170 FIB_ITERATE_PUT(&c
->iter
, z
);
174 } FIB_ITERATE_END(z
);
179 packetlen
= rip_outgoing_authentication(p
, (void *) &packet
->block
[0], packet
, i
);
181 DBG( ", sending %d blocks, ", i
);
183 DBG( "not sending NULL update\n" );
187 if (ipa_nonzero(c
->daddr
))
188 i
= sk_send_to( s
, packetlen
, c
->daddr
, c
->dport
);
190 i
= sk_send( s
, packetlen
);
192 DBG( "it wants more\n" );
196 if (i
<0) rip_tx_err( s
, i
);
201 DBG( "Looks like I'm" );
210 * rip_sendto - send whole routing table to selected destination
211 * @rif: interface to use. Notice that we lock interface so that at
212 * most one send to one interface is done.
215 rip_sendto( struct proto
*p
, ip_addr daddr
, int dport
, struct rip_interface
*rif
)
217 struct iface
*iface
= rif
->iface
;
218 struct rip_connection
*c
;
222 log (L_WARN
"%s: Interface %s is much too slow, dropping request", p
->name
, iface
->name
);
225 c
= mb_alloc( p
->pool
, sizeof( struct rip_connection
));
235 if (c
->rif
->sock
->data
!= rif
)
236 bug("not enough send magic");
239 FIB_ITERATE_INIT( &c
->iter
, &P
->rtable
);
240 add_head( &P
->connections
, NODE c
);
241 if (ipa_nonzero(daddr
))
242 TRACE(D_PACKETS
, "Sending my routing table to %I:%d on %s", daddr
, dport
, rif
->iface
->name
);
244 TRACE(D_PACKETS
, "Broadcasting routing table to %s", rif
->iface
->name
);
246 rip_tx(c
->rif
->sock
);
249 static struct rip_interface
*
250 find_interface(struct proto
*p
, struct iface
*what
)
252 struct rip_interface
*i
;
254 WALK_LIST (i
, P
->interfaces
)
255 if (i
->iface
== what
)
263 * This part is responsible for any updates that come from network
267 rip_rte_update_if_better(rtable
*tab
, net
*net
, struct proto
*p
, rte
*new)
271 old
= rte_find(net
, p
);
272 if (!old
|| p
->rte_better(new, old
) ||
273 (ipa_equal(old
->attrs
->from
, new->attrs
->from
) &&
274 (old
->u
.rip
.metric
!= new->u
.rip
.metric
)) )
275 rte_update(tab
, net
, p
, p
, new);
281 * advertise_entry - let main routing table know about our new entry
282 * @b: entry in network format
284 * This basically translates @b to format used by bird core and feeds
285 * bird core with this route.
288 advertise_entry( struct proto
*p
, struct rip_block
*b
, ip_addr whotoldme
, struct iface
*iface
)
294 struct rip_interface
*rif
;
297 bzero(&A
, sizeof(A
));
300 A
.scope
= SCOPE_UNIVERSE
;
301 A
.cast
= RTC_UNICAST
;
305 A
.gw
= ipa_nonzero(b
->nexthop
) ? b
->nexthop
: whotoldme
;
306 pxlen
= ipa_mklen(b
->netmask
);
308 /* FIXME: next hop is in other packet for v6 */
314 /* No need to look if destination looks valid - ie not net 0 or 127 -- core will do for us. */
316 neighbor
= neigh_find2( p
, &A
.gw
, iface
, 0 );
318 log( L_REMOTE
"%s: %I asked me to route %I/%d using not-neighbor %I.", p
->name
, A
.from
, b
->network
, pxlen
, A
.gw
);
321 if (neighbor
->scope
== SCOPE_HOST
) {
322 DBG("Self-destined route, ignoring.\n");
326 A
.iface
= neighbor
->iface
;
327 if (!(rif
= neighbor
->data
)) {
328 rif
= neighbor
->data
= find_interface(p
, A
.iface
);
331 bug("Route packet using unknown interface? No.");
333 /* set to: interface of nexthop */
336 log( L_REMOTE
"%s: %I gave me invalid pxlen/netmask for %I.", p
->name
, A
.from
, b
->network
);
339 n
= net_get( p
->table
, b
->network
, pxlen
);
342 r
->u
.rip
.metric
= ntohl(b
->metric
) + rif
->metric
;
344 r
->u
.rip
.metric
= b
->metric
+ rif
->metric
;
347 r
->u
.rip
.entry
= NULL
;
348 if (r
->u
.rip
.metric
> P_CF
->infinity
) r
->u
.rip
.metric
= P_CF
->infinity
;
349 r
->u
.rip
.tag
= ntohl(b
->tag
);
351 r
->pflags
= 0; /* Here go my flags */
352 rip_rte_update_if_better( p
->table
, n
, p
, r
);
357 * process_block - do some basic check and pass block to advertise_entry
360 process_block( struct proto
*p
, struct rip_block
*block
, ip_addr whotoldme
, struct iface
*iface
)
363 int metric
= ntohl( block
->metric
);
365 int metric
= block
->metric
;
367 ip_addr network
= block
->network
;
371 TRACE(D_ROUTES
, "block: %I tells me: %I/%d available, metric %d... ",
372 whotoldme
, network
, block
->pxlen
, metric
);
374 TRACE(D_ROUTES
, "block: %I tells me: %I/%d available, metric %d... ",
375 whotoldme
, network
, ipa_mklen(block
->netmask
), metric
);
378 if ((!metric
) || (metric
> P_CF
->infinity
)) {
379 #ifdef IPV6 /* Someone is sedning us nexthop and we are ignoring it */
381 { DBG( "IpV6 nexthop ignored" ); return; }
383 log( L_WARN
"%s: Got metric %d from %I", p
->name
, metric
, whotoldme
);
387 advertise_entry( p
, block
, whotoldme
, iface
);
390 #define BAD( x ) { log( L_REMOTE "%s: " x, p->name ); return 1; }
393 * rip_process_packet - this is main routine for incoming packets.
396 rip_process_packet( struct proto
*p
, struct rip_packet
*packet
, int num
, ip_addr whotoldme
, int port
, struct iface
*iface
)
399 int authenticated
= 0;
402 switch( packet
->heading
.version
) {
403 case RIP_V1
: DBG( "Rip1: " ); break;
404 case RIP_V2
: DBG( "Rip2: " ); break;
405 default: BAD( "Unknown version" );
408 switch( packet
->heading
.command
) {
409 case RIPCMD_REQUEST
: DBG( "Asked to send my routing table\n" );
410 if (P_CF
->honor
== HO_NEVER
)
411 BAD( "They asked me to send routing table, but I was told not to do it" );
413 if ((P_CF
->honor
== HO_NEIGHBOR
) && (!neigh_find2( p
, &whotoldme
, iface
, 0 )))
414 BAD( "They asked me to send routing table, but he is not my neighbor" );
415 rip_sendto( p
, whotoldme
, port
, HEAD(P
->interfaces
) ); /* no broadcast */
417 case RIPCMD_RESPONSE
: DBG( "*** Rtable from %I\n", whotoldme
);
418 if (port
!= P_CF
->port
) {
419 log( L_REMOTE
"%s: %I send me routing info from port %d", p
->name
, whotoldme
, port
);
423 if (!(neighbor
= neigh_find2( p
, &whotoldme
, iface
, 0 )) || neighbor
->scope
== SCOPE_HOST
) {
424 log( L_REMOTE
"%s: %I send me routing info but he is not my neighbor", p
->name
, whotoldme
);
428 for (i
=0; i
<num
; i
++) {
429 struct rip_block
*block
= &packet
->block
[i
];
431 /* Authentication is not defined for v6 */
432 if (block
->family
== 0xffff) {
434 continue; /* md5 tail has this family */
435 if (rip_incoming_authentication(p
, (void *) block
, packet
, num
, whotoldme
))
436 BAD( "Authentication failed" );
441 if ((!authenticated
) && (P_CF
->authtype
!= AT_NONE
))
442 BAD( "Packet is not authenticated and it should be" );
443 ipa_ntoh( block
->network
);
445 ipa_ntoh( block
->netmask
);
446 ipa_ntoh( block
->nexthop
);
447 if (packet
->heading
.version
== RIP_V1
) /* FIXME (nonurgent): switch to disable this? */
448 block
->netmask
= ipa_class_mask(block
->network
);
450 process_block( p
, block
, whotoldme
, iface
);
454 case RIPCMD_TRACEOFF
: BAD( "I was asked for traceon/traceoff" );
455 case 5: BAD( "Some Sun extension around here" );
456 default: BAD( "Unknown command" );
463 * rip_rx - Receive hook: do basic checks and pass packet to rip_process_packet
466 rip_rx(sock
*s
, int size
)
468 struct rip_interface
*i
= s
->data
;
469 struct proto
*p
= i
->proto
;
470 struct iface
*iface
= NULL
;
473 /* In non-listening mode, just ignore packet */
474 if (i
->mode
& IM_NOLISTEN
)
478 if (! i
->iface
|| s
->lifindex
!= i
->iface
->index
)
485 DBG( "RIP: message came: %d bytes from %I via %s\n", size
, s
->faddr
, i
->iface
? i
->iface
->name
: "(dummy)" );
486 size
-= sizeof( struct rip_packet_heading
);
487 if (size
< 0) BAD( "Too small packet" );
488 if (size
% sizeof( struct rip_block
)) BAD( "Odd sized packet" );
489 num
= size
/ sizeof( struct rip_block
);
490 if (num
>PACKET_MAX
) BAD( "Too many blocks" );
492 if (ipa_equal(i
->iface
->addr
->ip
, s
->faddr
)) {
493 DBG("My own packet\n");
497 rip_process_packet( p
, (struct rip_packet
*) s
->rbuf
, num
, s
->faddr
, s
->fport
, iface
);
502 * Interface to BIRD core
506 rip_dump_entry( struct rip_entry
*e
)
508 debug( "%I told me %d/%d ago: to %I/%d go via %I, metric %d ",
509 e
->whotoldme
, e
->updated
-now
, e
->changed
-now
, e
->n
.prefix
, e
->n
.pxlen
, e
->nexthop
, e
->metric
);
517 * Broadcast routing tables periodically (using rip_tx) and kill
518 * routes that are too old. RIP keeps a list of its own entries present
519 * in the core table by a linked list (functions rip_rte_insert() and
520 * rip_rte_delete() are responsible for that), it walks this list in the timer
521 * and in case an entry is too old, it is discarded.
527 struct proto
*p
= t
->data
;
528 struct fib_node
*e
, *et
;
531 DBG( "RIP: tick tock\n" );
533 WALK_LIST_DELSAFE( e
, et
, P
->garbage
) {
535 rte
= SKIP_BACK( struct rte
, u
.rip
.garbage
, e
);
538 struct proto
*p
= rte
->attrs
->proto
;
541 DBG( "Garbage: (%p)", rte
); rte_dump( rte
);
544 if (now
- rte
->lastmod
> P_CF
->timeout_time
) {
545 TRACE(D_EVENTS
, "entry is too old: %I", rte
->net
->n
.prefix
);
546 if (rte
->u
.rip
.entry
) {
547 rte
->u
.rip
.entry
->metric
= P_CF
->infinity
;
548 rte
->u
.rip
.metric
= P_CF
->infinity
;
552 if (now
- rte
->lastmod
> P_CF
->garbage_time
) {
553 TRACE(D_EVENTS
, "entry is much too old: %I", rte
->net
->n
.prefix
);
554 rte_discard(p
->table
, rte
);
558 DBG( "RIP: Broadcasting routing tables\n" );
560 struct rip_interface
*rif
;
561 WALK_LIST( rif
, P
->interfaces
) {
562 struct iface
*iface
= rif
->iface
;
564 if (!iface
) continue;
565 if (rif
->mode
& IM_QUIET
) continue;
566 if (!(iface
->flags
& IF_UP
)) continue;
568 rif
->triggered
= (P
->tx_count
% 6);
569 rip_sendto( p
, IPA_NONE
, 0, rif
);
574 DBG( "RIP: tick tock done\n" );
578 * rip_start - initialize instance of rip
581 rip_start(struct proto
*p
)
583 struct rip_interface
*rif
;
584 DBG( "RIP: starting instance...\n" );
586 assert( sizeof(struct rip_packet_heading
) == 4);
587 assert( sizeof(struct rip_block
) == 20);
588 assert( sizeof(struct rip_block_auth
) == 20);
591 P
->magic
= RIP_MAGIC
;
593 fib_init( &P
->rtable
, p
->pool
, sizeof( struct rip_entry
), 0, NULL
);
594 init_list( &P
->connections
);
595 init_list( &P
->garbage
);
596 init_list( &P
->interfaces
);
597 P
->timer
= tm_new( p
->pool
);
599 P
->timer
->randomize
= 5;
600 P
->timer
->recurrent
= (P_CF
->period
/ 6)+1;
601 P
->timer
->hook
= rip_timer
;
602 tm_start( P
->timer
, 5 );
603 rif
= new_iface(p
, NULL
, 0, NULL
); /* Initialize dummy interface */
604 add_head( &P
->interfaces
, NODE rif
);
607 rip_init_instance(p
);
609 DBG( "RIP: ...done\n");
613 static struct proto
*
614 rip_init(struct proto_config
*cfg
)
616 struct proto
*p
= proto_new(cfg
, sizeof(struct rip_proto
));
622 rip_dump(struct proto
*p
)
626 struct rip_interface
*rif
;
629 WALK_LIST( w
, P
->connections
) {
630 struct rip_connection
*n
= (void *) w
;
631 debug( "RIP: connection #%d: %I\n", n
->num
, n
->addr
);
634 FIB_WALK( &P
->rtable
, e
) {
635 debug( "RIP: entry #%d: ", i
++ );
636 rip_dump_entry( (struct rip_entry
*)e
);
639 WALK_LIST( rif
, P
->interfaces
) {
640 debug( "RIP: interface #%d: %s, %I, busy = %x\n", i
++, rif
->iface
?rif
->iface
->name
:"(dummy)", rif
->sock
->daddr
, rif
->busy
);
645 rip_get_route_info(rte
*rte
, byte
*buf
, ea_list
*attrs
)
647 eattr
*metric
= ea_find(attrs
, EA_RIP_METRIC
);
648 eattr
*tag
= ea_find(attrs
, EA_RIP_TAG
);
650 buf
+= bsprintf(buf
, " (%d/%d)", rte
->pref
, metric
? metric
->u
.data
: 0);
651 if (tag
&& tag
->u
.data
)
652 bsprintf(buf
, " t%04x", tag
->u
.data
);
656 kill_iface(struct rip_interface
*i
)
658 DBG( "RIP: Interface %s disappeared\n", i
->iface
->name
);
666 * @new: interface to be created or %NULL if we are creating a magic
667 * socket. The magic socket is used for listening and also for
668 * sending requested responses.
669 * @flags: interface flags
670 * @patt: pattern this interface matched, used for access to config options
672 * Create an interface structure and start listening on the interface.
674 static struct rip_interface
*
675 new_iface(struct proto
*p
, struct iface
*new, unsigned long flags
, struct iface_patt
*patt
)
677 struct rip_interface
*rif
;
678 struct rip_patt
*PATT
= (struct rip_patt
*) patt
;
680 rif
= mb_allocz(p
->pool
, sizeof( struct rip_interface
));
685 rif
->mode
= PATT
->mode
;
686 rif
->metric
= PATT
->metric
;
687 rif
->multicast
= (!(PATT
->mode
& IM_BROADCAST
)) && (flags
& IF_MULTICAST
);
689 /* lookup multicasts over unnumbered links - no: rip is not defined over unnumbered links */
692 DBG( "Doing multicasts!\n" );
694 rif
->sock
= sk_new( p
->pool
);
695 rif
->sock
->type
= SK_UDP
;
696 rif
->sock
->sport
= P_CF
->port
;
697 rif
->sock
->rx_hook
= rip_rx
;
698 rif
->sock
->data
= rif
;
699 rif
->sock
->rbsize
= 10240;
700 rif
->sock
->iface
= new; /* Automagically works for dummy interface */
701 rif
->sock
->tbuf
= mb_alloc( p
->pool
, sizeof( struct rip_packet
));
702 rif
->sock
->tx_hook
= rip_tx
;
703 rif
->sock
->err_hook
= rip_tx_err
;
704 rif
->sock
->daddr
= IPA_NONE
;
705 rif
->sock
->dport
= P_CF
->port
;
709 rif
->sock
->tos
= IP_PREC_INTERNET_CONTROL
;
710 rif
->sock
->flags
= SKF_LADDR_RX
;
714 if (new->addr
->flags
& IA_PEER
)
715 log( L_WARN
"%s: rip is not defined over unnumbered links", p
->name
);
716 rif
->sock
->saddr
= IPA_NONE
;
717 if (rif
->multicast
) {
719 rif
->sock
->daddr
= ipa_from_u32(0xe0000009);
721 rif
->sock
->daddr
= ipa_build(0xff020000, 0, 0, 9);
724 rif
->sock
->daddr
= new->addr
->brd
;
728 if (!ipa_nonzero(rif
->sock
->daddr
)) {
730 log( L_WARN
"%s: interface %s is too strange for me", p
->name
, rif
->iface
->name
);
733 if (sk_open(rif
->sock
)<0)
738 if (sk_setup_multicast(rif
->sock
) < 0)
740 if (sk_join_group(rif
->sock
, rif
->sock
->daddr
) < 0)
745 if (sk_set_broadcast(rif
->sock
, 1) < 0)
750 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
);
755 log( L_ERR
"%s: could not create socket for %s", p
->name
, rif
->iface
? rif
->iface
->name
: "(dummy)" );
761 /* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */
766 rip_real_if_add(struct object_lock
*lock
)
768 struct iface
*iface
= lock
->iface
;
769 struct proto
*p
= lock
->data
;
770 struct rip_interface
*rif
;
771 struct iface_patt
*k
= iface_patt_find(&P_CF
->iface_list
, iface
, iface
->addr
);
774 bug("This can not happen! It existed few seconds ago!" );
775 DBG("adding interface %s\n", iface
->name
);
776 rif
= new_iface(p
, iface
, iface
->flags
, k
);
778 add_head( &P
->interfaces
, NODE rif
);
779 DBG("Adding object lock of %p for %p\n", lock
, rif
);
781 } else { rfree(lock
); }
785 rip_if_notify(struct proto
*p
, unsigned c
, struct iface
*iface
)
787 DBG( "RIP: if notify\n" );
788 if (iface
->flags
& IF_IGNORE
)
790 if (c
& IF_CHANGE_DOWN
) {
791 struct rip_interface
*i
;
792 i
= find_interface(p
, iface
);
799 if (c
& IF_CHANGE_UP
) {
800 struct iface_patt
*k
= iface_patt_find(&P_CF
->iface_list
, iface
, iface
->addr
);
801 struct object_lock
*lock
;
802 struct rip_patt
*PATT
= (struct rip_patt
*) k
;
804 if (!k
) return; /* We are not interested in this interface */
806 lock
= olock_new( p
->pool
);
807 if (!(PATT
->mode
& IM_BROADCAST
) && (iface
->flags
& IF_MULTICAST
))
809 lock
->addr
= ipa_from_u32(0xe0000009);
811 ip_pton("FF02::9", &lock
->addr
);
814 lock
->addr
= iface
->addr
->brd
;
815 lock
->port
= P_CF
->port
;
817 lock
->hook
= rip_real_if_add
;
819 lock
->type
= OBJLOCK_UDP
;
824 static struct ea_list
*
825 rip_gen_attrs(struct linpool
*pool
, int metric
, u16 tag
)
827 struct ea_list
*l
= lp_alloc(pool
, sizeof(struct ea_list
) + 2*sizeof(eattr
));
830 l
->flags
= EALF_SORTED
;
832 l
->attrs
[0].id
= EA_RIP_TAG
;
833 l
->attrs
[0].flags
= 0;
834 l
->attrs
[0].type
= EAF_TYPE_INT
| EAF_TEMP
;
835 l
->attrs
[0].u
.data
= tag
;
836 l
->attrs
[1].id
= EA_RIP_METRIC
;
837 l
->attrs
[1].flags
= 0;
838 l
->attrs
[1].type
= EAF_TYPE_INT
| EAF_TEMP
;
839 l
->attrs
[1].u
.data
= metric
;
844 rip_import_control(struct proto
*p
, struct rte
**rt
, struct ea_list
**attrs
, struct linpool
*pool
)
846 if ((*rt
)->attrs
->proto
== p
) /* My own must not be touched */
849 if ((*rt
)->attrs
->source
!= RTS_RIP
) {
850 struct ea_list
*new = rip_gen_attrs(pool
, 1, 0);
857 static struct ea_list
*
858 rip_make_tmp_attrs(struct rte
*rt
, struct linpool
*pool
)
860 return rip_gen_attrs(pool
, rt
->u
.rip
.metric
, rt
->u
.rip
.tag
);
864 rip_store_tmp_attrs(struct rte
*rt
, struct ea_list
*attrs
)
866 rt
->u
.rip
.tag
= ea_get_int(attrs
, EA_RIP_TAG
, 0);
867 rt
->u
.rip
.metric
= ea_get_int(attrs
, EA_RIP_METRIC
, 1);
871 * rip_rt_notify - core tells us about new route (possibly our
872 * own), so store it into our data structures.
875 rip_rt_notify(struct proto
*p
, struct rtable
*table UNUSED
, struct network
*net
,
876 struct rte
*new, struct rte
*old UNUSED
, struct ea_list
*attrs
)
881 e
= fib_find( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
883 fib_delete( &P
->rtable
, e
);
886 e
= fib_get( &P
->rtable
, &net
->n
.prefix
, net
->n
.pxlen
);
888 e
->nexthop
= new->attrs
->gw
;
890 e
->whotoldme
= IPA_NONE
;
891 new->u
.rip
.entry
= e
;
893 e
->tag
= ea_get_int(attrs
, EA_RIP_TAG
, 0);
894 e
->metric
= ea_get_int(attrs
, EA_RIP_METRIC
, 1);
895 if (e
->metric
> P_CF
->infinity
)
896 e
->metric
= P_CF
->infinity
;
898 if (new->attrs
->proto
== p
)
899 e
->whotoldme
= new->attrs
->from
;
901 if (!e
->metric
) /* That's okay: this way user can set his own value for external
904 e
->updated
= e
->changed
= now
;
910 rip_rte_same(struct rte
*new, struct rte
*old
)
912 /* new->attrs == old->attrs always */
913 return new->u
.rip
.metric
== old
->u
.rip
.metric
;
918 rip_rte_better(struct rte
*new, struct rte
*old
)
920 struct proto
*p
= new->attrs
->proto
;
922 if (ipa_equal(old
->attrs
->from
, new->attrs
->from
))
925 if (old
->u
.rip
.metric
< new->u
.rip
.metric
)
928 if (old
->u
.rip
.metric
> new->u
.rip
.metric
)
931 if (old
->attrs
->proto
== new->attrs
->proto
) /* This does not make much sense for different protocols */
932 if ((old
->u
.rip
.metric
== new->u
.rip
.metric
) &&
933 ((now
- old
->lastmod
) > (P_CF
->timeout_time
/ 2)))
940 * rip_rte_insert - we maintain linked list of "our" entries in main
941 * routing table, so that we can timeout them correctly. rip_timer()
945 rip_rte_insert(net
*net UNUSED
, rte
*rte
)
947 struct proto
*p
= rte
->attrs
->proto
;
949 DBG( "rip_rte_insert: %p\n", rte
);
950 add_head( &P
->garbage
, &rte
->u
.rip
.garbage
);
954 * rip_rte_remove - link list maintenance
957 rip_rte_remove(net
*net UNUSED
, rte
*rte
)
959 // struct proto *p = rte->attrs->proto;
961 DBG( "rip_rte_remove: %p\n", rte
);
962 rem_node( &rte
->u
.rip
.garbage
);
966 rip_init_instance(struct proto
*p
)
968 p
->accept_ra_types
= RA_OPTIMAL
;
969 p
->if_notify
= rip_if_notify
;
970 p
->rt_notify
= rip_rt_notify
;
971 p
->import_control
= rip_import_control
;
972 p
->make_tmp_attrs
= rip_make_tmp_attrs
;
973 p
->store_tmp_attrs
= rip_store_tmp_attrs
;
974 p
->rte_better
= rip_rte_better
;
975 p
->rte_same
= rip_rte_same
;
976 p
->rte_insert
= rip_rte_insert
;
977 p
->rte_remove
= rip_rte_remove
;
981 rip_init_config(struct rip_proto_config
*c
)
983 init_list(&c
->iface_list
);
987 c
->garbage_time
= 120+180;
988 c
->timeout_time
= 120;
990 c
->authtype
= AT_NONE
;
994 rip_get_attr(eattr
*a
, byte
*buf
, int buflen UNUSED
)
997 case EA_RIP_METRIC
: bsprintf( buf
, "metric: %d", a
->u
.data
); return GA_FULL
;
998 case EA_RIP_TAG
: bsprintf( buf
, "tag: %d", a
->u
.data
); return GA_FULL
;
999 default: return GA_UNKNOWN
;
1004 rip_pat_compare(struct rip_patt
*a
, struct rip_patt
*b
)
1006 return ((a
->metric
== b
->metric
) &&
1007 (a
->mode
== b
->mode
));
1011 rip_reconfigure(struct proto
*p
, struct proto_config
*c
)
1013 struct rip_proto_config
*new = (struct rip_proto_config
*) c
;
1014 int generic
= sizeof(struct proto_config
) + sizeof(list
) /* + sizeof(struct password_item *) */;
1016 if (!iface_patts_equal(&P_CF
->iface_list
, &new->iface_list
, (void *) rip_pat_compare
))
1018 return !memcmp(((byte
*) P_CF
) + generic
,
1019 ((byte
*) new) + generic
,
1020 sizeof(struct rip_proto_config
) - generic
);
1024 rip_copy_config(struct proto_config
*dest
, struct proto_config
*src
)
1026 /* Shallow copy of everything */
1027 proto_copy_rest(dest
, src
, sizeof(struct rip_proto_config
));
1029 /* We clean up iface_list, ifaces are non-sharable */
1030 init_list(&((struct rip_proto_config
*) dest
)->iface_list
);
1032 /* Copy of passwords is OK, it just will be replaced in dest when used */
1036 struct protocol proto_rip
= {
1039 attr_class
: EAP_RIP
,
1040 preference
: DEF_PREF_RIP
,
1041 get_route_info
: rip_get_route_info
,
1042 get_attr
: rip_get_attr
,
1047 reconfigure
: rip_reconfigure
,
1048 copy_config
: rip_copy_config