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