xref: /aosp_15_r20/external/libnl/lib/route/nexthop_encap.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 
3 #include "nl-default.h"
4 
5 #include <linux/lwtunnel.h>
6 
7 #include "nl-route.h"
8 #include "nexthop-encap.h"
9 
10 static struct lwtunnel_encap_type {
11 	const char *name;
12 	struct nh_encap_ops *ops;
13 } lwtunnel_encap_types[__LWTUNNEL_ENCAP_MAX] = {
14 	[LWTUNNEL_ENCAP_NONE] = { .name = "none" },
15 	[LWTUNNEL_ENCAP_MPLS] = { .name = "mpls", .ops = &mpls_encap_ops },
16 	[LWTUNNEL_ENCAP_IP]   = { .name = "ip" },
17 	[LWTUNNEL_ENCAP_IP6]  = { .name = "ip6" },
18 	[LWTUNNEL_ENCAP_ILA]  = { .name = "ila" },
19 	[LWTUNNEL_ENCAP_BPF]  = { .name = "bpf" },
20 };
21 
nh_encap_type2str(unsigned int type)22 static const char *nh_encap_type2str(unsigned int type)
23 {
24 	const char *name;
25 
26 	if (type > LWTUNNEL_ENCAP_MAX)
27 		return "unknown";
28 
29 	name = lwtunnel_encap_types[type].name;
30 
31 	return name ? name : "unknown";
32 }
33 
nh_encap_dump(struct rtnl_nh_encap * rtnh_encap,struct nl_dump_params * dp)34 void nh_encap_dump(struct rtnl_nh_encap *rtnh_encap, struct nl_dump_params *dp)
35 {
36 	if (!rtnh_encap->ops)
37 		return;
38 
39 	nl_dump(dp, " encap %s ",
40 		nh_encap_type2str(rtnh_encap->ops->encap_type));
41 
42 	if (rtnh_encap->ops->dump)
43 		rtnh_encap->ops->dump(rtnh_encap->priv, dp);
44 }
45 
nh_encap_build_msg(struct nl_msg * msg,struct rtnl_nh_encap * rtnh_encap)46 int nh_encap_build_msg(struct nl_msg *msg, struct rtnl_nh_encap *rtnh_encap)
47 {
48 	struct nlattr *encap;
49 	int err;
50 
51 	if (!rtnh_encap->ops || !rtnh_encap->ops->build_msg) {
52 		NL_DBG(2, "Nexthop encap type not implemented\n");
53 		return -NLE_INVAL;
54 	}
55 
56 	NLA_PUT_U16(msg, RTA_ENCAP_TYPE, rtnh_encap->ops->encap_type);
57 
58 	encap = nla_nest_start(msg, RTA_ENCAP);
59 	if (!encap)
60 		goto nla_put_failure;
61 
62 	err = rtnh_encap->ops->build_msg(msg, rtnh_encap->priv);
63 	if (err < 0)
64 		return err;
65 
66 	nla_nest_end(msg, encap);
67 
68 	return 0;
69 
70 nla_put_failure:
71 	return -NLE_MSGSIZE;
72 }
73 
nh_encap_parse_msg(struct nlattr * encap,struct nlattr * encap_type,struct rtnl_nexthop * rtnh)74 int nh_encap_parse_msg(struct nlattr *encap, struct nlattr *encap_type,
75 		       struct rtnl_nexthop *rtnh)
76 {
77 	uint16_t e_type = nla_get_u16(encap_type);
78 
79 	if (e_type == LWTUNNEL_ENCAP_NONE) {
80 		NL_DBG(2, "RTA_ENCAP_TYPE should not be LWTUNNEL_ENCAP_NONE\n");
81 		return -NLE_INVAL;
82 	}
83 	if (e_type > LWTUNNEL_ENCAP_MAX) {
84 		NL_DBG(2, "Unknown RTA_ENCAP_TYPE: %d\n", e_type);
85 		return -NLE_INVAL;
86 	}
87 
88 	if (!lwtunnel_encap_types[e_type].ops) {
89 		NL_DBG(2, "RTA_ENCAP_TYPE %s is not implemented\n",
90 		       lwtunnel_encap_types[e_type].name);
91 		return -NLE_MSGTYPE_NOSUPPORT;
92 	}
93 
94 	return lwtunnel_encap_types[e_type].ops->parse_msg(encap, rtnh);
95 }
96 
nh_encap_compare(struct rtnl_nh_encap * a,struct rtnl_nh_encap * b)97 int nh_encap_compare(struct rtnl_nh_encap *a, struct rtnl_nh_encap *b)
98 {
99 	if (!a && !b)
100 		return 0;
101 
102 	if ((a && !b) || (!a && b) || (a->ops != b->ops))
103 		return 1;
104 
105 	if (!a->ops || !a->ops->compare)
106 		return 0;
107 
108 	return a->ops->compare(a->priv, b->priv);
109 }
110