1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 1997, 2000
6 * Swedish University of Agricultural Sciences
10 * Thanks to Jens Laas at Swedish University of Agricultural Sciences
11 * for reviewing and tests.
18 #include "sockunion.h"
24 #include "connected.h"
28 #include "lib_errors.h"
29 #include "zebra/interface.h"
30 #include "zebra/rtadv.h"
31 #include "zebra/rib.h"
32 #include "zebra/zebra_router.h"
33 #include "zebra/redistribute.h"
34 #include "zebra/irdp.h"
35 #include "zebra/zebra_errors.h"
36 #include <netinet/ip_icmp.h>
38 #include "sockunion.h"
44 DEFINE_MTYPE_STATIC(ZEBRA
, IRDP_IF
, "IRDP interface data");
46 #define IRDP_CONFIGED \
50 "Please Configure IRDP before using this command\n"); \
51 return CMD_WARNING_CONFIG_FAILED; \
55 static struct irdp_interface
*irdp_if_get(struct interface
*ifp
)
57 struct zebra_if
*zi
= ifp
->info
;
63 zi
->irdp
= XCALLOC(MTYPE_IRDP_IF
, sizeof(*zi
->irdp
));
65 if (!zi
->irdp
->started
)
71 static int irdp_if_delete(struct interface
*ifp
)
73 struct zebra_if
*zi
= ifp
->info
;
76 XFREE(MTYPE_IRDP_IF
, zi
->irdp
);
80 static const char *inet_2a(uint32_t a
, char *b
, size_t b_len
)
82 snprintf(b
, b_len
, "%u.%u.%u.%u", (a
)&0xFF, (a
>> 8) & 0xFF,
83 (a
>> 16) & 0xFF, (a
>> 24) & 0xFF);
88 static struct prefix
*irdp_get_prefix(struct interface
*ifp
)
90 struct listnode
*node
;
91 struct connected
*ifc
;
94 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
))
100 /* Join to the add/leave multicast group. */
101 static int if_group(struct interface
*ifp
, int sock
, uint32_t group
,
107 char b1
[INET_ADDRSTRLEN
];
109 memset(&m
, 0, sizeof(m
));
110 m
.imr_multiaddr
.s_addr
= htonl(group
);
111 p
= irdp_get_prefix(ifp
);
114 flog_warn(EC_ZEBRA_NO_IFACE_ADDR
,
115 "IRDP: can't get address for %s", ifp
->name
);
119 m
.imr_interface
= p
->u
.prefix4
;
121 ret
= setsockopt(sock
, IPPROTO_IP
, add_leave
, (char *)&m
,
122 sizeof(struct ip_mreq
));
124 flog_err_sys(EC_LIB_SOCKET
, "IRDP: %s can't setsockopt %s: %s",
125 add_leave
== IP_ADD_MEMBERSHIP
? "join group"
127 inet_2a(group
, b1
, sizeof(b1
)),
128 safe_strerror(errno
));
133 static int if_add_group(struct interface
*ifp
)
135 struct zebra_if
*zi
= ifp
->info
;
136 struct irdp_interface
*irdp
= zi
->irdp
;
138 char b1
[INET_ADDRSTRLEN
];
143 ret
= if_group(ifp
, irdp_sock
, INADDR_ALLRTRS_GROUP
, IP_ADD_MEMBERSHIP
);
148 if (irdp
->flags
& IF_DEBUG_MISC
)
149 zlog_debug("IRDP: Adding group %s for %s",
150 inet_2a(htonl(INADDR_ALLRTRS_GROUP
), b1
, sizeof(b1
)),
155 static int if_drop_group(struct interface
*ifp
)
157 struct zebra_if
*zi
= ifp
->info
;
158 struct irdp_interface
*irdp
= zi
->irdp
;
160 char b1
[INET_ADDRSTRLEN
];
165 ret
= if_group(ifp
, irdp_sock
, INADDR_ALLRTRS_GROUP
,
170 if (irdp
->flags
& IF_DEBUG_MISC
)
171 zlog_debug("IRDP: Leaving group %s for %s",
172 inet_2a(htonl(INADDR_ALLRTRS_GROUP
), b1
, sizeof(b1
)),
177 static void if_set_defaults(struct irdp_interface
*irdp
)
179 irdp
->MaxAdvertInterval
= IRDP_MAXADVERTINTERVAL
;
180 irdp
->MinAdvertInterval
= IRDP_MINADVERTINTERVAL
;
181 irdp
->Preference
= IRDP_PREFERENCE
;
182 irdp
->Lifetime
= IRDP_LIFETIME
;
186 static struct Adv
*Adv_new(void)
188 return XCALLOC(MTYPE_IRDP_IF
, sizeof(struct Adv
));
191 static void Adv_free(struct Adv
*adv
)
193 XFREE(MTYPE_IRDP_IF
, adv
);
196 static void irdp_if_start(struct interface
*ifp
, int multicast
,
199 struct zebra_if
*zi
= ifp
->info
;
200 struct irdp_interface
*irdp
= zi
->irdp
;
201 struct listnode
*node
;
202 struct connected
*ifc
;
203 uint32_t timer
, seed
;
207 irdp
->started
= true;
208 if (irdp
->flags
& IF_ACTIVE
) {
209 zlog_debug("IRDP: Interface is already active %s", ifp
->name
);
212 if ((irdp_sock
< 0) && ((irdp_sock
= irdp_sock_init()) < 0)) {
213 flog_warn(EC_ZEBRA_IRDP_CANNOT_ACTIVATE_IFACE
,
214 "IRDP: Cannot activate interface %s (cannot create IRDP socket)",
218 irdp
->flags
|= IF_ACTIVE
;
221 irdp
->flags
|= IF_BROADCAST
;
225 if (!(ifp
->flags
& IFF_UP
)) {
226 flog_warn(EC_ZEBRA_IRDP_IFACE_DOWN
,
227 "IRDP: Interface is down %s", ifp
->name
);
230 /* Shall we cancel if_start if if_add_group fails? */
235 if (!(ifp
->flags
& (IFF_MULTICAST
| IFF_ALLMULTI
))) {
236 flog_warn(EC_ZEBRA_IRDP_IFACE_MCAST_DISABLED
,
237 "IRDP: Interface not multicast enabled %s",
243 if_set_defaults(irdp
);
247 /* The spec suggests this for randomness */
251 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
252 seed
= ifc
->address
->u
.prefix4
.s_addr
;
257 timer
= (frr_weak_random() % IRDP_DEFAULT_INTERVAL
) + 1;
259 irdp
->AdvPrefList
= list_new();
260 irdp
->AdvPrefList
->del
= (void (*)(void *))Adv_free
; /* Destructor */
263 /* And this for startup. Speed limit from 1991 :-). But it's OK*/
265 if (irdp
->irdp_sent
< MAX_INITIAL_ADVERTISEMENTS
266 && timer
> MAX_INITIAL_ADVERT_INTERVAL
)
267 timer
= MAX_INITIAL_ADVERT_INTERVAL
;
270 if (irdp
->flags
& IF_DEBUG_MISC
)
271 zlog_debug("IRDP: Init timer for %s set to %u", ifp
->name
,
274 irdp
->t_advertise
= NULL
;
275 thread_add_timer(zrouter
.master
, irdp_send_thread
, ifp
, timer
,
279 static void irdp_if_stop(struct interface
*ifp
)
281 struct zebra_if
*zi
= ifp
->info
;
282 struct irdp_interface
*irdp
= zi
->irdp
;
285 zlog_debug("Interface %s structure is NULL", ifp
->name
);
289 if (!(irdp
->flags
& IF_ACTIVE
)) {
290 zlog_debug("Interface is not active %s", ifp
->name
);
294 if (!(irdp
->flags
& IF_BROADCAST
))
297 irdp_advert_off(ifp
);
299 list_delete(&irdp
->AdvPrefList
);
305 static void irdp_if_shutdown(struct interface
*ifp
)
307 struct zebra_if
*zi
= ifp
->info
;
308 struct irdp_interface
*irdp
= zi
->irdp
;
313 if (irdp
->flags
& IF_SHUTDOWN
) {
314 zlog_debug("IRDP: Interface is already shutdown %s", ifp
->name
);
318 irdp
->flags
|= IF_SHUTDOWN
;
319 irdp
->flags
&= ~IF_ACTIVE
;
321 if (!(irdp
->flags
& IF_BROADCAST
))
324 /* Tell the hosts we are out of service */
325 irdp_advert_off(ifp
);
328 static void irdp_if_no_shutdown(struct interface
*ifp
)
330 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
335 if (!(irdp
->flags
& IF_SHUTDOWN
)) {
336 zlog_debug("IRDP: Interface is not shutdown %s", ifp
->name
);
340 irdp
->flags
&= ~IF_SHUTDOWN
;
342 irdp_if_start(ifp
, irdp
->flags
& IF_BROADCAST
? false : true, false);
346 /* Write configuration to user */
348 int irdp_config_write(struct vty
*vty
, struct interface
*ifp
)
350 struct zebra_if
*zi
= ifp
->info
;
351 struct irdp_interface
*irdp
= zi
->irdp
;
353 struct listnode
*node
;
354 char b1
[INET_ADDRSTRLEN
];
359 if (irdp
->flags
& IF_ACTIVE
|| irdp
->flags
& IF_SHUTDOWN
) {
361 if (irdp
->flags
& IF_SHUTDOWN
)
362 vty_out(vty
, " ip irdp shutdown \n");
364 if (irdp
->flags
& IF_BROADCAST
)
365 vty_out(vty
, " ip irdp broadcast\n");
367 vty_out(vty
, " ip irdp multicast\n");
369 vty_out(vty
, " ip irdp preference %ld\n", irdp
->Preference
);
371 for (ALL_LIST_ELEMENTS_RO(irdp
->AdvPrefList
, node
, adv
))
372 vty_out(vty
, " ip irdp address %s preference %d\n",
373 inet_2a(adv
->ip
.s_addr
, b1
, sizeof(b1
)),
376 vty_out(vty
, " ip irdp holdtime %d\n", irdp
->Lifetime
);
378 vty_out(vty
, " ip irdp minadvertinterval %ld\n",
379 irdp
->MinAdvertInterval
);
381 vty_out(vty
, " ip irdp maxadvertinterval %ld\n",
382 irdp
->MaxAdvertInterval
);
388 DEFUN (ip_irdp_multicast
,
389 ip_irdp_multicast_cmd
,
392 "ICMP Router discovery on this interface\n"
393 "Use multicast mode\n")
395 VTY_DECLVAR_CONTEXT(interface
, ifp
);
398 irdp_if_start(ifp
, true, true);
402 DEFUN (ip_irdp_broadcast
,
403 ip_irdp_broadcast_cmd
,
406 "ICMP Router discovery on this interface\n"
407 "Use broadcast mode\n")
409 VTY_DECLVAR_CONTEXT(interface
, ifp
);
412 irdp_if_start(ifp
, false, true);
421 "Disable ICMP Router discovery on this interface\n")
423 VTY_DECLVAR_CONTEXT(interface
, ifp
);
429 DEFUN (ip_irdp_shutdown
,
430 ip_irdp_shutdown_cmd
,
433 "ICMP Router discovery on this interface\n"
434 "ICMP Router discovery shutdown on this interface\n")
436 VTY_DECLVAR_CONTEXT(interface
, ifp
);
438 irdp_if_shutdown(ifp
);
442 DEFUN (no_ip_irdp_shutdown
,
443 no_ip_irdp_shutdown_cmd
,
444 "no ip irdp shutdown",
447 "ICMP Router discovery on this interface\n"
448 "ICMP Router discovery no shutdown on this interface\n")
450 VTY_DECLVAR_CONTEXT(interface
, ifp
);
452 irdp_if_no_shutdown(ifp
);
456 DEFUN (ip_irdp_holdtime
,
457 ip_irdp_holdtime_cmd
,
458 "ip irdp holdtime (0-9000)",
460 "ICMP Router discovery on this interface\n"
461 "Set holdtime value\n"
462 "Holdtime value in seconds. Default is 1800 seconds\n")
465 VTY_DECLVAR_CONTEXT(interface
, ifp
);
466 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
470 irdp
->Lifetime
= atoi(argv
[idx_number
]->arg
);
474 DEFUN (ip_irdp_minadvertinterval
,
475 ip_irdp_minadvertinterval_cmd
,
476 "ip irdp minadvertinterval (3-1800)",
478 "ICMP Router discovery on this interface\n"
479 "Set minimum time between advertisement\n"
480 "Minimum advertisement interval in seconds\n")
483 VTY_DECLVAR_CONTEXT(interface
, ifp
);
484 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
488 if ((unsigned)atoi(argv
[idx_number
]->arg
) <= irdp
->MaxAdvertInterval
) {
489 irdp
->MinAdvertInterval
= atoi(argv
[idx_number
]->arg
);
493 "%% MinAdvertInterval must be less than or equal to MaxAdvertInterval\n");
494 return CMD_WARNING_CONFIG_FAILED
;
498 DEFUN (ip_irdp_maxadvertinterval
,
499 ip_irdp_maxadvertinterval_cmd
,
500 "ip irdp maxadvertinterval (4-1800)",
502 "ICMP Router discovery on this interface\n"
503 "Set maximum time between advertisement\n"
504 "Maximum advertisement interval in seconds\n")
507 VTY_DECLVAR_CONTEXT(interface
, ifp
);
508 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
512 if (irdp
->MinAdvertInterval
<= (unsigned)atoi(argv
[idx_number
]->arg
)) {
513 irdp
->MaxAdvertInterval
= atoi(argv
[idx_number
]->arg
);
517 "%% MaxAdvertInterval must be greater than or equal to MinAdvertInterval\n");
518 return CMD_WARNING_CONFIG_FAILED
;
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
);
537 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
541 irdp
->Preference
= atoi(argv
[idx_number
]->arg
);
545 DEFUN (ip_irdp_address_preference
,
546 ip_irdp_address_preference_cmd
,
547 "ip irdp address A.B.C.D preference (0-2147483647)",
549 "Alter ICMP Router discovery preference on this interface\n"
550 "Set IRDP address for advertise\n"
552 "Specify IRDP non-default preference to advertise\n"
553 "Preference level\n")
557 VTY_DECLVAR_CONTEXT(interface
, ifp
);
558 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
559 struct listnode
*node
;
567 ret
= inet_aton(argv
[idx_ipv4
]->arg
, &ip
);
569 return CMD_WARNING_CONFIG_FAILED
;
571 pref
= atoi(argv
[idx_number
]->arg
);
573 for (ALL_LIST_ELEMENTS_RO(irdp
->AdvPrefList
, node
, adv
))
574 if (adv
->ip
.s_addr
== ip
.s_addr
)
580 listnode_add(irdp
->AdvPrefList
, adv
);
585 DEFUN (no_ip_irdp_address_preference
,
586 no_ip_irdp_address_preference_cmd
,
587 "no ip irdp address A.B.C.D preference (0-2147483647)",
590 "Alter ICMP Router discovery preference on this interface\n"
591 "Select IRDP address\n"
593 "Reset ICMP Router discovery preference on this interface\n"
594 "Old preference level\n")
597 VTY_DECLVAR_CONTEXT(interface
, ifp
);
598 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
599 struct listnode
*node
, *nnode
;
606 ret
= inet_aton(argv
[idx_ipv4
]->arg
, &ip
);
608 return CMD_WARNING_CONFIG_FAILED
;
610 for (ALL_LIST_ELEMENTS(irdp
->AdvPrefList
, node
, nnode
, adv
)) {
611 if (adv
->ip
.s_addr
== ip
.s_addr
) {
612 listnode_delete(irdp
->AdvPrefList
, adv
);
620 DEFUN (ip_irdp_debug_messages
,
621 ip_irdp_debug_messages_cmd
,
622 "ip irdp debug messages",
624 "ICMP Router discovery debug Averts. and Solicits (short)\n"
625 "IRDP debugging options\n"
626 "Enable debugging for IRDP messages\n")
628 VTY_DECLVAR_CONTEXT(interface
, ifp
);
629 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
633 irdp
->flags
|= IF_DEBUG_MESSAGES
;
638 DEFUN (ip_irdp_debug_misc
,
639 ip_irdp_debug_misc_cmd
,
640 "ip irdp debug misc",
642 "ICMP Router discovery debug Averts. and Solicits (short)\n"
643 "IRDP debugging options\n"
644 "Enable debugging for miscellaneous IRDP events\n")
646 VTY_DECLVAR_CONTEXT(interface
, ifp
);
647 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
651 irdp
->flags
|= IF_DEBUG_MISC
;
656 DEFUN (ip_irdp_debug_packet
,
657 ip_irdp_debug_packet_cmd
,
658 "ip irdp debug packet",
660 "ICMP Router discovery debug Averts. and Solicits (short)\n"
661 "IRDP debugging options\n"
662 "Enable debugging for IRDP packets\n")
664 VTY_DECLVAR_CONTEXT(interface
, ifp
);
665 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
669 irdp
->flags
|= IF_DEBUG_PACKET
;
675 DEFUN (ip_irdp_debug_disable
,
676 ip_irdp_debug_disable_cmd
,
677 "ip irdp debug disable",
679 "ICMP Router discovery debug Averts. and Solicits (short)\n"
680 "IRDP debugging options\n"
681 "Disable debugging for all IRDP events\n")
683 VTY_DECLVAR_CONTEXT(interface
, ifp
);
684 struct irdp_interface
*irdp
= irdp_if_get(ifp
);
688 irdp
->flags
&= ~IF_DEBUG_PACKET
;
689 irdp
->flags
&= ~IF_DEBUG_MESSAGES
;
690 irdp
->flags
&= ~IF_DEBUG_MISC
;
695 void irdp_if_init(void)
697 hook_register(zebra_if_config_wr
, irdp_config_write
);
698 hook_register(if_del
, irdp_if_delete
);
700 install_element(INTERFACE_NODE
, &ip_irdp_broadcast_cmd
);
701 install_element(INTERFACE_NODE
, &ip_irdp_multicast_cmd
);
702 install_element(INTERFACE_NODE
, &no_ip_irdp_cmd
);
703 install_element(INTERFACE_NODE
, &ip_irdp_shutdown_cmd
);
704 install_element(INTERFACE_NODE
, &no_ip_irdp_shutdown_cmd
);
705 install_element(INTERFACE_NODE
, &ip_irdp_holdtime_cmd
);
706 install_element(INTERFACE_NODE
, &ip_irdp_maxadvertinterval_cmd
);
707 install_element(INTERFACE_NODE
, &ip_irdp_minadvertinterval_cmd
);
708 install_element(INTERFACE_NODE
, &ip_irdp_preference_cmd
);
709 install_element(INTERFACE_NODE
, &ip_irdp_address_preference_cmd
);
710 install_element(INTERFACE_NODE
, &no_ip_irdp_address_preference_cmd
);
712 install_element(INTERFACE_NODE
, &ip_irdp_debug_messages_cmd
);
713 install_element(INTERFACE_NODE
, &ip_irdp_debug_misc_cmd
);
714 install_element(INTERFACE_NODE
, &ip_irdp_debug_packet_cmd
);
715 install_element(INTERFACE_NODE
, &ip_irdp_debug_disable_cmd
);