blob: 3f5800460cfa3116fc2cf2750efb8debd85aebdb [file] [log] [blame]
Paul Jakma57345092011-12-25 17:52:09 +01001/*
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
Paul Jakma57345092011-12-25 17:52:09 +010040#include <zebra.h>
41#include "memory.h"
42#include "log.h"
43#include "command.h"
44#include "prefix.h"
45#include "vector.h"
Matthieu Boutierd3351d12012-01-19 22:36:56 +010046#include "distribute.h"
Paul Jakma57345092011-12-25 17:52:09 +010047
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"
Matthieu Boutier297a55b2012-01-18 16:39:29 +010055#include "neighbour.h"
Matthieu Boutier1f39f462012-01-18 20:01:31 +010056#include "route.h"
57#include "xroute.h"
Paul Jakma57345092011-12-25 17:52:09 +010058
59
60static int babel_enable_if_lookup (const char *ifname);
61static int babel_enable_if_add (const char *ifname);
62static int babel_enable_if_delete (const char *ifname);
63static int interface_recalculate(struct interface *ifp);
64static int interface_reset(struct interface *ifp);
65static int babel_if_new_hook (struct interface *ifp);
66static int babel_if_delete_hook (struct interface *ifp);
67static int interface_config_write (struct vty *vty);
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +010068static babel_interface_nfo * babel_interface_allocate (void);
Paul Jakma57345092011-12-25 17:52:09 +010069static void babel_interface_free (babel_interface_nfo *bi);
70
71
72static vector babel_enable_if; /* enable interfaces (by cmd). */
73static struct cmd_node babel_interface_node = /* babeld's interface node. */
74{
75 INTERFACE_NODE,
76 "%s(config-if)# ",
77 1 /* VTYSH */
78};
79
80
81int
82babel_interface_up (int cmd, struct zclient *client, zebra_size_t length)
83{
84 struct stream *s = NULL;
85 struct interface *ifp = NULL;
86
87 debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
88
89 s = zclient->ibuf;
90 ifp = zebra_interface_state_read(s);
91
92 if (ifp == NULL) {
93 return 0;
94 }
95
96 interface_recalculate(ifp);
97 return 0;
98}
99
100int
101babel_interface_down (int cmd, struct zclient *client, zebra_size_t length)
102{
103 struct stream *s = NULL;
104 struct interface *ifp = NULL;
105
106 debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
107
108 s = zclient->ibuf;
109 ifp = zebra_interface_state_read(s);
110
111 if (ifp == NULL) {
112 return 0;
113 }
114
115 interface_reset(ifp);
116 return 0;
117}
118
119int
120babel_interface_add (int cmd, struct zclient *client, zebra_size_t length)
121{
122 struct interface *ifp = NULL;
123
124 debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
125
126 /* read and add the interface in the iflist. */
127 ifp = zebra_interface_add_read (zclient->ibuf);
128
129 if (ifp == NULL) {
130 return 0;
131 }
132
133 interface_recalculate(ifp);
134
135 return 0;
136}
137
138int
139babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length)
140{
141 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
142 return 0;
143}
144
145int
146babel_interface_address_add (int cmd, struct zclient *client,
147 zebra_size_t length)
148{
149 babel_interface_nfo *babel_ifp;
150 struct connected *ifc;
151 struct prefix *prefix;
152
153 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
154
155 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
156 zclient->ibuf);
157
158 if (ifc == NULL)
159 return 0;
160
161 prefix = ifc->address;
162
163 if (prefix->family == AF_INET) {
164 flush_interface_routes(ifc->ifp, 0);
165 babel_ifp = babel_get_if_nfo(ifc->ifp);
166 if (babel_ifp->ipv4 == NULL) {
167 babel_ifp->ipv4 = malloc(4);
168 if (babel_ifp->ipv4 == NULL) {
169 zlog_err("not einough memory");
170 } else {
171 memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
172 }
173 }
174 }
175
176 send_request(ifc->ifp, NULL, 0);
177 send_update(ifc->ifp, 0, NULL, 0);
178
179 return 0;
180}
181
182int
183babel_interface_address_delete (int cmd, struct zclient *client,
184 zebra_size_t length)
185{
186 babel_interface_nfo *babel_ifp;
187 struct connected *ifc;
188 struct prefix *prefix;
189
190 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
191
192 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
193 zclient->ibuf);
194
195 if (ifc == NULL)
196 return 0;
197
198 prefix = ifc->address;
199
200 if (prefix->family == AF_INET) {
201 flush_interface_routes(ifc->ifp, 0);
202 babel_ifp = babel_get_if_nfo(ifc->ifp);
203 if (babel_ifp->ipv4 != NULL
204 && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) {
205 free(babel_ifp->ipv4);
206 babel_ifp->ipv4 = NULL;
207 }
208 }
209
210 send_request(ifc->ifp, NULL, 0);
211 send_update(ifc->ifp, 0, NULL, 0);
212
213 return 0;
214}
215
216/* Lookup function. */
217static int
218babel_enable_if_lookup (const char *ifname)
219{
220 unsigned int i;
221 char *str;
222
223 for (i = 0; i < vector_active (babel_enable_if); i++)
224 if ((str = vector_slot (babel_enable_if, i)) != NULL)
225 if (strcmp (str, ifname) == 0)
226 return i;
227 return -1;
228}
229
230/* Add interface to babel_enable_if. */
231static int
232babel_enable_if_add (const char *ifname)
233{
234 int ret;
235 struct interface *ifp = NULL;
236
237 ret = babel_enable_if_lookup (ifname);
238 if (ret >= 0)
239 return -1;
240
241 vector_set (babel_enable_if, strdup (ifname));
242
243 ifp = if_lookup_by_name(ifname);
244 if (ifp != NULL)
245 babel_get_if_nfo(ifp)->flags |= BABEL_IF_IS_ENABLE;
246
247 return 1;
248}
249
250/* Delete interface from babel_enable_if. */
251static int
252babel_enable_if_delete (const char *ifname)
253{
254 int babel_enable_if_index;
255 char *str;
256 struct interface *ifp = NULL;
257
258 babel_enable_if_index = babel_enable_if_lookup (ifname);
259 if (babel_enable_if_index < 0)
260 return -1;
261
262 str = vector_slot (babel_enable_if, babel_enable_if_index);
263 free (str);
264 vector_unset (babel_enable_if, babel_enable_if_index);
265
266 ifp = if_lookup_by_name(ifname);
267 if (ifp != NULL)
268 babel_get_if_nfo(ifp)->flags &= ~BABEL_IF_IS_ENABLE;
269
270 return 1;
271}
272
273
274/* [Babel Command] Babel enable on specified interface or matched network. */
275DEFUN (babel_network,
276 babel_network_cmd,
277 "network IF_OR_ADDR",
278 "Babel enable on specified interface or network.\n"
279 "Interface or address")
280{
281 int ret;
282 struct prefix p;
283
284 ret = str2prefix (argv[0], &p);
285
286 /* Given string is: */
287 if (ret) /* an IPv4 or v6 network */
288 return CMD_ERR_NO_MATCH; /* not implemented yet */
289 else /* an interface name */
290 ret = babel_enable_if_add (argv[0]);
291
292 if (ret < 0) {
293 vty_out (vty, "There is same network configuration %s%s", argv[0],
294 VTY_NEWLINE);
295 return CMD_WARNING;
296 }
297
298 return CMD_SUCCESS;
299}
300
301/* [Babel Command] Babel enable on specified interface or matched network. */
302DEFUN (no_babel_network,
303 no_babel_network_cmd,
304 "no network IF_OR_ADDR",
305 NO_STR
306 "Babel enable on specified interface or network.\n"
307 "Interface or address")
308{
309 int ret;
310 struct prefix p;
311
312 ret = str2prefix (argv[0], &p);
313
314 /* Given string is: */
315 if (ret) /* an IPv4 or v6 network */
316 return CMD_ERR_NO_MATCH; /* not implemented yet */
317 else /* an interface name */
318 ret = babel_enable_if_delete (argv[0]);
319
320 if (ret < 0) {
321 vty_out (vty, "can't find network %s%s", argv[0],
322 VTY_NEWLINE);
323 return CMD_WARNING;
324 }
325
326 return CMD_SUCCESS;
327}
328
329/* [Interface Command] Tell the interface is wire. */
330DEFUN (babel_set_wired,
331 babel_set_wired_cmd,
332 "wired",
333 "Set this interface as wired (default: wireless).\n"
334 "No attributes")
335{
336 struct interface *ifp;
337 babel_interface_nfo *babel_ifp;
338
339 ifp = vty->index;
340 babel_ifp = babel_get_if_nfo(ifp);
341
342 assert (babel_ifp != NULL);
343 babel_ifp->flags |= BABEL_IF_WIRED;
344 return CMD_SUCCESS;
345}
346
347/* [Interface Command] Tell the interface is wireless (default). */
348DEFUN (babel_set_wireless,
349 babel_set_wireless_cmd,
350 "wireless",
351 NO_STR
352 "Set this interface as wireless (is default).\n"
353 "No attributes")
354{
355 struct interface *ifp;
356 babel_interface_nfo *babel_ifp;
357
358 ifp = vty->index;
359 babel_ifp = babel_get_if_nfo(ifp);
360
361 assert (babel_ifp != NULL);
362 babel_ifp->flags &= ~BABEL_IF_WIRED;
363 return CMD_SUCCESS;
364}
365
366/* [Interface Command] Enable split horizon. */
367DEFUN (babel_split_horizon,
368 babel_split_horizon_cmd,
369 "babel split-horizon",
370 IPV6_STR
371 "Routing Information Protocol\n"
372 "Perform split horizon\n")
373{
374 struct interface *ifp;
375 babel_interface_nfo *babel_ifp;
376
377 ifp = vty->index;
378 babel_ifp = babel_get_if_nfo(ifp);
379
380 assert (babel_ifp != NULL);
381 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
382 return CMD_SUCCESS;
383}
384
385/* [Interface Command] Disable split horizon (default). */
386DEFUN (no_babel_split_horizon,
387 no_babel_split_horizon_cmd,
388 "no babel split-horizon",
389 NO_STR
390 IPV6_STR
391 "Routing Information Protocol\n"
392 "Perform split horizon\n")
393{
394 struct interface *ifp;
395 babel_interface_nfo *babel_ifp;
396
397 ifp = vty->index;
398 babel_ifp = babel_get_if_nfo(ifp);
399
400 assert (babel_ifp != NULL);
401 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
402 return CMD_SUCCESS;
403}
404
405/* [Interface Command]. */
406DEFUN (babel_set_hello_interval,
407 babel_set_hello_interval_cmd,
408 "hello interval <5-1000000>",
409 "Set interface's hello interval (default: 4000).\n"
410 "Value in miliseconds\n")
411{
412 struct interface *ifp;
413 babel_interface_nfo *babel_ifp;
414
415 int interval = atoi(argv[1]);
416
417 ifp = vty->index;
418 babel_ifp = babel_get_if_nfo(ifp);
419
420 assert (babel_ifp != NULL);
421 babel_ifp->hello_interval = interval;
422 return CMD_SUCCESS;
423}
424
425/* [Interface Command]. */
426DEFUN (babel_passive_interface,
427 babel_passive_interface_cmd,
428 "passive-interface",
429 "The daemon will only announce redistributed routes\n"
430 "Interface name\n")
431{
432 if (allow_duplicates) {
433 return CMD_WARNING;
434 }
435 parasitic = -1;
436 return CMD_SUCCESS;
437}
438
439/* [Interface Command]. */
440DEFUN (no_babel_passive_interface,
441 no_babel_passive_interface_cmd,
442 "no passive-interface",
443 NO_STR
444 "The daemon will announce all (filtred) routes\n"
445 "Interface name\n")
446{
447 parasitic = 0;
448 return CMD_SUCCESS;
449}
450
451
452int
453interface_idle(babel_interface_nfo *babel_ifp)
454{
455 return (idle_hello_interval > 0 &&
456 babel_ifp->activity_time < babel_now.tv_sec - idle_time);
457}
458
459/* This should be no more than half the hello interval, so that hellos
460 aren't sent late. The result is in milliseconds. */
461unsigned
462jitter(babel_interface_nfo *babel_ifp, int urgent)
463{
464 unsigned interval = babel_ifp->hello_interval;
465 if(urgent)
466 interval = MIN(interval, 100);
467 else
468 interval = MIN(interval, 4000);
469 return roughly(interval) / 4;
470}
471
472unsigned
473update_jitter(babel_interface_nfo *babel_ifp, int urgent)
474{
475 unsigned interval = babel_ifp->hello_interval;
476 if(urgent)
477 interval = MIN(interval, 100);
478 else
479 interval = MIN(interval, 4000);
480 return roughly(interval);
481}
482
483/* calculate babeld's specific datas of an interface (change when the interface
484 change) */
485static int
486interface_recalculate(struct interface *ifp)
487{
488 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
489 unsigned char *tmp = NULL;
490 int mtu, rc;
491 struct ipv6_mreq mreq;
492
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100493 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
494 interface_reset(ifp);
495 return -1;
496 }
497
498 babel_ifp->flags |= BABEL_IF_IS_UP;
499
Paul Jakma57345092011-12-25 17:52:09 +0100500 mtu = MIN(ifp->mtu, ifp->mtu6);
501
502 /* We need to be able to fit at least two messages into a packet,
503 so MTUs below 116 require lower layer fragmentation. */
504 /* In IPv6, the minimum MTU is 1280, and every host must be able
505 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
506 if(mtu < 128) {
507 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
508 mtu, ifp->name, ifp->ifindex);
509 mtu = 128;
510 }
511
512 /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
513 babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
514 tmp = babel_ifp->sendbuf;
515 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
516 if(babel_ifp->sendbuf == NULL) {
Matthieu Boutier4eedea52012-01-17 22:46:21 +0100517 zlog_err("Couldn't reallocate sendbuf.");
Paul Jakma57345092011-12-25 17:52:09 +0100518 free(tmp);
519 babel_ifp->bufsize = 0;
520 return -1;
521 }
522 tmp = NULL;
523
524 resize_receive_buffer(mtu);
525
526 if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */
527 babel_ifp->cost = 96;
528 babel_ifp->flags &= ~BABEL_IF_LQ;
529 } else {
530 babel_ifp->cost = 256;
531 babel_ifp->flags |= BABEL_IF_LQ;
532 }
533
534 babel_ifp->activity_time = babel_now.tv_sec;
535 /* Since the interface was marked as active above, the
536 idle_hello_interval cannot be the one being used here. */
537 babel_ifp->update_interval = babel_ifp->hello_interval * 4;
538
539 memset(&mreq, 0, sizeof(mreq));
540 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
541 mreq.ipv6mr_interface = ifp->ifindex;
542
543 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
544 (char*)&mreq, sizeof(mreq));
545 if(rc < 0) {
546 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
547 ifp->name, safe_strerror(errno));
548 /* This is probably due to a missing link-local address,
549 so down this interface, and wait until the main loop
550 tries to up it again. */
551 interface_reset(ifp);
552 return -1;
553 }
554
555 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
556 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
557 send_hello(ifp);
558 send_request(ifp, NULL, 0);
559
560 update_interface_metric(ifp);
561
562 debugf(BABEL_DEBUG_COMMON,
563 "Upped network %s (%s, cost=%d%s).",
564 ifp->name,
565 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
566 babel_ifp->cost,
567 babel_ifp->ipv4 ? ", IPv4" : "");
568
569 if(rc > 0)
570 send_update(ifp, 0, NULL, 0);
571
572 /* Check and set if interface is enable. */
573 if (babel_enable_if_lookup(ifp->name) >= 0) {
574 babel_ifp->flags |= BABEL_IF_IS_ENABLE;
575 } else {
576 babel_ifp->flags &= ~BABEL_IF_IS_ENABLE;
577 }
578
579 return 1;
580}
581
582/* Reset the interface as it was new: it's not removed from the interface list,
583 and may be considered as a upped interface. */
584static int
585interface_reset(struct interface *ifp)
586{
587 int rc;
588 struct ipv6_mreq mreq;
589 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
590
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100591 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
592 babel_ifp->flags &= ~BABEL_IF_IS_UP;
593
Paul Jakma57345092011-12-25 17:52:09 +0100594 flush_interface_routes(ifp, 0);
595 babel_ifp->buffered = 0;
596 babel_ifp->bufsize = 0;
597 free(babel_ifp->sendbuf);
598 babel_ifp->num_buffered_updates = 0;
599 babel_ifp->update_bufsize = 0;
600 if(babel_ifp->buffered_updates)
601 free(babel_ifp->buffered_updates);
602 babel_ifp->buffered_updates = NULL;
603 babel_ifp->sendbuf = NULL;
604
605 if(ifp->ifindex > 0) {
606 memset(&mreq, 0, sizeof(mreq));
607 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
608 mreq.ipv6mr_interface = ifp->ifindex;
609 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
610 (char*)&mreq, sizeof(mreq));
611 if(rc < 0)
612 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
613 ifp->name, safe_strerror(errno));
614 }
615
616 update_interface_metric(ifp);
617
618 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
619 ifp->name,
620 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
621 babel_ifp->cost,
622 babel_ifp->ipv4 ? ", IPv4" : "");
623
624 return 1;
625}
626
627/* Send retraction to all, and reset all interfaces statistics. */
628void
629babel_interface_close_all(void)
630{
631 struct interface *ifp = NULL;
632 struct listnode *linklist_node = NULL;
633
634 FOR_ALL_INTERFACES(ifp, linklist_node) {
635 if(!if_up(ifp))
636 continue;
637 send_wildcard_retraction(ifp);
638 /* Make sure that we expire quickly from our neighbours'
639 association caches. */
640 send_hello_noupdate(ifp, 10);
641 flushbuf(ifp);
642 usleep(roughly(1000));
643 gettime(&babel_now);
644 }
645 FOR_ALL_INTERFACES(ifp, linklist_node) {
646 if(!if_up(ifp))
647 continue;
648 /* Make sure they got it. */
649 send_wildcard_retraction(ifp);
650 send_hello_noupdate(ifp, 1);
651 flushbuf(ifp);
652 usleep(roughly(10000));
653 gettime(&babel_now);
654 interface_reset(ifp);
655 }
656}
657
658/* return "true" if address is one of our ipv6 addresses */
659int
660is_interface_ll_address(struct interface *ifp, const unsigned char *address)
661{
662 struct connected *connected;
663 struct listnode *node;
664
665 if(!if_up(ifp))
666 return 0;
667
668 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
669 if(connected->address->family == AF_INET6 &&
670 memcmp(&connected->address->u.prefix6, address, 16) == 0)
671 return 1;
672 }
673
674 return 0;
675}
676
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400677static void
678show_babel_interface_sub (struct vty *vty, struct interface *ifp)
679{
680 int is_up;
681 babel_interface_nfo *babel_ifp;
682
683 vty_out (vty, "%s is %s%s", ifp->name,
684 ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
685 vty_out (vty, " ifindex %u, MTU %u bytes %s%s",
686 ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
687
688 if (babel_enable_if_lookup (ifp->name) < 0)
689 {
690 vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
691 return;
692 }
693 if (!is_up)
694 {
695 vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
696 return;
697 }
698 babel_ifp = babel_get_if_nfo (ifp);
699 vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE);
700 vty_out (vty, " Operating mode is \"%s\"%s",
701 CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
702 vty_out (vty, " Split horizon mode is %s%s",
703 CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
704 vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
705}
706
707DEFUN (show_babel_interface,
708 show_babel_interface_cmd,
709 "show babel interface [INTERFACE]",
710 SHOW_STR
711 IP_STR
712 "Babel information\n"
713 "Interface information\n"
714 "Interface name\n")
715{
716 struct interface *ifp;
717 struct listnode *node;
718
719 if (argc == 0)
720 {
721 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
722 show_babel_interface_sub (vty, ifp);
723 return CMD_SUCCESS;
724 }
725 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
726 {
727 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
728 return CMD_WARNING;
729 }
730 show_babel_interface_sub (vty, ifp);
731 return CMD_SUCCESS;
732}
Paul Jakma57345092011-12-25 17:52:09 +0100733
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100734static void
735show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
736{
737 vty_out (vty,
738 "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
739 format_address(neigh->address),
740 neigh->ifp->name,
741 neigh->reach,
742 neighbour_rxcost(neigh),
743 neigh->txcost,
744 if_up(neigh->ifp) ? "" : " (down)",
745 VTY_NEWLINE);
746}
747
748DEFUN (show_babel_neighbour,
749 show_babel_neighbour_cmd,
750 "show babel neighbour [INTERFACE]",
751 SHOW_STR
752 IP_STR
753 "Babel information\n"
754 "Print neighbours\n"
755 "Interface name\n")
756{
757 struct neighbour *neigh;
758 struct interface *ifp;
759
760 if (argc == 0) {
761 FOR_ALL_NEIGHBOURS(neigh) {
762 show_babel_neighbour_sub(vty, neigh);
763 }
764 return CMD_SUCCESS;
765 }
766 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
767 {
768 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
769 return CMD_WARNING;
770 }
771 FOR_ALL_NEIGHBOURS(neigh) {
772 if(ifp->ifindex == neigh->ifp->ifindex) {
773 show_babel_neighbour_sub(vty, neigh);
774 }
775 }
776 return CMD_SUCCESS;
777}
778
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100779static void
780show_babel_routes_sub (struct vty *vty, struct babel_route *route)
781{
782 const unsigned char *nexthop =
783 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
784 NULL : route->nexthop;
785
786 vty_out(vty,
787 "%s metric %d refmetric %d id %s seqno %d age %d "
788 "via %s neigh %s%s%s%s%s",
789 format_prefix(route->src->prefix, route->src->plen),
790 route_metric(route), route->refmetric,
791 format_eui64(route->src->id),
792 (int)route->seqno,
793 (int)(babel_now.tv_sec - route->time),
794 route->neigh->ifp->name,
795 format_address(route->neigh->address),
796 nexthop ? " nexthop " : "",
797 nexthop ? format_address(nexthop) : "",
798 route->installed ? " (installed)" :
799 route_feasible(route) ? " (feasible)" : "",
800 VTY_NEWLINE);
801}
802
803static void
804show_babel_xroutes_sub (struct vty *vty, struct xroute *xroute)
805{
806 vty_out(vty, "%s metric %d (exported)%s",
807 format_prefix(xroutes->prefix, xroute->plen),
808 xroutes->metric,
809 VTY_NEWLINE);
810}
811
812DEFUN (show_babel_database,
813 show_babel_database_cmd,
814 "show babel database",
815 SHOW_STR
816 IP_STR
817 "Babel information\n"
818 "Database information\n"
819 "No attributes\n")
820{
821 int i;
822
823 for(i = 0; i < numroutes; i++) {
824 show_babel_routes_sub(vty, &routes[i]);
825 }
826 for(i = 0; i < numxroutes; i++) {
827 show_babel_xroutes_sub(vty, &xroutes[i]);
828 }
829
830 return CMD_SUCCESS;
831}
832
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100833DEFUN (show_babel_running_config,
834 show_babel_running_config_cmd,
835 "show babel running-config",
836 SHOW_STR
837 IP_STR
838 "Babel information\n"
839 "Configuration information\n"
840 "No attributes\n")
841{
842 vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
843 show_babel_main_configuration(vty);
844 show_babeld_configuration(vty);
845 vty_out(vty, " -- ditribution lists --%s", VTY_NEWLINE);
846 config_show_distribute(vty);
847
848 return CMD_SUCCESS;
849}
850
Paul Jakma57345092011-12-25 17:52:09 +0100851void
852babel_if_init ()
853{
854 /* initialize interface list */
855 if_init();
856 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
857 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
858
859 babel_enable_if = vector_init (1);
860
861 /* install interface node and commands */
862 install_element (CONFIG_NODE, &interface_cmd);
863 install_element (CONFIG_NODE, &no_interface_cmd);
864 install_node (&babel_interface_node, interface_config_write);
865 install_default(INTERFACE_NODE);
866 install_element(INTERFACE_NODE, &interface_cmd);
867 install_element(INTERFACE_NODE, &no_interface_cmd);
868
869 install_element(BABEL_NODE, &babel_network_cmd);
870 install_element(BABEL_NODE, &no_babel_network_cmd);
871 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
872 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
873 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
874 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
875 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
876 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
877 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400878
879 /* "show babel ..." commands */
880 install_element (VIEW_NODE, &show_babel_interface_cmd);
881 install_element (ENABLE_NODE, &show_babel_interface_cmd);
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100882 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
883 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100884 install_element(VIEW_NODE, &show_babel_database_cmd);
885 install_element(ENABLE_NODE, &show_babel_database_cmd);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100886 install_element(VIEW_NODE, &show_babel_running_config_cmd);
887 install_element(ENABLE_NODE, &show_babel_running_config_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100888}
889
890/* hooks: functions called respectively when struct interface is
891 created or deleted. */
892static int
893babel_if_new_hook (struct interface *ifp)
894{
895 ifp->info = babel_interface_allocate();
896 return 0;
897}
898
899static int
900babel_if_delete_hook (struct interface *ifp)
901{
902 babel_interface_free(ifp->info);
903 ifp->info = NULL;
904 return 0;
905}
906
907/* Configuration write function for babeld. */
908static int
909interface_config_write (struct vty *vty)
910{
911 struct listnode *node;
912 struct interface *ifp;
Paul Jakma57345092011-12-25 17:52:09 +0100913 int write = 0;
914
915 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
Paul Jakma57345092011-12-25 17:52:09 +0100916 /* Do not display the interface if there is no configuration about it */
917 if (ifp->desc == NULL)
918 continue;
919
920 vty_out (vty, "interface %s%s", ifp->name,
921 VTY_NEWLINE);
922 if (ifp->desc)
923 vty_out (vty, " description %s%s", ifp->desc,
924 VTY_NEWLINE);
925
926 /* TODO: to be completed... */
927
928 vty_out (vty, "!%s", VTY_NEWLINE);
929
930 write++;
931 }
932 return write;
933}
934
935/* functions to allocate or free memory for a babel_interface_nfo, filling
936 needed fields */
937static babel_interface_nfo *
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +0100938babel_interface_allocate (void)
Paul Jakma57345092011-12-25 17:52:09 +0100939{
940 babel_interface_nfo *babel_ifp;
941 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
942 if(babel_ifp == NULL)
943 return NULL;
944
945 /* Here are set the default values for an interface. */
946 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
947 /* All flags are unset */
948 babel_ifp->activity_time = babel_now.tv_sec;
949 babel_ifp->bucket_time = babel_now.tv_sec;
950 babel_ifp->bucket = BUCKET_TOKENS_MAX;
951 babel_ifp->hello_seqno = (random() & 0xFFFF);
952 babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
953
954 return babel_ifp;
955}
956
957static void
958babel_interface_free (babel_interface_nfo *babel_ifp)
959{
960 XFREE(MTYPE_BABEL_IF, babel_ifp);
961}