blob: 588fea708d536b7ae7650073f8b1b3e2cfe37263 [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",
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100296 "Enable Babel protocol on specified interface or network.\n"
Paul Jakma57345092011-12-25 17:52:09 +0100297 "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
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100324 "Disable Babel protocol on specified interface or network.\n"
Paul Jakma57345092011-12-25 17:52:09 +0100325 "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",
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100351 "Babel interface commands\n"
352 "Enable wired optimisations")
Paul Jakma57345092011-12-25 17:52:09 +0100353{
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",
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100369 "Babel interface commands\n"
370 "Disable wired optimiations (assume wireless)")
Paul Jakma57345092011-12-25 17:52:09 +0100371{
372 struct interface *ifp;
373 babel_interface_nfo *babel_ifp;
374
375 ifp = vty->index;
376 babel_ifp = babel_get_if_nfo(ifp);
377
378 assert (babel_ifp != NULL);
379 babel_ifp->flags &= ~BABEL_IF_WIRED;
380 return CMD_SUCCESS;
381}
382
383/* [Interface Command] Enable split horizon. */
384DEFUN (babel_split_horizon,
385 babel_split_horizon_cmd,
386 "babel split-horizon",
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100387 "Babel interface commands\n"
388 "Enable split horizon processing")
Paul Jakma57345092011-12-25 17:52:09 +0100389{
390 struct interface *ifp;
391 babel_interface_nfo *babel_ifp;
392
393 ifp = vty->index;
394 babel_ifp = babel_get_if_nfo(ifp);
395
396 assert (babel_ifp != NULL);
397 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
398 return CMD_SUCCESS;
399}
400
401/* [Interface Command] Disable split horizon (default). */
402DEFUN (no_babel_split_horizon,
403 no_babel_split_horizon_cmd,
404 "no babel split-horizon",
405 NO_STR
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100406 "Babel interface commands\n"
407 "Disable split horizon processing")
Paul Jakma57345092011-12-25 17:52:09 +0100408{
409 struct interface *ifp;
410 babel_interface_nfo *babel_ifp;
411
412 ifp = vty->index;
413 babel_ifp = babel_get_if_nfo(ifp);
414
415 assert (babel_ifp != NULL);
416 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
417 return CMD_SUCCESS;
418}
419
420/* [Interface Command]. */
421DEFUN (babel_set_hello_interval,
422 babel_set_hello_interval_cmd,
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100423 "babel hello-interval <20-655340>",
424 "Babel interface commands\n"
425 "Time between scheduled hellos\n"
426 "Milliseconds\n")
Paul Jakma57345092011-12-25 17:52:09 +0100427{
428 struct interface *ifp;
429 babel_interface_nfo *babel_ifp;
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100430 int interval;
Paul Jakma57345092011-12-25 17:52:09 +0100431
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100432 VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
Paul Jakma57345092011-12-25 17:52:09 +0100433
434 ifp = vty->index;
435 babel_ifp = babel_get_if_nfo(ifp);
Paul Jakma57345092011-12-25 17:52:09 +0100436 assert (babel_ifp != NULL);
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100437
Paul Jakma57345092011-12-25 17:52:09 +0100438 babel_ifp->hello_interval = interval;
439 return CMD_SUCCESS;
440}
441
442/* [Interface Command]. */
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100443DEFUN (babel_set_update_interval,
444 babel_set_update_interval_cmd,
445 "babel update-interval <20-655340>",
446 "Babel interface commands\n"
447 "Time between scheduled updates\n"
448 "Milliseconds\n")
449{
450 struct interface *ifp;
451 babel_interface_nfo *babel_ifp;
452 int interval;
453
454 VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
455
456 ifp = vty->index;
457 babel_ifp = babel_get_if_nfo(ifp);
458 assert (babel_ifp != NULL);
459
460 babel_ifp->update_interval = interval;
461 return CMD_SUCCESS;
462}
463
464/* [Interface Command]. */
Paul Jakma57345092011-12-25 17:52:09 +0100465DEFUN (babel_passive_interface,
466 babel_passive_interface_cmd,
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100467 "babel passive-interface",
468 "Babel interface commands\n"
469 "Only announce redistributed routes on this interface\n")
Paul Jakma57345092011-12-25 17:52:09 +0100470{
471 if (allow_duplicates) {
472 return CMD_WARNING;
473 }
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100474 parasitic = 1;
Paul Jakma57345092011-12-25 17:52:09 +0100475 return CMD_SUCCESS;
476}
477
478/* [Interface Command]. */
479DEFUN (no_babel_passive_interface,
480 no_babel_passive_interface_cmd,
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100481 "no babel passive-interface",
Paul Jakma57345092011-12-25 17:52:09 +0100482 NO_STR
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100483 "Babel interface commands\n"
484 "Announce all routes on this interface\n")
Paul Jakma57345092011-12-25 17:52:09 +0100485{
486 parasitic = 0;
487 return CMD_SUCCESS;
488}
489
Paul Jakma57345092011-12-25 17:52:09 +0100490/* This should be no more than half the hello interval, so that hellos
491 aren't sent late. The result is in milliseconds. */
492unsigned
493jitter(babel_interface_nfo *babel_ifp, int urgent)
494{
495 unsigned interval = babel_ifp->hello_interval;
496 if(urgent)
497 interval = MIN(interval, 100);
498 else
499 interval = MIN(interval, 4000);
500 return roughly(interval) / 4;
501}
502
503unsigned
504update_jitter(babel_interface_nfo *babel_ifp, int urgent)
505{
506 unsigned interval = babel_ifp->hello_interval;
507 if(urgent)
508 interval = MIN(interval, 100);
509 else
510 interval = MIN(interval, 4000);
511 return roughly(interval);
512}
513
514/* calculate babeld's specific datas of an interface (change when the interface
515 change) */
516static int
517interface_recalculate(struct interface *ifp)
518{
519 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
520 unsigned char *tmp = NULL;
521 int mtu, rc;
522 struct ipv6_mreq mreq;
523
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100524 if (!IS_ENABLE(ifp))
525 return -1;
526
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100527 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
528 interface_reset(ifp);
529 return -1;
530 }
531
532 babel_ifp->flags |= BABEL_IF_IS_UP;
533
Paul Jakma57345092011-12-25 17:52:09 +0100534 mtu = MIN(ifp->mtu, ifp->mtu6);
535
536 /* We need to be able to fit at least two messages into a packet,
537 so MTUs below 116 require lower layer fragmentation. */
538 /* In IPv6, the minimum MTU is 1280, and every host must be able
539 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
540 if(mtu < 128) {
541 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
542 mtu, ifp->name, ifp->ifindex);
543 mtu = 128;
544 }
545
546 /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
547 babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
548 tmp = babel_ifp->sendbuf;
549 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
550 if(babel_ifp->sendbuf == NULL) {
Matthieu Boutier4eedea52012-01-17 22:46:21 +0100551 zlog_err("Couldn't reallocate sendbuf.");
Paul Jakma57345092011-12-25 17:52:09 +0100552 free(tmp);
553 babel_ifp->bufsize = 0;
554 return -1;
555 }
556 tmp = NULL;
557
558 resize_receive_buffer(mtu);
559
560 if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */
561 babel_ifp->cost = 96;
562 babel_ifp->flags &= ~BABEL_IF_LQ;
563 } else {
564 babel_ifp->cost = 256;
565 babel_ifp->flags |= BABEL_IF_LQ;
566 }
567
Paul Jakma57345092011-12-25 17:52:09 +0100568 /* Since the interface was marked as active above, the
569 idle_hello_interval cannot be the one being used here. */
570 babel_ifp->update_interval = babel_ifp->hello_interval * 4;
571
572 memset(&mreq, 0, sizeof(mreq));
573 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
574 mreq.ipv6mr_interface = ifp->ifindex;
575
576 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
577 (char*)&mreq, sizeof(mreq));
578 if(rc < 0) {
579 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
580 ifp->name, safe_strerror(errno));
581 /* This is probably due to a missing link-local address,
582 so down this interface, and wait until the main loop
583 tries to up it again. */
584 interface_reset(ifp);
585 return -1;
586 }
587
588 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
589 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
590 send_hello(ifp);
591 send_request(ifp, NULL, 0);
592
593 update_interface_metric(ifp);
594
595 debugf(BABEL_DEBUG_COMMON,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100596 "Upped interface %s (%s, cost=%d, channel=%d%s).",
Paul Jakma57345092011-12-25 17:52:09 +0100597 ifp->name,
598 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
599 babel_ifp->cost,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100600 babel_ifp->channel,
Paul Jakma57345092011-12-25 17:52:09 +0100601 babel_ifp->ipv4 ? ", IPv4" : "");
602
603 if(rc > 0)
604 send_update(ifp, 0, NULL, 0);
605
Paul Jakma57345092011-12-25 17:52:09 +0100606 return 1;
607}
608
609/* Reset the interface as it was new: it's not removed from the interface list,
610 and may be considered as a upped interface. */
611static int
612interface_reset(struct interface *ifp)
613{
614 int rc;
615 struct ipv6_mreq mreq;
616 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
617
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100618 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
619 return 0;
620
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100621 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
622 babel_ifp->flags &= ~BABEL_IF_IS_UP;
623
Paul Jakma57345092011-12-25 17:52:09 +0100624 flush_interface_routes(ifp, 0);
625 babel_ifp->buffered = 0;
626 babel_ifp->bufsize = 0;
627 free(babel_ifp->sendbuf);
628 babel_ifp->num_buffered_updates = 0;
629 babel_ifp->update_bufsize = 0;
630 if(babel_ifp->buffered_updates)
631 free(babel_ifp->buffered_updates);
632 babel_ifp->buffered_updates = NULL;
633 babel_ifp->sendbuf = NULL;
634
635 if(ifp->ifindex > 0) {
636 memset(&mreq, 0, sizeof(mreq));
637 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
638 mreq.ipv6mr_interface = ifp->ifindex;
639 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
640 (char*)&mreq, sizeof(mreq));
641 if(rc < 0)
642 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
643 ifp->name, safe_strerror(errno));
644 }
645
646 update_interface_metric(ifp);
647
648 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
649 ifp->name,
650 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
651 babel_ifp->cost,
652 babel_ifp->ipv4 ? ", IPv4" : "");
653
654 return 1;
655}
656
657/* Send retraction to all, and reset all interfaces statistics. */
658void
659babel_interface_close_all(void)
660{
661 struct interface *ifp = NULL;
662 struct listnode *linklist_node = NULL;
663
664 FOR_ALL_INTERFACES(ifp, linklist_node) {
665 if(!if_up(ifp))
666 continue;
667 send_wildcard_retraction(ifp);
668 /* Make sure that we expire quickly from our neighbours'
669 association caches. */
670 send_hello_noupdate(ifp, 10);
671 flushbuf(ifp);
672 usleep(roughly(1000));
673 gettime(&babel_now);
674 }
675 FOR_ALL_INTERFACES(ifp, linklist_node) {
676 if(!if_up(ifp))
677 continue;
678 /* Make sure they got it. */
679 send_wildcard_retraction(ifp);
680 send_hello_noupdate(ifp, 1);
681 flushbuf(ifp);
682 usleep(roughly(10000));
683 gettime(&babel_now);
684 interface_reset(ifp);
685 }
686}
687
688/* return "true" if address is one of our ipv6 addresses */
689int
690is_interface_ll_address(struct interface *ifp, const unsigned char *address)
691{
692 struct connected *connected;
693 struct listnode *node;
694
695 if(!if_up(ifp))
696 return 0;
697
698 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
699 if(connected->address->family == AF_INET6 &&
700 memcmp(&connected->address->u.prefix6, address, 16) == 0)
701 return 1;
702 }
703
704 return 0;
705}
706
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400707static void
708show_babel_interface_sub (struct vty *vty, struct interface *ifp)
709{
710 int is_up;
711 babel_interface_nfo *babel_ifp;
712
713 vty_out (vty, "%s is %s%s", ifp->name,
714 ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
715 vty_out (vty, " ifindex %u, MTU %u bytes %s%s",
716 ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
717
718 if (babel_enable_if_lookup (ifp->name) < 0)
719 {
720 vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
721 return;
722 }
723 if (!is_up)
724 {
725 vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
726 return;
727 }
728 babel_ifp = babel_get_if_nfo (ifp);
729 vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE);
730 vty_out (vty, " Operating mode is \"%s\"%s",
731 CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
732 vty_out (vty, " Split horizon mode is %s%s",
733 CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
734 vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
Juliusz Chroboczek9c298c72012-02-11 14:06:24 +0100735 vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400736}
737
738DEFUN (show_babel_interface,
739 show_babel_interface_cmd,
740 "show babel interface [INTERFACE]",
741 SHOW_STR
742 IP_STR
743 "Babel information\n"
744 "Interface information\n"
745 "Interface name\n")
746{
747 struct interface *ifp;
748 struct listnode *node;
749
750 if (argc == 0)
751 {
752 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
753 show_babel_interface_sub (vty, ifp);
754 return CMD_SUCCESS;
755 }
756 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
757 {
758 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
759 return CMD_WARNING;
760 }
761 show_babel_interface_sub (vty, ifp);
762 return CMD_SUCCESS;
763}
Paul Jakma57345092011-12-25 17:52:09 +0100764
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100765static void
766show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
767{
768 vty_out (vty,
769 "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
770 format_address(neigh->address),
771 neigh->ifp->name,
772 neigh->reach,
773 neighbour_rxcost(neigh),
774 neigh->txcost,
775 if_up(neigh->ifp) ? "" : " (down)",
776 VTY_NEWLINE);
777}
778
779DEFUN (show_babel_neighbour,
780 show_babel_neighbour_cmd,
781 "show babel neighbour [INTERFACE]",
782 SHOW_STR
783 IP_STR
784 "Babel information\n"
785 "Print neighbours\n"
786 "Interface name\n")
787{
788 struct neighbour *neigh;
789 struct interface *ifp;
790
791 if (argc == 0) {
792 FOR_ALL_NEIGHBOURS(neigh) {
793 show_babel_neighbour_sub(vty, neigh);
794 }
795 return CMD_SUCCESS;
796 }
797 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
798 {
799 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
800 return CMD_WARNING;
801 }
802 FOR_ALL_NEIGHBOURS(neigh) {
803 if(ifp->ifindex == neigh->ifp->ifindex) {
804 show_babel_neighbour_sub(vty, neigh);
805 }
806 }
807 return CMD_SUCCESS;
808}
809
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100810static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100811show_babel_routes_sub (struct babel_route *route, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100812{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100813 struct vty *vty = (struct vty*) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100814 const unsigned char *nexthop =
815 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
816 NULL : route->nexthop;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100817 char channels[100];
818
819 if(route->channels[0] == 0)
820 channels[0] = '\0';
821 else {
822 int k, j = 0;
823 snprintf(channels, 100, " chan (");
824 j = strlen(channels);
825 for(k = 0; k < DIVERSITY_HOPS; k++) {
826 if(route->channels[k] == 0)
827 break;
828 if(k > 0)
829 channels[j++] = ',';
830 snprintf(channels + j, 100 - j, "%d", route->channels[k]);
831 j = strlen(channels);
832 }
833 snprintf(channels + j, 100 - j, ")");
834 if(k == 0)
835 channels[0] = '\0';
836 }
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100837
838 vty_out(vty,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100839 "%s metric %d refmetric %d id %s seqno %d%s age %d "
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100840 "via %s neigh %s%s%s%s%s",
841 format_prefix(route->src->prefix, route->src->plen),
842 route_metric(route), route->refmetric,
843 format_eui64(route->src->id),
844 (int)route->seqno,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100845 channels,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100846 (int)(babel_now.tv_sec - route->time),
847 route->neigh->ifp->name,
848 format_address(route->neigh->address),
849 nexthop ? " nexthop " : "",
850 nexthop ? format_address(nexthop) : "",
851 route->installed ? " (installed)" :
852 route_feasible(route) ? " (feasible)" : "",
853 VTY_NEWLINE);
854}
855
856static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100857show_babel_xroutes_sub (struct xroute *xroute, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100858{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100859 struct vty *vty = (struct vty *) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100860 vty_out(vty, "%s metric %d (exported)%s",
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100861 format_prefix(xroute->prefix, xroute->plen),
862 xroute->metric,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100863 VTY_NEWLINE);
864}
865
866DEFUN (show_babel_database,
867 show_babel_database_cmd,
868 "show babel database",
869 SHOW_STR
870 IP_STR
871 "Babel information\n"
872 "Database information\n"
873 "No attributes\n")
874{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100875 for_all_routes(show_babel_routes_sub, vty);
876 for_all_xroutes(show_babel_xroutes_sub, vty);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100877 return CMD_SUCCESS;
878}
879
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100880DEFUN (show_babel_running_config,
881 show_babel_running_config_cmd,
882 "show babel running-config",
883 SHOW_STR
884 IP_STR
885 "Babel information\n"
886 "Configuration information\n"
887 "No attributes\n")
888{
889 vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
890 show_babel_main_configuration(vty);
891 show_babeld_configuration(vty);
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100892 vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100893 config_show_distribute(vty);
894
895 return CMD_SUCCESS;
896}
897
Paul Jakma57345092011-12-25 17:52:09 +0100898void
899babel_if_init ()
900{
901 /* initialize interface list */
902 if_init();
903 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
904 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
905
906 babel_enable_if = vector_init (1);
907
908 /* install interface node and commands */
909 install_element (CONFIG_NODE, &interface_cmd);
910 install_element (CONFIG_NODE, &no_interface_cmd);
911 install_node (&babel_interface_node, interface_config_write);
912 install_default(INTERFACE_NODE);
913 install_element(INTERFACE_NODE, &interface_cmd);
914 install_element(INTERFACE_NODE, &no_interface_cmd);
915
916 install_element(BABEL_NODE, &babel_network_cmd);
917 install_element(BABEL_NODE, &no_babel_network_cmd);
918 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
919 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
920 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
921 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
922 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100923 install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100924 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
925 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400926
Juliusz Chroboczekec0c8482012-02-07 05:44:41 +0100927 /* "show babel ..." commands */
928 install_element(VIEW_NODE, &show_babel_interface_cmd);
929 install_element(ENABLE_NODE, &show_babel_interface_cmd);
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100930 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
931 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100932 install_element(VIEW_NODE, &show_babel_database_cmd);
933 install_element(ENABLE_NODE, &show_babel_database_cmd);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100934 install_element(VIEW_NODE, &show_babel_running_config_cmd);
935 install_element(ENABLE_NODE, &show_babel_running_config_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100936}
937
938/* hooks: functions called respectively when struct interface is
939 created or deleted. */
940static int
941babel_if_new_hook (struct interface *ifp)
942{
943 ifp->info = babel_interface_allocate();
944 return 0;
945}
946
947static int
948babel_if_delete_hook (struct interface *ifp)
949{
950 babel_interface_free(ifp->info);
951 ifp->info = NULL;
952 return 0;
953}
954
955/* Configuration write function for babeld. */
956static int
957interface_config_write (struct vty *vty)
958{
959 struct listnode *node;
960 struct interface *ifp;
Paul Jakma57345092011-12-25 17:52:09 +0100961 int write = 0;
962
963 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
Paul Jakma57345092011-12-25 17:52:09 +0100964 /* Do not display the interface if there is no configuration about it */
965 if (ifp->desc == NULL)
966 continue;
967
968 vty_out (vty, "interface %s%s", ifp->name,
969 VTY_NEWLINE);
970 if (ifp->desc)
971 vty_out (vty, " description %s%s", ifp->desc,
972 VTY_NEWLINE);
973
974 /* TODO: to be completed... */
975
976 vty_out (vty, "!%s", VTY_NEWLINE);
977
978 write++;
979 }
980 return write;
981}
982
983/* functions to allocate or free memory for a babel_interface_nfo, filling
984 needed fields */
985static babel_interface_nfo *
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +0100986babel_interface_allocate (void)
Paul Jakma57345092011-12-25 17:52:09 +0100987{
988 babel_interface_nfo *babel_ifp;
989 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
990 if(babel_ifp == NULL)
991 return NULL;
992
993 /* Here are set the default values for an interface. */
994 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
995 /* All flags are unset */
Paul Jakma57345092011-12-25 17:52:09 +0100996 babel_ifp->bucket_time = babel_now.tv_sec;
997 babel_ifp->bucket = BUCKET_TOKENS_MAX;
998 babel_ifp->hello_seqno = (random() & 0xFFFF);
999 babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +01001000 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
Paul Jakma57345092011-12-25 17:52:09 +01001001
1002 return babel_ifp;
1003}
1004
1005static void
1006babel_interface_free (babel_interface_nfo *babel_ifp)
1007{
1008 XFREE(MTYPE_BABEL_IF, babel_ifp);
1009}