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
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
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
62static 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);
70static babel_interface_nfo * babel_interface_allocate (void);
71static 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;
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
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;
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
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);
136    return 0;
137}
138
139int
140babel_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
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)
263        interface_recalculate(ifp);
264
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)
286        interface_reset(ifp);
287
288    return 1;
289}
290
291/* [Babel Command] Babel enable on specified interface or matched network. */
292DEFUN (babel_network,
293       babel_network_cmd,
294       "network IF_OR_ADDR",
295       "Enable Babel protocol on specified interface or network.\n"
296       "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
323       "Disable Babel protocol on specified interface or network.\n"
324       "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
346/* 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
365/* [Interface Command] Tell the interface is wire. */
366DEFUN (babel_set_wired,
367       babel_set_wired_cmd,
368       "babel wired",
369       "Babel interface commands\n"
370       "Enable wired optimisations")
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_set_wired_internal(babel_ifp, 1);
380    return CMD_SUCCESS;
381}
382
383/* [Interface Command] Tell the interface is wireless (default). */
384DEFUN (babel_set_wireless,
385       babel_set_wireless_cmd,
386       "babel wireless",
387       "Babel interface commands\n"
388       "Disable wired optimiations (assume wireless)")
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_set_wired_internal(babel_ifp, 0);
398    return CMD_SUCCESS;
399}
400
401/* [Interface Command] Enable split horizon. */
402DEFUN (babel_split_horizon,
403       babel_split_horizon_cmd,
404       "babel split-horizon",
405       "Babel interface commands\n"
406       "Enable split horizon processing")
407{
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
424       "Babel interface commands\n"
425       "Disable split horizon processing")
426{
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,
441       "babel hello-interval <20-655340>",
442       "Babel interface commands\n"
443       "Time between scheduled hellos\n"
444       "Milliseconds\n")
445{
446    struct interface *ifp;
447    babel_interface_nfo *babel_ifp;
448    int interval;
449
450    VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE);
451
452    ifp = vty->index;
453    babel_ifp = babel_get_if_nfo(ifp);
454    assert (babel_ifp != NULL);
455
456    babel_ifp->hello_interval = interval;
457    return CMD_SUCCESS;
458}
459
460/* [Interface Command]. */
461DEFUN (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
482/* 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
516    if (!IS_ENABLE(ifp))
517        return -1;
518
519    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
526    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) {
543        zlog_err("Couldn't reallocate sendbuf.");
544        free(tmp);
545        babel_ifp->bufsize = 0;
546        return -1;
547    }
548    tmp = NULL;
549
550    resize_receive_buffer(mtu);
551
552    memset(&mreq, 0, sizeof(mreq));
553    memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
554    mreq.ipv6mr_interface = ifp->ifindex;
555
556    rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
557                    (char*)&mreq, sizeof(mreq));
558    if(rc < 0) {
559        zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
560                 ifp->name, safe_strerror(errno));
561        /* This is probably due to a missing link-local address,
562         so down this interface, and wait until the main loop
563         tries to up it again. */
564        interface_reset(ifp);
565        return -1;
566    }
567
568    set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
569    set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
570    send_hello(ifp);
571    send_request(ifp, NULL, 0);
572
573    update_interface_metric(ifp);
574
575    debugf(BABEL_DEBUG_COMMON,
576           "Upped interface %s (%s, cost=%d, channel=%d%s).",
577           ifp->name,
578           (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
579           babel_ifp->cost,
580           babel_ifp->channel,
581           babel_ifp->ipv4 ? ", IPv4" : "");
582
583    if(rc > 0)
584        send_update(ifp, 0, NULL, 0);
585
586    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
598    if (!(babel_ifp->flags & BABEL_IF_IS_UP))
599        return 0;
600
601    debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name);
602    babel_ifp->flags &= ~BABEL_IF_IS_UP;
603
604    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
687static void
688show_babel_interface_sub (struct vty *vty, struct interface *ifp)
689{
690  int is_up;
691  babel_interface_nfo *babel_ifp;
692
693  vty_out (vty, "%s is %s%s", ifp->name,
694    ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE);
695  vty_out (vty, "  ifindex %u, MTU %u bytes %s%s",
696    ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE);
697
698  if (babel_enable_if_lookup (ifp->name) < 0)
699  {
700    vty_out (vty, "  Babel protocol is not enabled on this interface%s", VTY_NEWLINE);
701    return;
702  }
703  if (!is_up)
704  {
705    vty_out (vty, "  Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE);
706    return;
707  }
708  babel_ifp = babel_get_if_nfo (ifp);
709  vty_out (vty, "  Babel protocol is running on this interface%s", VTY_NEWLINE);
710  vty_out (vty, "  Operating mode is \"%s\"%s",
711           CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE);
712  vty_out (vty, "  Split horizon mode is %s%s",
713           CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE);
714  vty_out (vty, "  Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE);
715  vty_out (vty, "  Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE);
716}
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}
744
745static 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
790static void
791show_babel_routes_sub (struct babel_route *route, void *closure)
792{
793    struct vty *vty = (struct vty*) closure;
794    const unsigned char *nexthop =
795        memcmp(route->nexthop, route->neigh->address, 16) == 0 ?
796        NULL : route->nexthop;
797    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    }
817
818    vty_out(vty,
819            "%s metric %d refmetric %d id %s seqno %d%s age %d "
820            "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,
825            channels,
826            (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
837show_babel_xroutes_sub (struct xroute *xroute, void *closure)
838{
839    struct vty *vty = (struct vty *) closure;
840    vty_out(vty, "%s metric %d (exported)%s",
841            format_prefix(xroute->prefix, xroute->plen),
842            xroute->metric,
843            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{
855    for_all_routes(show_babel_routes_sub, vty);
856    for_all_xroutes(show_babel_xroutes_sub, vty);
857    return CMD_SUCCESS;
858}
859
860DEFUN (show_babel_parameters,
861       show_babel_parameters_cmd,
862       "show babel parameters",
863       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);
871    vty_out(vty, "    -- distribution lists --%s", VTY_NEWLINE);
872    config_show_distribute(vty);
873
874    return CMD_SUCCESS;
875}
876
877void
878babel_if_init ()
879{
880    /* initialize interface list */
881    if_init();
882    if_add_hook (IF_NEW_HOOK,    babel_if_new_hook);
883    if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
884
885    babel_enable_if = vector_init (1);
886
887    /* install interface node and commands */
888    install_element (CONFIG_NODE, &interface_cmd);
889    install_element (CONFIG_NODE, &no_interface_cmd);
890    install_node (&babel_interface_node, interface_config_write);
891    install_default(INTERFACE_NODE);
892    install_element(INTERFACE_NODE, &interface_cmd);
893    install_element(INTERFACE_NODE, &no_interface_cmd);
894
895    install_element(BABEL_NODE, &babel_network_cmd);
896    install_element(BABEL_NODE, &no_babel_network_cmd);
897    install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
898    install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
899    install_element(INTERFACE_NODE, &babel_set_wired_cmd);
900    install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
901    install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
902    install_element(INTERFACE_NODE, &babel_set_update_interval_cmd);
903
904    /* "show babel ..." commands */
905    install_element(VIEW_NODE, &show_babel_interface_cmd);
906    install_element(ENABLE_NODE, &show_babel_interface_cmd);
907    install_element(VIEW_NODE, &show_babel_neighbour_cmd);
908    install_element(ENABLE_NODE, &show_babel_neighbour_cmd);
909    install_element(VIEW_NODE, &show_babel_database_cmd);
910    install_element(ENABLE_NODE, &show_babel_database_cmd);
911    install_element(VIEW_NODE, &show_babel_parameters_cmd);
912    install_element(ENABLE_NODE, &show_babel_parameters_cmd);
913}
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
932/* Output an "interface" section for each of the known interfaces with
933babeld-specific statement lines where appropriate. */
934static int
935interface_config_write (struct vty *vty)
936{
937    struct listnode *node;
938    struct interface *ifp;
939    int write = 0;
940
941    for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
942        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);
947        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            }
961            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            }
971        }
972        vty_out (vty, "!%s", VTY_NEWLINE);
973        write++;
974    }
975    return write;
976}
977
978/* 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
994/* functions to allocate or free memory for a babel_interface_nfo, filling
995 needed fields */
996static babel_interface_nfo *
997babel_interface_allocate (void)
998{
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 */
1007    babel_ifp->bucket_time = babel_now.tv_sec;
1008    babel_ifp->bucket = BUCKET_TOKENS_MAX;
1009    babel_ifp->hello_seqno = (random() & 0xFFFF);
1010    babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL;
1011    babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL;
1012    babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING;
1013    babel_set_wired_internal(babel_ifp, 0);
1014
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}
1023