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
= (struct 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
);
61 dst
= dst_cache_get(&ilwt
->dst_cache
);
63 struct ipv6hdr
*ip6h
= ipv6_hdr(skb
);
66 /* Lookup a route for the new destination. Take into
67 * account that the base route may already have a gateway.
70 memset(&fl6
, 0, sizeof(fl6
));
71 fl6
.flowi6_oif
= orig_dst
->dev
->ifindex
;
72 fl6
.flowi6_iif
= LOOPBACK_IFINDEX
;
73 fl6
.daddr
= *rt6_nexthop((struct rt6_info
*)orig_dst
,
76 dst
= ip6_route_output(net
, NULL
, &fl6
);
83 dst
= xfrm_lookup(net
, dst
, flowi6_to_flowi(&fl6
), NULL
, 0);
90 dst_cache_set_ip6(&ilwt
->dst_cache
, dst
, &fl6
.saddr
);
93 skb_dst_set(skb
, dst
);
94 return dst_output(net
, sk
, skb
);
101 static int ila_input(struct sk_buff
*skb
)
103 struct dst_entry
*dst
= skb_dst(skb
);
104 struct ila_lwt
*ilwt
= ila_lwt_lwtunnel(dst
->lwtstate
);
106 if (skb
->protocol
!= htons(ETH_P_IPV6
))
109 if (!ilwt
->lwt_output
)
110 ila_update_ipv6_locator(skb
,
111 ila_params_lwtunnel(dst
->lwtstate
),
114 return dst
->lwtstate
->orig_input(skb
);
121 static const struct nla_policy ila_nl_policy
[ILA_ATTR_MAX
+ 1] = {
122 [ILA_ATTR_LOCATOR
] = { .type
= NLA_U64
, },
123 [ILA_ATTR_CSUM_MODE
] = { .type
= NLA_U8
, },
124 [ILA_ATTR_IDENT_TYPE
] = { .type
= NLA_U8
, },
125 [ILA_ATTR_HOOK_TYPE
] = { .type
= NLA_U8
, },
128 static int ila_build_state(struct net
*net
, struct nlattr
*nla
,
129 unsigned int family
, const void *cfg
,
130 struct lwtunnel_state
**ts
,
131 struct netlink_ext_ack
*extack
)
133 struct ila_lwt
*ilwt
;
134 struct ila_params
*p
;
135 struct nlattr
*tb
[ILA_ATTR_MAX
+ 1];
136 struct lwtunnel_state
*newts
;
137 const struct fib6_config
*cfg6
= cfg
;
138 struct ila_addr
*iaddr
;
139 u8 ident_type
= ILA_ATYPE_USE_FORMAT
;
140 u8 hook_type
= ILA_HOOK_ROUTE_OUTPUT
;
141 u8 csum_mode
= ILA_CSUM_NO_ACTION
;
142 bool lwt_output
= true;
146 if (family
!= AF_INET6
)
149 ret
= nla_parse_nested_deprecated(tb
, ILA_ATTR_MAX
, nla
,
150 ila_nl_policy
, extack
);
154 if (!tb
[ILA_ATTR_LOCATOR
])
157 iaddr
= (struct ila_addr
*)&cfg6
->fc_dst
;
159 if (tb
[ILA_ATTR_IDENT_TYPE
])
160 ident_type
= nla_get_u8(tb
[ILA_ATTR_IDENT_TYPE
]);
162 if (ident_type
== ILA_ATYPE_USE_FORMAT
) {
163 /* Infer identifier type from type field in formatted
167 if (cfg6
->fc_dst_len
< 8 * sizeof(struct ila_locator
) + 3) {
168 /* Need to have full locator and at least type field
169 * included in destination
174 eff_ident_type
= iaddr
->ident
.type
;
176 eff_ident_type
= ident_type
;
179 switch (eff_ident_type
) {
181 /* Don't allow ILA for IID type */
185 case ILA_ATYPE_VIRT_V4
:
186 case ILA_ATYPE_VIRT_UNI_V6
:
187 case ILA_ATYPE_VIRT_MULTI_V6
:
188 case ILA_ATYPE_NONLOCAL_ADDR
:
189 /* These ILA formats are not supported yet. */
194 if (tb
[ILA_ATTR_HOOK_TYPE
])
195 hook_type
= nla_get_u8(tb
[ILA_ATTR_HOOK_TYPE
]);
198 case ILA_HOOK_ROUTE_OUTPUT
:
201 case ILA_HOOK_ROUTE_INPUT
:
208 if (tb
[ILA_ATTR_CSUM_MODE
])
209 csum_mode
= nla_get_u8(tb
[ILA_ATTR_CSUM_MODE
]);
211 if (csum_mode
== ILA_CSUM_NEUTRAL_MAP
&&
212 ila_csum_neutral_set(iaddr
->ident
)) {
213 /* Don't allow translation if checksum neutral bit is
214 * configured and it's set in the SIR address.
219 newts
= lwtunnel_state_alloc(sizeof(*ilwt
));
223 ilwt
= ila_lwt_lwtunnel(newts
);
224 ret
= dst_cache_init(&ilwt
->dst_cache
, GFP_ATOMIC
);
230 ilwt
->lwt_output
= !!lwt_output
;
232 p
= ila_params_lwtunnel(newts
);
234 p
->csum_mode
= csum_mode
;
235 p
->ident_type
= ident_type
;
236 p
->locator
.v64
= (__force __be64
)nla_get_u64(tb
[ILA_ATTR_LOCATOR
]);
238 /* Precompute checksum difference for translation since we
239 * know both the old locator and the new one.
241 p
->locator_match
= iaddr
->loc
;
243 ila_init_saved_csum(p
);
245 newts
->type
= LWTUNNEL_ENCAP_ILA
;
246 newts
->flags
|= LWTUNNEL_STATE_OUTPUT_REDIRECT
|
247 LWTUNNEL_STATE_INPUT_REDIRECT
;
249 if (cfg6
->fc_dst_len
== 8 * sizeof(struct in6_addr
))
257 static void ila_destroy_state(struct lwtunnel_state
*lwt
)
259 dst_cache_destroy(&ila_lwt_lwtunnel(lwt
)->dst_cache
);
262 static int ila_fill_encap_info(struct sk_buff
*skb
,
263 struct lwtunnel_state
*lwtstate
)
265 struct ila_params
*p
= ila_params_lwtunnel(lwtstate
);
266 struct ila_lwt
*ilwt
= ila_lwt_lwtunnel(lwtstate
);
268 if (nla_put_u64_64bit(skb
, ILA_ATTR_LOCATOR
, (__force u64
)p
->locator
.v64
,
270 goto nla_put_failure
;
272 if (nla_put_u8(skb
, ILA_ATTR_CSUM_MODE
, (__force u8
)p
->csum_mode
))
273 goto nla_put_failure
;
275 if (nla_put_u8(skb
, ILA_ATTR_IDENT_TYPE
, (__force u8
)p
->ident_type
))
276 goto nla_put_failure
;
278 if (nla_put_u8(skb
, ILA_ATTR_HOOK_TYPE
,
279 ilwt
->lwt_output
? ILA_HOOK_ROUTE_OUTPUT
:
280 ILA_HOOK_ROUTE_INPUT
))
281 goto nla_put_failure
;
289 static int ila_encap_nlsize(struct lwtunnel_state
*lwtstate
)
291 return nla_total_size_64bit(sizeof(u64
)) + /* ILA_ATTR_LOCATOR */
292 nla_total_size(sizeof(u8
)) + /* ILA_ATTR_CSUM_MODE */
293 nla_total_size(sizeof(u8
)) + /* ILA_ATTR_IDENT_TYPE */
294 nla_total_size(sizeof(u8
)) + /* ILA_ATTR_HOOK_TYPE */
298 static int ila_encap_cmp(struct lwtunnel_state
*a
, struct lwtunnel_state
*b
)
300 struct ila_params
*a_p
= ila_params_lwtunnel(a
);
301 struct ila_params
*b_p
= ila_params_lwtunnel(b
);
303 return (a_p
->locator
.v64
!= b_p
->locator
.v64
);
306 static const struct lwtunnel_encap_ops ila_encap_ops
= {
307 .build_state
= ila_build_state
,
308 .destroy_state
= ila_destroy_state
,
309 .output
= ila_output
,
311 .fill_encap
= ila_fill_encap_info
,
312 .get_encap_size
= ila_encap_nlsize
,
313 .cmp_encap
= ila_encap_cmp
,
314 .owner
= THIS_MODULE
,
317 int ila_lwt_init(void)
319 return lwtunnel_encap_add_ops(&ila_encap_ops
, LWTUNNEL_ENCAP_ILA
);
322 void ila_lwt_fini(void)
324 lwtunnel_encap_del_ops(&ila_encap_ops
, LWTUNNEL_ENCAP_ILA
);