summaryrefslogtreecommitdiffstats
path: root/lib/route/nexthop_encap.c
blob: 226b901a66fafdca28b19eca072b5b055c9c84c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/* 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);
}