This command could be useful to inc/dec fields.

For example, to forward any TCP packet and decrease its TTL:
$ tc filter add dev enp0s9 protocol ip parent ffff: \
    flower ip_proto tcp \
    action pedit munge ip ttl add 0xff pipe \
    action mirred egress redirect dev veth0

In the example above, adding 0xff to this u8 field is actually
decreasing it by one, since the operation is masked.

Signed-off-by: Amir Vadai <a...@vadai.me>
---
 include/uapi/linux/tc_act/tc_pedit.h | 10 ++++++++++
 net/sched/act_pedit.c                | 16 +++++++++++++++-
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/include/uapi/linux/tc_act/tc_pedit.h 
b/include/uapi/linux/tc_act/tc_pedit.h
index 604e6729ad38..80028cd0bb1b 100644
--- a/include/uapi/linux/tc_act/tc_pedit.h
+++ b/include/uapi/linux/tc_act/tc_pedit.h
@@ -35,8 +35,13 @@ struct tc_pedit_sel {
 #define PEDIT_TYPE_SHIFT 24
 #define PEDIT_TYPE_MASK 0xff
 
+#define PEDIT_CMD_SHIFT 16
+#define PEDIT_CMD_MASK 0xff
+
 #define PEDIT_TYPE_GET(_val) \
        (((_val) >> PEDIT_TYPE_SHIFT) & PEDIT_TYPE_MASK)
+#define PEDIT_CMD_GET(_val) \
+       (((_val) >> PEDIT_CMD_SHIFT) & PEDIT_CMD_MASK)
 #define PEDIT_SHIFT_GET(_val) ((_val) & 0xff)
 
 enum pedit_header_type {
@@ -49,4 +54,9 @@ enum pedit_header_type {
        PEDIT_HDR_TYPE_UDP = 5,
 };
 
+enum pedit_cmd {
+       PEDIT_CMD_SET = 0,
+       PEDIT_CMD_ADD = 1,
+};
+
 #endif
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index 4b9c7184c752..aa137d51bf7f 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -169,6 +169,7 @@ static int tcf_pedit(struct sk_buff *skb, const struct 
tc_action *a,
                        u32 *ptr, _data;
                        int offset = tkey->off;
                        int hoffset;
+                       u32 val;
                        int rc;
                        enum pedit_header_type htype =
                                PEDIT_TYPE_GET(tkey->shift);
@@ -214,7 +215,20 @@ static int tcf_pedit(struct sk_buff *skb, const struct 
tc_action *a,
                        if (!ptr)
                                goto bad;
                        /* just do it, baby */
-                       *ptr = ((*ptr & tkey->mask) ^ tkey->val);
+                       switch (PEDIT_CMD_GET(tkey->shift)) {
+                       case PEDIT_CMD_SET:
+                               val = tkey->val;
+                               break;
+                       case PEDIT_CMD_ADD:
+                               val = (*ptr + tkey->val) & ~tkey->mask;
+                               break;
+                       default:
+                               pr_info("tc filter pedit bad command (%d)\n",
+                                       PEDIT_CMD_GET(tkey->shift));
+                               goto bad;
+                       }
+
+                       *ptr = ((*ptr & tkey->mask) ^ val);
                        if (ptr == &_data)
                                skb_store_bits(skb, hoffset + offset, ptr, 4);
                }
-- 
2.10.2

Reply via email to