blob: ff9c5eb473461e2257a2de130fe09a46fdffe37c [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"
46
47#include "babel_main.h"
48#include "util.h"
49#include "kernel.h"
50#include "babel_interface.h"
51#include "message.h"
52#include "route.h"
53#include "babel_zebra.h"
54
55
56static int babel_enable_if_lookup (const char *ifname);
57static int babel_enable_if_add (const char *ifname);
58static int babel_enable_if_delete (const char *ifname);
59static int interface_recalculate(struct interface *ifp);
60static int interface_reset(struct interface *ifp);
61static int babel_if_new_hook (struct interface *ifp);
62static int babel_if_delete_hook (struct interface *ifp);
63static int interface_config_write (struct vty *vty);
64static babel_interface_nfo * babel_interface_allocate ();
65static void babel_interface_free (babel_interface_nfo *bi);
66
67
68static vector babel_enable_if; /* enable interfaces (by cmd). */
69static struct cmd_node babel_interface_node = /* babeld's interface node. */
70{
71 INTERFACE_NODE,
72 "%s(config-if)# ",
73 1 /* VTYSH */
74};
75
76
77int
78babel_interface_up (int cmd, struct zclient *client, zebra_size_t length)
79{
80 struct stream *s = NULL;
81 struct interface *ifp = NULL;
82
83 debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
84
85 s = zclient->ibuf;
86 ifp = zebra_interface_state_read(s);
87
88 if (ifp == NULL) {
89 return 0;
90 }
91
92 interface_recalculate(ifp);
93 return 0;
94}
95
96int
97babel_interface_down (int cmd, struct zclient *client, zebra_size_t length)
98{
99 struct stream *s = NULL;
100 struct interface *ifp = NULL;
101
102 debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
103
104 s = zclient->ibuf;
105 ifp = zebra_interface_state_read(s);
106
107 if (ifp == NULL) {
108 return 0;
109 }
110
111 interface_reset(ifp);
112 return 0;
113}
114
115int
116babel_interface_add (int cmd, struct zclient *client, zebra_size_t length)
117{
118 struct interface *ifp = NULL;
119
120 debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
121
122 /* read and add the interface in the iflist. */
123 ifp = zebra_interface_add_read (zclient->ibuf);
124
125 if (ifp == NULL) {
126 return 0;
127 }
128
129 interface_recalculate(ifp);
130
131 return 0;
132}
133
134int
135babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length)
136{
137 debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
138 return 0;
139}
140
141int
142babel_interface_address_add (int cmd, struct zclient *client,
143 zebra_size_t length)
144{
145 babel_interface_nfo *babel_ifp;
146 struct connected *ifc;
147 struct prefix *prefix;
148
149 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
150
151 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
152 zclient->ibuf);
153
154 if (ifc == NULL)
155 return 0;
156
157 prefix = ifc->address;
158
159 if (prefix->family == AF_INET) {
160 flush_interface_routes(ifc->ifp, 0);
161 babel_ifp = babel_get_if_nfo(ifc->ifp);
162 if (babel_ifp->ipv4 == NULL) {
163 babel_ifp->ipv4 = malloc(4);
164 if (babel_ifp->ipv4 == NULL) {
165 zlog_err("not einough memory");
166 } else {
167 memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
168 }
169 }
170 }
171
172 send_request(ifc->ifp, NULL, 0);
173 send_update(ifc->ifp, 0, NULL, 0);
174
175 return 0;
176}
177
178int
179babel_interface_address_delete (int cmd, struct zclient *client,
180 zebra_size_t length)
181{
182 babel_interface_nfo *babel_ifp;
183 struct connected *ifc;
184 struct prefix *prefix;
185
186 debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
187
188 ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
189 zclient->ibuf);
190
191 if (ifc == NULL)
192 return 0;
193
194 prefix = ifc->address;
195
196 if (prefix->family == AF_INET) {
197 flush_interface_routes(ifc->ifp, 0);
198 babel_ifp = babel_get_if_nfo(ifc->ifp);
199 if (babel_ifp->ipv4 != NULL
200 && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) {
201 free(babel_ifp->ipv4);
202 babel_ifp->ipv4 = NULL;
203 }
204 }
205
206 send_request(ifc->ifp, NULL, 0);
207 send_update(ifc->ifp, 0, NULL, 0);
208
209 return 0;
210}
211
212/* Lookup function. */
213static int
214babel_enable_if_lookup (const char *ifname)
215{
216 unsigned int i;
217 char *str;
218
219 for (i = 0; i < vector_active (babel_enable_if); i++)
220 if ((str = vector_slot (babel_enable_if, i)) != NULL)
221 if (strcmp (str, ifname) == 0)
222 return i;
223 return -1;
224}
225
226/* Add interface to babel_enable_if. */
227static int
228babel_enable_if_add (const char *ifname)
229{
230 int ret;
231 struct interface *ifp = NULL;
232
233 ret = babel_enable_if_lookup (ifname);
234 if (ret >= 0)
235 return -1;
236
237 vector_set (babel_enable_if, strdup (ifname));
238
239 ifp = if_lookup_by_name(ifname);
240 if (ifp != NULL)
241 babel_get_if_nfo(ifp)->flags |= BABEL_IF_IS_ENABLE;
242
243 return 1;
244}
245
246/* Delete interface from babel_enable_if. */
247static int
248babel_enable_if_delete (const char *ifname)
249{
250 int babel_enable_if_index;
251 char *str;
252 struct interface *ifp = NULL;
253
254 babel_enable_if_index = babel_enable_if_lookup (ifname);
255 if (babel_enable_if_index < 0)
256 return -1;
257
258 str = vector_slot (babel_enable_if, babel_enable_if_index);
259 free (str);
260 vector_unset (babel_enable_if, babel_enable_if_index);
261
262 ifp = if_lookup_by_name(ifname);
263 if (ifp != NULL)
264 babel_get_if_nfo(ifp)->flags &= ~BABEL_IF_IS_ENABLE;
265
266 return 1;
267}
268
269
270/* [Babel Command] Babel enable on specified interface or matched network. */
271DEFUN (babel_network,
272 babel_network_cmd,
273 "network IF_OR_ADDR",
274 "Babel enable on specified interface or network.\n"
275 "Interface or address")
276{
277 int ret;
278 struct prefix p;
279
280 ret = str2prefix (argv[0], &p);
281
282 /* Given string is: */
283 if (ret) /* an IPv4 or v6 network */
284 return CMD_ERR_NO_MATCH; /* not implemented yet */
285 else /* an interface name */
286 ret = babel_enable_if_add (argv[0]);
287
288 if (ret < 0) {
289 vty_out (vty, "There is same network configuration %s%s", argv[0],
290 VTY_NEWLINE);
291 return CMD_WARNING;
292 }
293
294 return CMD_SUCCESS;
295}
296
297/* [Babel Command] Babel enable on specified interface or matched network. */
298DEFUN (no_babel_network,
299 no_babel_network_cmd,
300 "no network IF_OR_ADDR",
301 NO_STR
302 "Babel enable on specified interface or network.\n"
303 "Interface or address")
304{
305 int ret;
306 struct prefix p;
307
308 ret = str2prefix (argv[0], &p);
309
310 /* Given string is: */
311 if (ret) /* an IPv4 or v6 network */
312 return CMD_ERR_NO_MATCH; /* not implemented yet */
313 else /* an interface name */
314 ret = babel_enable_if_delete (argv[0]);
315
316 if (ret < 0) {
317 vty_out (vty, "can't find network %s%s", argv[0],
318 VTY_NEWLINE);
319 return CMD_WARNING;
320 }
321
322 return CMD_SUCCESS;
323}
324
325/* [Interface Command] Tell the interface is wire. */
326DEFUN (babel_set_wired,
327 babel_set_wired_cmd,
328 "wired",
329 "Set this interface as wired (default: wireless).\n"
330 "No attributes")
331{
332 struct interface *ifp;
333 babel_interface_nfo *babel_ifp;
334
335 ifp = vty->index;
336 babel_ifp = babel_get_if_nfo(ifp);
337
338 assert (babel_ifp != NULL);
339 babel_ifp->flags |= BABEL_IF_WIRED;
340 return CMD_SUCCESS;
341}
342
343/* [Interface Command] Tell the interface is wireless (default). */
344DEFUN (babel_set_wireless,
345 babel_set_wireless_cmd,
346 "wireless",
347 NO_STR
348 "Set this interface as wireless (is default).\n"
349 "No attributes")
350{
351 struct interface *ifp;
352 babel_interface_nfo *babel_ifp;
353
354 ifp = vty->index;
355 babel_ifp = babel_get_if_nfo(ifp);
356
357 assert (babel_ifp != NULL);
358 babel_ifp->flags &= ~BABEL_IF_WIRED;
359 return CMD_SUCCESS;
360}
361
362/* [Interface Command] Enable split horizon. */
363DEFUN (babel_split_horizon,
364 babel_split_horizon_cmd,
365 "babel split-horizon",
366 IPV6_STR
367 "Routing Information Protocol\n"
368 "Perform split horizon\n")
369{
370 struct interface *ifp;
371 babel_interface_nfo *babel_ifp;
372
373 ifp = vty->index;
374 babel_ifp = babel_get_if_nfo(ifp);
375
376 assert (babel_ifp != NULL);
377 babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
378 return CMD_SUCCESS;
379}
380
381/* [Interface Command] Disable split horizon (default). */
382DEFUN (no_babel_split_horizon,
383 no_babel_split_horizon_cmd,
384 "no babel split-horizon",
385 NO_STR
386 IPV6_STR
387 "Routing Information Protocol\n"
388 "Perform split horizon\n")
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]. */
402DEFUN (babel_set_hello_interval,
403 babel_set_hello_interval_cmd,
404 "hello interval <5-1000000>",
405 "Set interface's hello interval (default: 4000).\n"
406 "Value in miliseconds\n")
407{
408 struct interface *ifp;
409 babel_interface_nfo *babel_ifp;
410
411 int interval = atoi(argv[1]);
412
413 ifp = vty->index;
414 babel_ifp = babel_get_if_nfo(ifp);
415
416 assert (babel_ifp != NULL);
417 babel_ifp->hello_interval = interval;
418 return CMD_SUCCESS;
419}
420
421/* [Interface Command]. */
422DEFUN (babel_passive_interface,
423 babel_passive_interface_cmd,
424 "passive-interface",
425 "The daemon will only announce redistributed routes\n"
426 "Interface name\n")
427{
428 if (allow_duplicates) {
429 return CMD_WARNING;
430 }
431 parasitic = -1;
432 return CMD_SUCCESS;
433}
434
435/* [Interface Command]. */
436DEFUN (no_babel_passive_interface,
437 no_babel_passive_interface_cmd,
438 "no passive-interface",
439 NO_STR
440 "The daemon will announce all (filtred) routes\n"
441 "Interface name\n")
442{
443 parasitic = 0;
444 return CMD_SUCCESS;
445}
446
447
448int
449interface_idle(babel_interface_nfo *babel_ifp)
450{
451 return (idle_hello_interval > 0 &&
452 babel_ifp->activity_time < babel_now.tv_sec - idle_time);
453}
454
455/* This should be no more than half the hello interval, so that hellos
456 aren't sent late. The result is in milliseconds. */
457unsigned
458jitter(babel_interface_nfo *babel_ifp, int urgent)
459{
460 unsigned interval = babel_ifp->hello_interval;
461 if(urgent)
462 interval = MIN(interval, 100);
463 else
464 interval = MIN(interval, 4000);
465 return roughly(interval) / 4;
466}
467
468unsigned
469update_jitter(babel_interface_nfo *babel_ifp, int urgent)
470{
471 unsigned interval = babel_ifp->hello_interval;
472 if(urgent)
473 interval = MIN(interval, 100);
474 else
475 interval = MIN(interval, 4000);
476 return roughly(interval);
477}
478
479/* calculate babeld's specific datas of an interface (change when the interface
480 change) */
481static int
482interface_recalculate(struct interface *ifp)
483{
484 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
485 unsigned char *tmp = NULL;
486 int mtu, rc;
487 struct ipv6_mreq mreq;
488
489 mtu = MIN(ifp->mtu, ifp->mtu6);
490
491 /* We need to be able to fit at least two messages into a packet,
492 so MTUs below 116 require lower layer fragmentation. */
493 /* In IPv6, the minimum MTU is 1280, and every host must be able
494 to reassemble up to 1500 bytes, but I'd rather not rely on this. */
495 if(mtu < 128) {
496 debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
497 mtu, ifp->name, ifp->ifindex);
498 mtu = 128;
499 }
500
501 /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
502 babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
503 tmp = babel_ifp->sendbuf;
504 babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
505 if(babel_ifp->sendbuf == NULL) {
506 fprintf(stderr, "Couldn't reallocate sendbuf.\n");
507 free(tmp);
508 babel_ifp->bufsize = 0;
509 return -1;
510 }
511 tmp = NULL;
512
513 resize_receive_buffer(mtu);
514
515 if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */
516 babel_ifp->cost = 96;
517 babel_ifp->flags &= ~BABEL_IF_LQ;
518 } else {
519 babel_ifp->cost = 256;
520 babel_ifp->flags |= BABEL_IF_LQ;
521 }
522
523 babel_ifp->activity_time = babel_now.tv_sec;
524 /* Since the interface was marked as active above, the
525 idle_hello_interval cannot be the one being used here. */
526 babel_ifp->update_interval = babel_ifp->hello_interval * 4;
527
528 memset(&mreq, 0, sizeof(mreq));
529 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
530 mreq.ipv6mr_interface = ifp->ifindex;
531
532 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
533 (char*)&mreq, sizeof(mreq));
534 if(rc < 0) {
535 zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
536 ifp->name, safe_strerror(errno));
537 /* This is probably due to a missing link-local address,
538 so down this interface, and wait until the main loop
539 tries to up it again. */
540 interface_reset(ifp);
541 return -1;
542 }
543
544 set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
545 set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
546 send_hello(ifp);
547 send_request(ifp, NULL, 0);
548
549 update_interface_metric(ifp);
550
551 debugf(BABEL_DEBUG_COMMON,
552 "Upped network %s (%s, cost=%d%s).",
553 ifp->name,
554 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
555 babel_ifp->cost,
556 babel_ifp->ipv4 ? ", IPv4" : "");
557
558 if(rc > 0)
559 send_update(ifp, 0, NULL, 0);
560
561 /* Check and set if interface is enable. */
562 if (babel_enable_if_lookup(ifp->name) >= 0) {
563 babel_ifp->flags |= BABEL_IF_IS_ENABLE;
564 } else {
565 babel_ifp->flags &= ~BABEL_IF_IS_ENABLE;
566 }
567
568 return 1;
569}
570
571/* Reset the interface as it was new: it's not removed from the interface list,
572 and may be considered as a upped interface. */
573static int
574interface_reset(struct interface *ifp)
575{
576 int rc;
577 struct ipv6_mreq mreq;
578 babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
579
580 flush_interface_routes(ifp, 0);
581 babel_ifp->buffered = 0;
582 babel_ifp->bufsize = 0;
583 free(babel_ifp->sendbuf);
584 babel_ifp->num_buffered_updates = 0;
585 babel_ifp->update_bufsize = 0;
586 if(babel_ifp->buffered_updates)
587 free(babel_ifp->buffered_updates);
588 babel_ifp->buffered_updates = NULL;
589 babel_ifp->sendbuf = NULL;
590
591 if(ifp->ifindex > 0) {
592 memset(&mreq, 0, sizeof(mreq));
593 memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
594 mreq.ipv6mr_interface = ifp->ifindex;
595 rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
596 (char*)&mreq, sizeof(mreq));
597 if(rc < 0)
598 zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
599 ifp->name, safe_strerror(errno));
600 }
601
602 update_interface_metric(ifp);
603
604 debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
605 ifp->name,
606 (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
607 babel_ifp->cost,
608 babel_ifp->ipv4 ? ", IPv4" : "");
609
610 return 1;
611}
612
613/* Send retraction to all, and reset all interfaces statistics. */
614void
615babel_interface_close_all(void)
616{
617 struct interface *ifp = NULL;
618 struct listnode *linklist_node = NULL;
619
620 FOR_ALL_INTERFACES(ifp, linklist_node) {
621 if(!if_up(ifp))
622 continue;
623 send_wildcard_retraction(ifp);
624 /* Make sure that we expire quickly from our neighbours'
625 association caches. */
626 send_hello_noupdate(ifp, 10);
627 flushbuf(ifp);
628 usleep(roughly(1000));
629 gettime(&babel_now);
630 }
631 FOR_ALL_INTERFACES(ifp, linklist_node) {
632 if(!if_up(ifp))
633 continue;
634 /* Make sure they got it. */
635 send_wildcard_retraction(ifp);
636 send_hello_noupdate(ifp, 1);
637 flushbuf(ifp);
638 usleep(roughly(10000));
639 gettime(&babel_now);
640 interface_reset(ifp);
641 }
642}
643
644/* return "true" if address is one of our ipv6 addresses */
645int
646is_interface_ll_address(struct interface *ifp, const unsigned char *address)
647{
648 struct connected *connected;
649 struct listnode *node;
650
651 if(!if_up(ifp))
652 return 0;
653
654 FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
655 if(connected->address->family == AF_INET6 &&
656 memcmp(&connected->address->u.prefix6, address, 16) == 0)
657 return 1;
658 }
659
660 return 0;
661}
662
663
664void
665babel_if_init ()
666{
667 /* initialize interface list */
668 if_init();
669 if_add_hook (IF_NEW_HOOK, babel_if_new_hook);
670 if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
671
672 babel_enable_if = vector_init (1);
673
674 /* install interface node and commands */
675 install_element (CONFIG_NODE, &interface_cmd);
676 install_element (CONFIG_NODE, &no_interface_cmd);
677 install_node (&babel_interface_node, interface_config_write);
678 install_default(INTERFACE_NODE);
679 install_element(INTERFACE_NODE, &interface_cmd);
680 install_element(INTERFACE_NODE, &no_interface_cmd);
681
682 install_element(BABEL_NODE, &babel_network_cmd);
683 install_element(BABEL_NODE, &no_babel_network_cmd);
684 install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
685 install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
686 install_element(INTERFACE_NODE, &babel_set_wired_cmd);
687 install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
688 install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
689 install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
690 install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
691}
692
693/* hooks: functions called respectively when struct interface is
694 created or deleted. */
695static int
696babel_if_new_hook (struct interface *ifp)
697{
698 ifp->info = babel_interface_allocate();
699 return 0;
700}
701
702static int
703babel_if_delete_hook (struct interface *ifp)
704{
705 babel_interface_free(ifp->info);
706 ifp->info = NULL;
707 return 0;
708}
709
710/* Configuration write function for babeld. */
711static int
712interface_config_write (struct vty *vty)
713{
714 struct listnode *node;
715 struct interface *ifp;
Paul Jakma57345092011-12-25 17:52:09 +0100716 int write = 0;
717
718 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
Paul Jakma57345092011-12-25 17:52:09 +0100719 /* Do not display the interface if there is no configuration about it */
720 if (ifp->desc == NULL)
721 continue;
722
723 vty_out (vty, "interface %s%s", ifp->name,
724 VTY_NEWLINE);
725 if (ifp->desc)
726 vty_out (vty, " description %s%s", ifp->desc,
727 VTY_NEWLINE);
728
729 /* TODO: to be completed... */
730
731 vty_out (vty, "!%s", VTY_NEWLINE);
732
733 write++;
734 }
735 return write;
736}
737
738/* functions to allocate or free memory for a babel_interface_nfo, filling
739 needed fields */
740static babel_interface_nfo *
741babel_interface_allocate ()
742{
743 babel_interface_nfo *babel_ifp;
744 babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
745 if(babel_ifp == NULL)
746 return NULL;
747
748 /* Here are set the default values for an interface. */
749 memset(babel_ifp, 0, sizeof(babel_interface_nfo));
750 /* All flags are unset */
751 babel_ifp->activity_time = babel_now.tv_sec;
752 babel_ifp->bucket_time = babel_now.tv_sec;
753 babel_ifp->bucket = BUCKET_TOKENS_MAX;
754 babel_ifp->hello_seqno = (random() & 0xFFFF);
755 babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
756
757 return babel_ifp;
758}
759
760static void
761babel_interface_free (babel_interface_nfo *babel_ifp)
762{
763 XFREE(MTYPE_BABEL_IF, babel_ifp);
764}