]>
Commit | Line | Data |
---|---|---|
5734509c PJ |
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 | ||
5734509c PJ |
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 | ||
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 | ||
56 | static int babel_enable_if_lookup (const char *ifname); | |
57 | static int babel_enable_if_add (const char *ifname); | |
58 | static int babel_enable_if_delete (const char *ifname); | |
59 | static int interface_recalculate(struct interface *ifp); | |
60 | static int interface_reset(struct interface *ifp); | |
61 | static int babel_if_new_hook (struct interface *ifp); | |
62 | static int babel_if_delete_hook (struct interface *ifp); | |
63 | static int interface_config_write (struct vty *vty); | |
c7c53fa8 | 64 | static babel_interface_nfo * babel_interface_allocate (void); |
5734509c PJ |
65 | static void babel_interface_free (babel_interface_nfo *bi); |
66 | ||
67 | ||
68 | static vector babel_enable_if; /* enable interfaces (by cmd). */ | |
69 | static struct cmd_node babel_interface_node = /* babeld's interface node. */ | |
70 | { | |
71 | INTERFACE_NODE, | |
72 | "%s(config-if)# ", | |
73 | 1 /* VTYSH */ | |
74 | }; | |
75 | ||
76 | ||
77 | int | |
78 | babel_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 | ||
96 | int | |
97 | babel_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 | ||
115 | int | |
116 | babel_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 | ||
134 | int | |
135 | babel_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 | ||
141 | int | |
142 | babel_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 | ||
178 | int | |
179 | babel_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. */ | |
213 | static int | |
214 | babel_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. */ | |
227 | static int | |
228 | babel_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. */ | |
247 | static int | |
248 | babel_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. */ | |
271 | DEFUN (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. */ | |
298 | DEFUN (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. */ | |
326 | DEFUN (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). */ | |
344 | DEFUN (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. */ | |
363 | DEFUN (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). */ | |
382 | DEFUN (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]. */ | |
402 | DEFUN (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]. */ | |
422 | DEFUN (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]. */ | |
436 | DEFUN (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 | ||
448 | int | |
449 | interface_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. */ | |
457 | unsigned | |
458 | jitter(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 | ||
468 | unsigned | |
469 | update_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) */ | |
481 | static int | |
482 | interface_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) { | |
4eedea55 | 506 | zlog_err("Couldn't reallocate sendbuf."); |
5734509c PJ |
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. */ | |
573 | static int | |
574 | interface_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. */ | |
614 | void | |
615 | babel_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 */ | |
645 | int | |
646 | is_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 | ||
d4e46e68 DO |
663 | static void |
664 | show_babel_interface_sub (struct vty *vty, struct interface *ifp) | |
665 | { | |
666 | int is_up; | |
667 | babel_interface_nfo *babel_ifp; | |
668 | ||
669 | vty_out (vty, "%s is %s%s", ifp->name, | |
670 | ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE); | |
671 | vty_out (vty, " ifindex %u, MTU %u bytes %s%s", | |
672 | ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE); | |
673 | ||
674 | if (babel_enable_if_lookup (ifp->name) < 0) | |
675 | { | |
676 | vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE); | |
677 | return; | |
678 | } | |
679 | if (!is_up) | |
680 | { | |
681 | vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE); | |
682 | return; | |
683 | } | |
684 | babel_ifp = babel_get_if_nfo (ifp); | |
685 | vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE); | |
686 | vty_out (vty, " Operating mode is \"%s\"%s", | |
687 | CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE); | |
688 | vty_out (vty, " Split horizon mode is %s%s", | |
689 | CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE); | |
690 | vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE); | |
691 | } | |
692 | ||
693 | DEFUN (show_babel_interface, | |
694 | show_babel_interface_cmd, | |
695 | "show babel interface [INTERFACE]", | |
696 | SHOW_STR | |
697 | IP_STR | |
698 | "Babel information\n" | |
699 | "Interface information\n" | |
700 | "Interface name\n") | |
701 | { | |
702 | struct interface *ifp; | |
703 | struct listnode *node; | |
704 | ||
705 | if (argc == 0) | |
706 | { | |
707 | for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) | |
708 | show_babel_interface_sub (vty, ifp); | |
709 | return CMD_SUCCESS; | |
710 | } | |
711 | if ((ifp = if_lookup_by_name (argv[0])) == NULL) | |
712 | { | |
713 | vty_out (vty, "No such interface name%s", VTY_NEWLINE); | |
714 | return CMD_WARNING; | |
715 | } | |
716 | show_babel_interface_sub (vty, ifp); | |
717 | return CMD_SUCCESS; | |
718 | } | |
5734509c PJ |
719 | |
720 | void | |
721 | babel_if_init () | |
722 | { | |
723 | /* initialize interface list */ | |
724 | if_init(); | |
725 | if_add_hook (IF_NEW_HOOK, babel_if_new_hook); | |
726 | if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook); | |
727 | ||
728 | babel_enable_if = vector_init (1); | |
729 | ||
730 | /* install interface node and commands */ | |
731 | install_element (CONFIG_NODE, &interface_cmd); | |
732 | install_element (CONFIG_NODE, &no_interface_cmd); | |
733 | install_node (&babel_interface_node, interface_config_write); | |
734 | install_default(INTERFACE_NODE); | |
735 | install_element(INTERFACE_NODE, &interface_cmd); | |
736 | install_element(INTERFACE_NODE, &no_interface_cmd); | |
737 | ||
738 | install_element(BABEL_NODE, &babel_network_cmd); | |
739 | install_element(BABEL_NODE, &no_babel_network_cmd); | |
740 | install_element(INTERFACE_NODE, &babel_split_horizon_cmd); | |
741 | install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd); | |
742 | install_element(INTERFACE_NODE, &babel_set_wired_cmd); | |
743 | install_element(INTERFACE_NODE, &babel_set_wireless_cmd); | |
744 | install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd); | |
745 | install_element(INTERFACE_NODE, &babel_passive_interface_cmd); | |
746 | install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd); | |
d4e46e68 DO |
747 | |
748 | /* "show babel ..." commands */ | |
749 | install_element (VIEW_NODE, &show_babel_interface_cmd); | |
750 | install_element (ENABLE_NODE, &show_babel_interface_cmd); | |
5734509c PJ |
751 | } |
752 | ||
753 | /* hooks: functions called respectively when struct interface is | |
754 | created or deleted. */ | |
755 | static int | |
756 | babel_if_new_hook (struct interface *ifp) | |
757 | { | |
758 | ifp->info = babel_interface_allocate(); | |
759 | return 0; | |
760 | } | |
761 | ||
762 | static int | |
763 | babel_if_delete_hook (struct interface *ifp) | |
764 | { | |
765 | babel_interface_free(ifp->info); | |
766 | ifp->info = NULL; | |
767 | return 0; | |
768 | } | |
769 | ||
770 | /* Configuration write function for babeld. */ | |
771 | static int | |
772 | interface_config_write (struct vty *vty) | |
773 | { | |
774 | struct listnode *node; | |
775 | struct interface *ifp; | |
5734509c PJ |
776 | int write = 0; |
777 | ||
778 | for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { | |
5734509c PJ |
779 | /* Do not display the interface if there is no configuration about it */ |
780 | if (ifp->desc == NULL) | |
781 | continue; | |
782 | ||
783 | vty_out (vty, "interface %s%s", ifp->name, | |
784 | VTY_NEWLINE); | |
785 | if (ifp->desc) | |
786 | vty_out (vty, " description %s%s", ifp->desc, | |
787 | VTY_NEWLINE); | |
788 | ||
789 | /* TODO: to be completed... */ | |
790 | ||
791 | vty_out (vty, "!%s", VTY_NEWLINE); | |
792 | ||
793 | write++; | |
794 | } | |
795 | return write; | |
796 | } | |
797 | ||
798 | /* functions to allocate or free memory for a babel_interface_nfo, filling | |
799 | needed fields */ | |
800 | static babel_interface_nfo * | |
c7c53fa8 | 801 | babel_interface_allocate (void) |
5734509c PJ |
802 | { |
803 | babel_interface_nfo *babel_ifp; | |
804 | babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); | |
805 | if(babel_ifp == NULL) | |
806 | return NULL; | |
807 | ||
808 | /* Here are set the default values for an interface. */ | |
809 | memset(babel_ifp, 0, sizeof(babel_interface_nfo)); | |
810 | /* All flags are unset */ | |
811 | babel_ifp->activity_time = babel_now.tv_sec; | |
812 | babel_ifp->bucket_time = babel_now.tv_sec; | |
813 | babel_ifp->bucket = BUCKET_TOKENS_MAX; | |
814 | babel_ifp->hello_seqno = (random() & 0xFFFF); | |
815 | babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL; | |
816 | ||
817 | return babel_ifp; | |
818 | } | |
819 | ||
820 | static void | |
821 | babel_interface_free (babel_interface_nfo *babel_ifp) | |
822 | { | |
823 | XFREE(MTYPE_BABEL_IF, babel_ifp); | |
824 | } |