Blame view
net/sched/act_tunnel_key.c
22 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
d0f6dd8a9 net/sched: Introd... |
2 3 4 |
/* * Copyright (c) 2016, Amir Vadai <amir@vadai.me> * Copyright (c) 2016, Mellanox Technologies. All rights reserved. |
d0f6dd8a9 net/sched: Introd... |
5 6 7 8 9 10 11 |
*/ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/skbuff.h> #include <linux/rtnetlink.h> |
0ed5269f9 net/sched: add tu... |
12 |
#include <net/geneve.h> |
fca3f91cc net: sched: add v... |
13 |
#include <net/vxlan.h> |
e20d4ff2a net: sched: add e... |
14 |
#include <net/erspan.h> |
d0f6dd8a9 net/sched: Introd... |
15 16 17 |
#include <net/netlink.h> #include <net/pkt_sched.h> #include <net/dst.h> |
e5fdabacb net/sched: act_tu... |
18 |
#include <net/pkt_cls.h> |
d0f6dd8a9 net/sched: Introd... |
19 20 21 |
#include <linux/tc_act/tc_tunnel_key.h> #include <net/tc_act/tc_tunnel_key.h> |
c7d03a00b netns: make struc... |
22 |
static unsigned int tunnel_key_net_id; |
d0f6dd8a9 net/sched: Introd... |
23 24 25 26 27 28 29 30 |
static struct tc_action_ops act_tunnel_key_ops; static int tunnel_key_act(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_tunnel_key *t = to_tunnel_key(a); struct tcf_tunnel_key_params *params; int action; |
7fd4b288e tc/act: remove un... |
31 |
params = rcu_dereference_bh(t->params); |
d0f6dd8a9 net/sched: Introd... |
32 33 |
tcf_lastuse_update(&t->tcf_tm); |
5e1ad95b6 net: sched: extra... |
34 |
tcf_action_update_bstats(&t->common, skb); |
38230a3e0 net/sched: act_tu... |
35 |
action = READ_ONCE(t->tcf_action); |
d0f6dd8a9 net/sched: Introd... |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
switch (params->tcft_action) { case TCA_TUNNEL_KEY_ACT_RELEASE: skb_dst_drop(skb); break; case TCA_TUNNEL_KEY_ACT_SET: skb_dst_drop(skb); skb_dst_set(skb, dst_clone(¶ms->tcft_enc_metadata->dst)); break; default: WARN_ONCE(1, "Bad tunnel_key action %d. ", params->tcft_action); break; } |
d0f6dd8a9 net/sched: Introd... |
51 52 |
return action; } |
0ed5269f9 net/sched: add tu... |
53 54 |
static const struct nla_policy enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = { |
fca3f91cc net: sched: add v... |
55 56 |
[TCA_TUNNEL_KEY_ENC_OPTS_UNSPEC] = { .strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN }, |
0ed5269f9 net/sched: add tu... |
57 |
[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED }, |
fca3f91cc net: sched: add v... |
58 |
[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN] = { .type = NLA_NESTED }, |
e20d4ff2a net: sched: add e... |
59 |
[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN] = { .type = NLA_NESTED }, |
0ed5269f9 net/sched: add tu... |
60 61 62 63 64 65 66 67 68 |
}; static const struct nla_policy geneve_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1] = { [TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS] = { .type = NLA_U16 }, [TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE] = { .type = NLA_U8 }, [TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA] = { .type = NLA_BINARY, .len = 128 }, }; |
fca3f91cc net: sched: add v... |
69 70 71 72 |
static const struct nla_policy vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = { [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP] = { .type = NLA_U32 }, }; |
e20d4ff2a net: sched: add e... |
73 74 75 76 77 78 79 |
static const struct nla_policy erspan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1] = { [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER] = { .type = NLA_U8 }, [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX] = { .type = NLA_U32 }, [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR] = { .type = NLA_U8 }, [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID] = { .type = NLA_U8 }, }; |
0ed5269f9 net/sched: add tu... |
80 81 82 83 84 85 86 |
static int tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len, struct netlink_ext_ack *extack) { struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1]; int err, data_len, opt_len; u8 *data; |
8cb081746 netlink: make val... |
87 88 89 |
err = nla_parse_nested_deprecated(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, nla, geneve_opt_policy, extack); |
0ed5269f9 net/sched: add tu... |
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
if (err < 0) return err; if (!tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS] || !tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE] || !tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]) { NL_SET_ERR_MSG(extack, "Missing tunnel key geneve option class, type or data"); return -EINVAL; } data = nla_data(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]); data_len = nla_len(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]); if (data_len < 4) { NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is less than 4 bytes long"); return -ERANGE; } if (data_len % 4) { NL_SET_ERR_MSG(extack, "Tunnel key geneve option data is not a multiple of 4 bytes long"); return -ERANGE; } opt_len = sizeof(struct geneve_opt) + data_len; if (dst) { struct geneve_opt *opt = dst; WARN_ON(dst_len < opt_len); opt->opt_class = nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]); opt->type = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]); opt->length = data_len / 4; /* length is in units of 4 bytes */ opt->r1 = 0; opt->r2 = 0; opt->r3 = 0; memcpy(opt + 1, data, data_len); } return opt_len; } |
fca3f91cc net: sched: add v... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
static int tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len, struct netlink_ext_ack *extack) { struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1]; int err; err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, nla, vxlan_opt_policy, extack); if (err < 0) return err; if (!tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]) { NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option gbp"); return -EINVAL; } if (dst) { struct vxlan_metadata *md = dst; md->gbp = nla_get_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]); |
13e6ce98a net: sched: only ... |
151 |
md->gbp &= VXLAN_GBP_MASK; |
fca3f91cc net: sched: add v... |
152 153 154 155 |
} return sizeof(struct vxlan_metadata); } |
e20d4ff2a net: sched: add e... |
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
static int tunnel_key_copy_erspan_opt(const struct nlattr *nla, void *dst, int dst_len, struct netlink_ext_ack *extack) { struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1]; int err; u8 ver; err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, nla, erspan_opt_policy, extack); if (err < 0) return err; if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]) { NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver"); return -EINVAL; } ver = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]); if (ver == 1) { if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]) { NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option index"); return -EINVAL; } } else if (ver == 2) { if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR] || !tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]) { NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option dir or hwid"); return -EINVAL; } } else { NL_SET_ERR_MSG(extack, "Tunnel key erspan option ver is incorrect"); return -EINVAL; } if (dst) { struct erspan_metadata *md = dst; md->version = ver; if (ver == 1) { nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]; md->u.index = nla_get_be32(nla); } else { nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]; md->u.md2.dir = nla_get_u8(nla); nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]; set_hwid(&md->u.md2, nla_get_u8(nla)); } } return sizeof(struct erspan_metadata); } |
0ed5269f9 net/sched: add tu... |
208 209 210 |
static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst, int dst_len, struct netlink_ext_ack *extack) { |
fca3f91cc net: sched: add v... |
211 |
int err, rem, opt_len, len = nla_len(nla), opts_len = 0, type = 0; |
0ed5269f9 net/sched: add tu... |
212 |
const struct nlattr *attr, *head = nla_data(nla); |
8cb081746 netlink: make val... |
213 214 |
err = nla_validate_deprecated(head, len, TCA_TUNNEL_KEY_ENC_OPTS_MAX, enc_opts_policy, extack); |
0ed5269f9 net/sched: add tu... |
215 216 217 218 219 220 |
if (err) return err; nla_for_each_attr(attr, head, len, rem) { switch (nla_type(attr)) { case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE: |
fca3f91cc net: sched: add v... |
221 222 223 224 |
if (type && type != TUNNEL_GENEVE_OPT) { NL_SET_ERR_MSG(extack, "Duplicate type for geneve options"); return -EINVAL; } |
0ed5269f9 net/sched: add tu... |
225 226 227 228 229 |
opt_len = tunnel_key_copy_geneve_opt(attr, dst, dst_len, extack); if (opt_len < 0) return opt_len; opts_len += opt_len; |
4f0e97d07 net: sched: ensur... |
230 231 232 233 |
if (opts_len > IP_TUNNEL_OPTS_MAX) { NL_SET_ERR_MSG(extack, "Tunnel options exceeds max size"); return -EINVAL; } |
0ed5269f9 net/sched: add tu... |
234 235 236 237 |
if (dst) { dst_len -= opt_len; dst += opt_len; } |
fca3f91cc net: sched: add v... |
238 239 240 241 242 243 244 245 246 247 248 249 250 |
type = TUNNEL_GENEVE_OPT; break; case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN: if (type) { NL_SET_ERR_MSG(extack, "Duplicate type for vxlan options"); return -EINVAL; } opt_len = tunnel_key_copy_vxlan_opt(attr, dst, dst_len, extack); if (opt_len < 0) return opt_len; opts_len += opt_len; type = TUNNEL_VXLAN_OPT; |
0ed5269f9 net/sched: add tu... |
251 |
break; |
e20d4ff2a net: sched: add e... |
252 253 254 255 256 257 258 259 260 261 262 263 |
case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN: if (type) { NL_SET_ERR_MSG(extack, "Duplicate type for erspan options"); return -EINVAL; } opt_len = tunnel_key_copy_erspan_opt(attr, dst, dst_len, extack); if (opt_len < 0) return opt_len; opts_len += opt_len; type = TUNNEL_ERSPAN_OPT; break; |
0ed5269f9 net/sched: add tu... |
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
} } if (!opts_len) { NL_SET_ERR_MSG(extack, "Empty list of tunnel options"); return -EINVAL; } if (rem > 0) { NL_SET_ERR_MSG(extack, "Trailing data after parsing tunnel key options attributes"); return -EINVAL; } return opts_len; } static int tunnel_key_get_opts_len(struct nlattr *nla, struct netlink_ext_ack *extack) { return tunnel_key_copy_opts(nla, NULL, 0, extack); } static int tunnel_key_opts_set(struct nlattr *nla, struct ip_tunnel_info *info, int opts_len, struct netlink_ext_ack *extack) { info->options_len = opts_len; switch (nla_type(nla_data(nla))) { case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE: #if IS_ENABLED(CONFIG_INET) info->key.tun_flags |= TUNNEL_GENEVE_OPT; return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info), opts_len, extack); #else return -EAFNOSUPPORT; #endif |
fca3f91cc net: sched: add v... |
299 300 301 302 303 304 305 306 |
case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN: #if IS_ENABLED(CONFIG_INET) info->key.tun_flags |= TUNNEL_VXLAN_OPT; return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info), opts_len, extack); #else return -EAFNOSUPPORT; #endif |
e20d4ff2a net: sched: add e... |
307 308 309 310 311 312 313 314 |
case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN: #if IS_ENABLED(CONFIG_INET) info->key.tun_flags |= TUNNEL_ERSPAN_OPT; return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info), opts_len, extack); #else return -EAFNOSUPPORT; #endif |
0ed5269f9 net/sched: add tu... |
315 316 317 318 319 |
default: NL_SET_ERR_MSG(extack, "Cannot set tunnel options for unknown tunnel type"); return -EINVAL; } } |
d0f6dd8a9 net/sched: Introd... |
320 321 322 323 324 325 326 |
static const struct nla_policy tunnel_key_policy[TCA_TUNNEL_KEY_MAX + 1] = { [TCA_TUNNEL_KEY_PARMS] = { .len = sizeof(struct tc_tunnel_key) }, [TCA_TUNNEL_KEY_ENC_IPV4_SRC] = { .type = NLA_U32 }, [TCA_TUNNEL_KEY_ENC_IPV4_DST] = { .type = NLA_U32 }, [TCA_TUNNEL_KEY_ENC_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, [TCA_TUNNEL_KEY_ENC_IPV6_DST] = { .len = sizeof(struct in6_addr) }, [TCA_TUNNEL_KEY_ENC_KEY_ID] = { .type = NLA_U32 }, |
75bfbca01 net/sched: act_tu... |
327 |
[TCA_TUNNEL_KEY_ENC_DST_PORT] = {.type = NLA_U16}, |
86087e170 net: sched: act_t... |
328 |
[TCA_TUNNEL_KEY_NO_CSUM] = { .type = NLA_U8 }, |
0ed5269f9 net/sched: add tu... |
329 |
[TCA_TUNNEL_KEY_ENC_OPTS] = { .type = NLA_NESTED }, |
07a557f47 net/sched: tunnel... |
330 331 |
[TCA_TUNNEL_KEY_ENC_TOS] = { .type = NLA_U8 }, [TCA_TUNNEL_KEY_ENC_TTL] = { .type = NLA_U8 }, |
d0f6dd8a9 net/sched: Introd... |
332 |
}; |
9174c3df1 net/sched: act_tu... |
333 334 335 336 |
static void tunnel_key_release_params(struct tcf_tunnel_key_params *p) { if (!p) return; |
4177c5d94 net/sched: act_tu... |
337 |
if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET) |
9174c3df1 net/sched: act_tu... |
338 |
dst_release(&p->tcft_enc_metadata->dst); |
4177c5d94 net/sched: act_tu... |
339 |
|
9174c3df1 net/sched: act_tu... |
340 341 |
kfree_rcu(p, rcu); } |
d0f6dd8a9 net/sched: Introd... |
342 343 |
static int tunnel_key_init(struct net *net, struct nlattr *nla, struct nlattr *est, struct tc_action **a, |
789871bb2 net: sched: imple... |
344 |
int ovr, int bind, bool rtnl_held, |
abbb0d336 net: sched: exten... |
345 |
struct tcf_proto *tp, u32 act_flags, |
789871bb2 net: sched: imple... |
346 |
struct netlink_ext_ack *extack) |
d0f6dd8a9 net/sched: Introd... |
347 348 349 |
{ struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1]; |
d0f6dd8a9 net/sched: Introd... |
350 351 |
struct tcf_tunnel_key_params *params_new; struct metadata_dst *metadata = NULL; |
e5fdabacb net/sched: act_tu... |
352 |
struct tcf_chain *goto_ch = NULL; |
d0f6dd8a9 net/sched: Introd... |
353 354 355 |
struct tc_tunnel_key *parm; struct tcf_tunnel_key *t; bool exists = false; |
75bfbca01 net/sched: act_tu... |
356 |
__be16 dst_port = 0; |
80ef0f22c net/sched: act_tu... |
357 |
__be64 key_id = 0; |
0ed5269f9 net/sched: add tu... |
358 |
int opts_len = 0; |
80ef0f22c net/sched: act_tu... |
359 |
__be16 flags = 0; |
07a557f47 net/sched: tunnel... |
360 |
u8 tos, ttl; |
d0f6dd8a9 net/sched: Introd... |
361 |
int ret = 0; |
7be8ef2cd net: sched: use t... |
362 |
u32 index; |
d0f6dd8a9 net/sched: Introd... |
363 |
int err; |
9d7298cd1 net/sched: act_tu... |
364 365 |
if (!nla) { NL_SET_ERR_MSG(extack, "Tunnel requires attributes to be passed"); |
d0f6dd8a9 net/sched: Introd... |
366 |
return -EINVAL; |
9d7298cd1 net/sched: act_tu... |
367 |
} |
d0f6dd8a9 net/sched: Introd... |
368 |
|
8cb081746 netlink: make val... |
369 370 |
err = nla_parse_nested_deprecated(tb, TCA_TUNNEL_KEY_MAX, nla, tunnel_key_policy, extack); |
9d7298cd1 net/sched: act_tu... |
371 372 |
if (err < 0) { NL_SET_ERR_MSG(extack, "Failed to parse nested tunnel key attributes"); |
d0f6dd8a9 net/sched: Introd... |
373 |
return err; |
9d7298cd1 net/sched: act_tu... |
374 |
} |
d0f6dd8a9 net/sched: Introd... |
375 |
|
9d7298cd1 net/sched: act_tu... |
376 377 |
if (!tb[TCA_TUNNEL_KEY_PARMS]) { NL_SET_ERR_MSG(extack, "Missing tunnel key parameters"); |
d0f6dd8a9 net/sched: Introd... |
378 |
return -EINVAL; |
9d7298cd1 net/sched: act_tu... |
379 |
} |
d0f6dd8a9 net/sched: Introd... |
380 381 |
parm = nla_data(tb[TCA_TUNNEL_KEY_PARMS]); |
7be8ef2cd net: sched: use t... |
382 383 |
index = parm->index; err = tcf_idr_check_alloc(tn, &index, a, bind); |
0190c1d45 net: sched: atomi... |
384 385 386 |
if (err < 0) return err; exists = err; |
d0f6dd8a9 net/sched: Introd... |
387 388 389 390 391 392 393 |
if (exists && bind) return 0; switch (parm->t_action) { case TCA_TUNNEL_KEY_ACT_RELEASE: break; case TCA_TUNNEL_KEY_ACT_SET: |
80ef0f22c net/sched: act_tu... |
394 395 |
if (tb[TCA_TUNNEL_KEY_ENC_KEY_ID]) { __be32 key32; |
d0f6dd8a9 net/sched: Introd... |
396 |
|
80ef0f22c net/sched: act_tu... |
397 398 399 400 |
key32 = nla_get_be32(tb[TCA_TUNNEL_KEY_ENC_KEY_ID]); key_id = key32_to_tunnel_id(key32); flags = TUNNEL_KEY; } |
d0f6dd8a9 net/sched: Introd... |
401 |
|
80ef0f22c net/sched: act_tu... |
402 |
flags |= TUNNEL_CSUM; |
86087e170 net: sched: act_t... |
403 404 405 |
if (tb[TCA_TUNNEL_KEY_NO_CSUM] && nla_get_u8(tb[TCA_TUNNEL_KEY_NO_CSUM])) flags &= ~TUNNEL_CSUM; |
75bfbca01 net/sched: act_tu... |
406 407 |
if (tb[TCA_TUNNEL_KEY_ENC_DST_PORT]) dst_port = nla_get_be16(tb[TCA_TUNNEL_KEY_ENC_DST_PORT]); |
0ed5269f9 net/sched: add tu... |
408 409 410 411 412 413 414 415 |
if (tb[TCA_TUNNEL_KEY_ENC_OPTS]) { opts_len = tunnel_key_get_opts_len(tb[TCA_TUNNEL_KEY_ENC_OPTS], extack); if (opts_len < 0) { ret = opts_len; goto err_out; } } |
07a557f47 net/sched: tunnel... |
416 417 418 419 420 421 |
tos = 0; if (tb[TCA_TUNNEL_KEY_ENC_TOS]) tos = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TOS]); ttl = 0; if (tb[TCA_TUNNEL_KEY_ENC_TTL]) ttl = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_TTL]); |
d0f6dd8a9 net/sched: Introd... |
422 423 424 425 426 427 428 |
if (tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC] && tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]) { __be32 saddr; __be32 daddr; saddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]); daddr = nla_get_in_addr(tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]); |
07a557f47 net/sched: tunnel... |
429 |
metadata = __ip_tun_set_dst(saddr, daddr, tos, ttl, |
86087e170 net: sched: act_t... |
430 |
dst_port, flags, |
0ed5269f9 net/sched: add tu... |
431 |
key_id, opts_len); |
d0f6dd8a9 net/sched: Introd... |
432 433 434 435 436 437 438 |
} else if (tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC] && tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]) { struct in6_addr saddr; struct in6_addr daddr; saddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]); daddr = nla_get_in6_addr(tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]); |
07a557f47 net/sched: tunnel... |
439 |
metadata = __ipv6_tun_set_dst(&saddr, &daddr, tos, ttl, dst_port, |
86087e170 net: sched: act_t... |
440 |
0, flags, |
a7a12b5a0 net/sched: act_tu... |
441 |
key_id, opts_len); |
a1165b591 net/sched: act_tu... |
442 |
} else { |
9d7298cd1 net/sched: act_tu... |
443 |
NL_SET_ERR_MSG(extack, "Missing either ipv4 or ipv6 src and dst"); |
a1165b591 net/sched: act_tu... |
444 445 |
ret = -EINVAL; goto err_out; |
d0f6dd8a9 net/sched: Introd... |
446 447 448 |
} if (!metadata) { |
9d7298cd1 net/sched: act_tu... |
449 |
NL_SET_ERR_MSG(extack, "Cannot allocate tunnel metadata dst"); |
a1165b591 net/sched: act_tu... |
450 |
ret = -ENOMEM; |
d0f6dd8a9 net/sched: Introd... |
451 452 |
goto err_out; } |
41411e2fd net/sched: act_tu... |
453 454 455 456 457 |
#ifdef CONFIG_DST_CACHE ret = dst_cache_init(&metadata->u.tun_info.dst_cache, GFP_KERNEL); if (ret) goto release_tun_meta; #endif |
0ed5269f9 net/sched: add tu... |
458 459 460 461 462 |
if (opts_len) { ret = tunnel_key_opts_set(tb[TCA_TUNNEL_KEY_ENC_OPTS], &metadata->u.tun_info, opts_len, extack); if (ret < 0) |
4177c5d94 net/sched: act_tu... |
463 |
goto release_tun_meta; |
0ed5269f9 net/sched: add tu... |
464 |
} |
d0f6dd8a9 net/sched: Introd... |
465 466 467 |
metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX; break; default: |
9d7298cd1 net/sched: act_tu... |
468 |
NL_SET_ERR_MSG(extack, "Unknown tunnel key action"); |
51d4740f8 net sched actions... |
469 |
ret = -EINVAL; |
d0f6dd8a9 net/sched: Introd... |
470 471 472 473 |
goto err_out; } if (!exists) { |
e38226786 net: sched: updat... |
474 475 476 |
ret = tcf_idr_create_from_flags(tn, index, est, a, &act_tunnel_key_ops, bind, act_flags); |
9d7298cd1 net/sched: act_tu... |
477 478 |
if (ret) { NL_SET_ERR_MSG(extack, "Cannot create TC IDR"); |
4177c5d94 net/sched: act_tu... |
479 |
goto release_tun_meta; |
9d7298cd1 net/sched: act_tu... |
480 |
} |
d0f6dd8a9 net/sched: Introd... |
481 482 |
ret = ACT_P_CREATED; |
4e8ddd7f1 net: sched: don't... |
483 |
} else if (!ovr) { |
4e8ddd7f1 net: sched: don't... |
484 |
NL_SET_ERR_MSG(extack, "TC IDR already exists"); |
ee28bb56a net/sched: fix me... |
485 |
ret = -EEXIST; |
4177c5d94 net/sched: act_tu... |
486 |
goto release_tun_meta; |
d0f6dd8a9 net/sched: Introd... |
487 |
} |
e5fdabacb net/sched: act_tu... |
488 489 490 491 492 493 |
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); if (err < 0) { ret = err; exists = true; goto release_tun_meta; } |
d0f6dd8a9 net/sched: Introd... |
494 |
t = to_tunnel_key(*a); |
d0f6dd8a9 net/sched: Introd... |
495 496 |
params_new = kzalloc(sizeof(*params_new), GFP_KERNEL); if (unlikely(!params_new)) { |
9d7298cd1 net/sched: act_tu... |
497 |
NL_SET_ERR_MSG(extack, "Cannot allocate tunnel key parameters"); |
ee28bb56a net/sched: fix me... |
498 499 |
ret = -ENOMEM; exists = true; |
e5fdabacb net/sched: act_tu... |
500 |
goto put_chain; |
d0f6dd8a9 net/sched: Introd... |
501 |
} |
d0f6dd8a9 net/sched: Introd... |
502 503 |
params_new->tcft_action = parm->t_action; params_new->tcft_enc_metadata = metadata; |
653cd284a net: sched: alway... |
504 |
spin_lock_bh(&t->tcf_lock); |
e5fdabacb net/sched: act_tu... |
505 |
goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); |
445d37493 net/sched: Replac... |
506 507 |
params_new = rcu_replace_pointer(t->params, params_new, lockdep_is_held(&t->tcf_lock)); |
653cd284a net: sched: alway... |
508 |
spin_unlock_bh(&t->tcf_lock); |
9174c3df1 net/sched: act_tu... |
509 |
tunnel_key_release_params(params_new); |
e5fdabacb net/sched: act_tu... |
510 511 |
if (goto_ch) tcf_chain_put_by_act(goto_ch); |
d0f6dd8a9 net/sched: Introd... |
512 |
|
d0f6dd8a9 net/sched: Introd... |
513 |
return ret; |
e5fdabacb net/sched: act_tu... |
514 515 516 |
put_chain: if (goto_ch) tcf_chain_put_by_act(goto_ch); |
ee28bb56a net/sched: fix me... |
517 |
release_tun_meta: |
a3df633a3 net: sched: act_t... |
518 519 |
if (metadata) dst_release(&metadata->dst); |
ee28bb56a net/sched: fix me... |
520 |
|
d0f6dd8a9 net/sched: Introd... |
521 522 |
err_out: if (exists) |
65a206c01 net/sched: Change... |
523 |
tcf_idr_release(*a, bind); |
0190c1d45 net: sched: atomi... |
524 |
else |
7be8ef2cd net: sched: use t... |
525 |
tcf_idr_cleanup(tn, index); |
d0f6dd8a9 net/sched: Introd... |
526 527 |
return ret; } |
9a63b255d net_sched: remove... |
528 |
static void tunnel_key_release(struct tc_action *a) |
d0f6dd8a9 net/sched: Introd... |
529 530 531 |
{ struct tcf_tunnel_key *t = to_tunnel_key(a); struct tcf_tunnel_key_params *params; |
07c0f09e2 net/sched: act_tu... |
532 |
params = rcu_dereference_protected(t->params, 1); |
9174c3df1 net/sched: act_tu... |
533 |
tunnel_key_release_params(params); |
d0f6dd8a9 net/sched: Introd... |
534 |
} |
0ed5269f9 net/sched: add tu... |
535 536 537 538 539 540 |
static int tunnel_key_geneve_opts_dump(struct sk_buff *skb, const struct ip_tunnel_info *info) { int len = info->options_len; u8 *src = (u8 *)(info + 1); struct nlattr *start; |
ae0be8de9 netlink: make nla... |
541 |
start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE); |
0ed5269f9 net/sched: add tu... |
542 543 544 545 546 547 548 549 550 551 552 |
if (!start) return -EMSGSIZE; while (len > 0) { struct geneve_opt *opt = (struct geneve_opt *)src; if (nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS, opt->opt_class) || nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE, opt->type) || nla_put(skb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA, |
a162c3511 net_sched: proper... |
553 554 |
opt->length * 4, opt + 1)) { nla_nest_cancel(skb, start); |
0ed5269f9 net/sched: add tu... |
555 |
return -EMSGSIZE; |
a162c3511 net_sched: proper... |
556 |
} |
0ed5269f9 net/sched: add tu... |
557 558 559 560 561 562 563 564 |
len -= sizeof(struct geneve_opt) + opt->length * 4; src += sizeof(struct geneve_opt) + opt->length * 4; } nla_nest_end(skb, start); return 0; } |
fca3f91cc net: sched: add v... |
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 |
static int tunnel_key_vxlan_opts_dump(struct sk_buff *skb, const struct ip_tunnel_info *info) { struct vxlan_metadata *md = (struct vxlan_metadata *)(info + 1); struct nlattr *start; start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_VXLAN); if (!start) return -EMSGSIZE; if (nla_put_u32(skb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, md->gbp)) { nla_nest_cancel(skb, start); return -EMSGSIZE; } nla_nest_end(skb, start); return 0; } |
e20d4ff2a net: sched: add e... |
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 |
static int tunnel_key_erspan_opts_dump(struct sk_buff *skb, const struct ip_tunnel_info *info) { struct erspan_metadata *md = (struct erspan_metadata *)(info + 1); struct nlattr *start; start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN); if (!start) return -EMSGSIZE; if (nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER, md->version)) goto err; if (md->version == 1 && nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX, md->u.index)) goto err; if (md->version == 2 && (nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR, md->u.md2.dir) || nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID, get_hwid(&md->u.md2)))) goto err; nla_nest_end(skb, start); return 0; err: nla_nest_cancel(skb, start); return -EMSGSIZE; } |
0ed5269f9 net/sched: add tu... |
613 614 615 616 |
static int tunnel_key_opts_dump(struct sk_buff *skb, const struct ip_tunnel_info *info) { struct nlattr *start; |
a162c3511 net_sched: proper... |
617 |
int err = -EINVAL; |
0ed5269f9 net/sched: add tu... |
618 619 620 |
if (!info->options_len) return 0; |
ae0be8de9 netlink: make nla... |
621 |
start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS); |
0ed5269f9 net/sched: add tu... |
622 623 624 625 626 627 |
if (!start) return -EMSGSIZE; if (info->key.tun_flags & TUNNEL_GENEVE_OPT) { err = tunnel_key_geneve_opts_dump(skb, info); if (err) |
a162c3511 net_sched: proper... |
628 |
goto err_out; |
fca3f91cc net: sched: add v... |
629 630 631 632 |
} else if (info->key.tun_flags & TUNNEL_VXLAN_OPT) { err = tunnel_key_vxlan_opts_dump(skb, info); if (err) goto err_out; |
e20d4ff2a net: sched: add e... |
633 634 635 636 |
} else if (info->key.tun_flags & TUNNEL_ERSPAN_OPT) { err = tunnel_key_erspan_opts_dump(skb, info); if (err) goto err_out; |
0ed5269f9 net/sched: add tu... |
637 |
} else { |
a162c3511 net_sched: proper... |
638 639 640 |
err_out: nla_nest_cancel(skb, start); return err; |
0ed5269f9 net/sched: add tu... |
641 642 643 644 645 |
} nla_nest_end(skb, start); return 0; } |
d0f6dd8a9 net/sched: Introd... |
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 |
static int tunnel_key_dump_addresses(struct sk_buff *skb, const struct ip_tunnel_info *info) { unsigned short family = ip_tunnel_info_af(info); if (family == AF_INET) { __be32 saddr = info->key.u.ipv4.src; __be32 daddr = info->key.u.ipv4.dst; if (!nla_put_in_addr(skb, TCA_TUNNEL_KEY_ENC_IPV4_SRC, saddr) && !nla_put_in_addr(skb, TCA_TUNNEL_KEY_ENC_IPV4_DST, daddr)) return 0; } if (family == AF_INET6) { const struct in6_addr *saddr6 = &info->key.u.ipv6.src; const struct in6_addr *daddr6 = &info->key.u.ipv6.dst; if (!nla_put_in6_addr(skb, TCA_TUNNEL_KEY_ENC_IPV6_SRC, saddr6) && !nla_put_in6_addr(skb, TCA_TUNNEL_KEY_ENC_IPV6_DST, daddr6)) return 0; } return -EINVAL; } static int tunnel_key_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { unsigned char *b = skb_tail_pointer(skb); struct tcf_tunnel_key *t = to_tunnel_key(a); struct tcf_tunnel_key_params *params; struct tc_tunnel_key opt = { .index = t->tcf_index, |
036bb4432 net: sched: chang... |
682 683 |
.refcnt = refcount_read(&t->tcf_refcnt) - ref, .bindcnt = atomic_read(&t->tcf_bindcnt) - bind, |
d0f6dd8a9 net/sched: Introd... |
684 685 |
}; struct tcf_t tm; |
d0f6dd8a9 net/sched: Introd... |
686 |
|
653cd284a net: sched: alway... |
687 |
spin_lock_bh(&t->tcf_lock); |
729e01260 net: sched: act_t... |
688 689 690 |
params = rcu_dereference_protected(t->params, lockdep_is_held(&t->tcf_lock)); opt.action = t->tcf_action; |
d0f6dd8a9 net/sched: Introd... |
691 |
opt.t_action = params->tcft_action; |
d0f6dd8a9 net/sched: Introd... |
692 693 694 695 696 |
if (nla_put(skb, TCA_TUNNEL_KEY_PARMS, sizeof(opt), &opt)) goto nla_put_failure; if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) { |
0ed5269f9 net/sched: add tu... |
697 698 699 |
struct ip_tunnel_info *info = ¶ms->tcft_enc_metadata->u.tun_info; struct ip_tunnel_key *key = &info->key; |
d0f6dd8a9 net/sched: Introd... |
700 |
__be32 key_id = tunnel_id_to_key32(key->tun_id); |
80ef0f22c net/sched: act_tu... |
701 702 |
if (((key->tun_flags & TUNNEL_KEY) && nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_KEY_ID, key_id)) || |
d0f6dd8a9 net/sched: Introd... |
703 |
tunnel_key_dump_addresses(skb, |
75bfbca01 net/sched: act_tu... |
704 |
¶ms->tcft_enc_metadata->u.tun_info) || |
1c25324ca net/sched: act_tu... |
705 706 707 |
(key->tp_dst && nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_DST_PORT, key->tp_dst)) || |
86087e170 net: sched: act_t... |
708 |
nla_put_u8(skb, TCA_TUNNEL_KEY_NO_CSUM, |
0ed5269f9 net/sched: add tu... |
709 710 |
!(key->tun_flags & TUNNEL_CSUM)) || tunnel_key_opts_dump(skb, info)) |
d0f6dd8a9 net/sched: Introd... |
711 |
goto nla_put_failure; |
07a557f47 net/sched: tunnel... |
712 713 714 715 716 717 |
if (key->tos && nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_TOS, key->tos)) goto nla_put_failure; if (key->ttl && nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_TTL, key->ttl)) goto nla_put_failure; |
d0f6dd8a9 net/sched: Introd... |
718 719 720 721 722 723 |
} tcf_tm_dump(&tm, &t->tcf_tm); if (nla_put_64bit(skb, TCA_TUNNEL_KEY_TM, sizeof(tm), &tm, TCA_TUNNEL_KEY_PAD)) goto nla_put_failure; |
653cd284a net: sched: alway... |
724 |
spin_unlock_bh(&t->tcf_lock); |
d0f6dd8a9 net/sched: Introd... |
725 |
|
07c0f09e2 net/sched: act_tu... |
726 |
return skb->len; |
d0f6dd8a9 net/sched: Introd... |
727 728 |
nla_put_failure: |
653cd284a net: sched: alway... |
729 |
spin_unlock_bh(&t->tcf_lock); |
d0f6dd8a9 net/sched: Introd... |
730 |
nlmsg_trim(skb, b); |
07c0f09e2 net/sched: act_tu... |
731 |
return -1; |
d0f6dd8a9 net/sched: Introd... |
732 733 734 735 |
} static int tunnel_key_walker(struct net *net, struct sk_buff *skb, struct netlink_callback *cb, int type, |
417801055 net: sched: act: ... |
736 737 |
const struct tc_action_ops *ops, struct netlink_ext_ack *extack) |
d0f6dd8a9 net/sched: Introd... |
738 739 |
{ struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); |
b36201455 net: sched: act: ... |
740 |
return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
d0f6dd8a9 net/sched: Introd... |
741 |
} |
f061b48c1 Revert "net: sche... |
742 |
static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index) |
d0f6dd8a9 net/sched: Introd... |
743 744 |
{ struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); |
65a206c01 net/sched: Change... |
745 |
return tcf_idr_search(tn, a, index); |
d0f6dd8a9 net/sched: Introd... |
746 747 748 749 |
} static struct tc_action_ops act_tunnel_key_ops = { .kind = "tunnel_key", |
eddd2cf19 net: Change TCA_A... |
750 |
.id = TCA_ID_TUNNEL_KEY, |
d0f6dd8a9 net/sched: Introd... |
751 752 753 754 755 756 757 758 759 760 761 762 763 |
.owner = THIS_MODULE, .act = tunnel_key_act, .dump = tunnel_key_dump, .init = tunnel_key_init, .cleanup = tunnel_key_release, .walk = tunnel_key_walker, .lookup = tunnel_key_search, .size = sizeof(struct tcf_tunnel_key), }; static __net_init int tunnel_key_init_net(struct net *net) { struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); |
981471bd3 net_sched: fix a ... |
764 |
return tc_action_net_init(net, tn, &act_tunnel_key_ops); |
d0f6dd8a9 net/sched: Introd... |
765 |
} |
039af9c66 net_sched: switch... |
766 |
static void __net_exit tunnel_key_exit_net(struct list_head *net_list) |
d0f6dd8a9 net/sched: Introd... |
767 |
{ |
039af9c66 net_sched: switch... |
768 |
tc_action_net_exit(net_list, tunnel_key_net_id); |
d0f6dd8a9 net/sched: Introd... |
769 770 771 772 |
} static struct pernet_operations tunnel_key_net_ops = { .init = tunnel_key_init_net, |
039af9c66 net_sched: switch... |
773 |
.exit_batch = tunnel_key_exit_net, |
d0f6dd8a9 net/sched: Introd... |
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 |
.id = &tunnel_key_net_id, .size = sizeof(struct tc_action_net), }; static int __init tunnel_key_init_module(void) { return tcf_register_action(&act_tunnel_key_ops, &tunnel_key_net_ops); } static void __exit tunnel_key_cleanup_module(void) { tcf_unregister_action(&act_tunnel_key_ops, &tunnel_key_net_ops); } module_init(tunnel_key_init_module); module_exit(tunnel_key_cleanup_module); MODULE_AUTHOR("Amir Vadai <amir@vadai.me>"); MODULE_DESCRIPTION("ip tunnel manipulation actions"); MODULE_LICENSE("GPL v2"); |