1 #include <linux/errno.h>
3 #include <linux/kernel.h>
4 #include <linux/module.h>
5 #include <linux/skbuff.h>
6 #include <linux/socket.h>
7 #include <linux/types.h>
8 #include <net/checksum.h>
10 #include <net/ip6_fib.h>
11 #include <net/lwtunnel.h>
12 #include <net/protocol.h>
13 #include <uapi/linux/ila.h>
16 static inline struct ila_params
*ila_params_lwtunnel(
17 struct lwtunnel_state
*lwstate
)
19 return (struct ila_params
*)lwstate
->data
;
22 static int ila_output(struct net
*net
, struct sock
*sk
, struct sk_buff
*skb
)
24 struct dst_entry
*dst
= skb_dst(skb
);
26 if (skb
->protocol
!= htons(ETH_P_IPV6
))
29 ila_update_ipv6_locator(skb
, ila_params_lwtunnel(dst
->lwtstate
), true);
31 return dst
->lwtstate
->orig_output(net
, sk
, skb
);
38 static int ila_input(struct sk_buff
*skb
)
40 struct dst_entry
*dst
= skb_dst(skb
);
42 if (skb
->protocol
!= htons(ETH_P_IPV6
))
45 ila_update_ipv6_locator(skb
, ila_params_lwtunnel(dst
->lwtstate
), false);
47 return dst
->lwtstate
->orig_input(skb
);
54 static struct nla_policy ila_nl_policy
[ILA_ATTR_MAX
+ 1] = {
55 [ILA_ATTR_LOCATOR
] = { .type
= NLA_U64
, },
56 [ILA_ATTR_CSUM_MODE
] = { .type
= NLA_U8
, },
59 static int ila_build_state(struct net_device
*dev
, struct nlattr
*nla
,
60 unsigned int family
, const void *cfg
,
61 struct lwtunnel_state
**ts
)
64 struct nlattr
*tb
[ILA_ATTR_MAX
+ 1];
65 size_t encap_len
= sizeof(*p
);
66 struct lwtunnel_state
*newts
;
67 const struct fib6_config
*cfg6
= cfg
;
68 struct ila_addr
*iaddr
;
71 if (family
!= AF_INET6
)
74 if (cfg6
->fc_dst_len
< sizeof(struct ila_locator
) + 1) {
75 /* Need to have full locator and at least type field
76 * included in destination
81 iaddr
= (struct ila_addr
*)&cfg6
->fc_dst
;
83 if (!ila_addr_is_ila(iaddr
) || ila_csum_neutral_set(iaddr
->ident
)) {
84 /* Don't allow translation for a non-ILA address or checksum
85 * neutral flag to be set.
90 ret
= nla_parse_nested(tb
, ILA_ATTR_MAX
, nla
,
95 if (!tb
[ILA_ATTR_LOCATOR
])
98 newts
= lwtunnel_state_alloc(encap_len
);
102 newts
->len
= encap_len
;
103 p
= ila_params_lwtunnel(newts
);
105 p
->locator
.v64
= (__force __be64
)nla_get_u64(tb
[ILA_ATTR_LOCATOR
]);
107 /* Precompute checksum difference for translation since we
108 * know both the old locator and the new one.
110 p
->locator_match
= iaddr
->loc
;
111 p
->csum_diff
= compute_csum_diff8(
112 (__be32
*)&p
->locator_match
, (__be32
*)&p
->locator
);
114 if (tb
[ILA_ATTR_CSUM_MODE
])
115 p
->csum_mode
= nla_get_u8(tb
[ILA_ATTR_CSUM_MODE
]);
117 ila_init_saved_csum(p
);
119 newts
->type
= LWTUNNEL_ENCAP_ILA
;
120 newts
->flags
|= LWTUNNEL_STATE_OUTPUT_REDIRECT
|
121 LWTUNNEL_STATE_INPUT_REDIRECT
;
128 static int ila_fill_encap_info(struct sk_buff
*skb
,
129 struct lwtunnel_state
*lwtstate
)
131 struct ila_params
*p
= ila_params_lwtunnel(lwtstate
);
133 if (nla_put_u64_64bit(skb
, ILA_ATTR_LOCATOR
, (__force u64
)p
->locator
.v64
,
135 goto nla_put_failure
;
136 if (nla_put_u8(skb
, ILA_ATTR_CSUM_MODE
, (__force u8
)p
->csum_mode
))
137 goto nla_put_failure
;
145 static int ila_encap_nlsize(struct lwtunnel_state
*lwtstate
)
147 return nla_total_size_64bit(sizeof(u64
)) + /* ILA_ATTR_LOCATOR */
148 nla_total_size(sizeof(u8
)) + /* ILA_ATTR_CSUM_MODE */
152 static int ila_encap_cmp(struct lwtunnel_state
*a
, struct lwtunnel_state
*b
)
154 struct ila_params
*a_p
= ila_params_lwtunnel(a
);
155 struct ila_params
*b_p
= ila_params_lwtunnel(b
);
157 return (a_p
->locator
.v64
!= b_p
->locator
.v64
);
160 static const struct lwtunnel_encap_ops ila_encap_ops
= {
161 .build_state
= ila_build_state
,
162 .output
= ila_output
,
164 .fill_encap
= ila_fill_encap_info
,
165 .get_encap_size
= ila_encap_nlsize
,
166 .cmp_encap
= ila_encap_cmp
,
169 int ila_lwt_init(void)
171 return lwtunnel_encap_add_ops(&ila_encap_ops
, LWTUNNEL_ENCAP_ILA
);
174 void ila_lwt_fini(void)
176 lwtunnel_encap_del_ops(&ila_encap_ops
, LWTUNNEL_ENCAP_ILA
);