summaryrefslogtreecommitdiff
path: root/ripd/ripd.c
diff options
context:
space:
mode:
Diffstat (limited to 'ripd/ripd.c')
-rw-r--r--ripd/ripd.c225
1 files changed, 138 insertions, 87 deletions
diff --git a/ripd/ripd.c b/ripd/ripd.c
index fb3d574aaa..e3220a9267 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -6,6 +6,11 @@
#include <zebra.h>
+#ifdef CRYPTO_OPENSSL
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#endif
+
#include "vrf.h"
#include "if.h"
#include "command.h"
@@ -29,11 +34,14 @@
#include "privs.h"
#include "lib_errors.h"
#include "northbound_cli.h"
+#include "mgmt_be_client.h"
#include "network.h"
#include "lib/printfrr.h"
+#include "frrdistance.h"
#include "ripd/ripd.h"
#include "ripd/rip_nb.h"
+#include "ripd/rip_bfd.h"
#include "ripd/rip_debug.h"
#include "ripd/rip_errors.h"
#include "ripd/rip_interface.h"
@@ -155,7 +163,10 @@ struct rip_info *rip_ecmp_add(struct rip *rip, struct rip_info *rinfo_new)
{
struct route_node *rp = rinfo_new->rp;
struct rip_info *rinfo = NULL;
+ struct rip_info *rinfo_exist = NULL;
struct list *list = NULL;
+ struct listnode *node = NULL;
+ struct listnode *nnode = NULL;
if (rp->info == NULL)
rp->info = list_new();
@@ -166,6 +177,33 @@ struct rip_info *rip_ecmp_add(struct rip *rip, struct rip_info *rinfo_new)
if (listcount(list) && !rip->ecmp)
return NULL;
+ /* Add or replace an existing ECMP path with lower neighbor IP */
+ if (listcount(list) && listcount(list) >= rip->ecmp) {
+ struct rip_info *from_highest = NULL;
+
+ /* Find the rip_info struct that has the highest nexthop IP */
+ for (ALL_LIST_ELEMENTS(list, node, nnode, rinfo_exist))
+ if (!from_highest ||
+ (from_highest &&
+ IPV4_ADDR_CMP(&rinfo_exist->from,
+ &from_highest->from) > 0)) {
+ from_highest = rinfo_exist;
+ }
+
+ /* If we have a route in ECMP group, delete the old
+ * one that has a higher next-hop address. Lower IP is
+ * preferred.
+ */
+ if (rip->ecmp > 1 && from_highest &&
+ IPV4_ADDR_CMP(&from_highest->from, &rinfo_new->from) > 0) {
+ rip_ecmp_delete(rip, from_highest);
+ goto add_or_replace;
+ }
+
+ return NULL;
+ }
+
+add_or_replace:
rinfo = rip_info_new();
memcpy(rinfo, rinfo_new, sizeof(struct rip_info));
listnode_add(list, rinfo);
@@ -372,7 +410,6 @@ static int rip_filter(int rip_distribute, struct prefix_ipv4 *p,
static int rip_nexthop_check(struct rip *rip, struct in_addr *addr)
{
struct interface *ifp;
- struct listnode *cnode;
struct connected *ifc;
struct prefix *p;
@@ -380,7 +417,7 @@ static int rip_nexthop_check(struct rip *rip, struct in_addr *addr)
invalid nexthop. */
FOR_ALL_INTERFACES (rip->vrf, ifp) {
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) {
+ frr_each (if_connected, ifp->connected, ifc) {
p = ifc->address;
if (p->family == AF_INET
@@ -1123,7 +1160,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
if (from->sin_port != htons(RIP_PORT_DEFAULT)) {
zlog_info("response doesn't come from RIP port: %d",
from->sin_port);
- rip_peer_bad_packet(rip, from);
+ rip_peer_bad_packet(rip, ri, from);
return;
}
@@ -1137,7 +1174,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
zlog_info(
"This datagram doesn't come from a valid neighbor: %pI4",
&from->sin_addr);
- rip_peer_bad_packet(rip, from);
+ rip_peer_bad_packet(rip, ri, from);
return;
}
@@ -1147,7 +1184,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
; /* Alredy done in rip_read () */
/* Update RIP peer. */
- rip_peer_update(rip, from, packet->version);
+ rip_peer_update(rip, ri, from, packet->version);
/* Set RTE pointer. */
rte = packet->rte;
@@ -1171,12 +1208,18 @@ static void rip_response_process(struct rip_packet *packet, int size,
continue;
}
+ if (packet->version == RIPv1 && rte->tag != 0) {
+ zlog_warn("RIPv1 reserved field is nonzero: %d",
+ ntohs(rte->tag));
+ continue;
+ }
+
/* - is the destination address valid (e.g., unicast; not net 0
or 127) */
if (!rip_destination_check(rte->prefix)) {
zlog_info(
"Network is net 0 or net 127 or it is not unicast network");
- rip_peer_bad_route(rip, from);
+ rip_peer_bad_route(rip, ri, from);
continue;
}
@@ -1186,7 +1229,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
/* - is the metric valid (i.e., between 1 and 16, inclusive) */
if (!(rte->metric >= 1 && rte->metric <= 16)) {
zlog_info("Route's metric is not in the 1-16 range.");
- rip_peer_bad_route(rip, from);
+ rip_peer_bad_route(rip, ri, from);
continue;
}
@@ -1195,7 +1238,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
&& rte->nexthop.s_addr != INADDR_ANY) {
zlog_info("RIPv1 packet with nexthop value %pI4",
&rte->nexthop);
- rip_peer_bad_route(rip, from);
+ rip_peer_bad_route(rip, ri, from);
continue;
}
@@ -1326,7 +1369,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
zlog_warn(
"RIPv2 address %pI4 is not mask /%d applied one",
&rte->prefix, ip_masklen(rte->mask));
- rip_peer_bad_route(rip, from);
+ rip_peer_bad_route(rip, ri, from);
continue;
}
@@ -1643,7 +1686,7 @@ static void rip_request_process(struct rip_packet *packet, int size,
return;
/* RIP peer update. */
- rip_peer_update(rip, from, packet->version);
+ rip_peer_update(rip, ri, from, packet->version);
lim = ((caddr_t)packet) + size;
rte = packet->rte;
@@ -1711,7 +1754,7 @@ static void rip_read(struct event *t)
socklen_t fromlen;
struct interface *ifp = NULL;
struct connected *ifc;
- struct rip_interface *ri;
+ struct rip_interface *ri = NULL;
struct prefix p;
/* Fetch socket then register myself. */
@@ -1743,8 +1786,10 @@ static void rip_read(struct event *t)
/* Which interface is this packet comes from. */
ifc = if_lookup_address((void *)&from.sin_addr, AF_INET,
rip->vrf->vrf_id);
- if (ifc)
+ if (ifc) {
ifp = ifc->ifp;
+ ri = ifp->info;
+ }
/* RIP packet received */
if (IS_RIP_DEBUG_EVENT)
@@ -1753,7 +1798,7 @@ static void rip_read(struct event *t)
ifp ? ifp->name : "unknown", rip->vrf_name);
/* If this packet come from unknown interface, ignore it. */
- if (ifp == NULL) {
+ if (ifp == NULL || ri == NULL) {
zlog_info(
"%s: cannot find interface for packet from %pI4 port %d (VRF %s)",
__func__, &from.sin_addr, ntohs(from.sin_port),
@@ -1779,13 +1824,13 @@ static void rip_read(struct event *t)
if (len < RIP_PACKET_MINSIZ) {
zlog_warn("packet size %d is smaller than minimum size %d", len,
RIP_PACKET_MINSIZ);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
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);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
@@ -1793,7 +1838,7 @@ static void rip_read(struct event *t)
if ((len - RIP_PACKET_MINSIZ) % 20) {
zlog_warn("packet size %d is wrong for RIP packet alignment",
len);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
@@ -1807,7 +1852,7 @@ static void rip_read(struct event *t)
if (packet->version == 0) {
zlog_info("version 0 with command %d received.",
packet->command);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
@@ -1823,12 +1868,11 @@ static void rip_read(struct event *t)
packet->version = RIPv2;
/* Is RIP running or is this RIP neighbor ?*/
- ri = ifp->info;
if (!ri->running && !rip_neighbor_lookup(rip, &from)) {
if (IS_RIP_DEBUG_EVENT)
zlog_debug("RIP is not enabled on interface %s.",
ifp->name);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
@@ -1842,7 +1886,7 @@ static void rip_read(struct event *t)
zlog_debug(
" packet's v%d doesn't fit to if version spec",
packet->version);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
@@ -1857,7 +1901,7 @@ static void rip_read(struct event *t)
"packet RIPv%d is dropped because authentication disabled",
packet->version);
ripd_notif_send_auth_type_failure(ifp->name);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
@@ -1893,7 +1937,7 @@ static void rip_read(struct event *t)
zlog_debug(
"RIPv1 dropped because authentication enabled");
ripd_notif_send_auth_type_failure(ifp->name);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
} else if (ri->auth_type != RIP_NO_AUTH) {
@@ -1906,7 +1950,7 @@ static void rip_read(struct event *t)
zlog_debug(
"RIPv2 authentication failed: no auth RTE in packet");
ripd_notif_send_auth_type_failure(ifp->name);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
@@ -1916,7 +1960,7 @@ static void rip_read(struct event *t)
zlog_debug(
"RIPv2 dropped because authentication enabled");
ripd_notif_send_auth_type_failure(ifp->name);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
@@ -1952,7 +1996,7 @@ static void rip_read(struct event *t)
zlog_debug("RIPv2 %s authentication failure",
auth_desc);
ripd_notif_send_auth_failure(ifp->name);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
return;
}
}
@@ -1971,16 +2015,16 @@ static void rip_read(struct event *t)
zlog_info(
"Obsolete command %s received, please sent it to routed",
lookup_msg(rip_msg, packet->command, NULL));
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
break;
case RIP_POLL_ENTRY:
zlog_info("Obsolete command %s received",
lookup_msg(rip_msg, packet->command, NULL));
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
break;
default:
zlog_info("Unknown RIP command %d received", packet->command);
- rip_peer_bad_packet(rip, &from);
+ rip_peer_bad_packet(rip, ri, &from);
break;
}
}
@@ -2174,8 +2218,8 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
}
if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT) {
- for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected,
- listnode, tmp_ifc))
+ frr_each (if_connected, ifc->ifp->connected,
+ tmp_ifc)
if (prefix_match((struct prefix *)p,
tmp_ifc->address)) {
suppress = 1;
@@ -2284,8 +2328,8 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
if (rinfo->metric_out != RIP_METRIC_INFINITY &&
rinfo->type == ZEBRA_ROUTE_CONNECT) {
- for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected,
- listnode, tmp_ifc))
+ frr_each (if_connected, ifc->ifp->connected,
+ tmp_ifc)
if (prefix_match((struct prefix *)p,
tmp_ifc->address)) {
rinfo->metric_out =
@@ -2398,7 +2442,6 @@ static void rip_update_interface(struct connected *ifc, uint8_t version,
/* Update send to all interface and neighbor. */
static void rip_update_process(struct rip *rip, int route_type)
{
- struct listnode *ifnode, *ifnnode;
struct connected *connected;
struct interface *ifp;
struct rip_interface *ri;
@@ -2437,8 +2480,7 @@ static void rip_update_process(struct rip *rip, int route_type)
ifp->ifindex);
/* send update on each connected network */
- for (ALL_LIST_ELEMENTS(ifp->connected, ifnode, ifnnode,
- connected)) {
+ frr_each (if_connected, ifp->connected, connected) {
if (connected->address->family == AF_INET) {
if (vsend & RIPv1)
rip_update_interface(connected, RIPv1,
@@ -2624,6 +2666,36 @@ struct rip *rip_lookup_by_vrf_name(const char *vrf_name)
return RB_FIND(rip_instance_head, &rip_instances, &rip);
}
+/* Update ECMP routes to zebra when `allow-ecmp` changed. */
+void rip_ecmp_change(struct rip *rip)
+{
+ struct route_node *rp;
+ struct rip_info *rinfo;
+ struct list *list;
+ struct listnode *node, *nextnode;
+
+ for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
+ list = rp->info;
+ if (list && listcount(list) > 1) {
+ while (listcount(list) > rip->ecmp) {
+ struct rip_info *from_highest = NULL;
+
+ for (ALL_LIST_ELEMENTS(list, node, nextnode,
+ rinfo)) {
+ if (!from_highest ||
+ (from_highest &&
+ IPV4_ADDR_CMP(
+ &rinfo->from,
+ &from_highest->from) > 0))
+ from_highest = rinfo;
+ }
+
+ rip_ecmp_delete(rip, from_highest);
+ }
+ }
+ }
+}
+
/* Create new RIP instance and set it to global variable. */
struct rip *rip_create(const char *vrf_name, struct vrf *vrf, int socket)
{
@@ -2633,7 +2705,7 @@ struct rip *rip_create(const char *vrf_name, struct vrf *vrf, int socket)
rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf_name);
/* Set initial value. */
- rip->ecmp = yang_get_default_bool("%s/allow-ecmp", RIP_INSTANCE);
+ rip->ecmp = yang_get_default_uint8("%s/allow-ecmp", RIP_INSTANCE);
rip->default_metric =
yang_get_default_uint8("%s/default-metric", RIP_INSTANCE);
rip->distance =
@@ -2699,7 +2771,6 @@ int rip_request_send(struct sockaddr_in *to, struct interface *ifp,
{
struct rte *rte;
struct rip_packet rip_packet;
- struct listnode *node, *nnode;
memset(&rip_packet, 0, sizeof(rip_packet));
@@ -2723,7 +2794,7 @@ int rip_request_send(struct sockaddr_in *to, struct interface *ifp,
}
/* send request on each connected network */
- for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) {
+ frr_each (if_connected, ifp->connected, connected) {
struct prefix_ipv4 *p;
p = (struct prefix_ipv4 *)connected->address;
@@ -3183,45 +3254,38 @@ DEFUN (show_ip_rip_status,
return CMD_SUCCESS;
}
-/* RIP configuration write function. */
-static int config_write_rip(struct vty *vty)
-{
- struct rip *rip;
- int write = 0;
-
- RB_FOREACH(rip, rip_instance_head, &rip_instances) {
- char xpath[XPATH_MAXLEN];
- struct lyd_node *dnode;
+#include "ripd/ripd_clippy.c"
- snprintf(xpath, sizeof(xpath),
- "/frr-ripd:ripd/instance[vrf='%s']", rip->vrf_name);
+/*
+ * XPath: /frr-ripd:clear-rip-route
+ */
+DEFPY_YANG (clear_ip_rip,
+ clear_ip_rip_cmd,
+ "clear ip rip [vrf WORD]",
+ CLEAR_STR
+ IP_STR
+ "Clear IP RIP database\n"
+ VRF_CMD_HELP_STR)
+{
+ struct list *input;
+ int ret;
- dnode = yang_dnode_get(running_config->dnode, xpath);
- assert(dnode);
+ input = list_new();
+ if (vrf) {
+ struct yang_data *yang_vrf;
- nb_cli_show_dnode_cmds(vty, dnode, false);
+ yang_vrf = yang_data_new("/frr-ripd:clear-rip-route/input/vrf",
+ vrf);
+ listnode_add(input, yang_vrf);
+ }
- /* Distribute configuration. */
- config_write_distribute(vty, rip->distribute_ctx);
+ ret = nb_cli_rpc(vty, "/frr-ripd:clear-rip-route", input, NULL);
- vty_out(vty, "exit\n");
+ list_delete(&input);
- write = 1;
- }
-
- return write;
+ return ret;
}
-static int config_write_rip(struct vty *vty);
-/* RIP node structure. */
-static struct cmd_node rip_node = {
- .name = "rip",
- .node = RIP_NODE,
- .parent_node = CONFIG_NODE,
- .prompt = "%s(config-router)# ",
- .config_write = config_write_rip,
-};
-
/* Distribute-list update functions. */
static void rip_distribute_update(struct distribute_ctx *ctx,
struct distribute *dist)
@@ -3339,6 +3403,7 @@ void rip_clean(struct rip *rip)
route_table_finish(rip->distance_table);
RB_REMOVE(rip_instance_head, &rip_instances, rip);
+ XFREE(MTYPE_RIP_BFD_PROFILE, rip->default_bfd_profile);
XFREE(MTYPE_RIP_VRF_NAME, rip->vrf_name);
XFREE(MTYPE_RIP, rip);
}
@@ -3528,18 +3593,10 @@ static int rip_vrf_new(struct vrf *vrf)
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;
}
@@ -3590,8 +3647,6 @@ static int rip_vrf_disable(struct vrf *vrf)
void rip_vrf_init(void)
{
vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete);
-
- vrf_cmd_init(NULL);
}
void rip_vrf_terminate(void)
@@ -3602,20 +3657,18 @@ void rip_vrf_terminate(void)
/* Allocate new rip structure and set default value. */
void rip_init(void)
{
- /* Install top nodes. */
- install_node(&rip_node);
-
/* Install rip commands. */
install_element(VIEW_NODE, &show_ip_rip_cmd);
install_element(VIEW_NODE, &show_ip_rip_status_cmd);
-
- install_default(RIP_NODE);
+ install_element(ENABLE_NODE, &clear_ip_rip_cmd);
/* Debug related init. */
rip_debug_init();
+ /* Enable mgmt be debug */
+ mgmt_be_client_lib_vty_init();
/* Access list install. */
- access_list_init();
+ access_list_init_new(true);
access_list_add_hook(rip_distribute_update_all_wrapper);
access_list_delete_hook(rip_distribute_update_all_wrapper);
@@ -3629,6 +3682,4 @@ void rip_init(void)
route_map_add_hook(rip_routemap_update);
route_map_delete_hook(rip_routemap_update);
-
- if_rmap_init(RIP_NODE);
}