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