You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
2.5 KiB
105 lines
2.5 KiB
/* SPDX-License-Identifier: LGPL-2.1-only */
|
|
|
|
#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", .ops = &mpls_encap_ops },
|
|
[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)
|
|
{
|
|
const char *name;
|
|
|
|
if (type > LWTUNNEL_ENCAP_MAX)
|
|
return "unknown";
|
|
|
|
name = lwtunnel_encap_types[type].name;
|
|
|
|
return name ? 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);
|
|
}
|