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 along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 * This work includes work with the following copywrite:
26 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
31 * Thanks to Jens Låås at Swedish University of Agricultural Sciences
32 * for reviewing and tests.
42 #include "sockunion.h"
46 #include "zebra_memory.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"
67 inet_2a(u_int32_t a
, char *b
)
69 sprintf(b
, "%u.%u.%u.%u",
78 static struct prefix
*
79 irdp_get_prefix(struct interface
*ifp
)
81 struct listnode
*node
;
82 struct connected
*ifc
;
85 for (ALL_LIST_ELEMENTS_RO (ifp
->connected
, node
, ifc
))
91 /* Join to the add/leave multicast group. */
93 if_group (struct interface
*ifp
,
101 char b1
[INET_ADDRSTRLEN
];
103 memset (&m
, 0, 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",
120 safe_strerror (errno
));
126 if_add_group (struct interface
*ifp
)
128 struct zebra_if
*zi
= ifp
->info
;
129 struct irdp_interface
*irdp
= &zi
->irdp
;
131 char b1
[INET_ADDRSTRLEN
];
133 ret
= if_group (ifp
, irdp_sock
, INADDR_ALLRTRS_GROUP
, IP_ADD_MEMBERSHIP
);
138 if(irdp
->flags
& IF_DEBUG_MISC
)
139 zlog_debug("IRDP: Adding group %s for %s",
140 inet_2a(htonl(INADDR_ALLRTRS_GROUP
), b1
),
146 if_drop_group (struct interface
*ifp
)
148 struct zebra_if
*zi
= ifp
->info
;
149 struct irdp_interface
*irdp
= &zi
->irdp
;
151 char b1
[INET_ADDRSTRLEN
];
153 ret
= if_group (ifp
, irdp_sock
, INADDR_ALLRTRS_GROUP
, IP_DROP_MEMBERSHIP
);
157 if(irdp
->flags
& IF_DEBUG_MISC
)
158 zlog_debug("IRDP: Leaving group %s for %s",
159 inet_2a(htonl(INADDR_ALLRTRS_GROUP
), b1
),
165 if_set_defaults(struct interface
*ifp
)
167 struct zebra_if
*zi
=ifp
->info
;
168 struct irdp_interface
*irdp
=&zi
->irdp
;
170 irdp
->MaxAdvertInterval
= IRDP_MAXADVERTINTERVAL
;
171 irdp
->MinAdvertInterval
= IRDP_MINADVERTINTERVAL
;
172 irdp
->Preference
= IRDP_PREFERENCE
;
173 irdp
->Lifetime
= IRDP_LIFETIME
;
177 static struct Adv
*Adv_new (void)
179 return XCALLOC (MTYPE_TMP
, sizeof (struct Adv
));
183 Adv_free (struct Adv
*adv
)
185 XFREE (MTYPE_TMP
, adv
);
189 irdp_if_start(struct interface
*ifp
, int multicast
, int set_defaults
)
191 struct zebra_if
*zi
= ifp
->info
;
192 struct irdp_interface
*irdp
= &zi
->irdp
;
193 struct listnode
*node
;
194 struct connected
*ifc
;
195 u_int32_t timer
, seed
;
197 if (irdp
->flags
& IF_ACTIVE
) {
198 zlog_warn("IRDP: Interface is already active %s", ifp
->name
);
201 if ((irdp_sock
< 0) && ((irdp_sock
= irdp_sock_init()) < 0)) {
202 zlog_warn("IRDP: Cannot activate interface %s (cannot create "
203 "IRDP socket)", ifp
->name
);
206 irdp
->flags
|= IF_ACTIVE
;
209 irdp
->flags
|= IF_BROADCAST
;
213 if (! (ifp
->flags
& IFF_UP
)) {
214 zlog_warn("IRDP: Interface is down %s", ifp
->name
);
217 /* Shall we cancel if_start if if_add_group fails? */
222 if (! (ifp
->flags
& (IFF_MULTICAST
|IFF_ALLMULTI
))) {
223 zlog_warn("IRDP: Interface not multicast enabled %s", ifp
->name
);
228 if_set_defaults(ifp
);
232 /* The spec suggests this for randomness */
236 for (ALL_LIST_ELEMENTS_RO (ifp
->connected
, node
, ifc
))
238 seed
= ifc
->address
->u
.prefix4
.s_addr
;
243 timer
= (random () % IRDP_DEFAULT_INTERVAL
) + 1;
245 irdp
->AdvPrefList
= list_new();
246 irdp
->AdvPrefList
->del
= (void (*)(void *)) Adv_free
; /* Destructor */
249 /* And this for startup. Speed limit from 1991 :-). But it's OK*/
251 if(irdp
->irdp_sent
< MAX_INITIAL_ADVERTISEMENTS
&&
252 timer
> MAX_INITIAL_ADVERT_INTERVAL
)
253 timer
= MAX_INITIAL_ADVERT_INTERVAL
;
256 if(irdp
->flags
& IF_DEBUG_MISC
)
257 zlog_debug("IRDP: Init timer for %s set to %u",
261 irdp
->t_advertise
= NULL
;
262 thread_add_timer(zebrad
.master
, irdp_send_thread
, ifp
, timer
,
267 irdp_if_stop(struct interface
*ifp
)
269 struct zebra_if
*zi
=ifp
->info
;
270 struct irdp_interface
*irdp
=&zi
->irdp
;
273 zlog_warn ("Interface %s structure is NULL", ifp
->name
);
277 if (! (irdp
->flags
& IF_ACTIVE
)) {
278 zlog_warn("Interface is not active %s", ifp
->name
);
282 if(! (irdp
->flags
& IF_BROADCAST
))
285 irdp_advert_off(ifp
);
287 list_delete(irdp
->AdvPrefList
);
288 irdp
->AdvPrefList
=NULL
;
295 irdp_if_shutdown(struct interface
*ifp
)
297 struct zebra_if
*zi
= ifp
->info
;
298 struct irdp_interface
*irdp
= &zi
->irdp
;
300 if (irdp
->flags
& IF_SHUTDOWN
) {
301 zlog_warn("IRDP: Interface is already shutdown %s", ifp
->name
);
305 irdp
->flags
|= IF_SHUTDOWN
;
306 irdp
->flags
&= ~IF_ACTIVE
;
308 if(! (irdp
->flags
& IF_BROADCAST
))
311 /* Tell the hosts we are out of service */
312 irdp_advert_off(ifp
);
316 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", 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
;
340 struct listnode
*node
;
341 char b1
[INET_ADDRSTRLEN
];
343 if(irdp
->flags
& IF_ACTIVE
|| irdp
->flags
& IF_SHUTDOWN
) {
345 if( irdp
->flags
& IF_SHUTDOWN
)
346 vty_out (vty
, " ip irdp shutdown %s", VTY_NEWLINE
);
348 if( irdp
->flags
& IF_BROADCAST
)
349 vty_out (vty
, " ip irdp broadcast%s", VTY_NEWLINE
);
351 vty_out (vty
, " ip irdp multicast%s", VTY_NEWLINE
);
353 vty_out (vty
, " ip irdp preference %ld%s",
354 irdp
->Preference
, VTY_NEWLINE
);
356 for (ALL_LIST_ELEMENTS_RO (irdp
->AdvPrefList
, node
, adv
))
357 vty_out (vty
, " ip irdp address %s preference %d%s",
358 inet_2a(adv
->ip
.s_addr
, b1
),
362 vty_out (vty
, " ip irdp holdtime %d%s",
363 irdp
->Lifetime
, VTY_NEWLINE
);
365 vty_out (vty
, " ip irdp minadvertinterval %ld%s",
366 irdp
->MinAdvertInterval
, VTY_NEWLINE
);
368 vty_out (vty
, " ip irdp maxadvertinterval %ld%s",
369 irdp
->MaxAdvertInterval
, VTY_NEWLINE
);
375 DEFUN (ip_irdp_multicast
,
376 ip_irdp_multicast_cmd
,
379 "ICMP Router discovery on this interface\n"
380 "Use multicast mode\n")
382 VTY_DECLVAR_CONTEXT (interface
, ifp
);
384 irdp_if_start(ifp
, TRUE
, TRUE
);
388 DEFUN (ip_irdp_broadcast
,
389 ip_irdp_broadcast_cmd
,
392 "ICMP Router discovery on this interface\n"
393 "Use broadcast mode\n")
395 VTY_DECLVAR_CONTEXT (interface
, ifp
);
397 irdp_if_start(ifp
, FALSE
, TRUE
);
406 "Disable ICMP Router discovery on this interface\n")
408 VTY_DECLVAR_CONTEXT (interface
, ifp
);
414 DEFUN (ip_irdp_shutdown
,
415 ip_irdp_shutdown_cmd
,
418 "ICMP Router discovery on this interface\n"
419 "ICMP Router discovery shutdown on this interface\n")
421 VTY_DECLVAR_CONTEXT (interface
, ifp
);
423 irdp_if_shutdown(ifp
);
427 DEFUN (no_ip_irdp_shutdown
,
428 no_ip_irdp_shutdown_cmd
,
429 "no ip irdp shutdown",
432 "ICMP Router discovery on this interface\n"
433 "ICMP Router discovery no shutdown on this interface\n")
435 VTY_DECLVAR_CONTEXT (interface
, ifp
);
437 irdp_if_no_shutdown(ifp
);
441 DEFUN (ip_irdp_holdtime
,
442 ip_irdp_holdtime_cmd
,
443 "ip irdp holdtime (0-9000)",
445 "ICMP Router discovery on this interface\n"
446 "Set holdtime value\n"
447 "Holdtime value in seconds. Default is 1800 seconds\n")
450 VTY_DECLVAR_CONTEXT (interface
, ifp
);
452 struct irdp_interface
*irdp
;
457 irdp
->Lifetime
= atoi(argv
[idx_number
]->arg
);
461 DEFUN (ip_irdp_minadvertinterval
,
462 ip_irdp_minadvertinterval_cmd
,
463 "ip irdp minadvertinterval (3-1800)",
465 "ICMP Router discovery on this interface\n"
466 "Set minimum time between advertisement\n"
467 "Minimum advertisement interval in seconds\n")
470 VTY_DECLVAR_CONTEXT (interface
, ifp
);
472 struct irdp_interface
*irdp
;
477 if( (unsigned) atoi(argv
[idx_number
]->arg
) <= irdp
->MaxAdvertInterval
) {
478 irdp
->MinAdvertInterval
= atoi(argv
[idx_number
]->arg
);
483 vty_out (vty
, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s",
486 vty_out (vty
, "Please correct!%s",
491 DEFUN (ip_irdp_maxadvertinterval
,
492 ip_irdp_maxadvertinterval_cmd
,
493 "ip irdp maxadvertinterval (4-1800)",
495 "ICMP Router discovery on this interface\n"
496 "Set maximum time between advertisement\n"
497 "Maximum advertisement interval in seconds\n")
500 VTY_DECLVAR_CONTEXT (interface
, ifp
);
502 struct irdp_interface
*irdp
;
508 if( irdp
->MinAdvertInterval
<= (unsigned) atoi(argv
[idx_number
]->arg
) ) {
509 irdp
->MaxAdvertInterval
= atoi(argv
[idx_number
]->arg
);
514 vty_out (vty
, "ICMP warning maxadvertinterval is greater or equal than minadvertinterval%s",
517 vty_out (vty
, "Please correct!%s",
522 /* DEFUN needs to be fixed for negative ranages...
523 * "ip irdp preference <-2147483648-2147483647>",
524 * Be positive for now. :-)
527 DEFUN (ip_irdp_preference
,
528 ip_irdp_preference_cmd
,
529 "ip irdp preference (0-2147483647)",
531 "ICMP Router discovery on this interface\n"
532 "Set default preference level for this interface\n"
533 "Preference level\n")
536 VTY_DECLVAR_CONTEXT (interface
, ifp
);
538 struct irdp_interface
*irdp
;
543 irdp
->Preference
= atoi(argv
[idx_number
]->arg
);
547 DEFUN (ip_irdp_address_preference
,
548 ip_irdp_address_preference_cmd
,
549 "ip irdp address A.B.C.D preference (0-2147483647)",
551 "Alter ICMP Router discovery preference on this interface\n"
552 "Set IRDP address for advertise\n"
554 "Specify IRDP non-default preference to advertise\n"
555 "Preference level\n")
559 VTY_DECLVAR_CONTEXT (interface
, ifp
);
560 struct listnode
*node
;
565 struct irdp_interface
*irdp
;
571 ret
= inet_aton(argv
[idx_ipv4
]->arg
, &ip
);
572 if(!ret
) return CMD_WARNING
;
574 pref
= atoi(argv
[idx_number
]->arg
);
576 for (ALL_LIST_ELEMENTS_RO (irdp
->AdvPrefList
, node
, adv
))
577 if(adv
->ip
.s_addr
== ip
.s_addr
)
583 listnode_add(irdp
->AdvPrefList
, adv
);
589 DEFUN (no_ip_irdp_address_preference
,
590 no_ip_irdp_address_preference_cmd
,
591 "no ip irdp address A.B.C.D preference (0-2147483647)",
594 "Alter ICMP Router discovery preference on this interface\n"
595 "Select IRDP address\n"
597 "Reset ICMP Router discovery preference on this interface\n"
598 "Old preference level\n")
601 VTY_DECLVAR_CONTEXT (interface
, ifp
);
602 struct listnode
*node
, *nnode
;
606 struct irdp_interface
*irdp
;
612 ret
= inet_aton(argv
[idx_ipv4
]->arg
, &ip
);
616 for (ALL_LIST_ELEMENTS (irdp
->AdvPrefList
, node
, nnode
, adv
))
618 if(adv
->ip
.s_addr
== ip
.s_addr
)
620 listnode_delete(irdp
->AdvPrefList
, adv
);
628 DEFUN (ip_irdp_debug_messages
,
629 ip_irdp_debug_messages_cmd
,
630 "ip irdp debug messages",
632 "ICMP Router discovery debug Averts. and Solicits (short)\n"
633 "IRDP debugging options\n"
634 "Enable debugging for IRDP messages\n")
636 VTY_DECLVAR_CONTEXT (interface
, ifp
);
638 struct irdp_interface
*irdp
;
643 irdp
->flags
|= IF_DEBUG_MESSAGES
;
648 DEFUN (ip_irdp_debug_misc
,
649 ip_irdp_debug_misc_cmd
,
650 "ip irdp debug misc",
652 "ICMP Router discovery debug Averts. and Solicits (short)\n"
653 "IRDP debugging options\n"
654 "Enable debugging for miscellaneous IRDP events\n")
656 VTY_DECLVAR_CONTEXT (interface
, ifp
);
658 struct irdp_interface
*irdp
;
663 irdp
->flags
|= IF_DEBUG_MISC
;
668 DEFUN (ip_irdp_debug_packet
,
669 ip_irdp_debug_packet_cmd
,
670 "ip irdp debug packet",
672 "ICMP Router discovery debug Averts. and Solicits (short)\n"
673 "IRDP debugging options\n"
674 "Enable debugging for IRDP packets\n")
676 VTY_DECLVAR_CONTEXT (interface
, ifp
);
678 struct irdp_interface
*irdp
;
683 irdp
->flags
|= IF_DEBUG_PACKET
;
689 DEFUN (ip_irdp_debug_disable
,
690 ip_irdp_debug_disable_cmd
,
691 "ip irdp debug disable",
693 "ICMP Router discovery debug Averts. and Solicits (short)\n"
694 "IRDP debugging options\n"
695 "Disable debugging for all IRDP events\n")
697 VTY_DECLVAR_CONTEXT (interface
, ifp
);
699 struct irdp_interface
*irdp
;
704 irdp
->flags
&= ~IF_DEBUG_PACKET
;
705 irdp
->flags
&= ~IF_DEBUG_MESSAGES
;
706 irdp
->flags
&= ~IF_DEBUG_MISC
;
714 install_element (INTERFACE_NODE
, &ip_irdp_broadcast_cmd
);
715 install_element (INTERFACE_NODE
, &ip_irdp_multicast_cmd
);
716 install_element (INTERFACE_NODE
, &no_ip_irdp_cmd
);
717 install_element (INTERFACE_NODE
, &ip_irdp_shutdown_cmd
);
718 install_element (INTERFACE_NODE
, &no_ip_irdp_shutdown_cmd
);
719 install_element (INTERFACE_NODE
, &ip_irdp_holdtime_cmd
);
720 install_element (INTERFACE_NODE
, &ip_irdp_maxadvertinterval_cmd
);
721 install_element (INTERFACE_NODE
, &ip_irdp_minadvertinterval_cmd
);
722 install_element (INTERFACE_NODE
, &ip_irdp_preference_cmd
);
723 install_element (INTERFACE_NODE
, &ip_irdp_address_preference_cmd
);
724 install_element (INTERFACE_NODE
, &no_ip_irdp_address_preference_cmd
);
726 install_element (INTERFACE_NODE
, &ip_irdp_debug_messages_cmd
);
727 install_element (INTERFACE_NODE
, &ip_irdp_debug_misc_cmd
);
728 install_element (INTERFACE_NODE
, &ip_irdp_debug_packet_cmd
);
729 install_element (INTERFACE_NODE
, &ip_irdp_debug_disable_cmd
);
732 #endif /* HAVE_IRDP */