1 /* 2 * Copyright (C) 2017 Netronome Systems, Inc. 3 * 4 * This software is dual licensed under the GNU General License Version 2, 5 * June 1991 as shown in the file COPYING in the top-level directory of this 6 * source tree or the BSD 2-Clause License provided below. You have the 7 * option to license this software under the complete terms of either license. 8 * 9 * The BSD 2-Clause License: 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 15 * 1. Redistributions of source code must retain the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer. 18 * 19 * 2. Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials 22 * provided with the distribution. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 * SOFTWARE. 32 */ 33 34 #include <linux/bitfield.h> 35 #include <net/pkt_cls.h> 36 #include <net/switchdev.h> 37 #include <net/tc_act/tc_gact.h> 38 #include <net/tc_act/tc_mirred.h> 39 #include <net/tc_act/tc_pedit.h> 40 #include <net/tc_act/tc_vlan.h> 41 #include <net/tc_act/tc_tunnel_key.h> 42 43 #include "cmsg.h" 44 #include "main.h" 45 #include "../nfp_net_repr.h" 46 47 static void nfp_fl_pop_vlan(struct nfp_fl_pop_vlan *pop_vlan) 48 { 49 size_t act_size = sizeof(struct nfp_fl_pop_vlan); 50 u16 tmp_pop_vlan_op; 51 52 tmp_pop_vlan_op = 53 FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) | 54 FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_POP_VLAN); 55 56 pop_vlan->a_op = cpu_to_be16(tmp_pop_vlan_op); 57 pop_vlan->reserved = 0; 58 } 59 60 static void 61 nfp_fl_push_vlan(struct nfp_fl_push_vlan *push_vlan, 62 const struct tc_action *action) 63 { 64 size_t act_size = sizeof(struct nfp_fl_push_vlan); 65 struct tcf_vlan *vlan = to_vlan(action); 66 u16 tmp_push_vlan_tci; 67 u16 tmp_push_vlan_op; 68 69 tmp_push_vlan_op = 70 FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) | 71 FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_PUSH_VLAN); 72 73 push_vlan->a_op = cpu_to_be16(tmp_push_vlan_op); 74 /* Set action push vlan parameters. */ 75 push_vlan->reserved = 0; 76 push_vlan->vlan_tpid = tcf_vlan_push_proto(action); 77 78 tmp_push_vlan_tci = 79 FIELD_PREP(NFP_FL_PUSH_VLAN_PRIO, vlan->tcfv_push_prio) | 80 FIELD_PREP(NFP_FL_PUSH_VLAN_VID, vlan->tcfv_push_vid) | 81 NFP_FL_PUSH_VLAN_CFI; 82 push_vlan->vlan_tci = cpu_to_be16(tmp_push_vlan_tci); 83 } 84 85 static bool nfp_fl_netdev_is_tunnel_type(struct net_device *out_dev, 86 enum nfp_flower_tun_type tun_type) 87 { 88 if (!out_dev->rtnl_link_ops) 89 return false; 90 91 if (!strcmp(out_dev->rtnl_link_ops->kind, "vxlan")) 92 return tun_type == NFP_FL_TUNNEL_VXLAN; 93 94 return false; 95 } 96 97 static int 98 nfp_fl_output(struct nfp_fl_output *output, const struct tc_action *action, 99 struct nfp_fl_payload *nfp_flow, bool last, 100 struct net_device *in_dev, enum nfp_flower_tun_type tun_type, 101 int *tun_out_cnt) 102 { 103 size_t act_size = sizeof(struct nfp_fl_output); 104 u16 tmp_output_op, tmp_flags; 105 struct net_device *out_dev; 106 int ifindex; 107 108 /* Set action opcode to output action. */ 109 tmp_output_op = 110 FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) | 111 FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_OUTPUT); 112 113 output->a_op = cpu_to_be16(tmp_output_op); 114 115 ifindex = tcf_mirred_ifindex(action); 116 out_dev = __dev_get_by_index(dev_net(in_dev), ifindex); 117 if (!out_dev) 118 return -EOPNOTSUPP; 119 120 tmp_flags = last ? NFP_FL_OUT_FLAGS_LAST : 0; 121 122 if (tun_type) { 123 /* Verify the egress netdev matches the tunnel type. */ 124 if (!nfp_fl_netdev_is_tunnel_type(out_dev, tun_type)) 125 return -EOPNOTSUPP; 126 127 if (*tun_out_cnt) 128 return -EOPNOTSUPP; 129 (*tun_out_cnt)++; 130 131 output->flags = cpu_to_be16(tmp_flags | 132 NFP_FL_OUT_FLAGS_USE_TUN); 133 output->port = cpu_to_be32(NFP_FL_PORT_TYPE_TUN | tun_type); 134 } else { 135 /* Set action output parameters. */ 136 output->flags = cpu_to_be16(tmp_flags); 137 138 /* Only offload if egress ports are on the same device as the 139 * ingress port. 140 */ 141 if (!switchdev_port_same_parent_id(in_dev, out_dev)) 142 return -EOPNOTSUPP; 143 144 output->port = cpu_to_be32(nfp_repr_get_port_id(out_dev)); 145 if (!output->port) 146 return -EOPNOTSUPP; 147 } 148 nfp_flow->meta.shortcut = output->port; 149 150 return 0; 151 } 152 153 static bool nfp_fl_supported_tun_port(const struct tc_action *action) 154 { 155 struct ip_tunnel_info *tun = tcf_tunnel_info(action); 156 157 return tun->key.tp_dst == htons(NFP_FL_VXLAN_PORT); 158 } 159 160 static struct nfp_fl_pre_tunnel *nfp_fl_pre_tunnel(char *act_data, int act_len) 161 { 162 size_t act_size = sizeof(struct nfp_fl_pre_tunnel); 163 struct nfp_fl_pre_tunnel *pre_tun_act; 164 u16 tmp_pre_tun_op; 165 166 /* Pre_tunnel action must be first on action list. 167 * If other actions already exist they need pushed forward. 168 */ 169 if (act_len) 170 memmove(act_data + act_size, act_data, act_len); 171 172 pre_tun_act = (struct nfp_fl_pre_tunnel *)act_data; 173 174 memset(pre_tun_act, 0, act_size); 175 176 tmp_pre_tun_op = 177 FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) | 178 FIELD_PREP(NFP_FL_ACT_JMP_ID, NFP_FL_ACTION_OPCODE_PRE_TUNNEL); 179 180 pre_tun_act->a_op = cpu_to_be16(tmp_pre_tun_op); 181 182 return pre_tun_act; 183 } 184 185 static int 186 nfp_fl_set_vxlan(struct nfp_fl_set_vxlan *set_vxlan, 187 const struct tc_action *action, 188 struct nfp_fl_pre_tunnel *pre_tun) 189 { 190 struct ip_tunnel_info *vxlan = tcf_tunnel_info(action); 191 size_t act_size = sizeof(struct nfp_fl_set_vxlan); 192 u32 tmp_set_vxlan_type_index = 0; 193 u16 tmp_set_vxlan_op; 194 /* Currently support one pre-tunnel so index is always 0. */ 195 int pretun_idx = 0; 196 197 if (vxlan->options_len) { 198 /* Do not support options e.g. vxlan gpe. */ 199 return -EOPNOTSUPP; 200 } 201 202 tmp_set_vxlan_op = 203 FIELD_PREP(NFP_FL_ACT_LEN_LW, act_size >> NFP_FL_LW_SIZ) | 204 FIELD_PREP(NFP_FL_ACT_JMP_ID, 205 NFP_FL_ACTION_OPCODE_SET_IPV4_TUNNEL); 206 207 set_vxlan->a_op = cpu_to_be16(tmp_set_vxlan_op); 208 209 /* Set tunnel type and pre-tunnel index. */ 210 tmp_set_vxlan_type_index |= 211 FIELD_PREP(NFP_FL_IPV4_TUNNEL_TYPE, NFP_FL_TUNNEL_VXLAN) | 212 FIELD_PREP(NFP_FL_IPV4_PRE_TUN_INDEX, pretun_idx); 213 214 set_vxlan->tun_type_index = cpu_to_be32(tmp_set_vxlan_type_index); 215 216 set_vxlan->tun_id = vxlan->key.tun_id; 217 set_vxlan->tun_flags = vxlan->key.tun_flags; 218 set_vxlan->ipv4_ttl = vxlan->key.ttl; 219 set_vxlan->ipv4_tos = vxlan->key.tos; 220 221 /* Complete pre_tunnel action. */ 222 pre_tun->ipv4_dst = vxlan->key.u.ipv4.dst; 223 224 return 0; 225 } 226 227 static void nfp_fl_set_helper32(u32 value, u32 mask, u8 *p_exact, u8 *p_mask) 228 { 229 u32 oldvalue = get_unaligned((u32 *)p_exact); 230 u32 oldmask = get_unaligned((u32 *)p_mask); 231 232 value &= mask; 233 value |= oldvalue & ~mask; 234 235 put_unaligned(oldmask | mask, (u32 *)p_mask); 236 put_unaligned(value, (u32 *)p_exact); 237 } 238 239 static int 240 nfp_fl_set_eth(const struct tc_action *action, int idx, u32 off, 241 struct nfp_fl_set_eth *set_eth) 242 { 243 u16 tmp_set_eth_op; 244 u32 exact, mask; 245 246 if (off + 4 > ETH_ALEN * 2) 247 return -EOPNOTSUPP; 248 249 mask = ~tcf_pedit_mask(action, idx); 250 exact = tcf_pedit_val(action, idx); 251 252 if (exact & ~mask) 253 return -EOPNOTSUPP; 254 255 nfp_fl_set_helper32(exact, mask, &set_eth->eth_addr_val[off], 256 &set_eth->eth_addr_mask[off]); 257 258 set_eth->reserved = cpu_to_be16(0); 259 tmp_set_eth_op = FIELD_PREP(NFP_FL_ACT_LEN_LW, 260 sizeof(*set_eth) >> NFP_FL_LW_SIZ) | 261 FIELD_PREP(NFP_FL_ACT_JMP_ID, 262 NFP_FL_ACTION_OPCODE_SET_ETHERNET); 263 set_eth->a_op = cpu_to_be16(tmp_set_eth_op); 264 265 return 0; 266 } 267 268 static int 269 nfp_fl_set_ip4(const struct tc_action *action, int idx, u32 off, 270 struct nfp_fl_set_ip4_addrs *set_ip_addr) 271 { 272 u16 tmp_set_ipv4_op; 273 __be32 exact, mask; 274 275 /* We are expecting tcf_pedit to return a big endian value */ 276 mask = (__force __be32)~tcf_pedit_mask(action, idx); 277 exact = (__force __be32)tcf_pedit_val(action, idx); 278 279 if (exact & ~mask) 280 return -EOPNOTSUPP; 281 282 switch (off) { 283 case offsetof(struct iphdr, daddr): 284 set_ip_addr->ipv4_dst_mask = mask; 285 set_ip_addr->ipv4_dst = exact; 286 break; 287 case offsetof(struct iphdr, saddr): 288 set_ip_addr->ipv4_src_mask = mask; 289 set_ip_addr->ipv4_src = exact; 290 break; 291 default: 292 return -EOPNOTSUPP; 293 } 294 295 set_ip_addr->reserved = cpu_to_be16(0); 296 tmp_set_ipv4_op = FIELD_PREP(NFP_FL_ACT_LEN_LW, 297 sizeof(*set_ip_addr) >> NFP_FL_LW_SIZ) | 298 FIELD_PREP(NFP_FL_ACT_JMP_ID, 299 NFP_FL_ACTION_OPCODE_SET_IPV4_ADDRS); 300 set_ip_addr->a_op = cpu_to_be16(tmp_set_ipv4_op); 301 302 return 0; 303 } 304 305 static void 306 nfp_fl_set_ip6_helper(int opcode_tag, int idx, __be32 exact, __be32 mask, 307 struct nfp_fl_set_ipv6_addr *ip6) 308 { 309 u16 tmp_set_op; 310 311 ip6->ipv6[idx % 4].mask = mask; 312 ip6->ipv6[idx % 4].exact = exact; 313 314 ip6->reserved = cpu_to_be16(0); 315 tmp_set_op = FIELD_PREP(NFP_FL_ACT_LEN_LW, sizeof(*ip6) >> 316 NFP_FL_LW_SIZ) | 317 FIELD_PREP(NFP_FL_ACT_JMP_ID, opcode_tag); 318 ip6->a_op = cpu_to_be16(tmp_set_op); 319 } 320 321 static int 322 nfp_fl_set_ip6(const struct tc_action *action, int idx, u32 off, 323 struct nfp_fl_set_ipv6_addr *ip_dst, 324 struct nfp_fl_set_ipv6_addr *ip_src) 325 { 326 __be32 exact, mask; 327 328 /* We are expecting tcf_pedit to return a big endian value */ 329 mask = (__force __be32)~tcf_pedit_mask(action, idx); 330 exact = (__force __be32)tcf_pedit_val(action, idx); 331 332 if (exact & ~mask) 333 return -EOPNOTSUPP; 334 335 if (off < offsetof(struct ipv6hdr, saddr)) 336 return -EOPNOTSUPP; 337 else if (off < offsetof(struct ipv6hdr, daddr)) 338 nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_SRC, idx, 339 exact, mask, ip_src); 340 else if (off < offsetof(struct ipv6hdr, daddr) + 341 sizeof(struct in6_addr)) 342 nfp_fl_set_ip6_helper(NFP_FL_ACTION_OPCODE_SET_IPV6_DST, idx, 343 exact, mask, ip_dst); 344 else 345 return -EOPNOTSUPP; 346 347 return 0; 348 } 349 350 static int 351 nfp_fl_set_tport(const struct tc_action *action, int idx, u32 off, 352 struct nfp_fl_set_tport *set_tport, int opcode) 353 { 354 u32 exact, mask; 355 u16 tmp_set_op; 356 357 if (off) 358 return -EOPNOTSUPP; 359 360 mask = ~tcf_pedit_mask(action, idx); 361 exact = tcf_pedit_val(action, idx); 362 363 if (exact & ~mask) 364 return -EOPNOTSUPP; 365 366 nfp_fl_set_helper32(exact, mask, set_tport->tp_port_val, 367 set_tport->tp_port_mask); 368 369 set_tport->reserved = cpu_to_be16(0); 370 tmp_set_op = FIELD_PREP(NFP_FL_ACT_LEN_LW, 371 sizeof(*set_tport) >> NFP_FL_LW_SIZ); 372 tmp_set_op |= FIELD_PREP(NFP_FL_ACT_JMP_ID, opcode); 373 set_tport->a_op = cpu_to_be16(tmp_set_op); 374 375 return 0; 376 } 377 378 static int 379 nfp_fl_pedit(const struct tc_action *action, char *nfp_action, int *a_len) 380 { 381 struct nfp_fl_set_ipv6_addr set_ip6_dst, set_ip6_src; 382 struct nfp_fl_set_ip4_addrs set_ip_addr; 383 struct nfp_fl_set_tport set_tport; 384 struct nfp_fl_set_eth set_eth; 385 enum pedit_header_type htype; 386 int idx, nkeys, err; 387 size_t act_size; 388 u32 offset, cmd; 389 390 memset(&set_ip6_dst, 0, sizeof(set_ip6_dst)); 391 memset(&set_ip6_src, 0, sizeof(set_ip6_src)); 392 memset(&set_ip_addr, 0, sizeof(set_ip_addr)); 393 memset(&set_tport, 0, sizeof(set_tport)); 394 memset(&set_eth, 0, sizeof(set_eth)); 395 nkeys = tcf_pedit_nkeys(action); 396 397 for (idx = 0; idx < nkeys; idx++) { 398 cmd = tcf_pedit_cmd(action, idx); 399 htype = tcf_pedit_htype(action, idx); 400 offset = tcf_pedit_offset(action, idx); 401 402 if (cmd != TCA_PEDIT_KEY_EX_CMD_SET) 403 return -EOPNOTSUPP; 404 405 switch (htype) { 406 case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH: 407 err = nfp_fl_set_eth(action, idx, offset, &set_eth); 408 break; 409 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4: 410 err = nfp_fl_set_ip4(action, idx, offset, &set_ip_addr); 411 break; 412 case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6: 413 err = nfp_fl_set_ip6(action, idx, offset, &set_ip6_dst, 414 &set_ip6_src); 415 break; 416 case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP: 417 err = nfp_fl_set_tport(action, idx, offset, &set_tport, 418 NFP_FL_ACTION_OPCODE_SET_TCP); 419 break; 420 case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP: 421 err = nfp_fl_set_tport(action, idx, offset, &set_tport, 422 NFP_FL_ACTION_OPCODE_SET_UDP); 423 break; 424 default: 425 return -EOPNOTSUPP; 426 } 427 if (err) 428 return err; 429 } 430 431 if (set_eth.a_op) { 432 act_size = sizeof(set_eth); 433 memcpy(nfp_action, &set_eth, act_size); 434 *a_len += act_size; 435 } else if (set_ip_addr.a_op) { 436 act_size = sizeof(set_ip_addr); 437 memcpy(nfp_action, &set_ip_addr, act_size); 438 *a_len += act_size; 439 } else if (set_ip6_dst.a_op && set_ip6_src.a_op) { 440 /* TC compiles set src and dst IPv6 address as a single action, 441 * the hardware requires this to be 2 separate actions. 442 */ 443 act_size = sizeof(set_ip6_src); 444 memcpy(nfp_action, &set_ip6_src, act_size); 445 *a_len += act_size; 446 447 act_size = sizeof(set_ip6_dst); 448 memcpy(&nfp_action[sizeof(set_ip6_src)], &set_ip6_dst, 449 act_size); 450 *a_len += act_size; 451 } else if (set_ip6_dst.a_op) { 452 act_size = sizeof(set_ip6_dst); 453 memcpy(nfp_action, &set_ip6_dst, act_size); 454 *a_len += act_size; 455 } else if (set_ip6_src.a_op) { 456 act_size = sizeof(set_ip6_src); 457 memcpy(nfp_action, &set_ip6_src, act_size); 458 *a_len += act_size; 459 } else if (set_tport.a_op) { 460 act_size = sizeof(set_tport); 461 memcpy(nfp_action, &set_tport, act_size); 462 *a_len += act_size; 463 } 464 465 return 0; 466 } 467 468 static int 469 nfp_flower_loop_action(const struct tc_action *a, 470 struct nfp_fl_payload *nfp_fl, int *a_len, 471 struct net_device *netdev, 472 enum nfp_flower_tun_type *tun_type, int *tun_out_cnt) 473 { 474 struct nfp_fl_pre_tunnel *pre_tun; 475 struct nfp_fl_set_vxlan *s_vxl; 476 struct nfp_fl_push_vlan *psh_v; 477 struct nfp_fl_pop_vlan *pop_v; 478 struct nfp_fl_output *output; 479 int err; 480 481 if (is_tcf_gact_shot(a)) { 482 nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_DROP); 483 } else if (is_tcf_mirred_egress_redirect(a)) { 484 if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ) 485 return -EOPNOTSUPP; 486 487 output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len]; 488 err = nfp_fl_output(output, a, nfp_fl, true, netdev, *tun_type, 489 tun_out_cnt); 490 if (err) 491 return err; 492 493 *a_len += sizeof(struct nfp_fl_output); 494 } else if (is_tcf_mirred_egress_mirror(a)) { 495 if (*a_len + sizeof(struct nfp_fl_output) > NFP_FL_MAX_A_SIZ) 496 return -EOPNOTSUPP; 497 498 output = (struct nfp_fl_output *)&nfp_fl->action_data[*a_len]; 499 err = nfp_fl_output(output, a, nfp_fl, false, netdev, *tun_type, 500 tun_out_cnt); 501 if (err) 502 return err; 503 504 *a_len += sizeof(struct nfp_fl_output); 505 } else if (is_tcf_vlan(a) && tcf_vlan_action(a) == TCA_VLAN_ACT_POP) { 506 if (*a_len + sizeof(struct nfp_fl_pop_vlan) > NFP_FL_MAX_A_SIZ) 507 return -EOPNOTSUPP; 508 509 pop_v = (struct nfp_fl_pop_vlan *)&nfp_fl->action_data[*a_len]; 510 nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_POPV); 511 512 nfp_fl_pop_vlan(pop_v); 513 *a_len += sizeof(struct nfp_fl_pop_vlan); 514 } else if (is_tcf_vlan(a) && tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) { 515 if (*a_len + sizeof(struct nfp_fl_push_vlan) > NFP_FL_MAX_A_SIZ) 516 return -EOPNOTSUPP; 517 518 psh_v = (struct nfp_fl_push_vlan *)&nfp_fl->action_data[*a_len]; 519 nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL); 520 521 nfp_fl_push_vlan(psh_v, a); 522 *a_len += sizeof(struct nfp_fl_push_vlan); 523 } else if (is_tcf_tunnel_set(a) && nfp_fl_supported_tun_port(a)) { 524 /* Pre-tunnel action is required for tunnel encap. 525 * This checks for next hop entries on NFP. 526 * If none, the packet falls back before applying other actions. 527 */ 528 if (*a_len + sizeof(struct nfp_fl_pre_tunnel) + 529 sizeof(struct nfp_fl_set_vxlan) > NFP_FL_MAX_A_SIZ) 530 return -EOPNOTSUPP; 531 532 *tun_type = NFP_FL_TUNNEL_VXLAN; 533 pre_tun = nfp_fl_pre_tunnel(nfp_fl->action_data, *a_len); 534 nfp_fl->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL); 535 *a_len += sizeof(struct nfp_fl_pre_tunnel); 536 537 s_vxl = (struct nfp_fl_set_vxlan *)&nfp_fl->action_data[*a_len]; 538 err = nfp_fl_set_vxlan(s_vxl, a, pre_tun); 539 if (err) 540 return err; 541 542 *a_len += sizeof(struct nfp_fl_set_vxlan); 543 } else if (is_tcf_tunnel_release(a)) { 544 /* Tunnel decap is handled by default so accept action. */ 545 return 0; 546 } else if (is_tcf_pedit(a)) { 547 if (nfp_fl_pedit(a, &nfp_fl->action_data[*a_len], a_len)) 548 return -EOPNOTSUPP; 549 } else { 550 /* Currently we do not handle any other actions. */ 551 return -EOPNOTSUPP; 552 } 553 554 return 0; 555 } 556 557 int nfp_flower_compile_action(struct tc_cls_flower_offload *flow, 558 struct net_device *netdev, 559 struct nfp_fl_payload *nfp_flow) 560 { 561 int act_len, act_cnt, err, tun_out_cnt; 562 enum nfp_flower_tun_type tun_type; 563 const struct tc_action *a; 564 LIST_HEAD(actions); 565 566 memset(nfp_flow->action_data, 0, NFP_FL_MAX_A_SIZ); 567 nfp_flow->meta.act_len = 0; 568 tun_type = NFP_FL_TUNNEL_NONE; 569 act_len = 0; 570 act_cnt = 0; 571 tun_out_cnt = 0; 572 573 tcf_exts_to_list(flow->exts, &actions); 574 list_for_each_entry(a, &actions, list) { 575 err = nfp_flower_loop_action(a, nfp_flow, &act_len, netdev, 576 &tun_type, &tun_out_cnt); 577 if (err) 578 return err; 579 act_cnt++; 580 } 581 582 /* We optimise when the action list is small, this can unfortunately 583 * not happen once we have more than one action in the action list. 584 */ 585 if (act_cnt > 1) 586 nfp_flow->meta.shortcut = cpu_to_be32(NFP_FL_SC_ACT_NULL); 587 588 nfp_flow->meta.act_len = act_len; 589 590 return 0; 591 } 592