+// SPDX-License-Identifier: GPL-2.0-or-later
/* RIP version 1 and 2.
* Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
* Copyright (C) 1997, 98, 99 Kunihiro Ishiguro <kunihiro@zebra.org>
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
/* Prototypes. */
static void rip_output_process(struct connected *, struct sockaddr_in *, int,
uint8_t);
-static int rip_triggered_update(struct thread *);
+static void rip_triggered_update(struct thread *);
static int rip_update_jitter(unsigned long);
static void rip_distance_table_node_cleanup(struct route_table *table,
struct route_node *node);
}
/* RIP route garbage collect timer. */
-static int rip_garbage_collect(struct thread *t)
+static void rip_garbage_collect(struct thread *t)
{
struct rip_info *rinfo;
struct route_node *rp;
rinfo = THREAD_ARG(t);
- rinfo->t_garbage_collect = NULL;
/* Off timeout timer. */
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
/* Get route_node pointer. */
rp = rinfo->rp;
/* Free RIP routing information. */
rip_info_free(rinfo);
-
- return 0;
}
static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo);
rip_zebra_ipv4_delete(rip, rp);
/* Re-use the first entry, and delete the others. */
- for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
- if (tmp_rinfo != rinfo) {
- RIP_TIMER_OFF(tmp_rinfo->t_timeout);
- RIP_TIMER_OFF(tmp_rinfo->t_garbage_collect);
- list_delete_node(list, node);
- rip_info_free(tmp_rinfo);
- }
+ for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) {
+ if (tmp_rinfo == rinfo)
+ continue;
- RIP_TIMER_OFF(rinfo->t_timeout);
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(tmp_rinfo->t_timeout);
+ THREAD_OFF(tmp_rinfo->t_garbage_collect);
+ list_delete_node(list, node);
+ rip_info_free(tmp_rinfo);
+ }
+
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
memcpy(rinfo, rinfo_new, sizeof(struct rip_info));
if (rip_route_rte(rinfo)) {
struct route_node *rp = rinfo->rp;
struct list *list = (struct list *)rp->info;
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
if (listcount(list) > 1) {
/* Some other ECMP entries still exist. Just delete this entry.
*/
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_garbage_collect);
listnode_delete(list, rinfo);
if (rip_route_rte(rinfo)
&& CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
}
/* Timeout RIP routes. */
-static int rip_timeout(struct thread *t)
+static void rip_timeout(struct thread *t)
{
struct rip_info *rinfo = THREAD_ARG(t);
struct rip *rip = rip_info_get_instance(rinfo);
rip_ecmp_delete(rip, rinfo);
-
- return 0;
}
static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo)
{
if (rinfo->metric != RIP_METRIC_INFINITY) {
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
thread_add_timer(master, rip_timeout, rinfo, rip->timeout_time,
&rinfo->t_timeout);
}
const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in";
/* Input distribute-list filtering. */
- if (ri->list[rip_distribute]) {
- if (access_list_apply(ri->list[rip_distribute],
- (struct prefix *)p)
- == FILTER_DENY) {
- if (IS_RIP_DEBUG_PACKET)
- zlog_debug("%pFX filtered by distribute %s", p,
- inout);
- return -1;
- }
+ if (ri->list[rip_distribute] &&
+ access_list_apply(ri->list[rip_distribute], (struct prefix *)p) ==
+ FILTER_DENY) {
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_debug("%pFX filtered by distribute %s", p, inout);
+ return -1;
}
- if (ri->prefix[rip_distribute]) {
- if (prefix_list_apply(ri->prefix[rip_distribute],
- (struct prefix *)p)
- == PREFIX_DENY) {
- if (IS_RIP_DEBUG_PACKET)
- zlog_debug("%pFX filtered by prefix-list %s", p,
- inout);
- return -1;
- }
+
+ if (ri->prefix[rip_distribute] &&
+ prefix_list_apply(ri->prefix[rip_distribute], (struct prefix *)p) ==
+ PREFIX_DENY) {
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_debug("%pFX filtered by prefix-list %s", p, inout);
+ return -1;
}
/* All interface filter check. */
dist = distribute_lookup(ri->rip->distribute_ctx, NULL);
- if (dist) {
- if (dist->list[distribute]) {
- alist = access_list_lookup(AFI_IP,
- dist->list[distribute]);
+ if (!dist)
+ return 0;
- if (alist) {
- if (access_list_apply(alist, (struct prefix *)p)
- == FILTER_DENY) {
- if (IS_RIP_DEBUG_PACKET)
- zlog_debug(
- "%pFX filtered by distribute %s",
- p, inout);
- return -1;
- }
+ if (dist->list[distribute]) {
+ alist = access_list_lookup(AFI_IP, dist->list[distribute]);
+
+ if (alist) {
+ if (access_list_apply(alist, (struct prefix *)p) ==
+ FILTER_DENY) {
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_debug(
+ "%pFX filtered by distribute %s",
+ p, inout);
+ return -1;
}
}
- if (dist->prefix[distribute]) {
- plist = prefix_list_lookup(AFI_IP,
- dist->prefix[distribute]);
-
- if (plist) {
- if (prefix_list_apply(plist, (struct prefix *)p)
- == PREFIX_DENY) {
- if (IS_RIP_DEBUG_PACKET)
- zlog_debug(
- "%pFX filtered by prefix-list %s",
- p, inout);
- return -1;
- }
+ }
+ if (dist->prefix[distribute]) {
+ plist = prefix_list_lookup(AFI_IP, dist->prefix[distribute]);
+
+ if (plist) {
+ if (prefix_list_apply(plist, (struct prefix *)p) ==
+ PREFIX_DENY) {
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_debug(
+ "%pFX filtered by prefix-list %s",
+ p, inout);
+ return -1;
}
}
}
+
return 0;
}
&& IPV4_ADDR_SAME(&rinfo->nh.gate.ipv4, nexthop))
break;
- if (!listnextnode(node)) {
- /* Not found in the list */
+ if (listnextnode(node))
+ continue;
- if (rte->metric > rinfo->metric) {
- /* New route has a greater metric.
- * Discard it. */
- route_unlock_node(rp);
- return;
- }
+ /* Not found in the list */
- if (rte->metric < rinfo->metric)
- /* New route has a smaller metric.
- * Replace the ECMP list
- * with the new one in below. */
- break;
+ if (rte->metric > rinfo->metric) {
+ /* New route has a greater metric.
+ * Discard it. */
+ route_unlock_node(rp);
+ return;
+ }
- /* Metrics are same. We compare the distances.
- */
- old_dist = rinfo->distance
- ? rinfo->distance
+ if (rte->metric < rinfo->metric)
+ /* New route has a smaller metric.
+ * Replace the ECMP list
+ * with the new one in below. */
+ break;
+
+ /* Metrics are same. We compare the distances.
+ */
+ old_dist = rinfo->distance ? rinfo->distance
: ZEBRA_RIP_DISTANCE_DEFAULT;
- if (new_dist > old_dist) {
- /* New route has a greater distance.
- * Discard it. */
- route_unlock_node(rp);
- return;
- }
+ if (new_dist > old_dist) {
+ /* New route has a greater distance.
+ * Discard it. */
+ route_unlock_node(rp);
+ return;
+ }
- if (new_dist < old_dist)
- /* New route has a smaller distance.
- * Replace the ECMP list
- * with the new one in below. */
- break;
+ if (new_dist < old_dist)
+ /* New route has a smaller distance.
+ * Replace the ECMP list
+ * with the new one in below. */
+ break;
- /* Metrics and distances are both same. Keep
- * "rinfo" null and
- * the new route is added in the ECMP list in
- * below. */
- }
+ /* Metrics and distances are both same. Keep
+ * "rinfo" null and
+ * the new route is added in the ECMP list in
+ * below. */
}
if (rinfo) {
assert(newinfo.metric
!= RIP_METRIC_INFINITY);
- RIP_TIMER_OFF(rinfo->t_timeout);
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
memcpy(rinfo, &newinfo,
sizeof(struct rip_info));
rip_timeout_update(rip, rinfo);
struct key *key)
{
size_t doff = 0;
+ static uint32_t seq = 0;
assert(s && ri && ri->auth_type == RIP_AUTH_MD5);
/* RFC2080: The value used in the sequence number is
arbitrary, but two suggestions are the time of the
message's creation or a simple message counter. */
- stream_putl(s, time(NULL));
+ stream_putl(s, ++seq);
/* Reserved field must be zero. */
stream_putl(s, 0);
/* Check packet length. */
if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE)) {
- flog_err(
- EC_RIP_PACKET,
- "rip_auth_md5_set(): packet length %ld is less than minimum length.",
- len);
+ flog_err(EC_RIP_PACKET,
+ "%s: packet length %ld is less than minimum length.",
+ __func__, len);
return;
}
}
/* For RIPv1, there won't be a valid netmask.
-
- This is a best guess at the masks. If everyone was using old
- Ciscos before the 'ip subnet zero' option, it would be almost
- right too :-)
-
- Cisco summarize ripv1 advertisements to the classful boundary
- (/16 for class B's) except when the RIP packet does to inside
- the classful network in question. */
-
+ * This is a best guess at the masks. If everyone was using old
+ * Ciscos before the 'ip subnet zero' option, it would be almost
+ * right too :-)
+ *
+ * Cisco summarize ripv1 advertisements to the classful boundary
+ * (/16 for class B's) except when the RIP packet does to inside
+ * the classful network in question.
+ */
if ((packet->version == RIPv1
&& rte->prefix.s_addr != INADDR_ANY)
|| (packet->version == RIPv2
uint32_t destination;
if (subnetted == -1) {
- memcpy(&ifaddr, ifc->address,
- sizeof(struct prefix_ipv4));
+ memcpy(&ifaddr, ifc->address, sizeof(ifaddr));
memcpy(&ifaddrclass, &ifaddr,
- sizeof(struct prefix_ipv4));
+ sizeof(ifaddrclass));
apply_classful_mask_ipv4(&ifaddrclass);
subnetted = 0;
if (ifaddr.prefixlen > ifaddrclass.prefixlen)
inet_ntop(AF_INET, &sin.sin_addr, dst, sizeof(dst));
}
#undef ADDRESS_SIZE
- zlog_debug("rip_send_packet %pI4 > %s (%s)",
- &ifc->address->u.prefix4, dst,
- ifc->ifp->name);
+ zlog_debug("%s %pI4 > %s (%s)", __func__,
+ &ifc->address->u.prefix4, dst, ifc->ifp->name);
}
if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) {
/*
* ZEBRA_IFA_SECONDARY is set on linux when an interface is
- * configured
- * with multiple addresses on the same subnet: the first address
- * on the subnet is configured "primary", and all subsequent
- * addresses
- * on that subnet are treated as "secondary" addresses.
- * In order to avoid routing-table bloat on other rip listeners,
- * we do not send out RIP packets with ZEBRA_IFA_SECONDARY
- * source addrs.
+ * configured with multiple addresses on the same
+ * subnet: the first address on the subnet is configured
+ * "primary", and all subsequent addresses on that subnet
+ * are treated as "secondary" addresses. In order to avoid
+ * routing-table bloat on other rip listeners, we do not send
+ * out RIP packets with ZEBRA_IFA_SECONDARY source addrs.
* XXX Since Linux is the only system for which the
- * ZEBRA_IFA_SECONDARY
- * flag is set, we would end up sending a packet for a
- * "secondary"
- * source address on non-linux systems.
+ * ZEBRA_IFA_SECONDARY flag is set, we would end up
+ * sending a packet for a "secondary" source address on
+ * non-linux systems.
*/
if (IS_RIP_DEBUG_PACKET)
zlog_debug("duplicate dropped");
}
/* Make destination address. */
- memset(&sin, 0, sizeof(struct sockaddr_in));
+ memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sin.sin_len = sizeof(struct sockaddr_in);
cmsgptr->cmsg_type = IP_PKTINFO;
pkt = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
pkt->ipi_ifindex = ifc->ifp->ifindex;
+ pkt->ipi_spec_dst.s_addr = ifc->address->u.prefix4.s_addr;
#endif /* GNU_LINUX */
ret = sendmsg(rip->sock, &msg, 0);
rp = route_node_get(rip->table, (struct prefix *)p);
- memset(&newinfo, 0, sizeof(struct rip_info));
+ memset(&newinfo, 0, sizeof(newinfo));
newinfo.type = type;
newinfo.sub_type = sub_type;
newinfo.metric = 1;
RIP_TIMER_ON(rinfo->t_garbage_collect,
rip_garbage_collect,
rip->garbage_time);
- RIP_TIMER_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_timeout);
rinfo->flags |= RIP_RTF_CHANGED;
if (IS_RIP_DEBUG_EVENT)
}
/* First entry point of RIP packet. */
-static int rip_read(struct thread *t)
+static void rip_read(struct thread *t)
{
struct rip *rip = THREAD_ARG(t);
int sock;
/* Fetch socket then register myself. */
sock = THREAD_FD(t);
- rip->t_read = NULL;
/* Add myself to tne next event */
rip_event(rip, RIP_READ, sock);
/* RIPd manages only IPv4. */
- memset(&from, 0, sizeof(struct sockaddr_in));
+ memset(&from, 0, sizeof(from));
fromlen = sizeof(struct sockaddr_in);
len = recvfrom(sock, (char *)&rip_buf.buf, sizeof(rip_buf.buf), 0,
if (len < 0) {
zlog_info("recvfrom failed (VRF %s): %s", rip->vrf_name,
safe_strerror(errno));
- return len;
+ return;
}
/* Check is this packet comming from myself? */
if (IS_RIP_DEBUG_PACKET)
zlog_debug("ignore packet comes from myself (VRF %s)",
rip->vrf_name);
- return -1;
+ return;
}
/* Which interface is this packet comes from. */
/* If this packet come from unknown interface, ignore it. */
if (ifp == NULL) {
zlog_info(
- "rip_read: cannot find interface for packet from %pI4 port %d (VRF %s)",
- &from.sin_addr, ntohs(from.sin_port),
+ "%s: cannot find interface for packet from %pI4 port %d (VRF %s)",
+ __func__, &from.sin_addr, ntohs(from.sin_port),
rip->vrf_name);
- return -1;
+ return;
}
p.family = AF_INET;
if (ifc == NULL) {
zlog_info(
- "rip_read: cannot find connected address for packet from %pI4 port %d on interface %s (VRF %s)",
- &from.sin_addr, ntohs(from.sin_port),
+ "%s: cannot find connected address for packet from %pI4 port %d on interface %s (VRF %s)",
+ __func__, &from.sin_addr, ntohs(from.sin_port),
ifp->name, rip->vrf_name);
- return -1;
+ return;
}
/* Packet length check. */
zlog_warn("packet size %d is smaller than minimum size %d", len,
RIP_PACKET_MINSIZ);
rip_peer_bad_packet(rip, &from);
- return len;
+ return;
}
if (len > RIP_PACKET_MAXSIZ) {
zlog_warn("packet size %d is larger than max size %d", len,
RIP_PACKET_MAXSIZ);
rip_peer_bad_packet(rip, &from);
- return len;
+ return;
}
/* Packet alignment check. */
zlog_warn("packet size %d is wrong for RIP packet alignment",
len);
rip_peer_bad_packet(rip, &from);
- return len;
+ return;
}
/* Set RTE number. */
zlog_info("version 0 with command %d received.",
packet->command);
rip_peer_bad_packet(rip, &from);
- return -1;
+ return;
}
/* Dump RIP packet. */
zlog_debug("RIP is not enabled on interface %s.",
ifp->name);
rip_peer_bad_packet(rip, &from);
- return -1;
+ return;
}
/* RIP Version check. RFC2453, 4.6 and 5.1 */
" packet's v%d doesn't fit to if version spec",
packet->version);
rip_peer_bad_packet(rip, &from);
- return -1;
+ return;
}
/* RFC2453 5.2 If the router is not configured to authenticate RIP-2
packet->version);
ripd_notif_send_auth_type_failure(ifp->name);
rip_peer_bad_packet(rip, &from);
- return -1;
+ return;
}
/* RFC:
"RIPv1 dropped because authentication enabled");
ripd_notif_send_auth_type_failure(ifp->name);
rip_peer_bad_packet(rip, &from);
- return -1;
+ return;
}
} else if (ri->auth_type != RIP_NO_AUTH) {
const char *auth_desc;
"RIPv2 authentication failed: no auth RTE in packet");
ripd_notif_send_auth_type_failure(ifp->name);
rip_peer_bad_packet(rip, &from);
- return -1;
+ return;
}
/* First RTE must be an Authentication Family RTE */
"RIPv2 dropped because authentication enabled");
ripd_notif_send_auth_type_failure(ifp->name);
rip_peer_bad_packet(rip, &from);
- return -1;
+ return;
}
/* Check RIPv2 authentication. */
auth_desc);
ripd_notif_send_auth_failure(ifp->name);
rip_peer_bad_packet(rip, &from);
- return -1;
+ return;
}
}
rip_peer_bad_packet(rip, &from);
break;
}
-
- return len;
}
/* Write routing table entry to the stream and return next index of
}
if (version == RIPv1) {
- memcpy(&ifaddrclass, ifc->address, sizeof(struct prefix_ipv4));
+ memcpy(&ifaddrclass, ifc->address, sizeof(ifaddrclass));
apply_classful_mask_ipv4(&ifaddrclass);
subnetted = 0;
if (ifc->address->prefixlen > ifaddrclass.prefixlen)
subnetted = 1;
}
- for (rp = route_top(rip->table); rp; rp = route_next(rp))
- if ((list = rp->info) != NULL && listcount(list) != 0) {
- rinfo = listgetdata(listhead(list));
- /* For RIPv1, if we are subnetted, output subnets in our
- * network */
- /* that have the same mask as the output "interface".
- * For other */
- /* networks, only the classfull version is output. */
+ for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
+ list = rp->info;
- if (version == RIPv1) {
- p = (struct prefix_ipv4 *)&rp->p;
+ if (list == NULL)
+ continue;
- if (IS_RIP_DEBUG_PACKET)
- zlog_debug(
- "RIPv1 mask check, %pFX considered for output",
- &rp->p);
-
- if (subnetted
- && prefix_match(
- (struct prefix *)&ifaddrclass,
- &rp->p)) {
- if ((ifc->address->prefixlen
- != rp->p.prefixlen)
- && (rp->p.prefixlen
- != IPV4_MAX_BITLEN))
- continue;
- } else {
- memcpy(&classfull, &rp->p,
- sizeof(struct prefix_ipv4));
- apply_classful_mask_ipv4(&classfull);
- if (rp->p.u.prefix4.s_addr != INADDR_ANY
- && classfull.prefixlen
- != rp->p.prefixlen)
- continue;
- }
- if (IS_RIP_DEBUG_PACKET)
- zlog_debug(
- "RIPv1 mask check, %pFX made it through",
- &rp->p);
- } else
- p = (struct prefix_ipv4 *)&rp->p;
+ if (listcount(list) == 0)
+ continue;
- /* Apply output filters. */
- ret = rip_filter(RIP_FILTER_OUT, p, ri);
- if (ret < 0)
- continue;
+ rinfo = listgetdata(listhead(list));
+ /*
+ * For RIPv1, if we are subnetted, output subnets in our
+ * network that have the same mask as the output "interface".
+ * For other networks, only the classfull version is output.
+ */
+ if (version == RIPv1) {
+ p = (struct prefix_ipv4 *)&rp->p;
- /* Changed route only output. */
- if (route_type == rip_changed_route
- && (!(rinfo->flags & RIP_RTF_CHANGED)))
- continue;
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_debug(
+ "RIPv1 mask check, %pFX considered for output",
+ &rp->p);
+
+ if (subnetted &&
+ prefix_match((struct prefix *)&ifaddrclass,
+ &rp->p)) {
+ if ((ifc->address->prefixlen !=
+ rp->p.prefixlen) &&
+ (rp->p.prefixlen != IPV4_MAX_BITLEN))
+ continue;
+ } else {
+ memcpy(&classfull, &rp->p,
+ sizeof(struct prefix_ipv4));
+ apply_classful_mask_ipv4(&classfull);
+ if (rp->p.u.prefix4.s_addr != INADDR_ANY &&
+ classfull.prefixlen != rp->p.prefixlen)
+ continue;
+ }
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_debug(
+ "RIPv1 mask check, %pFX made it through",
+ &rp->p);
+ } else
+ p = (struct prefix_ipv4 *)&rp->p;
- /* Split horizon. */
- /* if (split_horizon == rip_split_horizon) */
- if (ri->split_horizon == RIP_SPLIT_HORIZON) {
- /*
- * We perform split horizon for RIP and
- * connected route.
- * For rip routes, we want to suppress the route
- * if we would
- * end up sending the route back on the
- * interface that we
- * learned it from, with a higher metric. For
- * connected routes,
- * we suppress the route if the prefix is a
- * subset of the
- * source address that we are going to use for
- * the packet
- * (in order to handle the case when multiple
- * subnets are
- * configured on the same interface).
- */
- int suppress = 0;
- struct rip_info *tmp_rinfo = NULL;
- struct connected *tmp_ifc = NULL;
-
- for (ALL_LIST_ELEMENTS_RO(list, listnode,
- tmp_rinfo))
- if (tmp_rinfo->type == ZEBRA_ROUTE_RIP
- && tmp_rinfo->nh.ifindex
- == ifc->ifp->ifindex) {
- suppress = 1;
- break;
- }
+ /* Apply output filters. */
+ ret = rip_filter(RIP_FILTER_OUT, p, ri);
+ if (ret < 0)
+ continue;
+
+ /* Changed route only output. */
+ if (route_type == rip_changed_route &&
+ (!(rinfo->flags & RIP_RTF_CHANGED)))
+ continue;
- if (!suppress
- && rinfo->type == ZEBRA_ROUTE_CONNECT) {
- for (ALL_LIST_ELEMENTS_RO(
- ifc->ifp->connected,
- listnode, tmp_ifc))
- if (prefix_match(
- (struct prefix *)p,
- tmp_ifc->address)) {
- suppress = 1;
- break;
- }
+ /* Split horizon. */
+ if (ri->split_horizon == RIP_SPLIT_HORIZON) {
+ /*
+ * We perform split horizon for RIP and connected
+ * route. For rip routes, we want to suppress the
+ * route if we would end up sending the route back on
+ * the interface that we learned it from, with a
+ * higher metric. For connected routes, we suppress
+ * the route if the prefix is a subset of the source
+ * address that we are going to use for the packet
+ * (in order to handle the case when multiple subnets
+ * are configured on the same interface).
+ */
+ int suppress = 0;
+ struct rip_info *tmp_rinfo = NULL;
+ struct connected *tmp_ifc = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, tmp_rinfo))
+ if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
+ tmp_rinfo->nh.ifindex ==
+ ifc->ifp->ifindex) {
+ suppress = 1;
+ break;
}
- if (suppress)
- continue;
+ if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT) {
+ for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected,
+ listnode, tmp_ifc))
+ if (prefix_match((struct prefix *)p,
+ tmp_ifc->address)) {
+ suppress = 1;
+ break;
+ }
}
- /* Preparation for route-map. */
- rinfo->metric_set = 0;
- rinfo->nexthop_out.s_addr = 0;
- rinfo->metric_out = rinfo->metric;
- rinfo->tag_out = rinfo->tag;
- rinfo->ifindex_out = ifc->ifp->ifindex;
-
- /* In order to avoid some local loops,
- * if the RIP route has a nexthop via this interface,
- * keep the nexthop,
- * otherwise set it to 0. The nexthop should not be
- * propagated
- * beyond the local broadcast/multicast area in order
- * to avoid an IGP multi-level recursive look-up.
- * see (4.4)
- */
- if (rinfo->nh.ifindex == ifc->ifp->ifindex)
- rinfo->nexthop_out = rinfo->nh.gate.ipv4;
+ if (suppress)
+ continue;
+ }
+
+ /* Preparation for route-map. */
+ rinfo->metric_set = 0;
+ rinfo->nexthop_out.s_addr = 0;
+ rinfo->metric_out = rinfo->metric;
+ rinfo->tag_out = rinfo->tag;
+ rinfo->ifindex_out = ifc->ifp->ifindex;
+
+ /* In order to avoid some local loops, if the RIP route has
+ * a nexthop via this interface, keep the nexthop, otherwise
+ * set it to 0. The nexthop should not be propagated beyond
+ * the local broadcast/multicast area in order to avoid an
+ * IGP multi-level recursive look-up. see (4.4)
+ */
+ if (rinfo->nh.ifindex == ifc->ifp->ifindex)
+ rinfo->nexthop_out = rinfo->nh.gate.ipv4;
- /* Interface route-map */
- if (ri->routemap[RIP_FILTER_OUT]) {
- ret = route_map_apply(
- ri->routemap[RIP_FILTER_OUT],
- (struct prefix *)p, rinfo);
+ /* Interface route-map */
+ if (ri->routemap[RIP_FILTER_OUT]) {
+ ret = route_map_apply(ri->routemap[RIP_FILTER_OUT],
+ (struct prefix *)p, rinfo);
- if (ret == RMAP_DENYMATCH) {
- if (IS_RIP_DEBUG_PACKET)
- zlog_debug(
- "RIP %pFX is filtered by route-map out",
- p);
- continue;
- }
+ if (ret == RMAP_DENYMATCH) {
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_debug(
+ "RIP %pFX is filtered by route-map out",
+ p);
+ continue;
}
+ }
- /* Apply redistribute route map - continue, if deny */
- if (rip->redist[rinfo->type].route_map.name
- && rinfo->sub_type != RIP_ROUTE_INTERFACE) {
- ret = route_map_apply(
- rip->redist[rinfo->type].route_map.map,
- (struct prefix *)p, rinfo);
+ /* Apply redistribute route map - continue, if deny */
+ if (rip->redist[rinfo->type].route_map.name &&
+ rinfo->sub_type != RIP_ROUTE_INTERFACE) {
+ ret = route_map_apply(
+ rip->redist[rinfo->type].route_map.map,
+ (struct prefix *)p, rinfo);
- if (ret == RMAP_DENYMATCH) {
- if (IS_RIP_DEBUG_PACKET)
- zlog_debug(
- "%pFX is filtered by route-map",
- p);
- continue;
- }
+ if (ret == RMAP_DENYMATCH) {
+ if (IS_RIP_DEBUG_PACKET)
+ zlog_debug(
+ "%pFX is filtered by route-map",
+ p);
+ continue;
}
+ }
- /* When route-map does not set metric. */
- if (!rinfo->metric_set) {
- /* If redistribute metric is set. */
- if (rip->redist[rinfo->type].metric_config
- && rinfo->metric != RIP_METRIC_INFINITY) {
- rinfo->metric_out =
- rip->redist[rinfo->type].metric;
- } else {
- /* If the route is not connected or
- localy generated
- one, use default-metric value*/
- if (rinfo->type != ZEBRA_ROUTE_RIP
- && rinfo->type
- != ZEBRA_ROUTE_CONNECT
- && rinfo->metric
- != RIP_METRIC_INFINITY)
- rinfo->metric_out =
- rip->default_metric;
- }
+ /* When route-map does not set metric. */
+ if (!rinfo->metric_set) {
+ /* If redistribute metric is set. */
+ if (rip->redist[rinfo->type].metric_config &&
+ rinfo->metric != RIP_METRIC_INFINITY) {
+ rinfo->metric_out =
+ rip->redist[rinfo->type].metric;
+ } else {
+ /* If the route is not connected or localy
+ * generated one, use default-metric value
+ */
+ if (rinfo->type != ZEBRA_ROUTE_RIP &&
+ rinfo->type != ZEBRA_ROUTE_CONNECT &&
+ rinfo->metric != RIP_METRIC_INFINITY)
+ rinfo->metric_out = rip->default_metric;
}
+ }
- /* Apply offset-list */
- if (rinfo->metric != RIP_METRIC_INFINITY)
- rip_offset_list_apply_out(p, ifc->ifp,
- &rinfo->metric_out);
-
- if (rinfo->metric_out > RIP_METRIC_INFINITY)
- rinfo->metric_out = RIP_METRIC_INFINITY;
-
- /* Perform split-horizon with poisoned reverse
- * for RIP and connected routes.
- **/
- if (ri->split_horizon
- == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
- /*
- * We perform split horizon for RIP and
- * connected route.
- * For rip routes, we want to suppress the route
- * if we would
- * end up sending the route back on the
- * interface that we
- * learned it from, with a higher metric. For
- * connected routes,
- * we suppress the route if the prefix is a
- * subset of the
- * source address that we are going to use for
- * the packet
- * (in order to handle the case when multiple
- * subnets are
- * configured on the same interface).
- */
- struct rip_info *tmp_rinfo = NULL;
- struct connected *tmp_ifc = NULL;
-
- for (ALL_LIST_ELEMENTS_RO(list, listnode,
- tmp_rinfo))
- if (tmp_rinfo->type == ZEBRA_ROUTE_RIP
- && tmp_rinfo->nh.ifindex
- == ifc->ifp->ifindex)
+ /* Apply offset-list */
+ if (rinfo->metric != RIP_METRIC_INFINITY)
+ rip_offset_list_apply_out(p, ifc->ifp,
+ &rinfo->metric_out);
+
+ if (rinfo->metric_out > RIP_METRIC_INFINITY)
+ rinfo->metric_out = RIP_METRIC_INFINITY;
+
+ /* Perform split-horizon with poisoned reverse
+ * for RIP and connected routes.
+ **/
+ if (ri->split_horizon == RIP_SPLIT_HORIZON_POISONED_REVERSE) {
+ /*
+ * We perform split horizon for RIP and connected
+ * route. For rip routes, we want to suppress the
+ * route if we would end up sending the route back
+ * on the interface that we learned it from, with a
+ * higher metric. For connected routes, we suppress
+ * the route if the prefix is a subset of the source
+ * address that we are going to use for the packet
+ * (in order to handle the case when multiple
+ * subnets are configured on the same interface).
+ */
+ struct rip_info *tmp_rinfo = NULL;
+ struct connected *tmp_ifc = NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, tmp_rinfo))
+ if (tmp_rinfo->type == ZEBRA_ROUTE_RIP &&
+ tmp_rinfo->nh.ifindex == ifc->ifp->ifindex)
+ rinfo->metric_out = RIP_METRIC_INFINITY;
+
+ if (rinfo->metric_out != RIP_METRIC_INFINITY &&
+ rinfo->type == ZEBRA_ROUTE_CONNECT) {
+ for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected,
+ listnode, tmp_ifc))
+ if (prefix_match((struct prefix *)p,
+ tmp_ifc->address)) {
rinfo->metric_out =
RIP_METRIC_INFINITY;
-
- if (rinfo->metric_out != RIP_METRIC_INFINITY
- && rinfo->type == ZEBRA_ROUTE_CONNECT) {
- for (ALL_LIST_ELEMENTS_RO(
- ifc->ifp->connected,
- listnode, tmp_ifc))
- if (prefix_match(
- (struct prefix *)p,
- tmp_ifc->address)) {
- rinfo->metric_out =
- RIP_METRIC_INFINITY;
- break;
- }
- }
+ break;
+ }
}
+ }
- /* Prepare preamble, auth headers, if needs be */
- if (num == 0) {
- stream_putc(s, RIP_RESPONSE);
- stream_putc(s, version);
- stream_putw(s, 0);
-
- /* auth header for !v1 && !no_auth */
- if ((ri->auth_type != RIP_NO_AUTH)
- && (version != RIPv1))
- doff = rip_auth_header_write(
- s, ri, key, auth_str,
- RIP_AUTH_SIMPLE_SIZE);
- }
+ /* Prepare preamble, auth headers, if needs be */
+ if (num == 0) {
+ stream_putc(s, RIP_RESPONSE);
+ stream_putc(s, version);
+ stream_putw(s, 0);
+
+ /* auth header for !v1 && !no_auth */
+ if ((ri->auth_type != RIP_NO_AUTH) &&
+ (version != RIPv1))
+ doff = rip_auth_header_write(
+ s, ri, key, auth_str,
+ RIP_AUTH_SIMPLE_SIZE);
+ }
- /* Write RTE to the stream. */
- num = rip_write_rte(num, s, p, version, rinfo);
- if (num == rtemax) {
- if (version == RIPv2
- && ri->auth_type == RIP_AUTH_MD5)
- rip_auth_md5_set(s, ri, doff, auth_str,
- RIP_AUTH_SIMPLE_SIZE);
-
- ret = rip_send_packet(STREAM_DATA(s),
- stream_get_endp(s), to,
- ifc);
-
- if (ret >= 0 && IS_RIP_DEBUG_SEND)
- rip_packet_dump((struct rip_packet *)
- STREAM_DATA(s),
- stream_get_endp(s),
- "SEND");
- num = 0;
- stream_reset(s);
- }
+ /* Write RTE to the stream. */
+ num = rip_write_rte(num, s, p, version, rinfo);
+ if (num == rtemax) {
+ if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
+ rip_auth_md5_set(s, ri, doff, auth_str,
+ RIP_AUTH_SIMPLE_SIZE);
+
+ ret = rip_send_packet(STREAM_DATA(s),
+ stream_get_endp(s), to, ifc);
+
+ if (ret >= 0 && IS_RIP_DEBUG_SEND)
+ rip_packet_dump(
+ (struct rip_packet *)STREAM_DATA(s),
+ stream_get_endp(s), "SEND");
+ num = 0;
+ stream_reset(s);
}
+ }
/* Flush unwritten RTE. */
if (num != 0) {
if (if_is_broadcast(ifp) || if_is_pointopoint(ifp)) {
if (ifc->address->family == AF_INET) {
/* Destination address and port setting. */
- memset(&to, 0, sizeof(struct sockaddr_in));
+ memset(&to, 0, sizeof(to));
if (ifc->destination)
/* use specified broadcast or peer destination
* addr */
if (ri->passive)
continue;
- if (ri->running) {
- /*
- * If there is no version configuration in the
- * interface,
- * use rip's version setting.
- */
- int vsend = ((ri->ri_send == RI_RIP_UNSPEC)
- ? rip->version_send
- : ri->ri_send);
+ if (!ri->running)
+ continue;
- if (IS_RIP_DEBUG_EVENT)
- zlog_debug("SEND UPDATE to %s ifindex %d",
- ifp->name, ifp->ifindex);
-
- /* send update on each connected network */
- for (ALL_LIST_ELEMENTS(ifp->connected, ifnode, ifnnode,
- connected)) {
- if (connected->address->family == AF_INET) {
- if (vsend & RIPv1)
- rip_update_interface(
- connected, RIPv1,
- route_type);
- if ((vsend & RIPv2)
- && if_is_multicast(ifp))
- rip_update_interface(
- connected, RIPv2,
- route_type);
- }
+ /*
+ * If there is no version configuration in the
+ * interface, use rip's version setting.
+ */
+ int vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? rip->version_send
+ : ri->ri_send);
+
+ if (IS_RIP_DEBUG_EVENT)
+ zlog_debug("SEND UPDATE to %s ifindex %d", ifp->name,
+ ifp->ifindex);
+
+ /* send update on each connected network */
+ for (ALL_LIST_ELEMENTS(ifp->connected, ifnode, ifnnode,
+ connected)) {
+ if (connected->address->family == AF_INET) {
+ if (vsend & RIPv1)
+ rip_update_interface(connected, RIPv1,
+ route_type);
+ if ((vsend & RIPv2) && if_is_multicast(ifp))
+ rip_update_interface(connected, RIPv2,
+ route_type);
}
}
}
/* RIP send updates to each neighbor. */
- for (rp = route_top(rip->neighbor); rp; rp = route_next(rp))
- if (rp->info != NULL) {
- p = &rp->p;
-
- connected = if_lookup_address(&p->u.prefix4, AF_INET,
- rip->vrf->vrf_id);
- if (!connected) {
- zlog_warn(
- "Neighbor %pI4 doesn't have connected interface!",
- &p->u.prefix4);
- continue;
- }
+ for (rp = route_top(rip->neighbor); rp; rp = route_next(rp)) {
+ if (rp->info == NULL)
+ continue;
- /* Set destination address and port */
- memset(&to, 0, sizeof(struct sockaddr_in));
- to.sin_addr = p->u.prefix4;
- to.sin_port = htons(RIP_PORT_DEFAULT);
+ p = &rp->p;
- /* RIP version is rip's configuration. */
- rip_output_process(connected, &to, route_type,
- rip->version_send);
+ connected = if_lookup_address(&p->u.prefix4, AF_INET,
+ rip->vrf->vrf_id);
+ if (!connected) {
+ zlog_warn(
+ "Neighbor %pI4 doesn't have connected interface!",
+ &p->u.prefix4);
+ continue;
}
+
+ /* Set destination address and port */
+ memset(&to, 0, sizeof(struct sockaddr_in));
+ to.sin_addr = p->u.prefix4;
+ to.sin_port = htons(RIP_PORT_DEFAULT);
+
+ /* RIP version is rip's configuration. */
+ rip_output_process(connected, &to, route_type,
+ rip->version_send);
+ }
}
/* RIP's periodical timer. */
-static int rip_update(struct thread *t)
+static void rip_update(struct thread *t)
{
struct rip *rip = THREAD_ARG(t);
- /* Clear timer pointer. */
- rip->t_update = NULL;
-
if (IS_RIP_DEBUG_EVENT)
zlog_debug("update timer fire!");
/* Triggered updates may be suppressed if a regular update is due by
the time the triggered update would be sent. */
- RIP_TIMER_OFF(rip->t_triggered_interval);
+ THREAD_OFF(rip->t_triggered_interval);
rip->trigger = 0;
/* Register myself. */
rip_event(rip, RIP_UPDATE_EVENT, 0);
-
- return 0;
}
/* Walk down the RIP routing table then clear changed flag. */
struct list *list = NULL;
struct listnode *listnode = NULL;
- for (rp = route_top(rip->table); rp; rp = route_next(rp))
- if ((list = rp->info) != NULL)
- for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- UNSET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
- /* This flag can be set only on the first entry.
- */
- break;
- }
+ for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
+ list = rp->info;
+
+ if (list == NULL)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
+ UNSET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
+ /* This flag can be set only on the first entry. */
+ break;
+ }
+ }
}
/* Triggered update interval timer. */
-static int rip_triggered_interval(struct thread *t)
+static void rip_triggered_interval(struct thread *t)
{
struct rip *rip = THREAD_ARG(t);
- rip->t_triggered_interval = NULL;
-
if (rip->trigger) {
rip->trigger = 0;
rip_triggered_update(t);
}
- return 0;
}
/* Execute triggered update. */
-static int rip_triggered_update(struct thread *t)
+static void rip_triggered_update(struct thread *t)
{
struct rip *rip = THREAD_ARG(t);
int interval;
- /* Clear thred pointer. */
- rip->t_triggered_update = NULL;
-
/* Cancel interval timer. */
- RIP_TIMER_OFF(rip->t_triggered_interval);
+ THREAD_OFF(rip->t_triggered_interval);
rip->trigger = 0;
/* Logging triggered update. */
update is triggered when the timer expires. */
interval = (frr_weak_random() % 5) + 1;
- rip->t_triggered_interval = NULL;
thread_add_timer(master, rip_triggered_interval, rip, interval,
&rip->t_triggered_interval);
-
- return 0;
}
/* Withdraw redistributed route. */
struct rip_info *rinfo = NULL;
struct list *list = NULL;
- for (rp = route_top(rip->table); rp; rp = route_next(rp))
- if ((list = rp->info) != NULL) {
- rinfo = listgetdata(listhead(list));
- if (rinfo->type == type
- && rinfo->sub_type != RIP_ROUTE_INTERFACE) {
- /* Perform poisoned reverse. */
- rinfo->metric = RIP_METRIC_INFINITY;
- RIP_TIMER_ON(rinfo->t_garbage_collect,
- rip_garbage_collect,
- rip->garbage_time);
- RIP_TIMER_OFF(rinfo->t_timeout);
- rinfo->flags |= RIP_RTF_CHANGED;
+ for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
+ list = rp->info;
- if (IS_RIP_DEBUG_EVENT) {
- struct prefix_ipv4 *p =
- (struct prefix_ipv4 *)&rp->p;
+ if (list == NULL)
+ continue;
- zlog_debug(
- "Poisone %pFX on the interface %s with an infinity metric [withdraw]",
- p,
- ifindex2ifname(
- rinfo->nh.ifindex,
- rip->vrf->vrf_id));
- }
+ rinfo = listgetdata(listhead(list));
- rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
- }
+ if (rinfo->type != type)
+ continue;
+
+ if (rinfo->sub_type == RIP_ROUTE_INTERFACE)
+ continue;
+
+ /* Perform poisoned reverse. */
+ rinfo->metric = RIP_METRIC_INFINITY;
+ RIP_TIMER_ON(rinfo->t_garbage_collect, rip_garbage_collect,
+ rip->garbage_time);
+ THREAD_OFF(rinfo->t_timeout);
+ rinfo->flags |= RIP_RTF_CHANGED;
+
+ if (IS_RIP_DEBUG_EVENT) {
+ struct prefix_ipv4 *p = (struct prefix_ipv4 *)&rp->p;
+
+ zlog_debug(
+ "Poisone %pFX on the interface %s with an infinity metric [withdraw]",
+ p,
+ ifindex2ifname(rinfo->nh.ifindex,
+ rip->vrf->vrf_id));
}
+
+ rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
+ }
}
struct rip *rip_lookup_by_vrf_id(vrf_id_t vrf_id)
switch (event) {
case RIP_READ:
- rip->t_read = NULL;
thread_add_read(master, rip_read, rip, sock, &rip->t_read);
break;
case RIP_UPDATE_EVENT:
- RIP_TIMER_OFF(rip->t_update);
+ THREAD_OFF(rip->t_update);
jitter = rip_update_jitter(rip->update_time);
thread_add_timer(master, rip_update, rip,
sock ? 2 : rip->update_time + jitter,
struct rip_distance *rdistance;
struct access_list *alist;
- memset(&p, 0, sizeof(struct prefix_ipv4));
+ memset(&p, 0, sizeof(p));
p.family = AF_INET;
p.prefix = rinfo->from;
p.prefixlen = IPV4_MAX_BITLEN;
vty_out(vty, " Distance: (default is %u)\n",
rip->distance ? rip->distance : ZEBRA_RIP_DISTANCE_DEFAULT);
- for (rn = route_top(rip->distance_table); rn; rn = route_next(rn))
- if ((rdistance = rn->info) != NULL) {
- if (header) {
- vty_out(vty,
- " Address Distance List\n");
- header = 0;
- }
- snprintfrr(buf, sizeof(buf), "%pFX", &rn->p);
- vty_out(vty, " %-20s %4d %s\n", buf,
- rdistance->distance,
- rdistance->access_list ? rdistance->access_list
- : "");
+ for (rn = route_top(rip->distance_table); rn; rn = route_next(rn)) {
+ rdistance = rn->info;
+
+ if (rdistance == NULL)
+ continue;
+
+ if (header) {
+ vty_out(vty, " Address Distance List\n");
+ header = 0;
}
+ snprintfrr(buf, sizeof(buf), "%pFX", &rn->p);
+ vty_out(vty, " %-20s %4d %s\n", buf, rdistance->distance,
+ rdistance->access_list ? rdistance->access_list : "");
+ }
}
/* Update ECMP routes to zebra when ECMP is disabled. */
struct list *list;
struct listnode *node, *nextnode;
- for (rp = route_top(rip->table); rp; rp = route_next(rp))
- if ((list = rp->info) != NULL && listcount(list) > 1) {
- rinfo = listgetdata(listhead(list));
- if (!rip_route_rte(rinfo))
- continue;
+ for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
+ list = rp->info;
- /* Drop all other entries, except the first one. */
- for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
- if (tmp_rinfo != rinfo) {
- RIP_TIMER_OFF(tmp_rinfo->t_timeout);
- RIP_TIMER_OFF(
- tmp_rinfo->t_garbage_collect);
- list_delete_node(list, node);
- rip_info_free(tmp_rinfo);
- }
+ if (!list)
+ continue;
+ if (listcount(list) == 0)
+ continue;
- /* Update zebra. */
- rip_zebra_ipv4_add(rip, rp);
+ rinfo = listgetdata(listhead(list));
+ if (!rip_route_rte(rinfo))
+ continue;
- /* Set the route change flag. */
- SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
+ /* Drop all other entries, except the first one. */
+ for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) {
+ if (tmp_rinfo == rinfo)
+ continue;
- /* Signal the output process to trigger an update. */
- rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
+ THREAD_OFF(tmp_rinfo->t_timeout);
+ THREAD_OFF(tmp_rinfo->t_garbage_collect);
+ list_delete_node(list, node);
+ rip_info_free(tmp_rinfo);
}
+
+ /* Update zebra. */
+ rip_zebra_ipv4_add(rip, rp);
+
+ /* Set the route change flag. */
+ SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
+
+ /* Signal the output process to trigger an update. */
+ rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
+ }
}
/* Print out routes update time. */
" (i) - interface\n\n"
" Network Next Hop Metric From Tag Time\n");
- for (np = route_top(rip->table); np; np = route_next(np))
- if ((list = np->info) != NULL)
- for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- int len;
-
- len = vty_out(
- vty, "%c(%s) %pFX",
- /* np->lock, For debugging. */
- zebra_route_char(rinfo->type),
- rip_route_type_print(rinfo->sub_type),
- &np->p);
-
- len = 24 - len;
-
- if (len > 0)
- vty_out(vty, "%*s", len, " ");
-
- switch (rinfo->nh.type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, "%-20pI4 %2d ",
- &rinfo->nh.gate.ipv4,
- rinfo->metric);
- break;
- case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty,
- "0.0.0.0 %2d ",
- rinfo->metric);
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty,
- "blackhole %2d ",
- rinfo->metric);
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty,
- "V6 Address Hidden %2d ",
- rinfo->metric);
- break;
- }
+ for (np = route_top(rip->table); np; np = route_next(np)) {
+ list = np->info;
- /* Route which exist in kernel routing table. */
- if ((rinfo->type == ZEBRA_ROUTE_RIP)
- && (rinfo->sub_type == RIP_ROUTE_RTE)) {
- vty_out(vty, "%-15pI4 ",
- &rinfo->from);
- vty_out(vty, "%3" ROUTE_TAG_PRI " ",
- (route_tag_t)rinfo->tag);
- rip_vty_out_uptime(vty, rinfo);
- } else if (rinfo->metric
- == RIP_METRIC_INFINITY) {
- vty_out(vty, "self ");
- vty_out(vty, "%3" ROUTE_TAG_PRI " ",
- (route_tag_t)rinfo->tag);
- rip_vty_out_uptime(vty, rinfo);
- } else {
- if (rinfo->external_metric) {
- len = vty_out(
- vty, "self (%s:%d)",
- zebra_route_string(
- rinfo->type),
- rinfo->external_metric);
- len = 16 - len;
- if (len > 0)
- vty_out(vty, "%*s", len,
- " ");
- } else
- vty_out(vty,
- "self ");
- vty_out(vty, "%3" ROUTE_TAG_PRI,
- (route_tag_t)rinfo->tag);
- }
+ if (!list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
+ int len;
- vty_out(vty, "\n");
+ len = vty_out(vty, "%c(%s) %pFX",
+ /* np->lock, For debugging. */
+ zebra_route_char(rinfo->type),
+ rip_route_type_print(rinfo->sub_type),
+ &np->p);
+
+ len = 24 - len;
+
+ if (len > 0)
+ vty_out(vty, "%*s", len, " ");
+
+ switch (rinfo->nh.type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ vty_out(vty, "%-20pI4 %2d ",
+ &rinfo->nh.gate.ipv4, rinfo->metric);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ vty_out(vty, "0.0.0.0 %2d ",
+ rinfo->metric);
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ vty_out(vty, "blackhole %2d ",
+ rinfo->metric);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ vty_out(vty, "V6 Address Hidden %2d ",
+ rinfo->metric);
+ break;
}
+
+ /* Route which exist in kernel routing table. */
+ if ((rinfo->type == ZEBRA_ROUTE_RIP) &&
+ (rinfo->sub_type == RIP_ROUTE_RTE)) {
+ vty_out(vty, "%-15pI4 ", &rinfo->from);
+ vty_out(vty, "%3" ROUTE_TAG_PRI " ",
+ (route_tag_t)rinfo->tag);
+ rip_vty_out_uptime(vty, rinfo);
+ } else if (rinfo->metric == RIP_METRIC_INFINITY) {
+ vty_out(vty, "self ");
+ vty_out(vty, "%3" ROUTE_TAG_PRI " ",
+ (route_tag_t)rinfo->tag);
+ rip_vty_out_uptime(vty, rinfo);
+ } else {
+ if (rinfo->external_metric) {
+ len = vty_out(
+ vty, "self (%s:%d)",
+ zebra_route_string(rinfo->type),
+ rinfo->external_metric);
+ len = 16 - len;
+ if (len > 0)
+ vty_out(vty, "%*s", len, " ");
+ } else
+ vty_out(vty, "self ");
+ vty_out(vty, "%3" ROUTE_TAG_PRI,
+ (route_tag_t)rinfo->tag);
+ }
+
+ vty_out(vty, "\n");
+ }
+ }
return CMD_SUCCESS;
}
vty_out(vty, " Routing for Networks:\n");
rip_show_network_config(vty, rip);
- {
- int found_passive = 0;
- FOR_ALL_INTERFACES (rip->vrf, ifp) {
- ri = ifp->info;
-
- if ((ri->enable_network || ri->enable_interface)
- && ri->passive) {
- if (!found_passive) {
- vty_out(vty,
- " Passive Interface(s):\n");
- found_passive = 1;
- }
- vty_out(vty, " %s\n", ifp->name);
+ int found_passive = 0;
+ FOR_ALL_INTERFACES (rip->vrf, ifp) {
+ ri = ifp->info;
+
+ if ((ri->enable_network || ri->enable_interface) &&
+ ri->passive) {
+ if (!found_passive) {
+ vty_out(vty, " Passive Interface(s):\n");
+ found_passive = 1;
}
+ vty_out(vty, " %s\n", ifp->name);
}
}
rip_zebra_ipv4_delete(rip, rp);
for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
- RIP_TIMER_OFF(rinfo->t_timeout);
- RIP_TIMER_OFF(rinfo->t_garbage_collect);
+ THREAD_OFF(rinfo->t_timeout);
+ THREAD_OFF(rinfo->t_garbage_collect);
rip_info_free(rinfo);
}
list_delete(&list);
rip_redistribute_disable(rip);
/* Cancel RIP related timers. */
- RIP_TIMER_OFF(rip->t_update);
- RIP_TIMER_OFF(rip->t_triggered_update);
- RIP_TIMER_OFF(rip->t_triggered_interval);
+ THREAD_OFF(rip->t_update);
+ THREAD_OFF(rip->t_triggered_update);
+ THREAD_OFF(rip->t_triggered_interval);
/* Cancel read thread. */
- thread_cancel(&rip->t_read);
+ THREAD_OFF(rip->t_read);
/* Close RIP socket. */
close(rip->sock);
static int rip_vrf_delete(struct vrf *vrf)
{
+ struct rip *rip;
+
if (IS_RIP_DEBUG_EVENT)
zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
vrf->vrf_id);
+ rip = rip_lookup_by_vrf_name(vrf->name);
+ if (!rip)
+ return 0;
+
+ rip_clean(rip);
+
return 0;
}
int socket;
rip = rip_lookup_by_vrf_name(vrf->name);
- if (!rip) {
- char *old_vrf_name = NULL;
-
- rip = (struct rip *)vrf->info;
- if (!rip)
- return 0;
- /* update vrf name */
- if (rip->vrf_name)
- old_vrf_name = rip->vrf_name;
- rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf->name);
- /*
- * HACK: Change the RIP VRF in the running configuration directly,
- * bypassing the northbound layer. This is necessary to avoid deleting
- * the RIP and readding it in the new VRF, which would have
- * several implications.
- */
- if (yang_module_find("frr-ripd") && old_vrf_name) {
- struct lyd_node *rip_dnode;
- char oldpath[XPATH_MAXLEN];
- char newpath[XPATH_MAXLEN];
-
- rip_dnode = yang_dnode_getf(
- running_config->dnode,
- "/frr-ripd:ripd/instance[vrf='%s']/vrf",
- old_vrf_name);
- if (rip_dnode) {
- yang_dnode_get_path(lyd_parent(rip_dnode),
- oldpath, sizeof(oldpath));
- yang_dnode_change_leaf(rip_dnode, vrf->name);
- yang_dnode_get_path(lyd_parent(rip_dnode),
- newpath, sizeof(newpath));
- nb_running_move_tree(oldpath, newpath);
- running_config->version++;
- }
- }
- XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
- }
if (!rip || rip->enabled)
return 0;
void rip_vrf_init(void)
{
- vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete,
- rip_vrf_enable);
+ vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete);
vrf_cmd_init(NULL);
}