2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIP version 1 and 2.
|
2005-09-29 13:25:50 +02:00
|
|
|
* Copyright (C) 2005 6WIND <alain.ritoux@6wind.com>
|
2002-12-13 21:15:29 +01:00
|
|
|
* Copyright (C) 1997, 98, 99 Kunihiro Ishiguro <kunihiro@zebra.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
2024-01-04 20:02:34 +01:00
|
|
|
#ifdef CRYPTO_OPENSSL
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/hmac.h>
|
|
|
|
#endif
|
|
|
|
|
2016-04-08 15:16:14 +02:00
|
|
|
#include "vrf.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "if.h"
|
|
|
|
#include "command.h"
|
|
|
|
#include "prefix.h"
|
|
|
|
#include "table.h"
|
2023-03-07 20:22:48 +01:00
|
|
|
#include "frrevent.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "memory.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "stream.h"
|
|
|
|
#include "filter.h"
|
|
|
|
#include "sockunion.h"
|
2004-09-26 18:11:14 +02:00
|
|
|
#include "sockopt.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "routemap.h"
|
2003-05-25 16:49:19 +02:00
|
|
|
#include "if_rmap.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "plist.h"
|
|
|
|
#include "distribute.h"
|
2019-07-11 11:28:15 +02:00
|
|
|
#ifdef CRYPTO_INTERNAL
|
2005-09-28 17:47:44 +02:00
|
|
|
#include "md5.h"
|
2019-07-11 11:28:15 +02:00
|
|
|
#endif
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "keychain.h"
|
2003-06-04 15:59:38 +02:00
|
|
|
#include "privs.h"
|
2018-06-18 15:50:29 +02:00
|
|
|
#include "lib_errors.h"
|
2018-05-09 06:34:58 +02:00
|
|
|
#include "northbound_cli.h"
|
2024-01-19 17:40:12 +01:00
|
|
|
#include "mgmt_be_client.h"
|
2020-04-17 15:35:15 +02:00
|
|
|
#include "network.h"
|
2020-10-22 20:16:33 +02:00
|
|
|
#include "lib/printfrr.h"
|
2023-11-04 09:47:46 +01:00
|
|
|
#include "frrdistance.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
#include "ripd/ripd.h"
|
2019-10-17 20:46:54 +02:00
|
|
|
#include "ripd/rip_nb.h"
|
2023-05-08 16:07:54 +02:00
|
|
|
#include "ripd/rip_bfd.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
#include "ripd/rip_debug.h"
|
2018-06-19 22:13:45 +02:00
|
|
|
#include "ripd/rip_errors.h"
|
2019-01-04 22:08:10 +01:00
|
|
|
#include "ripd/rip_interface.h"
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2004-09-17 10:39:08 +02:00
|
|
|
/* UDP receive buffer size */
|
|
|
|
#define RIP_UDP_RCV_BUF 41600
|
|
|
|
|
2019-06-21 08:39:33 +02:00
|
|
|
DEFINE_MGROUP(RIPD, "ripd");
|
|
|
|
DEFINE_MTYPE_STATIC(RIPD, RIP, "RIP structure");
|
|
|
|
DEFINE_MTYPE_STATIC(RIPD, RIP_VRF_NAME, "RIP VRF name");
|
|
|
|
DEFINE_MTYPE_STATIC(RIPD, RIP_INFO, "RIP route info");
|
|
|
|
DEFINE_MTYPE_STATIC(RIPD, RIP_DISTANCE, "RIP distance");
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Prototypes. */
|
2005-10-26 01:31:05 +02:00
|
|
|
static void rip_output_process(struct connected *, struct sockaddr_in *, int,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t);
|
2022-03-01 22:18:12 +01:00
|
|
|
static void rip_triggered_update(struct event *);
|
2005-10-26 01:31:05 +02:00
|
|
|
static int rip_update_jitter(unsigned long);
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_distance_table_node_cleanup(struct route_table *table,
|
|
|
|
struct route_node *node);
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_instance_enable(struct rip *rip, struct vrf *vrf, int sock);
|
|
|
|
static void rip_instance_disable(struct rip *rip);
|
2014-06-04 06:53:35 +02:00
|
|
|
|
lib, rip, ripng, babel, eigrp: add ctx pointer to distribute api
a distribute_ctx context pointer is returned after initialisation to the
calling daemon. this context pointer will be further used to do
discussion with distribute service. Today, there is no specific problem
with old api, since the pointer is the same in all the memory process.
but the pointer will be different if we have multiple instances. Right
now, this is not the case, but if that happens, that work will be used
for that.
distribute-list initialisation is split in two. the vty initialisation
is done at global level, while the context initialisation is done for
each routing daemon instance.
babel daemon is being equipped with a routing returning the main babel
instance.
also, a delete routine is available when the daemon routing instance is
suppressed.
a list of contexts is used inside distribute_list. This will permit
distribute_list utility to handle in the same daemon to handle more than
one context. This will be very useful in the vrf context.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2018-12-04 15:45:57 +01:00
|
|
|
static void rip_distribute_update(struct distribute_ctx *ctx,
|
|
|
|
struct distribute *dist);
|
|
|
|
|
2019-01-14 08:58:36 +01:00
|
|
|
static void rip_if_rmap_update(struct if_rmap_ctx *ctx,
|
|
|
|
struct if_rmap *if_rmap);
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIP output routes type. */
|
|
|
|
enum { rip_all_route, rip_changed_route };
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIP command strings. */
|
2008-08-14 18:59:25 +02:00
|
|
|
static const struct message rip_msg[] = {{RIP_REQUEST, "REQUEST"},
|
2002-12-13 21:15:29 +01:00
|
|
|
{RIP_RESPONSE, "RESPONSE"},
|
|
|
|
{RIP_TRACEON, "TRACEON"},
|
|
|
|
{RIP_TRACEOFF, "TRACEOFF"},
|
|
|
|
{RIP_POLL, "POLL"},
|
|
|
|
{RIP_POLL_ENTRY, "POLL ENTRY"},
|
|
|
|
{0}};
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Generate rb-tree of RIP instances. */
|
|
|
|
static inline int rip_instance_compare(const struct rip *a, const struct rip *b)
|
|
|
|
{
|
|
|
|
return strcmp(a->vrf_name, b->vrf_name);
|
|
|
|
}
|
|
|
|
RB_GENERATE(rip_instance_head, rip, entry, rip_instance_compare)
|
|
|
|
|
|
|
|
struct rip_instance_head rip_instances = RB_INITIALIZER(&rip_instances);
|
|
|
|
|
2021-09-07 05:35:16 +02:00
|
|
|
/* Utility function to set broadcast option to the socket. */
|
2002-12-13 21:15:29 +01:00
|
|
|
static int sockopt_broadcast(int sock)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int on = 1;
|
|
|
|
|
|
|
|
ret = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
|
2020-03-08 20:43:26 +01:00
|
|
|
sizeof(on));
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
zlog_warn("can't set sockopt SO_BROADCAST to socket %d", sock);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-09 06:35:04 +02:00
|
|
|
int rip_route_rte(struct rip_info *rinfo)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
return (rinfo->type == ZEBRA_ROUTE_RIP
|
|
|
|
&& rinfo->sub_type == RIP_ROUTE_RTE);
|
|
|
|
}
|
|
|
|
|
2005-10-26 01:31:05 +02:00
|
|
|
static struct rip_info *rip_info_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2008-08-18 23:13:29 +02:00
|
|
|
return XCALLOC(MTYPE_RIP_INFO, sizeof(struct rip_info));
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void rip_info_free(struct rip_info *rinfo)
|
|
|
|
{
|
|
|
|
XFREE(MTYPE_RIP_INFO, rinfo);
|
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip_info_get_instance(const struct rip_info *rinfo)
|
|
|
|
{
|
|
|
|
return route_table_get_info(rinfo->rp->table);
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIP route garbage collect timer. */
|
2022-03-01 22:18:12 +01:00
|
|
|
static void rip_garbage_collect(struct event *t)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct rip_info *rinfo;
|
|
|
|
struct route_node *rp;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
rinfo = EVENT_ARG(t);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Off timeout timer. */
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_timeout);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Get route_node pointer. */
|
|
|
|
rp = rinfo->rp;
|
|
|
|
|
|
|
|
/* Unlock route_node. */
|
2014-07-18 08:13:18 +02:00
|
|
|
listnode_delete(rp->info, rinfo);
|
|
|
|
if (list_isempty((struct list *)rp->info)) {
|
2018-10-02 11:39:51 +02:00
|
|
|
list_delete((struct list **)&rp->info);
|
2014-07-18 08:13:18 +02:00
|
|
|
route_unlock_node(rp);
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Free RIP routing information. */
|
|
|
|
rip_info_free(rinfo);
|
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo);
|
2014-07-18 08:13:18 +02:00
|
|
|
|
|
|
|
/* Add new route to the ECMP list.
|
2014-07-18 08:13:19 +02:00
|
|
|
* RETURN: the new entry added in the list, or NULL if it is not the first
|
|
|
|
* entry and ECMP is not allowed.
|
2014-07-18 08:13:18 +02:00
|
|
|
*/
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip_info *rip_ecmp_add(struct rip *rip, struct rip_info *rinfo_new)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2014-07-18 08:13:18 +02:00
|
|
|
struct route_node *rp = rinfo_new->rp;
|
|
|
|
struct rip_info *rinfo = NULL;
|
2023-05-04 08:13:07 +02:00
|
|
|
struct rip_info *rinfo_exist = NULL;
|
2014-07-18 08:13:18 +02:00
|
|
|
struct list *list = NULL;
|
2023-05-04 08:13:07 +02:00
|
|
|
struct listnode *node = NULL;
|
|
|
|
struct listnode *nnode = NULL;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if (rp->info == NULL)
|
|
|
|
rp->info = list_new();
|
|
|
|
list = (struct list *)rp->info;
|
|
|
|
|
2014-07-18 08:13:19 +02:00
|
|
|
/* If ECMP is not allowed and some entry already exists in the list,
|
|
|
|
* do nothing. */
|
|
|
|
if (listcount(list) && !rip->ecmp)
|
|
|
|
return NULL;
|
|
|
|
|
2023-05-04 08:13:07 +02:00
|
|
|
/* 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:
|
2014-07-18 08:13:18 +02:00
|
|
|
rinfo = rip_info_new();
|
|
|
|
memcpy(rinfo, rinfo_new, sizeof(struct rip_info));
|
|
|
|
listnode_add(list, rinfo);
|
|
|
|
|
|
|
|
if (rip_route_rte(rinfo)) {
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_timeout_update(rip, rinfo);
|
|
|
|
rip_zebra_ipv4_add(rip, rp);
|
2014-07-18 08:13:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the route change flag on the first entry. */
|
|
|
|
rinfo = listgetdata(listhead(list));
|
|
|
|
SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
|
|
|
|
|
|
|
|
/* Signal the output process to trigger an update (see section 2.5). */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
return rinfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Replace the ECMP list with the new route.
|
|
|
|
* RETURN: the new entry added in the list
|
|
|
|
*/
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip_info *rip_ecmp_replace(struct rip *rip, struct rip_info *rinfo_new)
|
2014-07-18 08:13:18 +02:00
|
|
|
{
|
|
|
|
struct route_node *rp = rinfo_new->rp;
|
|
|
|
struct list *list = (struct list *)rp->info;
|
|
|
|
struct rip_info *rinfo = NULL, *tmp_rinfo = NULL;
|
|
|
|
struct listnode *node = NULL, *nextnode = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if (list == NULL || listcount(list) == 0)
|
2019-01-04 22:08:10 +01:00
|
|
|
return rip_ecmp_add(rip, rinfo_new);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
/* Get the first entry */
|
|
|
|
rinfo = listgetdata(listhead(list));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
/* Learnt route replaced by a local one. Delete it from zebra. */
|
|
|
|
if (rip_route_rte(rinfo) && !rip_route_rte(rinfo_new))
|
|
|
|
if (CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_zebra_ipv4_delete(rip, rp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
/* Re-use the first entry, and delete the others. */
|
2022-02-16 14:05:34 +01:00
|
|
|
for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) {
|
|
|
|
if (tmp_rinfo == rinfo)
|
|
|
|
continue;
|
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(tmp_rinfo->t_timeout);
|
|
|
|
EVENT_OFF(tmp_rinfo->t_garbage_collect);
|
2022-02-16 14:05:34 +01:00
|
|
|
list_delete_node(list, node);
|
|
|
|
rip_info_free(tmp_rinfo);
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_timeout);
|
|
|
|
EVENT_OFF(rinfo->t_garbage_collect);
|
2014-07-18 08:13:18 +02:00
|
|
|
memcpy(rinfo, rinfo_new, sizeof(struct rip_info));
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if (rip_route_rte(rinfo)) {
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_timeout_update(rip, rinfo);
|
2014-07-18 08:13:18 +02:00
|
|
|
/* The ADD message implies an update. */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_zebra_ipv4_add(rip, rp);
|
2014-07-18 08:13:18 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
/* Set the route change flag. */
|
|
|
|
SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
/* Signal the output process to trigger an update (see section 2.5). */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
return rinfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete one route from the ECMP list.
|
|
|
|
* RETURN:
|
|
|
|
* null - the entry is freed, and other entries exist in the list
|
|
|
|
* the entry - the entry is the last one in the list; its metric is set
|
|
|
|
* to INFINITY, and the garbage collector is started for it
|
|
|
|
*/
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip_info *rip_ecmp_delete(struct rip *rip, struct rip_info *rinfo)
|
2014-07-18 08:13:18 +02:00
|
|
|
{
|
|
|
|
struct route_node *rp = rinfo->rp;
|
|
|
|
struct list *list = (struct list *)rp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_timeout);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if (listcount(list) > 1) {
|
|
|
|
/* Some other ECMP entries still exist. Just delete this entry.
|
|
|
|
*/
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_garbage_collect);
|
2014-07-18 08:13:18 +02:00
|
|
|
listnode_delete(list, rinfo);
|
|
|
|
if (rip_route_rte(rinfo)
|
|
|
|
&& CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
|
|
|
|
/* The ADD message implies the update. */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_zebra_ipv4_add(rip, rp);
|
2014-07-18 08:13:18 +02:00
|
|
|
rip_info_free(rinfo);
|
|
|
|
rinfo = NULL;
|
|
|
|
} else {
|
|
|
|
assert(rinfo == listgetdata(listhead(list)));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
/* This is the only entry left in the list. We must keep it in
|
|
|
|
* the list for garbage collection time, with INFINITY metric.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
rinfo->metric = RIP_METRIC_INFINITY;
|
|
|
|
RIP_TIMER_ON(rinfo->t_garbage_collect, rip_garbage_collect,
|
|
|
|
rip->garbage_time);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if (rip_route_rte(rinfo)
|
|
|
|
&& CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_zebra_ipv4_delete(rip, rp);
|
2014-07-18 08:13:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the route change flag on the first entry. */
|
|
|
|
rinfo = listgetdata(listhead(list));
|
|
|
|
SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
|
|
|
|
|
|
|
|
/* Signal the output process to trigger an update (see section 2.5). */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
|
2014-07-18 08:13:18 +02:00
|
|
|
|
|
|
|
return rinfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Timeout RIP routes. */
|
2022-03-01 22:18:12 +01:00
|
|
|
static void rip_timeout(struct event *t)
|
2014-07-18 08:13:18 +02:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct rip_info *rinfo = EVENT_ARG(t);
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip = rip_info_get_instance(rinfo);
|
|
|
|
|
|
|
|
rip_ecmp_delete(rip, rinfo);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-09-22 23:11:05 +02:00
|
|
|
if (rinfo->metric != RIP_METRIC_INFINITY) {
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_timeout);
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, rip_timeout, rinfo, rip->timeout_time,
|
|
|
|
&rinfo->t_timeout);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 23:11:05 +02:00
|
|
|
static int rip_filter(int rip_distribute, struct prefix_ipv4 *p,
|
2002-12-13 21:15:29 +01:00
|
|
|
struct rip_interface *ri)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2002-12-13 21:15:29 +01:00
|
|
|
struct distribute *dist;
|
2016-09-22 23:11:05 +02:00
|
|
|
struct access_list *alist;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct prefix_list *plist;
|
|
|
|
int distribute = rip_distribute == RIP_FILTER_OUT ? DISTRIBUTE_V4_OUT
|
|
|
|
: DISTRIBUTE_V4_IN;
|
2016-09-22 23:11:05 +02:00
|
|
|
const char *inout = rip_distribute == RIP_FILTER_OUT ? "out" : "in";
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Input distribute-list filtering. */
|
2022-02-16 14:05:34 +01:00
|
|
|
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;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
|
|
|
|
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;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* All interface filter check. */
|
2019-01-04 22:08:10 +01:00
|
|
|
dist = distribute_lookup(ri->rip->distribute_ctx, NULL);
|
2022-02-16 14:05:34 +01:00
|
|
|
if (!dist)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
}
|
|
|
|
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;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check nexthop address validity. */
|
2019-01-04 22:08:10 +01:00
|
|
|
static int rip_nexthop_check(struct rip *rip, struct in_addr *addr)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
struct connected *ifc;
|
|
|
|
struct prefix *p;
|
|
|
|
|
|
|
|
/* If nexthop address matches local configured address then it is
|
|
|
|
invalid nexthop. */
|
2016-04-08 15:16:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
FOR_ALL_INTERFACES (rip->vrf, ifp) {
|
2023-11-22 19:05:41 +01:00
|
|
|
frr_each (if_connected, ifp->connected, ifc) {
|
2002-12-13 21:15:29 +01:00
|
|
|
p = ifc->address;
|
|
|
|
|
|
|
|
if (p->family == AF_INET
|
|
|
|
&& IPV4_ADDR_SAME(&p->u.prefix4, addr))
|
|
|
|
return -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RIP add route to routing table. */
|
|
|
|
static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
|
|
|
|
struct interface *ifp)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip;
|
2003-05-25 16:49:19 +02:00
|
|
|
int ret;
|
2004-05-03 22:00:17 +02:00
|
|
|
struct prefix_ipv4 p;
|
|
|
|
struct route_node *rp;
|
|
|
|
struct rip_info *rinfo = NULL, newinfo;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct rip_interface *ri;
|
2004-12-08 20:24:06 +01:00
|
|
|
struct in_addr *nexthop;
|
2014-07-18 08:13:18 +02:00
|
|
|
int same = 0;
|
|
|
|
unsigned char old_dist, new_dist;
|
|
|
|
struct list *list = NULL;
|
|
|
|
struct listnode *node = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
/* Make prefix structure. */
|
2005-09-29 13:25:50 +02:00
|
|
|
memset(&p, 0, sizeof(struct prefix_ipv4));
|
2013-02-28 22:17:00 +01:00
|
|
|
p.family = AF_INET;
|
2004-05-03 22:00:17 +02:00
|
|
|
p.prefix = rte->prefix;
|
2002-12-13 21:15:29 +01:00
|
|
|
p.prefixlen = ip_masklen(rte->mask);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Make sure mask is applied. */
|
2014-07-18 08:13:18 +02:00
|
|
|
apply_mask_ipv4(&p);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
ri = ifp->info;
|
2019-01-04 22:08:10 +01:00
|
|
|
rip = ri->rip;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Apply input filters. */
|
2004-10-08 08:36:38 +02:00
|
|
|
ret = rip_filter(RIP_FILTER_IN, &p, ri);
|
|
|
|
if (ret < 0)
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
|
2004-10-08 08:36:38 +02:00
|
|
|
memset(&newinfo, 0, sizeof(newinfo));
|
2002-12-13 21:15:29 +01:00
|
|
|
newinfo.type = ZEBRA_ROUTE_RIP;
|
|
|
|
newinfo.sub_type = RIP_ROUTE_RTE;
|
2017-11-15 15:50:32 +01:00
|
|
|
newinfo.nh.gate.ipv4 = rte->nexthop;
|
2004-10-08 08:36:38 +02:00
|
|
|
newinfo.from = from->sin_addr;
|
2017-11-15 15:50:32 +01:00
|
|
|
newinfo.nh.ifindex = ifp->ifindex;
|
|
|
|
newinfo.nh.type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
2002-12-13 21:15:29 +01:00
|
|
|
newinfo.metric = rte->metric;
|
2014-07-18 08:13:18 +02:00
|
|
|
newinfo.metric_out = rte->metric; /* XXX */
|
2002-12-13 21:15:29 +01:00
|
|
|
newinfo.tag = ntohs(rte->tag); /* XXX */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Modify entry according to the interface routemap. */
|
|
|
|
if (ri->routemap[RIP_FILTER_IN]) {
|
|
|
|
/* The object should be of the type of rip_info */
|
2017-06-21 01:56:50 +02:00
|
|
|
ret = route_map_apply(ri->routemap[RIP_FILTER_IN],
|
2020-11-14 01:35:20 +01:00
|
|
|
(struct prefix *)&p, &newinfo);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ret == RMAP_DENYMATCH) {
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2020-10-22 20:16:33 +02:00
|
|
|
"RIP %pFX is filtered by route-map in",
|
|
|
|
&p);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Get back the object */
|
|
|
|
rte->nexthop = newinfo.nexthop_out;
|
|
|
|
rte->tag = htons(newinfo.tag_out); /* XXX */
|
2017-07-22 14:52:33 +02:00
|
|
|
rte->metric = newinfo.metric_out; /* XXX: the routemap uses the
|
|
|
|
metric_out field */
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Once the entry has been validated, update the metric by
|
2021-09-07 05:35:16 +02:00
|
|
|
adding the cost of the network on which the message
|
2002-12-13 21:15:29 +01:00
|
|
|
arrived. If the result is greater than infinity, use infinity
|
|
|
|
(RFC2453 Sec. 3.9.2) */
|
|
|
|
/* Zebra ripd can handle offset-list in. */
|
|
|
|
ret = rip_offset_list_apply_in(&p, ifp, &rte->metric);
|
|
|
|
|
2004-06-07 00:06:33 +02:00
|
|
|
/* If offset-list does not modify the metric use interface's
|
2002-12-13 21:15:29 +01:00
|
|
|
metric. */
|
2004-06-07 00:06:33 +02:00
|
|
|
if (!ret)
|
|
|
|
rte->metric += ifp->metric ? ifp->metric : 1;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
if (rte->metric > RIP_METRIC_INFINITY)
|
2002-12-13 21:15:29 +01:00
|
|
|
rte->metric = RIP_METRIC_INFINITY;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
/* Set nexthop pointer. */
|
2020-12-14 20:01:31 +01:00
|
|
|
if (rte->nexthop.s_addr == INADDR_ANY)
|
2002-12-13 21:15:29 +01:00
|
|
|
nexthop = &from->sin_addr;
|
2004-12-08 20:24:06 +01:00
|
|
|
else
|
2002-12-13 21:15:29 +01:00
|
|
|
nexthop = &rte->nexthop;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
/* Check if nexthop address is myself, then do nothing. */
|
2019-01-04 22:08:10 +01:00
|
|
|
if (rip_nexthop_check(rip, nexthop) < 0) {
|
2004-05-03 22:00:17 +02:00
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_debug("Nexthop address %pI4 is myself",
|
|
|
|
nexthop);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
/* Get index for the prefix. */
|
2002-12-13 21:15:29 +01:00
|
|
|
rp = route_node_get(rip->table, (struct prefix *)&p);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
newinfo.rp = rp;
|
2017-11-15 15:50:32 +01:00
|
|
|
newinfo.nh.gate.ipv4 = *nexthop;
|
|
|
|
newinfo.nh.type = NEXTHOP_TYPE_IPV4;
|
2002-12-13 21:15:29 +01:00
|
|
|
newinfo.metric = rte->metric;
|
|
|
|
newinfo.tag = ntohs(rte->tag);
|
2019-01-04 22:08:10 +01:00
|
|
|
newinfo.distance = rip_distance_apply(rip, &newinfo);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
new_dist = newinfo.distance ? newinfo.distance
|
2002-12-13 21:15:29 +01:00
|
|
|
: ZEBRA_RIP_DISTANCE_DEFAULT;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Check to see whether there is already RIP route on the table. */
|
2014-07-18 08:13:18 +02:00
|
|
|
if ((list = rp->info) != NULL)
|
2002-12-13 21:15:29 +01:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(list, node, rinfo)) {
|
2014-07-18 08:13:18 +02:00
|
|
|
/* Need to compare with redistributed entry or local
|
|
|
|
* entry */
|
|
|
|
if (!rip_route_rte(rinfo))
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IPV4_ADDR_SAME(&rinfo->from, &from->sin_addr)
|
2017-11-15 15:50:32 +01:00
|
|
|
&& IPV4_ADDR_SAME(&rinfo->nh.gate.ipv4, nexthop))
|
2017-07-17 14:03:14 +02:00
|
|
|
break;
|
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (listnextnode(node))
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* Not found in the list */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (rte->metric > rinfo->metric) {
|
|
|
|
/* New route has a greater metric.
|
|
|
|
* Discard it. */
|
|
|
|
route_unlock_node(rp);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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
|
2014-07-18 08:13:18 +02:00
|
|
|
: ZEBRA_RIP_DISTANCE_DEFAULT;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (new_dist > old_dist) {
|
|
|
|
/* New route has a greater distance.
|
|
|
|
* Discard it. */
|
|
|
|
route_unlock_node(rp);
|
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (new_dist < old_dist)
|
|
|
|
/* New route has a smaller distance.
|
|
|
|
* Replace the ECMP list
|
|
|
|
* with the new one in below. */
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* Metrics and distances are both same. Keep
|
|
|
|
* "rinfo" null and
|
|
|
|
* the new route is added in the ECMP list in
|
|
|
|
* below. */
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-06-07 00:06:33 +02:00
|
|
|
if (rinfo) {
|
|
|
|
/* Local static route. */
|
|
|
|
if (rinfo->type == ZEBRA_ROUTE_RIP
|
2002-12-13 21:15:29 +01:00
|
|
|
&& ((rinfo->sub_type == RIP_ROUTE_STATIC)
|
|
|
|
|| (rinfo->sub_type == RIP_ROUTE_DEFAULT))
|
|
|
|
&& rinfo->metric != RIP_METRIC_INFINITY) {
|
2004-12-08 20:24:06 +01:00
|
|
|
route_unlock_node(rp);
|
2004-06-07 00:06:33 +02:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-09-29 13:25:50 +02:00
|
|
|
/* Redistributed route check. */
|
2004-06-07 00:06:33 +02:00
|
|
|
if (rinfo->type != ZEBRA_ROUTE_RIP
|
2002-12-13 21:15:29 +01:00
|
|
|
&& rinfo->metric != RIP_METRIC_INFINITY) {
|
|
|
|
old_dist = rinfo->distance;
|
2004-12-08 20:24:06 +01:00
|
|
|
/* Only routes directly connected to an interface
|
|
|
|
* (nexthop == 0)
|
|
|
|
* may have a valid NULL distance */
|
2020-12-14 20:01:31 +01:00
|
|
|
if (rinfo->nh.gate.ipv4.s_addr != INADDR_ANY)
|
2006-01-30 19:12:42 +01:00
|
|
|
old_dist = old_dist
|
|
|
|
? old_dist
|
2002-12-13 21:15:29 +01:00
|
|
|
: ZEBRA_RIP_DISTANCE_DEFAULT;
|
|
|
|
/* If imported route does not have STRICT precedence,
|
|
|
|
mark it as a ghost */
|
|
|
|
if (new_dist <= old_dist
|
|
|
|
&& rte->metric != RIP_METRIC_INFINITY)
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_ecmp_replace(rip, &newinfo);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-09-29 13:25:50 +02:00
|
|
|
route_unlock_node(rp);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2004-05-03 22:00:17 +02:00
|
|
|
if (!rinfo) {
|
2014-07-18 08:13:18 +02:00
|
|
|
if (rp->info)
|
|
|
|
route_unlock_node(rp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Now, check to see whether there is already an explicit route
|
2004-05-03 22:00:17 +02:00
|
|
|
for the destination prefix. If there is no such route, add
|
|
|
|
this route to the routing table, unless the metric is
|
|
|
|
infinity (there is no point in adding a route which
|
|
|
|
unusable). */
|
2014-07-18 08:13:18 +02:00
|
|
|
if (rte->metric != RIP_METRIC_INFINITY)
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_ecmp_add(rip, &newinfo);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Route is there but we are not sure the route is RIP or not.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If there is an existing route, compare the next hop address
|
2004-05-03 22:00:17 +02:00
|
|
|
to the address of the router from which the datagram came.
|
|
|
|
If this datagram is from the same router as the existing
|
|
|
|
route, reinitialize the timeout. */
|
2003-05-25 16:49:19 +02:00
|
|
|
same = (IPV4_ADDR_SAME(&rinfo->from, &from->sin_addr)
|
2017-11-15 15:50:32 +01:00
|
|
|
&& (rinfo->nh.ifindex == ifp->ifindex));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-21 05:10:57 +02:00
|
|
|
old_dist = rinfo->distance ? rinfo->distance
|
2014-07-18 08:13:18 +02:00
|
|
|
: ZEBRA_RIP_DISTANCE_DEFAULT;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Next, compare the metrics. If the datagram is from the same
|
2004-05-03 22:00:17 +02:00
|
|
|
router as the existing route, and the new metric is different
|
|
|
|
than the old one; or, if the new metric is lower than the old
|
|
|
|
one, or if the tag has been changed; or if there is a route
|
|
|
|
with a lower administrave distance; or an update of the
|
|
|
|
distance on the actual route; do the following actions: */
|
|
|
|
if ((same && rinfo->metric != rte->metric)
|
|
|
|
|| (rte->metric < rinfo->metric)
|
|
|
|
|| ((same) && (rinfo->metric == rte->metric)
|
2014-07-18 08:13:18 +02:00
|
|
|
&& (newinfo.tag != rinfo->tag))
|
|
|
|
|| (old_dist > new_dist)
|
|
|
|
|| ((old_dist != new_dist) && same)) {
|
|
|
|
if (listcount(list) == 1) {
|
|
|
|
if (newinfo.metric != RIP_METRIC_INFINITY)
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_ecmp_replace(rip, &newinfo);
|
2002-12-13 21:15:29 +01:00
|
|
|
else
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_ecmp_delete(rip, rinfo);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2014-07-18 08:13:18 +02:00
|
|
|
if (newinfo.metric < rinfo->metric)
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_ecmp_replace(rip, &newinfo);
|
2014-07-18 08:13:18 +02:00
|
|
|
else if (newinfo.metric > rinfo->metric)
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_ecmp_delete(rip, rinfo);
|
2014-07-18 08:13:18 +02:00
|
|
|
else if (new_dist < old_dist)
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_ecmp_replace(rip, &newinfo);
|
2014-07-18 08:13:18 +02:00
|
|
|
else if (new_dist > old_dist)
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_ecmp_delete(rip, rinfo);
|
2002-12-13 21:15:29 +01:00
|
|
|
else {
|
2014-07-18 08:13:18 +02:00
|
|
|
int update = CHECK_FLAG(rinfo->flags,
|
|
|
|
RIP_RTF_FIB)
|
2017-07-17 14:03:14 +02:00
|
|
|
? 1
|
|
|
|
: 0;
|
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
assert(newinfo.metric
|
|
|
|
!= RIP_METRIC_INFINITY);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_timeout);
|
|
|
|
EVENT_OFF(rinfo->t_garbage_collect);
|
2014-07-18 08:13:18 +02:00
|
|
|
memcpy(rinfo, &newinfo,
|
|
|
|
sizeof(struct rip_info));
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_timeout_update(rip, rinfo);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if (update)
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_zebra_ipv4_add(rip, rp);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
/* - Set the route change flag on the
|
2014-07-18 08:13:18 +02:00
|
|
|
* first entry. */
|
|
|
|
rinfo = listgetdata(listhead(list));
|
|
|
|
SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2014-07-18 08:13:18 +02:00
|
|
|
} else /* same & no change */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_timeout_update(rip, rinfo);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Unlock tempolary lock of the route. */
|
|
|
|
route_unlock_node(rp);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Dump RIP packet */
|
|
|
|
static void rip_packet_dump(struct rip_packet *packet, int size,
|
2004-10-08 08:36:38 +02:00
|
|
|
const char *sndrcv)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2002-12-13 21:15:29 +01:00
|
|
|
caddr_t lim;
|
|
|
|
struct rte *rte;
|
2004-10-08 08:36:38 +02:00
|
|
|
const char *command_str;
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t netmask = 0;
|
|
|
|
uint8_t *p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Set command string. */
|
2004-12-08 20:24:06 +01:00
|
|
|
if (packet->command > 0 && packet->command < RIP_COMMAND_MAX)
|
2017-06-21 01:56:50 +02:00
|
|
|
command_str = lookup_msg(rip_msg, packet->command, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2002-12-13 21:15:29 +01:00
|
|
|
command_str = "unknown";
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Dump packet header. */
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug("%s %s version %d packet size %d", sndrcv, command_str,
|
2002-12-13 21:15:29 +01:00
|
|
|
packet->version, size);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Dump each routing table entry. */
|
|
|
|
rte = packet->rte;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
for (lim = (caddr_t)packet + size; (caddr_t)rte < lim; rte++) {
|
|
|
|
if (packet->version == RIPv2) {
|
|
|
|
netmask = ip_masklen(rte->mask);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-05-04 09:36:34 +02:00
|
|
|
if (rte->family == htons(RIP_FAMILY_AUTH)) {
|
2014-07-18 08:13:18 +02:00
|
|
|
if (rte->tag
|
2004-06-07 00:06:33 +02:00
|
|
|
== htons(RIP_AUTH_SIMPLE_PASSWORD)) {
|
2018-03-27 21:13:34 +02:00
|
|
|
p = (uint8_t *)&rte->prefix;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
|
|
|
" family 0x%X type %d auth string: %s",
|
2004-06-07 00:06:33 +02:00
|
|
|
ntohs(rte->family),
|
2016-10-01 20:42:34 +02:00
|
|
|
ntohs(rte->tag), p);
|
2004-06-07 00:06:33 +02:00
|
|
|
} else if (rte->tag == htons(RIP_AUTH_MD5)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
struct rip_md5_info *md5;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
md5 = (struct rip_md5_info *)&packet
|
2017-07-17 14:03:14 +02:00
|
|
|
->rte;
|
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
|
|
|
" family 0x%X type %d (MD5 authentication)",
|
2002-12-13 21:15:29 +01:00
|
|
|
ntohs(md5->family),
|
|
|
|
ntohs(md5->type));
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
" RIP-2 packet len %d Key ID %d Auth Data len %d",
|
2004-06-07 00:06:33 +02:00
|
|
|
ntohs(md5->packet_len),
|
|
|
|
md5->keyid, md5->auth_len);
|
2018-03-27 21:13:34 +02:00
|
|
|
zlog_debug(" Sequence Number %ld",
|
|
|
|
(unsigned long)ntohl(
|
|
|
|
md5->sequence));
|
2004-06-07 00:06:33 +02:00
|
|
|
} else if (rte->tag == htons(RIP_AUTH_DATA)) {
|
2018-03-27 21:13:34 +02:00
|
|
|
p = (uint8_t *)&rte->prefix;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
|
|
|
" family 0x%X type %d (MD5 data)",
|
2004-06-07 00:06:33 +02:00
|
|
|
ntohs(rte->family),
|
2014-07-18 08:13:18 +02:00
|
|
|
ntohs(rte->tag));
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
" MD5: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
|
2004-06-07 00:06:33 +02:00
|
|
|
p[0], p[1], p[2], p[3], p[4],
|
2016-06-14 20:07:08 +02:00
|
|
|
p[5], p[6], p[7], p[8], p[9],
|
|
|
|
p[10], p[11], p[12], p[13],
|
2004-06-07 00:06:33 +02:00
|
|
|
p[14], p[15]);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
|
|
|
" family 0x%X type %d (Unknown auth type)",
|
2002-12-13 21:15:29 +01:00
|
|
|
ntohs(rte->family),
|
|
|
|
ntohs(rte->tag));
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
} else
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2021-03-10 02:07:20 +01:00
|
|
|
" %pI4/%d -> %pI4 family %d tag %" ROUTE_TAG_PRI
|
2016-10-01 20:42:34 +02:00
|
|
|
" metric %ld",
|
2021-03-10 02:07:20 +01:00
|
|
|
&rte->prefix, netmask, &rte->nexthop,
|
2004-06-07 00:06:33 +02:00
|
|
|
ntohs(rte->family),
|
2002-12-13 21:15:29 +01:00
|
|
|
(route_tag_t)ntohs(rte->tag),
|
2018-03-27 21:13:34 +02:00
|
|
|
(unsigned long)ntohl(rte->metric));
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2021-03-10 02:07:20 +01:00
|
|
|
zlog_debug(" %pI4 family %d tag %" ROUTE_TAG_PRI
|
|
|
|
" metric %ld",
|
|
|
|
&rte->prefix, ntohs(rte->family),
|
|
|
|
(route_tag_t)ntohs(rte->tag),
|
|
|
|
(unsigned long)ntohl(rte->metric));
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if the destination address is valid (unicast; not net 0
|
|
|
|
or 127) (RFC2453 Section 3.9.2 - Page 26). But we don't
|
|
|
|
check net 0 because we accept default route. */
|
|
|
|
static int rip_destination_check(struct in_addr addr)
|
|
|
|
{
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t destination;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Convert to host byte order. */
|
|
|
|
destination = ntohl(addr.s_addr);
|
|
|
|
|
|
|
|
if (IPV4_NET127(destination))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Net 0 may match to the default route. */
|
|
|
|
if (IPV4_NET0(destination) && destination != 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Unicast address must belong to class A, B, C. */
|
|
|
|
if (IN_CLASSA(destination))
|
|
|
|
return 1;
|
|
|
|
if (IN_CLASSB(destination))
|
|
|
|
return 1;
|
|
|
|
if (IN_CLASSC(destination))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RIP version 2 authentication. */
|
|
|
|
static int rip_auth_simple_password(struct rte *rte, struct sockaddr_in *from,
|
|
|
|
struct interface *ifp)
|
|
|
|
{
|
|
|
|
struct rip_interface *ri;
|
2018-06-22 15:41:35 +02:00
|
|
|
char *auth_str = (char *)rte + offsetof(struct rte, prefix);
|
2016-11-10 15:53:21 +01:00
|
|
|
int i;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-10 15:53:21 +01:00
|
|
|
/* reject passwords with zeros in the middle of the string */
|
2018-06-22 15:41:35 +02:00
|
|
|
for (i = strnlen(auth_str, 16); i < 16; i++) {
|
2016-11-10 15:53:21 +01:00
|
|
|
if (auth_str[i] != '\0')
|
|
|
|
return 0;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_debug("RIPv2 simple password authentication from %pI4",
|
|
|
|
&from->sin_addr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
ri = ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ri->auth_type != RIP_AUTH_SIMPLE_PASSWORD
|
|
|
|
|| rte->tag != htons(RIP_AUTH_SIMPLE_PASSWORD))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Simple password authentication. */
|
2016-11-10 15:53:21 +01:00
|
|
|
if (ri->auth_str) {
|
2006-01-17 18:26:25 +01:00
|
|
|
if (strncmp(auth_str, ri->auth_str, 16) == 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
return 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ri->key_chain) {
|
2016-11-10 15:53:21 +01:00
|
|
|
struct keychain *keychain;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct key *key;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
keychain = keychain_lookup(ri->key_chain);
|
2018-08-01 14:48:36 +02:00
|
|
|
if (keychain == NULL || keychain->key == NULL)
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-11-10 15:53:21 +01:00
|
|
|
key = key_match_for_accept(keychain, auth_str);
|
2002-12-13 21:15:29 +01:00
|
|
|
if (key)
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RIP version 2 authentication with MD5. */
|
|
|
|
static int rip_auth_md5(struct rip_packet *packet, struct sockaddr_in *from,
|
2004-06-07 00:06:33 +02:00
|
|
|
int length, struct interface *ifp)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct rip_interface *ri;
|
|
|
|
struct rip_md5_info *md5;
|
2004-06-07 00:06:33 +02:00
|
|
|
struct rip_md5_data *md5data;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct keychain *keychain;
|
2006-01-17 18:26:25 +01:00
|
|
|
struct key *key;
|
2019-07-11 11:28:15 +02:00
|
|
|
#ifdef CRYPTO_OPENSSL
|
|
|
|
EVP_MD_CTX *ctx;
|
|
|
|
#elif CRYPTO_INTERNAL
|
2004-06-07 00:06:33 +02:00
|
|
|
MD5_CTX ctx;
|
2019-07-11 11:28:15 +02:00
|
|
|
#endif
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t digest[RIP_AUTH_MD5_SIZE];
|
|
|
|
uint16_t packet_len;
|
2019-02-26 20:55:28 +01:00
|
|
|
char auth_str[RIP_AUTH_MD5_SIZE] = {};
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-06-07 00:06:33 +02:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_debug("RIPv2 MD5 authentication from %pI4",
|
|
|
|
&from->sin_addr);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
ri = ifp->info;
|
|
|
|
md5 = (struct rip_md5_info *)&packet->rte;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Check auth type. */
|
|
|
|
if (ri->auth_type != RIP_AUTH_MD5 || md5->type != htons(RIP_AUTH_MD5))
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If the authentication length is less than 16, then it must be wrong
|
|
|
|
* for
|
|
|
|
* any interpretation of rfc2082. Some implementations also interpret
|
|
|
|
* this as RIP_HEADER_SIZE+ RIP_AUTH_MD5_SIZE, aka
|
2004-06-07 00:06:33 +02:00
|
|
|
* RIP_AUTH_MD5_COMPAT_SIZE.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2002-12-13 21:15:29 +01:00
|
|
|
if (!((md5->auth_len == RIP_AUTH_MD5_SIZE)
|
2005-02-05 00:42:41 +01:00
|
|
|
|| (md5->auth_len == RIP_AUTH_MD5_COMPAT_SIZE))) {
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"RIPv2 MD5 authentication, strange authentication length field %d",
|
2004-06-07 00:06:33 +02:00
|
|
|
md5->auth_len);
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2004-06-07 00:06:33 +02:00
|
|
|
/* grab and verify check packet length */
|
|
|
|
packet_len = ntohs(md5->packet_len);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2004-06-07 00:06:33 +02:00
|
|
|
if (packet_len > (length - RIP_HEADER_SIZE - RIP_AUTH_MD5_SIZE)) {
|
2004-06-04 03:42:38 +02:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"RIPv2 MD5 authentication, packet length field %d greater than received length %d!",
|
2004-06-07 00:06:33 +02:00
|
|
|
md5->packet_len, length);
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2004-06-07 00:06:33 +02:00
|
|
|
/* retrieve authentication data */
|
2018-03-27 21:13:34 +02:00
|
|
|
md5data = (struct rip_md5_data *)(((uint8_t *)packet) + packet_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ri->key_chain) {
|
|
|
|
keychain = keychain_lookup(ri->key_chain);
|
|
|
|
if (keychain == NULL)
|
2004-06-07 00:06:33 +02:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
key = key_lookup_for_accept(keychain, md5->keyid);
|
2018-08-01 06:03:24 +02:00
|
|
|
if (key == NULL || key->string == NULL)
|
2004-06-07 00:06:33 +02:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2021-07-26 21:31:41 +02:00
|
|
|
memcpy(auth_str, key->string,
|
|
|
|
MIN(sizeof(auth_str), strlen(key->string)));
|
2006-01-17 18:26:25 +01:00
|
|
|
} else if (ri->auth_str)
|
2021-07-26 21:31:41 +02:00
|
|
|
memcpy(auth_str, ri->auth_str,
|
|
|
|
MIN(sizeof(auth_str), strlen(ri->auth_str)));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2008-05-29 21:03:08 +02:00
|
|
|
if (auth_str[0] == 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* MD5 digest authentication. */
|
2019-07-11 11:28:15 +02:00
|
|
|
#ifdef CRYPTO_OPENSSL
|
|
|
|
unsigned int md5_size = RIP_AUTH_MD5_SIZE;
|
|
|
|
ctx = EVP_MD_CTX_new();
|
|
|
|
EVP_DigestInit(ctx, EVP_md5());
|
|
|
|
EVP_DigestUpdate(ctx, packet, packet_len + RIP_HEADER_SIZE);
|
|
|
|
EVP_DigestUpdate(ctx, auth_str, RIP_AUTH_MD5_SIZE);
|
|
|
|
EVP_DigestFinal(ctx, digest, &md5_size);
|
|
|
|
EVP_MD_CTX_free(ctx);
|
|
|
|
#elif CRYPTO_INTERNAL
|
2005-09-28 17:47:44 +02:00
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
MD5Init(&ctx);
|
2006-01-17 18:26:25 +01:00
|
|
|
MD5Update(&ctx, packet, packet_len + RIP_HEADER_SIZE);
|
|
|
|
MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
|
2005-09-28 17:47:44 +02:00
|
|
|
MD5Final(digest, &ctx);
|
2019-07-11 11:28:15 +02:00
|
|
|
#endif
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-01-17 18:26:25 +01:00
|
|
|
if (memcmp(md5data->digest, digest, RIP_AUTH_MD5_SIZE) == 0)
|
2002-12-13 21:15:29 +01:00
|
|
|
return packet_len;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
/* Pick correct auth string for sends, prepare auth_str buffer for use.
|
|
|
|
* (left justified and padded).
|
|
|
|
*
|
|
|
|
* presumes one of ri or key is valid, and that the auth strings they point
|
|
|
|
* to are nul terminated. If neither are present, auth_str will be fully
|
|
|
|
* zero padded.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void rip_auth_prepare_str_send(struct rip_interface *ri, struct key *key,
|
|
|
|
char *auth_str, int len)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2005-02-05 00:42:41 +01:00
|
|
|
assert(ri || key);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
memset(auth_str, 0, len);
|
|
|
|
if (key && key->string)
|
2021-07-26 21:31:41 +02:00
|
|
|
memcpy(auth_str, key->string,
|
|
|
|
MIN((size_t)len, strlen(key->string)));
|
2005-02-05 00:42:41 +01:00
|
|
|
else if (ri->auth_str)
|
2021-07-26 21:31:41 +02:00
|
|
|
memcpy(auth_str, ri->auth_str,
|
|
|
|
MIN((size_t)len, strlen(ri->auth_str)));
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
return;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
/* Write RIPv2 simple password authentication information
|
|
|
|
*
|
|
|
|
* auth_str is presumed to be 2 bytes and correctly prepared
|
|
|
|
* (left justified and zero padded).
|
|
|
|
*/
|
|
|
|
static void rip_auth_simple_write(struct stream *s, char *auth_str, int len)
|
|
|
|
{
|
|
|
|
assert(s && len == RIP_AUTH_SIMPLE_SIZE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
stream_putw(s, RIP_FAMILY_AUTH);
|
|
|
|
stream_putw(s, RIP_AUTH_SIMPLE_PASSWORD);
|
|
|
|
stream_put(s, auth_str, RIP_AUTH_SIMPLE_SIZE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
return;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
/* write RIPv2 MD5 "authentication header"
|
|
|
|
* (uses the auth key data field)
|
|
|
|
*
|
|
|
|
* Digest offset field is set to 0.
|
|
|
|
*
|
|
|
|
* returns: offset of the digest offset field, which must be set when
|
|
|
|
* length to the auth-data MD5 digest is known.
|
|
|
|
*/
|
|
|
|
static size_t rip_auth_md5_ah_write(struct stream *s, struct rip_interface *ri,
|
|
|
|
struct key *key)
|
|
|
|
{
|
2006-01-17 18:26:25 +01:00
|
|
|
size_t doff = 0;
|
2022-08-18 01:05:33 +02:00
|
|
|
static uint32_t seq = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
assert(s && ri && ri->auth_type == RIP_AUTH_MD5);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* MD5 authentication. */
|
2004-06-07 00:06:33 +02:00
|
|
|
stream_putw(s, RIP_FAMILY_AUTH);
|
2002-12-13 21:15:29 +01:00
|
|
|
stream_putw(s, RIP_AUTH_MD5);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
/* MD5 AH digest offset field.
|
|
|
|
*
|
|
|
|
* Set to placeholder value here, to true value when RIP-2 Packet length
|
|
|
|
* is known. Actual value is set in .....().
|
|
|
|
*/
|
2006-01-17 18:26:25 +01:00
|
|
|
doff = stream_get_endp(s);
|
2005-02-05 00:42:41 +01:00
|
|
|
stream_putw(s, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Key ID. */
|
|
|
|
if (key)
|
|
|
|
stream_putc(s, key->index % 256);
|
|
|
|
else
|
|
|
|
stream_putc(s, 1);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-06-07 00:06:33 +02:00
|
|
|
/* Auth Data Len. Set 16 for MD5 authentication data. Older ripds
|
|
|
|
* however expect RIP_HEADER_SIZE + RIP_AUTH_MD5_SIZE so we allow for
|
|
|
|
* this
|
|
|
|
* to be configurable.
|
|
|
|
*/
|
|
|
|
stream_putc(s, ri->md5_auth_len);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Sequence Number (non-decreasing). */
|
|
|
|
/* 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. */
|
2024-06-17 15:05:58 +02:00
|
|
|
stream_putl(s, seq++);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Reserved field must be zero. */
|
|
|
|
stream_putl(s, 0);
|
|
|
|
stream_putl(s, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-01-17 18:26:25 +01:00
|
|
|
return doff;
|
2005-02-05 00:42:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If authentication is in used, write the appropriate header
|
|
|
|
* returns stream offset to which length must later be written
|
|
|
|
* or 0 if this is not required
|
|
|
|
*/
|
|
|
|
static size_t rip_auth_header_write(struct stream *s, struct rip_interface *ri,
|
|
|
|
struct key *key, char *auth_str, int len)
|
|
|
|
{
|
|
|
|
assert(ri->auth_type != RIP_NO_AUTH);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
switch (ri->auth_type) {
|
|
|
|
case RIP_AUTH_SIMPLE_PASSWORD:
|
|
|
|
rip_auth_prepare_str_send(ri, key, auth_str, len);
|
|
|
|
rip_auth_simple_write(s, auth_str, len);
|
|
|
|
return 0;
|
|
|
|
case RIP_AUTH_MD5:
|
|
|
|
return rip_auth_md5_ah_write(s, ri, key);
|
|
|
|
}
|
|
|
|
assert(1);
|
2006-01-17 18:26:25 +01:00
|
|
|
return 0;
|
2005-02-05 00:42:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Write RIPv2 MD5 authentication data trailer */
|
|
|
|
static void rip_auth_md5_set(struct stream *s, struct rip_interface *ri,
|
|
|
|
size_t doff, char *auth_str, int authlen)
|
|
|
|
{
|
|
|
|
unsigned long len;
|
2019-07-11 11:28:15 +02:00
|
|
|
#ifdef CRYPTO_OPENSSL
|
|
|
|
EVP_MD_CTX *ctx;
|
|
|
|
#elif CRYPTO_INTERNAL
|
2005-09-28 17:47:44 +02:00
|
|
|
MD5_CTX ctx;
|
2019-07-11 11:28:15 +02:00
|
|
|
#endif
|
2005-02-05 00:42:41 +01:00
|
|
|
unsigned char digest[RIP_AUTH_MD5_SIZE];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
/* Make it sure this interface is configured as MD5
|
|
|
|
authentication. */
|
|
|
|
assert((ri->auth_type == RIP_AUTH_MD5)
|
|
|
|
&& (authlen == RIP_AUTH_MD5_SIZE));
|
|
|
|
assert(doff > 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
/* Get packet length. */
|
|
|
|
len = stream_get_endp(s);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
/* Check packet length. */
|
|
|
|
if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE)) {
|
2022-09-02 20:29:56 +02:00
|
|
|
flog_err(EC_RIP_PACKET,
|
|
|
|
"%s: packet length %ld is less than minimum length.",
|
|
|
|
__func__, len);
|
2005-02-05 00:42:41 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
/* Set the digest offset length in the header */
|
|
|
|
stream_putw_at(s, doff, len);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Set authentication data. */
|
2004-06-07 00:06:33 +02:00
|
|
|
stream_putw(s, RIP_FAMILY_AUTH);
|
|
|
|
stream_putw(s, RIP_AUTH_DATA);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Generate a digest for the RIP packet. */
|
2019-07-11 11:28:15 +02:00
|
|
|
#ifdef CRYPTO_OPENSSL
|
|
|
|
unsigned int md5_size = RIP_AUTH_MD5_SIZE;
|
|
|
|
ctx = EVP_MD_CTX_new();
|
|
|
|
EVP_DigestInit(ctx, EVP_md5());
|
|
|
|
EVP_DigestUpdate(ctx, STREAM_DATA(s), stream_get_endp(s));
|
|
|
|
EVP_DigestUpdate(ctx, auth_str, RIP_AUTH_MD5_SIZE);
|
|
|
|
EVP_DigestFinal(ctx, digest, &md5_size);
|
|
|
|
EVP_MD_CTX_free(ctx);
|
|
|
|
#elif CRYPTO_INTERNAL
|
2005-09-28 17:47:44 +02:00
|
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
|
|
MD5Init(&ctx);
|
2006-01-17 18:26:25 +01:00
|
|
|
MD5Update(&ctx, STREAM_DATA(s), stream_get_endp(s));
|
2005-09-28 17:47:44 +02:00
|
|
|
MD5Update(&ctx, auth_str, RIP_AUTH_MD5_SIZE);
|
|
|
|
MD5Final(digest, &ctx);
|
2019-07-11 11:28:15 +02:00
|
|
|
#endif
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Copy the digest to the packet. */
|
|
|
|
stream_write(s, digest, RIP_AUTH_MD5_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* RIP routing information. */
|
|
|
|
static void rip_response_process(struct rip_packet *packet, int size,
|
2004-10-22 12:27:28 +02:00
|
|
|
struct sockaddr_in *from,
|
|
|
|
struct connected *ifc)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip_interface *ri = ifc->ifp->info;
|
|
|
|
struct rip *rip = ri->rip;
|
2015-09-29 15:19:30 +02:00
|
|
|
caddr_t lim;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct rte *rte;
|
2004-06-07 00:06:33 +02:00
|
|
|
struct prefix_ipv4 ifaddr;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct prefix_ipv4 ifaddrclass;
|
|
|
|
int subnetted;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
memset(&ifaddr, 0, sizeof(ifaddr));
|
|
|
|
/* We don't know yet. */
|
|
|
|
subnetted = -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* The Response must be ignored if it is not from the RIP
|
|
|
|
port. (RFC2453 - Sec. 3.9.2)*/
|
2004-06-07 00:06:33 +02:00
|
|
|
if (from->sin_port != htons(RIP_PORT_DEFAULT)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
zlog_info("response doesn't come from RIP port: %d",
|
|
|
|
from->sin_port);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, from);
|
2002-12-13 21:15:29 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The datagram's IPv4 source address should be checked to see
|
|
|
|
whether the datagram is from a valid neighbor; the source of the
|
|
|
|
datagram must be on a directly connected network (RFC2453 - Sec.
|
|
|
|
3.9.2) */
|
2019-01-04 22:08:10 +01:00
|
|
|
if (if_lookup_address((void *)&from->sin_addr, AF_INET,
|
|
|
|
rip->vrf->vrf_id)
|
2002-12-13 21:15:29 +01:00
|
|
|
== NULL) {
|
|
|
|
zlog_info(
|
2020-10-22 20:16:33 +02:00
|
|
|
"This datagram doesn't come from a valid neighbor: %pI4",
|
|
|
|
&from->sin_addr);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, from);
|
2002-12-13 21:15:29 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It is also worth checking to see whether the response is from one
|
|
|
|
of the router's own addresses. */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
; /* Alredy done in rip_read () */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Update RIP peer. */
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_update(rip, ri, from, packet->version);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Set RTE pointer. */
|
|
|
|
rte = packet->rte;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
for (lim = (caddr_t)packet + size; (caddr_t)rte < lim; rte++) {
|
|
|
|
/* RIPv2 authentication check. */
|
2017-03-10 21:54:53 +01:00
|
|
|
/* If the Address Family Identifier of the first (and only the
|
2004-12-08 20:24:06 +01:00
|
|
|
first) entry in the message is 0xFFFF, then the remainder of
|
|
|
|
the entry contains the authentication. */
|
|
|
|
/* If the packet gets here it means authentication enabled */
|
|
|
|
/* Check is done in rip_read(). So, just skipping it */
|
|
|
|
if (packet->version == RIPv2 && rte == packet->rte
|
2002-12-13 21:15:29 +01:00
|
|
|
&& rte->family == htons(RIP_FAMILY_AUTH))
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
if (rte->family != htons(AF_INET)) {
|
|
|
|
/* Address family check. RIP only supports AF_INET. */
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_info("Unsupported family %d from %pI4",
|
2004-12-08 20:24:06 +01:00
|
|
|
ntohs(rte->family),
|
2020-10-22 20:16:33 +02:00
|
|
|
&from->sin_addr);
|
2002-12-13 21:15:29 +01:00
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-04-25 20:37:28 +02:00
|
|
|
if (packet->version == RIPv1 && rte->tag != 0) {
|
|
|
|
zlog_warn("RIPv1 reserved field is nonzero: %d",
|
|
|
|
ntohs(rte->tag));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2004-12-08 20:24:06 +01:00
|
|
|
/* - is the destination address valid (e.g., unicast; not net 0
|
2002-12-13 21:15:29 +01:00
|
|
|
or 127) */
|
2004-12-08 20:24:06 +01:00
|
|
|
if (!rip_destination_check(rte->prefix)) {
|
|
|
|
zlog_info(
|
|
|
|
"Network is net 0 or net 127 or it is not unicast network");
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_route(rip, ri, from);
|
2002-12-13 21:15:29 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert metric value to host byte order. */
|
|
|
|
rte->metric = ntohl(rte->metric);
|
|
|
|
|
|
|
|
/* - 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.");
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_route(rip, ri, from);
|
2002-12-13 21:15:29 +01:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* RIPv1 does not have nexthop value. */
|
2020-02-06 07:49:02 +01:00
|
|
|
if (packet->version == RIPv1
|
|
|
|
&& rte->nexthop.s_addr != INADDR_ANY) {
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_info("RIPv1 packet with nexthop value %pI4",
|
|
|
|
&rte->nexthop);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_route(rip, ri, from);
|
2002-12-13 21:15:29 +01:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* That is, if the provided information is ignored, a possibly
|
|
|
|
sub-optimal, but absolutely valid, route may be taken. If
|
|
|
|
the received Next Hop is not directly reachable, it should be
|
|
|
|
treated as 0.0.0.0. */
|
2020-02-06 07:49:02 +01:00
|
|
|
if (packet->version == RIPv2
|
|
|
|
&& rte->nexthop.s_addr != INADDR_ANY) {
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t addrval;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
/* Multicast address check. */
|
2002-12-13 21:50:29 +01:00
|
|
|
addrval = ntohl(rte->nexthop.s_addr);
|
|
|
|
if (IN_CLASSD(addrval)) {
|
|
|
|
zlog_info(
|
2020-10-22 20:16:33 +02:00
|
|
|
"Nexthop %pI4 is multicast address, skip this rte",
|
|
|
|
&rte->nexthop);
|
2002-12-13 21:50:29 +01:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:50:29 +01:00
|
|
|
if (!if_lookup_address((void *)&rte->nexthop, AF_INET,
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->vrf->vrf_id)) {
|
2002-12-13 21:50:29 +01:00
|
|
|
struct route_node *rn;
|
|
|
|
struct rip_info *rinfo;
|
2024-09-24 19:59:48 +02:00
|
|
|
struct prefix p = { 0 };
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2024-09-24 19:59:48 +02:00
|
|
|
p.family = AF_INET;
|
|
|
|
p.prefixlen = IPV4_MAX_BITLEN;
|
|
|
|
p.u.prefix4 = rte->nexthop;
|
|
|
|
|
|
|
|
rn = route_node_match(rip->table, &p);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:50:29 +01:00
|
|
|
if (rn) {
|
2002-12-13 21:15:29 +01:00
|
|
|
rinfo = rn->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:50:29 +01:00
|
|
|
if (rinfo->type == ZEBRA_ROUTE_RIP
|
|
|
|
&& rinfo->sub_type
|
|
|
|
== RIP_ROUTE_RTE) {
|
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2020-10-22 20:16:33 +02:00
|
|
|
"Next hop %pI4 is on RIP network. Set nexthop to the packet's originator",
|
|
|
|
&rte->nexthop);
|
2002-12-13 21:50:29 +01:00
|
|
|
rte->nexthop = rinfo->from;
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2002-12-13 21:50:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2020-10-22 20:16:33 +02:00
|
|
|
"Next hop %pI4 is not directly reachable. Treat it as 0.0.0.0",
|
|
|
|
&rte->nexthop);
|
2020-02-06 07:49:02 +01:00
|
|
|
rte->nexthop.s_addr =
|
|
|
|
INADDR_ANY;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
route_unlock_node(rn);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2002-12-13 21:50:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
2020-10-22 20:16:33 +02:00
|
|
|
"Next hop %pI4 is not directly reachable. Treat it as 0.0.0.0",
|
|
|
|
&rte->nexthop);
|
2020-02-06 07:49:02 +01:00
|
|
|
rte->nexthop.s_addr = INADDR_ANY;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:50:29 +01:00
|
|
|
/* For RIPv1, there won't be a valid netmask.
|
2022-02-16 14:05:34 +01:00
|
|
|
* 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.
|
|
|
|
*/
|
2020-02-06 07:49:02 +01:00
|
|
|
if ((packet->version == RIPv1
|
|
|
|
&& rte->prefix.s_addr != INADDR_ANY)
|
2002-12-13 21:15:29 +01:00
|
|
|
|| (packet->version == RIPv2
|
2020-02-06 07:49:02 +01:00
|
|
|
&& (rte->prefix.s_addr != INADDR_ANY
|
|
|
|
&& rte->mask.s_addr == INADDR_ANY))) {
|
2018-03-27 21:13:34 +02:00
|
|
|
uint32_t destination;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:50:29 +01:00
|
|
|
if (subnetted == -1) {
|
2022-05-11 12:14:01 +02:00
|
|
|
memcpy(&ifaddr, ifc->address, sizeof(ifaddr));
|
2004-10-22 12:27:28 +02:00
|
|
|
memcpy(&ifaddrclass, &ifaddr,
|
2022-05-11 12:14:01 +02:00
|
|
|
sizeof(ifaddrclass));
|
2004-10-22 12:27:28 +02:00
|
|
|
apply_classful_mask_ipv4(&ifaddrclass);
|
|
|
|
subnetted = 0;
|
|
|
|
if (ifaddr.prefixlen > ifaddrclass.prefixlen)
|
|
|
|
subnetted = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
destination = ntohl(rte->prefix.s_addr);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:50:29 +01:00
|
|
|
if (IN_CLASSA(destination))
|
2002-12-13 21:15:29 +01:00
|
|
|
masklen2ip(8, &rte->mask);
|
2002-12-13 21:50:29 +01:00
|
|
|
else if (IN_CLASSB(destination))
|
2002-12-13 21:15:29 +01:00
|
|
|
masklen2ip(16, &rte->mask);
|
2002-12-13 21:50:29 +01:00
|
|
|
else if (IN_CLASSC(destination))
|
2002-12-13 21:15:29 +01:00
|
|
|
masklen2ip(24, &rte->mask);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:50:29 +01:00
|
|
|
if (subnetted == 1)
|
|
|
|
masklen2ip(ifaddrclass.prefixlen,
|
|
|
|
(struct in_addr *)&destination);
|
|
|
|
if ((subnetted == 1)
|
2002-12-13 21:15:29 +01:00
|
|
|
&& ((rte->prefix.s_addr & destination)
|
2002-12-13 21:50:29 +01:00
|
|
|
== ifaddrclass.prefix.s_addr)) {
|
|
|
|
masklen2ip(ifaddr.prefixlen, &rte->mask);
|
|
|
|
if ((rte->prefix.s_addr & rte->mask.s_addr)
|
2002-12-13 21:15:29 +01:00
|
|
|
!= rte->prefix.s_addr)
|
2002-12-13 21:50:29 +01:00
|
|
|
masklen2ip(32, &rte->mask);
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_debug("Subnetted route %pI4",
|
|
|
|
&rte->prefix);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2002-12-13 21:50:29 +01:00
|
|
|
if ((rte->prefix.s_addr & rte->mask.s_addr)
|
2002-12-13 21:15:29 +01:00
|
|
|
!= rte->prefix.s_addr)
|
2002-12-13 21:50:29 +01:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2003-05-25 16:49:19 +02:00
|
|
|
if (IS_RIP_DEBUG_EVENT) {
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_debug("Resultant route %pI4",
|
|
|
|
&rte->prefix);
|
|
|
|
zlog_debug("Resultant mask %pI4",
|
|
|
|
&rte->mask);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* In case of RIPv2, if prefix in RTE is not netmask applied one
|
|
|
|
ignore the entry. */
|
2020-02-06 07:49:02 +01:00
|
|
|
if ((packet->version == RIPv2)
|
|
|
|
&& (rte->mask.s_addr != INADDR_ANY)
|
2002-12-13 21:15:29 +01:00
|
|
|
&& ((rte->prefix.s_addr & rte->mask.s_addr)
|
|
|
|
!= rte->prefix.s_addr)) {
|
2017-07-17 14:03:14 +02:00
|
|
|
zlog_warn(
|
2020-10-22 20:16:33 +02:00
|
|
|
"RIPv2 address %pI4 is not mask /%d applied one",
|
|
|
|
&rte->prefix, ip_masklen(rte->mask));
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_route(rip, ri, from);
|
2002-12-13 21:50:29 +01:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Default route's netmask is ignored. */
|
2020-02-06 07:49:02 +01:00
|
|
|
if (packet->version == RIPv2
|
|
|
|
&& (rte->prefix.s_addr == INADDR_ANY)
|
|
|
|
&& (rte->mask.s_addr != INADDR_ANY)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
|
|
|
"Default route with non-zero netmask. Set zero to netmask");
|
2020-02-06 07:49:02 +01:00
|
|
|
rte->mask.s_addr = INADDR_ANY;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Routing table updates. */
|
2004-10-22 12:27:28 +02:00
|
|
|
rip_rte_process(rte, from, ifc->ifp);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-03 19:46:49 +02:00
|
|
|
/* Make socket for RIP protocol. */
|
2019-01-04 22:08:10 +01:00
|
|
|
int rip_create_socket(struct vrf *vrf)
|
2005-06-03 19:46:49 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int sock;
|
|
|
|
struct sockaddr_in addr;
|
2019-01-04 22:08:10 +01:00
|
|
|
const char *vrf_dev = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-08-16 17:22:14 +02:00
|
|
|
memset(&addr, 0, sizeof(struct sockaddr_in));
|
ripd: fix race condition on input processing
In the early days of ripd, we supported running RIP on secondary IP
addresses. To do that, everytime we needed to send a multicast packet,
we would create a new temporary socket for each of the interface's
addresses and call bind() to change the source IP of the outgoing packets.
The problem with these temporary sockets is that they are more specific
than the global RIP socket (bound to INADDR_ANY). Then, even though these
sockets only exist for a short amount of time, they can receive some RIP
packets that were supposed to be received on the global RIP socket. And
since we never read from the temporary sockets, these packets are dropped.
Since we don't support secondary addresses anymore, the simplest way to
fix this problem is to stop using temporary sockets for sending multicast
packets. We are already setting IP_MULTICAST_IF before sending each
multicast packet, and in this case the primary address of the selected
interface is used as the source IP of the outgoing packets, which is
exactly what we want.
If we decide to reintroduce support for secondary addresses in the future,
we should try one of the following:
* Use IP_SENDSRCADDR/IP_PKTINFO to set the source address of the outgoing
multicast packets;
* Create one permanent UDP socket for each possible interface address,
and enable reading on all sockets.
Fixes the following IxANVL RIP tests: 7.10 and 14.1.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2016-11-11 23:19:13 +01:00
|
|
|
addr.sin_family = AF_INET;
|
|
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
[autoconf] bugs 162,303,178: Fix 'present but can not be compiled' warnings
2007-05-09 Paul Jakma <paul.jakma@sun.com>
* configure.ac: sys/conf.h depends on sys/param.h, at least on
FBSD 6.2.
(bug #363) Should check for in_pktinfo for IRDP
2006-05-27 Paul Jakma <paul.jakma@sun.com>
* configure.ac: General cleanup of header and type checks, introducing
an internal define, QUAGGA_INCLUDES, to build up a list of
stuff to include so as to avoid 'present but cant be compiled'
warnings.
Misc additional checks of things missing according to autoscan.
Add LIBM, for bgpd's use of libm, so as to avoid burdening
LIBS, and all the binaries, with libm linkage.
Remove the bad practice of using m4 changequote(), just
quote the []'s in the case statements properly.
This should fix bugs 162, 303 and 178.
* */*.{c,h}: Update all HAVE_* to the standard autoconf namespaced
HAVE_* defines. I.e. HAVE_SA_LEN -> HAVE_STRUCT_SOCKADDR_SA_LEN,
* bgpd/Makefile.am: Add LIBM to bgpd's LDADD, for pow().
2007-05-10 04:38:51 +02:00
|
|
|
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
ripd: fix race condition on input processing
In the early days of ripd, we supported running RIP on secondary IP
addresses. To do that, everytime we needed to send a multicast packet,
we would create a new temporary socket for each of the interface's
addresses and call bind() to change the source IP of the outgoing packets.
The problem with these temporary sockets is that they are more specific
than the global RIP socket (bound to INADDR_ANY). Then, even though these
sockets only exist for a short amount of time, they can receive some RIP
packets that were supposed to be received on the global RIP socket. And
since we never read from the temporary sockets, these packets are dropped.
Since we don't support secondary addresses anymore, the simplest way to
fix this problem is to stop using temporary sockets for sending multicast
packets. We are already setting IP_MULTICAST_IF before sending each
multicast packet, and in this case the primary address of the selected
interface is used as the source IP of the outgoing packets, which is
exactly what we want.
If we decide to reintroduce support for secondary addresses in the future,
we should try one of the following:
* Use IP_SENDSRCADDR/IP_PKTINFO to set the source address of the outgoing
multicast packets;
* Create one permanent UDP socket for each possible interface address,
and enable reading on all sockets.
Fixes the following IxANVL RIP tests: 7.10 and 14.1.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2016-11-11 23:19:13 +01:00
|
|
|
addr.sin_len = sizeof(struct sockaddr_in);
|
[autoconf] bugs 162,303,178: Fix 'present but can not be compiled' warnings
2007-05-09 Paul Jakma <paul.jakma@sun.com>
* configure.ac: sys/conf.h depends on sys/param.h, at least on
FBSD 6.2.
(bug #363) Should check for in_pktinfo for IRDP
2006-05-27 Paul Jakma <paul.jakma@sun.com>
* configure.ac: General cleanup of header and type checks, introducing
an internal define, QUAGGA_INCLUDES, to build up a list of
stuff to include so as to avoid 'present but cant be compiled'
warnings.
Misc additional checks of things missing according to autoscan.
Add LIBM, for bgpd's use of libm, so as to avoid burdening
LIBS, and all the binaries, with libm linkage.
Remove the bad practice of using m4 changequote(), just
quote the []'s in the case statements properly.
This should fix bugs 162, 303 and 178.
* */*.{c,h}: Update all HAVE_* to the standard autoconf namespaced
HAVE_* defines. I.e. HAVE_SA_LEN -> HAVE_STRUCT_SOCKADDR_SA_LEN,
* bgpd/Makefile.am: Add LIBM to bgpd's LDADD, for pow().
2007-05-10 04:38:51 +02:00
|
|
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
2005-08-16 17:22:14 +02:00
|
|
|
/* sending port must always be the RIP port */
|
|
|
|
addr.sin_port = htons(RIP_PORT_DEFAULT);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-06-03 19:46:49 +02:00
|
|
|
/* Make datagram socket. */
|
2019-01-04 22:08:10 +01:00
|
|
|
if (vrf->vrf_id != VRF_DEFAULT)
|
|
|
|
vrf_dev = vrf->name;
|
2019-08-13 15:47:23 +02:00
|
|
|
frr_with_privs(&ripd_privs) {
|
2019-01-04 22:08:10 +01:00
|
|
|
sock = vrf_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, vrf->vrf_id,
|
|
|
|
vrf_dev);
|
|
|
|
if (sock < 0) {
|
|
|
|
flog_err_sys(EC_LIB_SOCKET,
|
|
|
|
"Cannot create UDP socket: %s",
|
|
|
|
safe_strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
2005-06-03 19:46:49 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-06-03 19:46:49 +02:00
|
|
|
sockopt_broadcast(sock);
|
|
|
|
sockopt_reuseaddr(sock);
|
|
|
|
sockopt_reuseport(sock);
|
2016-11-12 22:11:13 +01:00
|
|
|
setsockopt_ipv4_multicast_loop(sock, 0);
|
2009-07-22 01:27:26 +02:00
|
|
|
#ifdef IPTOS_PREC_INTERNETCONTROL
|
|
|
|
setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL);
|
|
|
|
#endif
|
2019-04-08 18:08:00 +02:00
|
|
|
setsockopt_so_recvbuf(sock, RIP_UDP_RCV_BUF);
|
2005-06-03 19:46:49 +02:00
|
|
|
|
2019-08-13 15:47:23 +02:00
|
|
|
frr_with_privs(&ripd_privs) {
|
2018-08-13 19:52:57 +02:00
|
|
|
if ((ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
|
|
|
|
< 0) {
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_err("%s: Can't bind socket %d to %pI4 port %d: %s",
|
|
|
|
__func__, sock, &addr.sin_addr,
|
2018-08-13 19:52:57 +02:00
|
|
|
(int)ntohs(addr.sin_port),
|
|
|
|
safe_strerror(errno));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-08-10 18:36:43 +02:00
|
|
|
close(sock);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2005-06-03 19:46:49 +02:00
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
/* RIP packet send to destination address, on interface denoted by
|
|
|
|
* by connected argument. NULL to argument denotes destination should be
|
|
|
|
* should be RIP multicast group
|
|
|
|
*/
|
2018-03-27 21:13:34 +02:00
|
|
|
static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to,
|
2004-10-22 12:27:28 +02:00
|
|
|
struct connected *ifc)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip_interface *ri;
|
|
|
|
struct rip *rip;
|
ripd: fix race condition on input processing
In the early days of ripd, we supported running RIP on secondary IP
addresses. To do that, everytime we needed to send a multicast packet,
we would create a new temporary socket for each of the interface's
addresses and call bind() to change the source IP of the outgoing packets.
The problem with these temporary sockets is that they are more specific
than the global RIP socket (bound to INADDR_ANY). Then, even though these
sockets only exist for a short amount of time, they can receive some RIP
packets that were supposed to be received on the global RIP socket. And
since we never read from the temporary sockets, these packets are dropped.
Since we don't support secondary addresses anymore, the simplest way to
fix this problem is to stop using temporary sockets for sending multicast
packets. We are already setting IP_MULTICAST_IF before sending each
multicast packet, and in this case the primary address of the selected
interface is used as the source IP of the outgoing packets, which is
exactly what we want.
If we decide to reintroduce support for secondary addresses in the future,
we should try one of the following:
* Use IP_SENDSRCADDR/IP_PKTINFO to set the source address of the outgoing
multicast packets;
* Create one permanent UDP socket for each possible interface address,
and enable reading on all sockets.
Fixes the following IxANVL RIP tests: 7.10 and 14.1.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2016-11-11 23:19:13 +01:00
|
|
|
int ret;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct sockaddr_in sin;
|
2019-01-04 22:08:10 +01:00
|
|
|
struct msghdr msg;
|
|
|
|
struct iovec iov;
|
|
|
|
#ifdef GNU_LINUX
|
|
|
|
struct cmsghdr *cmsgptr;
|
|
|
|
char adata[256] = {};
|
|
|
|
struct in_pktinfo *pkt;
|
|
|
|
#endif /* GNU_LINUX */
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
assert(ifc != NULL);
|
2019-01-04 22:08:10 +01:00
|
|
|
ri = ifc->ifp->info;
|
|
|
|
rip = ri->rip;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-01-23 16:31:42 +01:00
|
|
|
if (IS_RIP_DEBUG_PACKET) {
|
2005-06-03 20:01:50 +02:00
|
|
|
#define ADDRESS_SIZE 20
|
|
|
|
char dst[ADDRESS_SIZE];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-01-23 16:31:42 +01:00
|
|
|
if (to) {
|
2020-10-22 20:16:33 +02:00
|
|
|
inet_ntop(AF_INET, &to->sin_addr, dst, sizeof(dst));
|
2004-01-23 16:31:42 +01:00
|
|
|
} else {
|
|
|
|
sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
|
2020-10-22 20:16:33 +02:00
|
|
|
inet_ntop(AF_INET, &sin.sin_addr, dst, sizeof(dst));
|
2004-01-23 16:31:42 +01:00
|
|
|
}
|
2005-06-03 20:01:50 +02:00
|
|
|
#undef ADDRESS_SIZE
|
2022-09-02 20:29:56 +02:00
|
|
|
zlog_debug("%s %pI4 > %s (%s)", __func__,
|
|
|
|
&ifc->address->u.prefix4, dst, ifc->ifp->name);
|
2004-01-23 16:31:42 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) {
|
2004-01-23 16:31:42 +01:00
|
|
|
/*
|
|
|
|
* ZEBRA_IFA_SECONDARY is set on linux when an interface is
|
2022-02-16 14:05:34 +01:00
|
|
|
* 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.
|
2004-01-23 16:31:42 +01:00
|
|
|
* XXX Since Linux is the only system for which the
|
2022-02-16 14:05:34 +01:00
|
|
|
* ZEBRA_IFA_SECONDARY flag is set, we would end up
|
|
|
|
* sending a packet for a "secondary" source address on
|
|
|
|
* non-linux systems.
|
2004-01-23 16:31:42 +01:00
|
|
|
*/
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug("duplicate dropped");
|
2004-01-23 16:31:42 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Make destination address. */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&sin, 0, sizeof(sin));
|
2002-12-13 21:15:29 +01:00
|
|
|
sin.sin_family = AF_INET;
|
[autoconf] bugs 162,303,178: Fix 'present but can not be compiled' warnings
2007-05-09 Paul Jakma <paul.jakma@sun.com>
* configure.ac: sys/conf.h depends on sys/param.h, at least on
FBSD 6.2.
(bug #363) Should check for in_pktinfo for IRDP
2006-05-27 Paul Jakma <paul.jakma@sun.com>
* configure.ac: General cleanup of header and type checks, introducing
an internal define, QUAGGA_INCLUDES, to build up a list of
stuff to include so as to avoid 'present but cant be compiled'
warnings.
Misc additional checks of things missing according to autoscan.
Add LIBM, for bgpd's use of libm, so as to avoid burdening
LIBS, and all the binaries, with libm linkage.
Remove the bad practice of using m4 changequote(), just
quote the []'s in the case statements properly.
This should fix bugs 162, 303 and 178.
* */*.{c,h}: Update all HAVE_* to the standard autoconf namespaced
HAVE_* defines. I.e. HAVE_SA_LEN -> HAVE_STRUCT_SOCKADDR_SA_LEN,
* bgpd/Makefile.am: Add LIBM to bgpd's LDADD, for pow().
2007-05-10 04:38:51 +02:00
|
|
|
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
|
2002-12-13 21:15:29 +01:00
|
|
|
sin.sin_len = sizeof(struct sockaddr_in);
|
[autoconf] bugs 162,303,178: Fix 'present but can not be compiled' warnings
2007-05-09 Paul Jakma <paul.jakma@sun.com>
* configure.ac: sys/conf.h depends on sys/param.h, at least on
FBSD 6.2.
(bug #363) Should check for in_pktinfo for IRDP
2006-05-27 Paul Jakma <paul.jakma@sun.com>
* configure.ac: General cleanup of header and type checks, introducing
an internal define, QUAGGA_INCLUDES, to build up a list of
stuff to include so as to avoid 'present but cant be compiled'
warnings.
Misc additional checks of things missing according to autoscan.
Add LIBM, for bgpd's use of libm, so as to avoid burdening
LIBS, and all the binaries, with libm linkage.
Remove the bad practice of using m4 changequote(), just
quote the []'s in the case statements properly.
This should fix bugs 162, 303 and 178.
* */*.{c,h}: Update all HAVE_* to the standard autoconf namespaced
HAVE_* defines. I.e. HAVE_SA_LEN -> HAVE_STRUCT_SOCKADDR_SA_LEN,
* bgpd/Makefile.am: Add LIBM to bgpd's LDADD, for pow().
2007-05-10 04:38:51 +02:00
|
|
|
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* When destination is specified, use it's port and address. */
|
|
|
|
if (to) {
|
|
|
|
sin.sin_port = to->sin_port;
|
|
|
|
sin.sin_addr = to->sin_addr;
|
|
|
|
} else {
|
|
|
|
sin.sin_port = htons(RIP_PORT_DEFAULT);
|
|
|
|
sin.sin_addr.s_addr = htonl(INADDR_RIP_GROUP);
|
ripd: fix race condition on input processing
In the early days of ripd, we supported running RIP on secondary IP
addresses. To do that, everytime we needed to send a multicast packet,
we would create a new temporary socket for each of the interface's
addresses and call bind() to change the source IP of the outgoing packets.
The problem with these temporary sockets is that they are more specific
than the global RIP socket (bound to INADDR_ANY). Then, even though these
sockets only exist for a short amount of time, they can receive some RIP
packets that were supposed to be received on the global RIP socket. And
since we never read from the temporary sockets, these packets are dropped.
Since we don't support secondary addresses anymore, the simplest way to
fix this problem is to stop using temporary sockets for sending multicast
packets. We are already setting IP_MULTICAST_IF before sending each
multicast packet, and in this case the primary address of the selected
interface is used as the source IP of the outgoing packets, which is
exactly what we want.
If we decide to reintroduce support for secondary addresses in the future,
we should try one of the following:
* Use IP_SENDSRCADDR/IP_PKTINFO to set the source address of the outgoing
multicast packets;
* Create one permanent UDP socket for each possible interface address,
and enable reading on all sockets.
Fixes the following IxANVL RIP tests: 7.10 and 14.1.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
2016-11-11 23:19:13 +01:00
|
|
|
|
|
|
|
rip_interface_multicast_set(rip->sock, ifc);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
|
|
msg.msg_name = (void *)&sin;
|
|
|
|
msg.msg_namelen = sizeof(struct sockaddr_in);
|
|
|
|
msg.msg_iov = &iov;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
iov.iov_base = buf;
|
|
|
|
iov.iov_len = size;
|
|
|
|
|
|
|
|
#ifdef GNU_LINUX
|
|
|
|
msg.msg_control = (void *)adata;
|
|
|
|
msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
|
|
|
|
|
|
|
|
cmsgptr = (struct cmsghdr *)adata;
|
|
|
|
cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
|
|
|
cmsgptr->cmsg_level = IPPROTO_IP;
|
|
|
|
cmsgptr->cmsg_type = IP_PKTINFO;
|
|
|
|
pkt = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
|
|
|
|
pkt->ipi_ifindex = ifc->ifp->ifindex;
|
2022-02-16 01:47:23 +01:00
|
|
|
pkt->ipi_spec_dst.s_addr = ifc->address->u.prefix4.s_addr;
|
2019-01-04 22:08:10 +01:00
|
|
|
#endif /* GNU_LINUX */
|
|
|
|
|
|
|
|
ret = sendmsg(rip->sock, &msg, 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2023-04-10 05:04:47 +02:00
|
|
|
zlog_debug("SEND to %pI4 port %d", &sin.sin_addr,
|
2003-10-16 01:20:17 +02:00
|
|
|
ntohs(sin.sin_port));
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
if (ret < 0)
|
2004-11-20 03:06:59 +01:00
|
|
|
zlog_warn("can't send packet : %s", safe_strerror(errno));
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add redistributed route to RIP table. */
|
2019-01-04 22:08:10 +01:00
|
|
|
void rip_redistribute_add(struct rip *rip, int type, int sub_type,
|
|
|
|
struct prefix_ipv4 *p, struct nexthop *nh,
|
|
|
|
unsigned int metric, unsigned char distance,
|
|
|
|
route_tag_t tag)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
int ret;
|
2014-07-18 08:13:18 +02:00
|
|
|
struct route_node *rp = NULL;
|
|
|
|
struct rip_info *rinfo = NULL, newinfo;
|
|
|
|
struct list *list = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Redistribute route */
|
|
|
|
ret = rip_destination_check(p->prefix);
|
2004-05-03 22:00:17 +02:00
|
|
|
if (!ret)
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
rp = route_node_get(rip->table, (struct prefix *)p);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&newinfo, 0, sizeof(newinfo));
|
2014-07-18 08:13:18 +02:00
|
|
|
newinfo.type = type;
|
|
|
|
newinfo.sub_type = sub_type;
|
|
|
|
newinfo.metric = 1;
|
|
|
|
newinfo.external_metric = metric;
|
|
|
|
newinfo.distance = distance;
|
2016-10-01 21:43:17 +02:00
|
|
|
if (tag <= UINT16_MAX) /* RIP only supports 16 bit tags */
|
|
|
|
newinfo.tag = tag;
|
2014-07-18 08:13:18 +02:00
|
|
|
newinfo.rp = rp;
|
2017-11-15 17:19:06 +01:00
|
|
|
newinfo.nh = *nh;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if ((list = rp->info) != NULL && listcount(list) != 0) {
|
|
|
|
rinfo = listgetdata(listhead(list));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (rinfo->type == ZEBRA_ROUTE_CONNECT
|
|
|
|
&& rinfo->sub_type == RIP_ROUTE_INTERFACE
|
|
|
|
&& rinfo->metric != RIP_METRIC_INFINITY) {
|
|
|
|
route_unlock_node(rp);
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Manually configured RIP route check. */
|
|
|
|
if (rinfo->type == ZEBRA_ROUTE_RIP
|
|
|
|
&& ((rinfo->sub_type == RIP_ROUTE_STATIC)
|
|
|
|
|| (rinfo->sub_type == RIP_ROUTE_DEFAULT))) {
|
|
|
|
if (type != ZEBRA_ROUTE_RIP
|
|
|
|
|| ((sub_type != RIP_ROUTE_STATIC)
|
|
|
|
&& (sub_type != RIP_ROUTE_DEFAULT))) {
|
|
|
|
route_unlock_node(rp);
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
(void)rip_ecmp_replace(rip, &newinfo);
|
2002-12-13 21:15:29 +01:00
|
|
|
route_unlock_node(rp);
|
2014-07-18 08:13:18 +02:00
|
|
|
} else
|
2019-01-04 22:08:10 +01:00
|
|
|
(void)rip_ecmp_add(rip, &newinfo);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-10-01 21:43:17 +02:00
|
|
|
if (IS_RIP_DEBUG_EVENT) {
|
2020-10-14 19:16:46 +02:00
|
|
|
zlog_debug("Redistribute new prefix %pFX", p);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Delete redistributed route from RIP table. */
|
2019-01-04 22:08:10 +01:00
|
|
|
void rip_redistribute_delete(struct rip *rip, int type, int sub_type,
|
|
|
|
struct prefix_ipv4 *p, ifindex_t ifindex)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
struct route_node *rp;
|
|
|
|
struct rip_info *rinfo;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
ret = rip_destination_check(p->prefix);
|
|
|
|
if (!ret)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
rp = route_node_lookup(rip->table, (struct prefix *)p);
|
|
|
|
if (rp) {
|
2014-07-18 08:13:18 +02:00
|
|
|
struct list *list = rp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if (list != NULL && listcount(list) != 0) {
|
|
|
|
rinfo = listgetdata(listhead(list));
|
|
|
|
if (rinfo != NULL && rinfo->type == type
|
|
|
|
&& rinfo->sub_type == sub_type
|
2017-11-15 15:50:32 +01:00
|
|
|
&& rinfo->nh.ifindex == ifindex) {
|
2014-07-18 08:13:18 +02:00
|
|
|
/* Perform poisoned reverse. */
|
|
|
|
rinfo->metric = RIP_METRIC_INFINITY;
|
|
|
|
RIP_TIMER_ON(rinfo->t_garbage_collect,
|
|
|
|
rip_garbage_collect,
|
|
|
|
rip->garbage_time);
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_timeout);
|
2014-07-18 08:13:18 +02:00
|
|
|
rinfo->flags |= RIP_RTF_CHANGED;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
|
|
|
zlog_debug(
|
2020-10-14 19:16:46 +02:00
|
|
|
"Poison %pFX on the interface %s with an infinity metric [delete]",
|
|
|
|
p,
|
2019-01-04 22:08:10 +01:00
|
|
|
ifindex2ifname(
|
|
|
|
ifindex,
|
|
|
|
rip->vrf->vrf_id));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
|
2014-07-18 08:13:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
route_unlock_node(rp);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Response to request called from rip_read ().*/
|
|
|
|
static void rip_request_process(struct rip_packet *packet, int size,
|
2004-10-22 12:27:28 +02:00
|
|
|
struct sockaddr_in *from, struct connected *ifc)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip;
|
2002-12-13 21:15:29 +01:00
|
|
|
caddr_t lim;
|
|
|
|
struct rte *rte;
|
|
|
|
struct prefix_ipv4 p;
|
|
|
|
struct route_node *rp;
|
|
|
|
struct rip_info *rinfo;
|
|
|
|
struct rip_interface *ri;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-05-25 16:49:19 +02:00
|
|
|
/* Does not reponse to the requests on the loopback interfaces */
|
2004-10-22 12:27:28 +02:00
|
|
|
if (if_is_loopback(ifc->ifp))
|
2003-05-25 16:49:19 +02:00
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-02-23 00:42:22 +01:00
|
|
|
/* Check RIP process is enabled on this interface. */
|
2004-10-22 12:27:28 +02:00
|
|
|
ri = ifc->ifp->info;
|
2003-05-25 16:49:19 +02:00
|
|
|
if (!ri->running)
|
|
|
|
return;
|
2019-01-04 22:08:10 +01:00
|
|
|
rip = ri->rip;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* When passive interface is specified, suppress responses */
|
|
|
|
if (ri->passive)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIP peer update. */
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_update(rip, ri, from, packet->version);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
lim = ((caddr_t)packet) + size;
|
|
|
|
rte = packet->rte;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* The Request is processed entry by entry. If there are no
|
|
|
|
entries, no response is given. */
|
|
|
|
if (lim == (caddr_t)rte)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* There is one special case. If there is exactly one entry in the
|
|
|
|
request, and it has an address family identifier of zero and a
|
|
|
|
metric of infinity (i.e., 16), then this is a request to send the
|
|
|
|
entire routing table. */
|
|
|
|
if (lim == ((caddr_t)(rte + 1)) && ntohs(rte->family) == 0
|
2014-07-18 08:13:18 +02:00
|
|
|
&& ntohl(rte->metric) == RIP_METRIC_INFINITY) {
|
2002-12-13 21:15:29 +01:00
|
|
|
/* All route with split horizon */
|
2004-10-22 12:27:28 +02:00
|
|
|
rip_output_process(ifc, from, rip_all_route, packet->version);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else {
|
2016-11-10 15:54:07 +01:00
|
|
|
if (ntohs(rte->family) != AF_INET)
|
2017-07-17 14:03:14 +02:00
|
|
|
return;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Examine the list of RTEs in the Request one by one. For each
|
|
|
|
entry, look up the destination in the router's routing
|
|
|
|
database and, if there is a route, put that route's metric in
|
|
|
|
the metric field of the RTE. If there is no explicit route
|
|
|
|
to the specified destination, put infinity in the metric
|
|
|
|
field. Once all the entries have been filled in, change the
|
|
|
|
command from Request to Response and send the datagram back
|
|
|
|
to the requestor. */
|
|
|
|
p.family = AF_INET;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
for (; ((caddr_t)rte) < lim; rte++) {
|
|
|
|
p.prefix = rte->prefix;
|
|
|
|
p.prefixlen = ip_masklen(rte->mask);
|
|
|
|
apply_mask_ipv4(&p);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
rp = route_node_lookup(rip->table, (struct prefix *)&p);
|
|
|
|
if (rp) {
|
2014-07-18 08:13:18 +02:00
|
|
|
rinfo = listgetdata(
|
2002-12-13 21:15:29 +01:00
|
|
|
listhead((struct list *)rp->info));
|
|
|
|
rte->metric = htonl(rinfo->metric);
|
|
|
|
route_unlock_node(rp);
|
2017-07-17 14:03:14 +02:00
|
|
|
} else
|
2002-12-13 21:15:29 +01:00
|
|
|
rte->metric = htonl(RIP_METRIC_INFINITY);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-10-22 12:27:28 +02:00
|
|
|
packet->command = RIP_RESPONSE;
|
2016-11-10 15:54:07 +01:00
|
|
|
|
2018-06-01 02:45:49 +02:00
|
|
|
(void)rip_send_packet((uint8_t *)packet, size, from, ifc);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->counters.queries++;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* First entry point of RIP packet. */
|
2022-03-01 22:18:12 +01:00
|
|
|
static void rip_read(struct event *t)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct rip *rip = EVENT_ARG(t);
|
2002-12-13 21:15:29 +01:00
|
|
|
int sock;
|
|
|
|
int ret;
|
|
|
|
int rtenum;
|
|
|
|
union rip_buf rip_buf;
|
|
|
|
struct rip_packet *packet;
|
|
|
|
struct sockaddr_in from;
|
2004-05-31 16:00:00 +02:00
|
|
|
int len;
|
2006-09-11 04:10:40 +02:00
|
|
|
int vrecv;
|
2004-05-31 16:00:00 +02:00
|
|
|
socklen_t fromlen;
|
2016-11-10 18:35:47 +01:00
|
|
|
struct interface *ifp = NULL;
|
2004-10-22 12:27:28 +02:00
|
|
|
struct connected *ifc;
|
2021-10-14 17:12:37 +02:00
|
|
|
struct rip_interface *ri = NULL;
|
2016-05-12 00:52:30 +02:00
|
|
|
struct prefix p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Fetch socket then register myself. */
|
2022-12-25 16:26:52 +01:00
|
|
|
sock = EVENT_FD(t);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Add myself to tne next event */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_event(rip, RIP_READ, sock);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIPd manages only IPv4. */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&from, 0, sizeof(from));
|
2002-12-13 21:15:29 +01:00
|
|
|
fromlen = sizeof(struct sockaddr_in);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
len = recvfrom(sock, (char *)&rip_buf.buf, sizeof(rip_buf.buf), 0,
|
|
|
|
(struct sockaddr *)&from, &fromlen);
|
|
|
|
if (len < 0) {
|
2019-01-04 22:08:10 +01:00
|
|
|
zlog_info("recvfrom failed (VRF %s): %s", rip->vrf_name,
|
|
|
|
safe_strerror(errno));
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Check is this packet comming from myself? */
|
2019-01-04 22:08:10 +01:00
|
|
|
if (if_check_address(rip, from.sin_addr)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
2019-01-04 22:08:10 +01:00
|
|
|
zlog_debug("ignore packet comes from myself (VRF %s)",
|
|
|
|
rip->vrf_name);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Which interface is this packet comes from. */
|
2019-01-04 22:08:10 +01:00
|
|
|
ifc = if_lookup_address((void *)&from.sin_addr, AF_INET,
|
|
|
|
rip->vrf->vrf_id);
|
2021-10-14 17:12:37 +02:00
|
|
|
if (ifc) {
|
2016-11-10 18:35:47 +01:00
|
|
|
ifp = ifc->ifp;
|
2021-10-14 17:12:37 +02:00
|
|
|
ri = ifp->info;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIP packet received */
|
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_debug("RECV packet from %pI4 port %d on %s (VRF %s)",
|
|
|
|
&from.sin_addr, ntohs(from.sin_port),
|
2019-01-04 22:08:10 +01:00
|
|
|
ifp ? ifp->name : "unknown", rip->vrf_name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If this packet come from unknown interface, ignore it. */
|
2021-10-14 17:12:37 +02:00
|
|
|
if (ifp == NULL || ri == NULL) {
|
2004-12-15 15:55:51 +01:00
|
|
|
zlog_info(
|
2022-09-02 20:29:56 +02:00
|
|
|
"%s: cannot find interface for packet from %pI4 port %d (VRF %s)",
|
|
|
|
__func__, &from.sin_addr, ntohs(from.sin_port),
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->vrf_name);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2004-10-22 12:27:28 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-05-12 00:52:30 +02:00
|
|
|
p.family = AF_INET;
|
|
|
|
p.u.prefix4 = from.sin_addr;
|
|
|
|
p.prefixlen = IPV4_MAX_BITLEN;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-05-12 00:52:30 +02:00
|
|
|
ifc = connected_lookup_prefix(ifp, &p);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
if (ifc == NULL) {
|
2004-12-15 15:55:51 +01:00
|
|
|
zlog_info(
|
2022-09-02 20:29:56 +02:00
|
|
|
"%s: cannot find connected address for packet from %pI4 port %d on interface %s (VRF %s)",
|
|
|
|
__func__, &from.sin_addr, ntohs(from.sin_port),
|
2019-01-04 22:08:10 +01:00
|
|
|
ifp->name, rip->vrf_name);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Packet length check. */
|
|
|
|
if (len < RIP_PACKET_MINSIZ) {
|
|
|
|
zlog_warn("packet size %d is smaller than minimum size %d", len,
|
|
|
|
RIP_PACKET_MINSIZ);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
if (len > RIP_PACKET_MAXSIZ) {
|
|
|
|
zlog_warn("packet size %d is larger than max size %d", len,
|
|
|
|
RIP_PACKET_MAXSIZ);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Packet alignment check. */
|
|
|
|
if ((len - RIP_PACKET_MINSIZ) % 20) {
|
|
|
|
zlog_warn("packet size %d is wrong for RIP packet alignment",
|
|
|
|
len);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Set RTE number. */
|
|
|
|
rtenum = ((len - RIP_PACKET_MINSIZ) / 20);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* For easy to handle. */
|
|
|
|
packet = &rip_buf.rip_packet;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIP version check. */
|
|
|
|
if (packet->version == 0) {
|
|
|
|
zlog_info("version 0 with command %d received.",
|
|
|
|
packet->command);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Dump RIP packet. */
|
|
|
|
if (IS_RIP_DEBUG_RECV)
|
|
|
|
rip_packet_dump(packet, len, "RECV");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RIP version adjust. This code should rethink now. RFC1058 says
|
|
|
|
that "Version 1 implementations are to ignore this extra data and
|
|
|
|
process only the fields specified in this document.". So RIPv3
|
|
|
|
packet should be treated as RIPv1 ignoring must be zero field. */
|
|
|
|
if (packet->version > RIPv2)
|
|
|
|
packet->version = RIPv2;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Is RIP running or is this RIP neighbor ?*/
|
2019-01-04 22:08:10 +01:00
|
|
|
if (!ri->running && !rip_neighbor_lookup(rip, &from)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug("RIP is not enabled on interface %s.",
|
|
|
|
ifp->name);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-05-04 09:36:34 +02:00
|
|
|
/* RIP Version check. RFC2453, 4.6 and 5.1 */
|
2006-09-11 04:10:40 +02:00
|
|
|
vrecv = ((ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv
|
|
|
|
: ri->ri_receive);
|
2016-11-10 16:15:43 +01:00
|
|
|
if (vrecv == RI_RIP_VERSION_NONE
|
|
|
|
|| ((packet->version == RIPv1) && !(vrecv & RIPv1))
|
|
|
|
|| ((packet->version == RIPv2) && !(vrecv & RIPv2))) {
|
2006-05-04 09:36:34 +02:00
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
|
|
|
zlog_debug(
|
|
|
|
" packet's v%d doesn't fit to if version spec",
|
|
|
|
packet->version);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2006-05-04 09:36:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* RFC2453 5.2 If the router is not configured to authenticate RIP-2
|
|
|
|
messages, then RIP-1 and unauthenticated RIP-2 messages will be
|
|
|
|
accepted; authenticated RIP-2 messages shall be discarded. */
|
|
|
|
if ((ri->auth_type == RIP_NO_AUTH) && rtenum
|
2004-06-07 00:06:33 +02:00
|
|
|
&& (packet->version == RIPv2)
|
|
|
|
&& (packet->rte->family == htons(RIP_FAMILY_AUTH))) {
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug(
|
|
|
|
"packet RIPv%d is dropped because authentication disabled",
|
2002-12-13 21:15:29 +01:00
|
|
|
packet->version);
|
2018-05-09 06:35:04 +02:00
|
|
|
ripd_notif_send_auth_type_failure(ifp->name);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-05-04 09:36:34 +02:00
|
|
|
/* RFC:
|
|
|
|
If the router is configured to authenticate RIP-2 messages, then
|
2002-12-13 21:15:29 +01:00
|
|
|
RIP-1 messages and RIP-2 messages which pass authentication
|
|
|
|
testing shall be accepted; unauthenticated and failed
|
|
|
|
authentication RIP-2 messages shall be discarded. For maximum
|
|
|
|
security, RIP-1 messages should be ignored when authentication is
|
|
|
|
in use (see section 4.1); otherwise, the routing information from
|
|
|
|
authenticated messages will be propagated by RIP-1 routers in an
|
2006-05-04 09:36:34 +02:00
|
|
|
unauthenticated manner.
|
|
|
|
*/
|
|
|
|
/* We make an exception for RIPv1 REQUEST packets, to which we'll
|
|
|
|
* always reply regardless of authentication settings, because:
|
|
|
|
*
|
|
|
|
* - if there other authorised routers on-link, the REQUESTor can
|
|
|
|
* passively obtain the routing updates anyway
|
|
|
|
* - if there are no other authorised routers on-link, RIP can
|
|
|
|
* easily be disabled for the link to prevent giving out information
|
|
|
|
* on state of this routers RIP routing table..
|
|
|
|
*
|
|
|
|
* I.e. if RIPv1 has any place anymore these days, it's as a very
|
|
|
|
* simple way to distribute routing information (e.g. to embedded
|
|
|
|
* hosts / appliances) and the ability to give out RIPv1
|
|
|
|
* routing-information freely, while still requiring RIPv2
|
|
|
|
* authentication for any RESPONSEs might be vaguely useful.
|
|
|
|
*/
|
|
|
|
if (ri->auth_type != RIP_NO_AUTH && packet->version == RIPv1) {
|
|
|
|
/* Discard RIPv1 messages other than REQUESTs */
|
|
|
|
if (packet->command != RIP_REQUEST) {
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"RIPv1 dropped because authentication enabled");
|
2018-05-09 06:35:04 +02:00
|
|
|
ripd_notif_send_auth_type_failure(ifp->name);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2006-05-04 09:36:34 +02:00
|
|
|
}
|
|
|
|
} else if (ri->auth_type != RIP_NO_AUTH) {
|
|
|
|
const char *auth_desc;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-05-04 09:36:34 +02:00
|
|
|
if (rtenum == 0) {
|
|
|
|
/* There definitely is no authentication in the packet.
|
|
|
|
*/
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
|
|
|
zlog_debug(
|
|
|
|
"RIPv2 authentication failed: no auth RTE in packet");
|
2018-05-09 06:35:04 +02:00
|
|
|
ripd_notif_send_auth_type_failure(ifp->name);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2006-05-04 09:36:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-05-04 09:36:34 +02:00
|
|
|
/* First RTE must be an Authentication Family RTE */
|
|
|
|
if (packet->rte->family != htons(RIP_FAMILY_AUTH)) {
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
|
|
|
zlog_debug(
|
2020-03-27 12:35:23 +01:00
|
|
|
"RIPv2 dropped because authentication enabled");
|
2018-05-09 06:35:04 +02:00
|
|
|
ripd_notif_send_auth_type_failure(ifp->name);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2006-05-04 09:36:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Check RIPv2 authentication. */
|
2006-05-04 09:36:34 +02:00
|
|
|
switch (ntohs(packet->rte->tag)) {
|
|
|
|
case RIP_AUTH_SIMPLE_PASSWORD:
|
|
|
|
auth_desc = "simple";
|
|
|
|
ret = rip_auth_simple_password(packet->rte, &from, ifp);
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-05-04 09:36:34 +02:00
|
|
|
case RIP_AUTH_MD5:
|
|
|
|
auth_desc = "MD5";
|
|
|
|
ret = rip_auth_md5(packet, &from, len, ifp);
|
|
|
|
/* Reset RIP packet length to trim MD5 data. */
|
|
|
|
len = ret;
|
|
|
|
break;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-05-04 09:36:34 +02:00
|
|
|
default:
|
|
|
|
ret = 0;
|
|
|
|
auth_desc = "unknown type";
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
|
|
|
zlog_debug(
|
|
|
|
"RIPv2 Unknown authentication type %d",
|
|
|
|
ntohs(packet->rte->tag));
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2006-05-04 09:36:34 +02:00
|
|
|
if (ret) {
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
|
|
|
zlog_debug("RIPv2 %s authentication success",
|
|
|
|
auth_desc);
|
|
|
|
} else {
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
|
|
|
zlog_debug("RIPv2 %s authentication failure",
|
|
|
|
auth_desc);
|
2018-05-09 06:35:04 +02:00
|
|
|
ripd_notif_send_auth_failure(ifp->name);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2022-02-23 01:04:25 +01:00
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2006-05-04 09:36:34 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Process each command. */
|
|
|
|
switch (packet->command) {
|
|
|
|
case RIP_RESPONSE:
|
2004-10-22 12:27:28 +02:00
|
|
|
rip_response_process(packet, len, &from, ifc);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
case RIP_REQUEST:
|
|
|
|
case RIP_POLL:
|
2004-10-22 12:27:28 +02:00
|
|
|
rip_request_process(packet, len, &from, ifc);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
case RIP_TRACEON:
|
|
|
|
case RIP_TRACEOFF:
|
|
|
|
zlog_info(
|
|
|
|
"Obsolete command %s received, please sent it to routed",
|
2017-06-21 01:56:50 +02:00
|
|
|
lookup_msg(rip_msg, packet->command, NULL));
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
case RIP_POLL_ENTRY:
|
|
|
|
zlog_info("Obsolete command %s received",
|
2017-06-21 01:56:50 +02:00
|
|
|
lookup_msg(rip_msg, packet->command, NULL));
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
zlog_info("Unknown RIP command %d received", packet->command);
|
2021-10-14 17:12:37 +02:00
|
|
|
rip_peer_bad_packet(rip, ri, &from);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write routing table entry to the stream and return next index of
|
|
|
|
the routing table entry in the stream. */
|
|
|
|
static int rip_write_rte(int num, struct stream *s, struct prefix_ipv4 *p,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t version, struct rip_info *rinfo)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct in_addr mask;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Write routing table entry. */
|
|
|
|
if (version == RIPv1) {
|
|
|
|
stream_putw(s, AF_INET);
|
|
|
|
stream_putw(s, 0);
|
|
|
|
stream_put_ipv4(s, p->prefix.s_addr);
|
|
|
|
stream_put_ipv4(s, 0);
|
|
|
|
stream_put_ipv4(s, 0);
|
|
|
|
stream_putl(s, rinfo->metric_out);
|
|
|
|
} else {
|
|
|
|
masklen2ip(p->prefixlen, &mask);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
stream_putw(s, AF_INET);
|
2003-05-25 16:49:19 +02:00
|
|
|
stream_putw(s, rinfo->tag_out);
|
2002-12-13 21:15:29 +01:00
|
|
|
stream_put_ipv4(s, p->prefix.s_addr);
|
|
|
|
stream_put_ipv4(s, mask.s_addr);
|
|
|
|
stream_put_ipv4(s, rinfo->nexthop_out.s_addr);
|
|
|
|
stream_putl(s, rinfo->metric_out);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
return ++num;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send update to the ifp or spcified neighbor. */
|
2004-10-22 12:27:28 +02:00
|
|
|
void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
|
2018-03-27 21:13:34 +02:00
|
|
|
int route_type, uint8_t version)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip;
|
2002-12-13 21:15:29 +01:00
|
|
|
int ret;
|
|
|
|
struct stream *s;
|
|
|
|
struct route_node *rp;
|
|
|
|
struct rip_info *rinfo;
|
|
|
|
struct rip_interface *ri;
|
|
|
|
struct prefix_ipv4 *p;
|
|
|
|
struct prefix_ipv4 classfull;
|
2002-12-13 21:50:29 +01:00
|
|
|
struct prefix_ipv4 ifaddrclass;
|
2005-02-05 00:42:41 +01:00
|
|
|
struct key *key = NULL;
|
|
|
|
/* this might need to made dynamic if RIP ever supported auth methods
|
|
|
|
with larger key string sizes */
|
|
|
|
char auth_str[RIP_AUTH_SIMPLE_SIZE];
|
2005-10-26 01:31:05 +02:00
|
|
|
size_t doff = 0; /* offset of digest offset field */
|
2005-08-16 17:22:14 +02:00
|
|
|
int num = 0;
|
2002-12-13 21:15:29 +01:00
|
|
|
int rtemax;
|
2003-06-08 23:22:18 +02:00
|
|
|
int subnetted = 0;
|
2014-07-18 08:13:18 +02:00
|
|
|
struct list *list = NULL;
|
|
|
|
struct listnode *listnode = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Logging output event. */
|
2003-05-25 16:49:19 +02:00
|
|
|
if (IS_RIP_DEBUG_EVENT) {
|
2017-07-17 14:03:14 +02:00
|
|
|
if (to)
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_debug("update routes to neighbor %pI4",
|
|
|
|
&to->sin_addr);
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug("update routes on interface %s ifindex %d",
|
2004-10-22 12:27:28 +02:00
|
|
|
ifc->ifp->name, ifc->ifp->ifindex);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Get RIP interface. */
|
|
|
|
ri = ifc->ifp->info;
|
|
|
|
rip = ri->rip;
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Set output stream. */
|
|
|
|
s = rip->obuf;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Reset stream and RTE counter. */
|
|
|
|
stream_reset(s);
|
2014-06-25 09:43:15 +02:00
|
|
|
rtemax = RIP_MAX_RTE;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If output interface is in simple password authentication mode, we
|
|
|
|
need space for authentication data. */
|
|
|
|
if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
|
|
|
|
rtemax -= 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If output interface is in MD5 authentication mode, we need space
|
|
|
|
for authentication header and data. */
|
|
|
|
if (ri->auth_type == RIP_AUTH_MD5)
|
|
|
|
rtemax -= 2;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If output interface is in simple password authentication mode
|
|
|
|
and string or keychain is specified we need space for auth. data */
|
|
|
|
if (ri->auth_type != RIP_NO_AUTH) {
|
|
|
|
if (ri->key_chain) {
|
|
|
|
struct keychain *keychain;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
keychain = keychain_lookup(ri->key_chain);
|
|
|
|
if (keychain)
|
|
|
|
key = key_lookup_for_send(keychain);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
/* to be passed to auth functions later */
|
2019-02-26 20:55:28 +01:00
|
|
|
rip_auth_prepare_str_send(ri, key, auth_str, sizeof(auth_str));
|
2018-08-06 08:14:00 +02:00
|
|
|
if (strlen(auth_str) == 0)
|
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2005-02-05 00:42:41 +01:00
|
|
|
if (version == RIPv1) {
|
2022-05-11 12:14:01 +02:00
|
|
|
memcpy(&ifaddrclass, ifc->address, sizeof(ifaddrclass));
|
2002-12-13 21:15:29 +01:00
|
|
|
apply_classful_mask_ipv4(&ifaddrclass);
|
2002-12-13 21:50:29 +01:00
|
|
|
subnetted = 0;
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ifc->address->prefixlen > ifaddrclass.prefixlen)
|
2003-06-08 23:22:18 +02:00
|
|
|
subnetted = 1;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
|
|
|
|
list = rp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (list == NULL)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (listcount(list) == 0)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* Apply output filters. */
|
|
|
|
ret = rip_filter(RIP_FILTER_OUT, p, ri);
|
|
|
|
if (ret < 0)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* Changed route only output. */
|
|
|
|
if (route_type == rip_changed_route &&
|
|
|
|
(!(rinfo->flags & RIP_RTF_CHANGED)))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* 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;
|
2018-03-21 12:46:36 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (!suppress && rinfo->type == ZEBRA_ROUTE_CONNECT) {
|
2023-11-22 19:05:41 +01:00
|
|
|
frr_each (if_connected, ifc->ifp->connected,
|
|
|
|
tmp_ifc)
|
2022-02-16 14:05:34 +01:00
|
|
|
if (prefix_match((struct prefix *)p,
|
|
|
|
tmp_ifc->address)) {
|
|
|
|
suppress = 1;
|
|
|
|
break;
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (suppress)
|
|
|
|
continue;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* 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;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* 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;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* 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);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (ret == RMAP_DENYMATCH) {
|
|
|
|
if (IS_RIP_DEBUG_PACKET)
|
|
|
|
zlog_debug(
|
|
|
|
"%pFX is filtered by route-map",
|
|
|
|
p);
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* 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;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* 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) {
|
2023-11-22 19:05:41 +01:00
|
|
|
frr_each (if_connected, ifc->ifp->connected,
|
|
|
|
tmp_ifc)
|
2022-02-16 14:05:34 +01:00
|
|
|
if (prefix_match((struct prefix *)p,
|
|
|
|
tmp_ifc->address)) {
|
2018-03-21 12:46:36 +01:00
|
|
|
rinfo->metric_out =
|
2014-07-18 08:13:18 +02:00
|
|
|
RIP_METRIC_INFINITY;
|
2022-02-16 14:05:34 +01:00
|
|
|
break;
|
|
|
|
}
|
2003-05-25 16:49:19 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* 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);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* 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);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Flush unwritten RTE. */
|
|
|
|
if (num != 0) {
|
|
|
|
if (version == RIPv2 && ri->auth_type == RIP_AUTH_MD5)
|
2005-02-05 00:42:41 +01:00
|
|
|
rip_auth_md5_set(s, ri, doff, auth_str,
|
|
|
|
RIP_AUTH_SIMPLE_SIZE);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
ret = rip_send_packet(STREAM_DATA(s), stream_get_endp(s), to,
|
|
|
|
ifc);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ret >= 0 && IS_RIP_DEBUG_SEND)
|
|
|
|
rip_packet_dump((struct rip_packet *)STREAM_DATA(s),
|
|
|
|
stream_get_endp(s), "SEND");
|
|
|
|
stream_reset(s);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Statistics updates. */
|
|
|
|
ri->sent_updates++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send RIP packet to the interface. */
|
2018-03-27 21:13:34 +02:00
|
|
|
static void rip_update_interface(struct connected *ifc, uint8_t version,
|
2004-10-22 12:27:28 +02:00
|
|
|
int route_type)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2016-11-10 15:55:09 +01:00
|
|
|
struct interface *ifp = ifc->ifp;
|
|
|
|
struct rip_interface *ri = ifp->info;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct sockaddr_in to;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* When RIP version is 2 and multicast enable interface. */
|
2016-11-10 15:55:09 +01:00
|
|
|
if (version == RIPv2 && !ri->v2_broadcast && if_is_multicast(ifp)) {
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2016-11-10 15:55:09 +01:00
|
|
|
zlog_debug("multicast announce on %s ", ifp->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
rip_output_process(ifc, NULL, route_type, version);
|
2002-12-13 21:15:29 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* If we can't send multicast packet, send it with unicast. */
|
2016-11-10 15:55:09 +01:00
|
|
|
if (if_is_broadcast(ifp) || if_is_pointopoint(ifp)) {
|
2004-10-22 12:27:28 +02:00
|
|
|
if (ifc->address->family == AF_INET) {
|
|
|
|
/* Destination address and port setting. */
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&to, 0, sizeof(to));
|
2004-10-22 12:27:28 +02:00
|
|
|
if (ifc->destination)
|
[PtP over ethernet] New peer flag allows much more addressing flexibility
2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* if.h: (struct connected) Add new ZEBRA_IFA_PEER flag indicating
whether a peer address has been configured. Comment now shows
the new interpretation of the destination addr: if ZEBRA_IFA_PEER
is set, then it must contain the destination address, otherwise
it may contain the broadcast address or be NULL.
(CONNECTED_DEST_HOST,CONNECTED_POINTOPOINT_HOST) Remove obsolete
macros that were specific to IPv4 and not fully general.
(CONNECTED_PEER) New macro to check ZEBRA_IFA_PEER flag.
(CONNECTED_PREFIX) New macro giving the prefix to insert into
the RIB: if CONNECTED_PEER, then use the destination (peer) address,
else use the address field.
(CONNECTED_ID) New macro to come up with an identifying address
for the struct connected.
* if.c: (if_lookup_address, connected_lookup_address) Streamline
logic with new CONNECTED_PREFIX macro.
* prefix.h: (PREFIX_COPY_IPV4, PREFIX_COPY_IPV6) New macros
for better performance than the general prefix_copy function.
* zclient.c: (zebra_interface_address_read) For non-null destination
addresses, set prefixlen to equal the address prefixlen. This
is needed to get the new CONNECTED_PREFIX macro to work properly.
* connected.c: (connected_up_ipv4, connected_down_ipv4,
connected_up_ipv6, connected_down_ipv6) Simplify logic using the
new CONNECTED_PREFIX macro.
(connected_add_ipv4) Set prefixlen in destination addresses (required
by the CONNECTED_PREFIX macro). Use CONNECTED_PEER macro instead
of testing for IFF_POINTOPOINT. Delete invalid warning message.
Warn about cases where the ZEBRA_IFA_PEER is set but no
destination address has been supplied (and turn off the flag).
(connected_add_ipv6) Add new flags argument so callers may set
the ZEBRA_IFA_PEER flag. If peer/broadcast address satisfies
IN6_IS_ADDR_UNSPECIFIED, then reject it with a warning.
Set prefixlen in destination address so CONNECTED_PREFIX will work.
* connected.h: (connected_add_ipv6) Add new flags argument so
callers may set the ZEBRA_IFA_PEER flag.
* interface.c: (connected_dump_vty) Use CONNECTED_PEER macro
to decide whether the destination address is a peer or broadcast
address (instead of checking IFF_BROADCAST and IFF_POINTOPOINT).
* if_ioctl.c: (if_getaddrs) Instead of setting a peer address
only when the IFF_POINTOPOINT is set, we now accept a peer
address whenever it is available and not the same as the local
address. Otherwise (no peer address assigned), we check
for a broadcast address (regardless of the IFF_BROADCAST flag).
And must now pass a flags value of ZEBRA_IFA_PEER to
connected_add_ipv4 when a peer address is assigned.
The same new logic is used with the IPv6 code as well (and we
pass the new flags argument to connected_add_ipv6).
(if_get_addr) Do not bother to check IFF_POINTOPOINT: just
issue the SIOCGIFDSTADDR ioctl and see if we get back
a peer address not matching the local address (and set
the ZEBRA_IFA_PEER in that case). If there's no peer address,
try to grab SIOCGIFBRDADDR regardless of whether IFF_BROADCAST is set.
* if_ioctl_solaris.c: (if_get_addr) Just try the SIOCGLIFDSTADDR ioctl
without bothering to check the IFF_POINTOPOINT flag. And if
no peer address was found, just try the SIOCGLIFBRDADDR ioctl
without checking the IFF_BROADCAST flag. Call connected_add_ipv4
and connected_add_ipv6 with appropriate flags.
* if_proc.c: (ifaddr_proc_ipv6) Must pass new flags argument to
connected_add_ipv6.
* kernel_socket.c: (ifam_read) Must pass new flags argument to
connected_add_ipv6.
* rt_netlink.c: (netlink_interface_addr) Copy logic from iproute2
to determine local and possible peer address (so there's no longer
a test for IFF_POINTOPOINT). Set ZEBRA_IFA_PEER flag appropriately.
Pass new flags argument to connected_add_ipv6.
(netlink_address) Test !CONNECTED_PEER instead of if_is_broadcast
to determine whether the connected destination address is a
broadcast address.
* bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete)
Simplify logic by using new CONNECTED_PREFIX macro.
* ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix,
ospf_if_lookup_recv_if) Simplify logic using new CONNECTED_PREFIX
macro.
* ospf_lsa.c: (lsa_link_ptop_set) Using the new CONNECTED_PREFIX
macro, both options collapse into the same code.
* ospf_snmp.c: (ospf_snmp_if_update) Simplify logic using new
CONNECTED_ID macro.
(ospf_snmp_is_if_have_addr) Simplify logic using new CONNECTED_PREFIX
macro.
* ospf_vty.c: (show_ip_ospf_interface_sub) Use new CONNECTED_PEER macro
instead of testing the IFF_POINTOPOINT flag.
* ospfd.c: (ospf_network_match_iface) Use new CONNECTED_PEER macro
instead of testing with if_is_pointopoint. And add commented-out
code to implement alternative (in my opinion) more elegant behavior
that has no special-case treatment for PtP addresses.
(ospf_network_run) Use new CONNECTED_ID macro to simplify logic.
* rip_interface.c: (rip_interface_multicast_set) Use new CONNECTED_ID
macro to simplify logic.
(rip_request_interface_send) Fix minor bug: ipv4_broadcast_addr does
not give a useful result if prefixlen is 32 (we require a peer
address in such cases).
* ripd.c: (rip_update_interface) Fix same bug as above.
2006-12-12 20:18:21 +01:00
|
|
|
/* use specified broadcast or peer destination
|
|
|
|
* addr */
|
2004-10-22 12:27:28 +02:00
|
|
|
to.sin_addr = ifc->destination->u.prefix4;
|
2021-07-01 16:42:03 +02:00
|
|
|
else if (ifc->address->prefixlen < IPV4_MAX_BITLEN)
|
2004-10-22 12:27:28 +02:00
|
|
|
/* calculate the appropriate broadcast address
|
|
|
|
*/
|
|
|
|
to.sin_addr.s_addr = ipv4_broadcast_addr(
|
|
|
|
ifc->address->u.prefix4.s_addr,
|
|
|
|
ifc->address->prefixlen);
|
[PtP over ethernet] New peer flag allows much more addressing flexibility
2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* if.h: (struct connected) Add new ZEBRA_IFA_PEER flag indicating
whether a peer address has been configured. Comment now shows
the new interpretation of the destination addr: if ZEBRA_IFA_PEER
is set, then it must contain the destination address, otherwise
it may contain the broadcast address or be NULL.
(CONNECTED_DEST_HOST,CONNECTED_POINTOPOINT_HOST) Remove obsolete
macros that were specific to IPv4 and not fully general.
(CONNECTED_PEER) New macro to check ZEBRA_IFA_PEER flag.
(CONNECTED_PREFIX) New macro giving the prefix to insert into
the RIB: if CONNECTED_PEER, then use the destination (peer) address,
else use the address field.
(CONNECTED_ID) New macro to come up with an identifying address
for the struct connected.
* if.c: (if_lookup_address, connected_lookup_address) Streamline
logic with new CONNECTED_PREFIX macro.
* prefix.h: (PREFIX_COPY_IPV4, PREFIX_COPY_IPV6) New macros
for better performance than the general prefix_copy function.
* zclient.c: (zebra_interface_address_read) For non-null destination
addresses, set prefixlen to equal the address prefixlen. This
is needed to get the new CONNECTED_PREFIX macro to work properly.
* connected.c: (connected_up_ipv4, connected_down_ipv4,
connected_up_ipv6, connected_down_ipv6) Simplify logic using the
new CONNECTED_PREFIX macro.
(connected_add_ipv4) Set prefixlen in destination addresses (required
by the CONNECTED_PREFIX macro). Use CONNECTED_PEER macro instead
of testing for IFF_POINTOPOINT. Delete invalid warning message.
Warn about cases where the ZEBRA_IFA_PEER is set but no
destination address has been supplied (and turn off the flag).
(connected_add_ipv6) Add new flags argument so callers may set
the ZEBRA_IFA_PEER flag. If peer/broadcast address satisfies
IN6_IS_ADDR_UNSPECIFIED, then reject it with a warning.
Set prefixlen in destination address so CONNECTED_PREFIX will work.
* connected.h: (connected_add_ipv6) Add new flags argument so
callers may set the ZEBRA_IFA_PEER flag.
* interface.c: (connected_dump_vty) Use CONNECTED_PEER macro
to decide whether the destination address is a peer or broadcast
address (instead of checking IFF_BROADCAST and IFF_POINTOPOINT).
* if_ioctl.c: (if_getaddrs) Instead of setting a peer address
only when the IFF_POINTOPOINT is set, we now accept a peer
address whenever it is available and not the same as the local
address. Otherwise (no peer address assigned), we check
for a broadcast address (regardless of the IFF_BROADCAST flag).
And must now pass a flags value of ZEBRA_IFA_PEER to
connected_add_ipv4 when a peer address is assigned.
The same new logic is used with the IPv6 code as well (and we
pass the new flags argument to connected_add_ipv6).
(if_get_addr) Do not bother to check IFF_POINTOPOINT: just
issue the SIOCGIFDSTADDR ioctl and see if we get back
a peer address not matching the local address (and set
the ZEBRA_IFA_PEER in that case). If there's no peer address,
try to grab SIOCGIFBRDADDR regardless of whether IFF_BROADCAST is set.
* if_ioctl_solaris.c: (if_get_addr) Just try the SIOCGLIFDSTADDR ioctl
without bothering to check the IFF_POINTOPOINT flag. And if
no peer address was found, just try the SIOCGLIFBRDADDR ioctl
without checking the IFF_BROADCAST flag. Call connected_add_ipv4
and connected_add_ipv6 with appropriate flags.
* if_proc.c: (ifaddr_proc_ipv6) Must pass new flags argument to
connected_add_ipv6.
* kernel_socket.c: (ifam_read) Must pass new flags argument to
connected_add_ipv6.
* rt_netlink.c: (netlink_interface_addr) Copy logic from iproute2
to determine local and possible peer address (so there's no longer
a test for IFF_POINTOPOINT). Set ZEBRA_IFA_PEER flag appropriately.
Pass new flags argument to connected_add_ipv6.
(netlink_address) Test !CONNECTED_PEER instead of if_is_broadcast
to determine whether the connected destination address is a
broadcast address.
* bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete)
Simplify logic by using new CONNECTED_PREFIX macro.
* ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix,
ospf_if_lookup_recv_if) Simplify logic using new CONNECTED_PREFIX
macro.
* ospf_lsa.c: (lsa_link_ptop_set) Using the new CONNECTED_PREFIX
macro, both options collapse into the same code.
* ospf_snmp.c: (ospf_snmp_if_update) Simplify logic using new
CONNECTED_ID macro.
(ospf_snmp_is_if_have_addr) Simplify logic using new CONNECTED_PREFIX
macro.
* ospf_vty.c: (show_ip_ospf_interface_sub) Use new CONNECTED_PEER macro
instead of testing the IFF_POINTOPOINT flag.
* ospfd.c: (ospf_network_match_iface) Use new CONNECTED_PEER macro
instead of testing with if_is_pointopoint. And add commented-out
code to implement alternative (in my opinion) more elegant behavior
that has no special-case treatment for PtP addresses.
(ospf_network_run) Use new CONNECTED_ID macro to simplify logic.
* rip_interface.c: (rip_interface_multicast_set) Use new CONNECTED_ID
macro to simplify logic.
(rip_request_interface_send) Fix minor bug: ipv4_broadcast_addr does
not give a useful result if prefixlen is 32 (we require a peer
address in such cases).
* ripd.c: (rip_update_interface) Fix same bug as above.
2006-12-12 20:18:21 +01:00
|
|
|
else
|
|
|
|
/* do not know where to send the packet */
|
|
|
|
return;
|
2004-10-22 12:27:28 +02:00
|
|
|
to.sin_port = htons(RIP_PORT_DEFAULT);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2020-10-22 20:16:33 +02:00
|
|
|
zlog_debug("%s announce to %pI4 on %s",
|
[PtP over ethernet] New peer flag allows much more addressing flexibility
2006-12-12 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
* if.h: (struct connected) Add new ZEBRA_IFA_PEER flag indicating
whether a peer address has been configured. Comment now shows
the new interpretation of the destination addr: if ZEBRA_IFA_PEER
is set, then it must contain the destination address, otherwise
it may contain the broadcast address or be NULL.
(CONNECTED_DEST_HOST,CONNECTED_POINTOPOINT_HOST) Remove obsolete
macros that were specific to IPv4 and not fully general.
(CONNECTED_PEER) New macro to check ZEBRA_IFA_PEER flag.
(CONNECTED_PREFIX) New macro giving the prefix to insert into
the RIB: if CONNECTED_PEER, then use the destination (peer) address,
else use the address field.
(CONNECTED_ID) New macro to come up with an identifying address
for the struct connected.
* if.c: (if_lookup_address, connected_lookup_address) Streamline
logic with new CONNECTED_PREFIX macro.
* prefix.h: (PREFIX_COPY_IPV4, PREFIX_COPY_IPV6) New macros
for better performance than the general prefix_copy function.
* zclient.c: (zebra_interface_address_read) For non-null destination
addresses, set prefixlen to equal the address prefixlen. This
is needed to get the new CONNECTED_PREFIX macro to work properly.
* connected.c: (connected_up_ipv4, connected_down_ipv4,
connected_up_ipv6, connected_down_ipv6) Simplify logic using the
new CONNECTED_PREFIX macro.
(connected_add_ipv4) Set prefixlen in destination addresses (required
by the CONNECTED_PREFIX macro). Use CONNECTED_PEER macro instead
of testing for IFF_POINTOPOINT. Delete invalid warning message.
Warn about cases where the ZEBRA_IFA_PEER is set but no
destination address has been supplied (and turn off the flag).
(connected_add_ipv6) Add new flags argument so callers may set
the ZEBRA_IFA_PEER flag. If peer/broadcast address satisfies
IN6_IS_ADDR_UNSPECIFIED, then reject it with a warning.
Set prefixlen in destination address so CONNECTED_PREFIX will work.
* connected.h: (connected_add_ipv6) Add new flags argument so
callers may set the ZEBRA_IFA_PEER flag.
* interface.c: (connected_dump_vty) Use CONNECTED_PEER macro
to decide whether the destination address is a peer or broadcast
address (instead of checking IFF_BROADCAST and IFF_POINTOPOINT).
* if_ioctl.c: (if_getaddrs) Instead of setting a peer address
only when the IFF_POINTOPOINT is set, we now accept a peer
address whenever it is available and not the same as the local
address. Otherwise (no peer address assigned), we check
for a broadcast address (regardless of the IFF_BROADCAST flag).
And must now pass a flags value of ZEBRA_IFA_PEER to
connected_add_ipv4 when a peer address is assigned.
The same new logic is used with the IPv6 code as well (and we
pass the new flags argument to connected_add_ipv6).
(if_get_addr) Do not bother to check IFF_POINTOPOINT: just
issue the SIOCGIFDSTADDR ioctl and see if we get back
a peer address not matching the local address (and set
the ZEBRA_IFA_PEER in that case). If there's no peer address,
try to grab SIOCGIFBRDADDR regardless of whether IFF_BROADCAST is set.
* if_ioctl_solaris.c: (if_get_addr) Just try the SIOCGLIFDSTADDR ioctl
without bothering to check the IFF_POINTOPOINT flag. And if
no peer address was found, just try the SIOCGLIFBRDADDR ioctl
without checking the IFF_BROADCAST flag. Call connected_add_ipv4
and connected_add_ipv6 with appropriate flags.
* if_proc.c: (ifaddr_proc_ipv6) Must pass new flags argument to
connected_add_ipv6.
* kernel_socket.c: (ifam_read) Must pass new flags argument to
connected_add_ipv6.
* rt_netlink.c: (netlink_interface_addr) Copy logic from iproute2
to determine local and possible peer address (so there's no longer
a test for IFF_POINTOPOINT). Set ZEBRA_IFA_PEER flag appropriately.
Pass new flags argument to connected_add_ipv6.
(netlink_address) Test !CONNECTED_PEER instead of if_is_broadcast
to determine whether the connected destination address is a
broadcast address.
* bgp_nexthop.c: (bgp_connected_add, bgp_connected_delete)
Simplify logic by using new CONNECTED_PREFIX macro.
* ospf_interface.c: (ospf_if_is_configured, ospf_if_lookup_by_prefix,
ospf_if_lookup_recv_if) Simplify logic using new CONNECTED_PREFIX
macro.
* ospf_lsa.c: (lsa_link_ptop_set) Using the new CONNECTED_PREFIX
macro, both options collapse into the same code.
* ospf_snmp.c: (ospf_snmp_if_update) Simplify logic using new
CONNECTED_ID macro.
(ospf_snmp_is_if_have_addr) Simplify logic using new CONNECTED_PREFIX
macro.
* ospf_vty.c: (show_ip_ospf_interface_sub) Use new CONNECTED_PEER macro
instead of testing the IFF_POINTOPOINT flag.
* ospfd.c: (ospf_network_match_iface) Use new CONNECTED_PEER macro
instead of testing with if_is_pointopoint. And add commented-out
code to implement alternative (in my opinion) more elegant behavior
that has no special-case treatment for PtP addresses.
(ospf_network_run) Use new CONNECTED_ID macro to simplify logic.
* rip_interface.c: (rip_interface_multicast_set) Use new CONNECTED_ID
macro to simplify logic.
(rip_request_interface_send) Fix minor bug: ipv4_broadcast_addr does
not give a useful result if prefixlen is 32 (we require a peer
address in such cases).
* ripd.c: (rip_update_interface) Fix same bug as above.
2006-12-12 20:18:21 +01:00
|
|
|
CONNECTED_PEER(ifc) ? "unicast"
|
|
|
|
: "broadcast",
|
2020-10-22 20:16:33 +02:00
|
|
|
&to.sin_addr, ifp->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-22 12:27:28 +02:00
|
|
|
rip_output_process(ifc, &to, route_type, version);
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update send to all interface and neighbor. */
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_update_process(struct rip *rip, int route_type)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2003-10-16 01:20:17 +02:00
|
|
|
struct connected *connected;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct interface *ifp;
|
|
|
|
struct rip_interface *ri;
|
|
|
|
struct route_node *rp;
|
|
|
|
struct sockaddr_in to;
|
2016-05-12 00:52:30 +02:00
|
|
|
struct prefix *p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Send RIP update to each interface. */
|
2019-01-04 22:08:10 +01:00
|
|
|
FOR_ALL_INTERFACES (rip->vrf, ifp) {
|
2002-12-13 21:15:29 +01:00
|
|
|
if (if_is_loopback(ifp))
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 22:03:13 +01:00
|
|
|
if (!if_is_operative(ifp))
|
2002-12-13 21:15:29 +01:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Fetch RIP interface information. */
|
|
|
|
ri = ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* When passive interface is specified, suppress announce to the
|
|
|
|
interface. */
|
|
|
|
if (ri->passive)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (!ri->running)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/*
|
|
|
|
* 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 */
|
2023-11-22 19:05:41 +01:00
|
|
|
frr_each (if_connected, ifp->connected, connected) {
|
2022-02-16 14:05:34 +01:00
|
|
|
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);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-10-16 01:20:17 +02:00
|
|
|
/* RIP send updates to each neighbor. */
|
2022-02-16 14:05:34 +01:00
|
|
|
for (rp = route_top(rip->neighbor); rp; rp = route_next(rp)) {
|
|
|
|
if (rp->info == NULL)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
p = &rp->p;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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;
|
2006-04-28 18:22:36 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* RIP's periodical timer. */
|
2022-03-01 22:18:12 +01:00
|
|
|
static void rip_update(struct event *t)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct rip *rip = EVENT_ARG(t);
|
2019-01-04 22:08:10 +01:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug("update timer fire!");
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Process update output. */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_update_process(rip, rip_all_route);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Triggered updates may be suppressed if a regular update is due by
|
|
|
|
the time the triggered update would be sent. */
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rip->t_triggered_interval);
|
2002-12-13 21:15:29 +01:00
|
|
|
rip->trigger = 0;
|
|
|
|
|
|
|
|
/* Register myself. */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_event(rip, RIP_UPDATE_EVENT, 0);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Walk down the RIP routing table then clear changed flag. */
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_clear_changed_flag(struct rip *rip)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_node *rp;
|
2014-07-18 08:13:18 +02:00
|
|
|
struct rip_info *rinfo = NULL;
|
|
|
|
struct list *list = NULL;
|
|
|
|
struct listnode *listnode = NULL;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Triggered update interval timer. */
|
2022-03-01 22:18:12 +01:00
|
|
|
static void rip_triggered_interval(struct event *t)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct rip *rip = EVENT_ARG(t);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
if (rip->trigger) {
|
|
|
|
rip->trigger = 0;
|
|
|
|
rip_triggered_update(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Execute triggered update. */
|
2022-03-01 22:18:12 +01:00
|
|
|
static void rip_triggered_update(struct event *t)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2022-12-25 16:26:52 +01:00
|
|
|
struct rip *rip = EVENT_ARG(t);
|
2002-12-13 21:15:29 +01:00
|
|
|
int interval;
|
|
|
|
|
|
|
|
/* Cancel interval timer. */
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rip->t_triggered_interval);
|
2002-12-13 21:15:29 +01:00
|
|
|
rip->trigger = 0;
|
|
|
|
|
|
|
|
/* Logging triggered update. */
|
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
2004-12-08 20:24:06 +01:00
|
|
|
zlog_debug("triggered update!");
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Split Horizon processing is done when generating triggered
|
|
|
|
updates as well as normal updates (see section 2.6). */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_update_process(rip, rip_changed_route);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Once all of the triggered updates have been generated, the route
|
|
|
|
change flags should be cleared. */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_clear_changed_flag(rip);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* After a triggered update is sent, a timer should be set for a
|
|
|
|
random interval between 1 and 5 seconds. If other changes that
|
|
|
|
would trigger updates occur before the timer expires, a single
|
|
|
|
update is triggered when the timer expires. */
|
2020-04-17 15:35:15 +02:00
|
|
|
interval = (frr_weak_random() % 5) + 1;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, rip_triggered_interval, rip, interval,
|
|
|
|
&rip->t_triggered_interval);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Withdraw redistributed route. */
|
2019-01-04 22:08:10 +01:00
|
|
|
void rip_redistribute_withdraw(struct rip *rip, int type)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2002-12-13 21:15:29 +01:00
|
|
|
struct route_node *rp;
|
2014-07-18 08:13:18 +02:00
|
|
|
struct rip_info *rinfo = NULL;
|
|
|
|
struct list *list = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
|
|
|
|
list = rp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (list == NULL)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
rinfo = listgetdata(listhead(list));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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);
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_timeout);
|
2022-02-16 14:05:34 +01:00
|
|
|
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));
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
|
|
|
|
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip_lookup_by_vrf_id(vrf_id_t vrf_id)
|
|
|
|
{
|
|
|
|
struct vrf *vrf;
|
|
|
|
|
|
|
|
vrf = vrf_lookup_by_id(vrf_id);
|
|
|
|
if (!vrf)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return vrf->info;
|
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip_lookup_by_vrf_name(const char *vrf_name)
|
|
|
|
{
|
|
|
|
struct rip rip;
|
|
|
|
|
|
|
|
rip.vrf_name = (char *)vrf_name;
|
|
|
|
|
|
|
|
return RB_FIND(rip_instance_head, &rip_instances, &rip);
|
|
|
|
}
|
|
|
|
|
2023-05-04 08:13:07 +02:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Create new RIP instance and set it to global variable. */
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip_create(const char *vrf_name, struct vrf *vrf, int socket)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip;
|
|
|
|
|
2014-07-18 08:13:18 +02:00
|
|
|
rip = XCALLOC(MTYPE_RIP, sizeof(struct rip));
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf_name);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Set initial value. */
|
2023-05-04 08:13:07 +02:00
|
|
|
rip->ecmp = yang_get_default_uint8("%s/allow-ecmp", RIP_INSTANCE);
|
2018-05-09 06:34:58 +02:00
|
|
|
rip->default_metric =
|
|
|
|
yang_get_default_uint8("%s/default-metric", RIP_INSTANCE);
|
|
|
|
rip->distance =
|
|
|
|
yang_get_default_uint8("%s/distance/default", RIP_INSTANCE);
|
2018-05-09 06:35:00 +02:00
|
|
|
rip->passive_default =
|
|
|
|
yang_get_default_bool("%s/passive-default", RIP_INSTANCE);
|
2018-05-09 06:34:58 +02:00
|
|
|
rip->garbage_time = yang_get_default_uint32("%s/timers/flush-interval",
|
|
|
|
RIP_INSTANCE);
|
|
|
|
rip->timeout_time = yang_get_default_uint32(
|
|
|
|
"%s/timers/holddown-interval", RIP_INSTANCE);
|
|
|
|
rip->update_time = yang_get_default_uint32("%s/timers/update-interval",
|
|
|
|
RIP_INSTANCE);
|
|
|
|
rip->version_send =
|
|
|
|
yang_get_default_enum("%s/version/send", RIP_INSTANCE);
|
|
|
|
rip->version_recv =
|
|
|
|
yang_get_default_enum("%s/version/receive", RIP_INSTANCE);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Initialize RIP data structures. */
|
2002-12-13 21:15:29 +01:00
|
|
|
rip->table = route_table_init();
|
2019-01-04 22:08:10 +01:00
|
|
|
route_table_set_info(rip->table, rip);
|
2002-12-13 21:15:29 +01:00
|
|
|
rip->neighbor = route_table_init();
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->peer_list = list_new();
|
|
|
|
rip->peer_list->cmp = (int (*)(void *, void *))rip_peer_list_cmp;
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->peer_list->del = rip_peer_list_del;
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->distance_table = route_table_init();
|
|
|
|
rip->distance_table->cleanup = rip_distance_table_node_cleanup;
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->enable_interface = vector_init(1);
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->enable_network = route_table_init();
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->passive_nondefault = vector_init(1);
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->offset_list_master = list_new();
|
|
|
|
rip->offset_list_master->cmp = (int (*)(void *, void *))offset_list_cmp;
|
2019-04-18 17:32:19 +02:00
|
|
|
rip->offset_list_master->del = (void (*)(void *))offset_list_free;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Distribute list install. */
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->distribute_ctx = distribute_list_ctx_create(vrf);
|
2019-01-04 22:08:10 +01:00
|
|
|
distribute_list_add_hook(rip->distribute_ctx, rip_distribute_update);
|
|
|
|
distribute_list_delete_hook(rip->distribute_ctx, rip_distribute_update);
|
|
|
|
|
2019-01-14 08:58:36 +01:00
|
|
|
/* if rmap install. */
|
2019-03-02 19:00:46 +01:00
|
|
|
rip->if_rmap_ctx = if_rmap_ctx_create(vrf_name);
|
2019-01-14 08:58:36 +01:00
|
|
|
if_rmap_hook_add(rip->if_rmap_ctx, rip_if_rmap_update);
|
|
|
|
if_rmap_hook_delete(rip->if_rmap_ctx, rip_if_rmap_update);
|
|
|
|
|
2003-05-25 16:49:19 +02:00
|
|
|
/* Make output stream. */
|
|
|
|
rip->obuf = stream_new(1500);
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Enable the routing instance if possible. */
|
|
|
|
if (vrf && vrf_is_enabled(vrf))
|
|
|
|
rip_instance_enable(rip, vrf, socket);
|
|
|
|
else {
|
|
|
|
rip->vrf = NULL;
|
|
|
|
rip->sock = -1;
|
2019-01-04 22:08:10 +01:00
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
RB_INSERT(rip_instance_head, &rip_instances, rip);
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
return rip;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* Sned RIP request to the destination. */
|
|
|
|
int rip_request_send(struct sockaddr_in *to, struct interface *ifp,
|
2018-03-27 21:13:34 +02:00
|
|
|
uint8_t version, struct connected *connected)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2002-12-13 21:15:29 +01:00
|
|
|
struct rte *rte;
|
|
|
|
struct rip_packet rip_packet;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
memset(&rip_packet, 0, sizeof(rip_packet));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
rip_packet.command = RIP_REQUEST;
|
|
|
|
rip_packet.version = version;
|
|
|
|
rte = rip_packet.rte;
|
|
|
|
rte->metric = htonl(RIP_METRIC_INFINITY);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (connected) {
|
2017-07-17 14:03:14 +02:00
|
|
|
/*
|
2004-01-23 16:31:42 +01:00
|
|
|
* connected is only sent for ripv1 case, or when
|
|
|
|
* interface does not support multicast. Caller loops
|
2002-12-13 21:15:29 +01:00
|
|
|
* over each connected address for this case.
|
2017-07-17 14:03:14 +02:00
|
|
|
*/
|
2018-03-27 21:13:34 +02:00
|
|
|
if (rip_send_packet((uint8_t *)&rip_packet, sizeof(rip_packet),
|
2004-10-22 12:27:28 +02:00
|
|
|
to, connected)
|
|
|
|
!= sizeof(rip_packet))
|
2004-01-23 16:31:42 +01:00
|
|
|
return -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2004-01-23 16:31:42 +01:00
|
|
|
return sizeof(rip_packet);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
/* send request on each connected network */
|
2023-11-22 19:05:41 +01:00
|
|
|
frr_each (if_connected, ifp->connected, connected) {
|
2002-12-13 21:15:29 +01:00
|
|
|
struct prefix_ipv4 *p;
|
|
|
|
|
|
|
|
p = (struct prefix_ipv4 *)connected->address;
|
|
|
|
|
2016-12-07 16:01:47 +01:00
|
|
|
if (p->family != AF_INET)
|
|
|
|
continue;
|
|
|
|
|
2018-03-27 21:13:34 +02:00
|
|
|
if (rip_send_packet((uint8_t *)&rip_packet, sizeof(rip_packet),
|
2004-10-22 12:27:28 +02:00
|
|
|
to, connected)
|
|
|
|
!= sizeof(rip_packet))
|
2002-12-13 21:15:29 +01:00
|
|
|
return -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2004-01-23 16:31:42 +01:00
|
|
|
return sizeof(rip_packet);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2004-01-23 16:31:42 +01:00
|
|
|
static int rip_update_jitter(unsigned long time)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2004-05-05 16:09:37 +02:00
|
|
|
#define JITTER_BOUND 4
|
|
|
|
/* We want to get the jitter to +/- 1/JITTER_BOUND the interval.
|
|
|
|
Given that, we cannot let time be less than JITTER_BOUND seconds.
|
|
|
|
The RIPv2 RFC says jitter should be small compared to
|
|
|
|
update_time. We consider 1/JITTER_BOUND to be small.
|
|
|
|
*/
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-05-05 16:09:37 +02:00
|
|
|
int jitter_input = time;
|
|
|
|
int jitter;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-05-05 16:09:37 +02:00
|
|
|
if (jitter_input < JITTER_BOUND)
|
|
|
|
jitter_input = JITTER_BOUND;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2020-04-17 15:35:15 +02:00
|
|
|
jitter = (((frr_weak_random() % ((jitter_input * 2) + 1))
|
|
|
|
- jitter_input));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-05-05 16:09:37 +02:00
|
|
|
return jitter / JITTER_BOUND;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
void rip_event(struct rip *rip, enum rip_event event, int sock)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
int jitter = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
switch (event) {
|
|
|
|
case RIP_READ:
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_read(master, rip_read, rip, sock, &rip->t_read);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
case RIP_UPDATE_EVENT:
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rip->t_update);
|
2002-12-13 21:15:29 +01:00
|
|
|
jitter = rip_update_jitter(rip->update_time);
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_timer(master, rip_update, rip,
|
|
|
|
sock ? 2 : rip->update_time + jitter,
|
|
|
|
&rip->t_update);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
case RIP_TRIGGERED_UPDATE:
|
|
|
|
if (rip->t_triggered_interval)
|
2017-05-05 23:22:25 +02:00
|
|
|
rip->trigger = 1;
|
2017-04-25 00:33:25 +02:00
|
|
|
else
|
2022-05-20 20:19:08 +02:00
|
|
|
event_add_event(master, rip_triggered_update, rip, 0,
|
|
|
|
&rip->t_triggered_update);
|
2002-12-13 21:15:29 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2018-05-09 06:34:59 +02:00
|
|
|
struct rip_distance *rip_distance_new(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2008-08-18 23:13:29 +02:00
|
|
|
return XCALLOC(MTYPE_RIP_DISTANCE, sizeof(struct rip_distance));
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2018-05-09 06:34:59 +02:00
|
|
|
void rip_distance_free(struct rip_distance *rdistance)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
if (rdistance->access_list)
|
|
|
|
free(rdistance->access_list);
|
2002-12-13 21:15:29 +01:00
|
|
|
XFREE(MTYPE_RIP_DISTANCE, rdistance);
|
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_distance_table_node_cleanup(struct route_table *table,
|
|
|
|
struct route_node *node)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct rip_distance *rdistance;
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
rdistance = node->info;
|
|
|
|
if (rdistance)
|
|
|
|
rip_distance_free(rdistance);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Apply RIP information to distance method. */
|
2019-01-04 22:08:10 +01:00
|
|
|
uint8_t rip_distance_apply(struct rip *rip, struct rip_info *rinfo)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2002-12-13 21:15:29 +01:00
|
|
|
struct route_node *rn;
|
|
|
|
struct prefix_ipv4 p;
|
|
|
|
struct rip_distance *rdistance;
|
|
|
|
struct access_list *alist;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-05-11 12:16:44 +02:00
|
|
|
memset(&p, 0, sizeof(p));
|
2002-12-13 21:15:29 +01:00
|
|
|
p.family = AF_INET;
|
|
|
|
p.prefix = rinfo->from;
|
|
|
|
p.prefixlen = IPV4_MAX_BITLEN;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Check source address. */
|
2019-01-04 22:08:10 +01:00
|
|
|
rn = route_node_match(rip->distance_table, (struct prefix *)&p);
|
2017-07-17 14:03:14 +02:00
|
|
|
if (rn) {
|
2002-12-13 21:15:29 +01:00
|
|
|
rdistance = rn->info;
|
|
|
|
route_unlock_node(rn);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (rdistance->access_list) {
|
|
|
|
alist = access_list_lookup(AFI_IP,
|
|
|
|
rdistance->access_list);
|
|
|
|
if (alist == NULL)
|
|
|
|
return 0;
|
|
|
|
if (access_list_apply(alist, &rinfo->rp->p)
|
|
|
|
== FILTER_DENY)
|
|
|
|
return 0;
|
2023-04-10 09:20:43 +02:00
|
|
|
}
|
|
|
|
return rdistance->distance;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2023-04-10 09:20:43 +02:00
|
|
|
return rip->distance;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_distance_show(struct vty *vty, struct rip *rip)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
struct route_node *rn;
|
|
|
|
struct rip_distance *rdistance;
|
|
|
|
int header = 1;
|
|
|
|
char buf[BUFSIZ];
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2018-05-09 06:34:59 +02:00
|
|
|
vty_out(vty, " Distance: (default is %u)\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
rip->distance ? rip->distance : ZEBRA_RIP_DISTANCE_DEFAULT);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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;
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
snprintfrr(buf, sizeof(buf), "%pFX", &rn->p);
|
|
|
|
vty_out(vty, " %-20s %4d %s\n", buf, rdistance->distance,
|
|
|
|
rdistance->access_list ? rdistance->access_list : "");
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2014-07-18 08:13:19 +02:00
|
|
|
/* Update ECMP routes to zebra when ECMP is disabled. */
|
2019-01-04 22:08:10 +01:00
|
|
|
void rip_ecmp_disable(struct rip *rip)
|
2014-07-18 08:13:19 +02:00
|
|
|
{
|
|
|
|
struct route_node *rp;
|
|
|
|
struct rip_info *rinfo, *tmp_rinfo;
|
|
|
|
struct list *list;
|
|
|
|
struct listnode *node, *nextnode;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
|
|
|
|
list = rp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (!list)
|
|
|
|
continue;
|
|
|
|
if (listcount(list) == 0)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
rinfo = listgetdata(listhead(list));
|
|
|
|
if (!rip_route_rte(rinfo))
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
/* Drop all other entries, except the first one. */
|
|
|
|
for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo)) {
|
|
|
|
if (tmp_rinfo == rinfo)
|
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(tmp_rinfo->t_timeout);
|
|
|
|
EVENT_OFF(tmp_rinfo->t_garbage_collect);
|
2022-02-16 14:05:34 +01:00
|
|
|
list_delete_node(list, node);
|
|
|
|
rip_info_free(tmp_rinfo);
|
2014-07-18 08:13:19 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
2014-07-18 08:13:19 +02:00
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Print out routes update time. */
|
|
|
|
static void rip_vty_out_uptime(struct vty *vty, struct rip_info *rinfo)
|
|
|
|
{
|
|
|
|
time_t clock;
|
2020-03-05 17:42:12 +01:00
|
|
|
struct tm tm;
|
2002-12-13 21:15:29 +01:00
|
|
|
#define TIME_BUF 25
|
|
|
|
char timebuf[TIME_BUF];
|
2022-03-01 22:18:12 +01:00
|
|
|
struct event *thread;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if ((thread = rinfo->t_timeout) != NULL) {
|
2022-12-11 14:19:00 +01:00
|
|
|
clock = event_timer_remain_second(thread);
|
2020-03-05 17:42:12 +01:00
|
|
|
gmtime_r(&clock, &tm);
|
|
|
|
strftime(timebuf, TIME_BUF, "%M:%S", &tm);
|
2002-12-13 21:15:29 +01:00
|
|
|
vty_out(vty, "%5s", timebuf);
|
|
|
|
} else if ((thread = rinfo->t_garbage_collect) != NULL) {
|
2022-12-11 14:19:00 +01:00
|
|
|
clock = event_timer_remain_second(thread);
|
2020-03-05 17:42:12 +01:00
|
|
|
gmtime_r(&clock, &tm);
|
|
|
|
strftime(timebuf, TIME_BUF, "%M:%S", &tm);
|
2002-12-13 21:15:29 +01:00
|
|
|
vty_out(vty, "%5s", timebuf);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
static const char *rip_route_type_print(int sub_type)
|
|
|
|
{
|
|
|
|
switch (sub_type) {
|
|
|
|
case RIP_ROUTE_RTE:
|
|
|
|
return "n";
|
|
|
|
case RIP_ROUTE_STATIC:
|
|
|
|
return "s";
|
|
|
|
case RIP_ROUTE_DEFAULT:
|
|
|
|
return "d";
|
|
|
|
case RIP_ROUTE_REDISTRIBUTE:
|
|
|
|
return "r";
|
|
|
|
case RIP_ROUTE_INTERFACE:
|
|
|
|
return "i";
|
|
|
|
default:
|
|
|
|
return "?";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFUN (show_ip_rip,
|
|
|
|
show_ip_rip_cmd,
|
2019-01-04 22:08:10 +01:00
|
|
|
"show ip rip [vrf NAME]",
|
2002-12-13 21:15:29 +01:00
|
|
|
SHOW_STR
|
|
|
|
IP_STR
|
2019-01-04 22:08:10 +01:00
|
|
|
"Show RIP routes\n"
|
|
|
|
VRF_CMD_HELP_STR)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct route_node *np;
|
2014-07-18 08:13:18 +02:00
|
|
|
struct rip_info *rinfo = NULL;
|
|
|
|
struct list *list = NULL;
|
|
|
|
struct listnode *listnode = NULL;
|
2019-01-04 22:08:10 +01:00
|
|
|
const char *vrf_name;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
if (argv_find(argv, argc, "vrf", &idx))
|
|
|
|
vrf_name = argv[idx + 1]->arg;
|
|
|
|
else
|
|
|
|
vrf_name = VRF_DEFAULT_NAME;
|
|
|
|
|
|
|
|
rip = rip_lookup_by_vrf_name(vrf_name);
|
|
|
|
if (!rip) {
|
|
|
|
vty_out(vty, "%% RIP instance not found\n");
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
if (!rip->enabled) {
|
|
|
|
vty_out(vty, "%% RIP instance is disabled\n");
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
2019-01-04 22:08:10 +01:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-13 20:17:06 +02:00
|
|
|
vty_out(vty,
|
2024-06-25 08:32:44 +02:00
|
|
|
"Codes: K - kernel route, C - connected, L - local, S - static,\n"
|
|
|
|
" R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n"
|
|
|
|
" T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n"
|
|
|
|
" f - OpenFabric, t - Table-Direct\n"
|
2017-07-13 20:17:06 +02:00
|
|
|
"Sub-codes:\n"
|
|
|
|
" (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n"
|
|
|
|
" (i) - interface\n\n"
|
|
|
|
" Network Next Hop Metric From Tag Time\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
for (np = route_top(rip->table); np; np = route_next(np)) {
|
|
|
|
list = np->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
if (!list)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
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, " ");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
|
|
|
|
vty_out(vty, "\n");
|
|
|
|
}
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2003-05-25 16:49:19 +02:00
|
|
|
/* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
|
|
|
|
DEFUN (show_ip_rip_status,
|
|
|
|
show_ip_rip_status_cmd,
|
2019-01-04 22:08:10 +01:00
|
|
|
"show ip rip [vrf NAME] status",
|
2002-12-13 21:15:29 +01:00
|
|
|
SHOW_STR
|
|
|
|
IP_STR
|
2003-05-25 16:49:19 +02:00
|
|
|
"Show RIP routes\n"
|
2019-01-04 22:08:10 +01:00
|
|
|
VRF_CMD_HELP_STR
|
2002-12-13 21:15:29 +01:00
|
|
|
"IP routing protocol process parameters and statistics\n")
|
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct interface *ifp;
|
|
|
|
struct rip_interface *ri;
|
2008-08-14 18:59:25 +02:00
|
|
|
extern const struct message ri_version_msg[];
|
2004-10-08 08:36:38 +02:00
|
|
|
const char *send_version;
|
|
|
|
const char *receive_version;
|
2019-01-04 22:08:10 +01:00
|
|
|
const char *vrf_name;
|
|
|
|
int idx = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
if (argv_find(argv, argc, "vrf", &idx))
|
|
|
|
vrf_name = argv[idx + 1]->arg;
|
|
|
|
else
|
|
|
|
vrf_name = VRF_DEFAULT_NAME;
|
|
|
|
|
|
|
|
rip = rip_lookup_by_vrf_name(vrf_name);
|
|
|
|
if (!rip) {
|
|
|
|
vty_out(vty, "%% RIP instance not found\n");
|
2002-12-13 21:15:29 +01:00
|
|
|
return CMD_SUCCESS;
|
2019-01-04 22:08:10 +01:00
|
|
|
}
|
|
|
|
if (!rip->enabled) {
|
|
|
|
vty_out(vty, "%% RIP instance is disabled\n");
|
|
|
|
return CMD_SUCCESS;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-13 18:50:29 +02:00
|
|
|
vty_out(vty, "Routing Protocol is \"rip\"\n");
|
2018-05-09 06:35:01 +02:00
|
|
|
vty_out(vty, " Sending updates every %u seconds with +/-50%%,",
|
2002-12-13 21:15:29 +01:00
|
|
|
rip->update_time);
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, " next due in %lu seconds\n",
|
2022-12-11 14:19:00 +01:00
|
|
|
event_timer_remain_second(rip->t_update));
|
2018-05-09 06:35:01 +02:00
|
|
|
vty_out(vty, " Timeout after %u seconds,", rip->timeout_time);
|
|
|
|
vty_out(vty, " garbage collect after %u seconds\n", rip->garbage_time);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Filtering status show. */
|
lib, rip, ripng, babel, eigrp: add ctx pointer to distribute api
a distribute_ctx context pointer is returned after initialisation to the
calling daemon. this context pointer will be further used to do
discussion with distribute service. Today, there is no specific problem
with old api, since the pointer is the same in all the memory process.
but the pointer will be different if we have multiple instances. Right
now, this is not the case, but if that happens, that work will be used
for that.
distribute-list initialisation is split in two. the vty initialisation
is done at global level, while the context initialisation is done for
each routing daemon instance.
babel daemon is being equipped with a routing returning the main babel
instance.
also, a delete routine is available when the daemon routing instance is
suppressed.
a list of contexts is used inside distribute_list. This will permit
distribute_list utility to handle in the same daemon to handle more than
one context. This will be very useful in the vrf context.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2018-12-04 15:45:57 +01:00
|
|
|
config_show_distribute(vty, rip->distribute_ctx);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Default metric information. */
|
2018-05-09 06:34:59 +02:00
|
|
|
vty_out(vty, " Default redistribution metric is %u\n",
|
2017-06-21 05:10:57 +02:00
|
|
|
rip->default_metric);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Redistribute information. */
|
|
|
|
vty_out(vty, " Redistributing:");
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_show_redistribute_config(vty, rip);
|
2017-07-13 19:04:25 +02:00
|
|
|
vty_out(vty, "\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, " Default version control: send version %s,",
|
2017-06-21 01:56:50 +02:00
|
|
|
lookup_msg(ri_version_msg, rip->version_send, NULL));
|
|
|
|
if (rip->version_recv == RI_RIP_VERSION_1_AND_2)
|
2002-12-13 21:15:29 +01:00
|
|
|
vty_out(vty, " receive any version \n");
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2017-06-21 01:56:50 +02:00
|
|
|
vty_out(vty, " receive version %s \n",
|
|
|
|
lookup_msg(ri_version_msg, rip->version_recv, NULL));
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-21 01:56:50 +02:00
|
|
|
vty_out(vty, " Interface Send Recv Key-chain\n");
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
FOR_ALL_INTERFACES (rip->vrf, ifp) {
|
2002-12-13 21:15:29 +01:00
|
|
|
ri = ifp->info;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2009-04-08 00:00:46 +02:00
|
|
|
if (!ri->running)
|
2017-06-21 01:56:50 +02:00
|
|
|
continue;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-06-21 01:56:50 +02:00
|
|
|
if (ri->enable_network || ri->enable_interface) {
|
|
|
|
if (ri->ri_send == RI_RIP_UNSPEC)
|
|
|
|
send_version =
|
|
|
|
lookup_msg(ri_version_msg,
|
2002-12-13 21:15:29 +01:00
|
|
|
rip->version_send, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2002-12-13 21:15:29 +01:00
|
|
|
send_version = lookup_msg(ri_version_msg,
|
2016-04-08 15:16:14 +02:00
|
|
|
ri->ri_send, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-06-07 03:04:45 +02:00
|
|
|
if (ri->ri_receive == RI_RIP_UNSPEC)
|
|
|
|
receive_version =
|
2017-06-21 01:56:50 +02:00
|
|
|
lookup_msg(ri_version_msg,
|
2003-06-07 03:04:45 +02:00
|
|
|
rip->version_recv, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2003-06-07 03:04:45 +02:00
|
|
|
receive_version = lookup_msg(
|
2017-07-13 17:49:13 +02:00
|
|
|
ri_version_msg, ri->ri_receive, NULL);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty, " %-17s%-3s %-3s %s\n", ifp->name,
|
|
|
|
send_version, receive_version,
|
|
|
|
ri->key_chain ? ri->key_chain : "");
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
vty_out(vty, " Routing for Networks:\n");
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_show_network_config(vty, rip);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2022-02-16 14:05:34 +01:00
|
|
|
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;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2022-02-16 14:05:34 +01:00
|
|
|
vty_out(vty, " %s\n", ifp->name);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
vty_out(vty, " Routing Information Sources:\n");
|
2017-07-13 17:49:13 +02:00
|
|
|
vty_out(vty,
|
2002-12-13 21:15:29 +01:00
|
|
|
" Gateway BadPackets BadRoutes Distance Last Update\n");
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_peer_display(vty, rip);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_distance_show(vty, rip);
|
2002-12-13 21:15:29 +01:00
|
|
|
|
|
|
|
return CMD_SUCCESS;
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2014-07-18 08:13:19 +02:00
|
|
|
/* Distribute-list update functions. */
|
lib, rip, ripng, babel, eigrp: add ctx pointer to distribute api
a distribute_ctx context pointer is returned after initialisation to the
calling daemon. this context pointer will be further used to do
discussion with distribute service. Today, there is no specific problem
with old api, since the pointer is the same in all the memory process.
but the pointer will be different if we have multiple instances. Right
now, this is not the case, but if that happens, that work will be used
for that.
distribute-list initialisation is split in two. the vty initialisation
is done at global level, while the context initialisation is done for
each routing daemon instance.
babel daemon is being equipped with a routing returning the main babel
instance.
also, a delete routine is available when the daemon routing instance is
suppressed.
a list of contexts is used inside distribute_list. This will permit
distribute_list utility to handle in the same daemon to handle more than
one context. This will be very useful in the vrf context.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2018-12-04 15:45:57 +01:00
|
|
|
static void rip_distribute_update(struct distribute_ctx *ctx,
|
|
|
|
struct distribute *dist)
|
2017-07-17 14:03:14 +02:00
|
|
|
{
|
2014-07-18 08:13:19 +02:00
|
|
|
struct interface *ifp;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct rip_interface *ri;
|
2017-07-13 17:49:13 +02:00
|
|
|
struct access_list *alist;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct prefix_list *plist;
|
2014-07-18 08:13:19 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
if (!ctx->vrf || !dist->ifname)
|
2017-06-21 05:10:57 +02:00
|
|
|
return;
|
2002-12-13 21:15:29 +01:00
|
|
|
|
2019-06-24 01:46:39 +02:00
|
|
|
ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
|
2002-12-13 21:15:29 +01:00
|
|
|
if (ifp == NULL)
|
|
|
|
return;
|
|
|
|
|
2008-12-01 20:10:34 +01:00
|
|
|
ri = ifp->info;
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
if (dist->list[DISTRIBUTE_V4_IN]) {
|
|
|
|
alist = access_list_lookup(AFI_IP,
|
|
|
|
dist->list[DISTRIBUTE_V4_IN]);
|
|
|
|
if (alist)
|
|
|
|
ri->list[RIP_FILTER_IN] = alist;
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2002-12-13 21:15:29 +01:00
|
|
|
ri->list[RIP_FILTER_IN] = NULL;
|
2017-03-11 13:27:15 +01:00
|
|
|
} else
|
|
|
|
ri->list[RIP_FILTER_IN] = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-22 23:11:07 +02:00
|
|
|
if (dist->list[DISTRIBUTE_V4_OUT]) {
|
|
|
|
alist = access_list_lookup(AFI_IP,
|
|
|
|
dist->list[DISTRIBUTE_V4_OUT]);
|
2002-12-13 21:15:29 +01:00
|
|
|
if (alist)
|
|
|
|
ri->list[RIP_FILTER_OUT] = alist;
|
|
|
|
else
|
|
|
|
ri->list[RIP_FILTER_OUT] = NULL;
|
|
|
|
} else
|
|
|
|
ri->list[RIP_FILTER_OUT] = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-22 23:11:07 +02:00
|
|
|
if (dist->prefix[DISTRIBUTE_V4_IN]) {
|
|
|
|
plist = prefix_list_lookup(AFI_IP,
|
|
|
|
dist->prefix[DISTRIBUTE_V4_IN]);
|
2002-12-13 21:15:29 +01:00
|
|
|
if (plist)
|
|
|
|
ri->prefix[RIP_FILTER_IN] = plist;
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2002-12-13 21:15:29 +01:00
|
|
|
ri->prefix[RIP_FILTER_IN] = NULL;
|
|
|
|
} else
|
|
|
|
ri->prefix[RIP_FILTER_IN] = NULL;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2016-09-22 23:11:07 +02:00
|
|
|
if (dist->prefix[DISTRIBUTE_V4_OUT]) {
|
|
|
|
plist = prefix_list_lookup(AFI_IP,
|
|
|
|
dist->prefix[DISTRIBUTE_V4_OUT]);
|
2002-12-13 21:15:29 +01:00
|
|
|
if (plist)
|
|
|
|
ri->prefix[RIP_FILTER_OUT] = plist;
|
2017-07-17 14:03:14 +02:00
|
|
|
else
|
2002-12-13 21:15:29 +01:00
|
|
|
ri->prefix[RIP_FILTER_OUT] = NULL;
|
|
|
|
} else
|
|
|
|
ri->prefix[RIP_FILTER_OUT] = NULL;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
void rip_distribute_update_interface(struct interface *ifp)
|
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip_interface *ri = ifp->info;
|
|
|
|
struct rip *rip = ri->rip;
|
2002-12-13 21:15:29 +01:00
|
|
|
struct distribute *dist;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
lib, rip, ripng, babel, eigrp: add ctx pointer to distribute api
a distribute_ctx context pointer is returned after initialisation to the
calling daemon. this context pointer will be further used to do
discussion with distribute service. Today, there is no specific problem
with old api, since the pointer is the same in all the memory process.
but the pointer will be different if we have multiple instances. Right
now, this is not the case, but if that happens, that work will be used
for that.
distribute-list initialisation is split in two. the vty initialisation
is done at global level, while the context initialisation is done for
each routing daemon instance.
babel daemon is being equipped with a routing returning the main babel
instance.
also, a delete routine is available when the daemon routing instance is
suppressed.
a list of contexts is used inside distribute_list. This will permit
distribute_list utility to handle in the same daemon to handle more than
one context. This will be very useful in the vrf context.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2018-12-04 15:45:57 +01:00
|
|
|
if (!rip)
|
|
|
|
return;
|
|
|
|
dist = distribute_lookup(rip->distribute_ctx, ifp->name);
|
2002-12-13 21:15:29 +01:00
|
|
|
if (dist)
|
lib, rip, ripng, babel, eigrp: add ctx pointer to distribute api
a distribute_ctx context pointer is returned after initialisation to the
calling daemon. this context pointer will be further used to do
discussion with distribute service. Today, there is no specific problem
with old api, since the pointer is the same in all the memory process.
but the pointer will be different if we have multiple instances. Right
now, this is not the case, but if that happens, that work will be used
for that.
distribute-list initialisation is split in two. the vty initialisation
is done at global level, while the context initialisation is done for
each routing daemon instance.
babel daemon is being equipped with a routing returning the main babel
instance.
also, a delete routine is available when the daemon routing instance is
suppressed.
a list of contexts is used inside distribute_list. This will permit
distribute_list utility to handle in the same daemon to handle more than
one context. This will be very useful in the vrf context.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2018-12-04 15:45:57 +01:00
|
|
|
rip_distribute_update(rip->distribute_ctx, dist);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Update all interface's distribute list. */
|
2004-06-11 13:27:03 +02:00
|
|
|
/* ARGSUSED */
|
|
|
|
static void rip_distribute_update_all(struct prefix_list *notused)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2017-10-03 03:06:01 +02:00
|
|
|
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
2002-12-13 21:15:29 +01:00
|
|
|
struct interface *ifp;
|
|
|
|
|
2017-10-06 20:25:58 +02:00
|
|
|
FOR_ALL_INTERFACES (vrf, ifp)
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
rip_distribute_update_interface(ifp);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
2004-05-31 16:00:00 +02:00
|
|
|
/* ARGSUSED */
|
|
|
|
static void rip_distribute_update_all_wrapper(struct access_list *notused)
|
|
|
|
{
|
2004-06-11 13:27:03 +02:00
|
|
|
rip_distribute_update_all(NULL);
|
2004-05-31 16:00:00 +02:00
|
|
|
}
|
2014-06-04 06:53:35 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Delete all added rip route. */
|
2019-01-04 22:08:10 +01:00
|
|
|
void rip_clean(struct rip *rip)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
2020-10-09 14:14:58 +02:00
|
|
|
rip_interfaces_clean(rip);
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
if (rip->enabled)
|
|
|
|
rip_instance_disable(rip);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
stream_free(rip->obuf);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
|
2019-01-04 22:08:10 +01:00
|
|
|
if (rip->redist[i].route_map.name)
|
|
|
|
free(rip->redist[i].route_map.name);
|
2019-01-04 22:08:10 +01:00
|
|
|
|
|
|
|
route_table_finish(rip->table);
|
|
|
|
route_table_finish(rip->neighbor);
|
2019-01-04 22:08:10 +01:00
|
|
|
list_delete(&rip->peer_list);
|
2019-01-04 22:08:10 +01:00
|
|
|
distribute_list_delete(&rip->distribute_ctx);
|
2019-03-02 19:00:46 +01:00
|
|
|
if_rmap_ctx_delete(rip->if_rmap_ctx);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_clean_network(rip);
|
|
|
|
rip_passive_nondefault_clean(rip);
|
2019-01-04 22:08:10 +01:00
|
|
|
vector_free(rip->enable_interface);
|
2019-01-04 22:08:10 +01:00
|
|
|
route_table_finish(rip->enable_network);
|
2019-01-04 22:08:10 +01:00
|
|
|
vector_free(rip->passive_nondefault);
|
2019-01-04 22:08:10 +01:00
|
|
|
list_delete(&rip->offset_list_master);
|
2019-01-04 22:08:10 +01:00
|
|
|
route_table_finish(rip->distance_table);
|
2019-01-04 22:08:10 +01:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
RB_REMOVE(rip_instance_head, &rip_instances, rip);
|
2023-05-08 16:07:54 +02:00
|
|
|
XFREE(MTYPE_RIP_BFD_PROFILE, rip->default_bfd_profile);
|
2019-01-04 22:08:10 +01:00
|
|
|
XFREE(MTYPE_RIP_VRF_NAME, rip->vrf_name);
|
2019-01-04 22:08:10 +01:00
|
|
|
XFREE(MTYPE_RIP, rip);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|
|
|
|
|
2019-01-14 08:58:36 +01:00
|
|
|
static void rip_if_rmap_update(struct if_rmap_ctx *ctx,
|
|
|
|
struct if_rmap *if_rmap)
|
2003-05-25 16:49:19 +02:00
|
|
|
{
|
2019-02-19 21:08:43 +01:00
|
|
|
struct interface *ifp = NULL;
|
2003-05-25 16:49:19 +02:00
|
|
|
struct rip_interface *ri;
|
|
|
|
struct route_map *rmap;
|
2019-02-19 21:08:43 +01:00
|
|
|
struct vrf *vrf = NULL;
|
2003-05-25 16:49:19 +02:00
|
|
|
|
2019-02-19 21:08:43 +01:00
|
|
|
if (ctx->name)
|
|
|
|
vrf = vrf_lookup_by_name(ctx->name);
|
|
|
|
if (vrf)
|
2019-06-24 01:46:39 +02:00
|
|
|
ifp = if_lookup_by_name(if_rmap->ifname, vrf->vrf_id);
|
2003-05-25 16:49:19 +02:00
|
|
|
if (ifp == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ri = ifp->info;
|
|
|
|
if (if_rmap->routemap[IF_RMAP_IN]) {
|
|
|
|
rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_IN]);
|
|
|
|
if (rmap)
|
|
|
|
ri->routemap[IF_RMAP_IN] = rmap;
|
|
|
|
else
|
|
|
|
ri->routemap[IF_RMAP_IN] = NULL;
|
|
|
|
} else
|
|
|
|
ri->routemap[RIP_FILTER_IN] = NULL;
|
|
|
|
|
|
|
|
if (if_rmap->routemap[IF_RMAP_OUT]) {
|
|
|
|
rmap = route_map_lookup_by_name(if_rmap->routemap[IF_RMAP_OUT]);
|
|
|
|
if (rmap)
|
|
|
|
ri->routemap[IF_RMAP_OUT] = rmap;
|
|
|
|
else
|
|
|
|
ri->routemap[IF_RMAP_OUT] = NULL;
|
|
|
|
} else
|
|
|
|
ri->routemap[RIP_FILTER_OUT] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rip_if_rmap_update_interface(struct interface *ifp)
|
|
|
|
{
|
2019-03-02 19:00:46 +01:00
|
|
|
struct rip_interface *ri = ifp->info;
|
|
|
|
struct rip *rip = ri->rip;
|
2003-05-25 16:49:19 +02:00
|
|
|
struct if_rmap *if_rmap;
|
2019-01-14 08:58:36 +01:00
|
|
|
struct if_rmap_ctx *ctx;
|
2003-05-25 16:49:19 +02:00
|
|
|
|
2019-01-14 08:58:36 +01:00
|
|
|
if (!rip)
|
|
|
|
return;
|
|
|
|
ctx = rip->if_rmap_ctx;
|
|
|
|
if (!ctx)
|
|
|
|
return;
|
|
|
|
if_rmap = if_rmap_lookup(ctx, ifp->name);
|
2003-05-25 16:49:19 +02:00
|
|
|
if (if_rmap)
|
2019-01-14 08:58:36 +01:00
|
|
|
rip_if_rmap_update(ctx, if_rmap);
|
2003-05-25 16:49:19 +02:00
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
static void rip_routemap_update_redistribute(struct rip *rip)
|
2003-05-25 16:49:19 +02:00
|
|
|
{
|
2019-01-04 22:08:10 +01:00
|
|
|
for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
|
2019-03-02 19:00:46 +01:00
|
|
|
if (rip->redist[i].route_map.name) {
|
2019-01-04 22:08:10 +01:00
|
|
|
rip->redist[i].route_map.map = route_map_lookup_by_name(
|
|
|
|
rip->redist[i].route_map.name);
|
2019-03-02 19:00:46 +01:00
|
|
|
route_map_counter_increment(
|
|
|
|
rip->redist[i].route_map.map);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2003-05-25 16:49:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-05-31 16:00:00 +02:00
|
|
|
/* ARGSUSED */
|
2004-10-11 14:57:57 +02:00
|
|
|
static void rip_routemap_update(const char *notused)
|
2003-05-25 16:49:19 +02:00
|
|
|
{
|
2017-10-03 03:06:01 +02:00
|
|
|
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
2019-01-04 22:08:10 +01:00
|
|
|
struct rip *rip;
|
2003-05-25 16:49:19 +02:00
|
|
|
struct interface *ifp;
|
|
|
|
|
2017-10-06 20:25:58 +02:00
|
|
|
FOR_ALL_INTERFACES (vrf, ifp)
|
2005-04-07 Paul Jakma <paul.jakma@sun.com>
* (global): Fix up list loops to match changes in lib/linklist,
and some basic auditing of usage.
* configure.ac: define QUAGGA_NO_DEPRECATED_INTERFACES
* HACKING: Add notes about deprecating interfaces and commands.
* lib/linklist.h: Add usage comments.
Rename getdata macro to listgetdata.
Rename nextnode to listnextnode and fix its odd behaviour to be
less dangerous.
Make listgetdata macro assert node is not null, NULL list entries
should be bug condition.
ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
with for loop, Suggested by Jim Carlson of Sun.
Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
"safety" of previous macro.
LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
distinguish from the similarly named functions, and reflect their
effect better.
Add a QUAGGA_NO_DEPRECATED_INTERFACES define guarded section
with the old defines which were modified above,
for backwards compatibility - guarded to prevent Quagga using it..
* lib/linklist.c: fix up for linklist.h changes.
* ospf6d/ospf6_abr.c: (ospf6_abr_examin_brouter) change to a single
scan of the area list, rather than scanning all areas first for
INTER_ROUTER and then again for INTER_NETWORK. According to
16.2, the scan should be area specific anyway, and further
ospf6d does not seem to implement 16.3 anyway.
2005-04-07 09:30:20 +02:00
|
|
|
rip_if_rmap_update_interface(ifp);
|
2003-05-25 16:49:19 +02:00
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
rip = vrf->info;
|
|
|
|
if (rip)
|
|
|
|
rip_routemap_update_redistribute(rip);
|
2003-05-25 16:49:19 +02:00
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Link RIP instance to VRF. */
|
|
|
|
static void rip_vrf_link(struct rip *rip, struct vrf *vrf)
|
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
|
|
|
|
rip->vrf = vrf;
|
|
|
|
rip->distribute_ctx->vrf = vrf;
|
|
|
|
vrf->info = rip;
|
|
|
|
|
|
|
|
FOR_ALL_INTERFACES (vrf, ifp)
|
|
|
|
rip_interface_sync(ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unlink RIP instance from VRF. */
|
|
|
|
static void rip_vrf_unlink(struct rip *rip, struct vrf *vrf)
|
|
|
|
{
|
|
|
|
struct interface *ifp;
|
|
|
|
|
|
|
|
rip->vrf = NULL;
|
|
|
|
rip->distribute_ctx->vrf = NULL;
|
|
|
|
vrf->info = NULL;
|
|
|
|
|
|
|
|
FOR_ALL_INTERFACES (vrf, ifp)
|
|
|
|
rip_interface_sync(ifp);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rip_instance_enable(struct rip *rip, struct vrf *vrf, int sock)
|
|
|
|
{
|
|
|
|
rip->sock = sock;
|
|
|
|
|
|
|
|
rip_vrf_link(rip, vrf);
|
|
|
|
rip->enabled = true;
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Resend all redistribute requests. */
|
|
|
|
rip_redistribute_enable(rip);
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Create read and timer thread. */
|
|
|
|
rip_event(rip, RIP_READ, rip->sock);
|
|
|
|
rip_event(rip, RIP_UPDATE_EVENT, 1);
|
|
|
|
|
|
|
|
rip_zebra_vrf_register(vrf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rip_instance_disable(struct rip *rip)
|
|
|
|
{
|
|
|
|
struct vrf *vrf = rip->vrf;
|
|
|
|
struct route_node *rp;
|
|
|
|
|
|
|
|
/* Clear RIP routes */
|
|
|
|
for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
|
|
|
|
struct rip_info *rinfo;
|
|
|
|
struct list *list;
|
|
|
|
struct listnode *listnode;
|
|
|
|
|
|
|
|
if ((list = rp->info) == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rinfo = listgetdata(listhead(list));
|
|
|
|
if (rip_route_rte(rinfo))
|
|
|
|
rip_zebra_ipv4_delete(rip, rp);
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rinfo->t_timeout);
|
|
|
|
EVENT_OFF(rinfo->t_garbage_collect);
|
2019-01-04 22:08:10 +01:00
|
|
|
rip_info_free(rinfo);
|
|
|
|
}
|
|
|
|
list_delete(&list);
|
|
|
|
rp->info = NULL;
|
|
|
|
route_unlock_node(rp);
|
|
|
|
}
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Flush all redistribute requests. */
|
|
|
|
rip_redistribute_disable(rip);
|
|
|
|
|
2019-01-04 22:08:10 +01:00
|
|
|
/* Cancel RIP related timers. */
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rip->t_update);
|
|
|
|
EVENT_OFF(rip->t_triggered_update);
|
|
|
|
EVENT_OFF(rip->t_triggered_interval);
|
2019-01-04 22:08:10 +01:00
|
|
|
|
|
|
|
/* Cancel read thread. */
|
2022-12-25 16:26:52 +01:00
|
|
|
EVENT_OFF(rip->t_read);
|
2019-01-04 22:08:10 +01:00
|
|
|
|
|
|
|
/* Close RIP socket. */
|
|
|
|
close(rip->sock);
|
|
|
|
rip->sock = -1;
|
|
|
|
|
|
|
|
/* Clear existing peers. */
|
|
|
|
list_delete_all_node(rip->peer_list);
|
|
|
|
|
|
|
|
rip_zebra_vrf_deregister(vrf);
|
|
|
|
|
|
|
|
rip_vrf_unlink(rip, vrf);
|
|
|
|
rip->enabled = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rip_vrf_new(struct vrf *vrf)
|
|
|
|
{
|
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
|
|
|
zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
|
|
|
|
vrf->vrf_id);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rip_vrf_delete(struct vrf *vrf)
|
|
|
|
{
|
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
|
|
|
zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
|
|
|
|
vrf->vrf_id);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rip_vrf_enable(struct vrf *vrf)
|
|
|
|
{
|
|
|
|
struct rip *rip;
|
|
|
|
int socket;
|
|
|
|
|
|
|
|
rip = rip_lookup_by_vrf_name(vrf->name);
|
|
|
|
if (!rip || rip->enabled)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
|
|
|
zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
|
|
|
|
vrf->vrf_id);
|
|
|
|
|
|
|
|
/* Activate the VRF RIP instance. */
|
|
|
|
if (!rip->enabled) {
|
|
|
|
socket = rip_create_socket(vrf);
|
|
|
|
if (socket < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
rip_instance_enable(rip, vrf, socket);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rip_vrf_disable(struct vrf *vrf)
|
|
|
|
{
|
|
|
|
struct rip *rip;
|
|
|
|
|
|
|
|
rip = rip_lookup_by_vrf_name(vrf->name);
|
|
|
|
if (!rip || !rip->enabled)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (IS_RIP_DEBUG_EVENT)
|
|
|
|
zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
|
|
|
|
vrf->vrf_id);
|
|
|
|
|
|
|
|
/* Deactivate the VRF RIP instance. */
|
|
|
|
if (rip->enabled)
|
|
|
|
rip_instance_disable(rip);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rip_vrf_init(void)
|
|
|
|
{
|
*: rework renaming the default VRF
Currently, it is possible to rename the default VRF either by passing
`-o` option to zebra or by creating a file in `/var/run/netns` and
binding it to `/proc/self/ns/net`.
In both cases, only zebra knows about the rename and other daemons learn
about it only after they connect to zebra. This is a problem, because
daemons may read their config before they connect to zebra. To handle
this rename after the config is read, we have some special code in every
single daemon, which is not very bad but not desirable in my opinion.
But things are getting worse when we need to handle this in northbound
layer as we have to manually rewrite the config nodes. This approach is
already hacky, but still works as every daemon handles its own NB
structures. But it is completely incompatible with the central
management daemon architecture we are aiming for, as mgmtd doesn't even
have a connection with zebra to learn from it. And it shouldn't have it,
because operational state changes should never affect configuration.
To solve the problem and simplify the code, I propose to expand the `-o`
option to all daemons. By using the startup option, we let daemons know
about the rename before they read their configs so we don't need any
special code to deal with it. There's an easy way to pass the option to
all daemons by using `frr_global_options` variable.
Unfortunately, the second way of renaming by creating a file in
`/var/run/netns` is incompatible with the new mgmtd architecture.
Theoretically, we could force daemons to read their configs only after
they connect to zebra, but it means adding even more code to handle a
very specific use-case. And anyway this won't work for mgmtd as it
doesn't have a connection with zebra. So I had to remove this option.
Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
2021-12-03 23:22:55 +01:00
|
|
|
vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete);
|
2019-01-04 22:08:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void rip_vrf_terminate(void)
|
|
|
|
{
|
|
|
|
vrf_terminate();
|
|
|
|
}
|
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Allocate new rip structure and set default value. */
|
2005-10-26 01:31:05 +02:00
|
|
|
void rip_init(void)
|
2002-12-13 21:15:29 +01:00
|
|
|
{
|
|
|
|
/* Install rip commands. */
|
|
|
|
install_element(VIEW_NODE, &show_ip_rip_cmd);
|
2003-05-25 16:49:19 +02:00
|
|
|
install_element(VIEW_NODE, &show_ip_rip_status_cmd);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Debug related init. */
|
|
|
|
rip_debug_init();
|
2024-01-19 17:40:12 +01:00
|
|
|
/* Enable mgmt be debug */
|
|
|
|
mgmt_be_client_lib_vty_init();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Access list install. */
|
2024-01-19 17:40:12 +01:00
|
|
|
access_list_init_new(true);
|
2004-05-31 16:00:00 +02:00
|
|
|
access_list_add_hook(rip_distribute_update_all_wrapper);
|
|
|
|
access_list_delete_hook(rip_distribute_update_all_wrapper);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2002-12-13 21:15:29 +01:00
|
|
|
/* Prefix list initialize.*/
|
|
|
|
prefix_list_init();
|
|
|
|
prefix_list_add_hook(rip_distribute_update_all);
|
|
|
|
prefix_list_delete_hook(rip_distribute_update_all);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-05-25 16:49:19 +02:00
|
|
|
/* Route-map */
|
|
|
|
rip_route_map_init();
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-05-25 16:49:19 +02:00
|
|
|
route_map_add_hook(rip_routemap_update);
|
|
|
|
route_map_delete_hook(rip_routemap_update);
|
2002-12-13 21:15:29 +01:00
|
|
|
}
|