]> git.proxmox.com Git - mirror_frr.git/blob - babeld/babel_interface.c
babeld: justify "running-config" meaning in CLI
[mirror_frr.git] / babeld / babel_interface.c
1 /*
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
19 Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
20
21 Permission is hereby granted, free of charge, to any person obtaining a copy
22 of this software and associated documentation files (the "Software"), to deal
23 in the Software without restriction, including without limitation the rights
24 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25 copies of the Software, and to permit persons to whom the Software is
26 furnished to do so, subject to the following conditions:
27
28 The above copyright notice and this permission notice shall be included in
29 all copies or substantial portions of the Software.
30
31 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
37 THE SOFTWARE.
38 */
39
40 #include <zebra.h>
41 #include "memory.h"
42 #include "log.h"
43 #include "command.h"
44 #include "prefix.h"
45 #include "vector.h"
46 #include "distribute.h"
47
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"
55 #include "neighbour.h"
56 #include "route.h"
57 #include "xroute.h"
58
59
60 #define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
61
62 static int babel_enable_if_lookup (const char *ifname);
63 static int babel_enable_if_add (const char *ifname);
64 static int babel_enable_if_delete (const char *ifname);
65 static int interface_recalculate(struct interface *ifp);
66 static int interface_reset(struct interface *ifp);
67 static int babel_if_new_hook (struct interface *ifp);
68 static int babel_if_delete_hook (struct interface *ifp);
69 static int interface_config_write (struct vty *vty);
70 static babel_interface_nfo * babel_interface_allocate (void);
71 static void babel_interface_free (babel_interface_nfo *bi);
72
73
74 static vector babel_enable_if; /* enable interfaces (by cmd). */
75 static struct cmd_node babel_interface_node = /* babeld's interface node. */
76 {
77 INTERFACE_NODE,
78 "%s(config-if)# ",
79 1 /* VTYSH */
80 };
81
82
83 int
84 babel_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;
92 ifp = zebra_interface_state_read(s); /* it updates iflist */
93
94 if (ifp == NULL) {
95 return 0;
96 }
97
98 interface_recalculate(ifp);
99 return 0;
100 }
101
102 int
103 babel_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;
111 ifp = zebra_interface_state_read(s); /* it updates iflist */
112
113 if (ifp == NULL) {
114 return 0;
115 }
116
117 interface_reset(ifp);
118 return 0;
119 }
120
121 int
122 babel_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);
136 return 0;
137 }
138
139 int
140 babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length)
141 {
142 struct interface *ifp;
143 struct stream *s;
144
145 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
146
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
160 return 0;
161 }
162
163 int
164 babel_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
200 int
201 babel_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. */
235 static int
236 babel_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. */
249 static int
250 babel_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)
263 interface_recalculate(ifp);
264
265 return 1;
266 }
267
268 /* Delete interface from babel_enable_if. */
269 static int
270 babel_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)
286 interface_reset(ifp);
287
288 return 1;
289 }
290
291
292 /* [Babel Command] Babel enable on specified interface or matched network. */
293 DEFUN (babel_network,
294 babel_network_cmd,
295 "network IF_OR_ADDR",
296 "Enable Babel protocol on specified interface or network.\n"
297 "Interface or address")
298 {
299 int ret;
300 struct prefix p;
301
302 ret = str2prefix (argv[0], &p);
303
304 /* Given string is: */
305 if (ret) /* an IPv4 or v6 network */
306 return CMD_ERR_NO_MATCH; /* not implemented yet */
307 else /* an interface name */
308 ret = babel_enable_if_add (argv[0]);
309
310 if (ret < 0) {
311 vty_out (vty, "There is same network configuration %s%s", argv[0],
312 VTY_NEWLINE);
313 return CMD_WARNING;
314 }
315
316 return CMD_SUCCESS;
317 }
318
319 /* [Babel Command] Babel enable on specified interface or matched network. */
320 DEFUN (no_babel_network,
321 no_babel_network_cmd,
322 "no network IF_OR_ADDR",
323 NO_STR
324 "Disable Babel protocol on specified interface or network.\n"
325 "Interface or address")
326 {
327 int ret;
328 struct prefix p;
329
330 ret = str2prefix (argv[0], &p);
331
332 /* Given string is: */
333 if (ret) /* an IPv4 or v6 network */
334 return CMD_ERR_NO_MATCH; /* not implemented yet */
335 else /* an interface name */
336 ret = babel_enable_if_delete (argv[0]);
337
338 if (ret < 0) {
339 vty_out (vty, "can't find network %s%s", argv[0],
340 VTY_NEWLINE);
341 return CMD_WARNING;
342 }
343
344 return CMD_SUCCESS;
345 }
346
347 /* [Interface Command] Tell the interface is wire. */
348 DEFUN (babel_set_wired,
349 babel_set_wired_cmd,
350 "babel wired",
351 "Babel interface commands\n"
352 "Enable wired optimisations")
353 {
354 struct interface *ifp;
355 babel_interface_nfo *babel_ifp;
356
357 ifp = vty->index;
358 babel_ifp = babel_get_if_nfo(ifp);
359
360 assert (babel_ifp != NULL);
361 babel_ifp->flags |= BABEL_IF_WIRED;
362 return CMD_SUCCESS;
363 }
364
365 /* [Interface Command] Tell the interface is wireless (default). */
366 DEFUN (babel_set_wireless,
367 babel_set_wireless_cmd,
368 "babel wireless",
369 "Babel interface commands\n"
370 "Disable wired optimiations (assume wireless)")
371 {
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. */
384 DEFUN (babel_split_horizon,
385 babel_split_horizon_cmd,
386 "babel split-horizon",
387 "Babel interface commands\n"
388 "Enable split horizon processing")
389 {
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). */
402 DEFUN (no_babel_split_horizon,
403 no_babel_split_horizon_cmd,
404 "no babel split-horizon",
405 NO_STR
406 "Babel interface commands\n"
407 "Disable split horizon processing")
408 {
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]. */
421 DEFUN (babel_set_hello_interval,
422 babel_set_hello_interval_cmd,
423 "babel hello-interval <20-655340>",
424 "Babel interface commands\n"
425 "Time between scheduled hellos\n"
426 "Milliseconds\n")
427 {
428 struct interface *ifp;
429 babel_interface_nfo *babel_ifp;
430 int interval;
431
432 VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
433
434 ifp = vty->index;
435 babel_ifp = babel_get_if_nfo(ifp);
436 assert (babel_ifp != NULL);
437
438 babel_ifp->hello_interval = interval;
439 return CMD_SUCCESS;
440 }
441
442 /* [Interface Command]. */
443 DEFUN (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]. */
465 DEFUN (babel_passive_interface,
466 babel_passive_interface_cmd,
467 "babel passive-interface",
468 "Babel interface commands\n"
469 "Only announce redistributed routes on this interface\n")
470 {
471 if (allow_duplicates) {
472 return CMD_WARNING;
473 }
474 parasitic = 1;
475 return CMD_SUCCESS;
476 }
477
478 /* [Interface Command]. */
479 DEFUN (no_babel_passive_interface,
480 no_babel_passive_interface_cmd,
481 "no babel passive-interface",
482 NO_STR
483 "Babel interface commands\n"
484 "Announce all routes on this interface\n")
485 {
486 parasitic = 0;
487 return CMD_SUCCESS;
488 }
489
490 /* This should be no more than half the hello interval, so that hellos
491 aren't sent late. The result is in milliseconds. */
492 unsigned
493 jitter(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
503 unsigned
504 update_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) */
516 static int
517 interface_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
524 if (!IS_ENABLE(ifp))
525 return -1;
526
527 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
534 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) {
551 zlog_err("Couldn't reallocate sendbuf.");
552 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
568 /* 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,
596 "Upped interface %s (%s, cost=%d, channel=%d%s).",
597 ifp->name,
598 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
599 babel_ifp->cost,
600 babel_ifp->channel,
601 babel_ifp->ipv4 ? ", IPv4" : "");
602
603 if(rc > 0)
604 send_update(ifp, 0, NULL, 0);
605
606 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. */
611 static int
612 interface_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
618 if (!(babel_ifp->flags & BABEL_IF_IS_UP))
619 return 0;
620
621 debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
622 babel_ifp->flags &= ~BABEL_IF_IS_UP;
623
624 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. */
658 void
659 babel_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 */
689 int
690 is_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
707 static void
708 show_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);
735 vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE);
736 }
737
738 DEFUN (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 }
764
765 static void
766 show_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
779 DEFUN (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
810 static void
811 show_babel_routes_sub (struct babel_route *route, void *closure)
812 {
813 struct vty *vty = (struct vty*) closure;
814 const unsigned char *nexthop =
815 memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
816 NULL : route->nexthop;
817 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 }
837
838 vty_out(vty,
839 "%s metric %d refmetric %d id %s seqno %d%s age %d "
840 "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,
845 channels,
846 (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
856 static void
857 show_babel_xroutes_sub (struct xroute *xroute, void *closure)
858 {
859 struct vty *vty = (struct vty *) closure;
860 vty_out(vty, "%s metric %d (exported)%s",
861 format_prefix(xroute->prefix, xroute->plen),
862 xroute->metric,
863 VTY_NEWLINE);
864 }
865
866 DEFUN (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 {
875 for_all_routes(show_babel_routes_sub, vty);
876 for_all_xroutes(show_babel_xroutes_sub, vty);
877 return CMD_SUCCESS;
878 }
879
880 DEFUN (show_babel_parameters,
881 show_babel_parameters_cmd,
882 "show babel parameters",
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 vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE);
892 config_show_distribute(vty);
893
894 return CMD_SUCCESS;
895 }
896
897 void
898 babel_if_init ()
899 {
900 /* initialize interface list */
901 if_init();
902 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
903 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
904
905 babel_enable_if = vector_init (1);
906
907 /* install interface node and commands */
908 install_element (CONFIG_NODE, &interface_cmd);
909 install_element (CONFIG_NODE, &no_interface_cmd);
910 install_node (&babel_interface_node, interface_config_write);
911 install_default(INTERFACE_NODE);
912 install_element(INTERFACE_NODE, &interface_cmd);
913 install_element(INTERFACE_NODE, &no_interface_cmd);
914
915 install_element(BABEL_NODE, &babel_network_cmd);
916 install_element(BABEL_NODE, &no_babel_network_cmd);
917 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
918 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
919 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
920 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
921 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
922 install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
923 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
924 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
925
926 /* "show babel ..." commands */
927 install_element(VIEW_NODE, &show_babel_interface_cmd);
928 install_element(ENABLE_NODE, &show_babel_interface_cmd);
929 install_element(VIEW_NODE, &show_babel_neighbour_cmd);
930 install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
931 install_element(VIEW_NODE, &show_babel_database_cmd);
932 install_element(ENABLE_NODE, &show_babel_database_cmd);
933 install_element(VIEW_NODE, &show_babel_parameters_cmd);
934 install_element(ENABLE_NODE, &show_babel_parameters_cmd);
935 }
936
937 /* hooks: functions called respectively when struct interface is
938 created or deleted. */
939 static int
940 babel_if_new_hook (struct interface *ifp)
941 {
942 ifp->info = babel_interface_allocate();
943 return 0;
944 }
945
946 static int
947 babel_if_delete_hook (struct interface *ifp)
948 {
949 babel_interface_free(ifp->info);
950 ifp->info = NULL;
951 return 0;
952 }
953
954 /* Configuration write function for babeld. */
955 static int
956 interface_config_write (struct vty *vty)
957 {
958 struct listnode *node;
959 struct interface *ifp;
960 int write = 0;
961
962 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
963 /* Do not display the interface if there is no configuration about it */
964 if (ifp->desc == NULL)
965 continue;
966
967 vty_out (vty, "interface %s%s", ifp->name,
968 VTY_NEWLINE);
969 if (ifp->desc)
970 vty_out (vty, " description %s%s", ifp->desc,
971 VTY_NEWLINE);
972
973 /* TODO: to be completed... */
974
975 vty_out (vty, "!%s", VTY_NEWLINE);
976
977 write++;
978 }
979 return write;
980 }
981
982 /* Output a "network" statement line for each of the enabled interfaces. */
983 int
984 babel_enable_if_config_write (struct vty * vty)
985 {
986 unsigned int i, lines = 0;
987 char *str;
988
989 for (i = 0; i < vector_active (babel_enable_if); i++)
990 if ((str = vector_slot (babel_enable_if, i)) != NULL)
991 {
992 vty_out (vty, " network %s%s", str, VTY_NEWLINE);
993 lines++;
994 }
995 return lines;
996 }
997
998 /* functions to allocate or free memory for a babel_interface_nfo, filling
999 needed fields */
1000 static babel_interface_nfo *
1001 babel_interface_allocate (void)
1002 {
1003 babel_interface_nfo *babel_ifp;
1004 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
1005 if(babel_ifp == NULL)
1006 return NULL;
1007
1008 /* Here are set the default values for an interface. */
1009 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
1010 /* All flags are unset */
1011 babel_ifp->bucket_time = babel_now.tv_sec;
1012 babel_ifp->bucket = BUCKET_TOKENS_MAX;
1013 babel_ifp->hello_seqno = (random() & 0xFFFF);
1014 babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
1015 babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
1016
1017 return babel_ifp;
1018 }
1019
1020 static void
1021 babel_interface_free (babel_interface_nfo *babel_ifp)
1022 {
1023 XFREE(MTYPE_BABEL_IF, babel_ifp);
1024 }