]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* |
2 | * Interface related function for RIPng. | |
3 | * Copyright (C) 1998 Kunihiro Ishiguro | |
4 | * | |
5 | * This file is part of GNU Zebra. | |
6 | * | |
7 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License as published by the | |
9 | * Free Software Foundation; either version 2, or (at your option) any | |
10 | * later version. | |
11 | * | |
12 | * GNU Zebra is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with GNU Zebra; see the file COPYING. If not, write to the Free | |
19 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
20 | * 02111-1307, USA. | |
21 | */ | |
22 | ||
23 | #include <zebra.h> | |
24 | ||
25 | #include "linklist.h" | |
26 | #include "if.h" | |
27 | #include "prefix.h" | |
28 | #include "memory.h" | |
29 | #include "network.h" | |
30 | #include "filter.h" | |
31 | #include "log.h" | |
32 | #include "stream.h" | |
33 | #include "zclient.h" | |
34 | #include "command.h" | |
35 | #include "table.h" | |
36 | #include "thread.h" | |
37 | ||
38 | #include "ripngd/ripngd.h" | |
39 | #include "ripngd/ripng_debug.h" | |
40 | \f | |
41 | /* If RFC2133 definition is used. */ | |
42 | #ifndef IPV6_JOIN_GROUP | |
43 | #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP | |
44 | #endif | |
45 | #ifndef IPV6_LEAVE_GROUP | |
46 | #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP | |
47 | #endif | |
48 | ||
49 | /* Static utility function. */ | |
50 | static void ripng_enable_apply (struct interface *); | |
51 | static void ripng_passive_interface_apply (struct interface *); | |
a94434b6 | 52 | int ripng_enable_if_lookup (char *ifname); |
53 | int ripng_enable_network_lookup2 (struct connected *connected); | |
54 | void ripng_enable_apply_all (); | |
718e3744 | 55 | |
56 | /* Join to the all rip routers multicast group. */ | |
57 | int | |
58 | ripng_multicast_join (struct interface *ifp) | |
59 | { | |
60 | int ret; | |
61 | struct ipv6_mreq mreq; | |
62 | ||
a94434b6 | 63 | if (if_is_up (ifp) && if_is_multicast (ifp)) { |
64 | memset (&mreq, 0, sizeof (mreq)); | |
65 | inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); | |
66 | mreq.ipv6mr_interface = ifp->ifindex; | |
718e3744 | 67 | |
a94434b6 | 68 | ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, |
69 | (char *) &mreq, sizeof (mreq)); | |
ddf1c26c | 70 | |
71 | if (ret < 0 && errno == EADDRINUSE) | |
72 | { | |
73 | /* | |
74 | * Group is already joined. This occurs due to sloppy group | |
75 | * management, in particular declining to leave the group on | |
76 | * an interface that has just gone down. | |
77 | */ | |
78 | zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name); | |
79 | return 0; /* not an error */ | |
80 | } | |
81 | ||
a94434b6 | 82 | if (ret < 0) |
83 | zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno)); | |
718e3744 | 84 | |
a94434b6 | 85 | if (IS_RIPNG_DEBUG_EVENT) |
86 | zlog_info ("RIPng %s join to all-rip-routers multicast group", ifp->name); | |
718e3744 | 87 | |
a94434b6 | 88 | if (ret < 0) |
89 | return -1; | |
90 | } | |
91 | return 0; | |
718e3744 | 92 | } |
93 | ||
94 | /* Leave from the all rip routers multicast group. */ | |
95 | int | |
96 | ripng_multicast_leave (struct interface *ifp) | |
97 | { | |
98 | int ret; | |
99 | struct ipv6_mreq mreq; | |
100 | ||
a94434b6 | 101 | if (if_is_up (ifp) && if_is_multicast (ifp)) { |
102 | memset (&mreq, 0, sizeof (mreq)); | |
103 | inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); | |
104 | mreq.ipv6mr_interface = ifp->ifindex; | |
718e3744 | 105 | |
a94434b6 | 106 | ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, |
107 | (char *) &mreq, sizeof (mreq)); | |
108 | if (ret < 0) | |
109 | zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", strerror (errno)); | |
110 | ||
111 | if (IS_RIPNG_DEBUG_EVENT) | |
112 | zlog_info ("RIPng %s leave from all-rip-routers multicast group", | |
113 | ifp->name); | |
114 | ||
115 | if (ret < 0) | |
116 | return -1; | |
117 | } | |
118 | ||
119 | return 0; | |
120 | } | |
121 | ||
122 | /* How many link local IPv6 address could be used on the interface ? */ | |
123 | int | |
124 | ripng_if_ipv6_lladdress_check (struct interface *ifp) | |
125 | { | |
126 | struct listnode *nn; | |
127 | struct connected *connected; | |
128 | int count = 0; | |
129 | ||
130 | for (nn = listhead (ifp->connected); nn; nextnode (nn)) | |
131 | if ((connected = getdata (nn)) != NULL) { | |
132 | struct prefix *p; | |
133 | p = connected->address; | |
718e3744 | 134 | |
a94434b6 | 135 | if ((p->family == AF_INET6) && |
136 | IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6)) | |
137 | count++; | |
138 | } | |
718e3744 | 139 | |
a94434b6 | 140 | return count; |
718e3744 | 141 | } |
142 | ||
143 | /* Check max mtu size. */ | |
144 | int | |
145 | ripng_check_max_mtu () | |
146 | { | |
147 | listnode node; | |
148 | struct interface *ifp; | |
149 | int mtu; | |
150 | ||
151 | mtu = 0; | |
152 | for (node = listhead (iflist); node; nextnode (node)) | |
153 | { | |
154 | ifp = getdata (node); | |
155 | if (mtu < ifp->mtu) | |
156 | mtu = ifp->mtu; | |
157 | } | |
158 | return mtu; | |
159 | } | |
160 | ||
161 | int | |
162 | ripng_if_down (struct interface *ifp) | |
163 | { | |
164 | struct route_node *rp; | |
165 | struct ripng_info *rinfo; | |
166 | struct ripng_interface *ri; | |
167 | ||
a94434b6 | 168 | if (ripng) |
718e3744 | 169 | { |
170 | for (rp = route_top (ripng->table); rp; rp = route_next (rp)) | |
171 | if ((rinfo = rp->info) != NULL) | |
172 | { | |
173 | /* Routes got through this interface. */ | |
174 | if (rinfo->ifindex == ifp->ifindex | |
175 | && rinfo->type == ZEBRA_ROUTE_RIPNG | |
176 | && rinfo->sub_type == RIPNG_ROUTE_RTE) | |
177 | { | |
178 | ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p, | |
179 | &rinfo->nexthop, | |
180 | rinfo->ifindex); | |
181 | ||
a94434b6 | 182 | ripng_redistribute_delete (rinfo->type, rinfo->sub_type, |
183 | (struct prefix_ipv6 *)&rp->p, | |
184 | rinfo->ifindex); | |
718e3744 | 185 | } |
186 | else | |
187 | { | |
a94434b6 | 188 | /* All redistributed routes got through this interface, |
189 | * but the static and system ones are kept. */ | |
190 | if ((rinfo->ifindex == ifp->ifindex) && | |
191 | (rinfo->type != ZEBRA_ROUTE_STATIC) && | |
192 | (rinfo->type != ZEBRA_ROUTE_SYSTEM)) | |
718e3744 | 193 | ripng_redistribute_delete (rinfo->type, rinfo->sub_type, |
194 | (struct prefix_ipv6 *) &rp->p, | |
195 | rinfo->ifindex); | |
196 | } | |
197 | } | |
198 | } | |
199 | ||
200 | ri = ifp->info; | |
201 | ||
a94434b6 | 202 | if (ri->running) |
718e3744 | 203 | { |
204 | if (IS_RIPNG_DEBUG_EVENT) | |
205 | zlog_info ("turn off %s", ifp->name); | |
206 | ||
207 | /* Leave from multicast group. */ | |
208 | ripng_multicast_leave (ifp); | |
209 | ||
210 | ri->running = 0; | |
211 | } | |
212 | ||
213 | return 0; | |
214 | } | |
215 | ||
216 | /* Inteface link up message processing. */ | |
217 | int | |
218 | ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length) | |
219 | { | |
220 | struct stream *s; | |
221 | struct interface *ifp; | |
222 | ||
223 | /* zebra_interface_state_read() updates interface structure in iflist. */ | |
224 | s = zclient->ibuf; | |
225 | ifp = zebra_interface_state_read (s); | |
226 | ||
227 | if (ifp == NULL) | |
228 | return 0; | |
229 | ||
230 | if (IS_RIPNG_DEBUG_ZEBRA) | |
231 | zlog_info ("interface up %s index %d flags %ld metric %d mtu %d", | |
232 | ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); | |
233 | ||
234 | /* Check if this interface is RIPng enabled or not. */ | |
235 | ripng_enable_apply (ifp); | |
236 | ||
237 | /* Check for a passive interface. */ | |
238 | ripng_passive_interface_apply (ifp); | |
239 | ||
240 | /* Apply distribute list to the all interface. */ | |
241 | ripng_distribute_update_interface (ifp); | |
242 | ||
243 | return 0; | |
244 | } | |
245 | ||
246 | /* Inteface link down message processing. */ | |
247 | int | |
248 | ripng_interface_down (int command, struct zclient *zclient, | |
249 | zebra_size_t length) | |
250 | { | |
251 | struct stream *s; | |
252 | struct interface *ifp; | |
253 | ||
254 | /* zebra_interface_state_read() updates interface structure in iflist. */ | |
255 | s = zclient->ibuf; | |
256 | ifp = zebra_interface_state_read (s); | |
257 | ||
258 | if (ifp == NULL) | |
259 | return 0; | |
260 | ||
261 | ripng_if_down (ifp); | |
262 | ||
263 | if (IS_RIPNG_DEBUG_ZEBRA) | |
264 | zlog_info ("interface down %s index %d flags %ld metric %d mtu %d", | |
265 | ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); | |
266 | ||
267 | return 0; | |
268 | } | |
269 | ||
270 | /* Inteface addition message from zebra. */ | |
271 | int | |
272 | ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length) | |
273 | { | |
274 | struct interface *ifp; | |
275 | ||
276 | ifp = zebra_interface_add_read (zclient->ibuf); | |
277 | ||
278 | if (IS_RIPNG_DEBUG_ZEBRA) | |
279 | zlog_info ("RIPng interface add %s index %d flags %ld metric %d mtu %d", | |
280 | ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); | |
281 | ||
282 | /* Check is this interface is RIP enabled or not.*/ | |
283 | ripng_enable_apply (ifp); | |
284 | ||
285 | /* Apply distribute list to the interface. */ | |
286 | ripng_distribute_update_interface (ifp); | |
287 | ||
288 | /* Check interface routemap. */ | |
289 | ripng_if_rmap_update_interface (ifp); | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
294 | int | |
295 | ripng_interface_delete (int command, struct zclient *zclient, | |
296 | zebra_size_t length) | |
297 | { | |
a94434b6 | 298 | struct interface *ifp; |
299 | struct stream *s; | |
300 | ||
301 | s = zclient->ibuf; | |
302 | /* zebra_interface_state_read() updates interface structure in iflist */ | |
303 | ifp = zebra_interface_state_read(s); | |
304 | ||
305 | if (ifp == NULL) | |
306 | return 0; | |
307 | ||
308 | if (if_is_up (ifp)) { | |
309 | ripng_if_down(ifp); | |
310 | } | |
311 | ||
312 | zlog_info("interface delete %s index %d flags %ld metric %d mtu %d", | |
313 | ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); | |
314 | ||
315 | /* To support pseudo interface do not free interface structure. */ | |
316 | /* if_delete(ifp); */ | |
317 | ||
718e3744 | 318 | return 0; |
319 | } | |
320 | ||
a94434b6 | 321 | void |
322 | ripng_interface_clean () | |
323 | { | |
324 | listnode node; | |
325 | struct interface *ifp; | |
326 | struct ripng_interface *ri; | |
327 | ||
328 | for (node = listhead (iflist); node; nextnode (node)) | |
329 | { | |
330 | ifp = getdata (node); | |
331 | ri = ifp->info; | |
332 | ||
333 | ri->enable_network = 0; | |
334 | ri->enable_interface = 0; | |
335 | ri->running = 0; | |
336 | ||
337 | if (ri->t_wakeup) | |
338 | { | |
339 | thread_cancel (ri->t_wakeup); | |
340 | ri->t_wakeup = NULL; | |
341 | } | |
342 | } | |
343 | } | |
344 | ||
345 | void | |
346 | ripng_interface_reset () { | |
347 | listnode node; | |
348 | struct interface *ifp; | |
349 | struct ripng_interface *ri; | |
350 | ||
351 | for (node = listhead (iflist); node; nextnode (node)) | |
352 | { | |
353 | ifp = getdata (node); | |
354 | ri = ifp->info; | |
355 | ||
356 | ri->enable_network = 0; | |
357 | ri->enable_interface = 0; | |
358 | ri->running = 0; | |
359 | ||
360 | ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; | |
361 | ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON; | |
362 | ||
363 | ri->list[RIPNG_FILTER_IN] = NULL; | |
364 | ri->list[RIPNG_FILTER_OUT] = NULL; | |
365 | ||
366 | ri->prefix[RIPNG_FILTER_IN] = NULL; | |
367 | ri->prefix[RIPNG_FILTER_OUT] = NULL; | |
368 | ||
369 | if (ri->t_wakeup) | |
370 | { | |
371 | thread_cancel (ri->t_wakeup); | |
372 | ri->t_wakeup = NULL; | |
373 | } | |
374 | ||
375 | ri->passive = 0; | |
376 | } | |
377 | } | |
378 | ||
379 | static void | |
380 | ripng_apply_address_add (struct connected *ifc) { | |
381 | struct prefix_ipv6 address; | |
382 | struct prefix *p; | |
383 | ||
384 | if (!ripng) | |
385 | return; | |
386 | ||
387 | if (! if_is_up(ifc->ifp)) | |
388 | return; | |
389 | ||
390 | p = ifc->address; | |
391 | ||
392 | memset (&address, 0, sizeof (address)); | |
393 | address.family = p->family; | |
394 | address.prefix = p->u.prefix6; | |
395 | address.prefixlen = p->prefixlen; | |
396 | apply_mask_ipv6(&address); | |
397 | ||
398 | /* Check if this interface is RIP enabled or not | |
399 | or Check if this address's prefix is RIP enabled */ | |
400 | if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) || | |
401 | (ripng_enable_network_lookup2(ifc) >= 0)) | |
402 | ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, | |
403 | &address, ifc->ifp->ifindex, NULL); | |
404 | ||
405 | } | |
406 | ||
718e3744 | 407 | int |
408 | ripng_interface_address_add (int command, struct zclient *zclient, | |
409 | zebra_size_t length) | |
410 | { | |
411 | struct connected *c; | |
412 | struct prefix *p; | |
718e3744 | 413 | |
0a589359 | 414 | c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, |
415 | zclient->ibuf); | |
718e3744 | 416 | |
417 | if (c == NULL) | |
418 | return 0; | |
419 | ||
420 | p = c->address; | |
421 | ||
422 | if (p->family == AF_INET6) | |
423 | { | |
424 | if (IS_RIPNG_DEBUG_ZEBRA) | |
425 | zlog_info ("RIPng connected address %s/%d add", | |
a94434b6 | 426 | inet6_ntop(&p->u.prefix6), |
718e3744 | 427 | p->prefixlen); |
428 | ||
a94434b6 | 429 | /* Check is this prefix needs to be redistributed. */ |
430 | ripng_apply_address_add(c); | |
431 | ||
432 | /* Let's try once again whether the interface could be activated */ | |
433 | if (c->ifp) { | |
434 | struct ripng_interface *ri = c->ifp->info; | |
435 | ||
436 | if (!ri->running) { | |
437 | /* Check if this interface is RIP enabled or not.*/ | |
438 | ripng_enable_apply (c->ifp); | |
439 | ||
440 | /* Apply distribute list to the interface. */ | |
441 | ripng_distribute_update_interface (c->ifp); | |
442 | ||
443 | /* Check interface routemap. */ | |
444 | ripng_if_rmap_update_interface (c->ifp); | |
445 | } | |
446 | } | |
447 | ||
718e3744 | 448 | } |
449 | ||
450 | return 0; | |
451 | } | |
452 | ||
a94434b6 | 453 | static void |
454 | ripng_apply_address_del (struct connected *ifc) { | |
455 | struct prefix_ipv6 address; | |
456 | struct prefix *p; | |
457 | ||
458 | if (!ripng) | |
459 | return; | |
460 | ||
461 | if (! if_is_up(ifc->ifp)) | |
462 | return; | |
463 | ||
464 | p = ifc->address; | |
465 | ||
466 | memset (&address, 0, sizeof (address)); | |
467 | address.family = p->family; | |
468 | address.prefix = p->u.prefix6; | |
469 | address.prefixlen = p->prefixlen; | |
470 | apply_mask_ipv6(&address); | |
471 | ||
472 | ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, | |
473 | &address, ifc->ifp->ifindex); | |
474 | } | |
475 | ||
718e3744 | 476 | int |
477 | ripng_interface_address_delete (int command, struct zclient *zclient, | |
478 | zebra_size_t length) | |
479 | { | |
480 | struct connected *ifc; | |
481 | struct prefix *p; | |
482 | char buf[INET6_ADDRSTRLEN]; | |
483 | ||
0a589359 | 484 | ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, |
485 | zclient->ibuf); | |
718e3744 | 486 | |
487 | if (ifc) | |
488 | { | |
489 | p = ifc->address; | |
490 | ||
491 | if (p->family == AF_INET6) | |
492 | { | |
493 | if (IS_RIPNG_DEBUG_ZEBRA) | |
494 | zlog_info ("RIPng connected address %s/%d delete", | |
495 | inet_ntop (AF_INET6, &p->u.prefix6, buf, | |
496 | INET6_ADDRSTRLEN), | |
497 | p->prefixlen); | |
498 | ||
a94434b6 | 499 | /* Check wether this prefix needs to be removed. */ |
500 | ripng_apply_address_del(ifc); | |
718e3744 | 501 | } |
502 | connected_free (ifc); | |
503 | } | |
504 | ||
505 | return 0; | |
506 | } | |
507 | \f | |
508 | /* RIPng enable interface vector. */ | |
509 | vector ripng_enable_if; | |
510 | ||
511 | /* RIPng enable network table. */ | |
512 | struct route_table *ripng_enable_network; | |
513 | ||
514 | /* Lookup RIPng enable network. */ | |
a94434b6 | 515 | /* Check wether the interface has at least a connected prefix that |
516 | * is within the ripng_enable_network table. */ | |
718e3744 | 517 | int |
a94434b6 | 518 | ripng_enable_network_lookup_if (struct interface *ifp) |
718e3744 | 519 | { |
520 | listnode listnode; | |
521 | struct connected *connected; | |
a94434b6 | 522 | struct prefix_ipv6 address; |
718e3744 | 523 | |
524 | for (listnode = listhead (ifp->connected); listnode; nextnode (listnode)) | |
525 | if ((connected = getdata (listnode)) != NULL) | |
526 | { | |
527 | struct prefix *p; | |
528 | struct route_node *node; | |
529 | ||
530 | p = connected->address; | |
531 | ||
532 | if (p->family == AF_INET6) | |
533 | { | |
a94434b6 | 534 | address.family = AF_INET6; |
535 | address.prefix = p->u.prefix6; | |
536 | address.prefixlen = IPV6_MAX_BITLEN; | |
537 | ||
538 | node = route_node_match (ripng_enable_network, | |
539 | (struct prefix *)&address); | |
718e3744 | 540 | if (node) |
541 | { | |
542 | route_unlock_node (node); | |
543 | return 1; | |
544 | } | |
545 | } | |
546 | } | |
547 | return -1; | |
548 | } | |
549 | ||
a94434b6 | 550 | /* Check wether connected is within the ripng_enable_network table. */ |
551 | int | |
552 | ripng_enable_network_lookup2 (struct connected *connected) | |
553 | { | |
554 | struct prefix_ipv6 address; | |
555 | struct prefix *p; | |
556 | ||
557 | p = connected->address; | |
558 | ||
559 | if (p->family == AF_INET6) { | |
560 | struct route_node *node; | |
561 | ||
562 | address.family = p->family; | |
563 | address.prefix = p->u.prefix6; | |
564 | address.prefixlen = IPV6_MAX_BITLEN; | |
565 | ||
566 | /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */ | |
567 | node = route_node_match (ripng_enable_network, | |
568 | (struct prefix *)&address); | |
569 | ||
570 | if (node) { | |
571 | route_unlock_node (node); | |
572 | return 1; | |
573 | } | |
574 | } | |
575 | ||
576 | return -1; | |
577 | } | |
578 | ||
718e3744 | 579 | /* Add RIPng enable network. */ |
580 | int | |
581 | ripng_enable_network_add (struct prefix *p) | |
582 | { | |
583 | struct route_node *node; | |
584 | ||
585 | node = route_node_get (ripng_enable_network, p); | |
586 | ||
587 | if (node->info) | |
588 | { | |
589 | route_unlock_node (node); | |
590 | return -1; | |
591 | } | |
592 | else | |
593 | node->info = "enabled"; | |
594 | ||
a94434b6 | 595 | /* XXX: One should find a better solution than a generic one */ |
596 | ripng_enable_apply_all(); | |
597 | ||
718e3744 | 598 | return 1; |
599 | } | |
600 | ||
601 | /* Delete RIPng enable network. */ | |
602 | int | |
603 | ripng_enable_network_delete (struct prefix *p) | |
604 | { | |
605 | struct route_node *node; | |
606 | ||
607 | node = route_node_lookup (ripng_enable_network, p); | |
608 | if (node) | |
609 | { | |
610 | node->info = NULL; | |
611 | ||
612 | /* Unlock info lock. */ | |
613 | route_unlock_node (node); | |
614 | ||
615 | /* Unlock lookup lock. */ | |
616 | route_unlock_node (node); | |
617 | ||
618 | return 1; | |
619 | } | |
620 | return -1; | |
621 | } | |
622 | ||
623 | /* Lookup function. */ | |
624 | int | |
625 | ripng_enable_if_lookup (char *ifname) | |
626 | { | |
627 | int i; | |
628 | char *str; | |
629 | ||
630 | for (i = 0; i < vector_max (ripng_enable_if); i++) | |
631 | if ((str = vector_slot (ripng_enable_if, i)) != NULL) | |
632 | if (strcmp (str, ifname) == 0) | |
633 | return i; | |
634 | return -1; | |
635 | } | |
636 | ||
637 | /* Add interface to ripng_enable_if. */ | |
638 | int | |
639 | ripng_enable_if_add (char *ifname) | |
640 | { | |
641 | int ret; | |
642 | ||
643 | ret = ripng_enable_if_lookup (ifname); | |
644 | if (ret >= 0) | |
645 | return -1; | |
646 | ||
647 | vector_set (ripng_enable_if, strdup (ifname)); | |
648 | ||
a94434b6 | 649 | ripng_enable_apply_all(); |
650 | ||
718e3744 | 651 | return 1; |
652 | } | |
653 | ||
654 | /* Delete interface from ripng_enable_if. */ | |
655 | int | |
656 | ripng_enable_if_delete (char *ifname) | |
657 | { | |
658 | int index; | |
659 | char *str; | |
660 | ||
661 | index = ripng_enable_if_lookup (ifname); | |
662 | if (index < 0) | |
663 | return -1; | |
664 | ||
665 | str = vector_slot (ripng_enable_if, index); | |
666 | free (str); | |
667 | vector_unset (ripng_enable_if, index); | |
668 | ||
a94434b6 | 669 | ripng_enable_apply_all(); |
670 | ||
718e3744 | 671 | return 1; |
672 | } | |
673 | ||
674 | /* Wake up interface. */ | |
675 | int | |
676 | ripng_interface_wakeup (struct thread *t) | |
677 | { | |
678 | struct interface *ifp; | |
679 | struct ripng_interface *ri; | |
680 | ||
681 | /* Get interface. */ | |
682 | ifp = THREAD_ARG (t); | |
683 | ||
684 | ri = ifp->info; | |
685 | ri->t_wakeup = NULL; | |
686 | ||
687 | /* Join to multicast group. */ | |
a94434b6 | 688 | if (ripng_multicast_join (ifp) < 0) { |
689 | zlog_err ("multicast join failed, interface %s not running", ifp->name); | |
690 | return 0; | |
691 | } | |
692 | ||
693 | /* Set running flag. */ | |
694 | ri->running = 1; | |
718e3744 | 695 | |
696 | /* Send RIP request to the interface. */ | |
697 | ripng_request (ifp); | |
698 | ||
699 | return 0; | |
700 | } | |
701 | ||
a94434b6 | 702 | int ripng_redistribute_check (int); |
703 | ||
704 | void | |
705 | ripng_connect_set (struct interface *ifp, int set) | |
706 | { | |
707 | struct listnode *nn; | |
708 | struct connected *connected; | |
709 | struct prefix_ipv6 address; | |
710 | ||
711 | for (nn = listhead (ifp->connected); nn; nextnode (nn)) | |
712 | if ((connected = getdata (nn)) != NULL) { | |
713 | struct prefix *p; | |
714 | p = connected->address; | |
715 | ||
716 | if (p->family != AF_INET6) | |
717 | continue; | |
718 | ||
719 | address.family = AF_INET6; | |
720 | address.prefix = p->u.prefix6; | |
721 | address.prefixlen = p->prefixlen; | |
722 | apply_mask_ipv6 (&address); | |
723 | ||
724 | if (set) { | |
725 | /* Check once more wether this prefix is within a "network IF_OR_PREF" one */ | |
726 | if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) || | |
727 | (ripng_enable_network_lookup2(connected) >= 0)) | |
728 | ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, | |
729 | &address, connected->ifp->ifindex, NULL); | |
730 | } else { | |
731 | ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, | |
732 | &address, connected->ifp->ifindex); | |
733 | if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT)) | |
734 | ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE, | |
735 | &address, connected->ifp->ifindex, NULL); | |
736 | } | |
737 | } | |
738 | } | |
739 | ||
718e3744 | 740 | /* Check RIPng is enabed on this interface. */ |
741 | void | |
742 | ripng_enable_apply (struct interface *ifp) | |
743 | { | |
744 | int ret; | |
745 | struct ripng_interface *ri = NULL; | |
746 | ||
747 | /* Check interface. */ | |
718e3744 | 748 | if (! if_is_up (ifp)) |
749 | return; | |
750 | ||
751 | ri = ifp->info; | |
752 | ||
a94434b6 | 753 | /* Is this interface a candidate for RIPng ? */ |
754 | ret = ripng_enable_network_lookup_if (ifp); | |
718e3744 | 755 | |
756 | /* If the interface is matched. */ | |
757 | if (ret > 0) | |
758 | ri->enable_network = 1; | |
759 | else | |
760 | ri->enable_network = 0; | |
761 | ||
762 | /* Check interface name configuration. */ | |
763 | ret = ripng_enable_if_lookup (ifp->name); | |
764 | if (ret >= 0) | |
765 | ri->enable_interface = 1; | |
766 | else | |
767 | ri->enable_interface = 0; | |
768 | ||
a94434b6 | 769 | /* any candidate interface MUST have a link-local IPv6 address */ |
770 | if ((! ripng_if_ipv6_lladdress_check (ifp)) && | |
771 | (ri->enable_network || ri->enable_interface)) { | |
772 | ri->enable_network = 0; | |
773 | ri->enable_interface = 0; | |
774 | zlog_warn("Interface %s does not have any link-local address", | |
775 | ifp->name); | |
776 | } | |
777 | ||
718e3744 | 778 | /* Update running status of the interface. */ |
779 | if (ri->enable_network || ri->enable_interface) | |
780 | { | |
718e3744 | 781 | { |
782 | if (IS_RIPNG_DEBUG_EVENT) | |
783 | zlog_info ("RIPng turn on %s", ifp->name); | |
784 | ||
785 | /* Add interface wake up thread. */ | |
786 | if (! ri->t_wakeup) | |
787 | ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup, | |
788 | ifp, 1); | |
718e3744 | 789 | |
a94434b6 | 790 | ripng_connect_set (ifp, 1); |
718e3744 | 791 | } |
792 | } | |
793 | else | |
794 | { | |
795 | if (ri->running) | |
796 | { | |
a94434b6 | 797 | /* Might as well clean up the route table as well |
798 | * ripng_if_down sets to 0 ri->running, and displays "turn off %s" | |
799 | **/ | |
800 | ripng_if_down(ifp); | |
718e3744 | 801 | |
a94434b6 | 802 | ripng_connect_set (ifp, 0); |
718e3744 | 803 | } |
804 | } | |
805 | } | |
806 | ||
807 | /* Set distribute list to all interfaces. */ | |
a94434b6 | 808 | void |
718e3744 | 809 | ripng_enable_apply_all () |
810 | { | |
811 | struct interface *ifp; | |
812 | listnode node; | |
813 | ||
814 | for (node = listhead (iflist); node; nextnode (node)) | |
815 | { | |
816 | ifp = getdata (node); | |
817 | ripng_enable_apply (ifp); | |
818 | } | |
819 | } | |
820 | \f | |
a94434b6 | 821 | /* Clear all network and neighbor configuration */ |
822 | void | |
823 | ripng_clean_network () | |
824 | { | |
825 | int i; | |
826 | char *str; | |
827 | struct route_node *rn; | |
828 | ||
829 | /* ripng_enable_network */ | |
830 | for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn)) | |
831 | if (rn->info) { | |
832 | rn->info = NULL; | |
833 | route_unlock_node(rn); | |
834 | } | |
835 | ||
836 | /* ripng_enable_if */ | |
837 | for (i = 0; i < vector_max (ripng_enable_if); i++) | |
838 | if ((str = vector_slot (ripng_enable_if, i)) != NULL) { | |
839 | free (str); | |
840 | vector_slot (ripng_enable_if, i) = NULL; | |
841 | } | |
842 | } | |
843 | \f | |
718e3744 | 844 | /* Vector to store passive-interface name. */ |
845 | vector Vripng_passive_interface; | |
846 | ||
847 | /* Utility function for looking up passive interface settings. */ | |
848 | int | |
849 | ripng_passive_interface_lookup (char *ifname) | |
850 | { | |
851 | int i; | |
852 | char *str; | |
853 | ||
854 | for (i = 0; i < vector_max (Vripng_passive_interface); i++) | |
855 | if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) | |
856 | if (strcmp (str, ifname) == 0) | |
857 | return i; | |
858 | return -1; | |
859 | } | |
860 | ||
861 | void | |
862 | ripng_passive_interface_apply (struct interface *ifp) | |
863 | { | |
864 | int ret; | |
865 | struct ripng_interface *ri; | |
866 | ||
867 | ri = ifp->info; | |
868 | ||
869 | ret = ripng_passive_interface_lookup (ifp->name); | |
870 | if (ret < 0) | |
871 | ri->passive = 0; | |
872 | else | |
873 | ri->passive = 1; | |
874 | } | |
875 | ||
876 | void | |
877 | ripng_passive_interface_apply_all (void) | |
878 | { | |
879 | struct interface *ifp; | |
880 | listnode node; | |
881 | ||
882 | for (node = listhead (iflist); node; nextnode (node)) | |
883 | { | |
884 | ifp = getdata (node); | |
885 | ripng_passive_interface_apply (ifp); | |
886 | } | |
887 | } | |
888 | ||
889 | /* Passive interface. */ | |
890 | int | |
891 | ripng_passive_interface_set (struct vty *vty, char *ifname) | |
892 | { | |
893 | if (ripng_passive_interface_lookup (ifname) >= 0) | |
894 | return CMD_WARNING; | |
895 | ||
896 | vector_set (Vripng_passive_interface, strdup (ifname)); | |
897 | ||
898 | ripng_passive_interface_apply_all (); | |
899 | ||
900 | return CMD_SUCCESS; | |
901 | } | |
902 | ||
903 | int | |
904 | ripng_passive_interface_unset (struct vty *vty, char *ifname) | |
905 | { | |
906 | int i; | |
907 | char *str; | |
908 | ||
909 | i = ripng_passive_interface_lookup (ifname); | |
910 | if (i < 0) | |
911 | return CMD_WARNING; | |
912 | ||
913 | str = vector_slot (Vripng_passive_interface, i); | |
914 | free (str); | |
915 | vector_unset (Vripng_passive_interface, i); | |
916 | ||
917 | ripng_passive_interface_apply_all (); | |
918 | ||
919 | return CMD_SUCCESS; | |
920 | } | |
921 | ||
922 | /* Free all configured RIP passive-interface settings. */ | |
923 | void | |
924 | ripng_passive_interface_clean (void) | |
925 | { | |
926 | int i; | |
927 | char *str; | |
928 | ||
929 | for (i = 0; i < vector_max (Vripng_passive_interface); i++) | |
930 | if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) | |
931 | { | |
932 | free (str); | |
933 | vector_slot (Vripng_passive_interface, i) = NULL; | |
934 | } | |
935 | ripng_passive_interface_apply_all (); | |
936 | } | |
937 | ||
938 | /* Write RIPng enable network and interface to the vty. */ | |
939 | int | |
a94434b6 | 940 | ripng_network_write (struct vty *vty, int config_mode) |
718e3744 | 941 | { |
942 | int i; | |
718e3744 | 943 | char *ifname; |
944 | struct route_node *node; | |
945 | char buf[BUFSIZ]; | |
946 | ||
947 | /* Write enable network. */ | |
948 | for (node = route_top (ripng_enable_network); node; node = route_next (node)) | |
949 | if (node->info) | |
950 | { | |
951 | struct prefix *p = &node->p; | |
a94434b6 | 952 | vty_out (vty, "%s%s/%d%s", |
953 | config_mode ? " network " : " ", | |
718e3744 | 954 | inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), |
955 | p->prefixlen, | |
956 | VTY_NEWLINE); | |
957 | ||
958 | } | |
959 | ||
960 | /* Write enable interface. */ | |
961 | for (i = 0; i < vector_max (ripng_enable_if); i++) | |
a94434b6 | 962 | if ((ifname = vector_slot (ripng_enable_if, i)) != NULL) |
963 | vty_out (vty, "%s%s%s", | |
964 | config_mode ? " network " : " ", | |
965 | ifname, | |
718e3744 | 966 | VTY_NEWLINE); |
967 | ||
968 | /* Write passive interface. */ | |
a94434b6 | 969 | if (config_mode) |
970 | for (i = 0; i < vector_max (Vripng_passive_interface); i++) | |
971 | if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL) | |
972 | vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE); | |
718e3744 | 973 | |
974 | return 0; | |
975 | } | |
976 | ||
977 | /* RIPng enable on specified interface or matched network. */ | |
978 | DEFUN (ripng_network, | |
979 | ripng_network_cmd, | |
980 | "network IF_OR_ADDR", | |
981 | "RIPng enable on specified interface or network.\n" | |
982 | "Interface or address") | |
983 | { | |
984 | int ret; | |
985 | struct prefix p; | |
986 | ||
987 | ret = str2prefix (argv[0], &p); | |
988 | ||
989 | /* Given string is IPv6 network or interface name. */ | |
990 | if (ret) | |
991 | ret = ripng_enable_network_add (&p); | |
992 | else | |
993 | ret = ripng_enable_if_add (argv[0]); | |
994 | ||
995 | if (ret < 0) | |
996 | { | |
997 | vty_out (vty, "There is same network configuration %s%s", argv[0], | |
998 | VTY_NEWLINE); | |
999 | return CMD_WARNING; | |
1000 | } | |
1001 | ||
718e3744 | 1002 | return CMD_SUCCESS; |
1003 | } | |
1004 | ||
1005 | /* RIPng enable on specified interface or matched network. */ | |
1006 | DEFUN (no_ripng_network, | |
1007 | no_ripng_network_cmd, | |
1008 | "no network IF_OR_ADDR", | |
1009 | NO_STR | |
1010 | "RIPng enable on specified interface or network.\n" | |
1011 | "Interface or address") | |
1012 | { | |
1013 | int ret; | |
1014 | struct prefix p; | |
1015 | ||
1016 | ret = str2prefix (argv[0], &p); | |
1017 | ||
1018 | /* Given string is interface name. */ | |
1019 | if (ret) | |
1020 | ret = ripng_enable_network_delete (&p); | |
1021 | else | |
1022 | ret = ripng_enable_if_delete (argv[0]); | |
1023 | ||
1024 | if (ret < 0) | |
1025 | { | |
1026 | vty_out (vty, "can't find network %s%s", argv[0], | |
1027 | VTY_NEWLINE); | |
1028 | return CMD_WARNING; | |
1029 | } | |
1030 | ||
a94434b6 | 1031 | return CMD_SUCCESS; |
1032 | } | |
1033 | ||
1034 | DEFUN (ipv6_ripng_split_horizon, | |
1035 | ipv6_ripng_split_horizon_cmd, | |
1036 | "ipv6 ripng split-horizon", | |
1037 | IPV6_STR | |
1038 | "Routing Information Protocol\n" | |
1039 | "Perform split horizon\n") | |
1040 | { | |
1041 | struct interface *ifp; | |
1042 | struct ripng_interface *ri; | |
1043 | ||
1044 | ifp = vty->index; | |
1045 | ri = ifp->info; | |
1046 | ||
1047 | ri->split_horizon = RIPNG_SPLIT_HORIZON; | |
1048 | return CMD_SUCCESS; | |
1049 | } | |
1050 | ||
1051 | DEFUN (ipv6_ripng_split_horizon_poisoned_reverse, | |
1052 | ipv6_ripng_split_horizon_poisoned_reverse_cmd, | |
1053 | "ipv6 ripng split-horizon poisoned-reverse", | |
1054 | IPV6_STR | |
1055 | "Routing Information Protocol\n" | |
1056 | "Perform split horizon\n" | |
1057 | "With poisoned-reverse\n") | |
1058 | { | |
1059 | struct interface *ifp; | |
1060 | struct ripng_interface *ri; | |
1061 | ||
1062 | ifp = vty->index; | |
1063 | ri = ifp->info; | |
1064 | ||
1065 | ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE; | |
1066 | return CMD_SUCCESS; | |
1067 | } | |
718e3744 | 1068 | |
a94434b6 | 1069 | DEFUN (no_ipv6_ripng_split_horizon, |
1070 | no_ipv6_ripng_split_horizon_cmd, | |
1071 | "no ipv6 ripng split-horizon", | |
1072 | NO_STR | |
1073 | IPV6_STR | |
1074 | "Routing Information Protocol\n" | |
1075 | "Perform split horizon\n") | |
1076 | { | |
1077 | struct interface *ifp; | |
1078 | struct ripng_interface *ri; | |
1079 | ||
1080 | ifp = vty->index; | |
1081 | ri = ifp->info; | |
1082 | ||
1083 | ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; | |
718e3744 | 1084 | return CMD_SUCCESS; |
1085 | } | |
1086 | ||
a94434b6 | 1087 | ALIAS (no_ipv6_ripng_split_horizon, |
1088 | no_ipv6_ripng_split_horizon_poisoned_reverse_cmd, | |
1089 | "no ipv6 ripng split-horizon poisoned-reverse", | |
1090 | NO_STR | |
1091 | IPV6_STR | |
1092 | "Routing Information Protocol\n" | |
1093 | "Perform split horizon\n" | |
1094 | "With poisoned-reverse\n") | |
1095 | ||
718e3744 | 1096 | DEFUN (ripng_passive_interface, |
1097 | ripng_passive_interface_cmd, | |
1098 | "passive-interface IFNAME", | |
1099 | "Suppress routing updates on an interface\n" | |
1100 | "Interface name\n") | |
1101 | { | |
1102 | return ripng_passive_interface_set (vty, argv[0]); | |
1103 | } | |
1104 | ||
1105 | DEFUN (no_ripng_passive_interface, | |
1106 | no_ripng_passive_interface_cmd, | |
1107 | "no passive-interface IFNAME", | |
1108 | NO_STR | |
1109 | "Suppress routing updates on an interface\n" | |
1110 | "Interface name\n") | |
1111 | { | |
1112 | return ripng_passive_interface_unset (vty, argv[0]); | |
1113 | } | |
1114 | \f | |
1115 | struct ripng_interface * | |
1116 | ri_new () | |
1117 | { | |
1118 | struct ripng_interface *ri; | |
1119 | ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface)); | |
a94434b6 | 1120 | |
1121 | /* Set default split-horizon behavior. If the interface is Frame | |
1122 | Relay or SMDS is enabled, the default value for split-horizon is | |
1123 | off. But currently Zebra does detect Frame Relay or SMDS | |
1124 | interface. So all interface is set to split horizon. */ | |
1125 | ri->split_horizon_default = RIPNG_SPLIT_HORIZON; | |
1126 | ri->split_horizon = ri->split_horizon_default; | |
1127 | ||
718e3744 | 1128 | return ri; |
1129 | } | |
1130 | ||
1131 | int | |
1132 | ripng_if_new_hook (struct interface *ifp) | |
1133 | { | |
1134 | ifp->info = ri_new (); | |
1135 | return 0; | |
1136 | } | |
1137 | ||
a94434b6 | 1138 | /* Called when interface structure deleted. */ |
1139 | int | |
1140 | ripng_if_delete_hook (struct interface *ifp) | |
1141 | { | |
1142 | XFREE (MTYPE_IF, ifp->info); | |
1143 | ifp->info = NULL; | |
1144 | return 0; | |
1145 | } | |
1146 | ||
718e3744 | 1147 | /* Configuration write function for ripngd. */ |
1148 | int | |
1149 | interface_config_write (struct vty *vty) | |
1150 | { | |
1151 | listnode node; | |
1152 | struct interface *ifp; | |
1153 | struct ripng_interface *ri; | |
1154 | int write = 0; | |
1155 | ||
1156 | for (node = listhead (iflist); node; nextnode (node)) | |
1157 | { | |
1158 | ifp = getdata (node); | |
1159 | ri = ifp->info; | |
1160 | ||
a94434b6 | 1161 | /* Do not display the interface if there is no |
1162 | * configuration about it. | |
1163 | **/ | |
1164 | if ((!ifp->desc) && | |
1165 | (ri->split_horizon == ri->split_horizon_default)) | |
1166 | continue; | |
1167 | ||
718e3744 | 1168 | vty_out (vty, "interface %s%s", ifp->name, |
1169 | VTY_NEWLINE); | |
1170 | if (ifp->desc) | |
1171 | vty_out (vty, " description %s%s", ifp->desc, | |
1172 | VTY_NEWLINE); | |
1173 | ||
a94434b6 | 1174 | /* Split horizon. */ |
1175 | if (ri->split_horizon != ri->split_horizon_default) | |
1176 | { | |
1177 | switch (ri->split_horizon) { | |
1178 | case RIPNG_SPLIT_HORIZON: | |
1179 | vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE); | |
1180 | break; | |
1181 | case RIPNG_SPLIT_HORIZON_POISONED_REVERSE: | |
1182 | vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s", | |
1183 | VTY_NEWLINE); | |
1184 | break; | |
1185 | case RIPNG_NO_SPLIT_HORIZON: | |
1186 | default: | |
1187 | vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE); | |
1188 | break; | |
1189 | } | |
1190 | } | |
1191 | ||
718e3744 | 1192 | vty_out (vty, "!%s", VTY_NEWLINE); |
1193 | ||
1194 | write++; | |
1195 | } | |
1196 | return write; | |
1197 | } | |
1198 | ||
1199 | /* ripngd's interface node. */ | |
1200 | struct cmd_node interface_node = | |
1201 | { | |
1202 | INTERFACE_NODE, | |
1203 | "%s(config-if)# ", | |
a94434b6 | 1204 | 1 /* VTYSH */ |
718e3744 | 1205 | }; |
1206 | ||
1207 | /* Initialization of interface. */ | |
1208 | void | |
1209 | ripng_if_init () | |
1210 | { | |
1211 | /* Interface initialize. */ | |
1212 | iflist = list_new (); | |
1213 | if_add_hook (IF_NEW_HOOK, ripng_if_new_hook); | |
a94434b6 | 1214 | if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook); |
718e3744 | 1215 | |
1216 | /* RIPng enable network init. */ | |
1217 | ripng_enable_network = route_table_init (); | |
1218 | ||
1219 | /* RIPng enable interface init. */ | |
1220 | ripng_enable_if = vector_init (1); | |
1221 | ||
1222 | /* RIPng passive interface. */ | |
1223 | Vripng_passive_interface = vector_init (1); | |
1224 | ||
1225 | /* Install interface node. */ | |
1226 | install_node (&interface_node, interface_config_write); | |
a94434b6 | 1227 | |
1228 | /* Install commands. */ | |
718e3744 | 1229 | install_element (CONFIG_NODE, &interface_cmd); |
32d2463c | 1230 | install_element (CONFIG_NODE, &no_interface_cmd); |
a94434b6 | 1231 | install_default (INTERFACE_NODE); |
718e3744 | 1232 | install_element (INTERFACE_NODE, &interface_desc_cmd); |
1233 | install_element (INTERFACE_NODE, &no_interface_desc_cmd); | |
1234 | ||
1235 | install_element (RIPNG_NODE, &ripng_network_cmd); | |
1236 | install_element (RIPNG_NODE, &no_ripng_network_cmd); | |
1237 | install_element (RIPNG_NODE, &ripng_passive_interface_cmd); | |
1238 | install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd); | |
a94434b6 | 1239 | |
1240 | install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); | |
1241 | install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd); | |
1242 | install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd); | |
1243 | install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd); | |
718e3744 | 1244 | } |