|
36 | 36 | #include <net/switchdev.h>
|
37 | 37 | #include <net/tc_act/tc_gact.h>
|
38 | 38 | #include <net/tc_act/tc_mirred.h>
|
| 39 | +#include <net/tc_act/tc_pedit.h> |
39 | 40 | #include <net/tc_act/tc_vlan.h>
|
40 | 41 | #include <net/tc_act/tc_tunnel_key.h>
|
41 | 42 |
|
@@ -223,6 +224,87 @@ nfp_fl_set_vxlan(struct nfp_fl_set_vxlan *set_vxlan,
|
223 | 224 | return 0;
|
224 | 225 | }
|
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_pedit(const struct tc_action *action, char *nfp_action, int *a_len) |
| 270 | +{ |
| 271 | + struct nfp_fl_set_eth set_eth; |
| 272 | + enum pedit_header_type htype; |
| 273 | + int idx, nkeys, err; |
| 274 | + size_t act_size; |
| 275 | + u32 offset, cmd; |
| 276 | + |
| 277 | + memset(&set_eth, 0, sizeof(set_eth)); |
| 278 | + nkeys = tcf_pedit_nkeys(action); |
| 279 | + |
| 280 | + for (idx = 0; idx < nkeys; idx++) { |
| 281 | + cmd = tcf_pedit_cmd(action, idx); |
| 282 | + htype = tcf_pedit_htype(action, idx); |
| 283 | + offset = tcf_pedit_offset(action, idx); |
| 284 | + |
| 285 | + if (cmd != TCA_PEDIT_KEY_EX_CMD_SET) |
| 286 | + return -EOPNOTSUPP; |
| 287 | + |
| 288 | + switch (htype) { |
| 289 | + case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH: |
| 290 | + err = nfp_fl_set_eth(action, idx, offset, &set_eth); |
| 291 | + break; |
| 292 | + default: |
| 293 | + return -EOPNOTSUPP; |
| 294 | + } |
| 295 | + if (err) |
| 296 | + return err; |
| 297 | + } |
| 298 | + |
| 299 | + if (set_eth.a_op) { |
| 300 | + act_size = sizeof(set_eth); |
| 301 | + memcpy(nfp_action, &set_eth, act_size); |
| 302 | + *a_len += act_size; |
| 303 | + } |
| 304 | + |
| 305 | + return 0; |
| 306 | +} |
| 307 | + |
226 | 308 | static int
|
227 | 309 | nfp_flower_loop_action(const struct tc_action *a,
|
228 | 310 | struct nfp_fl_payload *nfp_fl, int *a_len,
|
@@ -301,6 +383,9 @@ nfp_flower_loop_action(const struct tc_action *a,
|
301 | 383 | } else if (is_tcf_tunnel_release(a)) {
|
302 | 384 | /* Tunnel decap is handled by default so accept action. */
|
303 | 385 | return 0;
|
| 386 | + } else if (is_tcf_pedit(a)) { |
| 387 | + if (nfp_fl_pedit(a, &nfp_fl->action_data[*a_len], a_len)) |
| 388 | + return -EOPNOTSUPP; |
304 | 389 | } else {
|
305 | 390 | /* Currently we do not handle any other actions. */
|
306 | 391 | return -EOPNOTSUPP;
|
|
0 commit comments