blob: 0f254eccd6da238c10e9a5f13cce5f60ec994d32 [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,
Matthieu Boutier3c442e82012-02-08 23:30:46 +0100350 "babel wired",
Paul Jakma57345092011-12-25 17:52:09 +0100351 "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,
Matthieu Boutier3c442e82012-02-08 23:30:46 +0100368 "babel wireless",
Paul Jakma57345092011-12-25 17:52:09 +0100369 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
Paul Jakma57345092011-12-25 17:52:09 +0100470/* This should be no more than half the hello interval, so that hellos
471 aren't sent late. The result is in milliseconds. */
472unsigned
473jitter(babel_interface_nfo *babel_ifp, int urgent)
474{
475 unsigned interval = babel_ifp->hello_interval;
476 if(urgent)
477 interval = MIN(interval, 100);
478 else
479 interval = MIN(interval, 4000);
480 return roughly(interval) / 4;
481}
482
483unsigned
484update_jitter(babel_interface_nfo *babel_ifp, int urgent)
485{
486 unsigned interval = babel_ifp->hello_interval;
487 if(urgent)
488 interval = MIN(interval, 100);
489 else
490 interval = MIN(interval, 4000);
491 return roughly(interval);
492}
493
494/* calculate babeld's specific datas of an interface (change when the interface
495 change) */
496static int
497interface_recalculate(struct interface *ifp)
498{
499 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
500 unsigned char *tmp = NULL;
501 int mtu, rc;
502 struct ipv6_mreq mreq;
503
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100504 if (!IS_ENABLE(ifp))
505 return -1;
506
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100507 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
508 interface_reset(ifp);
509 return -1;
510 }
511
512 babel_ifp->flags |= BABEL_IF_IS_UP;
513
Paul Jakma57345092011-12-25 17:52:09 +0100514 mtu = MIN(ifp->mtu, ifp->mtu6);
515
516 /* We need to be able to fit at least two messages into a packet,
517 so MTUs below 116 require lower layer fragmentation. */
518 /* In IPv6, the minimum MTU is 1280, and every host must be able
519 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
520 if(mtu < 128) {
521 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
522 mtu, ifp->name, ifp->ifindex);
523 mtu = 128;
524 }
525
526 /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
527 babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
528 tmp = babel_ifp->sendbuf;
529 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
530 if(babel_ifp->sendbuf == NULL) {
Matthieu Boutier4eedea52012-01-17 22:46:21 +0100531 zlog_err("Couldn't reallocate sendbuf.");
Paul Jakma57345092011-12-25 17:52:09 +0100532 free(tmp);
533 babel_ifp->bufsize = 0;
534 return -1;
535 }
536 tmp = NULL;
537
538 resize_receive_buffer(mtu);
539
540 if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */
541 babel_ifp->cost = 96;
542 babel_ifp->flags &= ~BABEL_IF_LQ;
543 } else {
544 babel_ifp->cost = 256;
545 babel_ifp->flags |= BABEL_IF_LQ;
546 }
547
Paul Jakma57345092011-12-25 17:52:09 +0100548 /* Since the interface was marked as active above, the
549 idle_hello_interval cannot be the one being used here. */
550 babel_ifp->update_interval = babel_ifp->hello_interval * 4;
551
552 memset(&mreq, 0, sizeof(mreq));
553 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
554 mreq.ipv6mr_interface = ifp->ifindex;
555
556 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
557 (char*)&mreq, sizeof(mreq));
558 if(rc < 0) {
559 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
560 ifp->name, safe_strerror(errno));
561 /* This is probably due to a missing link-local address,
562 so down this interface, and wait until the main loop
563 tries to up it again. */
564 interface_reset(ifp);
565 return -1;
566 }
567
568 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
569 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
570 send_hello(ifp);
571 send_request(ifp, NULL, 0);
572
573 update_interface_metric(ifp);
574
575 debugf(BABEL_DEBUG_COMMON,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100576 "Upped interface %s (%s, cost=%d, channel=%d%s).",
Paul Jakma57345092011-12-25 17:52:09 +0100577 ifp->name,
578 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
579 babel_ifp->cost,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100580 babel_ifp->channel,
Paul Jakma57345092011-12-25 17:52:09 +0100581 babel_ifp->ipv4 ? ", IPv4" : "");
582
583 if(rc > 0)
584 send_update(ifp, 0, NULL, 0);
585
Paul Jakma57345092011-12-25 17:52:09 +0100586 return 1;
587}
588
589/* Reset the interface as it was new: it's not removed from the interface list,
590 and may be considered as a upped interface. */
591static int
592interface_reset(struct interface *ifp)
593{
594 int rc;
595 struct ipv6_mreq mreq;
596 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
597
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100598 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
599 return 0;
600
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100601 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
602 babel_ifp->flags &= ~BABEL_IF_IS_UP;
603
Paul Jakma57345092011-12-25 17:52:09 +0100604 flush_interface_routes(ifp, 0);
605 babel_ifp->buffered = 0;
606 babel_ifp->bufsize = 0;
607 free(babel_ifp->sendbuf);
608 babel_ifp->num_buffered_updates = 0;
609 babel_ifp->update_bufsize = 0;
610 if(babel_ifp->buffered_updates)
611 free(babel_ifp->buffered_updates);
612 babel_ifp->buffered_updates = NULL;
613 babel_ifp->sendbuf = NULL;
614
615 if(ifp->ifindex > 0) {
616 memset(&mreq, 0, sizeof(mreq));
617 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
618 mreq.ipv6mr_interface = ifp->ifindex;
619 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
620 (char*)&mreq, sizeof(mreq));
621 if(rc < 0)
622 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
623 ifp->name, safe_strerror(errno));
624 }
625
626 update_interface_metric(ifp);
627
628 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
629 ifp->name,
630 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
631 babel_ifp->cost,
632 babel_ifp->ipv4 ? ", IPv4" : "");
633
634 return 1;
635}
636
637/* Send retraction to all, and reset all interfaces statistics. */
638void
639babel_interface_close_all(void)
640{
641 struct interface *ifp = NULL;
642 struct listnode *linklist_node = NULL;
643
644 FOR_ALL_INTERFACES(ifp, linklist_node) {
645 if(!if_up(ifp))
646 continue;
647 send_wildcard_retraction(ifp);
648 /* Make sure that we expire quickly from our neighbours'
649 association caches. */
650 send_hello_noupdate(ifp, 10);
651 flushbuf(ifp);
652 usleep(roughly(1000));
653 gettime(&babel_now);
654 }
655 FOR_ALL_INTERFACES(ifp, linklist_node) {
656 if(!if_up(ifp))
657 continue;
658 /* Make sure they got it. */
659 send_wildcard_retraction(ifp);
660 send_hello_noupdate(ifp, 1);
661 flushbuf(ifp);
662 usleep(roughly(10000));
663 gettime(&babel_now);
664 interface_reset(ifp);
665 }
666}
667
668/* return "true" if address is one of our ipv6 addresses */
669int
670is_interface_ll_address(struct interface *ifp, const unsigned char *address)
671{
672 struct connected *connected;
673 struct listnode *node;
674
675 if(!if_up(ifp))
676 return 0;
677
678 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
679 if(connected->address->family == AF_INET6 &&
680 memcmp(&connected->address->u.prefix6, address, 16) == 0)
681 return 1;
682 }
683
684 return 0;
685}
686
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400687static void
688show_babel_interface_sub (struct vty *vty, struct interface *ifp)
689{
690 int is_up;
691 babel_interface_nfo *babel_ifp;
692
693 vty_out (vty, "%s is %s%s", ifp->name,
694 ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
695 vty_out (vty, " ifindex %u, MTU %u bytes %s%s",
696 ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
697
698 if (babel_enable_if_lookup (ifp->name) < 0)
699 {
700 vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
701 return;
702 }
703 if (!is_up)
704 {
705 vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
706 return;
707 }
708 babel_ifp = babel_get_if_nfo (ifp);
709 vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE);
710 vty_out (vty, " Operating mode is \"%s\"%s",
711 CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
712 vty_out (vty, " Split horizon mode is %s%s",
713 CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
714 vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
715}
716
717DEFUN (show_babel_interface,
718 show_babel_interface_cmd,
719 "show babel interface [INTERFACE]",
720 SHOW_STR
721 IP_STR
722 "Babel information\n"
723 "Interface information\n"
724 "Interface name\n")
725{
726 struct interface *ifp;
727 struct listnode *node;
728
729 if (argc == 0)
730 {
731 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
732 show_babel_interface_sub (vty, ifp);
733 return CMD_SUCCESS;
734 }
735 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
736 {
737 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
738 return CMD_WARNING;
739 }
740 show_babel_interface_sub (vty, ifp);
741 return CMD_SUCCESS;
742}
Paul Jakma57345092011-12-25 17:52:09 +0100743
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100744static void
745show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
746{
747 vty_out (vty,
748 "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
749 format_address(neigh->address),
750 neigh->ifp->name,
751 neigh->reach,
752 neighbour_rxcost(neigh),
753 neigh->txcost,
754 if_up(neigh->ifp) ? "" : " (down)",
755 VTY_NEWLINE);
756}
757
758DEFUN (show_babel_neighbour,
759 show_babel_neighbour_cmd,
760 "show babel neighbour [INTERFACE]",
761 SHOW_STR
762 IP_STR
763 "Babel information\n"
764 "Print neighbours\n"
765 "Interface name\n")
766{
767 struct neighbour *neigh;
768 struct interface *ifp;
769
770 if (argc == 0) {
771 FOR_ALL_NEIGHBOURS(neigh) {
772 show_babel_neighbour_sub(vty, neigh);
773 }
774 return CMD_SUCCESS;
775 }
776 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
777 {
778 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
779 return CMD_WARNING;
780 }
781 FOR_ALL_NEIGHBOURS(neigh) {
782 if(ifp->ifindex == neigh->ifp->ifindex) {
783 show_babel_neighbour_sub(vty, neigh);
784 }
785 }
786 return CMD_SUCCESS;
787}
788
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100789static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100790show_babel_routes_sub (struct babel_route *route, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100791{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100792 struct vty *vty = (struct vty*) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100793 const unsigned char *nexthop =
794 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
795 NULL : route->nexthop;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100796 char channels[100];
797
798 if(route->channels[0] == 0)
799 channels[0] = '\0';
800 else {
801 int k, j = 0;
802 snprintf(channels, 100, " chan (");
803 j = strlen(channels);
804 for(k = 0; k < DIVERSITY_HOPS; k++) {
805 if(route->channels[k] == 0)
806 break;
807 if(k > 0)
808 channels[j++] = ',';
809 snprintf(channels + j, 100 - j, "%d", route->channels[k]);
810 j = strlen(channels);
811 }
812 snprintf(channels + j, 100 - j, ")");
813 if(k == 0)
814 channels[0] = '\0';
815 }
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100816
817 vty_out(vty,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100818 "%s metric %d refmetric %d id %s seqno %d%s age %d "
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100819 "via %s neigh %s%s%s%s%s",
820 format_prefix(route->src->prefix, route->src->plen),
821 route_metric(route), route->refmetric,
822 format_eui64(route->src->id),
823 (int)route->seqno,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100824 channels,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100825 (int)(babel_now.tv_sec - route->time),
826 route->neigh->ifp->name,
827 format_address(route->neigh->address),
828 nexthop ? " nexthop " : "",
829 nexthop ? format_address(nexthop) : "",
830 route->installed ? " (installed)" :
831 route_feasible(route) ? " (feasible)" : "",
832 VTY_NEWLINE);
833}
834
835static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100836show_babel_xroutes_sub (struct xroute *xroute, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100837{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100838 struct vty *vty = (struct vty *) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100839 vty_out(vty, "%s metric %d (exported)%s",
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100840 format_prefix(xroute->prefix, xroute->plen),
841 xroute->metric,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100842 VTY_NEWLINE);
843}
844
845DEFUN (show_babel_database,
846 show_babel_database_cmd,
847 "show babel database",
848 SHOW_STR
849 IP_STR
850 "Babel information\n"
851 "Database information\n"
852 "No attributes\n")
853{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100854 for_all_routes(show_babel_routes_sub, vty);
855 for_all_xroutes(show_babel_xroutes_sub, vty);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100856 return CMD_SUCCESS;
857}
858
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100859DEFUN (show_babel_running_config,
860 show_babel_running_config_cmd,
861 "show babel running-config",
862 SHOW_STR
863 IP_STR
864 "Babel information\n"
865 "Configuration information\n"
866 "No attributes\n")
867{
868 vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
869 show_babel_main_configuration(vty);
870 show_babeld_configuration(vty);
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100871 vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100872 config_show_distribute(vty);
873
874 return CMD_SUCCESS;
875}
876
Paul Jakma57345092011-12-25 17:52:09 +0100877void
878babel_if_init ()
879{
880 /* initialize interface list */
881 if_init();
882 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
883 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
884
885 babel_enable_if = vector_init (1);
886
887 /* install interface node and commands */
888 install_element (CONFIG_NODE, &interface_cmd);
889 install_element (CONFIG_NODE, &no_interface_cmd);
890 install_node (&babel_interface_node, interface_config_write);
891 install_default(INTERFACE_NODE);
892 install_element(INTERFACE_NODE, &interface_cmd);
893 install_element(INTERFACE_NODE, &no_interface_cmd);
894
895 install_element(BABEL_NODE, &babel_network_cmd);
896 install_element(BABEL_NODE, &no_babel_network_cmd);
897 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
898 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
899 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
900 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
901 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
902 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
903 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400904
Juliusz Chroboczekec0c8482012-02-07 05:44:41 +0100905 /* "show babel ..." commands */
906 install_element(VIEW_NODE, &show_babel_interface_cmd);
907 install_element(ENABLE_NODE, &show_babel_interface_cmd);
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100908 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
909 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100910 install_element(VIEW_NODE, &show_babel_database_cmd);
911 install_element(ENABLE_NODE, &show_babel_database_cmd);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100912 install_element(VIEW_NODE, &show_babel_running_config_cmd);
913 install_element(ENABLE_NODE, &show_babel_running_config_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100914}
915
916/* hooks: functions called respectively when struct interface is
917 created or deleted. */
918static int
919babel_if_new_hook (struct interface *ifp)
920{
921 ifp->info = babel_interface_allocate();
922 return 0;
923}
924
925static int
926babel_if_delete_hook (struct interface *ifp)
927{
928 babel_interface_free(ifp->info);
929 ifp->info = NULL;
930 return 0;
931}
932
933/* Configuration write function for babeld. */
934static int
935interface_config_write (struct vty *vty)
936{
937 struct listnode *node;
938 struct interface *ifp;
Paul Jakma57345092011-12-25 17:52:09 +0100939 int write = 0;
940
941 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
Paul Jakma57345092011-12-25 17:52:09 +0100942 /* Do not display the interface if there is no configuration about it */
943 if (ifp->desc == NULL)
944 continue;
945
946 vty_out (vty, "interface %s%s", ifp->name,
947 VTY_NEWLINE);
948 if (ifp->desc)
949 vty_out (vty, " description %s%s", ifp->desc,
950 VTY_NEWLINE);
951
952 /* TODO: to be completed... */
953
954 vty_out (vty, "!%s", VTY_NEWLINE);
955
956 write++;
957 }
958 return write;
959}
960
961/* functions to allocate or free memory for a babel_interface_nfo, filling
962 needed fields */
963static babel_interface_nfo *
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +0100964babel_interface_allocate (void)
Paul Jakma57345092011-12-25 17:52:09 +0100965{
966 babel_interface_nfo *babel_ifp;
967 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
968 if(babel_ifp == NULL)
969 return NULL;
970
971 /* Here are set the default values for an interface. */
972 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
973 /* All flags are unset */
Paul Jakma57345092011-12-25 17:52:09 +0100974 babel_ifp->bucket_time = babel_now.tv_sec;
975 babel_ifp->bucket = BUCKET_TOKENS_MAX;
976 babel_ifp->hello_seqno = (random() & 0xFFFF);
977 babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100978 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
Paul Jakma57345092011-12-25 17:52:09 +0100979
980 return babel_ifp;
981}
982
983static void
984babel_interface_free (babel_interface_nfo *babel_ifp)
985{
986 XFREE(MTYPE_BABEL_IF, babel_ifp);
987}