blob: 047a6ebfa7af8a458e668b74b948b9ed3262b21b [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
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +010060#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
61
Paul Jakma57345092011-12-25 17:52:09 +010062static int babel_enable_if_lookup (const char *ifname);
63static int babel_enable_if_add (const char *ifname);
64static int babel_enable_if_delete (const char *ifname);
65static int interface_recalculate(struct interface *ifp);
66static int interface_reset(struct interface *ifp);
67static int babel_if_new_hook (struct interface *ifp);
68static int babel_if_delete_hook (struct interface *ifp);
69static int interface_config_write (struct vty *vty);
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +010070static babel_interface_nfo * babel_interface_allocate (void);
Paul Jakma57345092011-12-25 17:52:09 +010071static void babel_interface_free (babel_interface_nfo *bi);
72
73
74static vector babel_enable_if; /* enable interfaces (by cmd). */
75static struct cmd_node babel_interface_node = /* babeld's interface node. */
76{
77 INTERFACE_NODE,
78 "%s(config-if)# ",
79 1 /* VTYSH */
80};
81
82
83int
84babel_interface_up (int cmd, struct zclient *client, zebra_size_t length)
85{
86 struct stream *s = NULL;
87 struct interface *ifp = NULL;
88
89 debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
90
91 s = zclient->ibuf;
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +010092 ifp = zebra_interface_state_read(s); /* it updates iflist */
Paul Jakma57345092011-12-25 17:52:09 +010093
94 if (ifp == NULL) {
95 return 0;
96 }
97
98 interface_recalculate(ifp);
99 return 0;
100}
101
102int
103babel_interface_down (int cmd, struct zclient *client, zebra_size_t length)
104{
105 struct stream *s = NULL;
106 struct interface *ifp = NULL;
107
108 debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
109
110 s = zclient->ibuf;
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100111 ifp = zebra_interface_state_read(s); /* it updates iflist */
Paul Jakma57345092011-12-25 17:52:09 +0100112
113 if (ifp == NULL) {
114 return 0;
115 }
116
117 interface_reset(ifp);
118 return 0;
119}
120
121int
122babel_interface_add (int cmd, struct zclient *client, zebra_size_t length)
123{
124 struct interface *ifp = NULL;
125
126 debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
127
128 /* read and add the interface in the iflist. */
129 ifp = zebra_interface_add_read (zclient->ibuf);
130
131 if (ifp == NULL) {
132 return 0;
133 }
134
135 interface_recalculate(ifp);
Paul Jakma57345092011-12-25 17:52:09 +0100136 return 0;
137}
138
139int
140babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length)
141{
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100142 struct interface *ifp;
143 struct stream *s;
144
Paul Jakma57345092011-12-25 17:52:09 +0100145 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100146
147 s = zclient->ibuf;
148 ifp = zebra_interface_state_read(s); /* it updates iflist */
149
150 if (ifp == NULL)
151 return 0;
152
153 if (IS_ENABLE(ifp))
154 interface_reset(ifp);
155
156 /* To support pseudo interface do not free interface structure. */
157 /* if_delete(ifp); */
158 ifp->ifindex = IFINDEX_INTERNAL;
159
Paul Jakma57345092011-12-25 17:52:09 +0100160 return 0;
161}
162
163int
164babel_interface_address_add (int cmd, struct zclient *client,
165 zebra_size_t length)
166{
167 babel_interface_nfo *babel_ifp;
168 struct connected *ifc;
169 struct prefix *prefix;
170
171 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
172
173 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
174 zclient->ibuf);
175
176 if (ifc == NULL)
177 return 0;
178
179 prefix = ifc->address;
180
181 if (prefix->family == AF_INET) {
182 flush_interface_routes(ifc->ifp, 0);
183 babel_ifp = babel_get_if_nfo(ifc->ifp);
184 if (babel_ifp->ipv4 == NULL) {
185 babel_ifp->ipv4 = malloc(4);
186 if (babel_ifp->ipv4 == NULL) {
187 zlog_err("not einough memory");
188 } else {
189 memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
190 }
191 }
192 }
193
194 send_request(ifc->ifp, NULL, 0);
195 send_update(ifc->ifp, 0, NULL, 0);
196
197 return 0;
198}
199
200int
201babel_interface_address_delete (int cmd, struct zclient *client,
202 zebra_size_t length)
203{
204 babel_interface_nfo *babel_ifp;
205 struct connected *ifc;
206 struct prefix *prefix;
207
208 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
209
210 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
211 zclient->ibuf);
212
213 if (ifc == NULL)
214 return 0;
215
216 prefix = ifc->address;
217
218 if (prefix->family == AF_INET) {
219 flush_interface_routes(ifc->ifp, 0);
220 babel_ifp = babel_get_if_nfo(ifc->ifp);
221 if (babel_ifp->ipv4 != NULL
222 && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) {
223 free(babel_ifp->ipv4);
224 babel_ifp->ipv4 = NULL;
225 }
226 }
227
228 send_request(ifc->ifp, NULL, 0);
229 send_update(ifc->ifp, 0, NULL, 0);
230
231 return 0;
232}
233
234/* Lookup function. */
235static int
236babel_enable_if_lookup (const char *ifname)
237{
238 unsigned int i;
239 char *str;
240
241 for (i = 0; i < vector_active (babel_enable_if); i++)
242 if ((str = vector_slot (babel_enable_if, i)) != NULL)
243 if (strcmp (str, ifname) == 0)
244 return i;
245 return -1;
246}
247
248/* Add interface to babel_enable_if. */
249static int
250babel_enable_if_add (const char *ifname)
251{
252 int ret;
253 struct interface *ifp = NULL;
254
255 ret = babel_enable_if_lookup (ifname);
256 if (ret >= 0)
257 return -1;
258
259 vector_set (babel_enable_if, strdup (ifname));
260
261 ifp = if_lookup_by_name(ifname);
262 if (ifp != NULL)
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100263 interface_recalculate(ifp);
Paul Jakma57345092011-12-25 17:52:09 +0100264
265 return 1;
266}
267
268/* Delete interface from babel_enable_if. */
269static int
270babel_enable_if_delete (const char *ifname)
271{
272 int babel_enable_if_index;
273 char *str;
274 struct interface *ifp = NULL;
275
276 babel_enable_if_index = babel_enable_if_lookup (ifname);
277 if (babel_enable_if_index < 0)
278 return -1;
279
280 str = vector_slot (babel_enable_if, babel_enable_if_index);
281 free (str);
282 vector_unset (babel_enable_if, babel_enable_if_index);
283
284 ifp = if_lookup_by_name(ifname);
285 if (ifp != NULL)
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100286 interface_reset(ifp);
Paul Jakma57345092011-12-25 17:52:09 +0100287
288 return 1;
289}
290
291
292/* [Babel Command] Babel enable on specified interface or matched network. */
293DEFUN (babel_network,
294 babel_network_cmd,
295 "network IF_OR_ADDR",
296 "Babel enable on specified interface or network.\n"
297 "Interface or address")
298{
299 int ret;
300 struct prefix p;
301
302 ret = str2prefix (argv[0], &p);
303
304 /* Given string is: */
305 if (ret) /* an IPv4 or v6 network */
306 return CMD_ERR_NO_MATCH; /* not implemented yet */
307 else /* an interface name */
308 ret = babel_enable_if_add (argv[0]);
309
310 if (ret < 0) {
311 vty_out (vty, "There is same network configuration %s%s", argv[0],
312 VTY_NEWLINE);
313 return CMD_WARNING;
314 }
315
316 return CMD_SUCCESS;
317}
318
319/* [Babel Command] Babel enable on specified interface or matched network. */
320DEFUN (no_babel_network,
321 no_babel_network_cmd,
322 "no network IF_OR_ADDR",
323 NO_STR
324 "Babel enable on specified interface or network.\n"
325 "Interface or address")
326{
327 int ret;
328 struct prefix p;
329
330 ret = str2prefix (argv[0], &p);
331
332 /* Given string is: */
333 if (ret) /* an IPv4 or v6 network */
334 return CMD_ERR_NO_MATCH; /* not implemented yet */
335 else /* an interface name */
336 ret = babel_enable_if_delete (argv[0]);
337
338 if (ret < 0) {
339 vty_out (vty, "can't find network %s%s", argv[0],
340 VTY_NEWLINE);
341 return CMD_WARNING;
342 }
343
344 return CMD_SUCCESS;
345}
346
347/* [Interface Command] Tell the interface is wire. */
348DEFUN (babel_set_wired,
349 babel_set_wired_cmd,
350 "wired",
351 "Set this interface as wired (default: wireless).\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] Tell the interface is wireless (default). */
366DEFUN (babel_set_wireless,
367 babel_set_wireless_cmd,
368 "wireless",
369 NO_STR
370 "Set this interface as wireless (is default).\n"
371 "No attributes")
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_WIRED;
381 return CMD_SUCCESS;
382}
383
384/* [Interface Command] Enable split horizon. */
385DEFUN (babel_split_horizon,
386 babel_split_horizon_cmd,
387 "babel split-horizon",
388 IPV6_STR
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100389 "Perform split horizon\n"
390 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100391{
392 struct interface *ifp;
393 babel_interface_nfo *babel_ifp;
394
395 ifp = vty->index;
396 babel_ifp = babel_get_if_nfo(ifp);
397
398 assert (babel_ifp != NULL);
399 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
400 return CMD_SUCCESS;
401}
402
403/* [Interface Command] Disable split horizon (default). */
404DEFUN (no_babel_split_horizon,
405 no_babel_split_horizon_cmd,
406 "no babel split-horizon",
407 NO_STR
408 IPV6_STR
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100409 "Disable split horizon\n"
410 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100411{
412 struct interface *ifp;
413 babel_interface_nfo *babel_ifp;
414
415 ifp = vty->index;
416 babel_ifp = babel_get_if_nfo(ifp);
417
418 assert (babel_ifp != NULL);
419 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
420 return CMD_SUCCESS;
421}
422
423/* [Interface Command]. */
424DEFUN (babel_set_hello_interval,
425 babel_set_hello_interval_cmd,
426 "hello interval <5-1000000>",
427 "Set interface's hello interval (default: 4000).\n"
428 "Value in miliseconds\n")
429{
430 struct interface *ifp;
431 babel_interface_nfo *babel_ifp;
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100432 int interval;
Paul Jakma57345092011-12-25 17:52:09 +0100433
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100434 VTY_GET_INTEGER_RANGE("hello interval", interval, argv[0], 20, 10 * 0xFFFE);
Paul Jakma57345092011-12-25 17:52:09 +0100435
436 ifp = vty->index;
437 babel_ifp = babel_get_if_nfo(ifp);
Paul Jakma57345092011-12-25 17:52:09 +0100438 assert (babel_ifp != NULL);
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100439
Paul Jakma57345092011-12-25 17:52:09 +0100440 babel_ifp->hello_interval = interval;
441 return CMD_SUCCESS;
442}
443
444/* [Interface Command]. */
445DEFUN (babel_passive_interface,
446 babel_passive_interface_cmd,
447 "passive-interface",
448 "The daemon will only announce redistributed routes\n"
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100449 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100450{
451 if (allow_duplicates) {
452 return CMD_WARNING;
453 }
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100454 parasitic = 1;
Paul Jakma57345092011-12-25 17:52:09 +0100455 return CMD_SUCCESS;
456}
457
458/* [Interface Command]. */
459DEFUN (no_babel_passive_interface,
460 no_babel_passive_interface_cmd,
461 "no passive-interface",
462 NO_STR
463 "The daemon will announce all (filtred) routes\n"
Matthieu Boutier3f031ed2012-01-18 23:03:00 +0100464 "No attributes\n")
Paul Jakma57345092011-12-25 17:52:09 +0100465{
466 parasitic = 0;
467 return CMD_SUCCESS;
468}
469
470
471int
472interface_idle(babel_interface_nfo *babel_ifp)
473{
474 return (idle_hello_interval > 0 &&
475 babel_ifp->activity_time < babel_now.tv_sec - idle_time);
476}
477
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100478int
479update_hello_interval(struct interface *ifp)
480{
481 int rc = 0;
482 unsigned short interval;
483 struct babel_interface *babel_ifp = babel_get_if_nfo(ifp);
484
485 if(interface_idle(babel_ifp))
486 interval = idle_hello_interval;
487 else if(IF_CONF(ifp, hello_interval) > 0)
488 interval = IF_CONF(ifp, hello_interval);
489 else if((ifp->flags & BABEL_IF_WIRED))
490 interval = wired_hello_interval;
491 else
492 interval = wireless_hello_interval;
493
494 if(babel_ifp->hello_interval != interval) {
495 babel_ifp->hello_interval = interval;
496 rc = 1;
497 }
498
499 return rc;
500}
501
Paul Jakma57345092011-12-25 17:52:09 +0100502/* This should be no more than half the hello interval, so that hellos
503 aren't sent late. The result is in milliseconds. */
504unsigned
505jitter(babel_interface_nfo *babel_ifp, int urgent)
506{
507 unsigned interval = babel_ifp->hello_interval;
508 if(urgent)
509 interval = MIN(interval, 100);
510 else
511 interval = MIN(interval, 4000);
512 return roughly(interval) / 4;
513}
514
515unsigned
516update_jitter(babel_interface_nfo *babel_ifp, int urgent)
517{
518 unsigned interval = babel_ifp->hello_interval;
519 if(urgent)
520 interval = MIN(interval, 100);
521 else
522 interval = MIN(interval, 4000);
523 return roughly(interval);
524}
525
526/* calculate babeld's specific datas of an interface (change when the interface
527 change) */
528static int
529interface_recalculate(struct interface *ifp)
530{
531 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
532 unsigned char *tmp = NULL;
533 int mtu, rc;
534 struct ipv6_mreq mreq;
535
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100536 if (!IS_ENABLE(ifp))
537 return -1;
538
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100539 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
540 interface_reset(ifp);
541 return -1;
542 }
543
544 babel_ifp->flags |= BABEL_IF_IS_UP;
545
Paul Jakma57345092011-12-25 17:52:09 +0100546 mtu = MIN(ifp->mtu, ifp->mtu6);
547
548 /* We need to be able to fit at least two messages into a packet,
549 so MTUs below 116 require lower layer fragmentation. */
550 /* In IPv6, the minimum MTU is 1280, and every host must be able
551 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
552 if(mtu < 128) {
553 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
554 mtu, ifp->name, ifp->ifindex);
555 mtu = 128;
556 }
557
558 /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
559 babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
560 tmp = babel_ifp->sendbuf;
561 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
562 if(babel_ifp->sendbuf == NULL) {
Matthieu Boutier4eedea52012-01-17 22:46:21 +0100563 zlog_err("Couldn't reallocate sendbuf.");
Paul Jakma57345092011-12-25 17:52:09 +0100564 free(tmp);
565 babel_ifp->bufsize = 0;
566 return -1;
567 }
568 tmp = NULL;
569
570 resize_receive_buffer(mtu);
571
572 if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */
573 babel_ifp->cost = 96;
574 babel_ifp->flags &= ~BABEL_IF_LQ;
575 } else {
576 babel_ifp->cost = 256;
577 babel_ifp->flags |= BABEL_IF_LQ;
578 }
579
580 babel_ifp->activity_time = babel_now.tv_sec;
581 /* Since the interface was marked as active above, the
582 idle_hello_interval cannot be the one being used here. */
583 babel_ifp->update_interval = babel_ifp->hello_interval * 4;
584
585 memset(&mreq, 0, sizeof(mreq));
586 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
587 mreq.ipv6mr_interface = ifp->ifindex;
588
589 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
590 (char*)&mreq, sizeof(mreq));
591 if(rc < 0) {
592 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
593 ifp->name, safe_strerror(errno));
594 /* This is probably due to a missing link-local address,
595 so down this interface, and wait until the main loop
596 tries to up it again. */
597 interface_reset(ifp);
598 return -1;
599 }
600
601 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
602 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
603 send_hello(ifp);
604 send_request(ifp, NULL, 0);
605
606 update_interface_metric(ifp);
607
608 debugf(BABEL_DEBUG_COMMON,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100609 "Upped interface %s (%s, cost=%d, channel=%d%s).",
Paul Jakma57345092011-12-25 17:52:09 +0100610 ifp->name,
611 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
612 babel_ifp->cost,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100613 babel_ifp->channel,
Paul Jakma57345092011-12-25 17:52:09 +0100614 babel_ifp->ipv4 ? ", IPv4" : "");
615
616 if(rc > 0)
617 send_update(ifp, 0, NULL, 0);
618
Paul Jakma57345092011-12-25 17:52:09 +0100619 return 1;
620}
621
622/* Reset the interface as it was new: it's not removed from the interface list,
623 and may be considered as a upped interface. */
624static int
625interface_reset(struct interface *ifp)
626{
627 int rc;
628 struct ipv6_mreq mreq;
629 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
630
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100631 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
632 return 0;
633
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100634 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
635 babel_ifp->flags &= ~BABEL_IF_IS_UP;
636
Paul Jakma57345092011-12-25 17:52:09 +0100637 flush_interface_routes(ifp, 0);
638 babel_ifp->buffered = 0;
639 babel_ifp->bufsize = 0;
640 free(babel_ifp->sendbuf);
641 babel_ifp->num_buffered_updates = 0;
642 babel_ifp->update_bufsize = 0;
643 if(babel_ifp->buffered_updates)
644 free(babel_ifp->buffered_updates);
645 babel_ifp->buffered_updates = NULL;
646 babel_ifp->sendbuf = NULL;
647
648 if(ifp->ifindex > 0) {
649 memset(&mreq, 0, sizeof(mreq));
650 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
651 mreq.ipv6mr_interface = ifp->ifindex;
652 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
653 (char*)&mreq, sizeof(mreq));
654 if(rc < 0)
655 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
656 ifp->name, safe_strerror(errno));
657 }
658
659 update_interface_metric(ifp);
660
661 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
662 ifp->name,
663 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
664 babel_ifp->cost,
665 babel_ifp->ipv4 ? ", IPv4" : "");
666
667 return 1;
668}
669
670/* Send retraction to all, and reset all interfaces statistics. */
671void
672babel_interface_close_all(void)
673{
674 struct interface *ifp = NULL;
675 struct listnode *linklist_node = NULL;
676
677 FOR_ALL_INTERFACES(ifp, linklist_node) {
678 if(!if_up(ifp))
679 continue;
680 send_wildcard_retraction(ifp);
681 /* Make sure that we expire quickly from our neighbours'
682 association caches. */
683 send_hello_noupdate(ifp, 10);
684 flushbuf(ifp);
685 usleep(roughly(1000));
686 gettime(&babel_now);
687 }
688 FOR_ALL_INTERFACES(ifp, linklist_node) {
689 if(!if_up(ifp))
690 continue;
691 /* Make sure they got it. */
692 send_wildcard_retraction(ifp);
693 send_hello_noupdate(ifp, 1);
694 flushbuf(ifp);
695 usleep(roughly(10000));
696 gettime(&babel_now);
697 interface_reset(ifp);
698 }
699}
700
701/* return "true" if address is one of our ipv6 addresses */
702int
703is_interface_ll_address(struct interface *ifp, const unsigned char *address)
704{
705 struct connected *connected;
706 struct listnode *node;
707
708 if(!if_up(ifp))
709 return 0;
710
711 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
712 if(connected->address->family == AF_INET6 &&
713 memcmp(&connected->address->u.prefix6, address, 16) == 0)
714 return 1;
715 }
716
717 return 0;
718}
719
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400720static void
721show_babel_interface_sub (struct vty *vty, struct interface *ifp)
722{
723 int is_up;
724 babel_interface_nfo *babel_ifp;
725
726 vty_out (vty, "%s is %s%s", ifp->name,
727 ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
728 vty_out (vty, " ifindex %u, MTU %u bytes %s%s",
729 ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
730
731 if (babel_enable_if_lookup (ifp->name) < 0)
732 {
733 vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
734 return;
735 }
736 if (!is_up)
737 {
738 vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
739 return;
740 }
741 babel_ifp = babel_get_if_nfo (ifp);
742 vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE);
743 vty_out (vty, " Operating mode is \"%s\"%s",
744 CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
745 vty_out (vty, " Split horizon mode is %s%s",
746 CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
747 vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
748}
749
750DEFUN (show_babel_interface,
751 show_babel_interface_cmd,
752 "show babel interface [INTERFACE]",
753 SHOW_STR
754 IP_STR
755 "Babel information\n"
756 "Interface information\n"
757 "Interface name\n")
758{
759 struct interface *ifp;
760 struct listnode *node;
761
762 if (argc == 0)
763 {
764 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
765 show_babel_interface_sub (vty, ifp);
766 return CMD_SUCCESS;
767 }
768 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
769 {
770 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
771 return CMD_WARNING;
772 }
773 show_babel_interface_sub (vty, ifp);
774 return CMD_SUCCESS;
775}
Paul Jakma57345092011-12-25 17:52:09 +0100776
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100777static void
778show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
779{
780 vty_out (vty,
781 "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
782 format_address(neigh->address),
783 neigh->ifp->name,
784 neigh->reach,
785 neighbour_rxcost(neigh),
786 neigh->txcost,
787 if_up(neigh->ifp) ? "" : " (down)",
788 VTY_NEWLINE);
789}
790
791DEFUN (show_babel_neighbour,
792 show_babel_neighbour_cmd,
793 "show babel neighbour [INTERFACE]",
794 SHOW_STR
795 IP_STR
796 "Babel information\n"
797 "Print neighbours\n"
798 "Interface name\n")
799{
800 struct neighbour *neigh;
801 struct interface *ifp;
802
803 if (argc == 0) {
804 FOR_ALL_NEIGHBOURS(neigh) {
805 show_babel_neighbour_sub(vty, neigh);
806 }
807 return CMD_SUCCESS;
808 }
809 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
810 {
811 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
812 return CMD_WARNING;
813 }
814 FOR_ALL_NEIGHBOURS(neigh) {
815 if(ifp->ifindex == neigh->ifp->ifindex) {
816 show_babel_neighbour_sub(vty, neigh);
817 }
818 }
819 return CMD_SUCCESS;
820}
821
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100822static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100823show_babel_routes_sub (struct babel_route *route, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100824{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100825 struct vty *vty = (struct vty*) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100826 const unsigned char *nexthop =
827 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
828 NULL : route->nexthop;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100829 char channels[100];
830
831 if(route->channels[0] == 0)
832 channels[0] = '\0';
833 else {
834 int k, j = 0;
835 snprintf(channels, 100, " chan (");
836 j = strlen(channels);
837 for(k = 0; k < DIVERSITY_HOPS; k++) {
838 if(route->channels[k] == 0)
839 break;
840 if(k > 0)
841 channels[j++] = ',';
842 snprintf(channels + j, 100 - j, "%d", route->channels[k]);
843 j = strlen(channels);
844 }
845 snprintf(channels + j, 100 - j, ")");
846 if(k == 0)
847 channels[0] = '\0';
848 }
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100849
850 vty_out(vty,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100851 "%s metric %d refmetric %d id %s seqno %d%s age %d "
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100852 "via %s neigh %s%s%s%s%s",
853 format_prefix(route->src->prefix, route->src->plen),
854 route_metric(route), route->refmetric,
855 format_eui64(route->src->id),
856 (int)route->seqno,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100857 channels,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100858 (int)(babel_now.tv_sec - route->time),
859 route->neigh->ifp->name,
860 format_address(route->neigh->address),
861 nexthop ? " nexthop " : "",
862 nexthop ? format_address(nexthop) : "",
863 route->installed ? " (installed)" :
864 route_feasible(route) ? " (feasible)" : "",
865 VTY_NEWLINE);
866}
867
868static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100869show_babel_xroutes_sub (struct xroute *xroute, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100870{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100871 struct vty *vty = (struct vty *) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100872 vty_out(vty, "%s metric %d (exported)%s",
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100873 format_prefix(xroute->prefix, xroute->plen),
874 xroute->metric,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100875 VTY_NEWLINE);
876}
877
878DEFUN (show_babel_database,
879 show_babel_database_cmd,
880 "show babel database",
881 SHOW_STR
882 IP_STR
883 "Babel information\n"
884 "Database information\n"
885 "No attributes\n")
886{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100887 for_all_routes(show_babel_routes_sub, vty);
888 for_all_xroutes(show_babel_xroutes_sub, vty);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100889 return CMD_SUCCESS;
890}
891
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100892DEFUN (show_babel_running_config,
893 show_babel_running_config_cmd,
894 "show babel running-config",
895 SHOW_STR
896 IP_STR
897 "Babel information\n"
898 "Configuration information\n"
899 "No attributes\n")
900{
901 vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
902 show_babel_main_configuration(vty);
903 show_babeld_configuration(vty);
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100904 vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100905 config_show_distribute(vty);
906
907 return CMD_SUCCESS;
908}
909
Paul Jakma57345092011-12-25 17:52:09 +0100910void
911babel_if_init ()
912{
913 /* initialize interface list */
914 if_init();
915 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
916 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
917
918 babel_enable_if = vector_init (1);
919
920 /* install interface node and commands */
921 install_element (CONFIG_NODE, &interface_cmd);
922 install_element (CONFIG_NODE, &no_interface_cmd);
923 install_node (&babel_interface_node, interface_config_write);
924 install_default(INTERFACE_NODE);
925 install_element(INTERFACE_NODE, &interface_cmd);
926 install_element(INTERFACE_NODE, &no_interface_cmd);
927
928 install_element(BABEL_NODE, &babel_network_cmd);
929 install_element(BABEL_NODE, &no_babel_network_cmd);
930 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
931 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
932 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
933 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
934 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
935 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
936 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400937
Juliusz Chroboczekec0c8482012-02-07 05:44:41 +0100938 /* "show babel ..." commands */
939 install_element(VIEW_NODE, &show_babel_interface_cmd);
940 install_element(ENABLE_NODE, &show_babel_interface_cmd);
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100941 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
942 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100943 install_element(VIEW_NODE, &show_babel_database_cmd);
944 install_element(ENABLE_NODE, &show_babel_database_cmd);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100945 install_element(VIEW_NODE, &show_babel_running_config_cmd);
946 install_element(ENABLE_NODE, &show_babel_running_config_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100947}
948
949/* hooks: functions called respectively when struct interface is
950 created or deleted. */
951static int
952babel_if_new_hook (struct interface *ifp)
953{
954 ifp->info = babel_interface_allocate();
955 return 0;
956}
957
958static int
959babel_if_delete_hook (struct interface *ifp)
960{
961 babel_interface_free(ifp->info);
962 ifp->info = NULL;
963 return 0;
964}
965
966/* Configuration write function for babeld. */
967static int
968interface_config_write (struct vty *vty)
969{
970 struct listnode *node;
971 struct interface *ifp;
Paul Jakma57345092011-12-25 17:52:09 +0100972 int write = 0;
973
974 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
Paul Jakma57345092011-12-25 17:52:09 +0100975 /* Do not display the interface if there is no configuration about it */
976 if (ifp->desc == NULL)
977 continue;
978
979 vty_out (vty, "interface %s%s", ifp->name,
980 VTY_NEWLINE);
981 if (ifp->desc)
982 vty_out (vty, " description %s%s", ifp->desc,
983 VTY_NEWLINE);
984
985 /* TODO: to be completed... */
986
987 vty_out (vty, "!%s", VTY_NEWLINE);
988
989 write++;
990 }
991 return write;
992}
993
994/* functions to allocate or free memory for a babel_interface_nfo, filling
995 needed fields */
996static babel_interface_nfo *
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +0100997babel_interface_allocate (void)
Paul Jakma57345092011-12-25 17:52:09 +0100998{
999 babel_interface_nfo *babel_ifp;
1000 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
1001 if(babel_ifp == NULL)
1002 return NULL;
1003
1004 /* Here are set the default values for an interface. */
1005 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
1006 /* All flags are unset */
1007 babel_ifp->activity_time = babel_now.tv_sec;
1008 babel_ifp->bucket_time = babel_now.tv_sec;
1009 babel_ifp->bucket = BUCKET_TOKENS_MAX;
1010 babel_ifp->hello_seqno = (random() & 0xFFFF);
1011 babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +01001012 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
Paul Jakma57345092011-12-25 17:52:09 +01001013
1014 return babel_ifp;
1015}
1016
1017static void
1018babel_interface_free (babel_interface_nfo *babel_ifp)
1019{
1020 XFREE(MTYPE_BABEL_IF, babel_ifp);
1021}