3 * Copyright (C) 2000 Robert Olsson.
4 * Swedish University of Agricultural Sciences
6 * This file is part of GNU Zebra.
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 * This work includes work with the following copywrite:
27 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
32 * Thanks to Jens Låås at Swedish University of Agricultural Sciences
33 * for reviewing and tests.
43 #include "sockunion.h"
49 #include "connected.h"
53 #include "zebra/interface.h"
54 #include "zebra/rtadv.h"
55 #include "zebra/rib.h"
56 #include "zebra/zserv.h"
57 #include "zebra/redistribute.h"
58 #include "zebra/irdp.h"
59 #include <netinet/ip_icmp.h>
61 #include "sockunion.h"
65 /* Master of threads. */
66 extern struct thread_master
*master
;
68 int in_cksum (void *ptr
, int nbytes
);
70 int irdp_send_thread(struct thread
*t_advert
);
71 char *inet_2a(u_int32_t a
, char *b
);
72 void irdp_advert_off(struct interface
*ifp
);
75 char b1
[16], b2
[16], b3
[16], b4
[16]; /* For inet_2a */
77 struct prefix
*irdp_get_prefix(struct interface
*ifp
)
80 struct connected
*ifc
;
83 for (node
= listhead (ifp
->connected
); node
; nextnode (node
)) {
90 /* Join to the add/leave multicast group. */
91 int if_group (struct interface
*ifp
,
103 bzero (&m
, sizeof (m
));
104 m
.imr_multiaddr
.s_addr
= htonl (group
);
105 p
= irdp_get_prefix(ifp
);
108 zlog_warn ("IRDP: can't get address for %s", ifp
->name
);
112 m
.imr_interface
= p
->u
.prefix4
;
114 ret
= setsockopt (sock
, IPPROTO_IP
, add_leave
,
115 (char *) &m
, sizeof (struct ip_mreq
));
117 zlog_warn ("IRDP: %s can't setsockopt %s: %s",
118 add_leave
== IP_ADD_MEMBERSHIP
? "join group":"leave group",
125 int if_add_group (struct interface
*ifp
)
127 struct zebra_if
*zi
= ifp
->info
;
128 struct irdp_interface
*irdp
= &zi
->irdp
;
131 ret
= if_group (ifp
, irdp_sock
, INADDR_ALLRTRS_GROUP
, IP_ADD_MEMBERSHIP
);
136 if(irdp
->flags
& IF_DEBUG_MISC
)
137 zlog_warn("IRDP: Adding group %s for %s\n",
138 inet_2a(htonl(INADDR_ALLRTRS_GROUP
), b1
),
142 int if_drop_group (struct interface
*ifp
)
144 struct zebra_if
*zi
= ifp
->info
;
145 struct irdp_interface
*irdp
= &zi
->irdp
;
148 ret
= if_group (ifp
, irdp_sock
, INADDR_ALLRTRS_GROUP
, IP_DROP_MEMBERSHIP
);
152 if(irdp
->flags
& IF_DEBUG_MISC
)
153 zlog_warn("IRDP: Leaving group %s for %s\n",
154 inet_2a(htonl(INADDR_ALLRTRS_GROUP
), b1
),
159 struct interface
*get_iflist_ifp(int idx
)
162 struct interface
*ifp
;
164 for (node
= listhead (iflist
); node
; nextnode (node
)) {
165 ifp
= getdata (node
);
166 if(ifp
->ifindex
== idx
) return ifp
;
172 if_set_defaults(struct interface
*ifp
)
174 struct zebra_if
*zi
=ifp
->info
;
175 struct irdp_interface
*irdp
=&zi
->irdp
;
177 irdp
->MaxAdvertInterval
= IRDP_MAXADVERTINTERVAL
;
178 irdp
->MinAdvertInterval
= IRDP_MINADVERTINTERVAL
;
179 irdp
->Preference
= IRDP_PREFERENCE
;
180 irdp
->Lifetime
= IRDP_LIFETIME
;
184 struct Adv
*Adv_new ()
187 new = XMALLOC (MTYPE_TMP
, sizeof (struct Adv
));
188 memset (new, 0, sizeof (struct Adv
));
192 void Adv_free (struct Adv
*adv
)
194 XFREE (MTYPE_TMP
, adv
);
197 void irdp_if_start(struct interface
*ifp
, int multicast
, int set_defaults
)
199 struct zebra_if
*zi
= ifp
->info
;
200 struct irdp_interface
*irdp
= &zi
->irdp
;
202 u_int32_t timer
, seed
;
204 if (irdp
->flags
& IF_ACTIVE
) {
205 zlog_warn("IRDP: Interface is already active %s\n", ifp
->name
);
208 irdp
->flags
|= IF_ACTIVE
;
211 irdp
->flags
|= IF_BROADCAST
;
215 if (! (ifp
->flags
& IFF_UP
)) {
216 zlog_warn("IRDP: Interface is down %s\n", ifp
->name
);
219 /* Shall we cancel if_start if if_add_group fails? */
224 if (! (ifp
->flags
& (IFF_MULTICAST
|IFF_ALLMULTI
))) {
225 zlog_warn("IRDP: Interface not multicast enabled %s\n", ifp
->name
);
230 if_set_defaults(ifp
);
234 /* The spec suggests this for randomness */
238 for (node
= listhead (ifp
->connected
); node
; nextnode (node
))
240 struct connected
*ifc
= getdata (node
);
241 seed
= ifc
->address
->u
.prefix4
.s_addr
;
245 timer
= (random () % IRDP_DEFAULT_INTERVAL
) + 1;
247 irdp
->AdvPrefList
= list_new();
248 irdp
->AdvPrefList
->del
= (void *) Adv_free
; /* Destructor */
251 /* And this for startup. Speed limit from 1991 :-). But it's OK*/
253 if(irdp
->irdp_sent
< MAX_INITIAL_ADVERTISEMENTS
&&
254 timer
> MAX_INITIAL_ADVERT_INTERVAL
)
255 timer
= MAX_INITIAL_ADVERT_INTERVAL
;
258 if(irdp
->flags
& IF_DEBUG_MISC
)
259 zlog_warn("IRDP: Init timer for %s set to %u\n",
263 irdp
->t_advertise
= thread_add_timer(master
,
269 void irdp_if_stop(struct interface
*ifp
)
271 struct zebra_if
*zi
=ifp
->info
;
272 struct irdp_interface
*irdp
=&zi
->irdp
;
275 zlog_warn ("Interface %s structure is NULL", ifp
->name
);
279 if (! (irdp
->flags
& IF_ACTIVE
)) {
280 zlog_warn("Interface is not active %s\n", ifp
->name
);
284 if(! (irdp
->flags
& IF_BROADCAST
))
287 irdp_advert_off(ifp
);
289 list_delete(irdp
->AdvPrefList
);
290 irdp
->AdvPrefList
=NULL
;
296 void irdp_if_shutdown(struct interface
*ifp
)
298 struct zebra_if
*zi
= ifp
->info
;
299 struct irdp_interface
*irdp
= &zi
->irdp
;
301 if (irdp
->flags
& IF_SHUTDOWN
) {
302 zlog_warn("IRDP: Interface is already shutdown %s\n", ifp
->name
);
306 irdp
->flags
|= IF_SHUTDOWN
;
307 irdp
->flags
&= ~IF_ACTIVE
;
309 if(! (irdp
->flags
& IF_BROADCAST
))
312 /* Tell the hosts we are out of service */
313 irdp_advert_off(ifp
);
316 void irdp_if_no_shutdown(struct interface
*ifp
)
318 struct zebra_if
*zi
= ifp
->info
;
319 struct irdp_interface
*irdp
= &zi
->irdp
;
321 if (! (irdp
->flags
& IF_SHUTDOWN
)) {
322 zlog_warn("IRDP: Interface is not shutdown %s\n", ifp
->name
);
326 irdp
->flags
&= ~IF_SHUTDOWN
;
328 irdp_if_start(ifp
, irdp
->flags
& IF_BROADCAST
? FALSE
: TRUE
, FALSE
);
333 /* Write configuration to user */
335 void irdp_config_write (struct vty
*vty
, struct interface
*ifp
)
337 struct zebra_if
*zi
=ifp
->info
;
338 struct irdp_interface
*irdp
=&zi
->irdp
;
342 if(irdp
->flags
& IF_ACTIVE
|| irdp
->flags
& IF_SHUTDOWN
) {
344 if( irdp
->flags
& IF_SHUTDOWN
)
345 vty_out (vty
, " ip irdp shutdown %s", VTY_NEWLINE
);
347 if( irdp
->flags
& IF_BROADCAST
)
348 vty_out (vty
, " ip irdp broadcast%s", VTY_NEWLINE
);
350 vty_out (vty
, " ip irdp multicast%s", VTY_NEWLINE
);
352 vty_out (vty
, " ip irdp preference %ld%s",
353 irdp
->Preference
, VTY_NEWLINE
);
355 for (node
= listhead (irdp
->AdvPrefList
); node
; nextnode (node
)) {
356 adv
= getdata (node
);
357 vty_out (vty
, " ip irdp address %s preference %d%s",
358 inet_2a(adv
->ip
.s_addr
, b1
),
364 vty_out (vty
, " ip irdp holdtime %d%s",
365 irdp
->Lifetime
, VTY_NEWLINE
);
367 vty_out (vty
, " ip irdp minadvertinterval %ld%s",
368 irdp
->MinAdvertInterval
, VTY_NEWLINE
);
370 vty_out (vty
, " ip irdp maxadvertinterval %ld%s",
371 irdp
->MaxAdvertInterval
, VTY_NEWLINE
);
377 DEFUN (ip_irdp_multicast
,
378 ip_irdp_multicast_cmd
,
381 "ICMP Router discovery on this interface using multicast\n")
383 struct interface
*ifp
;
385 ifp
= (struct interface
*) vty
->index
;
390 irdp_if_start(ifp
, TRUE
, TRUE
);
394 DEFUN (ip_irdp_broadcast
,
395 ip_irdp_broadcast_cmd
,
398 "ICMP Router discovery on this interface using broadcast\n")
400 struct interface
*ifp
;
402 ifp
= (struct interface
*) vty
->index
;
407 irdp_if_start(ifp
, FALSE
, TRUE
);
415 "Disable ICMP Router discovery on this interface\n")
417 struct interface
*ifp
;
419 ifp
= (struct interface
*) vty
->index
;
428 DEFUN (ip_irdp_shutdown
,
429 ip_irdp_shutdown_cmd
,
432 "ICMP Router discovery shutdown on this interface\n")
434 struct interface
*ifp
;
436 ifp
= (struct interface
*) vty
->index
;
441 irdp_if_shutdown(ifp
);
445 DEFUN (ip_irdp_no_shutdown
,
446 ip_irdp_no_shutdown_cmd
,
447 "no ip irdp shutdown",
449 "ICMP Router discovery no shutdown on this interface\n")
451 struct interface
*ifp
;
453 ifp
= (struct interface
*) vty
->index
;
458 irdp_if_no_shutdown(ifp
);
462 DEFUN (ip_irdp_holdtime
,
463 ip_irdp_holdtime_cmd
,
464 "ip irdp holdtime <0-9000>",
466 "ICMP Router discovery on this interface\n"
467 "Set holdtime value\n"
468 "Holdtime value in seconds. Default is 1800 seconds\n")
470 struct interface
*ifp
;
472 struct irdp_interface
*irdp
;
473 ifp
= (struct interface
*) vty
->index
;
481 irdp
->Lifetime
= atoi(argv
[0]);
485 DEFUN (ip_irdp_minadvertinterval
,
486 ip_irdp_minadvertinterval_cmd
,
487 "ip irdp minadvertinterval <3-1800>",
489 "ICMP Router discovery on this interface\n"
490 "Set minimum time between advertisement\n"
491 "Minimum advertisement interval in seconds\n")
493 struct interface
*ifp
;
495 struct irdp_interface
*irdp
;
496 ifp
= (struct interface
*) vty
->index
;
504 if( atoi(argv
[0]) <= irdp
->MaxAdvertInterval
) {
505 irdp
->MinAdvertInterval
= atoi(argv
[0]);
510 vty_out (vty
, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s",
513 vty_out (vty
, "Please correct!%s",
518 DEFUN (ip_irdp_maxadvertinterval
,
519 ip_irdp_maxadvertinterval_cmd
,
520 "ip irdp maxadvertinterval <4-1800>",
522 "ICMP Router discovery on this interface\n"
523 "Set maximum time between advertisement\n"
524 "Maximum advertisement interval in seconds\n")
526 struct interface
*ifp
;
528 struct irdp_interface
*irdp
;
529 ifp
= (struct interface
*) vty
->index
;
538 if( irdp
->MinAdvertInterval
<= atoi(argv
[0]) ) {
539 irdp
->MaxAdvertInterval
= atoi(argv
[0]);
544 vty_out (vty
, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s",
547 vty_out (vty
, "Please correct!%s",
552 DEFUN (ip_irdp_preference
,
553 ip_irdp_preference_cmd
,
555 /* DEFUN needs to be fixed for negative ranages...
556 Be positive for now. :-)
558 "ip irdp preference <-2147483648-2147483647>",
562 "ip irdp preference <0-2147483647>",
564 "ICMP Router discovery on this interface\n"
565 "Set default preference level for this interface\n"
566 "Preference level\n")
568 struct interface
*ifp
;
570 struct irdp_interface
*irdp
;
571 ifp
= (struct interface
*) vty
->index
;
579 irdp
->Preference
= atoi(argv
[0]);
583 DEFUN (ip_irdp_address_preference
,
584 ip_irdp_address_preference_cmd
,
585 "ip irdp address A.B.C.D preference <0-2147483647>",
587 "Alter ICMP Router discovery preference this interface\n"
588 "Specify IRDP non-default preference to advertise\n"
589 "Set IRDP address for advertise\n"
590 "Preference level\n")
596 struct interface
*ifp
;
598 struct irdp_interface
*irdp
;
601 ifp
= (struct interface
*) vty
->index
;
609 ret
= inet_aton(argv
[0], &ip
);
610 if(!ret
) return CMD_WARNING
;
612 pref
= atoi(argv
[1]);
614 for (node
= listhead (irdp
->AdvPrefList
); node
; nextnode (node
)) {
615 adv
= getdata (node
);
616 if(adv
->ip
.s_addr
== ip
.s_addr
) return CMD_SUCCESS
;
622 listnode_add(irdp
->AdvPrefList
, adv
);
628 DEFUN (ip_irdp_address_preference_no
,
629 ip_irdp_address_preference_cmd_no
,
630 "no ip irdp address A.B.C.D preference <0-2147483647>",
632 "Alter ICMP Router discovery preference this interface\n"
633 "Removes IRDP non-default preference\n"
634 "Select IRDP address\n"
635 "Old preference level\n")
641 struct interface
*ifp
;
643 struct irdp_interface
*irdp
;
646 ifp
= (struct interface
*) vty
->index
;
654 ret
= inet_aton(argv
[0], &ip
);
655 if(!ret
) return CMD_WARNING
;
657 pref
= atoi(argv
[1]);
659 for (node
= listhead (irdp
->AdvPrefList
); node
; nextnode (node
)) {
660 adv
= getdata (node
);
661 if(adv
->ip
.s_addr
== ip
.s_addr
) {
662 listnode_delete(irdp
->AdvPrefList
, adv
);
672 DEFUN (ip_irdp_debug_messages
,
673 ip_irdp_debug_messages_cmd
,
674 "ip irdp debug messages",
676 "ICMP Router discovery debug Averts. and Solicits (short)\n")
678 struct interface
*ifp
;
680 struct irdp_interface
*irdp
;
681 ifp
= (struct interface
*) vty
->index
;
689 irdp
->flags
|= IF_DEBUG_MESSAGES
;
694 DEFUN (ip_irdp_debug_misc
,
695 ip_irdp_debug_misc_cmd
,
696 "ip irdp debug misc",
698 "ICMP Router discovery debug Averts. and Solicits (short)\n")
700 struct interface
*ifp
;
702 struct irdp_interface
*irdp
;
703 ifp
= (struct interface
*) vty
->index
;
711 irdp
->flags
|= IF_DEBUG_MISC
;
716 DEFUN (ip_irdp_debug_packet
,
717 ip_irdp_debug_packet_cmd
,
718 "ip irdp debug packet",
720 "ICMP Router discovery debug Averts. and Solicits (short)\n")
722 struct interface
*ifp
;
724 struct irdp_interface
*irdp
;
725 ifp
= (struct interface
*) vty
->index
;
733 irdp
->flags
|= IF_DEBUG_PACKET
;
739 DEFUN (ip_irdp_debug_disable
,
740 ip_irdp_debug_disable_cmd
,
741 "ip irdp debug disable",
743 "ICMP Router discovery debug Averts. and Solicits (short)\n")
745 struct interface
*ifp
;
747 struct irdp_interface
*irdp
;
748 ifp
= (struct interface
*) vty
->index
;
756 irdp
->flags
&= ~IF_DEBUG_PACKET
;
757 irdp
->flags
&= ~IF_DEBUG_MESSAGES
;
758 irdp
->flags
&= ~IF_DEBUG_MISC
;
766 install_element (INTERFACE_NODE
, &ip_irdp_broadcast_cmd
);
767 install_element (INTERFACE_NODE
, &ip_irdp_multicast_cmd
);
768 install_element (INTERFACE_NODE
, &ip_irdp_cmd_no
);
769 install_element (INTERFACE_NODE
, &ip_irdp_shutdown_cmd
);
770 install_element (INTERFACE_NODE
, &ip_irdp_no_shutdown_cmd
);
771 install_element (INTERFACE_NODE
, &ip_irdp_holdtime_cmd
);
772 install_element (INTERFACE_NODE
, &ip_irdp_maxadvertinterval_cmd
);
773 install_element (INTERFACE_NODE
, &ip_irdp_minadvertinterval_cmd
);
774 install_element (INTERFACE_NODE
, &ip_irdp_preference_cmd
);
775 install_element (INTERFACE_NODE
, &ip_irdp_address_preference_cmd
);
776 install_element (INTERFACE_NODE
, &ip_irdp_address_preference_cmd_no
);
778 install_element (INTERFACE_NODE
, &ip_irdp_debug_messages_cmd
);
779 install_element (INTERFACE_NODE
, &ip_irdp_debug_misc_cmd
);
780 install_element (INTERFACE_NODE
, &ip_irdp_debug_packet_cmd
);
781 install_element (INTERFACE_NODE
, &ip_irdp_debug_disable_cmd
);
784 #endif /* HAVE_IRDP */