blob: 226b901a66fafdca28b19eca072b5b055c9c84c3 [file] [log] [blame]
/* SPDX-License-Identifier: LGPL-2.1-only */
#include "nl-default.h"
#include <linux/lwtunnel.h>
#include "nl-route.h"
#include "nexthop-encap.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)
{
if (!rtnh_encap->ops)
return;
nl_dump(dp, " encap %s ",
nh_encap_type2str(rtnh_encap->ops->encap_type));
if (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 < 0)
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);
}