blob: 2b5f9569bc0b9a7fbb4778545f5c83576425c10b [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 memset(&mreq, 0, sizeof(mreq));
569 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
570 mreq.ipv6mr_interface = ifp->ifindex;
571
572 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
573 (char*)&mreq, sizeof(mreq));
574 if(rc < 0) {
575 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
576 ifp->name, safe_strerror(errno));
577 /* This is probably due to a missing link-local address,
578 so down this interface, and wait until the main loop
579 tries to up it again. */
580 interface_reset(ifp);
581 return -1;
582 }
583
584 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
585 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
586 send_hello(ifp);
587 send_request(ifp, NULL, 0);
588
589 update_interface_metric(ifp);
590
591 debugf(BABEL_DEBUG_COMMON,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100592 "Upped interface %s (%s, cost=%d, channel=%d%s).",
Paul Jakma57345092011-12-25 17:52:09 +0100593 ifp->name,
594 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
595 babel_ifp->cost,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100596 babel_ifp->channel,
Paul Jakma57345092011-12-25 17:52:09 +0100597 babel_ifp->ipv4 ? ", IPv4" : "");
598
599 if(rc > 0)
600 send_update(ifp, 0, NULL, 0);
601
Paul Jakma57345092011-12-25 17:52:09 +0100602 return 1;
603}
604
605/* Reset the interface as it was new: it's not removed from the interface list,
606 and may be considered as a upped interface. */
607static int
608interface_reset(struct interface *ifp)
609{
610 int rc;
611 struct ipv6_mreq mreq;
612 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
613
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100614 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
615 return 0;
616
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100617 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
618 babel_ifp->flags &= ~BABEL_IF_IS_UP;
619
Paul Jakma57345092011-12-25 17:52:09 +0100620 flush_interface_routes(ifp, 0);
621 babel_ifp->buffered = 0;
622 babel_ifp->bufsize = 0;
623 free(babel_ifp->sendbuf);
624 babel_ifp->num_buffered_updates = 0;
625 babel_ifp->update_bufsize = 0;
626 if(babel_ifp->buffered_updates)
627 free(babel_ifp->buffered_updates);
628 babel_ifp->buffered_updates = NULL;
629 babel_ifp->sendbuf = NULL;
630
631 if(ifp->ifindex > 0) {
632 memset(&mreq, 0, sizeof(mreq));
633 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
634 mreq.ipv6mr_interface = ifp->ifindex;
635 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
636 (char*)&mreq, sizeof(mreq));
637 if(rc < 0)
638 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
639 ifp->name, safe_strerror(errno));
640 }
641
642 update_interface_metric(ifp);
643
644 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
645 ifp->name,
646 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
647 babel_ifp->cost,
648 babel_ifp->ipv4 ? ", IPv4" : "");
649
650 return 1;
651}
652
653/* Send retraction to all, and reset all interfaces statistics. */
654void
655babel_interface_close_all(void)
656{
657 struct interface *ifp = NULL;
658 struct listnode *linklist_node = NULL;
659
660 FOR_ALL_INTERFACES(ifp, linklist_node) {
661 if(!if_up(ifp))
662 continue;
663 send_wildcard_retraction(ifp);
664 /* Make sure that we expire quickly from our neighbours'
665 association caches. */
666 send_hello_noupdate(ifp, 10);
667 flushbuf(ifp);
668 usleep(roughly(1000));
669 gettime(&babel_now);
670 }
671 FOR_ALL_INTERFACES(ifp, linklist_node) {
672 if(!if_up(ifp))
673 continue;
674 /* Make sure they got it. */
675 send_wildcard_retraction(ifp);
676 send_hello_noupdate(ifp, 1);
677 flushbuf(ifp);
678 usleep(roughly(10000));
679 gettime(&babel_now);
680 interface_reset(ifp);
681 }
682}
683
684/* return "true" if address is one of our ipv6 addresses */
685int
686is_interface_ll_address(struct interface *ifp, const unsigned char *address)
687{
688 struct connected *connected;
689 struct listnode *node;
690
691 if(!if_up(ifp))
692 return 0;
693
694 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
695 if(connected->address->family == AF_INET6 &&
696 memcmp(&connected->address->u.prefix6, address, 16) == 0)
697 return 1;
698 }
699
700 return 0;
701}
702
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400703static void
704show_babel_interface_sub (struct vty *vty, struct interface *ifp)
705{
706 int is_up;
707 babel_interface_nfo *babel_ifp;
708
709 vty_out (vty, "%s is %s%s", ifp->name,
710 ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
711 vty_out (vty, " ifindex %u, MTU %u bytes %s%s",
712 ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
713
714 if (babel_enable_if_lookup (ifp->name) < 0)
715 {
716 vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
717 return;
718 }
719 if (!is_up)
720 {
721 vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
722 return;
723 }
724 babel_ifp = babel_get_if_nfo (ifp);
725 vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE);
726 vty_out (vty, " Operating mode is \"%s\"%s",
727 CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
728 vty_out (vty, " Split horizon mode is %s%s",
729 CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
730 vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
Juliusz Chroboczek9c298c72012-02-11 14:06:24 +0100731 vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400732}
733
734DEFUN (show_babel_interface,
735 show_babel_interface_cmd,
736 "show babel interface [INTERFACE]",
737 SHOW_STR
738 IP_STR
739 "Babel information\n"
740 "Interface information\n"
741 "Interface name\n")
742{
743 struct interface *ifp;
744 struct listnode *node;
745
746 if (argc == 0)
747 {
748 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
749 show_babel_interface_sub (vty, ifp);
750 return CMD_SUCCESS;
751 }
752 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
753 {
754 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
755 return CMD_WARNING;
756 }
757 show_babel_interface_sub (vty, ifp);
758 return CMD_SUCCESS;
759}
Paul Jakma57345092011-12-25 17:52:09 +0100760
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100761static void
762show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
763{
764 vty_out (vty,
765 "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
766 format_address(neigh->address),
767 neigh->ifp->name,
768 neigh->reach,
769 neighbour_rxcost(neigh),
770 neigh->txcost,
771 if_up(neigh->ifp) ? "" : " (down)",
772 VTY_NEWLINE);
773}
774
775DEFUN (show_babel_neighbour,
776 show_babel_neighbour_cmd,
777 "show babel neighbour [INTERFACE]",
778 SHOW_STR
779 IP_STR
780 "Babel information\n"
781 "Print neighbours\n"
782 "Interface name\n")
783{
784 struct neighbour *neigh;
785 struct interface *ifp;
786
787 if (argc == 0) {
788 FOR_ALL_NEIGHBOURS(neigh) {
789 show_babel_neighbour_sub(vty, neigh);
790 }
791 return CMD_SUCCESS;
792 }
793 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
794 {
795 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
796 return CMD_WARNING;
797 }
798 FOR_ALL_NEIGHBOURS(neigh) {
799 if(ifp->ifindex == neigh->ifp->ifindex) {
800 show_babel_neighbour_sub(vty, neigh);
801 }
802 }
803 return CMD_SUCCESS;
804}
805
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100806static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100807show_babel_routes_sub (struct babel_route *route, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100808{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100809 struct vty *vty = (struct vty*) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100810 const unsigned char *nexthop =
811 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
812 NULL : route->nexthop;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100813 char channels[100];
814
815 if(route->channels[0] == 0)
816 channels[0] = '\0';
817 else {
818 int k, j = 0;
819 snprintf(channels, 100, " chan (");
820 j = strlen(channels);
821 for(k = 0; k < DIVERSITY_HOPS; k++) {
822 if(route->channels[k] == 0)
823 break;
824 if(k > 0)
825 channels[j++] = ',';
826 snprintf(channels + j, 100 - j, "%d", route->channels[k]);
827 j = strlen(channels);
828 }
829 snprintf(channels + j, 100 - j, ")");
830 if(k == 0)
831 channels[0] = '\0';
832 }
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100833
834 vty_out(vty,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100835 "%s metric %d refmetric %d id %s seqno %d%s age %d "
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100836 "via %s neigh %s%s%s%s%s",
837 format_prefix(route->src->prefix, route->src->plen),
838 route_metric(route), route->refmetric,
839 format_eui64(route->src->id),
840 (int)route->seqno,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100841 channels,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100842 (int)(babel_now.tv_sec - route->time),
843 route->neigh->ifp->name,
844 format_address(route->neigh->address),
845 nexthop ? " nexthop " : "",
846 nexthop ? format_address(nexthop) : "",
847 route->installed ? " (installed)" :
848 route_feasible(route) ? " (feasible)" : "",
849 VTY_NEWLINE);
850}
851
852static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100853show_babel_xroutes_sub (struct xroute *xroute, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100854{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100855 struct vty *vty = (struct vty *) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100856 vty_out(vty, "%s metric %d (exported)%s",
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100857 format_prefix(xroute->prefix, xroute->plen),
858 xroute->metric,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100859 VTY_NEWLINE);
860}
861
862DEFUN (show_babel_database,
863 show_babel_database_cmd,
864 "show babel database",
865 SHOW_STR
866 IP_STR
867 "Babel information\n"
868 "Database information\n"
869 "No attributes\n")
870{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100871 for_all_routes(show_babel_routes_sub, vty);
872 for_all_xroutes(show_babel_xroutes_sub, vty);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100873 return CMD_SUCCESS;
874}
875
Denis Ovsienkoa14ef5e2012-02-11 21:06:16 +0400876DEFUN (show_babel_parameters,
877 show_babel_parameters_cmd,
878 "show babel parameters",
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100879 SHOW_STR
880 IP_STR
881 "Babel information\n"
882 "Configuration information\n"
883 "No attributes\n")
884{
885 vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
886 show_babel_main_configuration(vty);
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100887 vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE);
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100888 config_show_distribute(vty);
889
890 return CMD_SUCCESS;
891}
892
Paul Jakma57345092011-12-25 17:52:09 +0100893void
894babel_if_init ()
895{
896 /* initialize interface list */
897 if_init();
898 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
899 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
900
901 babel_enable_if = vector_init (1);
902
903 /* install interface node and commands */
904 install_element (CONFIG_NODE, &interface_cmd);
905 install_element (CONFIG_NODE, &no_interface_cmd);
906 install_node (&babel_interface_node, interface_config_write);
907 install_default(INTERFACE_NODE);
908 install_element(INTERFACE_NODE, &interface_cmd);
909 install_element(INTERFACE_NODE, &no_interface_cmd);
910
911 install_element(BABEL_NODE, &babel_network_cmd);
912 install_element(BABEL_NODE, &no_babel_network_cmd);
913 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
914 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
915 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
916 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
917 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100918 install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100919 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
920 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400921
Juliusz Chroboczekec0c8482012-02-07 05:44:41 +0100922 /* "show babel ..." commands */
923 install_element(VIEW_NODE, &show_babel_interface_cmd);
924 install_element(ENABLE_NODE, &show_babel_interface_cmd);
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100925 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
926 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100927 install_element(VIEW_NODE, &show_babel_database_cmd);
928 install_element(ENABLE_NODE, &show_babel_database_cmd);
Denis Ovsienkoa14ef5e2012-02-11 21:06:16 +0400929 install_element(VIEW_NODE, &show_babel_parameters_cmd);
930 install_element(ENABLE_NODE, &show_babel_parameters_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100931}
932
933/* hooks: functions called respectively when struct interface is
934 created or deleted. */
935static int
936babel_if_new_hook (struct interface *ifp)
937{
938 ifp->info = babel_interface_allocate();
939 return 0;
940}
941
942static int
943babel_if_delete_hook (struct interface *ifp)
944{
945 babel_interface_free(ifp->info);
946 ifp->info = NULL;
947 return 0;
948}
949
Denis Ovsienkocb4b13d2012-02-13 22:13:37 +0400950/* Output an "interface" section for each of the known interfaces with
951babeld-specific statement lines where appropriate. */
Paul Jakma57345092011-12-25 17:52:09 +0100952static int
953interface_config_write (struct vty *vty)
954{
955 struct listnode *node;
956 struct interface *ifp;
Paul Jakma57345092011-12-25 17:52:09 +0100957 int write = 0;
958
959 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
Paul Jakma57345092011-12-25 17:52:09 +0100960 vty_out (vty, "interface %s%s", ifp->name,
961 VTY_NEWLINE);
962 if (ifp->desc)
963 vty_out (vty, " description %s%s", ifp->desc,
964 VTY_NEWLINE);
Denis Ovsienkocb4b13d2012-02-13 22:13:37 +0400965 if (IS_ENABLE (ifp))
966 {
967 babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
968 /* wireless/no split-horizon is the default */
969 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
970 {
971 vty_out (vty, " babel wired%s", VTY_NEWLINE);
972 write++;
973 }
974 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON))
975 {
976 vty_out (vty, " babel split-horizon%s", VTY_NEWLINE);
977 write++;
978 }
979 }
Paul Jakma57345092011-12-25 17:52:09 +0100980 vty_out (vty, "!%s", VTY_NEWLINE);
Paul Jakma57345092011-12-25 17:52:09 +0100981 write++;
982 }
983 return write;
984}
985
Denis Ovsienkoa14ef5e2012-02-11 21:06:16 +0400986/* Output a "network" statement line for each of the enabled interfaces. */
987int
988babel_enable_if_config_write (struct vty * vty)
989{
990 unsigned int i, lines = 0;
991 char *str;
992
993 for (i = 0; i < vector_active (babel_enable_if); i++)
994 if ((str = vector_slot (babel_enable_if, i)) != NULL)
995 {
996 vty_out (vty, " network %s%s", str, VTY_NEWLINE);
997 lines++;
998 }
999 return lines;
1000}
1001
Paul Jakma57345092011-12-25 17:52:09 +01001002/* functions to allocate or free memory for a babel_interface_nfo, filling
1003 needed fields */
1004static babel_interface_nfo *
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +01001005babel_interface_allocate (void)
Paul Jakma57345092011-12-25 17:52:09 +01001006{
1007 babel_interface_nfo *babel_ifp;
1008 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
1009 if(babel_ifp == NULL)
1010 return NULL;
1011
1012 /* Here are set the default values for an interface. */
1013 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
1014 /* All flags are unset */
Paul Jakma57345092011-12-25 17:52:09 +01001015 babel_ifp->bucket_time = babel_now.tv_sec;
1016 babel_ifp->bucket = BUCKET_TOKENS_MAX;
1017 babel_ifp->hello_seqno = (random() & 0xFFFF);
Juliusz Chroboczek36329c02012-02-14 08:49:57 +01001018 babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL;
1019 babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +01001020 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
Paul Jakma57345092011-12-25 17:52:09 +01001021
1022 return babel_ifp;
1023}
1024
1025static void
1026babel_interface_free (babel_interface_nfo *babel_ifp)
1027{
1028 XFREE(MTYPE_BABEL_IF, babel_ifp);
1029}