]> git.proxmox.com Git - mirror_frr.git/blob - zebra/irdp_interface.c
merge with upstream
[mirror_frr.git] / zebra / irdp_interface.c
1 /*
2 *
3 * Copyright (C) 2000 Robert Olsson.
4 * Swedish University of Agricultural Sciences
5 *
6 * This file is part of GNU Zebra.
7 *
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
11 * later version.
12 *
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.
17 *
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
21 */
22
23 /*
24 * This work includes work with the following copywrite:
25 *
26 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
27 *
28 */
29
30 /*
31 * Thanks to Jens Låås at Swedish University of Agricultural Sciences
32 * for reviewing and tests.
33 */
34
35
36 #include <zebra.h>
37
38 #ifdef HAVE_IRDP
39
40 #include "if.h"
41 #include "vty.h"
42 #include "sockunion.h"
43 #include "prefix.h"
44 #include "command.h"
45 #include "memory.h"
46 #include "zebra_memory.h"
47 #include "stream.h"
48 #include "ioctl.h"
49 #include "connected.h"
50 #include "log.h"
51 #include "zclient.h"
52 #include "thread.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>
60 #include "if.h"
61 #include "sockunion.h"
62 #include "log.h"
63
64 extern int irdp_sock;
65
66 static const char *inet_2a(u_int32_t a, char *b)
67 {
68 sprintf(b, "%u.%u.%u.%u", (a)&0xFF, (a >> 8) & 0xFF, (a >> 16) & 0xFF,
69 (a >> 24) & 0xFF);
70 return b;
71 }
72
73
74 static struct prefix *irdp_get_prefix(struct interface *ifp)
75 {
76 struct listnode *node;
77 struct connected *ifc;
78
79 if (ifp->connected)
80 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
81 return ifc->address;
82
83 return NULL;
84 }
85
86 /* Join to the add/leave multicast group. */
87 static int if_group(struct interface *ifp, int sock, u_int32_t group,
88 int add_leave)
89 {
90 struct ip_mreq m;
91 struct prefix *p;
92 int ret;
93 char b1[INET_ADDRSTRLEN];
94
95 memset(&m, 0, sizeof(m));
96 m.imr_multiaddr.s_addr = htonl(group);
97 p = irdp_get_prefix(ifp);
98
99 if (!p) {
100 zlog_warn("IRDP: can't get address for %s", ifp->name);
101 return 1;
102 }
103
104 m.imr_interface = p->u.prefix4;
105
106 ret = setsockopt(sock, IPPROTO_IP, add_leave, (char *)&m,
107 sizeof(struct ip_mreq));
108 if (ret < 0)
109 zlog_warn("IRDP: %s can't setsockopt %s: %s",
110 add_leave == IP_ADD_MEMBERSHIP ? "join group"
111 : "leave group",
112 inet_2a(group, b1), safe_strerror(errno));
113
114 return ret;
115 }
116
117 static int if_add_group(struct interface *ifp)
118 {
119 struct zebra_if *zi = ifp->info;
120 struct irdp_interface *irdp = &zi->irdp;
121 int ret;
122 char b1[INET_ADDRSTRLEN];
123
124 ret = if_group(ifp, irdp_sock, INADDR_ALLRTRS_GROUP, IP_ADD_MEMBERSHIP);
125 if (ret < 0) {
126 return ret;
127 }
128
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);
132 return 0;
133 }
134
135 static int if_drop_group(struct interface *ifp)
136 {
137 struct zebra_if *zi = ifp->info;
138 struct irdp_interface *irdp = &zi->irdp;
139 int ret;
140 char b1[INET_ADDRSTRLEN];
141
142 ret = if_group(ifp, irdp_sock, INADDR_ALLRTRS_GROUP,
143 IP_DROP_MEMBERSHIP);
144 if (ret < 0)
145 return ret;
146
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);
150 return 0;
151 }
152
153 static void if_set_defaults(struct interface *ifp)
154 {
155 struct zebra_if *zi = ifp->info;
156 struct irdp_interface *irdp = &zi->irdp;
157
158 irdp->MaxAdvertInterval = IRDP_MAXADVERTINTERVAL;
159 irdp->MinAdvertInterval = IRDP_MINADVERTINTERVAL;
160 irdp->Preference = IRDP_PREFERENCE;
161 irdp->Lifetime = IRDP_LIFETIME;
162 }
163
164
165 static struct Adv *Adv_new(void)
166 {
167 return XCALLOC(MTYPE_TMP, sizeof(struct Adv));
168 }
169
170 static void Adv_free(struct Adv *adv)
171 {
172 XFREE(MTYPE_TMP, adv);
173 }
174
175 static void irdp_if_start(struct interface *ifp, int multicast,
176 int set_defaults)
177 {
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;
183
184 if (irdp->flags & IF_ACTIVE) {
185 zlog_warn("IRDP: Interface is already active %s", ifp->name);
186 return;
187 }
188 if ((irdp_sock < 0) && ((irdp_sock = irdp_sock_init()) < 0)) {
189 zlog_warn(
190 "IRDP: Cannot activate interface %s (cannot create "
191 "IRDP socket)",
192 ifp->name);
193 return;
194 }
195 irdp->flags |= IF_ACTIVE;
196
197 if (!multicast)
198 irdp->flags |= IF_BROADCAST;
199
200 if_add_update(ifp);
201
202 if (!(ifp->flags & IFF_UP)) {
203 zlog_warn("IRDP: Interface is down %s", ifp->name);
204 }
205
206 /* Shall we cancel if_start if if_add_group fails? */
207
208 if (multicast) {
209 if_add_group(ifp);
210
211 if (!(ifp->flags & (IFF_MULTICAST | IFF_ALLMULTI))) {
212 zlog_warn("IRDP: Interface not multicast enabled %s",
213 ifp->name);
214 }
215 }
216
217 if (set_defaults)
218 if_set_defaults(ifp);
219
220 irdp->irdp_sent = 0;
221
222 /* The spec suggests this for randomness */
223
224 seed = 0;
225 if (ifp->connected)
226 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
227 seed = ifc->address->u.prefix4.s_addr;
228 break;
229 }
230
231 srandom(seed);
232 timer = (random() % IRDP_DEFAULT_INTERVAL) + 1;
233
234 irdp->AdvPrefList = list_new();
235 irdp->AdvPrefList->del = (void (*)(void *))Adv_free; /* Destructor */
236
237
238 /* And this for startup. Speed limit from 1991 :-). But it's OK*/
239
240 if (irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS
241 && timer > MAX_INITIAL_ADVERT_INTERVAL)
242 timer = MAX_INITIAL_ADVERT_INTERVAL;
243
244
245 if (irdp->flags & IF_DEBUG_MISC)
246 zlog_debug("IRDP: Init timer for %s set to %u", ifp->name,
247 timer);
248
249 irdp->t_advertise = NULL;
250 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
251 &irdp->t_advertise);
252 }
253
254 static void irdp_if_stop(struct interface *ifp)
255 {
256 struct zebra_if *zi = ifp->info;
257 struct irdp_interface *irdp = &zi->irdp;
258
259 if (irdp == NULL) {
260 zlog_warn("Interface %s structure is NULL", ifp->name);
261 return;
262 }
263
264 if (!(irdp->flags & IF_ACTIVE)) {
265 zlog_warn("Interface is not active %s", ifp->name);
266 return;
267 }
268
269 if (!(irdp->flags & IF_BROADCAST))
270 if_drop_group(ifp);
271
272 irdp_advert_off(ifp);
273
274 list_delete(irdp->AdvPrefList);
275 irdp->AdvPrefList = NULL;
276
277 irdp->flags = 0;
278 }
279
280
281 static void irdp_if_shutdown(struct interface *ifp)
282 {
283 struct zebra_if *zi = ifp->info;
284 struct irdp_interface *irdp = &zi->irdp;
285
286 if (irdp->flags & IF_SHUTDOWN) {
287 zlog_warn("IRDP: Interface is already shutdown %s", ifp->name);
288 return;
289 }
290
291 irdp->flags |= IF_SHUTDOWN;
292 irdp->flags &= ~IF_ACTIVE;
293
294 if (!(irdp->flags & IF_BROADCAST))
295 if_drop_group(ifp);
296
297 /* Tell the hosts we are out of service */
298 irdp_advert_off(ifp);
299 }
300
301 static void irdp_if_no_shutdown(struct interface *ifp)
302 {
303 struct zebra_if *zi = ifp->info;
304 struct irdp_interface *irdp = &zi->irdp;
305
306 if (!(irdp->flags & IF_SHUTDOWN)) {
307 zlog_warn("IRDP: Interface is not shutdown %s", ifp->name);
308 return;
309 }
310
311 irdp->flags &= ~IF_SHUTDOWN;
312
313 irdp_if_start(ifp, irdp->flags & IF_BROADCAST ? FALSE : TRUE, FALSE);
314 }
315
316
317 /* Write configuration to user */
318
319 void irdp_config_write(struct vty *vty, struct interface *ifp)
320 {
321 struct zebra_if *zi = ifp->info;
322 struct irdp_interface *irdp = &zi->irdp;
323 struct Adv *adv;
324 struct listnode *node;
325 char b1[INET_ADDRSTRLEN];
326
327 if (irdp->flags & IF_ACTIVE || irdp->flags & IF_SHUTDOWN) {
328
329 if (irdp->flags & IF_SHUTDOWN)
330 vty_out(vty, " ip irdp shutdown \n");
331
332 if (irdp->flags & IF_BROADCAST)
333 vty_out(vty, " ip irdp broadcast\n");
334 else
335 vty_out(vty, " ip irdp multicast\n");
336
337 vty_out(vty, " ip irdp preference %ld\n", irdp->Preference);
338
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);
342
343 vty_out(vty, " ip irdp holdtime %d\n", irdp->Lifetime);
344
345 vty_out(vty, " ip irdp minadvertinterval %ld\n",
346 irdp->MinAdvertInterval);
347
348 vty_out(vty, " ip irdp maxadvertinterval %ld\n",
349 irdp->MaxAdvertInterval);
350 }
351 }
352
353
354 DEFUN (ip_irdp_multicast,
355 ip_irdp_multicast_cmd,
356 "ip irdp multicast",
357 IP_STR
358 "ICMP Router discovery on this interface\n"
359 "Use multicast mode\n")
360 {
361 VTY_DECLVAR_CONTEXT(interface, ifp);
362
363 irdp_if_start(ifp, TRUE, TRUE);
364 return CMD_SUCCESS;
365 }
366
367 DEFUN (ip_irdp_broadcast,
368 ip_irdp_broadcast_cmd,
369 "ip irdp broadcast",
370 IP_STR
371 "ICMP Router discovery on this interface\n"
372 "Use broadcast mode\n")
373 {
374 VTY_DECLVAR_CONTEXT(interface, ifp);
375
376 irdp_if_start(ifp, FALSE, TRUE);
377 return CMD_SUCCESS;
378 }
379
380 DEFUN (no_ip_irdp,
381 no_ip_irdp_cmd,
382 "no ip irdp",
383 NO_STR
384 IP_STR
385 "Disable ICMP Router discovery on this interface\n")
386 {
387 VTY_DECLVAR_CONTEXT(interface, ifp);
388
389 irdp_if_stop(ifp);
390 return CMD_SUCCESS;
391 }
392
393 DEFUN (ip_irdp_shutdown,
394 ip_irdp_shutdown_cmd,
395 "ip irdp shutdown",
396 IP_STR
397 "ICMP Router discovery on this interface\n"
398 "ICMP Router discovery shutdown on this interface\n")
399 {
400 VTY_DECLVAR_CONTEXT(interface, ifp);
401
402 irdp_if_shutdown(ifp);
403 return CMD_SUCCESS;
404 }
405
406 DEFUN (no_ip_irdp_shutdown,
407 no_ip_irdp_shutdown_cmd,
408 "no ip irdp shutdown",
409 NO_STR
410 IP_STR
411 "ICMP Router discovery on this interface\n"
412 "ICMP Router discovery no shutdown on this interface\n")
413 {
414 VTY_DECLVAR_CONTEXT(interface, ifp);
415
416 irdp_if_no_shutdown(ifp);
417 return CMD_SUCCESS;
418 }
419
420 DEFUN (ip_irdp_holdtime,
421 ip_irdp_holdtime_cmd,
422 "ip irdp holdtime (0-9000)",
423 IP_STR
424 "ICMP Router discovery on this interface\n"
425 "Set holdtime value\n"
426 "Holdtime value in seconds. Default is 1800 seconds\n")
427 {
428 int idx_number = 3;
429 VTY_DECLVAR_CONTEXT(interface, ifp);
430 struct zebra_if *zi;
431 struct irdp_interface *irdp;
432
433 zi = ifp->info;
434 irdp = &zi->irdp;
435
436 irdp->Lifetime = atoi(argv[idx_number]->arg);
437 return CMD_SUCCESS;
438 }
439
440 DEFUN (ip_irdp_minadvertinterval,
441 ip_irdp_minadvertinterval_cmd,
442 "ip irdp minadvertinterval (3-1800)",
443 IP_STR
444 "ICMP Router discovery on this interface\n"
445 "Set minimum time between advertisement\n"
446 "Minimum advertisement interval in seconds\n")
447 {
448 int idx_number = 3;
449 VTY_DECLVAR_CONTEXT(interface, ifp);
450 struct zebra_if *zi;
451 struct irdp_interface *irdp;
452
453 zi = ifp->info;
454 irdp = &zi->irdp;
455
456 if ((unsigned)atoi(argv[idx_number]->arg) <= irdp->MaxAdvertInterval) {
457 irdp->MinAdvertInterval = atoi(argv[idx_number]->arg);
458 return CMD_SUCCESS;
459 } else {
460 vty_out(vty,
461 "%% MinAdvertInterval must be less than or equal to "
462 "MaxAdvertInterval\n");
463 return CMD_WARNING_CONFIG_FAILED;
464 }
465 }
466
467 DEFUN (ip_irdp_maxadvertinterval,
468 ip_irdp_maxadvertinterval_cmd,
469 "ip irdp maxadvertinterval (4-1800)",
470 IP_STR
471 "ICMP Router discovery on this interface\n"
472 "Set maximum time between advertisement\n"
473 "Maximum advertisement interval in seconds\n")
474 {
475 int idx_number = 3;
476 VTY_DECLVAR_CONTEXT(interface, ifp);
477 struct zebra_if *zi;
478 struct irdp_interface *irdp;
479
480 zi = ifp->info;
481 irdp = &zi->irdp;
482
483 if (irdp->MinAdvertInterval <= (unsigned)atoi(argv[idx_number]->arg)) {
484 irdp->MaxAdvertInterval = atoi(argv[idx_number]->arg);
485 return CMD_SUCCESS;
486 } else {
487 vty_out(vty,
488 "%% MaxAdvertInterval must be greater than or equal to "
489 "MinAdvertInterval\n");
490 return CMD_WARNING_CONFIG_FAILED;
491 }
492 }
493
494 /* DEFUN needs to be fixed for negative ranages...
495 * "ip irdp preference <-2147483648-2147483647>",
496 * Be positive for now. :-)
497 */
498
499 DEFUN (ip_irdp_preference,
500 ip_irdp_preference_cmd,
501 "ip irdp preference (0-2147483647)",
502 IP_STR
503 "ICMP Router discovery on this interface\n"
504 "Set default preference level for this interface\n"
505 "Preference level\n")
506 {
507 int idx_number = 3;
508 VTY_DECLVAR_CONTEXT(interface, ifp);
509 struct zebra_if *zi;
510 struct irdp_interface *irdp;
511
512 zi = ifp->info;
513 irdp = &zi->irdp;
514
515 irdp->Preference = atoi(argv[idx_number]->arg);
516 return CMD_SUCCESS;
517 }
518
519 DEFUN (ip_irdp_address_preference,
520 ip_irdp_address_preference_cmd,
521 "ip irdp address A.B.C.D preference (0-2147483647)",
522 IP_STR
523 "Alter ICMP Router discovery preference on this interface\n"
524 "Set IRDP address for advertise\n"
525 "IPv4 address\n"
526 "Specify IRDP non-default preference to advertise\n"
527 "Preference level\n")
528 {
529 int idx_ipv4 = 3;
530 int idx_number = 5;
531 VTY_DECLVAR_CONTEXT(interface, ifp);
532 struct listnode *node;
533 struct in_addr ip;
534 int pref;
535 int ret;
536 struct zebra_if *zi;
537 struct irdp_interface *irdp;
538 struct Adv *adv;
539
540 zi = ifp->info;
541 irdp = &zi->irdp;
542
543 ret = inet_aton(argv[idx_ipv4]->arg, &ip);
544 if (!ret)
545 return CMD_WARNING_CONFIG_FAILED;
546
547 pref = atoi(argv[idx_number]->arg);
548
549 for (ALL_LIST_ELEMENTS_RO(irdp->AdvPrefList, node, adv))
550 if (adv->ip.s_addr == ip.s_addr)
551 return CMD_SUCCESS;
552
553 adv = Adv_new();
554 adv->ip = ip;
555 adv->pref = pref;
556 listnode_add(irdp->AdvPrefList, adv);
557
558 return CMD_SUCCESS;
559 }
560
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)",
564 NO_STR
565 IP_STR
566 "Alter ICMP Router discovery preference on this interface\n"
567 "Select IRDP address\n"
568 "IPv4 address\n"
569 "Reset ICMP Router discovery preference on this interface\n"
570 "Old preference level\n")
571 {
572 int idx_ipv4 = 4;
573 VTY_DECLVAR_CONTEXT(interface, ifp);
574 struct listnode *node, *nnode;
575 struct in_addr ip;
576 int ret;
577 struct zebra_if *zi;
578 struct irdp_interface *irdp;
579 struct Adv *adv;
580
581 zi = ifp->info;
582 irdp = &zi->irdp;
583
584 ret = inet_aton(argv[idx_ipv4]->arg, &ip);
585 if (!ret)
586 return CMD_WARNING_CONFIG_FAILED;
587
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);
591 break;
592 }
593 }
594
595 return CMD_SUCCESS;
596 }
597
598 DEFUN (ip_irdp_debug_messages,
599 ip_irdp_debug_messages_cmd,
600 "ip irdp debug messages",
601 IP_STR
602 "ICMP Router discovery debug Averts. and Solicits (short)\n"
603 "IRDP debugging options\n"
604 "Enable debugging for IRDP messages\n")
605 {
606 VTY_DECLVAR_CONTEXT(interface, ifp);
607 struct zebra_if *zi;
608 struct irdp_interface *irdp;
609
610 zi = ifp->info;
611 irdp = &zi->irdp;
612
613 irdp->flags |= IF_DEBUG_MESSAGES;
614
615 return CMD_SUCCESS;
616 }
617
618 DEFUN (ip_irdp_debug_misc,
619 ip_irdp_debug_misc_cmd,
620 "ip irdp debug misc",
621 IP_STR
622 "ICMP Router discovery debug Averts. and Solicits (short)\n"
623 "IRDP debugging options\n"
624 "Enable debugging for miscellaneous IRDP events\n")
625 {
626 VTY_DECLVAR_CONTEXT(interface, ifp);
627 struct zebra_if *zi;
628 struct irdp_interface *irdp;
629
630 zi = ifp->info;
631 irdp = &zi->irdp;
632
633 irdp->flags |= IF_DEBUG_MISC;
634
635 return CMD_SUCCESS;
636 }
637
638 DEFUN (ip_irdp_debug_packet,
639 ip_irdp_debug_packet_cmd,
640 "ip irdp debug packet",
641 IP_STR
642 "ICMP Router discovery debug Averts. and Solicits (short)\n"
643 "IRDP debugging options\n"
644 "Enable debugging for IRDP packets\n")
645 {
646 VTY_DECLVAR_CONTEXT(interface, ifp);
647 struct zebra_if *zi;
648 struct irdp_interface *irdp;
649
650 zi = ifp->info;
651 irdp = &zi->irdp;
652
653 irdp->flags |= IF_DEBUG_PACKET;
654
655 return CMD_SUCCESS;
656 }
657
658
659 DEFUN (ip_irdp_debug_disable,
660 ip_irdp_debug_disable_cmd,
661 "ip irdp debug disable",
662 IP_STR
663 "ICMP Router discovery debug Averts. and Solicits (short)\n"
664 "IRDP debugging options\n"
665 "Disable debugging for all IRDP events\n")
666 {
667 VTY_DECLVAR_CONTEXT(interface, ifp);
668 struct zebra_if *zi;
669 struct irdp_interface *irdp;
670
671 zi = ifp->info;
672 irdp = &zi->irdp;
673
674 irdp->flags &= ~IF_DEBUG_PACKET;
675 irdp->flags &= ~IF_DEBUG_MESSAGES;
676 irdp->flags &= ~IF_DEBUG_MISC;
677
678 return CMD_SUCCESS;
679 }
680
681 void irdp_init()
682 {
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);
694
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);
699 }
700
701 #endif /* HAVE_IRDP */