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