]> git.proxmox.com Git - mirror_frr.git/blame - ripd/rip_interface.c
ripd: add VRF support
[mirror_frr.git] / ripd / rip_interface.c
CommitLineData
718e3744 1/* Interface related function for RIP.
2 * Copyright (C) 1997, 98 Kunihiro Ishiguro <kunihiro@zebra.org>
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
896014f4
DL
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
718e3744 19 */
20
21#include <zebra.h>
22
23#include "command.h"
24#include "if.h"
25#include "sockunion.h"
26#include "prefix.h"
27#include "memory.h"
28#include "network.h"
29#include "table.h"
30#include "log.h"
31#include "stream.h"
32#include "thread.h"
33#include "zclient.h"
34#include "filter.h"
35#include "sockopt.h"
edd7c245 36#include "privs.h"
77cbe4a1 37#include "lib_errors.h"
f0ab22fb 38#include "northbound_cli.h"
718e3744 39
40#include "zebra/connected.h"
41
42#include "ripd/ripd.h"
43#include "ripd/rip_debug.h"
dc63bfd4 44#include "ripd/rip_interface.h"
6b0655a2 45
d62a17ae 46DEFINE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc))
47DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc))
3012671f 48
dc63bfd4 49/* static prototypes */
d62a17ae 50static void rip_enable_apply(struct interface *);
51static void rip_passive_interface_apply(struct interface *);
dc63bfd4 52static int rip_if_down(struct interface *ifp);
045c5389 53static int rip_enable_if_lookup(struct rip *rip, const char *ifname);
d62a17ae 54static int rip_enable_network_lookup2(struct connected *connected);
045c5389 55static void rip_enable_apply_all(struct rip *rip);
6b0655a2 56
d62a17ae 57const struct message ri_version_msg[] = {{RI_RIP_VERSION_1, "1"},
58 {RI_RIP_VERSION_2, "2"},
59 {RI_RIP_VERSION_1_AND_2, "1 2"},
60 {RI_RIP_VERSION_NONE, "none"},
61 {0}};
718e3744 62
718e3744 63/* Join to the RIP version 2 multicast group. */
d62a17ae 64static int ipv4_multicast_join(int sock, struct in_addr group,
65 struct in_addr ifa, ifindex_t ifindex)
718e3744 66{
d62a17ae 67 int ret;
718e3744 68
d62a17ae 69 ret = setsockopt_ipv4_multicast(sock, IP_ADD_MEMBERSHIP, ifa,
70 group.s_addr, ifindex);
718e3744 71
d62a17ae 72 if (ret < 0)
73 zlog_info("can't setsockopt IP_ADD_MEMBERSHIP %s",
74 safe_strerror(errno));
718e3744 75
d62a17ae 76 return ret;
718e3744 77}
78
79/* Leave from the RIP version 2 multicast group. */
d62a17ae 80static int ipv4_multicast_leave(int sock, struct in_addr group,
81 struct in_addr ifa, ifindex_t ifindex)
718e3744 82{
d62a17ae 83 int ret;
718e3744 84
d62a17ae 85 ret = setsockopt_ipv4_multicast(sock, IP_DROP_MEMBERSHIP, ifa,
86 group.s_addr, ifindex);
718e3744 87
d62a17ae 88 if (ret < 0)
89 zlog_info("can't setsockopt IP_DROP_MEMBERSHIP");
718e3744 90
d62a17ae 91 return ret;
718e3744 92}
6b0655a2 93
d62a17ae 94static void rip_interface_reset(struct rip_interface *);
1dec2166 95
718e3744 96/* Allocate new RIP's interface configuration. */
ae7b826a 97static struct rip_interface *rip_interface_new(void)
718e3744 98{
d62a17ae 99 struct rip_interface *ri;
718e3744 100
d62a17ae 101 ri = XCALLOC(MTYPE_RIP_INTERFACE, sizeof(struct rip_interface));
718e3744 102
d62a17ae 103 rip_interface_reset(ri);
718e3744 104
d62a17ae 105 return ri;
718e3744 106}
107
d62a17ae 108void rip_interface_multicast_set(int sock, struct connected *connected)
718e3744 109{
d62a17ae 110 struct in_addr addr;
4a3867d0 111
d62a17ae 112 assert(connected != NULL);
4a3867d0 113
d62a17ae 114 addr = CONNECTED_ID(connected)->u.prefix4;
115
116 if (setsockopt_ipv4_multicast_if(sock, addr, connected->ifp->ifindex)
117 < 0) {
118 zlog_warn(
119 "Can't setsockopt IP_MULTICAST_IF on fd %d to "
120 "ifindex %d for interface %s",
121 sock, connected->ifp->ifindex, connected->ifp->name);
122 }
4a3867d0 123
d62a17ae 124 return;
3fb9cd6e 125}
718e3744 126
127/* Send RIP request packet to specified interface. */
d7c0a89a 128static void rip_request_interface_send(struct interface *ifp, uint8_t version)
718e3744 129{
d62a17ae 130 struct sockaddr_in to;
718e3744 131
d62a17ae 132 /* RIPv2 support multicast. */
133 if (version == RIPv2 && if_is_multicast(ifp)) {
718e3744 134
d62a17ae 135 if (IS_RIP_DEBUG_EVENT)
136 zlog_debug("multicast request on %s", ifp->name);
718e3744 137
d62a17ae 138 rip_request_send(NULL, ifp, version, NULL);
139 return;
140 }
718e3744 141
d62a17ae 142 /* RIPv1 and non multicast interface. */
143 if (if_is_pointopoint(ifp) || if_is_broadcast(ifp)) {
144 struct listnode *cnode, *cnnode;
145 struct connected *connected;
146
147 if (IS_RIP_DEBUG_EVENT)
148 zlog_debug("broadcast request to %s", ifp->name);
149
150 for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode,
151 connected)) {
2e37ad7f
RW
152 if (connected->address->family != AF_INET)
153 continue;
154
155 memset(&to, 0, sizeof(struct sockaddr_in));
156 to.sin_port = htons(RIP_PORT_DEFAULT);
157 if (connected->destination)
158 /* use specified broadcast or peer
159 * destination addr */
160 to.sin_addr = connected->destination->u.prefix4;
161 else if (connected->address->prefixlen
162 < IPV4_MAX_PREFIXLEN)
163 /* calculate the appropriate broadcast
164 * address */
165 to.sin_addr.s_addr = ipv4_broadcast_addr(
166 connected->address->u.prefix4.s_addr,
167 connected->address->prefixlen);
168 else
169 /* do not know where to send the packet
170 */
171 continue;
172
173 if (IS_RIP_DEBUG_EVENT)
174 zlog_debug("SEND request to %s",
175 inet_ntoa(to.sin_addr));
176
177 rip_request_send(&to, ifp, version, connected);
d62a17ae 178 }
718e3744 179 }
718e3744 180}
181
182/* This will be executed when interface goes up. */
d62a17ae 183static void rip_request_interface(struct interface *ifp)
718e3744 184{
d62a17ae 185 struct rip_interface *ri;
2e37ad7f 186 int vsend;
718e3744 187
d62a17ae 188 /* In default ripd doesn't send RIP_REQUEST to the loopback interface.
189 */
190 if (if_is_loopback(ifp))
191 return;
718e3744 192
d62a17ae 193 /* If interface is down, don't send RIP packet. */
194 if (!if_is_operative(ifp))
195 return;
718e3744 196
d62a17ae 197 /* Fetch RIP interface information. */
198 ri = ifp->info;
718e3744 199
d62a17ae 200 /* If there is no version configuration in the interface,
201 use rip's version setting. */
045c5389 202 vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? ri->rip->version_send
2e37ad7f
RW
203 : ri->ri_send);
204 if (vsend & RIPv1)
205 rip_request_interface_send(ifp, RIPv1);
206 if (vsend & RIPv2)
207 rip_request_interface_send(ifp, RIPv2);
718e3744 208}
209
2c239705 210#if 0
718e3744 211/* Send RIP request to the neighbor. */
dc63bfd4 212static void
718e3744 213rip_request_neighbor (struct in_addr addr)
214{
215 struct sockaddr_in to;
216
217 memset (&to, 0, sizeof (struct sockaddr_in));
218 to.sin_port = htons (RIP_PORT_DEFAULT);
219 to.sin_addr = addr;
220
931cd54d 221 rip_request_send (&to, NULL, rip->version_send, NULL);
718e3744 222}
223
224/* Request routes at all interfaces. */
dc63bfd4 225static void
226rip_request_neighbor_all (void)
718e3744 227{
228 struct route_node *rp;
229
230 if (! rip)
231 return;
232
233 if (IS_RIP_DEBUG_EVENT)
5d6c3779 234 zlog_debug ("request to the all neighbor");
718e3744 235
236 /* Send request to all neighbor. */
237 for (rp = route_top (rip->neighbor); rp; rp = route_next (rp))
238 if (rp->info)
239 rip_request_neighbor (rp->p.u.prefix4);
240}
2c239705 241#endif
718e3744 242
243/* Multicast packet receive socket. */
d62a17ae 244static int rip_multicast_join(struct interface *ifp, int sock)
718e3744 245{
d62a17ae 246 struct listnode *cnode;
247 struct connected *ifc;
718e3744 248
d62a17ae 249 if (if_is_operative(ifp) && if_is_multicast(ifp)) {
250 if (IS_RIP_DEBUG_EVENT)
251 zlog_debug("multicast join at %s", ifp->name);
718e3744 252
d62a17ae 253 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) {
254 struct prefix_ipv4 *p;
255 struct in_addr group;
256
257 p = (struct prefix_ipv4 *)ifc->address;
258
259 if (p->family != AF_INET)
260 continue;
261
262 group.s_addr = htonl(INADDR_RIP_GROUP);
263 if (ipv4_multicast_join(sock, group, p->prefix,
264 ifp->ifindex)
265 < 0)
266 return -1;
267 else
268 return 0;
269 }
718e3744 270 }
d62a17ae 271 return 0;
718e3744 272}
273
274/* Leave from multicast group. */
d62a17ae 275static void rip_multicast_leave(struct interface *ifp, int sock)
718e3744 276{
d62a17ae 277 struct listnode *cnode;
278 struct connected *connected;
718e3744 279
d62a17ae 280 if (if_is_up(ifp) && if_is_multicast(ifp)) {
281 if (IS_RIP_DEBUG_EVENT)
282 zlog_debug("multicast leave from %s", ifp->name);
718e3744 283
d62a17ae 284 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) {
285 struct prefix_ipv4 *p;
286 struct in_addr group;
287
288 p = (struct prefix_ipv4 *)connected->address;
289
290 if (p->family != AF_INET)
291 continue;
292
293 group.s_addr = htonl(INADDR_RIP_GROUP);
294 if (ipv4_multicast_leave(sock, group, p->prefix,
295 ifp->ifindex)
296 == 0)
297 return;
298 }
299 }
718e3744 300}
301
302/* Is there and address on interface that I could use ? */
d62a17ae 303static int rip_if_ipv4_address_check(struct interface *ifp)
718e3744 304{
d62a17ae 305 struct listnode *nn;
306 struct connected *connected;
307 int count = 0;
718e3744 308
d62a17ae 309 for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) {
310 struct prefix *p;
718e3744 311
d62a17ae 312 p = connected->address;
313
314 if (p->family == AF_INET)
315 count++;
316 }
718e3744 317
d62a17ae 318 return count;
718e3744 319}
d62a17ae 320
31a476c7 321
322/* Does this address belongs to me ? */
045c5389 323int if_check_address(struct rip *rip, struct in_addr addr)
d62a17ae 324{
d62a17ae 325 struct interface *ifp;
31a476c7 326
ae7b826a 327 FOR_ALL_INTERFACES (rip->vrf, ifp) {
d62a17ae 328 struct listnode *cnode;
329 struct connected *connected;
31a476c7 330
d62a17ae 331 for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, connected)) {
332 struct prefix_ipv4 *p;
31a476c7 333
d62a17ae 334 p = (struct prefix_ipv4 *)connected->address;
335
336 if (p->family != AF_INET)
337 continue;
338
339 if (IPV4_ADDR_CMP(&p->prefix, &addr) == 0)
340 return 1;
341 }
31a476c7 342 }
d62a17ae 343 return 0;
31a476c7 344}
345
718e3744 346/* Inteface link down message processing. */
d62a17ae 347int rip_interface_down(int command, struct zclient *zclient,
348 zebra_size_t length, vrf_id_t vrf_id)
718e3744 349{
d62a17ae 350 struct interface *ifp;
351 struct stream *s;
718e3744 352
d62a17ae 353 s = zclient->ibuf;
718e3744 354
d62a17ae 355 /* zebra_interface_state_read() updates interface structure in
356 iflist. */
357 ifp = zebra_interface_state_read(s, vrf_id);
718e3744 358
d62a17ae 359 if (ifp == NULL)
360 return 0;
718e3744 361
ae7b826a 362 rip_interface_sync(ifp);
d62a17ae 363 rip_if_down(ifp);
718e3744 364
d62a17ae 365 if (IS_RIP_DEBUG_ZEBRA)
366 zlog_debug(
ae7b826a
RW
367 "interface %s vrf %u index %d flags %llx metric %d mtu %d is down",
368 ifp->name, ifp->vrf_id, ifp->ifindex,
369 (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
d62a17ae 370
371 return 0;
718e3744 372}
373
374/* Inteface link up message processing */
d62a17ae 375int rip_interface_up(int command, struct zclient *zclient, zebra_size_t length,
376 vrf_id_t vrf_id)
718e3744 377{
d62a17ae 378 struct interface *ifp;
379
380 /* zebra_interface_state_read () updates interface structure in
381 iflist. */
382 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
718e3744 383
d62a17ae 384 if (ifp == NULL)
385 return 0;
718e3744 386
d62a17ae 387 if (IS_RIP_DEBUG_ZEBRA)
388 zlog_debug(
ae7b826a
RW
389 "interface %s vrf %u index %d flags %#llx metric %d mtu %d is up",
390 ifp->name, ifp->vrf_id, ifp->ifindex,
391 (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
392
393 rip_interface_sync(ifp);
718e3744 394
d62a17ae 395 /* Check if this interface is RIP enabled or not.*/
396 rip_enable_apply(ifp);
718e3744 397
d62a17ae 398 /* Check for a passive interface */
399 rip_passive_interface_apply(ifp);
718e3744 400
d62a17ae 401 /* Apply distribute list to the all interface. */
402 rip_distribute_update_interface(ifp);
718e3744 403
d62a17ae 404 return 0;
718e3744 405}
406
407/* Inteface addition message from zebra. */
d62a17ae 408int rip_interface_add(int command, struct zclient *zclient, zebra_size_t length,
409 vrf_id_t vrf_id)
718e3744 410{
d62a17ae 411 struct interface *ifp;
718e3744 412
d62a17ae 413 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
ae7b826a 414 rip_interface_sync(ifp);
718e3744 415
d62a17ae 416 if (IS_RIP_DEBUG_ZEBRA)
417 zlog_debug(
ae7b826a
RW
418 "interface add %s vrf %u index %d flags %#llx metric %d mtu %d",
419 ifp->name, ifp->vrf_id, ifp->ifindex,
420 (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
718e3744 421
d62a17ae 422 /* Check if this interface is RIP enabled or not.*/
423 rip_enable_apply(ifp);
718e3744 424
d62a17ae 425 /* Check for a passive interface */
426 rip_passive_interface_apply(ifp);
718e3744 427
d62a17ae 428 /* Apply distribute list to the all interface. */
429 rip_distribute_update_interface(ifp);
718e3744 430
d62a17ae 431 /* rip_request_neighbor_all (); */
16705130 432
d62a17ae 433 /* Check interface routemap. */
434 rip_if_rmap_update_interface(ifp);
435
436 return 0;
718e3744 437}
438
d62a17ae 439int rip_interface_delete(int command, struct zclient *zclient,
440 zebra_size_t length, vrf_id_t vrf_id)
718e3744 441{
d62a17ae 442 struct interface *ifp;
443 struct stream *s;
444
718e3744 445
d62a17ae 446 s = zclient->ibuf;
447 /* zebra_interface_state_read() updates interface structure in iflist */
448 ifp = zebra_interface_state_read(s, vrf_id);
718e3744 449
d62a17ae 450 if (ifp == NULL)
451 return 0;
452
ae7b826a 453 rip_interface_sync(ifp);
d62a17ae 454 if (if_is_up(ifp)) {
455 rip_if_down(ifp);
456 }
718e3744 457
ae7b826a
RW
458 zlog_info(
459 "interface delete %s vrf %u index %d flags %#llx metric %d mtu %d",
460 ifp->name, ifp->vrf_id, ifp->ifindex,
461 (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
718e3744 462
d62a17ae 463 /* To support pseudo interface do not free interface structure. */
464 /* if_delete(ifp); */
ff880b78 465 if_set_index(ifp, IFINDEX_INTERNAL);
718e3744 466
d62a17ae 467 return 0;
718e3744 468}
469
ae7b826a
RW
470/* VRF update for an interface. */
471int rip_interface_vrf_update(int command, struct zclient *zclient,
472 zebra_size_t length, vrf_id_t vrf_id)
473{
474 struct interface *ifp;
475 vrf_id_t new_vrf_id;
476
477 ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
478 &new_vrf_id);
479 if (!ifp)
480 return 0;
481
482 if (IS_RIP_DEBUG_ZEBRA)
483 zlog_debug("interface %s VRF change vrf_id %u new vrf id %u",
484 ifp->name, vrf_id, new_vrf_id);
485
486 if_update_to_new_vrf(ifp, new_vrf_id);
487 rip_interface_sync(ifp);
488
489 return 0;
490}
491
d62a17ae 492static void rip_interface_clean(struct rip_interface *ri)
4305dfd1 493{
d62a17ae 494 ri->enable_network = 0;
495 ri->enable_interface = 0;
496 ri->running = 0;
718e3744 497
d62a17ae 498 if (ri->t_wakeup) {
499 thread_cancel(ri->t_wakeup);
500 ri->t_wakeup = NULL;
501 }
4305dfd1 502}
718e3744 503
045c5389 504void rip_interfaces_clean(struct rip *rip)
718e3744 505{
d62a17ae 506 struct interface *ifp;
718e3744 507
ae7b826a 508 FOR_ALL_INTERFACES (rip->vrf, ifp)
d62a17ae 509 rip_interface_clean(ifp->info);
1dec2166 510}
718e3744 511
d62a17ae 512static void rip_interface_reset(struct rip_interface *ri)
4305dfd1 513{
94b117b2
RW
514 ri->auth_type = yang_get_default_enum("%s/authentication-scheme/mode",
515 RIP_IFACE);
516 ri->md5_auth_len = yang_get_default_enum(
517 "%s/authentication-scheme/md5-auth-length", RIP_IFACE);
718e3744 518
d62a17ae 519 /* Set default split-horizon behavior. If the interface is Frame
520 Relay or SMDS is enabled, the default value for split-horizon is
521 off. But currently Zebra does detect Frame Relay or SMDS
522 interface. So all interface is set to split horizon. */
94b117b2
RW
523 ri->split_horizon =
524 yang_get_default_enum("%s/split-horizon", RIP_IFACE);
718e3744 525
94b117b2
RW
526 ri->ri_send = yang_get_default_enum("%s/version-send", RIP_IFACE);
527 ri->ri_receive = yang_get_default_enum("%s/version-receive", RIP_IFACE);
528 ri->v2_broadcast = yang_get_default_bool("%s/v2-broadcast", RIP_IFACE);
f90310cf 529
03c20031
DS
530 if (ri->auth_str)
531 XFREE(MTYPE_RIP_INTERFACE_STRING, ri->auth_str);
532
533 if (ri->key_chain)
534 XFREE(MTYPE_RIP_INTERFACE_STRING, ri->key_chain);
535
d62a17ae 536 ri->list[RIP_FILTER_IN] = NULL;
537 ri->list[RIP_FILTER_OUT] = NULL;
718e3744 538
d62a17ae 539 ri->prefix[RIP_FILTER_IN] = NULL;
540 ri->prefix[RIP_FILTER_OUT] = NULL;
718e3744 541
d62a17ae 542 ri->recv_badpackets = 0;
543 ri->recv_badroutes = 0;
544 ri->sent_updates = 0;
4305dfd1 545
d62a17ae 546 ri->passive = 0;
718e3744 547
d62a17ae 548 rip_interface_clean(ri);
4305dfd1 549}
718e3744 550
d62a17ae 551int rip_if_down(struct interface *ifp)
718e3744 552{
045c5389 553 struct rip *rip;
d62a17ae 554 struct route_node *rp;
555 struct rip_info *rinfo;
556 struct rip_interface *ri = NULL;
557 struct list *list = NULL;
558 struct listnode *listnode = NULL, *nextnode = NULL;
045c5389
RW
559
560 ri = ifp->info;
561 rip = ri->rip;
d62a17ae 562 if (rip) {
563 for (rp = route_top(rip->table); rp; rp = route_next(rp))
564 if ((list = rp->info) != NULL)
565 for (ALL_LIST_ELEMENTS(list, listnode, nextnode,
566 rinfo))
dd127197 567 if (rinfo->nh.ifindex == ifp->ifindex)
045c5389 568 rip_ecmp_delete(rip, rinfo);
d62a17ae 569
570 if (ri->running) {
571 if (IS_RIP_DEBUG_EVENT)
572 zlog_debug("turn off %s", ifp->name);
573
574 /* Leave from multicast group. */
575 rip_multicast_leave(ifp, rip->sock);
576
577 ri->running = 0;
578 }
579 }
580
581 return 0;
718e3744 582}
583
d62a17ae 584static void rip_apply_address_add(struct connected *ifc)
dc63bfd4 585{
045c5389
RW
586 struct rip_interface *ri = ifc->ifp->info;
587 struct rip *rip = ri->rip;
d62a17ae 588 struct prefix_ipv4 address;
3f5682c8 589 struct nexthop nh;
d62a17ae 590 struct prefix *p;
16705130 591
d62a17ae 592 if (!rip)
593 return;
16705130 594
d62a17ae 595 if (!if_is_up(ifc->ifp))
596 return;
16705130 597
d62a17ae 598 p = ifc->address;
16705130 599
d62a17ae 600 memset(&address, 0, sizeof(address));
3f5682c8
DS
601 memset(&nh, 0, sizeof(nh));
602
d62a17ae 603 address.family = p->family;
604 address.prefix = p->u.prefix4;
605 address.prefixlen = p->prefixlen;
606 apply_mask_ipv4(&address);
16705130 607
3f5682c8
DS
608 nh.ifindex = ifc->ifp->ifindex;
609 nh.type = NEXTHOP_TYPE_IFINDEX;
610
d62a17ae 611 /* Check if this interface is RIP enabled or not
612 or Check if this address's prefix is RIP enabled */
045c5389 613 if ((rip_enable_if_lookup(rip, ifc->ifp->name) >= 0)
d62a17ae 614 || (rip_enable_network_lookup2(ifc) >= 0))
045c5389
RW
615 rip_redistribute_add(rip, ZEBRA_ROUTE_CONNECT,
616 RIP_ROUTE_INTERFACE, &address, &nh, 0, 0,
617 0);
16705130 618}
619
d62a17ae 620int rip_interface_address_add(int command, struct zclient *zclient,
621 zebra_size_t length, vrf_id_t vrf_id)
718e3744 622{
d62a17ae 623 struct connected *ifc;
624 struct prefix *p;
718e3744 625
d62a17ae 626 ifc = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
627 zclient->ibuf, vrf_id);
718e3744 628
d62a17ae 629 if (ifc == NULL)
630 return 0;
718e3744 631
d62a17ae 632 p = ifc->address;
718e3744 633
d62a17ae 634 if (p->family == AF_INET) {
635 if (IS_RIP_DEBUG_ZEBRA)
636 zlog_debug("connected address %s/%d is added",
637 inet_ntoa(p->u.prefix4), p->prefixlen);
16705130 638
d62a17ae 639 rip_enable_apply(ifc->ifp);
640 /* Check if this prefix needs to be redistributed */
641 rip_apply_address_add(ifc);
718e3744 642
d62a17ae 643 hook_call(rip_ifaddr_add, ifc);
644 }
718e3744 645
d62a17ae 646 return 0;
718e3744 647}
648
d62a17ae 649static void rip_apply_address_del(struct connected *ifc)
650{
045c5389
RW
651 struct rip_interface *ri = ifc->ifp->info;
652 struct rip *rip = ri->rip;
d62a17ae 653 struct prefix_ipv4 address;
654 struct prefix *p;
16705130 655
d62a17ae 656 if (!rip)
657 return;
16705130 658
d62a17ae 659 if (!if_is_up(ifc->ifp))
660 return;
16705130 661
d62a17ae 662 p = ifc->address;
16705130 663
d62a17ae 664 memset(&address, 0, sizeof(address));
665 address.family = p->family;
666 address.prefix = p->u.prefix4;
667 address.prefixlen = p->prefixlen;
668 apply_mask_ipv4(&address);
16705130 669
045c5389 670 rip_redistribute_delete(rip, ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
d62a17ae 671 &address, ifc->ifp->ifindex);
16705130 672}
673
d62a17ae 674int rip_interface_address_delete(int command, struct zclient *zclient,
675 zebra_size_t length, vrf_id_t vrf_id)
718e3744 676{
d62a17ae 677 struct connected *ifc;
678 struct prefix *p;
718e3744 679
d62a17ae 680 ifc = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
681 zclient->ibuf, vrf_id);
718e3744 682
d62a17ae 683 if (ifc) {
684 p = ifc->address;
685 if (p->family == AF_INET) {
686 if (IS_RIP_DEBUG_ZEBRA)
687 zlog_debug("connected address %s/%d is deleted",
688 inet_ntoa(p->u.prefix4),
689 p->prefixlen);
16705130 690
d62a17ae 691 hook_call(rip_ifaddr_del, ifc);
718e3744 692
d62a17ae 693 /* Chech wether this prefix needs to be removed */
694 rip_apply_address_del(ifc);
695 }
718e3744 696
d62a17ae 697 connected_free(ifc);
698 }
718e3744 699
d62a17ae 700 return 0;
718e3744 701}
6b0655a2 702
718e3744 703/* Check interface is enabled by network statement. */
16705130 704/* Check wether the interface has at least a connected prefix that
705 * is within the ripng_enable_network table. */
d62a17ae 706static int rip_enable_network_lookup_if(struct interface *ifp)
707{
045c5389
RW
708 struct rip_interface *ri = ifp->info;
709 struct rip *rip = ri->rip;
d62a17ae 710 struct listnode *node, *nnode;
711 struct connected *connected;
712 struct prefix_ipv4 address;
713
1205fdc4
RW
714 if (!rip)
715 return -1;
716
d62a17ae 717 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) {
718 struct prefix *p;
dc7204b7 719 struct route_node *n;
d62a17ae 720
721 p = connected->address;
722
723 if (p->family == AF_INET) {
724 address.family = AF_INET;
725 address.prefix = p->u.prefix4;
726 address.prefixlen = IPV4_MAX_BITLEN;
727
1205fdc4 728 n = route_node_match(rip->enable_network,
dc7204b7
A
729 (struct prefix *)&address);
730 if (n) {
731 route_unlock_node(n);
d62a17ae 732 return 1;
733 }
734 }
735 }
736 return -1;
718e3744 737}
738
16705130 739/* Check wether connected is within the ripng_enable_network table. */
045c5389 740static int rip_enable_network_lookup2(struct connected *connected)
16705130 741{
045c5389
RW
742 struct rip_interface *ri = connected->ifp->info;
743 struct rip *rip = ri->rip;
d62a17ae 744 struct prefix_ipv4 address;
745 struct prefix *p;
16705130 746
d62a17ae 747 p = connected->address;
16705130 748
d62a17ae 749 if (p->family == AF_INET) {
750 struct route_node *node;
16705130 751
d62a17ae 752 address.family = p->family;
753 address.prefix = p->u.prefix4;
754 address.prefixlen = IPV4_MAX_BITLEN;
16705130 755
d62a17ae 756 /* LPM on p->family, p->u.prefix4/IPV4_MAX_BITLEN within
1205fdc4
RW
757 * rip->enable_network */
758 node = route_node_match(rip->enable_network,
d62a17ae 759 (struct prefix *)&address);
16705130 760
d62a17ae 761 if (node) {
762 route_unlock_node(node);
763 return 1;
764 }
765 }
16705130 766
d62a17ae 767 return -1;
16705130 768}
718e3744 769/* Add RIP enable network. */
045c5389 770int rip_enable_network_add(struct rip *rip, struct prefix *p)
718e3744 771{
d62a17ae 772 struct route_node *node;
718e3744 773
1205fdc4 774 node = route_node_get(rip->enable_network, p);
718e3744 775
d62a17ae 776 if (node->info) {
777 route_unlock_node(node);
3d7a1be8 778 return NB_ERR_INCONSISTENCY;
d62a17ae 779 } else
780 node->info = (void *)1;
718e3744 781
d62a17ae 782 /* XXX: One should find a better solution than a generic one */
045c5389 783 rip_enable_apply_all(rip);
16705130 784
3d7a1be8 785 return NB_OK;
718e3744 786}
787
788/* Delete RIP enable network. */
045c5389 789int rip_enable_network_delete(struct rip *rip, struct prefix *p)
718e3744 790{
d62a17ae 791 struct route_node *node;
718e3744 792
1205fdc4 793 node = route_node_lookup(rip->enable_network, p);
d62a17ae 794 if (node) {
795 node->info = NULL;
718e3744 796
d62a17ae 797 /* Unlock info lock. */
798 route_unlock_node(node);
718e3744 799
d62a17ae 800 /* Unlock lookup lock. */
801 route_unlock_node(node);
718e3744 802
d62a17ae 803 /* XXX: One should find a better solution than a generic one */
045c5389 804 rip_enable_apply_all(rip);
16705130 805
3d7a1be8 806 return NB_OK;
d62a17ae 807 }
3d7a1be8
RW
808
809 return NB_ERR_INCONSISTENCY;
718e3744 810}
811
812/* Check interface is enabled by ifname statement. */
045c5389 813static int rip_enable_if_lookup(struct rip *rip, const char *ifname)
718e3744 814{
d62a17ae 815 unsigned int i;
816 char *str;
718e3744 817
ca046902
RW
818 if (!rip)
819 return -1;
820
821 for (i = 0; i < vector_active(rip->enable_interface); i++)
822 if ((str = vector_slot(rip->enable_interface, i)) != NULL)
d62a17ae 823 if (strcmp(str, ifname) == 0)
824 return i;
825 return -1;
718e3744 826}
827
828/* Add interface to rip_enable_if. */
045c5389 829int rip_enable_if_add(struct rip *rip, const char *ifname)
718e3744 830{
d62a17ae 831 int ret;
718e3744 832
045c5389 833 ret = rip_enable_if_lookup(rip, ifname);
d62a17ae 834 if (ret >= 0)
3d7a1be8 835 return NB_ERR_INCONSISTENCY;
718e3744 836
ca046902 837 vector_set(rip->enable_interface,
03c20031 838 XSTRDUP(MTYPE_RIP_INTERFACE_STRING, ifname));
718e3744 839
045c5389 840 rip_enable_apply_all(rip); /* TODOVJ */
16705130 841
3d7a1be8 842 return NB_OK;
718e3744 843}
844
845/* Delete interface from rip_enable_if. */
045c5389 846int rip_enable_if_delete(struct rip *rip, const char *ifname)
718e3744 847{
d62a17ae 848 int index;
849 char *str;
718e3744 850
045c5389 851 index = rip_enable_if_lookup(rip, ifname);
d62a17ae 852 if (index < 0)
3d7a1be8 853 return NB_ERR_INCONSISTENCY;
718e3744 854
ca046902 855 str = vector_slot(rip->enable_interface, index);
03c20031 856 XFREE(MTYPE_RIP_INTERFACE_STRING, str);
ca046902 857 vector_unset(rip->enable_interface, index);
718e3744 858
045c5389 859 rip_enable_apply_all(rip); /* TODOVJ */
16705130 860
3d7a1be8 861 return NB_OK;
718e3744 862}
863
864/* Join to multicast group and send request to the interface. */
d62a17ae 865static int rip_interface_wakeup(struct thread *t)
718e3744 866{
d62a17ae 867 struct interface *ifp;
868 struct rip_interface *ri;
718e3744 869
d62a17ae 870 /* Get interface. */
871 ifp = THREAD_ARG(t);
718e3744 872
d62a17ae 873 ri = ifp->info;
874 ri->t_wakeup = NULL;
718e3744 875
d62a17ae 876 /* Join to multicast group. */
045c5389 877 if (rip_multicast_join(ifp, ri->rip->sock) < 0) {
450971aa 878 flog_err_sys(EC_LIB_SOCKET,
09c866e3
QY
879 "multicast join failed, interface %s not running",
880 ifp->name);
d62a17ae 881 return 0;
882 }
718e3744 883
d62a17ae 884 /* Set running flag. */
885 ri->running = 1;
886
887 /* Send RIP request to the interface. */
888 rip_request_interface(ifp);
889
890 return 0;
891}
892
893static void rip_connect_set(struct interface *ifp, int set)
894{
045c5389
RW
895 struct rip_interface *ri = ifp->info;
896 struct rip *rip = ri->rip;
d62a17ae 897 struct listnode *node, *nnode;
898 struct connected *connected;
899 struct prefix_ipv4 address;
3f5682c8
DS
900 struct nexthop nh;
901
902 memset(&nh, 0, sizeof(nh));
d62a17ae 903
904 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) {
905 struct prefix *p;
906 p = connected->address;
907
908 if (p->family != AF_INET)
909 continue;
910
911 address.family = AF_INET;
912 address.prefix = p->u.prefix4;
913 address.prefixlen = p->prefixlen;
914 apply_mask_ipv4(&address);
915
3f5682c8
DS
916 nh.ifindex = connected->ifp->ifindex;
917 nh.type = NEXTHOP_TYPE_IFINDEX;
d62a17ae 918 if (set) {
919 /* Check once more wether this prefix is within a
920 * "network IF_OR_PREF" one */
045c5389
RW
921 if ((rip_enable_if_lookup(rip, connected->ifp->name)
922 >= 0)
d62a17ae 923 || (rip_enable_network_lookup2(connected) >= 0))
045c5389 924 rip_redistribute_add(rip, ZEBRA_ROUTE_CONNECT,
996c9314
LB
925 RIP_ROUTE_INTERFACE,
926 &address, &nh, 0, 0, 0);
d62a17ae 927 } else {
045c5389 928 rip_redistribute_delete(rip, ZEBRA_ROUTE_CONNECT,
d62a17ae 929 RIP_ROUTE_INTERFACE, &address,
930 connected->ifp->ifindex);
045c5389
RW
931 if (rip_redistribute_check(rip, ZEBRA_ROUTE_CONNECT))
932 rip_redistribute_add(rip, ZEBRA_ROUTE_CONNECT,
996c9314
LB
933 RIP_ROUTE_REDISTRIBUTE,
934 &address, &nh, 0, 0, 0);
d62a17ae 935 }
936 }
718e3744 937}
938
939/* Update interface status. */
d62a17ae 940void rip_enable_apply(struct interface *ifp)
718e3744 941{
d62a17ae 942 int ret;
943 struct rip_interface *ri = NULL;
718e3744 944
d62a17ae 945 /* Check interface. */
946 if (!if_is_operative(ifp))
947 return;
718e3744 948
d62a17ae 949 ri = ifp->info;
950
951 /* Check network configuration. */
952 ret = rip_enable_network_lookup_if(ifp);
953
954 /* If the interface is matched. */
955 if (ret > 0)
956 ri->enable_network = 1;
957 else
958 ri->enable_network = 0;
959
960 /* Check interface name configuration. */
045c5389 961 ret = rip_enable_if_lookup(ri->rip, ifp->name);
d62a17ae 962 if (ret >= 0)
963 ri->enable_interface = 1;
964 else
965 ri->enable_interface = 0;
718e3744 966
d62a17ae 967 /* any interface MUST have an IPv4 address */
968 if (!rip_if_ipv4_address_check(ifp)) {
969 ri->enable_network = 0;
970 ri->enable_interface = 0;
718e3744 971 }
718e3744 972
d62a17ae 973 /* Update running status of the interface. */
974 if (ri->enable_network || ri->enable_interface) {
2e37ad7f
RW
975 if (IS_RIP_DEBUG_EVENT)
976 zlog_debug("turn on %s", ifp->name);
977
978 /* Add interface wake up thread. */
979 thread_add_timer(master, rip_interface_wakeup, ifp, 1,
980 &ri->t_wakeup);
981 rip_connect_set(ifp, 1);
982 } else if (ri->running) {
983 /* Might as well clean up the route table as well
984 * rip_if_down sets to 0 ri->running, and displays "turn
985 *off %s"
986 **/
987 rip_if_down(ifp);
d62a17ae 988
2e37ad7f 989 rip_connect_set(ifp, 0);
718e3744 990 }
718e3744 991}
992
993/* Apply network configuration to all interface. */
045c5389 994static void rip_enable_apply_all(struct rip *rip)
718e3744 995{
d62a17ae 996 struct interface *ifp;
718e3744 997
d62a17ae 998 /* Check each interface. */
ae7b826a 999 FOR_ALL_INTERFACES (rip->vrf, ifp)
d62a17ae 1000 rip_enable_apply(ifp);
718e3744 1001}
1002
045c5389 1003int rip_neighbor_lookup(struct rip *rip, struct sockaddr_in *from)
718e3744 1004{
d62a17ae 1005 struct prefix_ipv4 p;
1006 struct route_node *node;
718e3744 1007
d62a17ae 1008 memset(&p, 0, sizeof(struct prefix_ipv4));
1009 p.family = AF_INET;
1010 p.prefix = from->sin_addr;
1011 p.prefixlen = IPV4_MAX_BITLEN;
718e3744 1012
d62a17ae 1013 node = route_node_lookup(rip->neighbor, (struct prefix *)&p);
1014 if (node) {
1015 route_unlock_node(node);
1016 return 1;
1017 }
1018 return 0;
718e3744 1019}
1020
1021/* Add new RIP neighbor to the neighbor tree. */
045c5389 1022int rip_neighbor_add(struct rip *rip, struct prefix_ipv4 *p)
718e3744 1023{
d62a17ae 1024 struct route_node *node;
718e3744 1025
d62a17ae 1026 node = route_node_get(rip->neighbor, (struct prefix *)p);
718e3744 1027
d62a17ae 1028 if (node->info)
f0ab22fb 1029 return NB_ERR_INCONSISTENCY;
718e3744 1030
d62a17ae 1031 node->info = rip->neighbor;
718e3744 1032
f0ab22fb 1033 return NB_OK;
718e3744 1034}
1035
1036/* Delete RIP neighbor from the neighbor tree. */
045c5389 1037int rip_neighbor_delete(struct rip *rip, struct prefix_ipv4 *p)
718e3744 1038{
d62a17ae 1039 struct route_node *node;
718e3744 1040
d62a17ae 1041 /* Lock for look up. */
1042 node = route_node_lookup(rip->neighbor, (struct prefix *)p);
1043 if (!node)
f0ab22fb 1044 return NB_ERR_INCONSISTENCY;
718e3744 1045
d62a17ae 1046 node->info = NULL;
718e3744 1047
d62a17ae 1048 /* Unlock lookup lock. */
1049 route_unlock_node(node);
718e3744 1050
d62a17ae 1051 /* Unlock real neighbor information lock. */
1052 route_unlock_node(node);
1053
f0ab22fb 1054 return NB_OK;
718e3744 1055}
1056
1057/* Clear all network and neighbor configuration. */
045c5389 1058void rip_clean_network(struct rip *rip)
d62a17ae 1059{
1060 unsigned int i;
1061 char *str;
1062 struct route_node *rn;
1063
1205fdc4
RW
1064 /* rip->enable_network. */
1065 for (rn = route_top(rip->enable_network); rn; rn = route_next(rn))
d62a17ae 1066 if (rn->info) {
1067 rn->info = NULL;
1068 route_unlock_node(rn);
1069 }
1070
ca046902
RW
1071 /* rip->enable_interface. */
1072 for (i = 0; i < vector_active(rip->enable_interface); i++)
1073 if ((str = vector_slot(rip->enable_interface, i)) != NULL) {
03c20031 1074 XFREE(MTYPE_RIP_INTERFACE_STRING, str);
ca046902 1075 vector_slot(rip->enable_interface, i) = NULL;
d62a17ae 1076 }
718e3744 1077}
6b0655a2 1078
718e3744 1079/* Utility function for looking up passive interface settings. */
045c5389 1080static int rip_passive_nondefault_lookup(struct rip *rip, const char *ifname)
718e3744 1081{
d62a17ae 1082 unsigned int i;
1083 char *str;
718e3744 1084
5a29c0d5
RW
1085 for (i = 0; i < vector_active(rip->passive_nondefault); i++)
1086 if ((str = vector_slot(rip->passive_nondefault, i)) != NULL)
d62a17ae 1087 if (strcmp(str, ifname) == 0)
1088 return i;
1089 return -1;
718e3744 1090}
1091
045c5389 1092static void rip_passive_interface_apply(struct interface *ifp)
718e3744 1093{
045c5389 1094 struct rip *rip;
d62a17ae 1095 struct rip_interface *ri;
718e3744 1096
045c5389
RW
1097 ri = ifp->info;
1098 rip = ri->rip;
44f2f852
RW
1099 if (rip == NULL)
1100 return;
1101
045c5389 1102 ri->passive = ((rip_passive_nondefault_lookup(rip, ifp->name) < 0)
44f2f852
RW
1103 ? rip->passive_default
1104 : !rip->passive_default);
4aaff3f8 1105
d62a17ae 1106 if (IS_RIP_DEBUG_ZEBRA)
1107 zlog_debug("interface %s: passive = %d", ifp->name,
1108 ri->passive);
718e3744 1109}
1110
045c5389 1111static void rip_passive_interface_apply_all(struct rip *rip)
718e3744 1112{
d62a17ae 1113 struct interface *ifp;
718e3744 1114
ae7b826a 1115 FOR_ALL_INTERFACES (rip->vrf, ifp)
d62a17ae 1116 rip_passive_interface_apply(ifp);
718e3744 1117}
1118
1119/* Passive interface. */
045c5389 1120int rip_passive_nondefault_set(struct rip *rip, const char *ifname)
718e3744 1121{
045c5389 1122 if (rip_passive_nondefault_lookup(rip, ifname) >= 0)
44f2f852
RW
1123 /*
1124 * Don't return an error, this can happen after changing
1125 * 'passive-default'.
1126 */
1127 return NB_OK;
718e3744 1128
5a29c0d5 1129 vector_set(rip->passive_nondefault,
03c20031 1130 XSTRDUP(MTYPE_RIP_INTERFACE_STRING, ifname));
718e3744 1131
045c5389 1132 rip_passive_interface_apply_all(rip);
718e3744 1133
44f2f852 1134 return NB_OK;
718e3744 1135}
1136
045c5389 1137int rip_passive_nondefault_unset(struct rip *rip, const char *ifname)
718e3744 1138{
d62a17ae 1139 int i;
1140 char *str;
718e3744 1141
045c5389 1142 i = rip_passive_nondefault_lookup(rip, ifname);
d62a17ae 1143 if (i < 0)
44f2f852
RW
1144 /*
1145 * Don't return an error, this can happen after changing
1146 * 'passive-default'.
1147 */
1148 return NB_OK;
718e3744 1149
5a29c0d5 1150 str = vector_slot(rip->passive_nondefault, i);
03c20031 1151 XFREE(MTYPE_RIP_INTERFACE_STRING, str);
5a29c0d5 1152 vector_unset(rip->passive_nondefault, i);
718e3744 1153
045c5389 1154 rip_passive_interface_apply_all(rip);
718e3744 1155
44f2f852 1156 return NB_OK;
718e3744 1157}
1158
1159/* Free all configured RIP passive-interface settings. */
045c5389 1160void rip_passive_nondefault_clean(struct rip *rip)
718e3744 1161{
d62a17ae 1162 unsigned int i;
1163 char *str;
718e3744 1164
5a29c0d5
RW
1165 for (i = 0; i < vector_active(rip->passive_nondefault); i++)
1166 if ((str = vector_slot(rip->passive_nondefault, i)) != NULL) {
03c20031 1167 XFREE(MTYPE_RIP_INTERFACE_STRING, str);
5a29c0d5 1168 vector_slot(rip->passive_nondefault, i) = NULL;
d62a17ae 1169 }
045c5389 1170 rip_passive_interface_apply_all(rip);
718e3744 1171}
6b0655a2 1172
718e3744 1173/* Write rip configuration of each interface. */
d62a17ae 1174static int rip_interface_config_write(struct vty *vty)
1175{
ae7b826a 1176 struct vrf *vrf;
94b117b2 1177 int write = 0;
d62a17ae 1178
ae7b826a
RW
1179 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1180 struct interface *ifp;
d62a17ae 1181
ae7b826a
RW
1182 FOR_ALL_INTERFACES (vrf, ifp) {
1183 struct lyd_node *dnode;
1184
1185 dnode = yang_dnode_get(
1186 running_config->dnode,
1187 "/frr-interface:lib/interface[name='%s'][vrf='%s']",
1188 ifp->name, vrf->name);
1189 if (dnode == NULL)
1190 continue;
d62a17ae 1191
ae7b826a
RW
1192 write = 1;
1193 nb_cli_show_dnode_cmds(vty, dnode, false);
1194 }
d62a17ae 1195 }
94b117b2
RW
1196
1197 return write;
d62a17ae 1198}
1199
045c5389 1200int rip_show_network_config(struct vty *vty, struct rip *rip)
d62a17ae 1201{
1202 unsigned int i;
1203 char *ifname;
1204 struct route_node *node;
1205
1206 /* Network type RIP enable interface statement. */
1205fdc4 1207 for (node = route_top(rip->enable_network); node;
d62a17ae 1208 node = route_next(node))
1209 if (node->info)
44f2f852 1210 vty_out(vty, " %s/%u\n",
d62a17ae 1211 inet_ntoa(node->p.u.prefix4),
1212 node->p.prefixlen);
1213
1214 /* Interface name RIP enable statement. */
ca046902
RW
1215 for (i = 0; i < vector_active(rip->enable_interface); i++)
1216 if ((ifname = vector_slot(rip->enable_interface, i)) != NULL)
44f2f852 1217 vty_out(vty, " %s\n", ifname);
d62a17ae 1218
1219 /* RIP neighbors listing. */
1220 for (node = route_top(rip->neighbor); node; node = route_next(node))
1221 if (node->info)
44f2f852 1222 vty_out(vty, " %s\n", inet_ntoa(node->p.u.prefix4));
718e3744 1223
d62a17ae 1224 return 0;
1225}
1226
1227static struct cmd_node interface_node = {
9d303b37 1228 INTERFACE_NODE, "%s(config-if)# ", 1,
718e3744 1229};
1230
ae7b826a
RW
1231void rip_interface_sync(struct interface *ifp)
1232{
1233 struct vrf *vrf;
1234
1235 vrf = vrf_lookup_by_id(ifp->vrf_id);
1236 if (vrf) {
1237 struct rip_interface *ri;
1238
1239 ri = ifp->info;
1240 if (ri)
1241 ri->rip = vrf->info;
1242 }
1243}
1244
718e3744 1245/* Called when interface structure allocated. */
d62a17ae 1246static int rip_interface_new_hook(struct interface *ifp)
718e3744 1247{
ae7b826a
RW
1248 ifp->info = rip_interface_new();
1249 rip_interface_sync(ifp);
1250
d62a17ae 1251 return 0;
718e3744 1252}
1253
1254/* Called when interface structure deleted. */
d62a17ae 1255static int rip_interface_delete_hook(struct interface *ifp)
718e3744 1256{
72010aca 1257 rip_interface_reset(ifp->info);
d62a17ae 1258 XFREE(MTYPE_RIP_INTERFACE, ifp->info);
1259 ifp->info = NULL;
1260 return 0;
718e3744 1261}
1262
1263/* Allocate and initialize interface vector. */
d62a17ae 1264void rip_if_init(void)
718e3744 1265{
d62a17ae 1266 /* Default initial size of interface vector. */
ce19a04a
DL
1267 hook_register_prio(if_add, 0, rip_interface_new_hook);
1268 hook_register_prio(if_del, 0, rip_interface_delete_hook);
d62a17ae 1269
d62a17ae 1270 /* Install interface node. */
1271 install_node(&interface_node, rip_interface_config_write);
1272 if_cmd_init();
718e3744 1273}