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