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"
66 static const char *inet_2a(u_int32_t a
, char *b
)
68 sprintf(b
, "%u.%u.%u.%u", (a
)&0xFF, (a
>> 8) & 0xFF, (a
>> 16) & 0xFF,
74 static struct prefix
*irdp_get_prefix(struct interface
*ifp
)
76 struct listnode
*node
;
77 struct connected
*ifc
;
80 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
))
86 /* Join to the add/leave multicast group. */
87 static int if_group(struct interface
*ifp
, int sock
, u_int32_t group
,
93 char b1
[INET_ADDRSTRLEN
];
95 memset(&m
, 0, sizeof(m
));
96 m
.imr_multiaddr
.s_addr
= htonl(group
);
97 p
= irdp_get_prefix(ifp
);
100 zlog_warn("IRDP: can't get address for %s", ifp
->name
);
104 m
.imr_interface
= p
->u
.prefix4
;
106 ret
= setsockopt(sock
, IPPROTO_IP
, add_leave
, (char *)&m
,
107 sizeof(struct ip_mreq
));
109 zlog_warn("IRDP: %s can't setsockopt %s: %s",
110 add_leave
== IP_ADD_MEMBERSHIP
? "join group"
112 inet_2a(group
, b1
), safe_strerror(errno
));
117 static int if_add_group(struct interface
*ifp
)
119 struct zebra_if
*zi
= ifp
->info
;
120 struct irdp_interface
*irdp
= &zi
->irdp
;
122 char b1
[INET_ADDRSTRLEN
];
124 ret
= if_group(ifp
, irdp_sock
, INADDR_ALLRTRS_GROUP
, IP_ADD_MEMBERSHIP
);
129 if (irdp
->flags
& IF_DEBUG_MISC
)
130 zlog_debug("IRDP: Adding group %s for %s",
131 inet_2a(htonl(INADDR_ALLRTRS_GROUP
), b1
), ifp
->name
);
135 static int if_drop_group(struct interface
*ifp
)
137 struct zebra_if
*zi
= ifp
->info
;
138 struct irdp_interface
*irdp
= &zi
->irdp
;
140 char b1
[INET_ADDRSTRLEN
];
142 ret
= if_group(ifp
, irdp_sock
, INADDR_ALLRTRS_GROUP
,
147 if (irdp
->flags
& IF_DEBUG_MISC
)
148 zlog_debug("IRDP: Leaving group %s for %s",
149 inet_2a(htonl(INADDR_ALLRTRS_GROUP
), b1
), ifp
->name
);
153 static void if_set_defaults(struct interface
*ifp
)
155 struct zebra_if
*zi
= ifp
->info
;
156 struct irdp_interface
*irdp
= &zi
->irdp
;
158 irdp
->MaxAdvertInterval
= IRDP_MAXADVERTINTERVAL
;
159 irdp
->MinAdvertInterval
= IRDP_MINADVERTINTERVAL
;
160 irdp
->Preference
= IRDP_PREFERENCE
;
161 irdp
->Lifetime
= IRDP_LIFETIME
;
165 static struct Adv
*Adv_new(void)
167 return XCALLOC(MTYPE_TMP
, sizeof(struct Adv
));
170 static void Adv_free(struct Adv
*adv
)
172 XFREE(MTYPE_TMP
, adv
);
175 static void irdp_if_start(struct interface
*ifp
, int multicast
,
178 struct zebra_if
*zi
= ifp
->info
;
179 struct irdp_interface
*irdp
= &zi
->irdp
;
180 struct listnode
*node
;
181 struct connected
*ifc
;
182 u_int32_t timer
, seed
;
184 if (irdp
->flags
& IF_ACTIVE
) {
185 zlog_warn("IRDP: Interface is already active %s", ifp
->name
);
188 if ((irdp_sock
< 0) && ((irdp_sock
= irdp_sock_init()) < 0)) {
190 "IRDP: Cannot activate interface %s (cannot create "
195 irdp
->flags
|= IF_ACTIVE
;
198 irdp
->flags
|= IF_BROADCAST
;
202 if (!(ifp
->flags
& IFF_UP
)) {
203 zlog_warn("IRDP: Interface is down %s", ifp
->name
);
206 /* Shall we cancel if_start if if_add_group fails? */
211 if (!(ifp
->flags
& (IFF_MULTICAST
| IFF_ALLMULTI
))) {
212 zlog_warn("IRDP: Interface not multicast enabled %s",
218 if_set_defaults(ifp
);
222 /* The spec suggests this for randomness */
226 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
227 seed
= ifc
->address
->u
.prefix4
.s_addr
;
232 timer
= (random() % IRDP_DEFAULT_INTERVAL
) + 1;
234 irdp
->AdvPrefList
= list_new();
235 irdp
->AdvPrefList
->del
= (void (*)(void *))Adv_free
; /* Destructor */
238 /* And this for startup. Speed limit from 1991 :-). But it's OK*/
240 if (irdp
->irdp_sent
< MAX_INITIAL_ADVERTISEMENTS
241 && timer
> MAX_INITIAL_ADVERT_INTERVAL
)
242 timer
= MAX_INITIAL_ADVERT_INTERVAL
;
245 if (irdp
->flags
& IF_DEBUG_MISC
)
246 zlog_debug("IRDP: Init timer for %s set to %u", ifp
->name
,
249 irdp
->t_advertise
= NULL
;
250 thread_add_timer(zebrad
.master
, irdp_send_thread
, ifp
, timer
,
254 static void irdp_if_stop(struct interface
*ifp
)
256 struct zebra_if
*zi
= ifp
->info
;
257 struct irdp_interface
*irdp
= &zi
->irdp
;
260 zlog_warn("Interface %s structure is NULL", ifp
->name
);
264 if (!(irdp
->flags
& IF_ACTIVE
)) {
265 zlog_warn("Interface is not active %s", ifp
->name
);
269 if (!(irdp
->flags
& IF_BROADCAST
))
272 irdp_advert_off(ifp
);
274 list_delete(irdp
->AdvPrefList
);
275 irdp
->AdvPrefList
= NULL
;
281 static void irdp_if_shutdown(struct interface
*ifp
)
283 struct zebra_if
*zi
= ifp
->info
;
284 struct irdp_interface
*irdp
= &zi
->irdp
;
286 if (irdp
->flags
& IF_SHUTDOWN
) {
287 zlog_warn("IRDP: Interface is already shutdown %s", ifp
->name
);
291 irdp
->flags
|= IF_SHUTDOWN
;
292 irdp
->flags
&= ~IF_ACTIVE
;
294 if (!(irdp
->flags
& IF_BROADCAST
))
297 /* Tell the hosts we are out of service */
298 irdp_advert_off(ifp
);
301 static void irdp_if_no_shutdown(struct interface
*ifp
)
303 struct zebra_if
*zi
= ifp
->info
;
304 struct irdp_interface
*irdp
= &zi
->irdp
;
306 if (!(irdp
->flags
& IF_SHUTDOWN
)) {
307 zlog_warn("IRDP: Interface is not shutdown %s", ifp
->name
);
311 irdp
->flags
&= ~IF_SHUTDOWN
;
313 irdp_if_start(ifp
, irdp
->flags
& IF_BROADCAST
? FALSE
: TRUE
, FALSE
);
317 /* Write configuration to user */
319 void irdp_config_write(struct vty
*vty
, struct interface
*ifp
)
321 struct zebra_if
*zi
= ifp
->info
;
322 struct irdp_interface
*irdp
= &zi
->irdp
;
324 struct listnode
*node
;
325 char b1
[INET_ADDRSTRLEN
];
327 if (irdp
->flags
& IF_ACTIVE
|| irdp
->flags
& IF_SHUTDOWN
) {
329 if (irdp
->flags
& IF_SHUTDOWN
)
330 vty_out(vty
, " ip irdp shutdown \n");
332 if (irdp
->flags
& IF_BROADCAST
)
333 vty_out(vty
, " ip irdp broadcast\n");
335 vty_out(vty
, " ip irdp multicast\n");
337 vty_out(vty
, " ip irdp preference %ld\n", irdp
->Preference
);
339 for (ALL_LIST_ELEMENTS_RO(irdp
->AdvPrefList
, node
, adv
))
340 vty_out(vty
, " ip irdp address %s preference %d\n",
341 inet_2a(adv
->ip
.s_addr
, b1
), adv
->pref
);
343 vty_out(vty
, " ip irdp holdtime %d\n", irdp
->Lifetime
);
345 vty_out(vty
, " ip irdp minadvertinterval %ld\n",
346 irdp
->MinAdvertInterval
);
348 vty_out(vty
, " ip irdp maxadvertinterval %ld\n",
349 irdp
->MaxAdvertInterval
);
354 DEFUN (ip_irdp_multicast
,
355 ip_irdp_multicast_cmd
,
358 "ICMP Router discovery on this interface\n"
359 "Use multicast mode\n")
361 VTY_DECLVAR_CONTEXT(interface
, ifp
);
363 irdp_if_start(ifp
, TRUE
, TRUE
);
367 DEFUN (ip_irdp_broadcast
,
368 ip_irdp_broadcast_cmd
,
371 "ICMP Router discovery on this interface\n"
372 "Use broadcast mode\n")
374 VTY_DECLVAR_CONTEXT(interface
, ifp
);
376 irdp_if_start(ifp
, FALSE
, TRUE
);
385 "Disable ICMP Router discovery on this interface\n")
387 VTY_DECLVAR_CONTEXT(interface
, ifp
);
393 DEFUN (ip_irdp_shutdown
,
394 ip_irdp_shutdown_cmd
,
397 "ICMP Router discovery on this interface\n"
398 "ICMP Router discovery shutdown on this interface\n")
400 VTY_DECLVAR_CONTEXT(interface
, ifp
);
402 irdp_if_shutdown(ifp
);
406 DEFUN (no_ip_irdp_shutdown
,
407 no_ip_irdp_shutdown_cmd
,
408 "no ip irdp shutdown",
411 "ICMP Router discovery on this interface\n"
412 "ICMP Router discovery no shutdown on this interface\n")
414 VTY_DECLVAR_CONTEXT(interface
, ifp
);
416 irdp_if_no_shutdown(ifp
);
420 DEFUN (ip_irdp_holdtime
,
421 ip_irdp_holdtime_cmd
,
422 "ip irdp holdtime (0-9000)",
424 "ICMP Router discovery on this interface\n"
425 "Set holdtime value\n"
426 "Holdtime value in seconds. Default is 1800 seconds\n")
429 VTY_DECLVAR_CONTEXT(interface
, ifp
);
431 struct irdp_interface
*irdp
;
436 irdp
->Lifetime
= atoi(argv
[idx_number
]->arg
);
440 DEFUN (ip_irdp_minadvertinterval
,
441 ip_irdp_minadvertinterval_cmd
,
442 "ip irdp minadvertinterval (3-1800)",
444 "ICMP Router discovery on this interface\n"
445 "Set minimum time between advertisement\n"
446 "Minimum advertisement interval in seconds\n")
449 VTY_DECLVAR_CONTEXT(interface
, ifp
);
451 struct irdp_interface
*irdp
;
456 if ((unsigned)atoi(argv
[idx_number
]->arg
) <= irdp
->MaxAdvertInterval
) {
457 irdp
->MinAdvertInterval
= atoi(argv
[idx_number
]->arg
);
461 "%% MinAdvertInterval must be less than or equal to "
462 "MaxAdvertInterval\n");
463 return CMD_WARNING_CONFIG_FAILED
;
467 DEFUN (ip_irdp_maxadvertinterval
,
468 ip_irdp_maxadvertinterval_cmd
,
469 "ip irdp maxadvertinterval (4-1800)",
471 "ICMP Router discovery on this interface\n"
472 "Set maximum time between advertisement\n"
473 "Maximum advertisement interval in seconds\n")
476 VTY_DECLVAR_CONTEXT(interface
, ifp
);
478 struct irdp_interface
*irdp
;
483 if (irdp
->MinAdvertInterval
<= (unsigned)atoi(argv
[idx_number
]->arg
)) {
484 irdp
->MaxAdvertInterval
= atoi(argv
[idx_number
]->arg
);
488 "%% MaxAdvertInterval must be greater than or equal to "
489 "MinAdvertInterval\n");
490 return CMD_WARNING_CONFIG_FAILED
;
494 /* DEFUN needs to be fixed for negative ranages...
495 * "ip irdp preference <-2147483648-2147483647>",
496 * Be positive for now. :-)
499 DEFUN (ip_irdp_preference
,
500 ip_irdp_preference_cmd
,
501 "ip irdp preference (0-2147483647)",
503 "ICMP Router discovery on this interface\n"
504 "Set default preference level for this interface\n"
505 "Preference level\n")
508 VTY_DECLVAR_CONTEXT(interface
, ifp
);
510 struct irdp_interface
*irdp
;
515 irdp
->Preference
= atoi(argv
[idx_number
]->arg
);
519 DEFUN (ip_irdp_address_preference
,
520 ip_irdp_address_preference_cmd
,
521 "ip irdp address A.B.C.D preference (0-2147483647)",
523 "Alter ICMP Router discovery preference on this interface\n"
524 "Set IRDP address for advertise\n"
526 "Specify IRDP non-default preference to advertise\n"
527 "Preference level\n")
531 VTY_DECLVAR_CONTEXT(interface
, ifp
);
532 struct listnode
*node
;
537 struct irdp_interface
*irdp
;
543 ret
= inet_aton(argv
[idx_ipv4
]->arg
, &ip
);
545 return CMD_WARNING_CONFIG_FAILED
;
547 pref
= atoi(argv
[idx_number
]->arg
);
549 for (ALL_LIST_ELEMENTS_RO(irdp
->AdvPrefList
, node
, adv
))
550 if (adv
->ip
.s_addr
== ip
.s_addr
)
556 listnode_add(irdp
->AdvPrefList
, adv
);
561 DEFUN (no_ip_irdp_address_preference
,
562 no_ip_irdp_address_preference_cmd
,
563 "no ip irdp address A.B.C.D preference (0-2147483647)",
566 "Alter ICMP Router discovery preference on this interface\n"
567 "Select IRDP address\n"
569 "Reset ICMP Router discovery preference on this interface\n"
570 "Old preference level\n")
573 VTY_DECLVAR_CONTEXT(interface
, ifp
);
574 struct listnode
*node
, *nnode
;
578 struct irdp_interface
*irdp
;
584 ret
= inet_aton(argv
[idx_ipv4
]->arg
, &ip
);
586 return CMD_WARNING_CONFIG_FAILED
;
588 for (ALL_LIST_ELEMENTS(irdp
->AdvPrefList
, node
, nnode
, adv
)) {
589 if (adv
->ip
.s_addr
== ip
.s_addr
) {
590 listnode_delete(irdp
->AdvPrefList
, adv
);
598 DEFUN (ip_irdp_debug_messages
,
599 ip_irdp_debug_messages_cmd
,
600 "ip irdp debug messages",
602 "ICMP Router discovery debug Averts. and Solicits (short)\n"
603 "IRDP debugging options\n"
604 "Enable debugging for IRDP messages\n")
606 VTY_DECLVAR_CONTEXT(interface
, ifp
);
608 struct irdp_interface
*irdp
;
613 irdp
->flags
|= IF_DEBUG_MESSAGES
;
618 DEFUN (ip_irdp_debug_misc
,
619 ip_irdp_debug_misc_cmd
,
620 "ip irdp debug misc",
622 "ICMP Router discovery debug Averts. and Solicits (short)\n"
623 "IRDP debugging options\n"
624 "Enable debugging for miscellaneous IRDP events\n")
626 VTY_DECLVAR_CONTEXT(interface
, ifp
);
628 struct irdp_interface
*irdp
;
633 irdp
->flags
|= IF_DEBUG_MISC
;
638 DEFUN (ip_irdp_debug_packet
,
639 ip_irdp_debug_packet_cmd
,
640 "ip irdp debug packet",
642 "ICMP Router discovery debug Averts. and Solicits (short)\n"
643 "IRDP debugging options\n"
644 "Enable debugging for IRDP packets\n")
646 VTY_DECLVAR_CONTEXT(interface
, ifp
);
648 struct irdp_interface
*irdp
;
653 irdp
->flags
|= IF_DEBUG_PACKET
;
659 DEFUN (ip_irdp_debug_disable
,
660 ip_irdp_debug_disable_cmd
,
661 "ip irdp debug disable",
663 "ICMP Router discovery debug Averts. and Solicits (short)\n"
664 "IRDP debugging options\n"
665 "Disable debugging for all IRDP events\n")
667 VTY_DECLVAR_CONTEXT(interface
, ifp
);
669 struct irdp_interface
*irdp
;
674 irdp
->flags
&= ~IF_DEBUG_PACKET
;
675 irdp
->flags
&= ~IF_DEBUG_MESSAGES
;
676 irdp
->flags
&= ~IF_DEBUG_MISC
;
683 install_element(INTERFACE_NODE
, &ip_irdp_broadcast_cmd
);
684 install_element(INTERFACE_NODE
, &ip_irdp_multicast_cmd
);
685 install_element(INTERFACE_NODE
, &no_ip_irdp_cmd
);
686 install_element(INTERFACE_NODE
, &ip_irdp_shutdown_cmd
);
687 install_element(INTERFACE_NODE
, &no_ip_irdp_shutdown_cmd
);
688 install_element(INTERFACE_NODE
, &ip_irdp_holdtime_cmd
);
689 install_element(INTERFACE_NODE
, &ip_irdp_maxadvertinterval_cmd
);
690 install_element(INTERFACE_NODE
, &ip_irdp_minadvertinterval_cmd
);
691 install_element(INTERFACE_NODE
, &ip_irdp_preference_cmd
);
692 install_element(INTERFACE_NODE
, &ip_irdp_address_preference_cmd
);
693 install_element(INTERFACE_NODE
, &no_ip_irdp_address_preference_cmd
);
695 install_element(INTERFACE_NODE
, &ip_irdp_debug_messages_cmd
);
696 install_element(INTERFACE_NODE
, &ip_irdp_debug_misc_cmd
);
697 install_element(INTERFACE_NODE
, &ip_irdp_debug_packet_cmd
);
698 install_element(INTERFACE_NODE
, &ip_irdp_debug_disable_cmd
);
701 #endif /* HAVE_IRDP */