mirror of
https://gitee.com/openharmony/third_party_libnl
synced 2024-11-24 02:29:50 +00:00
route: Add support for lwtunnel encapsulations
Add framework to support lwtunnel encapsulations per nexthop. Encapsulations types are expected to fill in the nh_encap_ops for building and parsing messages, compare encapsulations in routes, dumping the encapsulations and freeing memory. Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
parent
000a792c7b
commit
0164d57aee
@ -385,6 +385,7 @@ lib_libnl_route_3_la_SOURCES = \
|
||||
lib/route/neightbl.c \
|
||||
lib/route/netconf.c \
|
||||
lib/route/nexthop.c \
|
||||
lib/route/nexthop_encap.c \
|
||||
lib/route/pktloc.c \
|
||||
lib/route/qdisc/blackhole.c \
|
||||
lib/route/qdisc.c \
|
||||
|
30
include/netlink-private/route/nexthop-encap.h
Normal file
30
include/netlink-private/route/nexthop-encap.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef NETLINK_NEXTHOP_ENCAP_H_
|
||||
#define NETLINK_NEXTHOP_ENCAP_H_
|
||||
|
||||
struct nh_encap_ops {
|
||||
uint16_t encap_type;
|
||||
|
||||
int (*build_msg)(struct nl_msg *msg, void *priv);
|
||||
int (*parse_msg)(struct nlattr *nla, struct rtnl_nexthop *rtnh);
|
||||
|
||||
int (*compare)(void *a, void *b);
|
||||
|
||||
void (*dump)(void *priv, struct nl_dump_params *dp);
|
||||
void (*destructor)(void *priv);
|
||||
};
|
||||
|
||||
struct rtnl_nh_encap;
|
||||
|
||||
/*
|
||||
* generic nexthop encap
|
||||
*/
|
||||
void nh_set_encap(struct rtnl_nexthop *nh, struct rtnl_nh_encap *rtnh_encap);
|
||||
|
||||
int nh_encap_parse_msg(struct nlattr *encap, struct nlattr *encap_type,
|
||||
struct rtnl_nexthop *rtnh);
|
||||
int nh_encap_build_msg(struct nl_msg *msg, struct rtnl_nh_encap *rtnh_encap);
|
||||
|
||||
void nh_encap_dump(struct rtnl_nh_encap *rtnh_encap, struct nl_dump_params *dp);
|
||||
|
||||
int nh_encap_compare(struct rtnl_nh_encap *a, struct rtnl_nh_encap *b);
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#include <netlink-private/object-api.h>
|
||||
#include <netlink-private/route/tc-api.h>
|
||||
#include <netlink-private/route/link/sriov.h>
|
||||
#include <netlink-private/route/nexthop-encap.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/genetlink.h>
|
||||
@ -300,6 +301,12 @@ struct rtnl_addr
|
||||
struct rtnl_link *a_link;
|
||||
};
|
||||
|
||||
struct rtnl_nh_encap
|
||||
{
|
||||
struct nh_encap_ops *ops;
|
||||
void *priv; /* private data for encap type */
|
||||
};
|
||||
|
||||
struct rtnl_nexthop
|
||||
{
|
||||
uint8_t rtnh_flags;
|
||||
@ -313,6 +320,7 @@ struct rtnl_nexthop
|
||||
uint32_t rtnh_realms;
|
||||
struct nl_addr * rtnh_newdst;
|
||||
struct nl_addr * rtnh_via;
|
||||
struct rtnl_nh_encap * rtnh_encap;
|
||||
};
|
||||
|
||||
struct rtnl_route
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include <netlink-private/netlink.h>
|
||||
#include <netlink-private/route/nexthop-encap.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/utils.h>
|
||||
#include <netlink/route/rtnl.h>
|
||||
@ -29,6 +30,7 @@
|
||||
#define NH_ATTR_REALMS 0x000010
|
||||
#define NH_ATTR_NEWDST 0x000020
|
||||
#define NH_ATTR_VIA 0x000040
|
||||
#define NH_ATTR_ENCAP 0x000080
|
||||
/** @endcond */
|
||||
|
||||
/**
|
||||
@ -98,6 +100,12 @@ void rtnl_route_nh_free(struct rtnl_nexthop *nh)
|
||||
nl_addr_put(nh->rtnh_gateway);
|
||||
nl_addr_put(nh->rtnh_newdst);
|
||||
nl_addr_put(nh->rtnh_via);
|
||||
if (nh->rtnh_encap) {
|
||||
if (nh->rtnh_encap->ops && nh->rtnh_encap->ops->destructor)
|
||||
nh->rtnh_encap->ops->destructor(nh->rtnh_encap->priv);
|
||||
free(nh->rtnh_encap->priv);
|
||||
free(nh->rtnh_encap);
|
||||
}
|
||||
free(nh);
|
||||
}
|
||||
|
||||
@ -119,6 +127,8 @@ int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
|
||||
b->rtnh_newdst));
|
||||
diff |= NH_DIFF(VIA, nl_addr_cmp(a->rtnh_via,
|
||||
b->rtnh_via));
|
||||
diff |= NH_DIFF(ENCAP, nh_encap_compare(a->rtnh_encap,
|
||||
b->rtnh_encap));
|
||||
|
||||
if (loose)
|
||||
diff |= NH_DIFF(FLAGS,
|
||||
@ -138,6 +148,9 @@ static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
|
||||
|
||||
link_cache = nl_cache_mngt_require_safe("route/link");
|
||||
|
||||
if (nh->ce_mask & NH_ATTR_ENCAP)
|
||||
nh_encap_dump(nh->rtnh_encap, dp);
|
||||
|
||||
if (nh->ce_mask & NH_ATTR_NEWDST)
|
||||
nl_dump(dp, "as to %s ",
|
||||
nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf)));
|
||||
@ -177,6 +190,9 @@ static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
|
||||
|
||||
nl_dump(dp, "nexthop");
|
||||
|
||||
if (nh->ce_mask & NH_ATTR_ENCAP)
|
||||
nh_encap_dump(nh->rtnh_encap, dp);
|
||||
|
||||
if (nh->ce_mask & NH_ATTR_NEWDST)
|
||||
nl_dump(dp, " as to %s",
|
||||
nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf)));
|
||||
@ -233,6 +249,24 @@ void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
|
||||
}
|
||||
}
|
||||
|
||||
void nh_set_encap(struct rtnl_nexthop *nh, struct rtnl_nh_encap *rtnh_encap)
|
||||
{
|
||||
if (nh->rtnh_encap) {
|
||||
if (nh->rtnh_encap->ops && nh->rtnh_encap->ops->destructor)
|
||||
nh->rtnh_encap->ops->destructor(nh->rtnh_encap->priv);
|
||||
free(nh->rtnh_encap->priv);
|
||||
free(nh->rtnh_encap);
|
||||
}
|
||||
|
||||
if (rtnh_encap) {
|
||||
nh->rtnh_encap = rtnh_encap;
|
||||
nh->ce_mask |= NH_ATTR_ENCAP;
|
||||
} else {
|
||||
nh->rtnh_encap = NULL;
|
||||
nh->ce_mask &= ~NH_ATTR_ENCAP;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Attributes
|
||||
* @{
|
||||
|
99
lib/route/nexthop_encap.c
Normal file
99
lib/route/nexthop_encap.c
Normal file
@ -0,0 +1,99 @@
|
||||
|
||||
#include <netlink-private/netlink.h>
|
||||
#include <netlink-private/types.h>
|
||||
#include <netlink-private/route/nexthop-encap.h>
|
||||
#include <linux/lwtunnel.h>
|
||||
|
||||
static struct lwtunnel_encap_type {
|
||||
const char *name;
|
||||
struct nh_encap_ops *ops;
|
||||
} lwtunnel_encap_types[__LWTUNNEL_ENCAP_MAX] = {
|
||||
[LWTUNNEL_ENCAP_NONE] = { .name = "none" },
|
||||
[LWTUNNEL_ENCAP_MPLS] = { .name = "mpls" },
|
||||
[LWTUNNEL_ENCAP_IP] = { .name = "ip" },
|
||||
[LWTUNNEL_ENCAP_IP6] = { .name = "ip6" },
|
||||
[LWTUNNEL_ENCAP_ILA] = { .name = "ila" },
|
||||
[LWTUNNEL_ENCAP_BPF] = { .name = "bpf" },
|
||||
};
|
||||
|
||||
static const char *nh_encap_type2str(unsigned int type)
|
||||
{
|
||||
if (type > LWTUNNEL_ENCAP_MAX)
|
||||
return "unknown";
|
||||
|
||||
return lwtunnel_encap_types[type].name ? : "unknown";
|
||||
}
|
||||
|
||||
void nh_encap_dump(struct rtnl_nh_encap *rtnh_encap, struct nl_dump_params *dp)
|
||||
{
|
||||
nl_dump(dp, " encap %s ",
|
||||
nh_encap_type2str(rtnh_encap->ops->encap_type));
|
||||
|
||||
if (rtnh_encap->ops && rtnh_encap->ops->dump)
|
||||
rtnh_encap->ops->dump(rtnh_encap->priv, dp);
|
||||
}
|
||||
|
||||
int nh_encap_build_msg(struct nl_msg *msg, struct rtnl_nh_encap *rtnh_encap)
|
||||
{
|
||||
struct nlattr *encap;
|
||||
int err;
|
||||
|
||||
if (!rtnh_encap->ops || !rtnh_encap->ops->build_msg) {
|
||||
NL_DBG(2, "Nexthop encap type not implemented\n");
|
||||
return -NLE_INVAL;
|
||||
}
|
||||
|
||||
NLA_PUT_U16(msg, RTA_ENCAP_TYPE, rtnh_encap->ops->encap_type);
|
||||
|
||||
encap = nla_nest_start(msg, RTA_ENCAP);
|
||||
if (!encap)
|
||||
goto nla_put_failure;
|
||||
|
||||
err = rtnh_encap->ops->build_msg(msg, rtnh_encap->priv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
nla_nest_end(msg, encap);
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -NLE_MSGSIZE;
|
||||
}
|
||||
|
||||
int nh_encap_parse_msg(struct nlattr *encap, struct nlattr *encap_type,
|
||||
struct rtnl_nexthop *rtnh)
|
||||
{
|
||||
uint16_t e_type = nla_get_u16(encap_type);
|
||||
|
||||
if (e_type == LWTUNNEL_ENCAP_NONE) {
|
||||
NL_DBG(2, "RTA_ENCAP_TYPE should not be LWTUNNEL_ENCAP_NONE\n");
|
||||
return -NLE_INVAL;
|
||||
}
|
||||
if (e_type > LWTUNNEL_ENCAP_MAX) {
|
||||
NL_DBG(2, "Unknown RTA_ENCAP_TYPE: %d\n", e_type);
|
||||
return -NLE_INVAL;
|
||||
}
|
||||
|
||||
if (!lwtunnel_encap_types[e_type].ops) {
|
||||
NL_DBG(2, "RTA_ENCAP_TYPE %s is not implemented\n",
|
||||
lwtunnel_encap_types[e_type].name);
|
||||
return -NLE_MSGTYPE_NOSUPPORT;
|
||||
}
|
||||
|
||||
return lwtunnel_encap_types[e_type].ops->parse_msg(encap, rtnh);
|
||||
}
|
||||
|
||||
int nh_encap_compare(struct rtnl_nh_encap *a, struct rtnl_nh_encap *b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return 0;
|
||||
|
||||
if ((a && !b) || (!a && b) || (a->ops != b->ops))
|
||||
return 1;
|
||||
|
||||
if (!a->ops || !a->ops->compare)
|
||||
return 0;
|
||||
|
||||
return a->ops->compare(a->priv, b->priv);
|
||||
}
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include <netlink-private/netlink.h>
|
||||
#include <netlink-private/utils.h>
|
||||
#include <netlink-private/route/nexthop-encap.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/cache.h>
|
||||
#include <netlink/utils.h>
|
||||
@ -1014,6 +1015,8 @@ static struct nla_policy route_policy[RTA_MAX+1] = {
|
||||
[RTA_METRICS] = { .type = NLA_NESTED },
|
||||
[RTA_MULTIPATH] = { .type = NLA_NESTED },
|
||||
[RTA_TTL_PROPAGATE] = { .type = NLA_U8 },
|
||||
[RTA_ENCAP] = { .type = NLA_NESTED },
|
||||
[RTA_ENCAP_TYPE] = { .type = NLA_U16 },
|
||||
};
|
||||
|
||||
static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
|
||||
@ -1089,6 +1092,14 @@ static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
|
||||
if (err)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (ntb[RTA_ENCAP] && ntb[RTA_ENCAP_TYPE]) {
|
||||
err = nh_encap_parse_msg(ntb[RTA_ENCAP],
|
||||
ntb[RTA_ENCAP_TYPE],
|
||||
nh);
|
||||
if (err)
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
rtnl_route_add_nexthop(route, nh);
|
||||
@ -1275,6 +1286,13 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
|
||||
nla_get_u8(tb[RTA_TTL_PROPAGATE]));
|
||||
}
|
||||
|
||||
if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]) {
|
||||
err = nh_encap_parse_msg(tb[RTA_ENCAP],
|
||||
tb[RTA_ENCAP_TYPE], old_nh);
|
||||
if (err)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (old_nh) {
|
||||
rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff);
|
||||
if (route->rt_nr_nh == 0) {
|
||||
@ -1402,6 +1420,9 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
|
||||
NLA_PUT_ADDR(msg, RTA_NEWDST, nh->rtnh_newdst);
|
||||
if (nh->rtnh_via && rtnl_route_put_via(msg, nh->rtnh_via) < 0)
|
||||
goto nla_put_failure;
|
||||
if (nh->rtnh_encap &&
|
||||
nh_encap_build_msg(msg, nh->rtnh_encap) < 0)
|
||||
goto nla_put_failure;
|
||||
} else if (rtnl_route_get_nnexthops(route) > 1) {
|
||||
struct nlattr *multipath;
|
||||
struct rtnl_nexthop *nh;
|
||||
@ -1434,6 +1455,10 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
|
||||
if (nh->rtnh_realms)
|
||||
NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
|
||||
|
||||
if (nh->rtnh_encap &&
|
||||
nh_encap_build_msg(msg, nh->rtnh_encap) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) -
|
||||
(void *) rtnh;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user