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