xref: /aosp_15_r20/external/libnl/lib/route/nh_encap_mpls.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 
3 #include "nl-default.h"
4 
5 #include <linux/mpls_iptunnel.h>
6 #include <linux/lwtunnel.h>
7 
8 #include <netlink/route/nexthop.h>
9 
10 #include "nl-route.h"
11 #include "nexthop-encap.h"
12 
13 struct mpls_iptunnel_encap {
14 	struct nl_addr *dst;
15 	uint8_t ttl;
16 };
17 
mpls_encap_dump(void * priv,struct nl_dump_params * dp)18 static void mpls_encap_dump(void *priv, struct nl_dump_params *dp)
19 {
20 	struct mpls_iptunnel_encap *encap_info = priv;
21 	char buf[256];
22 
23 	nl_dump(dp, "%s ", nl_addr2str(encap_info->dst, buf, sizeof(buf)));
24 
25 	if (encap_info->ttl)
26 		nl_dump(dp, "ttl %u ", encap_info->ttl);
27 }
28 
mpls_encap_build_msg(struct nl_msg * msg,void * priv)29 static int mpls_encap_build_msg(struct nl_msg *msg, void *priv)
30 {
31 	struct mpls_iptunnel_encap *encap_info = priv;
32 
33 	NLA_PUT_ADDR(msg, MPLS_IPTUNNEL_DST, encap_info->dst);
34 	if (encap_info->ttl)
35 		NLA_PUT_U8(msg, MPLS_IPTUNNEL_TTL, encap_info->ttl);
36 
37 	return 0;
38 
39 nla_put_failure:
40 	return -NLE_MSGSIZE;
41 }
42 
mpls_encap_destructor(void * priv)43 static void mpls_encap_destructor(void *priv)
44 {
45 	struct mpls_iptunnel_encap *encap_info = priv;
46 
47 	nl_addr_put(encap_info->dst);
48 }
49 
50 static struct nla_policy mpls_encap_policy[MPLS_IPTUNNEL_MAX + 1] = {
51 	[MPLS_IPTUNNEL_DST]     = { .type = NLA_U32 },
52 	[MPLS_IPTUNNEL_TTL]     = { .type = NLA_U8 },
53 };
54 
mpls_encap_parse_msg(struct nlattr * nla,struct rtnl_nexthop * nh)55 static int mpls_encap_parse_msg(struct nlattr *nla, struct rtnl_nexthop *nh)
56 {
57 	struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1];
58 	struct nl_addr *labels;
59 	uint8_t ttl = 0;
60 	int err;
61 
62 	err = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla, mpls_encap_policy);
63 	if (err < 0)
64 		return err;
65 
66 	if (!tb[MPLS_IPTUNNEL_DST])
67 		return -NLE_INVAL;
68 
69 	labels = nl_addr_alloc_attr(tb[MPLS_IPTUNNEL_DST], AF_MPLS);
70 	if (!labels)
71 		return -NLE_NOMEM;
72 
73 	if (tb[MPLS_IPTUNNEL_TTL])
74 		ttl = nla_get_u8(tb[MPLS_IPTUNNEL_TTL]);
75 
76 	err = rtnl_route_nh_encap_mpls(nh, labels, ttl);
77 
78 	nl_addr_put(labels);
79 
80 	return err;
81 }
82 
mpls_encap_compare(void * _a,void * _b)83 static int mpls_encap_compare(void *_a, void *_b)
84 {
85 	struct mpls_iptunnel_encap *a = _a;
86 	struct mpls_iptunnel_encap *b = _b;
87 	int diff = 0;
88 
89 	diff |= (a->ttl != b->ttl);
90 	diff |= nl_addr_cmp(a->dst, b->dst);
91 
92 	return diff;
93 }
94 
95 struct nh_encap_ops mpls_encap_ops = {
96 	.encap_type	= LWTUNNEL_ENCAP_MPLS,
97 	.build_msg	= mpls_encap_build_msg,
98 	.parse_msg	= mpls_encap_parse_msg,
99 	.compare	= mpls_encap_compare,
100 	.dump		= mpls_encap_dump,
101 	.destructor	= mpls_encap_destructor,
102 };
103 
rtnl_route_nh_encap_mpls(struct rtnl_nexthop * nh,struct nl_addr * addr,uint8_t ttl)104 int rtnl_route_nh_encap_mpls(struct rtnl_nexthop *nh,
105 			     struct nl_addr *addr,
106 			     uint8_t ttl)
107 {
108 	struct mpls_iptunnel_encap *mpls_encap;
109 	struct rtnl_nh_encap *rtnh_encap;
110 
111 	if (!addr)
112 		return -NLE_INVAL;
113 
114 	rtnh_encap = calloc(1, sizeof(*rtnh_encap));
115 	if (!rtnh_encap)
116 		return -NLE_NOMEM;
117 
118 	mpls_encap = calloc(1, sizeof(*mpls_encap));
119 	if (!mpls_encap) {
120 		free(rtnh_encap);
121 		return -NLE_NOMEM;
122 	}
123 
124 	mpls_encap->dst = nl_addr_get(addr);
125 	mpls_encap->ttl = ttl;
126 
127 	rtnh_encap->priv = mpls_encap;
128 	rtnh_encap->ops = &mpls_encap_ops;
129 
130 	nh_set_encap(nh, rtnh_encap);
131 
132 	return 0;
133 }
134 
rtnl_route_nh_get_encap_mpls_dst(struct rtnl_nexthop * nh)135 struct nl_addr *rtnl_route_nh_get_encap_mpls_dst(struct rtnl_nexthop *nh)
136 {
137 	struct mpls_iptunnel_encap *mpls_encap;
138 
139 	if (!nh->rtnh_encap || nh->rtnh_encap->ops->encap_type != LWTUNNEL_ENCAP_MPLS)
140 		return NULL;
141 
142 	mpls_encap = (struct mpls_iptunnel_encap *)nh->rtnh_encap->priv;
143 	if (!mpls_encap)
144 		return NULL;
145 
146 	return mpls_encap->dst;
147 }
148 
rtnl_route_nh_get_encap_mpls_ttl(struct rtnl_nexthop * nh)149 uint8_t rtnl_route_nh_get_encap_mpls_ttl(struct rtnl_nexthop *nh)
150 {
151 	struct mpls_iptunnel_encap *mpls_encap;
152 
153 	if (!nh->rtnh_encap || nh->rtnh_encap->ops->encap_type != LWTUNNEL_ENCAP_MPLS)
154 		return 0;
155 
156 	mpls_encap = (struct mpls_iptunnel_encap *)nh->rtnh_encap->priv;
157 	if (!mpls_encap)
158 		return 0;
159 
160 	return mpls_encap->ttl;
161 }
162