blob: ace28127ff43ce6692c28c84f9b69aa08861bbe6 [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
Paul Jakma57345092011-12-25 17:52:09 +0100291/* [Babel Command] Babel enable on specified interface or matched network. */
292DEFUN (babel_network,
293 babel_network_cmd,
294 "network IF_OR_ADDR",
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100295 "Enable Babel protocol on specified interface or network.\n"
Paul Jakma57345092011-12-25 17:52:09 +0100296 "Interface or address")
297{
298 int ret;
299 struct prefix p;
300
301 ret = str2prefix (argv[0], &p);
302
303 /* Given string is: */
304 if (ret) /* an IPv4 or v6 network */
305 return CMD_ERR_NO_MATCH; /* not implemented yet */
306 else /* an interface name */
307 ret = babel_enable_if_add (argv[0]);
308
309 if (ret < 0) {
310 vty_out (vty, "There is same network configuration %s%s", argv[0],
311 VTY_NEWLINE);
312 return CMD_WARNING;
313 }
314
315 return CMD_SUCCESS;
316}
317
318/* [Babel Command] Babel enable on specified interface or matched network. */
319DEFUN (no_babel_network,
320 no_babel_network_cmd,
321 "no network IF_OR_ADDR",
322 NO_STR
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100323 "Disable Babel protocol on specified interface or network.\n"
Paul Jakma57345092011-12-25 17:52:09 +0100324 "Interface or address")
325{
326 int ret;
327 struct prefix p;
328
329 ret = str2prefix (argv[0], &p);
330
331 /* Given string is: */
332 if (ret) /* an IPv4 or v6 network */
333 return CMD_ERR_NO_MATCH; /* not implemented yet */
334 else /* an interface name */
335 ret = babel_enable_if_delete (argv[0]);
336
337 if (ret < 0) {
338 vty_out (vty, "can't find network %s%s", argv[0],
339 VTY_NEWLINE);
340 return CMD_WARNING;
341 }
342
343 return CMD_SUCCESS;
344}
345
Juliusz Chroboczek260948c2012-02-14 09:09:32 +0100346/* There are a number of interface parameters that must be changed when
347 an interface becomes wired/wireless. In Quagga, they cannot be
348 configured separately. */
349
350static void
351babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired)
352{
353 if(wired) {
354 babel_ifp->flags |= BABEL_IF_WIRED;
355 babel_ifp->cost = 96;
356 babel_ifp->flags &= ~BABEL_IF_LQ;
357 } else {
358 babel_ifp->flags &= ~BABEL_IF_WIRED;
359 babel_ifp->cost = 256;
360 babel_ifp->flags |= BABEL_IF_LQ;
361 }
362
363}
364
Paul Jakma57345092011-12-25 17:52:09 +0100365/* [Interface Command] Tell the interface is wire. */
366DEFUN (babel_set_wired,
367 babel_set_wired_cmd,
Matthieu Boutier3c442e82012-02-08 23:30:46 +0100368 "babel wired",
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100369 "Babel interface commands\n"
370 "Enable wired optimisations")
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);
Juliusz Chroboczek260948c2012-02-14 09:09:32 +0100379 babel_set_wired_internal(babel_ifp, 1);
Paul Jakma57345092011-12-25 17:52:09 +0100380 return CMD_SUCCESS;
381}
382
383/* [Interface Command] Tell the interface is wireless (default). */
384DEFUN (babel_set_wireless,
385 babel_set_wireless_cmd,
Matthieu Boutier3c442e82012-02-08 23:30:46 +0100386 "babel wireless",
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100387 "Babel interface commands\n"
388 "Disable wired optimiations (assume wireless)")
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);
Juliusz Chroboczek260948c2012-02-14 09:09:32 +0100397 babel_set_wired_internal(babel_ifp, 0);
Paul Jakma57345092011-12-25 17:52:09 +0100398 return CMD_SUCCESS;
399}
400
401/* [Interface Command] Enable split horizon. */
402DEFUN (babel_split_horizon,
403 babel_split_horizon_cmd,
404 "babel split-horizon",
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100405 "Babel interface commands\n"
406 "Enable split horizon processing")
Paul Jakma57345092011-12-25 17:52:09 +0100407{
408 struct interface *ifp;
409 babel_interface_nfo *babel_ifp;
410
411 ifp = vty->index;
412 babel_ifp = babel_get_if_nfo(ifp);
413
414 assert (babel_ifp != NULL);
415 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
416 return CMD_SUCCESS;
417}
418
419/* [Interface Command] Disable split horizon (default). */
420DEFUN (no_babel_split_horizon,
421 no_babel_split_horizon_cmd,
422 "no babel split-horizon",
423 NO_STR
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100424 "Babel interface commands\n"
425 "Disable split horizon processing")
Paul Jakma57345092011-12-25 17:52:09 +0100426{
427 struct interface *ifp;
428 babel_interface_nfo *babel_ifp;
429
430 ifp = vty->index;
431 babel_ifp = babel_get_if_nfo(ifp);
432
433 assert (babel_ifp != NULL);
434 babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
435 return CMD_SUCCESS;
436}
437
438/* [Interface Command]. */
439DEFUN (babel_set_hello_interval,
440 babel_set_hello_interval_cmd,
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100441 "babel hello-interval <20-655340>",
442 "Babel interface commands\n"
443 "Time between scheduled hellos\n"
444 "Milliseconds\n")
Paul Jakma57345092011-12-25 17:52:09 +0100445{
446 struct interface *ifp;
447 babel_interface_nfo *babel_ifp;
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100448 int interval;
Paul Jakma57345092011-12-25 17:52:09 +0100449
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100450 VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
Paul Jakma57345092011-12-25 17:52:09 +0100451
452 ifp = vty->index;
453 babel_ifp = babel_get_if_nfo(ifp);
Paul Jakma57345092011-12-25 17:52:09 +0100454 assert (babel_ifp != NULL);
Juliusz Chroboczek38846de2012-02-07 05:43:36 +0100455
Paul Jakma57345092011-12-25 17:52:09 +0100456 babel_ifp->hello_interval = interval;
457 return CMD_SUCCESS;
458}
459
460/* [Interface Command]. */
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100461DEFUN (babel_set_update_interval,
462 babel_set_update_interval_cmd,
463 "babel update-interval <20-655340>",
464 "Babel interface commands\n"
465 "Time between scheduled updates\n"
466 "Milliseconds\n")
467{
468 struct interface *ifp;
469 babel_interface_nfo *babel_ifp;
470 int interval;
471
472 VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
473
474 ifp = vty->index;
475 babel_ifp = babel_get_if_nfo(ifp);
476 assert (babel_ifp != NULL);
477
478 babel_ifp->update_interval = interval;
479 return CMD_SUCCESS;
480}
481
Paul Jakma57345092011-12-25 17:52:09 +0100482/* This should be no more than half the hello interval, so that hellos
483 aren't sent late. The result is in milliseconds. */
484unsigned
485jitter(babel_interface_nfo *babel_ifp, int urgent)
486{
487 unsigned interval = babel_ifp->hello_interval;
488 if(urgent)
489 interval = MIN(interval, 100);
490 else
491 interval = MIN(interval, 4000);
492 return roughly(interval) / 4;
493}
494
495unsigned
496update_jitter(babel_interface_nfo *babel_ifp, int urgent)
497{
498 unsigned interval = babel_ifp->hello_interval;
499 if(urgent)
500 interval = MIN(interval, 100);
501 else
502 interval = MIN(interval, 4000);
503 return roughly(interval);
504}
505
506/* calculate babeld's specific datas of an interface (change when the interface
507 change) */
508static int
509interface_recalculate(struct interface *ifp)
510{
511 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
512 unsigned char *tmp = NULL;
513 int mtu, rc;
514 struct ipv6_mreq mreq;
515
Matthieu Boutier8c4e57a2012-01-28 00:29:51 +0100516 if (!IS_ENABLE(ifp))
517 return -1;
518
Matthieu Boutier0ee8a1f2012-01-18 00:52:06 +0100519 if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) {
520 interface_reset(ifp);
521 return -1;
522 }
523
524 babel_ifp->flags |= BABEL_IF_IS_UP;
525
Paul Jakma57345092011-12-25 17:52:09 +0100526 mtu = MIN(ifp->mtu, ifp->mtu6);
527
528 /* We need to be able to fit at least two messages into a packet,
529 so MTUs below 116 require lower layer fragmentation. */
530 /* In IPv6, the minimum MTU is 1280, and every host must be able
531 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
532 if(mtu < 128) {
533 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
534 mtu, ifp->name, ifp->ifindex);
535 mtu = 128;
536 }
537
538 /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
539 babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
540 tmp = babel_ifp->sendbuf;
541 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
542 if(babel_ifp->sendbuf == NULL) {
Matthieu Boutier4eedea52012-01-17 22:46:21 +0100543 zlog_err("Couldn't reallocate sendbuf.");
Paul Jakma57345092011-12-25 17:52:09 +0100544 free(tmp);
545 babel_ifp->bufsize = 0;
546 return -1;
547 }
548 tmp = NULL;
549
550 resize_receive_buffer(mtu);
551
Paul Jakma57345092011-12-25 17:52:09 +0100552 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);
Juliusz Chroboczek9c298c72012-02-11 14:06:24 +0100715 vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400716}
717
718DEFUN (show_babel_interface,
719 show_babel_interface_cmd,
720 "show babel interface [INTERFACE]",
721 SHOW_STR
722 IP_STR
723 "Babel information\n"
724 "Interface information\n"
725 "Interface name\n")
726{
727 struct interface *ifp;
728 struct listnode *node;
729
730 if (argc == 0)
731 {
732 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
733 show_babel_interface_sub (vty, ifp);
734 return CMD_SUCCESS;
735 }
736 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
737 {
738 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
739 return CMD_WARNING;
740 }
741 show_babel_interface_sub (vty, ifp);
742 return CMD_SUCCESS;
743}
Paul Jakma57345092011-12-25 17:52:09 +0100744
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100745static void
746show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh)
747{
748 vty_out (vty,
749 "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s",
750 format_address(neigh->address),
751 neigh->ifp->name,
752 neigh->reach,
753 neighbour_rxcost(neigh),
754 neigh->txcost,
755 if_up(neigh->ifp) ? "" : " (down)",
756 VTY_NEWLINE);
757}
758
759DEFUN (show_babel_neighbour,
760 show_babel_neighbour_cmd,
761 "show babel neighbour [INTERFACE]",
762 SHOW_STR
763 IP_STR
764 "Babel information\n"
765 "Print neighbours\n"
766 "Interface name\n")
767{
768 struct neighbour *neigh;
769 struct interface *ifp;
770
771 if (argc == 0) {
772 FOR_ALL_NEIGHBOURS(neigh) {
773 show_babel_neighbour_sub(vty, neigh);
774 }
775 return CMD_SUCCESS;
776 }
777 if ((ifp = if_lookup_by_name (argv[0])) == NULL)
778 {
779 vty_out (vty, "No such interface name%s", VTY_NEWLINE);
780 return CMD_WARNING;
781 }
782 FOR_ALL_NEIGHBOURS(neigh) {
783 if(ifp->ifindex == neigh->ifp->ifindex) {
784 show_babel_neighbour_sub(vty, neigh);
785 }
786 }
787 return CMD_SUCCESS;
788}
789
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100790static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100791show_babel_routes_sub (struct babel_route *route, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100792{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100793 struct vty *vty = (struct vty*) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100794 const unsigned char *nexthop =
795 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
796 NULL : route->nexthop;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100797 char channels[100];
798
799 if(route->channels[0] == 0)
800 channels[0] = '\0';
801 else {
802 int k, j = 0;
803 snprintf(channels, 100, " chan (");
804 j = strlen(channels);
805 for(k = 0; k < DIVERSITY_HOPS; k++) {
806 if(route->channels[k] == 0)
807 break;
808 if(k > 0)
809 channels[j++] = ',';
810 snprintf(channels + j, 100 - j, "%d", route->channels[k]);
811 j = strlen(channels);
812 }
813 snprintf(channels + j, 100 - j, ")");
814 if(k == 0)
815 channels[0] = '\0';
816 }
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100817
818 vty_out(vty,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100819 "%s metric %d refmetric %d id %s seqno %d%s age %d "
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100820 "via %s neigh %s%s%s%s%s",
821 format_prefix(route->src->prefix, route->src->plen),
822 route_metric(route), route->refmetric,
823 format_eui64(route->src->id),
824 (int)route->seqno,
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100825 channels,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100826 (int)(babel_now.tv_sec - route->time),
827 route->neigh->ifp->name,
828 format_address(route->neigh->address),
829 nexthop ? " nexthop " : "",
830 nexthop ? format_address(nexthop) : "",
831 route->installed ? " (installed)" :
832 route_feasible(route) ? " (feasible)" : "",
833 VTY_NEWLINE);
834}
835
836static void
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100837show_babel_xroutes_sub (struct xroute *xroute, void *closure)
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100838{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100839 struct vty *vty = (struct vty *) closure;
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100840 vty_out(vty, "%s metric %d (exported)%s",
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100841 format_prefix(xroute->prefix, xroute->plen),
842 xroute->metric,
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100843 VTY_NEWLINE);
844}
845
846DEFUN (show_babel_database,
847 show_babel_database_cmd,
848 "show babel database",
849 SHOW_STR
850 IP_STR
851 "Babel information\n"
852 "Database information\n"
853 "No attributes\n")
854{
Matthieu Boutierc35fafd2012-01-23 23:46:32 +0100855 for_all_routes(show_babel_routes_sub, vty);
856 for_all_xroutes(show_babel_xroutes_sub, vty);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100857 return CMD_SUCCESS;
858}
859
Denis Ovsienkoa14ef5e2012-02-11 21:06:16 +0400860DEFUN (show_babel_parameters,
861 show_babel_parameters_cmd,
862 "show babel parameters",
Matthieu Boutierd3351d12012-01-19 22:36:56 +0100863 SHOW_STR
864 IP_STR
865 "Babel information\n"
866 "Configuration information\n"
867 "No attributes\n")
868{
869 vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE);
870 show_babel_main_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);
Juliusz Chroboczekc428edb2012-02-11 14:02:10 +0100902 install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
Denis Ovsienkod4e46e62012-01-17 19:25:03 +0400903
Juliusz Chroboczekec0c8482012-02-07 05:44:41 +0100904 /* "show babel ..." commands */
905 install_element(VIEW_NODE, &show_babel_interface_cmd);
906 install_element(ENABLE_NODE, &show_babel_interface_cmd);
Matthieu Boutier297a55b2012-01-18 16:39:29 +0100907 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
908 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
Matthieu Boutier1f39f462012-01-18 20:01:31 +0100909 install_element(VIEW_NODE, &show_babel_database_cmd);
910 install_element(ENABLE_NODE, &show_babel_database_cmd);
Denis Ovsienkoa14ef5e2012-02-11 21:06:16 +0400911 install_element(VIEW_NODE, &show_babel_parameters_cmd);
912 install_element(ENABLE_NODE, &show_babel_parameters_cmd);
Paul Jakma57345092011-12-25 17:52:09 +0100913}
914
915/* hooks: functions called respectively when struct interface is
916 created or deleted. */
917static int
918babel_if_new_hook (struct interface *ifp)
919{
920 ifp->info = babel_interface_allocate();
921 return 0;
922}
923
924static int
925babel_if_delete_hook (struct interface *ifp)
926{
927 babel_interface_free(ifp->info);
928 ifp->info = NULL;
929 return 0;
930}
931
Denis Ovsienkocb4b13d2012-02-13 22:13:37 +0400932/* Output an "interface" section for each of the known interfaces with
933babeld-specific statement lines where appropriate. */
Paul Jakma57345092011-12-25 17:52:09 +0100934static 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 vty_out (vty, "interface %s%s", ifp->name,
943 VTY_NEWLINE);
944 if (ifp->desc)
945 vty_out (vty, " description %s%s", ifp->desc,
946 VTY_NEWLINE);
Denis Ovsienkocb4b13d2012-02-13 22:13:37 +0400947 if (IS_ENABLE (ifp))
948 {
949 babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp);
950 /* wireless/no split-horizon is the default */
951 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED))
952 {
953 vty_out (vty, " babel wired%s", VTY_NEWLINE);
954 write++;
955 }
956 if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON))
957 {
958 vty_out (vty, " babel split-horizon%s", VTY_NEWLINE);
959 write++;
960 }
Denis Ovsienkocbde1552012-02-14 15:12:03 +0400961 if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL)
962 {
963 vty_out (vty, " babel hello-interval %u%s", babel_ifp->hello_interval, VTY_NEWLINE);
964 write++;
965 }
966 if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL)
967 {
968 vty_out (vty, " babel update-interval %u%s", babel_ifp->update_interval, VTY_NEWLINE);
969 write++;
970 }
Denis Ovsienkocb4b13d2012-02-13 22:13:37 +0400971 }
Paul Jakma57345092011-12-25 17:52:09 +0100972 vty_out (vty, "!%s", VTY_NEWLINE);
Paul Jakma57345092011-12-25 17:52:09 +0100973 write++;
974 }
975 return write;
976}
977
Denis Ovsienkoa14ef5e2012-02-11 21:06:16 +0400978/* Output a "network" statement line for each of the enabled interfaces. */
979int
980babel_enable_if_config_write (struct vty * vty)
981{
982 unsigned int i, lines = 0;
983 char *str;
984
985 for (i = 0; i < vector_active (babel_enable_if); i++)
986 if ((str = vector_slot (babel_enable_if, i)) != NULL)
987 {
988 vty_out (vty, " network %s%s", str, VTY_NEWLINE);
989 lines++;
990 }
991 return lines;
992}
993
Paul Jakma57345092011-12-25 17:52:09 +0100994/* functions to allocate or free memory for a babel_interface_nfo, filling
995 needed fields */
996static babel_interface_nfo *
Matthieu Boutierc7c53fa2012-01-08 16:43:08 +0100997babel_interface_allocate (void)
Paul Jakma57345092011-12-25 17:52:09 +0100998{
999 babel_interface_nfo *babel_ifp;
1000 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
1001 if(babel_ifp == NULL)
1002 return NULL;
1003
1004 /* Here are set the default values for an interface. */
1005 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
1006 /* All flags are unset */
Paul Jakma57345092011-12-25 17:52:09 +01001007 babel_ifp->bucket_time = babel_now.tv_sec;
1008 babel_ifp->bucket = BUCKET_TOKENS_MAX;
1009 babel_ifp->hello_seqno = (random() & 0xFFFF);
Juliusz Chroboczek36329c02012-02-14 08:49:57 +01001010 babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL;
1011 babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL;
Matthieu Boutierc35fafd2012-01-23 23:46:32 +01001012 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
Juliusz Chroboczek260948c2012-02-14 09:09:32 +01001013 babel_set_wired_internal(babel_ifp, 0);
Paul Jakma57345092011-12-25 17:52:09 +01001014
1015 return babel_ifp;
1016}
1017
1018static void
1019babel_interface_free (babel_interface_nfo *babel_ifp)
1020{
1021 XFREE(MTYPE_BABEL_IF, babel_ifp);
1022}