blob: 1c8c88687d3e06fa499d7030106410aa28a726f2 [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
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100371 "Perform split horizon\n"
372 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100373{
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
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100391 "Disable split horizon\n"
392 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100393{
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"
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100430 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100431{
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"
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100445 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100446{
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
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100459int
460update_hello_interval(struct interface *ifp)
461{
462 int rc = 0;
463 unsigned short interval;
464 struct babel_interface *babel_ifp = babel_get_if_nfo(ifp);
465
466 if(interface_idle(babel_ifp))
467 interval = idle_hello_interval;
468 else if(IF_CONF(ifp, hello_interval) > 0)
469 interval = IF_CONF(ifp, hello_interval);
470 else if((ifp->flags & BABEL_IF_WIRED))
471 interval = wired_hello_interval;
472 else
473 interval = wireless_hello_interval;
474
475 if(babel_ifp->hello_interval != interval) {
476 babel_ifp->hello_interval = interval;
477 rc = 1;
478 }
479
480 return rc;
481}
482
Paul Jakma57345092011-12-25 17:52:09 +0100483/* This should be no more than half the hello interval, so that hellos
484 aren't sent late. The result is in milliseconds. */
485unsigned
486jitter(babel_interface_nfo *babel_ifp, int urgent)
487{
488 unsigned interval = babel_ifp->hello_interval;
489 if(urgent)
490 interval = MIN(interval, 100);
491 else
492 interval = MIN(interval, 4000);
493 return roughly(interval) / 4;
494}
495
496unsigned
497update_jitter(babel_interface_nfo *babel_ifp, int urgent)
498{
499 unsigned interval = babel_ifp->hello_interval;
500 if(urgent)
501 interval = MIN(interval, 100);
502 else
503 interval = MIN(interval, 4000);
504 return roughly(interval);
505}
506
507/* calculate babeld's specific datas of an interface (change when the interface
508 change) */
509static int
510interface_recalculate(struct interface *ifp)
511{
512 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
513 unsigned char *tmp = NULL;
514 int mtu, rc;
515 struct ipv6_mreq mreq;
516
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100517 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
518 interface_reset(ifp);
519 return -1;
520 }
521
522 babel_ifp->flags |= BABEL_IF_IS_UP;
523
Paul Jakma57345092011-12-25 17:52:09 +0100524 mtu = MIN(ifp->mtu, ifp->mtu6);
525
526 /* We need to be able to fit at least two messages into a packet,
527 so MTUs below 116 require lower layer fragmentation. */
528 /* In IPv6, the minimum MTU is 1280, and every host must be able
529 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
530 if(mtu < 128) {
531 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
532 mtu, ifp->name, ifp->ifindex);
533 mtu = 128;
534 }
535
536 /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
537 babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
538 tmp = babel_ifp->sendbuf;
539 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
540 if(babel_ifp->sendbuf == NULL) {
Matthieu Boutier4eedea52012-01-17 22:46:21 +0100541 zlog_err("Couldn't reallocate sendbuf.");
Paul Jakma57345092011-12-25 17:52:09 +0100542 free(tmp);
543 babel_ifp->bufsize = 0;
544 return -1;
545 }
546 tmp = NULL;
547
548 resize_receive_buffer(mtu);
549
550 if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */
551 babel_ifp->cost = 96;
552 babel_ifp->flags &= ~BABEL_IF_LQ;
553 } else {
554 babel_ifp->cost = 256;
555 babel_ifp->flags |= BABEL_IF_LQ;
556 }
557
558 babel_ifp->activity_time = babel_now.tv_sec;
559 /* Since the interface was marked as active above, the
560 idle_hello_interval cannot be the one being used here. */
561 babel_ifp->update_interval = babel_ifp->hello_interval * 4;
562
563 memset(&mreq, 0, sizeof(mreq));
564 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
565 mreq.ipv6mr_interface = ifp->ifindex;
566
567 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
568 (char*)&mreq, sizeof(mreq));
569 if(rc < 0) {
570 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
571 ifp->name, safe_strerror(errno));
572 /* This is probably due to a missing link-local address,
573 so down this interface, and wait until the main loop
574 tries to up it again. */
575 interface_reset(ifp);
576 return -1;
577 }
578
579 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
580 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
581 send_hello(ifp);
582 send_request(ifp, NULL, 0);
583
584 update_interface_metric(ifp);
585
586 debugf(BABEL_DEBUG_COMMON,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100587 "Upped interface %s (%s, cost=%d, channel=%d%s).",
Paul Jakma57345092011-12-25 17:52:09 +0100588 ifp->name,
589 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
590 babel_ifp->cost,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100591 babel_ifp->channel,
Paul Jakma57345092011-12-25 17:52:09 +0100592 babel_ifp->ipv4 ? ", IPv4" : "");
593
594 if(rc > 0)
595 send_update(ifp, 0, NULL, 0);
596
597 /* Check and set if interface is enable. */
598 if (babel_enable_if_lookup(ifp->name) >= 0) {
599 babel_ifp->flags |= BABEL_IF_IS_ENABLE;
600 } else {
601 babel_ifp->flags &= ~BABEL_IF_IS_ENABLE;
602 }
603
604 return 1;
605}
606
607/* Reset the interface as it was new: it's not removed from the interface list,
608 and may be considered as a upped interface. */
609static int
610interface_reset(struct interface *ifp)
611{
612 int rc;
613 struct ipv6_mreq mreq;
614 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
615
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100616 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
617 babel_ifp->flags &= ~BABEL_IF_IS_UP;
618
Paul Jakma57345092011-12-25 17:52:09 +0100619 flush_interface_routes(ifp, 0);
620 babel_ifp->buffered = 0;
621 babel_ifp->bufsize = 0;
622 free(babel_ifp->sendbuf);
623 babel_ifp->num_buffered_updates = 0;
624 babel_ifp->update_bufsize = 0;
625 if(babel_ifp->buffered_updates)
626 free(babel_ifp->buffered_updates);
627 babel_ifp->buffered_updates = NULL;
628 babel_ifp->sendbuf = NULL;
629
630 if(ifp->ifindex > 0) {
631 memset(&mreq, 0, sizeof(mreq));
632 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
633 mreq.ipv6mr_interface = ifp->ifindex;
634 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
635 (char*)&mreq, sizeof(mreq));
636 if(rc < 0)
637 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
638 ifp->name, safe_strerror(errno));
639 }
640
641 update_interface_metric(ifp);
642
643 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
644 ifp->name,
645 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
646 babel_ifp->cost,
647 babel_ifp->ipv4 ? ", IPv4" : "");
648
649 return 1;
650}
651
652/* Send retraction to all, and reset all interfaces statistics. */
653void
654babel_interface_close_all(void)
655{
656 struct interface *ifp = NULL;
657 struct listnode *linklist_node = NULL;
658
659 FOR_ALL_INTERFACES(ifp, linklist_node) {
660 if(!if_up(ifp))
661 continue;
662 send_wildcard_retraction(ifp);
663 /* Make sure that we expire quickly from our neighbours'
664 association caches. */
665 send_hello_noupdate(ifp, 10);
666 flushbuf(ifp);
667 usleep(roughly(1000));
668 gettime(&babel_now);
669 }
670 FOR_ALL_INTERFACES(ifp, linklist_node) {
671 if(!if_up(ifp))
672 continue;
673 /* Make sure they got it. */
674 send_wildcard_retraction(ifp);
675 send_hello_noupdate(ifp, 1);
676 flushbuf(ifp);
677 usleep(roughly(10000));
678 gettime(&babel_now);
679 interface_reset(ifp);
680 }
681}
682
683/* return "true" if address is one of our ipv6 addresses */
684int
685is_interface_ll_address(struct interface *ifp, const unsigned char *address)
686{
687 struct connected *connected;
688 struct listnode *node;
689
690 if(!if_up(ifp))
691 return 0;
692
693 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
694 if(connected->address->family == AF_INET6 &&
695 memcmp(&connected->address->u.prefix6, address, 16) == 0)
696 return 1;
697 }
698
699 return 0;
700}
701
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400702static void
703show_babel_interface_sub (struct vty *vty, struct interface *ifp)
704{
705 int is_up;
706 babel_interface_nfo *babel_ifp;
707
708 vty_out (vty, "%s is %s%s", ifp->name,
709 ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
710 vty_out (vty, " ifindex %u, MTU %u bytes %s%s",
711 ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
712
713 if (babel_enable_if_lookup (ifp->name) < 0)
714 {
715 vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
716 return;
717 }
718 if (!is_up)
719 {
720 vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
721 return;
722 }
723 babel_ifp = babel_get_if_nfo (ifp);
724 vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE);
725 vty_out (vty, " Operating mode is \"%s\"%s",
726 CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
727 vty_out (vty, " Split horizon mode is %s%s",
728 CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
729 vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
730}
731
732DEFUN (show_babel_interface,
733 show_babel_interface_cmd,
734 "show babel interface [INTERFACE]",
735 SHOW_STR
736 IP_STR
737 "Babel information\n"
738 "Interface information\n"
739 "Interface name\n")
740{
741 struct interface *ifp;
742 struct listnode *node;
743
744 if (argc == 0)
745 {
746 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
747 show_babel_interface_sub (vty, ifp);
748 return CMD_SUCCESS;
749 }
750 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
751 {
752 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
753 return CMD_WARNING;
754 }
755 show_babel_interface_sub (vty, ifp);
756 return CMD_SUCCESS;
757}
Paul Jakma57345092011-12-25 17:52:09 +0100758
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100759static void
760show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
761{
762 vty_out (vty,
763 "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
764 format_address(neigh->address),
765 neigh->ifp->name,
766 neigh->reach,
767 neighbour_rxcost(neigh),
768 neigh->txcost,
769 if_up(neigh->ifp) ? "" : " (down)",
770 VTY_NEWLINE);
771}
772
773DEFUN (show_babel_neighbour,
774 show_babel_neighbour_cmd,
775 "show babel neighbour [INTERFACE]",
776 SHOW_STR
777 IP_STR
778 "Babel information\n"
779 "Print neighbours\n"
780 "Interface name\n")
781{
782 struct neighbour *neigh;
783 struct interface *ifp;
784
785 if (argc == 0) {
786 FOR_ALL_NEIGHBOURS(neigh) {
787 show_babel_neighbour_sub(vty, neigh);
788 }
789 return CMD_SUCCESS;
790 }
791 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
792 {
793 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
794 return CMD_WARNING;
795 }
796 FOR_ALL_NEIGHBOURS(neigh) {
797 if(ifp->ifindex == neigh->ifp->ifindex) {
798 show_babel_neighbour_sub(vty, neigh);
799 }
800 }
801 return CMD_SUCCESS;
802}
803
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100804static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100805show_babel_routes_sub (struct babel_route *route, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100806{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100807 struct vty *vty = (struct vty*) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100808 const unsigned char *nexthop =
809 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
810 NULL : route->nexthop;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100811 char channels[100];
812
813 if(route->channels[0] == 0)
814 channels[0] = '\0';
815 else {
816 int k, j = 0;
817 snprintf(channels, 100, " chan (");
818 j = strlen(channels);
819 for(k = 0; k < DIVERSITY_HOPS; k++) {
820 if(route->channels[k] == 0)
821 break;
822 if(k > 0)
823 channels[j++] = ',';
824 snprintf(channels + j, 100 - j, "%d", route->channels[k]);
825 j = strlen(channels);
826 }
827 snprintf(channels + j, 100 - j, ")");
828 if(k == 0)
829 channels[0] = '\0';
830 }
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100831
832 vty_out(vty,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100833 "%s metric %d refmetric %d id %s seqno %d%s age %d "
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100834 "via %s neigh %s%s%s%s%s",
835 format_prefix(route->src->prefix, route->src->plen),
836 route_metric(route), route->refmetric,
837 format_eui64(route->src->id),
838 (int)route->seqno,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100839 channels,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100840 (int)(babel_now.tv_sec - route->time),
841 route->neigh->ifp->name,
842 format_address(route->neigh->address),
843 nexthop ? " nexthop " : "",
844 nexthop ? format_address(nexthop) : "",
845 route->installed ? " (installed)" :
846 route_feasible(route) ? " (feasible)" : "",
847 VTY_NEWLINE);
848}
849
850static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100851show_babel_xroutes_sub (struct xroute *xroute, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100852{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100853 struct vty *vty = (struct vty *) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100854 vty_out(vty, "%s metric %d (exported)%s",
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100855 format_prefix(xroute->prefix, xroute->plen),
856 xroute->metric,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100857 VTY_NEWLINE);
858}
859
860DEFUN (show_babel_database,
861 show_babel_database_cmd,
862 "show babel database",
863 SHOW_STR
864 IP_STR
865 "Babel information\n"
866 "Database information\n"
867 "No attributes\n")
868{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100869 for_all_routes(show_babel_routes_sub, vty);
870 for_all_xroutes(show_babel_xroutes_sub, vty);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100871 return CMD_SUCCESS;
872}
873
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100874DEFUN (show_babel_running_config,
875 show_babel_running_config_cmd,
876 "show babel running-config",
877 SHOW_STR
878 IP_STR
879 "Babel information\n"
880 "Configuration information\n"
881 "No attributes\n")
882{
883 vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
884 show_babel_main_configuration(vty);
885 show_babeld_configuration(vty);
886 vty_out(vty, " -- ditribution lists --%s", VTY_NEWLINE);
887 config_show_distribute(vty);
888
889 return CMD_SUCCESS;
890}
891
Paul Jakma57345092011-12-25 17:52:09 +0100892void
893babel_if_init ()
894{
895 /* initialize interface list */
896 if_init();
897 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
898 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
899
900 babel_enable_if = vector_init (1);
901
902 /* install interface node and commands */
903 install_element (CONFIG_NODE, &interface_cmd);
904 install_element (CONFIG_NODE, &no_interface_cmd);
905 install_node (&babel_interface_node, interface_config_write);
906 install_default(INTERFACE_NODE);
907 install_element(INTERFACE_NODE, &interface_cmd);
908 install_element(INTERFACE_NODE, &no_interface_cmd);
909
910 install_element(BABEL_NODE, &babel_network_cmd);
911 install_element(BABEL_NODE, &no_babel_network_cmd);
912 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
913 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
914 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
915 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
916 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
917 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
918 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400919
920 /* "show babel ..." commands */
921 install_element (VIEW_NODE, &show_babel_interface_cmd);
922 install_element (ENABLE_NODE, &show_babel_interface_cmd);
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100923 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
924 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100925 install_element(VIEW_NODE, &show_babel_database_cmd);
926 install_element(ENABLE_NODE, &show_babel_database_cmd);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100927 install_element(VIEW_NODE, &show_babel_running_config_cmd);
928 install_element(ENABLE_NODE, &show_babel_running_config_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100929}
930
931/* hooks: functions called respectively when struct interface is
932 created or deleted. */
933static int
934babel_if_new_hook (struct interface *ifp)
935{
936 ifp->info = babel_interface_allocate();
937 return 0;
938}
939
940static int
941babel_if_delete_hook (struct interface *ifp)
942{
943 babel_interface_free(ifp->info);
944 ifp->info = NULL;
945 return 0;
946}
947
948/* Configuration write function for babeld. */
949static int
950interface_config_write (struct vty *vty)
951{
952 struct listnode *node;
953 struct interface *ifp;
Paul Jakma57345092011-12-25 17:52:09 +0100954 int write = 0;
955
956 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
Paul Jakma57345092011-12-25 17:52:09 +0100957 /* Do not display the interface if there is no configuration about it */
958 if (ifp->desc == NULL)
959 continue;
960
961 vty_out (vty, "interface %s%s", ifp->name,
962 VTY_NEWLINE);
963 if (ifp->desc)
964 vty_out (vty, " description %s%s", ifp->desc,
965 VTY_NEWLINE);
966
967 /* TODO: to be completed... */
968
969 vty_out (vty, "!%s", VTY_NEWLINE);
970
971 write++;
972 }
973 return write;
974}
975
976/* functions to allocate or free memory for a babel_interface_nfo, filling
977 needed fields */
978static babel_interface_nfo *
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +0100979babel_interface_allocate (void)
Paul Jakma57345092011-12-25 17:52:09 +0100980{
981 babel_interface_nfo *babel_ifp;
982 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
983 if(babel_ifp == NULL)
984 return NULL;
985
986 /* Here are set the default values for an interface. */
987 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
988 /* All flags are unset */
989 babel_ifp->activity_time = babel_now.tv_sec;
990 babel_ifp->bucket_time = babel_now.tv_sec;
991 babel_ifp->bucket = BUCKET_TOKENS_MAX;
992 babel_ifp->hello_seqno = (random() & 0xFFFF);
993 babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100994 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
Paul Jakma57345092011-12-25 17:52:09 +0100995
996 return babel_ifp;
997}
998
999static void
1000babel_interface_free (babel_interface_nfo *babel_ifp)
1001{
1002 XFREE(MTYPE_BABEL_IF, babel_ifp);
1003}