diff options
Diffstat (limited to 'ripd/ripd.c')
| -rw-r--r-- | ripd/ripd.c | 225 |
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); } |
