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