2007-09-15 01:28:01 +02:00
|
|
|
/*
|
|
|
|
* lib/route/nexthop.c Routing Nexthop
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation version 2.1
|
|
|
|
* of the License.
|
|
|
|
*
|
2008-04-29 23:31:30 +02:00
|
|
|
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ingroup route_obj
|
|
|
|
* @defgroup nexthop Nexthop
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2013-01-24 13:51:24 +01:00
|
|
|
#include <netlink-private/netlink.h>
|
2007-09-15 01:28:01 +02:00
|
|
|
#include <netlink/netlink.h>
|
|
|
|
#include <netlink/utils.h>
|
|
|
|
#include <netlink/route/rtnl.h>
|
|
|
|
#include <netlink/route/route.h>
|
|
|
|
|
2008-04-29 23:31:30 +02:00
|
|
|
/** @cond SKIP */
|
|
|
|
#define NH_ATTR_FLAGS 0x000001
|
|
|
|
#define NH_ATTR_WEIGHT 0x000002
|
|
|
|
#define NH_ATTR_IFINDEX 0x000004
|
|
|
|
#define NH_ATTR_GATEWAY 0x000008
|
|
|
|
#define NH_ATTR_REALMS 0x000010
|
|
|
|
/** @endcond */
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
/**
|
|
|
|
* @name Allocation/Freeing
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct rtnl_nexthop *rtnl_route_nh_alloc(void)
|
|
|
|
{
|
|
|
|
struct rtnl_nexthop *nh;
|
|
|
|
|
|
|
|
nh = calloc(1, sizeof(*nh));
|
2008-05-14 17:49:44 +02:00
|
|
|
if (!nh)
|
2007-09-15 01:28:01 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
nl_init_list_head(&nh->rtnh_list);
|
|
|
|
|
|
|
|
return nh;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
|
|
|
|
{
|
|
|
|
struct rtnl_nexthop *nh;
|
|
|
|
|
|
|
|
nh = rtnl_route_nh_alloc();
|
|
|
|
if (!nh)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
nh->rtnh_flags = src->rtnh_flags;
|
|
|
|
nh->rtnh_flag_mask = src->rtnh_flag_mask;
|
|
|
|
nh->rtnh_weight = src->rtnh_weight;
|
|
|
|
nh->rtnh_ifindex = src->rtnh_ifindex;
|
2008-04-29 23:31:30 +02:00
|
|
|
nh->ce_mask = src->ce_mask;
|
2007-09-15 01:28:01 +02:00
|
|
|
|
|
|
|
if (src->rtnh_gateway) {
|
|
|
|
nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
|
|
|
|
if (!nh->rtnh_gateway) {
|
|
|
|
free(nh);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nh;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtnl_route_nh_free(struct rtnl_nexthop *nh)
|
|
|
|
{
|
|
|
|
nl_addr_put(nh->rtnh_gateway);
|
|
|
|
free(nh);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|
|
|
|
|
2008-04-29 23:31:30 +02:00
|
|
|
int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
|
|
|
|
uint32_t attrs, int loose)
|
|
|
|
{
|
|
|
|
int diff = 0;
|
|
|
|
|
|
|
|
#define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR)
|
|
|
|
|
|
|
|
diff |= NH_DIFF(IFINDEX, a->rtnh_ifindex != b->rtnh_ifindex);
|
|
|
|
diff |= NH_DIFF(WEIGHT, a->rtnh_weight != b->rtnh_weight);
|
|
|
|
diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms);
|
|
|
|
diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway,
|
|
|
|
b->rtnh_gateway));
|
|
|
|
|
|
|
|
if (loose)
|
|
|
|
diff |= NH_DIFF(FLAGS,
|
|
|
|
(a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask);
|
|
|
|
else
|
|
|
|
diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags);
|
|
|
|
|
|
|
|
#undef NH_DIFF
|
|
|
|
|
|
|
|
return diff;
|
|
|
|
}
|
|
|
|
|
2008-05-23 23:45:14 +02:00
|
|
|
static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
|
2008-04-29 23:31:30 +02:00
|
|
|
{
|
|
|
|
struct nl_cache *link_cache;
|
|
|
|
char buf[128];
|
|
|
|
|
2012-11-16 01:11:55 +01:00
|
|
|
link_cache = nl_cache_mngt_require_safe("route/link");
|
2008-04-29 23:31:30 +02:00
|
|
|
|
|
|
|
nl_dump(dp, "via");
|
|
|
|
|
|
|
|
if (nh->ce_mask & NH_ATTR_GATEWAY)
|
|
|
|
nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway,
|
|
|
|
buf, sizeof(buf)));
|
|
|
|
|
|
|
|
if(nh->ce_mask & NH_ATTR_IFINDEX) {
|
|
|
|
if (link_cache) {
|
|
|
|
nl_dump(dp, " dev %s",
|
|
|
|
rtnl_link_i2name(link_cache,
|
|
|
|
nh->rtnh_ifindex,
|
|
|
|
buf, sizeof(buf)));
|
|
|
|
} else
|
|
|
|
nl_dump(dp, " dev %d", nh->rtnh_ifindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
nl_dump(dp, " ");
|
2012-11-16 01:11:55 +01:00
|
|
|
|
|
|
|
if (link_cache)
|
|
|
|
nl_cache_put(link_cache);
|
2008-04-29 23:31:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
|
|
|
|
{
|
|
|
|
struct nl_cache *link_cache;
|
|
|
|
char buf[128];
|
|
|
|
|
2012-11-16 01:11:55 +01:00
|
|
|
link_cache = nl_cache_mngt_require_safe("route/link");
|
2008-04-29 23:31:30 +02:00
|
|
|
|
|
|
|
nl_dump(dp, "nexthop");
|
|
|
|
|
|
|
|
if (nh->ce_mask & NH_ATTR_GATEWAY)
|
|
|
|
nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
|
|
|
|
buf, sizeof(buf)));
|
|
|
|
|
|
|
|
if(nh->ce_mask & NH_ATTR_IFINDEX) {
|
|
|
|
if (link_cache) {
|
|
|
|
nl_dump(dp, " dev %s",
|
|
|
|
rtnl_link_i2name(link_cache,
|
|
|
|
nh->rtnh_ifindex,
|
|
|
|
buf, sizeof(buf)));
|
|
|
|
} else
|
|
|
|
nl_dump(dp, " dev %d", nh->rtnh_ifindex);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nh->ce_mask & NH_ATTR_WEIGHT)
|
|
|
|
nl_dump(dp, " weight %u", nh->rtnh_weight);
|
|
|
|
|
|
|
|
if (nh->ce_mask & NH_ATTR_REALMS)
|
|
|
|
nl_dump(dp, " realm %04x:%04x",
|
|
|
|
RTNL_REALM_FROM(nh->rtnh_realms),
|
|
|
|
RTNL_REALM_TO(nh->rtnh_realms));
|
|
|
|
|
|
|
|
if (nh->ce_mask & NH_ATTR_FLAGS)
|
|
|
|
nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags,
|
|
|
|
buf, sizeof(buf)));
|
2012-11-16 01:11:55 +01:00
|
|
|
|
|
|
|
if (link_cache)
|
|
|
|
nl_cache_put(link_cache);
|
2008-04-29 23:31:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
|
|
|
|
{
|
|
|
|
switch (dp->dp_type) {
|
2008-05-23 23:45:14 +02:00
|
|
|
case NL_DUMP_LINE:
|
|
|
|
nh_dump_line(nh, dp);
|
2008-04-29 23:31:30 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NL_DUMP_DETAILS:
|
|
|
|
case NL_DUMP_STATS:
|
|
|
|
if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
|
|
|
|
nh_dump_details(nh, dp);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
/**
|
|
|
|
* @name Attributes
|
2008-04-29 23:31:30 +02:00
|
|
|
* @{
|
2007-09-15 01:28:01 +02:00
|
|
|
*/
|
|
|
|
|
2008-04-29 23:31:30 +02:00
|
|
|
void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
|
|
|
nh->rtnh_weight = weight;
|
2008-04-29 23:31:30 +02:00
|
|
|
nh->ce_mask |= NH_ATTR_WEIGHT;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2008-04-29 23:31:30 +02:00
|
|
|
uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
|
2007-09-15 01:28:01 +02:00
|
|
|
{
|
2008-04-29 23:31:30 +02:00
|
|
|
return nh->rtnh_weight;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
|
|
|
|
{
|
|
|
|
nh->rtnh_ifindex = ifindex;
|
2008-04-29 23:31:30 +02:00
|
|
|
nh->ce_mask |= NH_ATTR_IFINDEX;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
|
|
|
|
{
|
2008-04-29 23:31:30 +02:00
|
|
|
return nh->rtnh_ifindex;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
2012-05-09 15:03:46 +02:00
|
|
|
/* FIXME: Convert to return an int */
|
2007-09-15 01:28:01 +02:00
|
|
|
void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
|
|
|
|
{
|
|
|
|
struct nl_addr *old = nh->rtnh_gateway;
|
|
|
|
|
2008-04-29 23:31:30 +02:00
|
|
|
if (addr) {
|
|
|
|
nh->rtnh_gateway = nl_addr_get(addr);
|
|
|
|
nh->ce_mask |= NH_ATTR_GATEWAY;
|
|
|
|
} else {
|
|
|
|
nh->ce_mask &= ~NH_ATTR_GATEWAY;
|
|
|
|
nh->rtnh_gateway = NULL;
|
|
|
|
}
|
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
if (old)
|
|
|
|
nl_addr_put(old);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
|
|
|
|
{
|
2008-04-29 23:31:30 +02:00
|
|
|
return nh->rtnh_gateway;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
|
|
|
|
{
|
|
|
|
nh->rtnh_flag_mask |= flags;
|
|
|
|
nh->rtnh_flags |= flags;
|
2008-04-29 23:31:30 +02:00
|
|
|
nh->ce_mask |= NH_ATTR_FLAGS;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
|
|
|
|
{
|
|
|
|
nh->rtnh_flag_mask |= flags;
|
|
|
|
nh->rtnh_flags &= ~flags;
|
2008-04-29 23:31:30 +02:00
|
|
|
nh->ce_mask |= NH_ATTR_FLAGS;
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
|
|
|
|
{
|
2008-04-29 23:31:30 +02:00
|
|
|
return nh->rtnh_flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
|
|
|
|
{
|
|
|
|
nh->rtnh_realms = realms;
|
|
|
|
nh->ce_mask |= NH_ATTR_REALMS;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
|
|
|
|
{
|
|
|
|
return nh->rtnh_realms;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name Nexthop Flags Translations
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2010-11-17 16:09:08 +01:00
|
|
|
static const struct trans_tbl nh_flags[] = {
|
2014-07-26 15:06:59 +02:00
|
|
|
__ADD(RTNH_F_DEAD, dead),
|
|
|
|
__ADD(RTNH_F_PERVASIVE, pervasive),
|
|
|
|
__ADD(RTNH_F_ONLINK, onlink),
|
2008-04-29 23:31:30 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
|
|
|
|
}
|
|
|
|
|
|
|
|
int rtnl_route_nh_str2flags(const char *name)
|
|
|
|
{
|
|
|
|
return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
|
2007-09-15 01:28:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @} */
|
2008-04-29 23:31:30 +02:00
|
|
|
|
2007-09-15 01:28:01 +02:00
|
|
|
/** @} */
|