]> git.proxmox.com Git - mirror_frr.git/blame - babeld/babel_interface.c
babeld: justify "running-config" meaning in CLI
[mirror_frr.git] / babeld / babel_interface.c
CommitLineData
5734509c
PJ
1/*
2 * This file is free software: you may copy, redistribute and/or modify it
3 * under the terms of the GNU General Public License as published by the
4 * Free Software Foundation, either version 2 of the License, or (at your
5 * option) any later version.
6 *
7 * This file is distributed in the hope that it will be useful, but
8 * WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * This file incorporates work covered by the following copyright and
16 * permission notice:
17 *
18
19Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
20
21Permission is hereby granted, free of charge, to any person obtaining a copy
22of this software and associated documentation files (the "Software"), to deal
23in the Software without restriction, including without limitation the rights
24to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25copies of the Software, and to permit persons to whom the Software is
26furnished to do so, subject to the following conditions:
27
28The above copyright notice and this permission notice shall be included in
29all copies or substantial portions of the Software.
30
31THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37THE SOFTWARE.
38*/
39
5734509c
PJ
40#include <zebra.h>
41#include "memory.h"
42#include "log.h"
43#include "command.h"
44#include "prefix.h"
45#include "vector.h"
d3351d1e 46#include "distribute.h"
5734509c
PJ
47
48#include "babel_main.h"
49#include "util.h"
50#include "kernel.h"
51#include "babel_interface.h"
52#include "message.h"
53#include "route.h"
54#include "babel_zebra.h"
297a55ba 55#include "neighbour.h"
1f39f466
MB
56#include "route.h"
57#include "xroute.h"
5734509c
PJ
58
59
8c4e57a5
MB
60#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
61
5734509c
PJ
62static int babel_enable_if_lookup (const char *ifname);
63static int babel_enable_if_add (const char *ifname);
64static int babel_enable_if_delete (const char *ifname);
65static int interface_recalculate(struct interface *ifp);
66static int interface_reset(struct interface *ifp);
67static int babel_if_new_hook (struct interface *ifp);
68static int babel_if_delete_hook (struct interface *ifp);
69static int interface_config_write (struct vty *vty);
c7c53fa8 70static babel_interface_nfo * babel_interface_allocate (void);
5734509c
PJ
71static void babel_interface_free (babel_interface_nfo *bi);
72
73
74static vector babel_enable_if; /* enable interfaces (by cmd). */
75static struct cmd_node babel_interface_node = /* babeld's interface node. */
76{
77 INTERFACE_NODE,
78 "%s(config-if)# ",
79 1 /* VTYSH */
80};
81
82
83int
84babel_interface_up (int cmd, struct zclient *client, zebra_size_t length)
85{
86 struct stream *s = NULL;
87 struct interface *ifp = NULL;
88
89 debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
90
91 s = zclient->ibuf;
8c4e57a5 92 ifp = zebra_interface_state_read(s); /* it updates iflist */
5734509c
PJ
93
94 if (ifp == NULL) {
95 return 0;
96 }
97
98 interface_recalculate(ifp);
99 return 0;
100}
101
102int
103babel_interface_down (int cmd, struct zclient *client, zebra_size_t length)
104{
105 struct stream *s = NULL;
106 struct interface *ifp = NULL;
107
108 debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
109
110 s = zclient->ibuf;
8c4e57a5 111 ifp = zebra_interface_state_read(s); /* it updates iflist */
5734509c
PJ
112
113 if (ifp == NULL) {
114 return 0;
115 }
116
117 interface_reset(ifp);
118 return 0;
119}
120
121int
122babel_interface_add (int cmd, struct zclient *client, zebra_size_t length)
123{
124 struct interface *ifp = NULL;
125
126 debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
127
128 /* read and add the interface in the iflist. */
129 ifp = zebra_interface_add_read (zclient->ibuf);
130
131 if (ifp == NULL) {
132 return 0;
133 }
134
135 interface_recalculate(ifp);
5734509c
PJ
136 return 0;
137}
138
139int
140babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length)
141{
8c4e57a5
MB
142 struct interface *ifp;
143 struct stream *s;
144
5734509c 145 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
8c4e57a5
MB
146
147 s = zclient->ibuf;
148 ifp = zebra_interface_state_read(s); /* it updates iflist */
149
150 if (ifp == NULL)
151 return 0;
152
153 if (IS_ENABLE(ifp))
154 interface_reset(ifp);
155
156 /* To support pseudo interface do not free interface structure. */
157 /* if_delete(ifp); */
158 ifp->ifindex = IFINDEX_INTERNAL;
159
5734509c
PJ
160 return 0;
161}
162
163int
164babel_interface_address_add (int cmd, struct zclient *client,
165 zebra_size_t length)
166{
167 babel_interface_nfo *babel_ifp;
168 struct connected *ifc;
169 struct prefix *prefix;
170
171 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
172
173 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
174 zclient->ibuf);
175
176 if (ifc == NULL)
177 return 0;
178
179 prefix = ifc->address;
180
181 if (prefix->family == AF_INET) {
182 flush_interface_routes(ifc->ifp, 0);
183 babel_ifp = babel_get_if_nfo(ifc->ifp);
184 if (babel_ifp->ipv4 == NULL) {
185 babel_ifp->ipv4 = malloc(4);
186 if (babel_ifp->ipv4 == NULL) {
187 zlog_err("not einough memory");
188 } else {
189 memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
190 }
191 }
192 }
193
194 send_request(ifc->ifp, NULL, 0);
195 send_update(ifc->ifp, 0, NULL, 0);
196
197 return 0;
198}
199
200int
201babel_interface_address_delete (int cmd, struct zclient *client,
202 zebra_size_t length)
203{
204 babel_interface_nfo *babel_ifp;
205 struct connected *ifc;
206 struct prefix *prefix;
207
208 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
209
210 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
211 zclient->ibuf);
212
213 if (ifc == NULL)
214 return 0;
215
216 prefix = ifc->address;
217
218 if (prefix->family == AF_INET) {
219 flush_interface_routes(ifc->ifp, 0);
220 babel_ifp = babel_get_if_nfo(ifc->ifp);
221 if (babel_ifp->ipv4 != NULL
222 && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) {
223 free(babel_ifp->ipv4);
224 babel_ifp->ipv4 = NULL;
225 }
226 }
227
228 send_request(ifc->ifp, NULL, 0);
229 send_update(ifc->ifp, 0, NULL, 0);
230
231 return 0;
232}
233
234/* Lookup function. */
235static int
236babel_enable_if_lookup (const char *ifname)
237{
238 unsigned int i;
239 char *str;
240
241 for (i = 0; i < vector_active (babel_enable_if); i++)
242 if ((str = vector_slot (babel_enable_if, i)) != NULL)
243 if (strcmp (str, ifname) == 0)
244 return i;
245 return -1;
246}
247
248/* Add interface to babel_enable_if. */
249static int
250babel_enable_if_add (const char *ifname)
251{
252 int ret;
253 struct interface *ifp = NULL;
254
255 ret = babel_enable_if_lookup (ifname);
256 if (ret >= 0)
257 return -1;
258
259 vector_set (babel_enable_if, strdup (ifname));
260
261 ifp = if_lookup_by_name(ifname);
262 if (ifp != NULL)
8c4e57a5 263 interface_recalculate(ifp);
5734509c
PJ
264
265 return 1;
266}
267
268/* Delete interface from babel_enable_if. */
269static int
270babel_enable_if_delete (const char *ifname)
271{
272 int babel_enable_if_index;
273 char *str;
274 struct interface *ifp = NULL;
275
276 babel_enable_if_index = babel_enable_if_lookup (ifname);
277 if (babel_enable_if_index < 0)
278 return -1;
279
280 str = vector_slot (babel_enable_if, babel_enable_if_index);
281 free (str);
282 vector_unset (babel_enable_if, babel_enable_if_index);
283
284 ifp = if_lookup_by_name(ifname);
285 if (ifp != NULL)
8c4e57a5 286 interface_reset(ifp);
5734509c
PJ
287
288 return 1;
289}
290
291
292/* [Babel Command] Babel enable on specified interface or matched network. */
293DEFUN (babel_network,
294 babel_network_cmd,
295 "network IF_OR_ADDR",
c428edba 296 "Enable Babel protocol on specified interface or network.\n"
5734509c
PJ
297 "Interface or address")
298{
299 int ret;
300 struct prefix p;
301
302 ret = str2prefix (argv[0], &p);
303
304 /* Given string is: */
305 if (ret) /* an IPv4 or v6 network */
306 return CMD_ERR_NO_MATCH; /* not implemented yet */
307 else /* an interface name */
308 ret = babel_enable_if_add (argv[0]);
309
310 if (ret < 0) {
311 vty_out (vty, "There is same network configuration %s%s", argv[0],
312 VTY_NEWLINE);
313 return CMD_WARNING;
314 }
315
316 return CMD_SUCCESS;
317}
318
319/* [Babel Command] Babel enable on specified interface or matched network. */
320DEFUN (no_babel_network,
321 no_babel_network_cmd,
322 "no network IF_OR_ADDR",
323 NO_STR
c428edba 324 "Disable Babel protocol on specified interface or network.\n"
5734509c
PJ
325 "Interface or address")
326{
327 int ret;
328 struct prefix p;
329
330 ret = str2prefix (argv[0], &p);
331
332 /* Given string is: */
333 if (ret) /* an IPv4 or v6 network */
334 return CMD_ERR_NO_MATCH; /* not implemented yet */
335 else /* an interface name */
336 ret = babel_enable_if_delete (argv[0]);
337
338 if (ret < 0) {
339 vty_out (vty, "can't find network %s%s", argv[0],
340 VTY_NEWLINE);
341 return CMD_WARNING;
342 }
343
344 return CMD_SUCCESS;
345}
346
347/* [Interface Command] Tell the interface is wire. */
348DEFUN (babel_set_wired,
349 babel_set_wired_cmd,
3c442e88 350 "babel wired",
c428edba
JC
351 "Babel interface commands\n"
352 "Enable wired optimisations")
5734509c
PJ
353{
354 struct interface *ifp;
355 babel_interface_nfo *babel_ifp;
356
357 ifp = vty->index;
358 babel_ifp = babel_get_if_nfo(ifp);
359
360 assert (babel_ifp != NULL);
361 babel_ifp->flags |= BABEL_IF_WIRED;
362 return CMD_SUCCESS;
363}
364
365/* [Interface Command] Tell the interface is wireless (default). */
366DEFUN (babel_set_wireless,
367 babel_set_wireless_cmd,
3c442e88 368 "babel wireless",
c428edba
JC
369 "Babel interface commands\n"
370 "Disable wired optimiations (assume wireless)")
5734509c
PJ
371{
372 struct interface *ifp;
373 babel_interface_nfo *babel_ifp;
374
375 ifp = vty->index;
376 babel_ifp = babel_get_if_nfo(ifp);
377
378 assert (babel_ifp != NULL);
379 babel_ifp->flags &= ~BABEL_IF_WIRED;
380 return CMD_SUCCESS;
381}
382
383/* [Interface Command] Enable split horizon. */
384DEFUN (babel_split_horizon,
385 babel_split_horizon_cmd,
386 "babel split-horizon",
c428edba
JC
387 "Babel interface commands\n"
388 "Enable split horizon processing")
5734509c
PJ
389{
390 struct interface *ifp;
391 babel_interface_nfo *babel_ifp;
392
393 ifp = vty->index;
394 babel_ifp = babel_get_if_nfo(ifp);
395
396 assert (babel_ifp != NULL);
397 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
398 return CMD_SUCCESS;
399}
400
401/* [Interface Command] Disable split horizon (default). */
402DEFUN (no_babel_split_horizon,
403 no_babel_split_horizon_cmd,
404 "no babel split-horizon",
405 NO_STR
c428edba
JC
406 "Babel interface commands\n"
407 "Disable split horizon processing")
5734509c
PJ
408{
409 struct interface *ifp;
410 babel_interface_nfo *babel_ifp;
411
412 ifp = vty->index;
413 babel_ifp = babel_get_if_nfo(ifp);
414
415 assert (babel_ifp != NULL);
416 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
417 return CMD_SUCCESS;
418}
419
420/* [Interface Command]. */
421DEFUN (babel_set_hello_interval,
422 babel_set_hello_interval_cmd,
c428edba
JC
423 "babel hello-interval <20-655340>",
424 "Babel interface commands\n"
425 "Time between scheduled hellos\n"
426 "Milliseconds\n")
5734509c
PJ
427{
428 struct interface *ifp;
429 babel_interface_nfo *babel_ifp;
38846de1 430 int interval;
5734509c 431
c428edba 432 VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
5734509c
PJ
433
434 ifp = vty->index;
435 babel_ifp = babel_get_if_nfo(ifp);
5734509c 436 assert (babel_ifp != NULL);
38846de1 437
5734509c
PJ
438 babel_ifp->hello_interval = interval;
439 return CMD_SUCCESS;
440}
441
c428edba
JC
442/* [Interface Command]. */
443DEFUN (babel_set_update_interval,
444 babel_set_update_interval_cmd,
445 "babel update-interval <20-655340>",
446 "Babel interface commands\n"
447 "Time between scheduled updates\n"
448 "Milliseconds\n")
449{
450 struct interface *ifp;
451 babel_interface_nfo *babel_ifp;
452 int interval;
453
454 VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
455
456 ifp = vty->index;
457 babel_ifp = babel_get_if_nfo(ifp);
458 assert (babel_ifp != NULL);
459
460 babel_ifp->update_interval = interval;
461 return CMD_SUCCESS;
462}
463
5734509c
PJ
464/* [Interface Command]. */
465DEFUN (babel_passive_interface,
466 babel_passive_interface_cmd,
c428edba
JC
467 "babel passive-interface",
468 "Babel interface commands\n"
469 "Only announce redistributed routes on this interface\n")
5734509c
PJ
470{
471 if (allow_duplicates) {
472 return CMD_WARNING;
473 }
38846de1 474 parasitic = 1;
5734509c
PJ
475 return CMD_SUCCESS;
476}
477
478/* [Interface Command]. */
479DEFUN (no_babel_passive_interface,
480 no_babel_passive_interface_cmd,
c428edba 481 "no babel passive-interface",
5734509c 482 NO_STR
c428edba
JC
483 "Babel interface commands\n"
484 "Announce all routes on this interface\n")
5734509c
PJ
485{
486 parasitic = 0;
487 return CMD_SUCCESS;
488}
489
5734509c
PJ
490/* This should be no more than half the hello interval, so that hellos
491 aren't sent late. The result is in milliseconds. */
492unsigned
493jitter(babel_interface_nfo *babel_ifp, int urgent)
494{
495 unsigned interval = babel_ifp->hello_interval;
496 if(urgent)
497 interval = MIN(interval, 100);
498 else
499 interval = MIN(interval, 4000);
500 return roughly(interval) / 4;
501}
502
503unsigned
504update_jitter(babel_interface_nfo *babel_ifp, int urgent)
505{
506 unsigned interval = babel_ifp->hello_interval;
507 if(urgent)
508 interval = MIN(interval, 100);
509 else
510 interval = MIN(interval, 4000);
511 return roughly(interval);
512}
513
514/* calculate babeld's specific datas of an interface (change when the interface
515 change) */
516static int
517interface_recalculate(struct interface *ifp)
518{
519 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
520 unsigned char *tmp = NULL;
521 int mtu, rc;
522 struct ipv6_mreq mreq;
523
8c4e57a5
MB
524 if (!IS_ENABLE(ifp))
525 return -1;
526
0ee8a1f1
MB
527 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
528 interface_reset(ifp);
529 return -1;
530 }
531
532 babel_ifp->flags |= BABEL_IF_IS_UP;
533
5734509c
PJ
534 mtu = MIN(ifp->mtu, ifp->mtu6);
535
536 /* We need to be able to fit at least two messages into a packet,
537 so MTUs below 116 require lower layer fragmentation. */
538 /* In IPv6, the minimum MTU is 1280, and every host must be able
539 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
540 if(mtu < 128) {
541 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
542 mtu, ifp->name, ifp->ifindex);
543 mtu = 128;
544 }
545
546 /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
547 babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
548 tmp = babel_ifp->sendbuf;
549 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
550 if(babel_ifp->sendbuf == NULL) {
4eedea55 551 zlog_err("Couldn't reallocate sendbuf.");
5734509c
PJ
552 free(tmp);
553 babel_ifp->bufsize = 0;
554 return -1;
555 }
556 tmp = NULL;
557
558 resize_receive_buffer(mtu);
559
560 if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */
561 babel_ifp->cost = 96;
562 babel_ifp->flags &= ~BABEL_IF_LQ;
563 } else {
564 babel_ifp->cost = 256;
565 babel_ifp->flags |= BABEL_IF_LQ;
566 }
567
5734509c
PJ
568 /* Since the interface was marked as active above, the
569 idle_hello_interval cannot be the one being used here. */
570 babel_ifp->update_interval = babel_ifp->hello_interval * 4;
571
572 memset(&mreq, 0, sizeof(mreq));
573 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
574 mreq.ipv6mr_interface = ifp->ifindex;
575
576 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
577 (char*)&mreq, sizeof(mreq));
578 if(rc < 0) {
579 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
580 ifp->name, safe_strerror(errno));
581 /* This is probably due to a missing link-local address,
582 so down this interface, and wait until the main loop
583 tries to up it again. */
584 interface_reset(ifp);
585 return -1;
586 }
587
588 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
589 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
590 send_hello(ifp);
591 send_request(ifp, NULL, 0);
592
593 update_interface_metric(ifp);
594
595 debugf(BABEL_DEBUG_COMMON,
c35fafdf 596 "Upped interface %s (%s, cost=%d, channel=%d%s).",
5734509c
PJ
597 ifp->name,
598 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
599 babel_ifp->cost,
c35fafdf 600 babel_ifp->channel,
5734509c
PJ
601 babel_ifp->ipv4 ? ", IPv4" : "");
602
603 if(rc > 0)
604 send_update(ifp, 0, NULL, 0);
605
5734509c
PJ
606 return 1;
607}
608
609/* Reset the interface as it was new: it's not removed from the interface list,
610 and may be considered as a upped interface. */
611static int
612interface_reset(struct interface *ifp)
613{
614 int rc;
615 struct ipv6_mreq mreq;
616 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
617
8c4e57a5
MB
618 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
619 return 0;
620
0ee8a1f1
MB
621 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
622 babel_ifp->flags &= ~BABEL_IF_IS_UP;
623
5734509c
PJ
624 flush_interface_routes(ifp, 0);
625 babel_ifp->buffered = 0;
626 babel_ifp->bufsize = 0;
627 free(babel_ifp->sendbuf);
628 babel_ifp->num_buffered_updates = 0;
629 babel_ifp->update_bufsize = 0;
630 if(babel_ifp->buffered_updates)
631 free(babel_ifp->buffered_updates);
632 babel_ifp->buffered_updates = NULL;
633 babel_ifp->sendbuf = NULL;
634
635 if(ifp->ifindex > 0) {
636 memset(&mreq, 0, sizeof(mreq));
637 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
638 mreq.ipv6mr_interface = ifp->ifindex;
639 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
640 (char*)&mreq, sizeof(mreq));
641 if(rc < 0)
642 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
643 ifp->name, safe_strerror(errno));
644 }
645
646 update_interface_metric(ifp);
647
648 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
649 ifp->name,
650 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
651 babel_ifp->cost,
652 babel_ifp->ipv4 ? ", IPv4" : "");
653
654 return 1;
655}
656
657/* Send retraction to all, and reset all interfaces statistics. */
658void
659babel_interface_close_all(void)
660{
661 struct interface *ifp = NULL;
662 struct listnode *linklist_node = NULL;
663
664 FOR_ALL_INTERFACES(ifp, linklist_node) {
665 if(!if_up(ifp))
666 continue;
667 send_wildcard_retraction(ifp);
668 /* Make sure that we expire quickly from our neighbours'
669 association caches. */
670 send_hello_noupdate(ifp, 10);
671 flushbuf(ifp);
672 usleep(roughly(1000));
673 gettime(&babel_now);
674 }
675 FOR_ALL_INTERFACES(ifp, linklist_node) {
676 if(!if_up(ifp))
677 continue;
678 /* Make sure they got it. */
679 send_wildcard_retraction(ifp);
680 send_hello_noupdate(ifp, 1);
681 flushbuf(ifp);
682 usleep(roughly(10000));
683 gettime(&babel_now);
684 interface_reset(ifp);
685 }
686}
687
688/* return "true" if address is one of our ipv6 addresses */
689int
690is_interface_ll_address(struct interface *ifp, const unsigned char *address)
691{
692 struct connected *connected;
693 struct listnode *node;
694
695 if(!if_up(ifp))
696 return 0;
697
698 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
699 if(connected->address->family == AF_INET6 &&
700 memcmp(&connected->address->u.prefix6, address, 16) == 0)
701 return 1;
702 }
703
704 return 0;
705}
706
d4e46e68
DO
707static void
708show_babel_interface_sub (struct vty *vty, struct interface *ifp)
709{
710 int is_up;
711 babel_interface_nfo *babel_ifp;
712
713 vty_out (vty, "%s is %s%s", ifp->name,
714 ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
715 vty_out (vty, " ifindex %u, MTU %u bytes %s%s",
716 ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
717
718 if (babel_enable_if_lookup (ifp->name) < 0)
719 {
720 vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
721 return;
722 }
723 if (!is_up)
724 {
725 vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
726 return;
727 }
728 babel_ifp = babel_get_if_nfo (ifp);
729 vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE);
730 vty_out (vty, " Operating mode is \"%s\"%s",
731 CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
732 vty_out (vty, " Split horizon mode is %s%s",
733 CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
734 vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
9c298c71 735 vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE);
d4e46e68
DO
736}
737
738DEFUN (show_babel_interface,
739 show_babel_interface_cmd,
740 "show babel interface [INTERFACE]",
741 SHOW_STR
742 IP_STR
743 "Babel information\n"
744 "Interface information\n"
745 "Interface name\n")
746{
747 struct interface *ifp;
748 struct listnode *node;
749
750 if (argc == 0)
751 {
752 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
753 show_babel_interface_sub (vty, ifp);
754 return CMD_SUCCESS;
755 }
756 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
757 {
758 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
759 return CMD_WARNING;
760 }
761 show_babel_interface_sub (vty, ifp);
762 return CMD_SUCCESS;
763}
5734509c 764
297a55ba
MB
765static void
766show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
767{
768 vty_out (vty,
769 "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
770 format_address(neigh->address),
771 neigh->ifp->name,
772 neigh->reach,
773 neighbour_rxcost(neigh),
774 neigh->txcost,
775 if_up(neigh->ifp) ? "" : " (down)",
776 VTY_NEWLINE);
777}
778
779DEFUN (show_babel_neighbour,
780 show_babel_neighbour_cmd,
781 "show babel neighbour [INTERFACE]",
782 SHOW_STR
783 IP_STR
784 "Babel information\n"
785 "Print neighbours\n"
786 "Interface name\n")
787{
788 struct neighbour *neigh;
789 struct interface *ifp;
790
791 if (argc == 0) {
792 FOR_ALL_NEIGHBOURS(neigh) {
793 show_babel_neighbour_sub(vty, neigh);
794 }
795 return CMD_SUCCESS;
796 }
797 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
798 {
799 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
800 return CMD_WARNING;
801 }
802 FOR_ALL_NEIGHBOURS(neigh) {
803 if(ifp->ifindex == neigh->ifp->ifindex) {
804 show_babel_neighbour_sub(vty, neigh);
805 }
806 }
807 return CMD_SUCCESS;
808}
809
1f39f466 810static void
c35fafdf 811show_babel_routes_sub (struct babel_route *route, void *closure)
1f39f466 812{
c35fafdf 813 struct vty *vty = (struct vty*) closure;
1f39f466
MB
814 const unsigned char *nexthop =
815 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
816 NULL : route->nexthop;
c35fafdf
MB
817 char channels[100];
818
819 if(route->channels[0] == 0)
820 channels[0] = '\0';
821 else {
822 int k, j = 0;
823 snprintf(channels, 100, " chan (");
824 j = strlen(channels);
825 for(k = 0; k < DIVERSITY_HOPS; k++) {
826 if(route->channels[k] == 0)
827 break;
828 if(k > 0)
829 channels[j++] = ',';
830 snprintf(channels + j, 100 - j, "%d", route->channels[k]);
831 j = strlen(channels);
832 }
833 snprintf(channels + j, 100 - j, ")");
834 if(k == 0)
835 channels[0] = '\0';
836 }
1f39f466
MB
837
838 vty_out(vty,
c35fafdf 839 "%s metric %d refmetric %d id %s seqno %d%s age %d "
1f39f466
MB
840 "via %s neigh %s%s%s%s%s",
841 format_prefix(route->src->prefix, route->src->plen),
842 route_metric(route), route->refmetric,
843 format_eui64(route->src->id),
844 (int)route->seqno,
c35fafdf 845 channels,
1f39f466
MB
846 (int)(babel_now.tv_sec - route->time),
847 route->neigh->ifp->name,
848 format_address(route->neigh->address),
849 nexthop ? " nexthop " : "",
850 nexthop ? format_address(nexthop) : "",
851 route->installed ? " (installed)" :
852 route_feasible(route) ? " (feasible)" : "",
853 VTY_NEWLINE);
854}
855
856static void
c35fafdf 857show_babel_xroutes_sub (struct xroute *xroute, void *closure)
1f39f466 858{
c35fafdf 859 struct vty *vty = (struct vty *) closure;
1f39f466 860 vty_out(vty, "%s metric %d (exported)%s",
c35fafdf
MB
861 format_prefix(xroute->prefix, xroute->plen),
862 xroute->metric,
1f39f466
MB
863 VTY_NEWLINE);
864}
865
866DEFUN (show_babel_database,
867 show_babel_database_cmd,
868 "show babel database",
869 SHOW_STR
870 IP_STR
871 "Babel information\n"
872 "Database information\n"
873 "No attributes\n")
874{
c35fafdf
MB
875 for_all_routes(show_babel_routes_sub, vty);
876 for_all_xroutes(show_babel_xroutes_sub, vty);
1f39f466
MB
877 return CMD_SUCCESS;
878}
879
a14ef5ee
DO
880DEFUN (show_babel_parameters,
881 show_babel_parameters_cmd,
882 "show babel parameters",
d3351d1e
MB
883 SHOW_STR
884 IP_STR
885 "Babel information\n"
886 "Configuration information\n"
887 "No attributes\n")
888{
889 vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
890 show_babel_main_configuration(vty);
38846de1 891 vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE);
d3351d1e
MB
892 config_show_distribute(vty);
893
894 return CMD_SUCCESS;
895}
896
5734509c
PJ
897void
898babel_if_init ()
899{
900 /* initialize interface list */
901 if_init();
902 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
903 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
904
905 babel_enable_if = vector_init (1);
906
907 /* install interface node and commands */
908 install_element (CONFIG_NODE, &interface_cmd);
909 install_element (CONFIG_NODE, &no_interface_cmd);
910 install_node (&babel_interface_node, interface_config_write);
911 install_default(INTERFACE_NODE);
912 install_element(INTERFACE_NODE, &interface_cmd);
913 install_element(INTERFACE_NODE, &no_interface_cmd);
914
915 install_element(BABEL_NODE, &babel_network_cmd);
916 install_element(BABEL_NODE, &no_babel_network_cmd);
917 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
918 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
919 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
920 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
921 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
c428edba 922 install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
5734509c
PJ
923 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
924 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
d4e46e68 925
ec0c8480
JC
926 /* "show babel ..." commands */
927 install_element(VIEW_NODE, &show_babel_interface_cmd);
928 install_element(ENABLE_NODE, &show_babel_interface_cmd);
297a55ba
MB
929 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
930 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
1f39f466
MB
931 install_element(VIEW_NODE, &show_babel_database_cmd);
932 install_element(ENABLE_NODE, &show_babel_database_cmd);
a14ef5ee
DO
933 install_element(VIEW_NODE, &show_babel_parameters_cmd);
934 install_element(ENABLE_NODE, &show_babel_parameters_cmd);
5734509c
PJ
935}
936
937/* hooks: functions called respectively when struct interface is
938 created or deleted. */
939static int
940babel_if_new_hook (struct interface *ifp)
941{
942 ifp->info = babel_interface_allocate();
943 return 0;
944}
945
946static int
947babel_if_delete_hook (struct interface *ifp)
948{
949 babel_interface_free(ifp->info);
950 ifp->info = NULL;
951 return 0;
952}
953
954/* Configuration write function for babeld. */
955static int
956interface_config_write (struct vty *vty)
957{
958 struct listnode *node;
959 struct interface *ifp;
5734509c
PJ
960 int write = 0;
961
962 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
5734509c
PJ
963 /* Do not display the interface if there is no configuration about it */
964 if (ifp->desc == NULL)
965 continue;
966
967 vty_out (vty, "interface %s%s", ifp->name,
968 VTY_NEWLINE);
969 if (ifp->desc)
970 vty_out (vty, " description %s%s", ifp->desc,
971 VTY_NEWLINE);
972
973 /* TODO: to be completed... */
974
975 vty_out (vty, "!%s", VTY_NEWLINE);
976
977 write++;
978 }
979 return write;
980}
981
a14ef5ee
DO
982/* Output a "network" statement line for each of the enabled interfaces. */
983int
984babel_enable_if_config_write (struct vty * vty)
985{
986 unsigned int i, lines = 0;
987 char *str;
988
989 for (i = 0; i < vector_active (babel_enable_if); i++)
990 if ((str = vector_slot (babel_enable_if, i)) != NULL)
991 {
992 vty_out (vty, " network %s%s", str, VTY_NEWLINE);
993 lines++;
994 }
995 return lines;
996}
997
5734509c
PJ
998/* functions to allocate or free memory for a babel_interface_nfo, filling
999 needed fields */
1000static babel_interface_nfo *
c7c53fa8 1001babel_interface_allocate (void)
5734509c
PJ
1002{
1003 babel_interface_nfo *babel_ifp;
1004 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
1005 if(babel_ifp == NULL)
1006 return NULL;
1007
1008 /* Here are set the default values for an interface. */
1009 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
1010 /* All flags are unset */
5734509c
PJ
1011 babel_ifp->bucket_time = babel_now.tv_sec;
1012 babel_ifp->bucket = BUCKET_TOKENS_MAX;
1013 babel_ifp->hello_seqno = (random() & 0xFFFF);
1014 babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
c35fafdf 1015 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
5734509c
PJ
1016
1017 return babel_ifp;
1018}
1019
1020static void
1021babel_interface_free (babel_interface_nfo *babel_ifp)
1022{
1023 XFREE(MTYPE_BABEL_IF, babel_ifp);
1024}