@@ -572,12 +572,68 @@ static int nft_payload_set_dump(struct sk_buff *skb, const struct nft_expr *expr
return -1;
}
+static int nft_payload_set_offload(struct nft_offload_ctx *ctx,
+ struct nft_flow_rule *flow,
+ const struct nft_expr *expr)
+{
+ const struct nft_payload_set *priv = nft_expr_priv(expr);
+ struct nft_offload_reg *reg = &ctx->regs[priv->sreg];
+ const struct nft_data *data = ®->action.data;
+ struct flow_action_entry *entry;
+ u32 len = priv->len;
+ u32 offset, last;
+ int n_actions, i;
+
+ if (priv->base != NFT_PAYLOAD_LL_HEADER || len > 16)
+ return -EOPNOTSUPP;
+
+ offset = priv->offset;
+ n_actions = len >> 2;
+ last = len & 0x3;
+
+ for (i = 0; i < n_actions; i++) {
+ entry = &flow->rule->action.entries[ctx->num_actions++];
+
+ entry->id = FLOW_ACTION_MANGLE;
+ entry->mangle.htype = FLOW_ACT_MANGLE_HDR_TYPE_ETH;
+ entry->mangle.mask = 0;
+ entry->mangle.val = data->data[i];
+ entry->mangle.offset = offset;
+ offset = offset + 4;
+ }
+
+ if (last) {
+ entry = &flow->rule->action.entries[ctx->num_actions++];
+
+ entry->id = FLOW_ACTION_MANGLE;
+ entry->mangle.htype = FLOW_ACT_MANGLE_HDR_TYPE_ETH;
+ entry->mangle.mask = ~((1 << (last * 8)) - 1);
+ entry->mangle.val = data->data[i];
+ entry->mangle.offset = offset;
+ }
+
+ return 0;
+}
+
+static int nft_payload_set_offload_actions(const struct nft_expr *expr)
+{
+ const struct nft_payload_set *priv = nft_expr_priv(expr);
+ u32 len = priv->len;
+
+ if (priv->base != NFT_PAYLOAD_LL_HEADER || len > 16)
+ return 0;
+
+ return (len >> 2) + !!(len & 3);
+}
+
static const struct nft_expr_ops nft_payload_set_ops = {
.type = &nft_payload_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_payload_set)),
.eval = nft_payload_set_eval,
.init = nft_payload_set_init,
.dump = nft_payload_set_dump,
+ .offload = nft_payload_set_offload,
+ .offload_actions = nft_payload_set_offload_actions,
};
static const struct nft_expr_ops *