| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2016, Amir Vadai <amir@vadai.me> |
|---|
| 3 | 4 | * Copyright (c) 2016, Mellanox Technologies. All rights reserved. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 6 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 7 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 8 | | - * (at your option) any later version. |
|---|
| 9 | 5 | */ |
|---|
| 10 | 6 | |
|---|
| 11 | 7 | #include <linux/module.h> |
|---|
| .. | .. |
|---|
| 14 | 10 | #include <linux/skbuff.h> |
|---|
| 15 | 11 | #include <linux/rtnetlink.h> |
|---|
| 16 | 12 | #include <net/geneve.h> |
|---|
| 13 | +#include <net/vxlan.h> |
|---|
| 14 | +#include <net/erspan.h> |
|---|
| 17 | 15 | #include <net/netlink.h> |
|---|
| 18 | 16 | #include <net/pkt_sched.h> |
|---|
| 19 | 17 | #include <net/dst.h> |
|---|
| 18 | +#include <net/pkt_cls.h> |
|---|
| 20 | 19 | |
|---|
| 21 | 20 | #include <linux/tc_act/tc_tunnel_key.h> |
|---|
| 22 | 21 | #include <net/tc_act/tc_tunnel_key.h> |
|---|
| .. | .. |
|---|
| 34 | 33 | params = rcu_dereference_bh(t->params); |
|---|
| 35 | 34 | |
|---|
| 36 | 35 | tcf_lastuse_update(&t->tcf_tm); |
|---|
| 37 | | - bstats_cpu_update(this_cpu_ptr(t->common.cpu_bstats), skb); |
|---|
| 36 | + tcf_action_update_bstats(&t->common, skb); |
|---|
| 38 | 37 | action = READ_ONCE(t->tcf_action); |
|---|
| 39 | 38 | |
|---|
| 40 | 39 | switch (params->tcft_action) { |
|---|
| .. | .. |
|---|
| 56 | 55 | |
|---|
| 57 | 56 | static const struct nla_policy |
|---|
| 58 | 57 | enc_opts_policy[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1] = { |
|---|
| 58 | + [TCA_TUNNEL_KEY_ENC_OPTS_UNSPEC] = { |
|---|
| 59 | + .strict_start_type = TCA_TUNNEL_KEY_ENC_OPTS_VXLAN }, |
|---|
| 59 | 60 | [TCA_TUNNEL_KEY_ENC_OPTS_GENEVE] = { .type = NLA_NESTED }, |
|---|
| 61 | + [TCA_TUNNEL_KEY_ENC_OPTS_VXLAN] = { .type = NLA_NESTED }, |
|---|
| 62 | + [TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN] = { .type = NLA_NESTED }, |
|---|
| 60 | 63 | }; |
|---|
| 61 | 64 | |
|---|
| 62 | 65 | static const struct nla_policy |
|---|
| .. | .. |
|---|
| 67 | 70 | .len = 128 }, |
|---|
| 68 | 71 | }; |
|---|
| 69 | 72 | |
|---|
| 73 | +static const struct nla_policy |
|---|
| 74 | +vxlan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1] = { |
|---|
| 75 | + [TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP] = { .type = NLA_U32 }, |
|---|
| 76 | +}; |
|---|
| 77 | + |
|---|
| 78 | +static const struct nla_policy |
|---|
| 79 | +erspan_opt_policy[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1] = { |
|---|
| 80 | + [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER] = { .type = NLA_U8 }, |
|---|
| 81 | + [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX] = { .type = NLA_U32 }, |
|---|
| 82 | + [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR] = { .type = NLA_U8 }, |
|---|
| 83 | + [TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID] = { .type = NLA_U8 }, |
|---|
| 84 | +}; |
|---|
| 85 | + |
|---|
| 70 | 86 | static int |
|---|
| 71 | 87 | tunnel_key_copy_geneve_opt(const struct nlattr *nla, void *dst, int dst_len, |
|---|
| 72 | 88 | struct netlink_ext_ack *extack) |
|---|
| .. | .. |
|---|
| 75 | 91 | int err, data_len, opt_len; |
|---|
| 76 | 92 | u8 *data; |
|---|
| 77 | 93 | |
|---|
| 78 | | - err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, |
|---|
| 79 | | - nla, geneve_opt_policy, extack); |
|---|
| 94 | + err = nla_parse_nested_deprecated(tb, |
|---|
| 95 | + TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, |
|---|
| 96 | + nla, geneve_opt_policy, extack); |
|---|
| 80 | 97 | if (err < 0) |
|---|
| 81 | 98 | return err; |
|---|
| 82 | 99 | |
|---|
| .. | .. |
|---|
| 118 | 135 | return opt_len; |
|---|
| 119 | 136 | } |
|---|
| 120 | 137 | |
|---|
| 138 | +static int |
|---|
| 139 | +tunnel_key_copy_vxlan_opt(const struct nlattr *nla, void *dst, int dst_len, |
|---|
| 140 | + struct netlink_ext_ack *extack) |
|---|
| 141 | +{ |
|---|
| 142 | + struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1]; |
|---|
| 143 | + int err; |
|---|
| 144 | + |
|---|
| 145 | + err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, nla, |
|---|
| 146 | + vxlan_opt_policy, extack); |
|---|
| 147 | + if (err < 0) |
|---|
| 148 | + return err; |
|---|
| 149 | + |
|---|
| 150 | + if (!tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]) { |
|---|
| 151 | + NL_SET_ERR_MSG(extack, "Missing tunnel key vxlan option gbp"); |
|---|
| 152 | + return -EINVAL; |
|---|
| 153 | + } |
|---|
| 154 | + |
|---|
| 155 | + if (dst) { |
|---|
| 156 | + struct vxlan_metadata *md = dst; |
|---|
| 157 | + |
|---|
| 158 | + md->gbp = nla_get_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]); |
|---|
| 159 | + md->gbp &= VXLAN_GBP_MASK; |
|---|
| 160 | + } |
|---|
| 161 | + |
|---|
| 162 | + return sizeof(struct vxlan_metadata); |
|---|
| 163 | +} |
|---|
| 164 | + |
|---|
| 165 | +static int |
|---|
| 166 | +tunnel_key_copy_erspan_opt(const struct nlattr *nla, void *dst, int dst_len, |
|---|
| 167 | + struct netlink_ext_ack *extack) |
|---|
| 168 | +{ |
|---|
| 169 | + struct nlattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1]; |
|---|
| 170 | + int err; |
|---|
| 171 | + u8 ver; |
|---|
| 172 | + |
|---|
| 173 | + err = nla_parse_nested(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, nla, |
|---|
| 174 | + erspan_opt_policy, extack); |
|---|
| 175 | + if (err < 0) |
|---|
| 176 | + return err; |
|---|
| 177 | + |
|---|
| 178 | + if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]) { |
|---|
| 179 | + NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option ver"); |
|---|
| 180 | + return -EINVAL; |
|---|
| 181 | + } |
|---|
| 182 | + |
|---|
| 183 | + ver = nla_get_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]); |
|---|
| 184 | + if (ver == 1) { |
|---|
| 185 | + if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]) { |
|---|
| 186 | + NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option index"); |
|---|
| 187 | + return -EINVAL; |
|---|
| 188 | + } |
|---|
| 189 | + } else if (ver == 2) { |
|---|
| 190 | + if (!tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR] || |
|---|
| 191 | + !tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]) { |
|---|
| 192 | + NL_SET_ERR_MSG(extack, "Missing tunnel key erspan option dir or hwid"); |
|---|
| 193 | + return -EINVAL; |
|---|
| 194 | + } |
|---|
| 195 | + } else { |
|---|
| 196 | + NL_SET_ERR_MSG(extack, "Tunnel key erspan option ver is incorrect"); |
|---|
| 197 | + return -EINVAL; |
|---|
| 198 | + } |
|---|
| 199 | + |
|---|
| 200 | + if (dst) { |
|---|
| 201 | + struct erspan_metadata *md = dst; |
|---|
| 202 | + |
|---|
| 203 | + md->version = ver; |
|---|
| 204 | + if (ver == 1) { |
|---|
| 205 | + nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]; |
|---|
| 206 | + md->u.index = nla_get_be32(nla); |
|---|
| 207 | + } else { |
|---|
| 208 | + nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]; |
|---|
| 209 | + md->u.md2.dir = nla_get_u8(nla); |
|---|
| 210 | + nla = tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]; |
|---|
| 211 | + set_hwid(&md->u.md2, nla_get_u8(nla)); |
|---|
| 212 | + } |
|---|
| 213 | + } |
|---|
| 214 | + |
|---|
| 215 | + return sizeof(struct erspan_metadata); |
|---|
| 216 | +} |
|---|
| 217 | + |
|---|
| 121 | 218 | static int tunnel_key_copy_opts(const struct nlattr *nla, u8 *dst, |
|---|
| 122 | 219 | int dst_len, struct netlink_ext_ack *extack) |
|---|
| 123 | 220 | { |
|---|
| 124 | | - int err, rem, opt_len, len = nla_len(nla), opts_len = 0; |
|---|
| 221 | + int err, rem, opt_len, len = nla_len(nla), opts_len = 0, type = 0; |
|---|
| 125 | 222 | const struct nlattr *attr, *head = nla_data(nla); |
|---|
| 126 | 223 | |
|---|
| 127 | | - err = nla_validate(head, len, TCA_TUNNEL_KEY_ENC_OPTS_MAX, |
|---|
| 128 | | - enc_opts_policy, extack); |
|---|
| 224 | + err = nla_validate_deprecated(head, len, TCA_TUNNEL_KEY_ENC_OPTS_MAX, |
|---|
| 225 | + enc_opts_policy, extack); |
|---|
| 129 | 226 | if (err) |
|---|
| 130 | 227 | return err; |
|---|
| 131 | 228 | |
|---|
| 132 | 229 | nla_for_each_attr(attr, head, len, rem) { |
|---|
| 133 | 230 | switch (nla_type(attr)) { |
|---|
| 134 | 231 | case TCA_TUNNEL_KEY_ENC_OPTS_GENEVE: |
|---|
| 232 | + if (type && type != TUNNEL_GENEVE_OPT) { |
|---|
| 233 | + NL_SET_ERR_MSG(extack, "Duplicate type for geneve options"); |
|---|
| 234 | + return -EINVAL; |
|---|
| 235 | + } |
|---|
| 135 | 236 | opt_len = tunnel_key_copy_geneve_opt(attr, dst, |
|---|
| 136 | 237 | dst_len, extack); |
|---|
| 137 | 238 | if (opt_len < 0) |
|---|
| .. | .. |
|---|
| 145 | 246 | dst_len -= opt_len; |
|---|
| 146 | 247 | dst += opt_len; |
|---|
| 147 | 248 | } |
|---|
| 249 | + type = TUNNEL_GENEVE_OPT; |
|---|
| 250 | + break; |
|---|
| 251 | + case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN: |
|---|
| 252 | + if (type) { |
|---|
| 253 | + NL_SET_ERR_MSG(extack, "Duplicate type for vxlan options"); |
|---|
| 254 | + return -EINVAL; |
|---|
| 255 | + } |
|---|
| 256 | + opt_len = tunnel_key_copy_vxlan_opt(attr, dst, |
|---|
| 257 | + dst_len, extack); |
|---|
| 258 | + if (opt_len < 0) |
|---|
| 259 | + return opt_len; |
|---|
| 260 | + opts_len += opt_len; |
|---|
| 261 | + type = TUNNEL_VXLAN_OPT; |
|---|
| 262 | + break; |
|---|
| 263 | + case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN: |
|---|
| 264 | + if (type) { |
|---|
| 265 | + NL_SET_ERR_MSG(extack, "Duplicate type for erspan options"); |
|---|
| 266 | + return -EINVAL; |
|---|
| 267 | + } |
|---|
| 268 | + opt_len = tunnel_key_copy_erspan_opt(attr, dst, |
|---|
| 269 | + dst_len, extack); |
|---|
| 270 | + if (opt_len < 0) |
|---|
| 271 | + return opt_len; |
|---|
| 272 | + opts_len += opt_len; |
|---|
| 273 | + type = TUNNEL_ERSPAN_OPT; |
|---|
| 148 | 274 | break; |
|---|
| 149 | 275 | } |
|---|
| 150 | 276 | } |
|---|
| .. | .. |
|---|
| 181 | 307 | #else |
|---|
| 182 | 308 | return -EAFNOSUPPORT; |
|---|
| 183 | 309 | #endif |
|---|
| 310 | + case TCA_TUNNEL_KEY_ENC_OPTS_VXLAN: |
|---|
| 311 | +#if IS_ENABLED(CONFIG_INET) |
|---|
| 312 | + info->key.tun_flags |= TUNNEL_VXLAN_OPT; |
|---|
| 313 | + return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info), |
|---|
| 314 | + opts_len, extack); |
|---|
| 315 | +#else |
|---|
| 316 | + return -EAFNOSUPPORT; |
|---|
| 317 | +#endif |
|---|
| 318 | + case TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN: |
|---|
| 319 | +#if IS_ENABLED(CONFIG_INET) |
|---|
| 320 | + info->key.tun_flags |= TUNNEL_ERSPAN_OPT; |
|---|
| 321 | + return tunnel_key_copy_opts(nla, ip_tunnel_info_opts(info), |
|---|
| 322 | + opts_len, extack); |
|---|
| 323 | +#else |
|---|
| 324 | + return -EAFNOSUPPORT; |
|---|
| 325 | +#endif |
|---|
| 184 | 326 | default: |
|---|
| 185 | 327 | NL_SET_ERR_MSG(extack, "Cannot set tunnel options for unknown tunnel type"); |
|---|
| 186 | 328 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 207 | 349 | return; |
|---|
| 208 | 350 | if (p->tcft_action == TCA_TUNNEL_KEY_ACT_SET) |
|---|
| 209 | 351 | dst_release(&p->tcft_enc_metadata->dst); |
|---|
| 352 | + |
|---|
| 210 | 353 | kfree_rcu(p, rcu); |
|---|
| 211 | 354 | } |
|---|
| 212 | 355 | |
|---|
| 213 | 356 | static int tunnel_key_init(struct net *net, struct nlattr *nla, |
|---|
| 214 | 357 | struct nlattr *est, struct tc_action **a, |
|---|
| 215 | 358 | int ovr, int bind, bool rtnl_held, |
|---|
| 359 | + struct tcf_proto *tp, u32 act_flags, |
|---|
| 216 | 360 | struct netlink_ext_ack *extack) |
|---|
| 217 | 361 | { |
|---|
| 218 | 362 | struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); |
|---|
| 219 | 363 | struct nlattr *tb[TCA_TUNNEL_KEY_MAX + 1]; |
|---|
| 220 | 364 | struct tcf_tunnel_key_params *params_new; |
|---|
| 221 | 365 | struct metadata_dst *metadata = NULL; |
|---|
| 366 | + struct tcf_chain *goto_ch = NULL; |
|---|
| 222 | 367 | struct tc_tunnel_key *parm; |
|---|
| 223 | 368 | struct tcf_tunnel_key *t; |
|---|
| 224 | 369 | bool exists = false; |
|---|
| 225 | 370 | __be16 dst_port = 0; |
|---|
| 371 | + __be64 key_id = 0; |
|---|
| 226 | 372 | int opts_len = 0; |
|---|
| 227 | | - __be64 key_id; |
|---|
| 228 | | - __be16 flags; |
|---|
| 373 | + __be16 flags = 0; |
|---|
| 229 | 374 | u8 tos, ttl; |
|---|
| 230 | 375 | int ret = 0; |
|---|
| 231 | 376 | u32 index; |
|---|
| .. | .. |
|---|
| 236 | 381 | return -EINVAL; |
|---|
| 237 | 382 | } |
|---|
| 238 | 383 | |
|---|
| 239 | | - err = nla_parse_nested(tb, TCA_TUNNEL_KEY_MAX, nla, tunnel_key_policy, |
|---|
| 240 | | - extack); |
|---|
| 384 | + err = nla_parse_nested_deprecated(tb, TCA_TUNNEL_KEY_MAX, nla, |
|---|
| 385 | + tunnel_key_policy, extack); |
|---|
| 241 | 386 | if (err < 0) { |
|---|
| 242 | 387 | NL_SET_ERR_MSG(extack, "Failed to parse nested tunnel key attributes"); |
|---|
| 243 | 388 | return err; |
|---|
| .. | .. |
|---|
| 261 | 406 | case TCA_TUNNEL_KEY_ACT_RELEASE: |
|---|
| 262 | 407 | break; |
|---|
| 263 | 408 | case TCA_TUNNEL_KEY_ACT_SET: |
|---|
| 264 | | - if (!tb[TCA_TUNNEL_KEY_ENC_KEY_ID]) { |
|---|
| 265 | | - NL_SET_ERR_MSG(extack, "Missing tunnel key id"); |
|---|
| 266 | | - ret = -EINVAL; |
|---|
| 267 | | - goto err_out; |
|---|
| 409 | + if (tb[TCA_TUNNEL_KEY_ENC_KEY_ID]) { |
|---|
| 410 | + __be32 key32; |
|---|
| 411 | + |
|---|
| 412 | + key32 = nla_get_be32(tb[TCA_TUNNEL_KEY_ENC_KEY_ID]); |
|---|
| 413 | + key_id = key32_to_tunnel_id(key32); |
|---|
| 414 | + flags = TUNNEL_KEY; |
|---|
| 268 | 415 | } |
|---|
| 269 | 416 | |
|---|
| 270 | | - key_id = key32_to_tunnel_id(nla_get_be32(tb[TCA_TUNNEL_KEY_ENC_KEY_ID])); |
|---|
| 271 | | - |
|---|
| 272 | | - flags = TUNNEL_KEY | TUNNEL_CSUM; |
|---|
| 417 | + flags |= TUNNEL_CSUM; |
|---|
| 273 | 418 | if (tb[TCA_TUNNEL_KEY_NO_CSUM] && |
|---|
| 274 | 419 | nla_get_u8(tb[TCA_TUNNEL_KEY_NO_CSUM])) |
|---|
| 275 | 420 | flags &= ~TUNNEL_CSUM; |
|---|
| .. | .. |
|---|
| 327 | 472 | goto err_out; |
|---|
| 328 | 473 | } |
|---|
| 329 | 474 | |
|---|
| 475 | +#ifdef CONFIG_DST_CACHE |
|---|
| 476 | + ret = dst_cache_init(&metadata->u.tun_info.dst_cache, GFP_KERNEL); |
|---|
| 477 | + if (ret) |
|---|
| 478 | + goto release_tun_meta; |
|---|
| 479 | +#endif |
|---|
| 480 | + |
|---|
| 330 | 481 | if (opts_len) { |
|---|
| 331 | 482 | ret = tunnel_key_opts_set(tb[TCA_TUNNEL_KEY_ENC_OPTS], |
|---|
| 332 | 483 | &metadata->u.tun_info, |
|---|
| .. | .. |
|---|
| 344 | 495 | } |
|---|
| 345 | 496 | |
|---|
| 346 | 497 | if (!exists) { |
|---|
| 347 | | - ret = tcf_idr_create(tn, index, est, a, |
|---|
| 348 | | - &act_tunnel_key_ops, bind, true); |
|---|
| 498 | + ret = tcf_idr_create_from_flags(tn, index, est, a, |
|---|
| 499 | + &act_tunnel_key_ops, bind, |
|---|
| 500 | + act_flags); |
|---|
| 349 | 501 | if (ret) { |
|---|
| 350 | 502 | NL_SET_ERR_MSG(extack, "Cannot create TC IDR"); |
|---|
| 351 | 503 | goto release_tun_meta; |
|---|
| .. | .. |
|---|
| 358 | 510 | goto release_tun_meta; |
|---|
| 359 | 511 | } |
|---|
| 360 | 512 | |
|---|
| 513 | + err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack); |
|---|
| 514 | + if (err < 0) { |
|---|
| 515 | + ret = err; |
|---|
| 516 | + exists = true; |
|---|
| 517 | + goto release_tun_meta; |
|---|
| 518 | + } |
|---|
| 361 | 519 | t = to_tunnel_key(*a); |
|---|
| 362 | 520 | |
|---|
| 363 | 521 | params_new = kzalloc(sizeof(*params_new), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 365 | 523 | NL_SET_ERR_MSG(extack, "Cannot allocate tunnel key parameters"); |
|---|
| 366 | 524 | ret = -ENOMEM; |
|---|
| 367 | 525 | exists = true; |
|---|
| 368 | | - goto release_tun_meta; |
|---|
| 526 | + goto put_chain; |
|---|
| 369 | 527 | } |
|---|
| 370 | 528 | params_new->tcft_action = parm->t_action; |
|---|
| 371 | 529 | params_new->tcft_enc_metadata = metadata; |
|---|
| 372 | 530 | |
|---|
| 373 | 531 | spin_lock_bh(&t->tcf_lock); |
|---|
| 374 | | - t->tcf_action = parm->action; |
|---|
| 375 | | - rcu_swap_protected(t->params, params_new, |
|---|
| 376 | | - lockdep_is_held(&t->tcf_lock)); |
|---|
| 532 | + goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch); |
|---|
| 533 | + params_new = rcu_replace_pointer(t->params, params_new, |
|---|
| 534 | + lockdep_is_held(&t->tcf_lock)); |
|---|
| 377 | 535 | spin_unlock_bh(&t->tcf_lock); |
|---|
| 378 | 536 | tunnel_key_release_params(params_new); |
|---|
| 379 | | - |
|---|
| 380 | | - if (ret == ACT_P_CREATED) |
|---|
| 381 | | - tcf_idr_insert(tn, *a); |
|---|
| 537 | + if (goto_ch) |
|---|
| 538 | + tcf_chain_put_by_act(goto_ch); |
|---|
| 382 | 539 | |
|---|
| 383 | 540 | return ret; |
|---|
| 541 | + |
|---|
| 542 | +put_chain: |
|---|
| 543 | + if (goto_ch) |
|---|
| 544 | + tcf_chain_put_by_act(goto_ch); |
|---|
| 384 | 545 | |
|---|
| 385 | 546 | release_tun_meta: |
|---|
| 386 | 547 | if (metadata) |
|---|
| .. | .. |
|---|
| 410 | 571 | u8 *src = (u8 *)(info + 1); |
|---|
| 411 | 572 | struct nlattr *start; |
|---|
| 412 | 573 | |
|---|
| 413 | | - start = nla_nest_start(skb, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE); |
|---|
| 574 | + start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE); |
|---|
| 414 | 575 | if (!start) |
|---|
| 415 | 576 | return -EMSGSIZE; |
|---|
| 416 | 577 | |
|---|
| .. | .. |
|---|
| 435 | 596 | return 0; |
|---|
| 436 | 597 | } |
|---|
| 437 | 598 | |
|---|
| 599 | +static int tunnel_key_vxlan_opts_dump(struct sk_buff *skb, |
|---|
| 600 | + const struct ip_tunnel_info *info) |
|---|
| 601 | +{ |
|---|
| 602 | + struct vxlan_metadata *md = (struct vxlan_metadata *)(info + 1); |
|---|
| 603 | + struct nlattr *start; |
|---|
| 604 | + |
|---|
| 605 | + start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_VXLAN); |
|---|
| 606 | + if (!start) |
|---|
| 607 | + return -EMSGSIZE; |
|---|
| 608 | + |
|---|
| 609 | + if (nla_put_u32(skb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, md->gbp)) { |
|---|
| 610 | + nla_nest_cancel(skb, start); |
|---|
| 611 | + return -EMSGSIZE; |
|---|
| 612 | + } |
|---|
| 613 | + |
|---|
| 614 | + nla_nest_end(skb, start); |
|---|
| 615 | + return 0; |
|---|
| 616 | +} |
|---|
| 617 | + |
|---|
| 618 | +static int tunnel_key_erspan_opts_dump(struct sk_buff *skb, |
|---|
| 619 | + const struct ip_tunnel_info *info) |
|---|
| 620 | +{ |
|---|
| 621 | + struct erspan_metadata *md = (struct erspan_metadata *)(info + 1); |
|---|
| 622 | + struct nlattr *start; |
|---|
| 623 | + |
|---|
| 624 | + start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN); |
|---|
| 625 | + if (!start) |
|---|
| 626 | + return -EMSGSIZE; |
|---|
| 627 | + |
|---|
| 628 | + if (nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER, md->version)) |
|---|
| 629 | + goto err; |
|---|
| 630 | + |
|---|
| 631 | + if (md->version == 1 && |
|---|
| 632 | + nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX, md->u.index)) |
|---|
| 633 | + goto err; |
|---|
| 634 | + |
|---|
| 635 | + if (md->version == 2 && |
|---|
| 636 | + (nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR, |
|---|
| 637 | + md->u.md2.dir) || |
|---|
| 638 | + nla_put_u8(skb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID, |
|---|
| 639 | + get_hwid(&md->u.md2)))) |
|---|
| 640 | + goto err; |
|---|
| 641 | + |
|---|
| 642 | + nla_nest_end(skb, start); |
|---|
| 643 | + return 0; |
|---|
| 644 | +err: |
|---|
| 645 | + nla_nest_cancel(skb, start); |
|---|
| 646 | + return -EMSGSIZE; |
|---|
| 647 | +} |
|---|
| 648 | + |
|---|
| 438 | 649 | static int tunnel_key_opts_dump(struct sk_buff *skb, |
|---|
| 439 | 650 | const struct ip_tunnel_info *info) |
|---|
| 440 | 651 | { |
|---|
| .. | .. |
|---|
| 444 | 655 | if (!info->options_len) |
|---|
| 445 | 656 | return 0; |
|---|
| 446 | 657 | |
|---|
| 447 | | - start = nla_nest_start(skb, TCA_TUNNEL_KEY_ENC_OPTS); |
|---|
| 658 | + start = nla_nest_start_noflag(skb, TCA_TUNNEL_KEY_ENC_OPTS); |
|---|
| 448 | 659 | if (!start) |
|---|
| 449 | 660 | return -EMSGSIZE; |
|---|
| 450 | 661 | |
|---|
| 451 | 662 | if (info->key.tun_flags & TUNNEL_GENEVE_OPT) { |
|---|
| 452 | 663 | err = tunnel_key_geneve_opts_dump(skb, info); |
|---|
| 664 | + if (err) |
|---|
| 665 | + goto err_out; |
|---|
| 666 | + } else if (info->key.tun_flags & TUNNEL_VXLAN_OPT) { |
|---|
| 667 | + err = tunnel_key_vxlan_opts_dump(skb, info); |
|---|
| 668 | + if (err) |
|---|
| 669 | + goto err_out; |
|---|
| 670 | + } else if (info->key.tun_flags & TUNNEL_ERSPAN_OPT) { |
|---|
| 671 | + err = tunnel_key_erspan_opts_dump(skb, info); |
|---|
| 453 | 672 | if (err) |
|---|
| 454 | 673 | goto err_out; |
|---|
| 455 | 674 | } else { |
|---|
| .. | .. |
|---|
| 518 | 737 | struct ip_tunnel_key *key = &info->key; |
|---|
| 519 | 738 | __be32 key_id = tunnel_id_to_key32(key->tun_id); |
|---|
| 520 | 739 | |
|---|
| 521 | | - if (nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_KEY_ID, key_id) || |
|---|
| 740 | + if (((key->tun_flags & TUNNEL_KEY) && |
|---|
| 741 | + nla_put_be32(skb, TCA_TUNNEL_KEY_ENC_KEY_ID, key_id)) || |
|---|
| 522 | 742 | tunnel_key_dump_addresses(skb, |
|---|
| 523 | 743 | ¶ms->tcft_enc_metadata->u.tun_info) || |
|---|
| 524 | | - nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_DST_PORT, key->tp_dst) || |
|---|
| 744 | + (key->tp_dst && |
|---|
| 745 | + nla_put_be16(skb, TCA_TUNNEL_KEY_ENC_DST_PORT, |
|---|
| 746 | + key->tp_dst)) || |
|---|
| 525 | 747 | nla_put_u8(skb, TCA_TUNNEL_KEY_NO_CSUM, |
|---|
| 526 | 748 | !(key->tun_flags & TUNNEL_CSUM)) || |
|---|
| 527 | 749 | tunnel_key_opts_dump(skb, info)) |
|---|
| .. | .. |
|---|
| 558 | 780 | return tcf_generic_walker(tn, skb, cb, type, ops, extack); |
|---|
| 559 | 781 | } |
|---|
| 560 | 782 | |
|---|
| 561 | | -static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index, |
|---|
| 562 | | - struct netlink_ext_ack *extack) |
|---|
| 783 | +static int tunnel_key_search(struct net *net, struct tc_action **a, u32 index) |
|---|
| 563 | 784 | { |
|---|
| 564 | 785 | struct tc_action_net *tn = net_generic(net, tunnel_key_net_id); |
|---|
| 565 | 786 | |
|---|
| .. | .. |
|---|
| 568 | 789 | |
|---|
| 569 | 790 | static struct tc_action_ops act_tunnel_key_ops = { |
|---|
| 570 | 791 | .kind = "tunnel_key", |
|---|
| 571 | | - .type = TCA_ACT_TUNNEL_KEY, |
|---|
| 792 | + .id = TCA_ID_TUNNEL_KEY, |
|---|
| 572 | 793 | .owner = THIS_MODULE, |
|---|
| 573 | 794 | .act = tunnel_key_act, |
|---|
| 574 | 795 | .dump = tunnel_key_dump, |
|---|