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