1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/errno.h>
4 #include <linux/kernel.h>
5 #include <linux/module.h>
6 #include <linux/skbuff.h>
7 #include <linux/socket.h>
8 #include <linux/types.h>
9 #include <net/checksum.h>
10 #include <net/dst_cache.h>
12 #include <net/ip6_fib.h>
13 #include <net/ip6_route.h>
14 #include <net/lwtunnel.h>
15 #include <net/protocol.h>
16 #include <uapi/linux/ila.h>
21 struct dst_cache dst_cache
;
26 static inline struct ila_lwt
*ila_lwt_lwtunnel(
27 struct lwtunnel_state
*lwt
)
29 return (struct ila_lwt
*)lwt
->data
;
32 static inline struct ila_params
*ila_params_lwtunnel(
33 struct lwtunnel_state
*lwt
)
35 return &ila_lwt_lwtunnel(lwt
)->p
;
38 static int ila_output(struct net
*net
, struct sock
*sk
, struct sk_buff
*skb
)
40 struct dst_entry
*orig_dst
= skb_dst(skb
);
41 struct rt6_info
*rt
= dst_rt6_info(orig_dst
);
42 struct ila_lwt
*ilwt
= ila_lwt_lwtunnel(orig_dst
->lwtstate
);
43 struct dst_entry
*dst
;
46 if (skb
->protocol
!= htons(ETH_P_IPV6
))
50 ila_update_ipv6_locator(skb
,
51 ila_params_lwtunnel(orig_dst
->lwtstate
),
54 if (rt
->rt6i_flags
& (RTF_GATEWAY
| RTF_CACHE
)) {
55 /* Already have a next hop address in route, no need for
58 return orig_dst
->lwtstate
->orig_output(net
, sk
, skb
);
62 dst
= dst_cache_get(&ilwt
->dst_cache
);
65 struct ipv6hdr
*ip6h
= ipv6_hdr(skb
);
68 /* Lookup a route for the new destination. Take into
69 * account that the base route may already have a gateway.
72 memset(&fl6
, 0, sizeof(fl6
));
73 fl6
.flowi6_oif
= orig_dst
->dev
->ifindex
;
74 fl6
.flowi6_iif
= LOOPBACK_IFINDEX
;
75 fl6
.daddr
= *rt6_nexthop(dst_rt6_info(orig_dst
),
78 dst
= ip6_route_output(net
, NULL
, &fl6
);
85 dst
= xfrm_lookup(net
, dst
, flowi6_to_flowi(&fl6
), NULL
, 0);
91 if (ilwt
->connected
) {
93 dst_cache_set_ip6(&ilwt
->dst_cache
, dst
, &fl6
.saddr
);
98 skb_dst_set(skb
, dst
);
99 return dst_output(net
, sk
, skb
);
106 static int ila_input(struct sk_buff
*skb
)
108 struct dst_entry
*dst
= skb_dst(skb
);
109 struct ila_lwt
*ilwt
= ila_lwt_lwtunnel(dst
->lwtstate
);
111 if (skb
->protocol
!= htons(ETH_P_IPV6
))
114 if (!ilwt
->lwt_output
)
115 ila_update_ipv6_locator(skb
,
116 ila_params_lwtunnel(dst
->lwtstate
),
119 return dst
->lwtstate
->orig_input(skb
);
126 static const struct nla_policy ila_nl_policy
[ILA_ATTR_MAX
+ 1] = {
127 [ILA_ATTR_LOCATOR
] = { .type
= NLA_U64
, },
128 [ILA_ATTR_CSUM_MODE
] = { .type
= NLA_U8
, },
129 [ILA_ATTR_IDENT_TYPE
] = { .type
= NLA_U8
, },
130 [ILA_ATTR_HOOK_TYPE
] = { .type
= NLA_U8
, },
133 static int ila_build_state(struct net
*net
, struct nlattr
*nla
,
134 unsigned int family
, const void *cfg
,
135 struct lwtunnel_state
**ts
,
136 struct netlink_ext_ack
*extack
)
138 struct ila_lwt
*ilwt
;
139 struct ila_params
*p
;
140 struct nlattr
*tb
[ILA_ATTR_MAX
+ 1];
141 struct lwtunnel_state
*newts
;
142 const struct fib6_config
*cfg6
= cfg
;
143 struct ila_addr
*iaddr
;
144 u8 ident_type
= ILA_ATYPE_USE_FORMAT
;
145 u8 hook_type
= ILA_HOOK_ROUTE_OUTPUT
;
146 u8 csum_mode
= ILA_CSUM_NO_ACTION
;
147 bool lwt_output
= true;
151 if (family
!= AF_INET6
)
154 ret
= nla_parse_nested_deprecated(tb
, ILA_ATTR_MAX
, nla
,
155 ila_nl_policy
, extack
);
159 if (!tb
[ILA_ATTR_LOCATOR
])
162 iaddr
= (struct ila_addr
*)&cfg6
->fc_dst
;
164 if (tb
[ILA_ATTR_IDENT_TYPE
])
165 ident_type
= nla_get_u8(tb
[ILA_ATTR_IDENT_TYPE
]);
167 if (ident_type
== ILA_ATYPE_USE_FORMAT
) {
168 /* Infer identifier type from type field in formatted
172 if (cfg6
->fc_dst_len
< 8 * sizeof(struct ila_locator
) + 3) {
173 /* Need to have full locator and at least type field
174 * included in destination
179 eff_ident_type
= iaddr
->ident
.type
;
181 eff_ident_type
= ident_type
;
184 switch (eff_ident_type
) {
186 /* Don't allow ILA for IID type */
190 case ILA_ATYPE_VIRT_V4
:
191 case ILA_ATYPE_VIRT_UNI_V6
:
192 case ILA_ATYPE_VIRT_MULTI_V6
:
193 case ILA_ATYPE_NONLOCAL_ADDR
:
194 /* These ILA formats are not supported yet. */
199 if (tb
[ILA_ATTR_HOOK_TYPE
])
200 hook_type
= nla_get_u8(tb
[ILA_ATTR_HOOK_TYPE
]);
203 case ILA_HOOK_ROUTE_OUTPUT
:
206 case ILA_HOOK_ROUTE_INPUT
:
213 if (tb
[ILA_ATTR_CSUM_MODE
])
214 csum_mode
= nla_get_u8(tb
[ILA_ATTR_CSUM_MODE
]);
216 if (csum_mode
== ILA_CSUM_NEUTRAL_MAP
&&
217 ila_csum_neutral_set(iaddr
->ident
)) {
218 /* Don't allow translation if checksum neutral bit is
219 * configured and it's set in the SIR address.
224 newts
= lwtunnel_state_alloc(sizeof(*ilwt
));
228 ilwt
= ila_lwt_lwtunnel(newts
);
229 ret
= dst_cache_init(&ilwt
->dst_cache
, GFP_ATOMIC
);
235 ilwt
->lwt_output
= !!lwt_output
;
237 p
= ila_params_lwtunnel(newts
);
239 p
->csum_mode
= csum_mode
;
240 p
->ident_type
= ident_type
;
241 p
->locator
.v64
= (__force __be64
)nla_get_u64(tb
[ILA_ATTR_LOCATOR
]);
243 /* Precompute checksum difference for translation since we
244 * know both the old locator and the new one.
246 p
->locator_match
= iaddr
->loc
;
248 ila_init_saved_csum(p
);
250 newts
->type
= LWTUNNEL_ENCAP_ILA
;
251 newts
->flags
|= LWTUNNEL_STATE_OUTPUT_REDIRECT
|
252 LWTUNNEL_STATE_INPUT_REDIRECT
;
254 if (cfg6
->fc_dst_len
== 8 * sizeof(struct in6_addr
))
262 static void ila_destroy_state(struct lwtunnel_state
*lwt
)
264 dst_cache_destroy(&ila_lwt_lwtunnel(lwt
)->dst_cache
);
267 static int ila_fill_encap_info(struct sk_buff
*skb
,
268 struct lwtunnel_state
*lwtstate
)
270 struct ila_params
*p
= ila_params_lwtunnel(lwtstate
);
271 struct ila_lwt
*ilwt
= ila_lwt_lwtunnel(lwtstate
);
273 if (nla_put_u64_64bit(skb
, ILA_ATTR_LOCATOR
, (__force u64
)p
->locator
.v64
,
275 goto nla_put_failure
;
277 if (nla_put_u8(skb
, ILA_ATTR_CSUM_MODE
, (__force u8
)p
->csum_mode
))
278 goto nla_put_failure
;
280 if (nla_put_u8(skb
, ILA_ATTR_IDENT_TYPE
, (__force u8
)p
->ident_type
))
281 goto nla_put_failure
;
283 if (nla_put_u8(skb
, ILA_ATTR_HOOK_TYPE
,
284 ilwt
->lwt_output
? ILA_HOOK_ROUTE_OUTPUT
:
285 ILA_HOOK_ROUTE_INPUT
))
286 goto nla_put_failure
;
294 static int ila_encap_nlsize(struct lwtunnel_state
*lwtstate
)
296 return nla_total_size_64bit(sizeof(u64
)) + /* ILA_ATTR_LOCATOR */
297 nla_total_size(sizeof(u8
)) + /* ILA_ATTR_CSUM_MODE */
298 nla_total_size(sizeof(u8
)) + /* ILA_ATTR_IDENT_TYPE */
299 nla_total_size(sizeof(u8
)) + /* ILA_ATTR_HOOK_TYPE */
303 static int ila_encap_cmp(struct lwtunnel_state
*a
, struct lwtunnel_state
*b
)
305 struct ila_params
*a_p
= ila_params_lwtunnel(a
);
306 struct ila_params
*b_p
= ila_params_lwtunnel(b
);
308 return (a_p
->locator
.v64
!= b_p
->locator
.v64
);
311 static const struct lwtunnel_encap_ops ila_encap_ops
= {
312 .build_state
= ila_build_state
,
313 .destroy_state
= ila_destroy_state
,
314 .output
= ila_output
,
316 .fill_encap
= ila_fill_encap_info
,
317 .get_encap_size
= ila_encap_nlsize
,
318 .cmp_encap
= ila_encap_cmp
,
319 .owner
= THIS_MODULE
,
322 int ila_lwt_init(void)
324 return lwtunnel_encap_add_ops(&ila_encap_ops
, LWTUNNEL_ENCAP_ILA
);
327 void ila_lwt_fini(void)
329 lwtunnel_encap_del_ops(&ila_encap_ops
, LWTUNNEL_ENCAP_ILA
);