[{"id":1770228,"web_url":"http://patchwork.ozlabs.org/comment/1770228/","msgid":"<20170918150107.GD25154@vergenet.net>","list_archive_url":null,"date":"2017-09-18T15:01:09","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":64714,"url":"http://patchwork.ozlabs.org/api/people/64714/","name":"Simon Horman","email":"simon.horman@netronome.com"},"content":"On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n> From: Paul Blakey <paulb@mellanox.com>\n> \n> To be later used to implement ovs action set offloading.\n> \n> Signed-off-by: Paul Blakey <paulb@mellanox.com>\n> Reviewed-by: Roi Dayan <roid@mellanox.com>\n> ---\n>  lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n>  lib/tc.h |  16 +++\n>  2 files changed, 385 insertions(+), 3 deletions(-)\n> \n> diff --git a/lib/tc.c b/lib/tc.c\n> index c9cada2..743b2ee 100644\n> --- a/lib/tc.c\n> +++ b/lib/tc.c\n> @@ -21,8 +21,10 @@\n>  #include <errno.h>\n>  #include <linux/if_ether.h>\n>  #include <linux/rtnetlink.h>\n> +#include <linux/tc_act/tc_csum.h>\n>  #include <linux/tc_act/tc_gact.h>\n>  #include <linux/tc_act/tc_mirred.h>\n> +#include <linux/tc_act/tc_pedit.h>\n>  #include <linux/tc_act/tc_tunnel_key.h>\n>  #include <linux/tc_act/tc_vlan.h>\n>  #include <linux/gen_stats.h>\n> @@ -33,11 +35,14 @@\n>  #include \"netlink-socket.h\"\n>  #include \"netlink.h\"\n>  #include \"openvswitch/ofpbuf.h\"\n> +#include \"openvswitch/util.h\"\n>  #include \"openvswitch/vlog.h\"\n>  #include \"packets.h\"\n>  #include \"timeval.h\"\n>  #include \"unaligned.h\"\n>  \n> +#define MAX_PEDIT_OFFSETS 8\n\nWhy 8?\n\n> +\n>  VLOG_DEFINE_THIS_MODULE(tc);\n>  \n>  static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);\n> @@ -50,6 +55,82 @@ enum tc_offload_policy {\n>  \n>  static enum tc_offload_policy tc_policy = TC_POLICY_NONE;\n>  \n> +struct tc_pedit_key_ex {\n> +    enum pedit_header_type htype;\n> +    enum pedit_cmd cmd;\n> +};\n> +\n> +struct flower_key_to_pedit {\n> +    enum pedit_header_type htype;\n> +    int flower_offset;\n> +    int offset;\n> +    int size;\n> +};\n> +\n> +static struct flower_key_to_pedit flower_pedit_map[] = {\n> +    {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> +        12,\n> +        offsetof(struct tc_flower_key, ipv4.ipv4_src),\n> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> +        16,\n> +        offsetof(struct tc_flower_key, ipv4.ipv4_dst),\n> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> +        8,\n> +        offsetof(struct tc_flower_key, ipv4.rewrite_ttl),\n> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n> +        8,\n> +        offsetof(struct tc_flower_key, ipv6.ipv6_src),\n> +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n> +        24,\n> +        offsetof(struct tc_flower_key, ipv6.ipv6_dst),\n> +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> +        6,\n> +        offsetof(struct tc_flower_key, src_mac),\n> +        MEMBER_SIZEOF(struct tc_flower_key, src_mac)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> +        0,\n> +        offsetof(struct tc_flower_key, dst_mac),\n> +        MEMBER_SIZEOF(struct tc_flower_key, dst_mac)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> +        12,\n> +        offsetof(struct tc_flower_key, eth_type),\n> +        MEMBER_SIZEOF(struct tc_flower_key, eth_type)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n> +        0,\n> +        offsetof(struct tc_flower_key, tcp_src),\n> +        MEMBER_SIZEOF(struct tc_flower_key, tcp_src)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n> +        2,\n> +        offsetof(struct tc_flower_key, tcp_dst),\n> +        MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n> +        0,\n> +        offsetof(struct tc_flower_key, udp_src),\n> +        MEMBER_SIZEOF(struct tc_flower_key, udp_src)\n> +    }, {\n> +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n> +        2,\n> +        offsetof(struct tc_flower_key, udp_dst),\n> +        MEMBER_SIZEOF(struct tc_flower_key, udp_dst)\n> +    },\n> +};\n> +\n>  struct tcmsg *\n>  tc_make_request(int ifindex, int type, unsigned int flags,\n>                  struct ofpbuf *request)\n> @@ -365,6 +446,96 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {\n>      }\n>  }\n>  \n> +static const struct nl_policy pedit_policy[] = {\n> +            [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,\n> +                                     .min_len = sizeof(struct tc_pedit),\n> +                                     .optional = false, },\n> +            [TCA_PEDIT_KEYS_EX]   = { .type = NL_A_NESTED,\n> +                                      .optional = false, },\n> +};\n> +\n> +static int\n> +nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)\n> +{\n> +    struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];\n> +    const struct tc_pedit *pe;\n> +    const struct tc_pedit_key *keys;\n> +    const struct nlattr *nla, *keys_ex, *ex_type;\n> +    const void *keys_attr;\n> +    char *rewrite_key = (void *) &flower->rewrite.key;\n> +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n> +    size_t keys_ex_size, left;\n> +    int type, i = 0;\n> +\n> +    if (!nl_parse_nested(options, pedit_policy, pe_attrs,\n> +                         ARRAY_SIZE(pedit_policy))) {\n> +        VLOG_ERR_RL(&error_rl, \"failed to parse pedit action options\");\n> +        return EPROTO;\n> +    }\n> +\n> +    pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);\n> +    keys = pe->keys;\n> +    keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];\n> +    keys_ex = nl_attr_get(keys_attr);\n> +    keys_ex_size = nl_attr_get_size(keys_attr);\n> +\n> +    NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {\n> +        if (i >= pe->nkeys) {\n> +            break;\n> +        }\n> +\n> +        if (nl_attr_type(nla) == TCA_PEDIT_KEY_EX) {\n> +            ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);\n> +            type = nl_attr_get_u16(ex_type);\n> +\n> +            for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {\n> +                struct flower_key_to_pedit *m = &flower_pedit_map[j];\n> +                int flower_off = m->flower_offset;\n> +                int sz = m->size;\n> +                int mf = m->offset;\n> +\n> +                if (m->htype != type) {\n> +                   continue;\n> +                }\n> +\n> +                /* check overlap between current pedit key, which is always\n> +                 * 4 bytes (range [off, off + 3]), and a map entry in\n> +                 * flower_pedit_map (range [mf, mf + sz - 1]) */\n> +                if ((keys->off >= mf && keys->off < mf + sz)\n> +                    || (keys->off + 3 >= mf && keys->off + 3 < mf + sz)) {\n> +                    int diff = flower_off + (keys->off - mf);\n> +                    uint32_t *dst = (void *) (rewrite_key + diff);\n> +                    uint32_t *dst_m = (void *) (rewrite_mask + diff);\n> +                    uint32_t mask = ~(keys->mask);\n> +                    uint32_t zero_bits;\n> +\n> +                    if (keys->off < mf) {\n> +                        zero_bits = 8 * (mf - keys->off);\n> +                        mask &= UINT32_MAX << zero_bits;\n> +                    } else if (keys->off + 4 > mf + m->size) {\n> +                        zero_bits = 8 * (keys->off + 4 - mf - m->size);\n> +                        mask &= UINT32_MAX >> zero_bits;\n> +                    }\n> +\n> +                    *dst_m |= mask;\n> +                    *dst |= keys->val & mask;\n> +                }\n> +            }\n\nIf I understand the above correctly it is designed to make\npedit actions disjoint. If so, why is that necessary?\n\n> +        } else {\n> +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n> +                        nl_attr_type(nla));\n> +            return EOPNOTSUPP;\n> +        }\n\nI think the code could exit early here as\nnl_msg_put_flower_rewrite_pedits() does below.\n\n\n> +\n> +        keys++;\n> +        i++;\n> +    }\n> +\n> +    flower->rewrite.rewrite = true;\n> +\n> +    return 0;\n> +}\n> +\n>  static const struct nl_policy tunnel_key_policy[] = {\n>      [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,\n>                                 .min_len = sizeof(struct tc_tunnel_key),\n> @@ -608,6 +779,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)\n>          nl_parse_act_vlan(act_options, flower);\n>      } else if (!strcmp(act_kind, \"tunnel_key\")) {\n>          nl_parse_act_tunnel_key(act_options, flower);\n> +    } else if (!strcmp(act_kind, \"pedit\")) {\n> +        nl_parse_act_pedit(act_options, flower);\n> +    } else if (!strcmp(act_kind, \"csum\")) {\n> +        /* not doing anything for now, ovs has an implicit csum recalculation\n> +         * with rewriting of packet headers (translating of pedit acts). */\n\nI wonder if the absence of a csum action when needed (by TC)\nshould be treated as an error.\n\n>      } else {\n>          VLOG_ERR_RL(&error_rl, \"unknown tc action kind: %s\", act_kind);\n>          return EINVAL;\n> @@ -809,6 +985,48 @@ tc_get_tc_cls_policy(enum tc_offload_policy policy)\n>  }\n>  \n>  static void\n> +nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags)\n> +{\n> +    size_t offset;\n> +\n> +    nl_msg_put_string(request, TCA_ACT_KIND, \"csum\");\n> +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n> +    {\n> +        struct tc_csum parm = { .action = TC_ACT_PIPE,\n> +                                .update_flags = flags };\n> +\n> +        nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);\n> +    }\n> +    nl_msg_end_nested(request, offset);\n> +}\n> +\n> +static void\n> +nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,\n> +                     struct tc_pedit_key_ex *ex)\n> +{\n> +    size_t ksize = sizeof *parm + (parm->nkeys * sizeof(struct tc_pedit_key));\n\nAre there unnecessary () on the line above?\n\n> +    size_t offset, offset_keys_ex, offset_key;\n> +    int i;\n> +\n> +    nl_msg_put_string(request, TCA_ACT_KIND, \"pedit\");\n> +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n> +    {\n> +        parm->action = TC_ACT_PIPE;\n> +\n> +        nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);\n> +        offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);\n> +        for (i = 0; i < parm->nkeys; i++, ex++) {\n> +            offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);\n> +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);\n> +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);\n> +            nl_msg_end_nested(request, offset_key);\n> +        }\n> +        nl_msg_end_nested(request, offset_keys_ex);\n> +    }\n> +    nl_msg_end_nested(request, offset);\n> +}\n> +\n> +static void\n>  nl_msg_put_act_push_vlan(struct ofpbuf *request, uint16_t vid, uint8_t prio)\n>  {\n>      size_t offset;\n> @@ -930,7 +1148,127 @@ nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {\n>      }\n>  }\n>  \n> +/* Given flower, a key_to_pedit map entry, calculates the rest,\n> + * where:\n> + *\n> + * mask, data - pointers of where read the first word of flower->key/mask.\n> + * current_offset - which offset to use for the first pedit action.\n> + * cnt - max pedits actions to use.\n> + * first_word_mask/last_word_mask - the mask to use for the first/last read\n> + * (as we read entire words). */\n>  static void\n> +calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m,\n> +             int *cur_offset, int *cnt, uint32_t *last_word_mask,\n> +             uint32_t *first_word_mask, uint32_t **mask, uint32_t **data)\n> +{\n> +    int start_offset, max_offset, total_size;\n> +    int diff, right_zero_bits, left_zero_bits;\n> +    char *rewrite_key = (void *) &flower->rewrite.key;\n> +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n> +\n> +    max_offset = m->offset + m->size;\n> +    start_offset = ROUND_DOWN(m->offset, 4);\n> +    diff = m->offset - start_offset;\n> +    total_size = max_offset - start_offset;\n> +    right_zero_bits = 8 * (4 - (max_offset % 4));\n> +    left_zero_bits = 8 * (m->offset - start_offset);\n> +\n> +    *cur_offset = start_offset;\n> +    *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);\n> +    *last_word_mask = UINT32_MAX >> right_zero_bits;\n> +    *first_word_mask = UINT32_MAX << left_zero_bits;\n> +    *data = (void *) (rewrite_key + m->flower_offset - diff);\n> +    *mask = (void *) (rewrite_mask + m->flower_offset - diff);\n\nThe type of *data and *mask is uint32_t *.\nWhy not cast to that type?\n\n> +}\n> +\n> +static inline void\n> +csum_update_flag(struct tc_flower *flower,\n> +                 enum pedit_header_type htype) {\n\nI think the above two lines could be one.\n\n> +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4) {\n\nA case statement might be nicer here.\n\n> +        flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;\n> +    }\n> +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4\n> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP6\n> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_TCP\n> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_UDP) {\n> +        if (flower->key.ip_proto == IPPROTO_TCP) {\n> +            flower->mask.ip_proto = UINT8_MAX;\n\nWhat if the mask was not UINT8_MAX to start with?\nDoesn't this create a different flow?\n\n> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;\n> +        } else if (flower->key.ip_proto == IPPROTO_UDP) {\n> +            flower->mask.ip_proto = UINT8_MAX;\n> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;\n> +        } else if (flower->key.ip_proto == IPPROTO_ICMP\n> +                   || flower->key.ip_proto == IPPROTO_ICMPV6) {\n> +            flower->mask.ip_proto = UINT8_MAX;\n> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;\n> +        }\n> +    }\n> +}\n> +\n> +static int\n> +nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,\n> +                                 struct tc_flower *flower)\n> +{\n> +    struct {\n> +        struct tc_pedit sel;\n> +        struct tc_pedit_key keys[MAX_PEDIT_OFFSETS];\n> +        struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];\n> +    } sel = {\n> +        .sel = {\n> +            .nkeys = 0\n> +        }\n> +    };\n> +    int i, j;\n> +\n> +    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {\n> +        struct flower_key_to_pedit *m = &flower_pedit_map[i];\n> +        struct tc_pedit_key *pedit_key = NULL;\n> +        struct tc_pedit_key_ex *pedit_key_ex = NULL;\n> +        uint32_t *mask, *data, first_word_mask, last_word_mask;\n> +        int cnt = 0, cur_offset = 0;\n> +\n> +        if (!m->size) {\n> +            continue;\n> +        }\n> +\n> +        calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask,\n> +                     &first_word_mask, &mask, &data);\n> +\n> +        for (j = 0; j < cnt; j++,  mask++, data++, cur_offset += 4) {\n> +            uint32_t mask_word = *mask;\n> +\n> +            if (j == 0) {\n> +                mask_word &= first_word_mask;\n> +            }\n> +            if (j == cnt - 1) {\n> +                mask_word &= last_word_mask;\n> +            }\n> +            if (!mask_word) {\n> +                continue;\n> +            }\n> +            if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {\n> +                VLOG_WARN_RL(&error_rl, \"reached too many pedit offsets: %d\",\n> +                             MAX_PEDIT_OFFSETS);\n> +                return EOPNOTSUPP;\n> +            }\n> +\n> +            pedit_key = &sel.keys[sel.sel.nkeys];\n> +            pedit_key_ex = &sel.keys_ex[sel.sel.nkeys];\n> +            pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;\n> +            pedit_key_ex->htype = m->htype;\n> +            pedit_key->off = cur_offset;\n> +            pedit_key->mask = ~mask_word;\n> +            pedit_key->val = *data & mask_word;\n> +            sel.sel.nkeys++;\n> +            csum_update_flag(flower, m->htype);\n> +        }\n> +    }\n> +    nl_msg_put_act_pedit(request, &sel.sel, sel.keys_ex);\n> +\n> +    return 0;\n> +}\n> +\n> +static int\n>  nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>  {\n>      size_t offset;\n> @@ -939,7 +1277,20 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>      offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);\n>      {\n>          uint16_t act_index = 1;\n> +        int error;\n>  \n> +        if (flower->rewrite.rewrite) {\n> +            act_offset = nl_msg_start_nested(request, act_index++);\n> +            error = nl_msg_put_flower_rewrite_pedits(request, flower);\n> +            if (error) {\n> +                return error;\n> +            }\n> +            nl_msg_end_nested(request, act_offset);\n> +\n> +            act_offset = nl_msg_start_nested(request, act_index++);\n> +            nl_msg_put_act_csum(request, flower->csum_update_flags);\n> +            nl_msg_end_nested(request, act_offset);\n> +        }\n>          if (flower->set.set) {\n>              act_offset = nl_msg_start_nested(request, act_index++);\n>              nl_msg_put_act_tunnel_key_set(request, flower->set.id,\n> @@ -980,6 +1331,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>          }\n>      }\n>      nl_msg_end_nested(request, offset);\n> +\n> +    return 0;\n>  }\n>  \n>  static void\n> @@ -1021,11 +1374,19 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)\n>      nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \\\n>                              &flower->mask.member, sizeof flower->key.member)\n>  \n> -static void\n> +static int\n>  nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n>  {\n> +\n>      uint16_t host_eth_type = ntohs(flower->key.eth_type);\n>      bool is_vlan = (host_eth_type == ETH_TYPE_VLAN);\n> +    int err;\n> +\n> +    /* need to parse acts first as some acts require changing the matching */\n\nThis seems strange to me.\n\n> +    err  = nl_msg_put_flower_acts(request, flower);\n> +    if (err) {\n> +        return err;\n> +    }\n>  \n>      if (is_vlan) {\n>          host_eth_type = ntohs(flower->key.encap_eth_type);\n> @@ -1083,7 +1444,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n>          nl_msg_put_flower_tunnel(request, flower);\n>      }\n>  \n> -    nl_msg_put_flower_acts(request, flower);\n> +    return 0;\n>  }\n>  \n>  int\n> @@ -1106,7 +1467,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n>      nl_msg_put_string(&request, TCA_KIND, \"flower\");\n>      basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);\n>      {\n> -        nl_msg_put_flower_options(&request, flower);\n> +        error = nl_msg_put_flower_options(&request, flower);\n> +\n> +        if (error) {\n> +            ofpbuf_uninit(&request);\n> +            return error;\n> +        }\n>      }\n>      nl_msg_end_nested(&request, basic_offset);\n>  \n> diff --git a/lib/tc.h b/lib/tc.h\n> index 6c69b79..7876051 100644\n> --- a/lib/tc.h\n> +++ b/lib/tc.h\n> @@ -96,6 +96,7 @@ struct tc_flower_key {\n>      struct {\n>          ovs_be32 ipv4_src;\n>          ovs_be32 ipv4_dst;\n> +        uint8_t rewrite_ttl;\n>      } ipv4;\n>      struct {\n>          struct in6_addr ipv6_src;\n> @@ -120,6 +121,14 @@ struct tc_flower {\n>      uint64_t lastused;\n>  \n>      struct {\n> +        bool rewrite;\n> +        struct tc_flower_key key;\n> +        struct tc_flower_key mask;\n> +    } rewrite;\n> +\n> +    uint32_t csum_update_flags;\n> +\n> +    struct {\n>          bool set;\n>          ovs_be64 id;\n>          ovs_be16 tp_src;\n> @@ -152,6 +161,13 @@ struct tc_flower {\n>      struct tc_cookie act_cookie;\n>  };\n>  \n> +/* assert that if we overflow with a masked write of uint32_t to the last byte\n> + * of flower.rewrite we overflow inside struct flower.\n> + * shouldn't happen unless someone moves rewrite to the end of flower */\n> +BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)\n> +                  + MEMBER_SIZEOF(struct tc_flower, rewrite)\n> +                  + sizeof(uint32_t) - 2 < sizeof(struct tc_flower));\n> +\n>  int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n>                        struct tc_flower *flower);\n>  int tc_del_filter(int ifindex, int prio, int handle);\n> -- \n> 2.7.5\n>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=netronome-com.20150623.gappssmtp.com\n\theader.i=@netronome-com.20150623.gappssmtp.com\n\theader.b=\"aCK7vl0E\"; dkim-atps=neutral"],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xwq2k6Qlsz9s4s\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 19 Sep 2017 01:01:18 +1000 (AEST)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id DFD98B6A;\n\tMon, 18 Sep 2017 15:01:14 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 91D41ACA\n\tfor <dev@openvswitch.org>; Mon, 18 Sep 2017 15:01:13 +0000 (UTC)","from mail-wr0-f181.google.com (mail-wr0-f181.google.com\n\t[209.85.128.181])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 10C50157\n\tfor <dev@openvswitch.org>; Mon, 18 Sep 2017 15:01:11 +0000 (UTC)","by mail-wr0-f181.google.com with SMTP id m18so753782wrm.2\n\tfor <dev@openvswitch.org>; Mon, 18 Sep 2017 08:01:11 -0700 (PDT)","from vergenet.net ([217.111.208.18])\n\tby smtp.gmail.com with ESMTPSA id\n\tu13sm6763068wre.11.2017.09.18.08.01.08\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tMon, 18 Sep 2017 08:01:09 -0700 (PDT)"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=netronome-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=MiDFqncZDJTQbINhGdpRIVQVT8DXObnHHD4Z+JOTpDQ=;\n\tb=aCK7vl0EGO6CPnTkqZOS6H0EashXaapzxI32cMkhO5EfHQOVNPXSUfgkD3Yte2EKzf\n\tW5IBUwdDPCu6ldL7a8THedTSaQKmFDnqj5pjCcwHBwwF0knQH/cXsBCws7cWfxL4nx8l\n\tmJ6YKJnNfYrZHAtKPOB94G3AipK9h5BQPhm2loq058GkOX/DlQ4sBtDZgUvuIovFs86s\n\taksqDh/xNTBnSWM5NfDflmMzY4EmQoU2+w79jAtYPFVeV7l/8hWFh9W+P7jEguhLz99G\n\t7v98b4sFloI2201+aKRCoPInVr6ITK8DnGiMjEPof2+XwDI/LUXmYHQpt4Q3cGpxMXx+\n\tYh6g==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=MiDFqncZDJTQbINhGdpRIVQVT8DXObnHHD4Z+JOTpDQ=;\n\tb=rKNwI6Q1Vp/RJI4pgzsQ0gGI8rr6Xb0pTpeaFaB7nGFdHzh3P6WtUlJmp/kPpmja/8\n\t0gePOLLHh957+Sdzy2U90g1bd/QOJDg1Lb/CsdF6mKYIDutPc+WA4daWDSZrWETUsSs/\n\tCZA/poENDoLvNxR1f3x5TMHy7mPI/uKYtQKNG4QYOXud5H1IJWjJezvxZfcWL9gqO+pS\n\tmo72xdQTvrxJpfg1MCmyR6CmJmU/vlh32gM9/8ZE8cld04NXIie2bwCXpsFWhT2LMQti\n\tBsY+lBvPcSqWjx84HFjJVUkqrLZ/C1vsNSlqDMhcT1wBwb3Nohnrw3Y6pNE4n77GYk6W\n\tA0bg==","X-Gm-Message-State":"AHPjjUhr/ZNIrnDKeH2gJN/KXDalWeCchpLiBTKAt1f8UW3LdjN1j/1l\n\tIkHy7c1B/0oyBhPNTfUE1g==","X-Google-Smtp-Source":"ADKCNb4BgP9khLEk1Tr6g00DaphluBZaRFZqyi6Zb1OFDnZBNgI9SxyYvVgPNjx0359KBEkko9zA7g==","X-Received":"by 10.223.173.204 with SMTP id\n\tw70mr30752210wrc.281.1505746870214; \n\tMon, 18 Sep 2017 08:01:10 -0700 (PDT)","Date":"Mon, 18 Sep 2017 17:01:09 +0200","From":"Simon Horman <simon.horman@netronome.com>","To":"Roi Dayan <roid@mellanox.com>","Message-ID":"<20170918150107.GD25154@vergenet.net>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<1505708164-10270-4-git-send-email-roid@mellanox.com>","User-Agent":"Mutt/1.5.23 (2014-03-12)","X-Spam-Status":"No, score=0.5 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tRCVD_IN_DNSWL_NONE,\n\tRCVD_IN_SORBS_SPAM autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1774735,"web_url":"http://patchwork.ozlabs.org/comment/1774735/","msgid":"<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>","list_archive_url":null,"date":"2017-09-25T13:31:42","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":70001,"url":"http://patchwork.ozlabs.org/api/people/70001/","name":"Paul Blakey","email":"paulb@mellanox.com"},"content":"On 18/09/2017 18:01, Simon Horman wrote:\n> On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n>> From: Paul Blakey <paulb@mellanox.com>\n>>\n>> To be later used to implement ovs action set offloading.\n>>\n>> Signed-off-by: Paul Blakey <paulb@mellanox.com>\n>> Reviewed-by: Roi Dayan <roid@mellanox.com>\n>> ---\n>>   lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n>>   lib/tc.h |  16 +++\n>>   2 files changed, 385 insertions(+), 3 deletions(-)\n>>\n>> diff --git a/lib/tc.c b/lib/tc.c\n>> index c9cada2..743b2ee 100644\n>> --- a/lib/tc.c\n>> +++ b/lib/tc.c\n>> @@ -21,8 +21,10 @@\n>>   #include <errno.h>\n>>   #include <linux/if_ether.h>\n>>   #include <linux/rtnetlink.h>\n>> +#include <linux/tc_act/tc_csum.h>\n>>   #include <linux/tc_act/tc_gact.h>\n>>   #include <linux/tc_act/tc_mirred.h>\n>> +#include <linux/tc_act/tc_pedit.h>\n>>   #include <linux/tc_act/tc_tunnel_key.h>\n>>   #include <linux/tc_act/tc_vlan.h>\n>>   #include <linux/gen_stats.h>\n>> @@ -33,11 +35,14 @@\n>>   #include \"netlink-socket.h\"\n>>   #include \"netlink.h\"\n>>   #include \"openvswitch/ofpbuf.h\"\n>> +#include \"openvswitch/util.h\"\n>>   #include \"openvswitch/vlog.h\"\n>>   #include \"packets.h\"\n>>   #include \"timeval.h\"\n>>   #include \"unaligned.h\"\n>>   \n>> +#define MAX_PEDIT_OFFSETS 8\n> \n> Why 8?\nWe don't expect anything more right now (ipv6 src/dst rewrite requires 8 \npedits iirc). I can't think of a larger use case, maybe ipv6 + macs if \nthat's makes sens. do you suggest we increase it? to what?\n\n> \n>> +\n>>   VLOG_DEFINE_THIS_MODULE(tc);\n>>   \n>>   static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);\n>> @@ -50,6 +55,82 @@ enum tc_offload_policy {\n>>   \n>>   static enum tc_offload_policy tc_policy = TC_POLICY_NONE;\n>>   \n>> +struct tc_pedit_key_ex {\n>> +    enum pedit_header_type htype;\n>> +    enum pedit_cmd cmd;\n>> +};\n>> +\n>> +struct flower_key_to_pedit {\n>> +    enum pedit_header_type htype;\n>> +    int flower_offset;\n>> +    int offset;\n>> +    int size;\n>> +};\n>> +\n>> +static struct flower_key_to_pedit flower_pedit_map[] = {\n>> +    {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>> +        12,\n>> +        offsetof(struct tc_flower_key, ipv4.ipv4_src),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>> +        16,\n>> +        offsetof(struct tc_flower_key, ipv4.ipv4_dst),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>> +        8,\n>> +        offsetof(struct tc_flower_key, ipv4.rewrite_ttl),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n>> +        8,\n>> +        offsetof(struct tc_flower_key, ipv6.ipv6_src),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n>> +        24,\n>> +        offsetof(struct tc_flower_key, ipv6.ipv6_dst),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>> +        6,\n>> +        offsetof(struct tc_flower_key, src_mac),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, src_mac)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>> +        0,\n>> +        offsetof(struct tc_flower_key, dst_mac),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, dst_mac)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>> +        12,\n>> +        offsetof(struct tc_flower_key, eth_type),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, eth_type)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n>> +        0,\n>> +        offsetof(struct tc_flower_key, tcp_src),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, tcp_src)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n>> +        2,\n>> +        offsetof(struct tc_flower_key, tcp_dst),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n>> +        0,\n>> +        offsetof(struct tc_flower_key, udp_src),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, udp_src)\n>> +    }, {\n>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n>> +        2,\n>> +        offsetof(struct tc_flower_key, udp_dst),\n>> +        MEMBER_SIZEOF(struct tc_flower_key, udp_dst)\n>> +    },\n>> +};\n>> +\n>>   struct tcmsg *\n>>   tc_make_request(int ifindex, int type, unsigned int flags,\n>>                   struct ofpbuf *request)\n>> @@ -365,6 +446,96 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {\n>>       }\n>>   }\n>>   \n>> +static const struct nl_policy pedit_policy[] = {\n>> +            [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,\n>> +                                     .min_len = sizeof(struct tc_pedit),\n>> +                                     .optional = false, },\n>> +            [TCA_PEDIT_KEYS_EX]   = { .type = NL_A_NESTED,\n>> +                                      .optional = false, },\n>> +};\n>> +\n>> +static int\n>> +nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)\n>> +{\n>> +    struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];\n>> +    const struct tc_pedit *pe;\n>> +    const struct tc_pedit_key *keys;\n>> +    const struct nlattr *nla, *keys_ex, *ex_type;\n>> +    const void *keys_attr;\n>> +    char *rewrite_key = (void *) &flower->rewrite.key;\n>> +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n>> +    size_t keys_ex_size, left;\n>> +    int type, i = 0;\n>> +\n>> +    if (!nl_parse_nested(options, pedit_policy, pe_attrs,\n>> +                         ARRAY_SIZE(pedit_policy))) {\n>> +        VLOG_ERR_RL(&error_rl, \"failed to parse pedit action options\");\n>> +        return EPROTO;\n>> +    }\n>> +\n>> +    pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);\n>> +    keys = pe->keys;\n>> +    keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];\n>> +    keys_ex = nl_attr_get(keys_attr);\n>> +    keys_ex_size = nl_attr_get_size(keys_attr);\n>> +\n>> +    NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {\n>> +        if (i >= pe->nkeys) {\n>> +            break;\n>> +        }\n>> +\n>> +        if (nl_attr_type(nla) == TCA_PEDIT_KEY_EX) {\n>> +            ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);\n>> +            type = nl_attr_get_u16(ex_type);\n>> +\n>> +            for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {\n>> +                struct flower_key_to_pedit *m = &flower_pedit_map[j];\n>> +                int flower_off = m->flower_offset;\n>> +                int sz = m->size;\n>> +                int mf = m->offset;\n>> +\n>> +                if (m->htype != type) {\n>> +                   continue;\n>> +                }\n>> +\n>> +                /* check overlap between current pedit key, which is always\n>> +                 * 4 bytes (range [off, off + 3]), and a map entry in\n>> +                 * flower_pedit_map (range [mf, mf + sz - 1]) */\n>> +                if ((keys->off >= mf && keys->off < mf + sz)\n>> +                    || (keys->off + 3 >= mf && keys->off + 3 < mf + sz)) {\n>> +                    int diff = flower_off + (keys->off - mf);\n>> +                    uint32_t *dst = (void *) (rewrite_key + diff);\n>> +                    uint32_t *dst_m = (void *) (rewrite_mask + diff);\n>> +                    uint32_t mask = ~(keys->mask);\n>> +                    uint32_t zero_bits;\n>> +\n>> +                    if (keys->off < mf) {\n>> +                        zero_bits = 8 * (mf - keys->off);\n>> +                        mask &= UINT32_MAX << zero_bits;\n>> +                    } else if (keys->off + 4 > mf + m->size) {\n>> +                        zero_bits = 8 * (keys->off + 4 - mf - m->size);\n>> +                        mask &= UINT32_MAX >> zero_bits;\n>> +                    }\n>> +\n>> +                    *dst_m |= mask;\n>> +                    *dst |= keys->val & mask;\n>> +                }\n>> +            }\n> \n> If I understand the above correctly it is designed to make\n> pedit actions disjoint. If so, why is that necessary? >\n\nIt's not, as a single flower key rewrite can be split to multiple pedit \nactions it finds the overlap between a flower key and a pedit action, \nif they do overlap it translates it to the correct offset and masks it out.\n\n>> +        } else {\n>> +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n>> +                        nl_attr_type(nla));\n>> +            return EOPNOTSUPP;\n>> +        }\n> \n> I think the code could exit early here as\n> nl_msg_put_flower_rewrite_pedits() does below.\n> \n\nSorry, didn't understand. can you give an example?\n\n> \n>> +\n>> +        keys++;\n>> +        i++;\n>> +    }\n>> +\n>> +    flower->rewrite.rewrite = true;\n>> +\n>> +    return 0;\n>> +}\n>> +\n>>   static const struct nl_policy tunnel_key_policy[] = {\n>>       [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,\n>>                                  .min_len = sizeof(struct tc_tunnel_key),\n>> @@ -608,6 +779,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)\n>>           nl_parse_act_vlan(act_options, flower);\n>>       } else if (!strcmp(act_kind, \"tunnel_key\")) {\n>>           nl_parse_act_tunnel_key(act_options, flower);\n>> +    } else if (!strcmp(act_kind, \"pedit\")) {\n>> +        nl_parse_act_pedit(act_options, flower);\n>> +    } else if (!strcmp(act_kind, \"csum\")) {\n>> +        /* not doing anything for now, ovs has an implicit csum recalculation\n>> +         * with rewriting of packet headers (translating of pedit acts). */\n> \n> I wonder if the absence of a csum action when needed (by TC)\n> should be treated as an error >\n\nDo you mean validating csum flags from each protocol and such (like in put)?\n\n>>       } else {\n>>           VLOG_ERR_RL(&error_rl, \"unknown tc action kind: %s\", act_kind);\n>>           return EINVAL;\n>> @@ -809,6 +985,48 @@ tc_get_tc_cls_policy(enum tc_offload_policy policy)\n>>   }\n>>   \n>>   static void\n>> +nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags)\n>> +{\n>> +    size_t offset;\n>> +\n>> +    nl_msg_put_string(request, TCA_ACT_KIND, \"csum\");\n>> +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n>> +    {\n>> +        struct tc_csum parm = { .action = TC_ACT_PIPE,\n>> +                                .update_flags = flags };\n>> +\n>> +        nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);\n>> +    }\n>> +    nl_msg_end_nested(request, offset);\n>> +}\n>> +\n>> +static void\n>> +nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,\n>> +                     struct tc_pedit_key_ex *ex)\n>> +{\n>> +    size_t ksize = sizeof *parm + (parm->nkeys * sizeof(struct tc_pedit_key));\n> \n> Are there unnecessary () on the line above?\nNo, I'll remove them.\n\n> \n>> +    size_t offset, offset_keys_ex, offset_key;\n>> +    int i;\n>> +\n>> +    nl_msg_put_string(request, TCA_ACT_KIND, \"pedit\");\n>> +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n>> +    {\n>> +        parm->action = TC_ACT_PIPE;\n>> +\n>> +        nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);\n>> +        offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);\n>> +        for (i = 0; i < parm->nkeys; i++, ex++) {\n>> +            offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);\n>> +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);\n>> +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);\n>> +            nl_msg_end_nested(request, offset_key);\n>> +        }\n>> +        nl_msg_end_nested(request, offset_keys_ex);\n>> +    }\n>> +    nl_msg_end_nested(request, offset);\n>> +}\n>> +\n>> +static void\n>>   nl_msg_put_act_push_vlan(struct ofpbuf *request, uint16_t vid, uint8_t prio)\n>>   {\n>>       size_t offset;\n>> @@ -930,7 +1148,127 @@ nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {\n>>       }\n>>   }\n>>   \n>> +/* Given flower, a key_to_pedit map entry, calculates the rest,\n>> + * where:\n>> + *\n>> + * mask, data - pointers of where read the first word of flower->key/mask.\n>> + * current_offset - which offset to use for the first pedit action.\n>> + * cnt - max pedits actions to use.\n>> + * first_word_mask/last_word_mask - the mask to use for the first/last read\n>> + * (as we read entire words). */\n>>   static void\n>> +calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m,\n>> +             int *cur_offset, int *cnt, uint32_t *last_word_mask,\n>> +             uint32_t *first_word_mask, uint32_t **mask, uint32_t **data)\n>> +{\n>> +    int start_offset, max_offset, total_size;\n>> +    int diff, right_zero_bits, left_zero_bits;\n>> +    char *rewrite_key = (void *) &flower->rewrite.key;\n>> +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n>> +\n>> +    max_offset = m->offset + m->size;\n>> +    start_offset = ROUND_DOWN(m->offset, 4);\n>> +    diff = m->offset - start_offset;\n>> +    total_size = max_offset - start_offset;\n>> +    right_zero_bits = 8 * (4 - (max_offset % 4));\n>> +    left_zero_bits = 8 * (m->offset - start_offset);\n>> +\n>> +    *cur_offset = start_offset;\n>> +    *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);\n>> +    *last_word_mask = UINT32_MAX >> right_zero_bits;\n>> +    *first_word_mask = UINT32_MAX << left_zero_bits;\n>> +    *data = (void *) (rewrite_key + m->flower_offset - diff);\n>> +    *mask = (void *) (rewrite_mask + m->flower_offset - diff);\n> \n> The type of *data and *mask is uint32_t *.\n> Why not cast to that type?\n\nIt's to avoid warning of increasing pointer alignment (-Wcast-align).\n\n> \n>> +}\n>> +\n>> +static inline void\n>> +csum_update_flag(struct tc_flower *flower,\n>> +                 enum pedit_header_type htype) {\n> \n> I think the above two lines could be one.\n> \n>> +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4) {\n> \n> A case statement might be nicer here.\n\nRight, thanks.\n\n> \n>> +        flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;\n>> +    }\n>> +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4\n>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP6\n>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_TCP\n>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_UDP) {\n>> +        if (flower->key.ip_proto == IPPROTO_TCP) {\n>> +            flower->mask.ip_proto = UINT8_MAX;\n> \n> What if the mask was not UINT8_MAX to start with?\n> Doesn't this create a different flow?\n\nThis is so the checksum will be strict (not setting/recalc udp checksum \non non udp packets). It creates a more specific flow, a subset of the \noriginal. This is fine as datapath is free to ignore a mask, which is \nthe same as a full mask we've set.\n\n> \n>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;\n>> +        } else if (flower->key.ip_proto == IPPROTO_UDP) {\n>> +            flower->mask.ip_proto = UINT8_MAX;\n>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;\n>> +        } else if (flower->key.ip_proto == IPPROTO_ICMP\n>> +                   || flower->key.ip_proto == IPPROTO_ICMPV6) {\n>> +            flower->mask.ip_proto = UINT8_MAX;\n>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;\n>> +        }\n>> +    }\n>> +}\n>> +\n>> +static int\n>> +nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,\n>> +                                 struct tc_flower *flower)\n>> +{\n>> +    struct {\n>> +        struct tc_pedit sel;\n>> +        struct tc_pedit_key keys[MAX_PEDIT_OFFSETS];\n>> +        struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];\n>> +    } sel = {\n>> +        .sel = {\n>> +            .nkeys = 0\n>> +        }\n>> +    };\n>> +    int i, j;\n>> +\n>> +    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {\n>> +        struct flower_key_to_pedit *m = &flower_pedit_map[i];\n>> +        struct tc_pedit_key *pedit_key = NULL;\n>> +        struct tc_pedit_key_ex *pedit_key_ex = NULL;\n>> +        uint32_t *mask, *data, first_word_mask, last_word_mask;\n>> +        int cnt = 0, cur_offset = 0;\n>> +\n>> +        if (!m->size) {\n>> +            continue;\n>> +        }\n>> +\n>> +        calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask,\n>> +                     &first_word_mask, &mask, &data);\n>> +\n>> +        for (j = 0; j < cnt; j++,  mask++, data++, cur_offset += 4) {\n>> +            uint32_t mask_word = *mask;\n>> +\n>> +            if (j == 0) {\n>> +                mask_word &= first_word_mask;\n>> +            }\n>> +            if (j == cnt - 1) {\n>> +                mask_word &= last_word_mask;\n>> +            }\n>> +            if (!mask_word) {\n>> +                continue;\n>> +            }\n>> +            if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {\n>> +                VLOG_WARN_RL(&error_rl, \"reached too many pedit offsets: %d\",\n>> +                             MAX_PEDIT_OFFSETS);\n>> +                return EOPNOTSUPP;\n>> +            }\n>> +\n>> +            pedit_key = &sel.keys[sel.sel.nkeys];\n>> +            pedit_key_ex = &sel.keys_ex[sel.sel.nkeys];\n>> +            pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;\n>> +            pedit_key_ex->htype = m->htype;\n>> +            pedit_key->off = cur_offset;\n>> +            pedit_key->mask = ~mask_word;\n>> +            pedit_key->val = *data & mask_word;\n>> +            sel.sel.nkeys++;\n>> +            csum_update_flag(flower, m->htype);\n>> +        }\n>> +    }\n>> +    nl_msg_put_act_pedit(request, &sel.sel, sel.keys_ex);\n>> +\n>> +    return 0;\n>> +}\n>> +\n>> +static int\n>>   nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>   {\n>>       size_t offset;\n>> @@ -939,7 +1277,20 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>       offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);\n>>       {\n>>           uint16_t act_index = 1;\n>> +        int error;\n>>   \n>> +        if (flower->rewrite.rewrite) {\n>> +            act_offset = nl_msg_start_nested(request, act_index++);\n>> +            error = nl_msg_put_flower_rewrite_pedits(request, flower);\n>> +            if (error) {\n>> +                return error;\n>> +            }\n>> +            nl_msg_end_nested(request, act_offset);\n>> +\n>> +            act_offset = nl_msg_start_nested(request, act_index++);\n>> +            nl_msg_put_act_csum(request, flower->csum_update_flags);\n>> +            nl_msg_end_nested(request, act_offset);\n>> +        }\n>>           if (flower->set.set) {\n>>               act_offset = nl_msg_start_nested(request, act_index++);\n>>               nl_msg_put_act_tunnel_key_set(request, flower->set.id,\n>> @@ -980,6 +1331,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>           }\n>>       }\n>>       nl_msg_end_nested(request, offset);\n>> +\n>> +    return 0;\n>>   }\n>>   \n>>   static void\n>> @@ -1021,11 +1374,19 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)\n>>       nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \\\n>>                               &flower->mask.member, sizeof flower->key.member)\n>>   \n>> -static void\n>> +static int\n>>   nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n>>   {\n>> +\n>>       uint16_t host_eth_type = ntohs(flower->key.eth_type);\n>>       bool is_vlan = (host_eth_type == ETH_TYPE_VLAN);\n>> +    int err;\n>> +\n>> +    /* need to parse acts first as some acts require changing the matching */\n> \n> This seems strange to me.\n\nfrom the strict (normalized?) header checksum.\n\n> \n>> +    err  = nl_msg_put_flower_acts(request, flower);\n>> +    if (err) {\n>> +        return err;\n>> +    }\n>>   \n>>       if (is_vlan) {\n>>           host_eth_type = ntohs(flower->key.encap_eth_type);\n>> @@ -1083,7 +1444,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n>>           nl_msg_put_flower_tunnel(request, flower);\n>>       }\n>>   \n>> -    nl_msg_put_flower_acts(request, flower);\n>> +    return 0;\n>>   }\n>>   \n>>   int\n>> @@ -1106,7 +1467,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n>>       nl_msg_put_string(&request, TCA_KIND, \"flower\");\n>>       basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);\n>>       {\n>> -        nl_msg_put_flower_options(&request, flower);\n>> +        error = nl_msg_put_flower_options(&request, flower);\n>> +\n>> +        if (error) {\n>> +            ofpbuf_uninit(&request);\n>> +            return error;\n>> +        }\n>>       }\n>>       nl_msg_end_nested(&request, basic_offset);\n>>   \n>> diff --git a/lib/tc.h b/lib/tc.h\n>> index 6c69b79..7876051 100644\n>> --- a/lib/tc.h\n>> +++ b/lib/tc.h\n>> @@ -96,6 +96,7 @@ struct tc_flower_key {\n>>       struct {\n>>           ovs_be32 ipv4_src;\n>>           ovs_be32 ipv4_dst;\n>> +        uint8_t rewrite_ttl;\n>>       } ipv4;\n>>       struct {\n>>           struct in6_addr ipv6_src;\n>> @@ -120,6 +121,14 @@ struct tc_flower {\n>>       uint64_t lastused;\n>>   \n>>       struct {\n>> +        bool rewrite;\n>> +        struct tc_flower_key key;\n>> +        struct tc_flower_key mask;\n>> +    } rewrite;\n>> +\n>> +    uint32_t csum_update_flags;\n>> +\n>> +    struct {\n>>           bool set;\n>>           ovs_be64 id;\n>>           ovs_be16 tp_src;\n>> @@ -152,6 +161,13 @@ struct tc_flower {\n>>       struct tc_cookie act_cookie;\n>>   };\n>>   \n>> +/* assert that if we overflow with a masked write of uint32_t to the last byte\n>> + * of flower.rewrite we overflow inside struct flower.\n>> + * shouldn't happen unless someone moves rewrite to the end of flower */\n>> +BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)\n>> +                  + MEMBER_SIZEOF(struct tc_flower, rewrite)\n>> +                  + sizeof(uint32_t) - 2 < sizeof(struct tc_flower));\n>> +\n>>   int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n>>                         struct tc_flower *flower);\n>>   int tc_del_filter(int ifindex, int prio, int handle);\n>> -- \n>> 2.7.5\n>>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=Mellanox.com header.i=@Mellanox.com\n\theader.b=\"NWYA4Zd+\"; dkim-atps=neutral","spf=none (sender IP is )\n\tsmtp.mailfrom=paulb@mellanox.com; "],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y14kW2h0Dz9t5c\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 25 Sep 2017 23:32:01 +1000 (AEST)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 7DFC1B14;\n\tMon, 25 Sep 2017 13:31:58 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id CB02DAF4\n\tfor <dev@openvswitch.org>; Mon, 25 Sep 2017 13:31:56 +0000 (UTC)","from EUR01-HE1-obe.outbound.protection.outlook.com\n\t(mail-he1eur01on0084.outbound.protection.outlook.com [104.47.0.84])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id DA0AC204\n\tfor <dev@openvswitch.org>; Mon, 25 Sep 2017 13:31:54 +0000 (UTC)","from [10.223.3.152] (193.47.165.251) by\n\tDB5PR05MB1640.eurprd05.prod.outlook.com (2a01:111:e400:5bb3::14) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.77.7;\n\tMon, 25 Sep 2017 13:31:49 +0000"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com;\n\ts=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version;\n\tbh=OXflXynMTzZFTSjBFiysF3Y70MU6FCvaNqx5jjeTpE8=;\n\tb=NWYA4Zd+mYU2Qe1feHExFqJq8XSQXyXwz6M4cFaD0PLzRw/9XXefiLVx1HsgPt1o/6i7wcSsYPKhrK7QF3vyGI1PfMvlUocOEG4vuUSJz4b5j9CUaOJFeIv4RVivXieBKCiGmmfbp4sqMlBOidHTMx7gCiBXmAlgPAD8RFnieUI=","To":"Simon Horman <simon.horman@netronome.com>, Roi Dayan <roid@mellanox.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>","From":"Paul Blakey <paulb@mellanox.com>","Message-ID":"<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>","Date":"Mon, 25 Sep 2017 16:31:42 +0300","User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101\n\tThunderbird/52.3.0","MIME-Version":"1.0","In-Reply-To":"<20170918150107.GD25154@vergenet.net>","Content-Language":"en-US","X-Originating-IP":"[193.47.165.251]","X-ClientProxiedBy":"AM5PR0601CA0046.eurprd06.prod.outlook.com\n\t(2603:10a6:203:68::32) To DB5PR05MB1640.eurprd05.prod.outlook.com\n\t(2a01:111:e400:5bb3::14)","X-MS-PublicTrafficType":"Email","X-MS-Office365-Filtering-Correlation-Id":"4992f83b-45b7-44bc-3c36-08d50419c6ed","X-MS-Office365-Filtering-HT":"Tenant","X-Microsoft-Antispam":"UriScan:; BCL:0; PCL:0;\n\tRULEID:(22001)(2017030254152)(48565401081)(2017052603199)(201703131423075)(201703031133081)(201702281549075);\n\tSRVR:DB5PR05MB1640; ","X-Microsoft-Exchange-Diagnostics":["1; DB5PR05MB1640;\n\t3:JaC/GvYgbVwfjbTdhdoqJMGPNUlEUU/4gmU6DMWPN+oHzSHnS2De9rM7k5+ck9ghjXlBWMRP/Sp23QWgjcW4EqjB+6Y2MPZyux5GbIvz54cIB0ecz3fGdej9E7JQ5dP+NKmWr+aRYKN/QtV33S4FEn0owk6gPVyYxJeWcI6pcxzKVjsLL/UcYdlRdLKgrjDemhTVxwR3tApvYNFDkKoacFvmQdKgy5QfA2jNlhJPv9ORpEvr3Ddvvhr5V5a+12fu;\n\t25:KF0KPQmzMYI8Xqu/41OUCUMjngL5gFKJKzXjKdI6/s587wZSLzps6lzAqOvtVnqjyvtzjiYtuzYwAumBjLOYmaJa+mJx0JdceBnPWe3N6/7Qt0Xsoonlk5JvpMeqH5rH09SgjkIcDalZ3mQ66uM7KDRcv1QAd0aa10AnNFcdDOEHJ79wAwBCFA8SY9MDN0p3q56k6DO+jZfKfPxv+x5GWSiz3+itT6TWaj9OsTIEm9uSre0Pf+8obEHqrBaKRBpTzdIfUHnLp5IoO3XMzOL1DWqzb8hlxt6nB//W9PHURB/yE9Dj4oCgUYEN/1v9k8OPEzNyA0xdIbo82igXMxkYKw==;\n\t31:gVfz9wBm0s0+xvpnq3EOkvCrk6gKeGvgCrzy84LDJ1puYU+XQ33gsFqVfJFTWjTtNu78hE4FWgvNWlgrbCMHBtPub5292uCow0LcSZIw3OvmL8MZP6brwGc2FkHV0kbbrBpYv8F2XifIH9mdCvDbgoPpJzfbda4J8VG59eN2MJWtP5fcySMew+bJjpFeVFva04x93Aq9E0Pig8EsOB1RKxGbw1Muw0FPwr9WzlykK5M=","1; DB5PR05MB1640;\n\t20:oO/VcZrV4ySUEht9Ipe+u5dHJ15wEwMvC2HTYhuBnhU5eqW2ee1Kc7AL5TTlM+npdFOEvEuQh+Dt0mFRe4zhdKo32UadVH+R+6oLEfkD4oLqaUL7xUlb/rMPahuYEGjJPN7U8XQ+lC4znTi73dny5lNbEym+AcD0EmRuFRtlO3oXI4iVO6zXsl6dk/kPVC4mP34no8/v80Noruu4V9ipRioYUf+pqKkrI78wrx9Dxp+0c7EEJ1Rn2z9yu6NE7fV/QEumS0Wz9BQ2H2nXM4XRShDzsLPkEcz8fev49Gy9uSwlu9sYL2iv9QZH1NiCp+cd99wQSQGR9TfXQo11kqGUQLJpH2vdMImKKn4UD43uDFEFv0DYZJIf+xOS60hnTD0dSw8/YNuyI2ef2xrp5HeLtEYcH9i+g5iLWY2cl42i9oaq/E3hTyuHzoQxkgrrrz5870sap0sYxLzYl1koPj99QtyoMcveoBGURHt+DDiFP0Spq1uFthf72QEWuf+RYrs5;\n\t4:ugwfevi+tnDno2P9tgnhLcHJSPKgLIKrk0THE9ocm2W+9kQ7MAiMCIs6NOJR9M3vFBPi6YF1yqIJWeRHc+p+Lh2yBXRO2ZqtzN/LO29EYAnbFx3A1cowIAXKsMjwGANRyJPU+BBc1JoLVi0vnM1eEcpcJZ1Yp37xk2RUcO3eBE2FwLzE5sKoMvSVyE8JnKMHeg3+Qz8YNaAzNBVIcztxFcsiaTtpffcm5X2i5kvlnbfHS0Vt4dihjrK6K0XD0wjLcx5Dd9LAjkDtCcTEpL9kI13Pp44TttKsA4eRJCte/1E=","=?windows-1255?Q?1; DB5PR05MB1640;\n\t23:SD5AYD6ZcO4AQdXtbyD6PelZkwCr2UPfs9ZKp?=\n\t=?cp1255?q?GMdoRvwyRLI/axXKm7iORW+1kv7Fo?=\n\t=?cp1255?q?UiwpkjusolvaID/RJ8tzNwiJYRMzOafITgjYdr8SxVufClLQ1+H6pgJ?=\n\t=?cp1255?q?2VXvq12BXCNmKGYX81kEAXOX+tUj3/JTTRzSgb8cDyfygUFWIKXdJcI?=\n\t=?cp1255?q?DN1olFxcjQ8yc2jCpIiDyI/CH2TPXYKq8qct83BfVx5rqM/xLEB//g3?=\n\t=?cp1255?q?AHR0yHpvKxThhckNdiA6dDuTArbwrNUz8dtqT93Lisykjv0KXFsUBDY?=\n\t=?cp1255?q?yG6gQBJLTAz87LYU7B8KHd6+QOrHfzzdShDHNVuFB+HJDDldOLDT9Hk?=\n\t=?cp1255?q?9EMuhzb+tEPSlVfgzm3sJLReZOrMEEKeembW+krJNjTLkameE+t36c+?=\n\t=?cp1255?q?eGfpZ+TAp7zjqn+UxrPP01Pp/jHkphhLBSB1aTEQCbP/E7rzw5QnQtE?=\n\t=?cp1255?q?0y3tn8CN249CiZjK4sRw7qdIyA3ZGiwzpt0CXsGcP3z+DIAS5rBubAD?=\n\t=?cp1255?q?QhDW3yfQZVIgAChpKonSehrNjEQ1CVqR2g4xMJQ+Rl7U1B9kNi47Snc?=\n\t=?cp1255?q?hNq/mmMZ4TOGYcMCSl1xYM/bFVkjJ9CriqFia5XVDUPPQDPGDN3TIby?=\n\t=?cp1255?q?PnHiy7wK9eBNgYHC5CR51XpRXmojfVbbS1ibrJnYJ5WWxA9HNuNWqmh?=\n\t=?cp1255?q?KS/baV2HhFVA+1bEum6FT2Gz8zI2WtdcDD8pJgNdQcb1kDDl+ljJhGx?=\n\t=?cp1255?q?uNvErqZsg3bZqqGWw1z8iHi2RJgKrrcuatc0q+3STDvY0OWK4MQGZLz?=\n\t=?cp1255?q?bDyOHZaLl9lJufSlSTXraGaHWHc5jrX8WttLhnb4teAUg4PTi3o3hP9?=\n\t=?cp1255?q?Lh3Fn71NYtGXEaD8NqDL74hy0L9l2GL53/3vIJbFeJ0/0/0KG23QaOS?=\n\t=?cp1255?q?CamTabSM7uUPs7+jXaD1dIsbfxtwOLeyDTLBi4WdszLD+jOuAFfxFyF?=\n\t=?cp1255?q?YH/WAQFxTS519jA1tN7KK/I8rzXBGkdW5OM3SqGkeWndXZyuWklw93Y?=\n\t=?cp1255?q?1RORIEtNbbklhcy3uJruLXkp/V2+gH5aly7ywJYK/vPpY4Jzk2lO0Kz?=\n\t=?cp1255?q?wBj1q7PyCS7QqyFP6LlWeUAe9Dw1Nj906uz7e4TLYSWEP9wf0YxDb2D?=\n\t=?cp1255?q?5nbC4b5EVdJ/l2TSfnSDnID3j1EMOsb3Verq7WthsM79e53d3whQ6xq?=\n\t=?cp1255?q?Xnen+dwZwoAiz/mxdNYXbXnmC7UnWyuZh1HWJgw+ke45rEed7BZlCEe?=\n\t=?cp1255?q?dm3Ce688BECrDT/KEa/MmGzCi9cl5ziO42VJIm09XHmonxCSd3KpZVC?=\n\t=?cp1255?q?lOijYInkSj1RBr1HdW1HNerbfQY2NDpgp6OPUCK5JQuBr4jLLJW+bv7?=\n\t=?cp1255?q?JFJOchx178lphtl8+SlrEprelNb5bb2oH+EkJS+JTmm/fdYEYO12o7h?=\n\t=?cp1255?q?eG5XKWpVPiIo4EBzG9XPhOYg1I8xNtivruFhKAxUd5Ew=3D=3D?=","1; DB5PR05MB1640;\n\t6:LnR9G3KJLIi7xfBKOu6ef4qurg00J8D6hPs3IknBPpEcnhu4n5Jd/NVf1nmvW1f++1g1tQBC+laK4+ZUUXO+cxG5Ffi+FvwyClPeCTf0inejDtrFpXtPatOkS36sk9Rz/7fmFepSIBAGtmn0HRKBZjbU1uQhGlGYKGanA7X1BhkizIj00riyaUWEnLUOj1dIO8aZx+71QFlEFU2ndaT+uauw+gAXK3niwu0Wn1UJLNI/qXLa6Mhg0vwGoElvnhzBMmY2Dx8XSyYQpgEx6/cakj7je3inOcW8WDFgo476+O3SkQmN7u0dXDslJ15+umFYQs6EYYI89poMvdDOgsRsUg==;\n\t5:+wFCSqT8CMN97wdOq1X8ZsgTVX2oCjIvrdD85KZZ4vH5ouyOnIuXd9rDpPlH58BgEd6twIe/3SnMibvMs/KYNS/P08MfrBpOwz0i8BkGfL21JDJeBxsogzFjHDPN6hL4dFpEujAGjS4a9jXR9f8BdQ==;\n\t24:ffdcoqlUt7czHVzTYHZYrL4ncgMRQCDvDJLx8s7PM2lVV9aHsjuiQqoiB5XwQBbW63oQyk7rMRbqocN4aeJKFnmgDC5UJKMDg9oK/Lzu4jc=;\n\t7:qvU/e9MFNJkD9SISFUbJ1QyFnaVFheSpLXhs0GOa1X5hrNiSGduVdzaURLOEYNy6HQQEEFqZsYpH3XoQPKSyydxY2vBwCC8OmSBFnWbNe0aR5wN8lFRhfINGpC2rc4lzH9daY4EKvRFa7HWA9kafUrNjYx2lshVqJB5dZYKDl6/NcDoYqmRhMaV4h1Oy/6LNxDj5ZpQuLHuQ5i78yYxCmcmTieQJjDUf3pNjNJw+elc="],"X-MS-TrafficTypeDiagnostic":"DB5PR05MB1640:","X-Exchange-Antispam-Report-Test":"UriScan:(17755550239193);","X-Microsoft-Antispam-PRVS":"<DB5PR05MB16406D214DD4A5B2238C8035CF7A0@DB5PR05MB1640.eurprd05.prod.outlook.com>","X-Exchange-Antispam-Report-CFA-Test":"BCL:0; PCL:0;\n\tRULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(5005006)(8121501046)(3002001)(10201501046)(100000703101)(100105400095)(93006095)(93001095)(6055026)(6041248)(20161123562025)(20161123560025)(20161123558100)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123555025)(20161123564025)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);\n\tSRVR:DB5PR05MB1640; BCL:0; PCL:0;\n\tRULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);\n\tSRVR:DB5PR05MB1640; ","X-Forefront-PRVS":"04410E544A","X-Forefront-Antispam-Report":"SFV:NSPM;\n\tSFS:(10009020)(6049001)(6009001)(376002)(39860400002)(346002)(24454002)(189002)(199003)(54094003)(110136005)(36756003)(47776003)(105586002)(3846002)(478600001)(66066001)(64126003)(65806001)(65956001)(39060400002)(53546010)(31686004)(106356001)(31696002)(101416001)(81156014)(54356999)(76176999)(81166006)(50986999)(8936002)(229853002)(86362001)(77096006)(6116002)(16526017)(6486002)(53936002)(230700001)(4326008)(6666003)(33646002)(6636002)(316002)(83506001)(50466002)(8676002)(6246003)(2950100002)(25786009)(7736002)(2906002)(3260700006)(305945005)(5660300001)(16576012)(97736004)(65826007)(68736007)(58126008)(189998001);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:DB5PR05MB1640; H:[10.223.3.152];\n\tFPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; ","Received-SPF":"None (protection.outlook.com: mellanox.com does not designate\n\tpermitted sender hosts)","SpamDiagnosticOutput":"1:99","SpamDiagnosticMetadata":"NSPM","X-OriginatorOrg":"Mellanox.com","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"25 Sep 2017 13:31:49.3735\n\t(UTC)","X-MS-Exchange-CrossTenant-FromEntityHeader":"Hosted","X-MS-Exchange-CrossTenant-Id":"a652971c-7d2e-4d9b-a6a4-d149256f461b","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"DB5PR05MB1640","X-Spam-Status":"No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tDKIM_VALID_AU,RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Transfer-Encoding":"7bit","Content-Type":"text/plain; charset=\"us-ascii\"; Format=\"flowed\"","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1776160,"web_url":"http://patchwork.ozlabs.org/comment/1776160/","msgid":"<20170927090817.GB25449@vergenet.net>","list_archive_url":null,"date":"2017-09-27T09:08:18","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":64714,"url":"http://patchwork.ozlabs.org/api/people/64714/","name":"Simon Horman","email":"simon.horman@netronome.com"},"content":"On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n> \n> \n> On 18/09/2017 18:01, Simon Horman wrote:\n> >On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n> >>From: Paul Blakey <paulb@mellanox.com>\n> >>\n> >>To be later used to implement ovs action set offloading.\n> >>\n> >>Signed-off-by: Paul Blakey <paulb@mellanox.com>\n> >>Reviewed-by: Roi Dayan <roid@mellanox.com>\n> >>---\n> >>  lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n> >>  lib/tc.h |  16 +++\n> >>  2 files changed, 385 insertions(+), 3 deletions(-)\n> >>\n> >>diff --git a/lib/tc.c b/lib/tc.c\n> >>index c9cada2..743b2ee 100644\n> >>--- a/lib/tc.c\n> >>+++ b/lib/tc.c\n> >>@@ -21,8 +21,10 @@\n> >>  #include <errno.h>\n> >>  #include <linux/if_ether.h>\n> >>  #include <linux/rtnetlink.h>\n> >>+#include <linux/tc_act/tc_csum.h>\n> >>  #include <linux/tc_act/tc_gact.h>\n> >>  #include <linux/tc_act/tc_mirred.h>\n> >>+#include <linux/tc_act/tc_pedit.h>\n> >>  #include <linux/tc_act/tc_tunnel_key.h>\n> >>  #include <linux/tc_act/tc_vlan.h>\n> >>  #include <linux/gen_stats.h>\n> >>@@ -33,11 +35,14 @@\n> >>  #include \"netlink-socket.h\"\n> >>  #include \"netlink.h\"\n> >>  #include \"openvswitch/ofpbuf.h\"\n> >>+#include \"openvswitch/util.h\"\n> >>  #include \"openvswitch/vlog.h\"\n> >>  #include \"packets.h\"\n> >>  #include \"timeval.h\"\n> >>  #include \"unaligned.h\"\n> >>+#define MAX_PEDIT_OFFSETS 8\n> >\n> >Why 8?\n> We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n> pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n> that's makes sens. do you suggest we increase it? to what?\n\nIt seems strange to me to place a somewhat arbitrary small limit\nwhen none exists in the pedit API being used. I would at prefer if\nit was at least a bigger, say 16 or 32.\n\n> >>  VLOG_DEFINE_THIS_MODULE(tc);\n> >>  static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);\n> >>@@ -50,6 +55,82 @@ enum tc_offload_policy {\n> >>  static enum tc_offload_policy tc_policy = TC_POLICY_NONE;\n> >>+struct tc_pedit_key_ex {\n> >>+    enum pedit_header_type htype;\n> >>+    enum pedit_cmd cmd;\n> >>+};\n> >>+\n> >>+struct flower_key_to_pedit {\n> >>+    enum pedit_header_type htype;\n> >>+    int flower_offset;\n> >>+    int offset;\n> >>+    int size;\n> >>+};\n> >>+\n> >>+static struct flower_key_to_pedit flower_pedit_map[] = {\n> >>+    {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> >>+        12,\n> >>+        offsetof(struct tc_flower_key, ipv4.ipv4_src),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> >>+        16,\n> >>+        offsetof(struct tc_flower_key, ipv4.ipv4_dst),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> >>+        8,\n> >>+        offsetof(struct tc_flower_key, ipv4.rewrite_ttl),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n> >>+        8,\n> >>+        offsetof(struct tc_flower_key, ipv6.ipv6_src),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n> >>+        24,\n> >>+        offsetof(struct tc_flower_key, ipv6.ipv6_dst),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> >>+        6,\n> >>+        offsetof(struct tc_flower_key, src_mac),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, src_mac)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> >>+        0,\n> >>+        offsetof(struct tc_flower_key, dst_mac),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, dst_mac)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> >>+        12,\n> >>+        offsetof(struct tc_flower_key, eth_type),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, eth_type)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n> >>+        0,\n> >>+        offsetof(struct tc_flower_key, tcp_src),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, tcp_src)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n> >>+        2,\n> >>+        offsetof(struct tc_flower_key, tcp_dst),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n> >>+        0,\n> >>+        offsetof(struct tc_flower_key, udp_src),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, udp_src)\n> >>+    }, {\n> >>+        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n> >>+        2,\n> >>+        offsetof(struct tc_flower_key, udp_dst),\n> >>+        MEMBER_SIZEOF(struct tc_flower_key, udp_dst)\n> >>+    },\n> >>+};\n> >>+\n> >>  struct tcmsg *\n> >>  tc_make_request(int ifindex, int type, unsigned int flags,\n> >>                  struct ofpbuf *request)\n> >>@@ -365,6 +446,96 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {\n> >>      }\n> >>  }\n> >>+static const struct nl_policy pedit_policy[] = {\n> >>+            [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,\n> >>+                                     .min_len = sizeof(struct tc_pedit),\n> >>+                                     .optional = false, },\n> >>+            [TCA_PEDIT_KEYS_EX]   = { .type = NL_A_NESTED,\n> >>+                                      .optional = false, },\n> >>+};\n> >>+\n> >>+static int\n> >>+nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)\n> >>+{\n> >>+    struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];\n> >>+    const struct tc_pedit *pe;\n> >>+    const struct tc_pedit_key *keys;\n> >>+    const struct nlattr *nla, *keys_ex, *ex_type;\n> >>+    const void *keys_attr;\n> >>+    char *rewrite_key = (void *) &flower->rewrite.key;\n> >>+    char *rewrite_mask = (void *) &flower->rewrite.mask;\n> >>+    size_t keys_ex_size, left;\n> >>+    int type, i = 0;\n> >>+\n> >>+    if (!nl_parse_nested(options, pedit_policy, pe_attrs,\n> >>+                         ARRAY_SIZE(pedit_policy))) {\n> >>+        VLOG_ERR_RL(&error_rl, \"failed to parse pedit action options\");\n> >>+        return EPROTO;\n> >>+    }\n> >>+\n> >>+    pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);\n> >>+    keys = pe->keys;\n> >>+    keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];\n> >>+    keys_ex = nl_attr_get(keys_attr);\n> >>+    keys_ex_size = nl_attr_get_size(keys_attr);\n> >>+\n> >>+    NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {\n> >>+        if (i >= pe->nkeys) {\n> >>+            break;\n> >>+        }\n> >>+\n> >>+        if (nl_attr_type(nla) == TCA_PEDIT_KEY_EX) {\n> >>+            ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);\n> >>+            type = nl_attr_get_u16(ex_type);\n> >>+\n> >>+            for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {\n> >>+                struct flower_key_to_pedit *m = &flower_pedit_map[j];\n> >>+                int flower_off = m->flower_offset;\n> >>+                int sz = m->size;\n> >>+                int mf = m->offset;\n> >>+\n> >>+                if (m->htype != type) {\n> >>+                   continue;\n> >>+                }\n> >>+\n> >>+                /* check overlap between current pedit key, which is always\n> >>+                 * 4 bytes (range [off, off + 3]), and a map entry in\n> >>+                 * flower_pedit_map (range [mf, mf + sz - 1]) */\n> >>+                if ((keys->off >= mf && keys->off < mf + sz)\n> >>+                    || (keys->off + 3 >= mf && keys->off + 3 < mf + sz)) {\n> >>+                    int diff = flower_off + (keys->off - mf);\n> >>+                    uint32_t *dst = (void *) (rewrite_key + diff);\n> >>+                    uint32_t *dst_m = (void *) (rewrite_mask + diff);\n> >>+                    uint32_t mask = ~(keys->mask);\n> >>+                    uint32_t zero_bits;\n> >>+\n> >>+                    if (keys->off < mf) {\n> >>+                        zero_bits = 8 * (mf - keys->off);\n> >>+                        mask &= UINT32_MAX << zero_bits;\n> >>+                    } else if (keys->off + 4 > mf + m->size) {\n> >>+                        zero_bits = 8 * (keys->off + 4 - mf - m->size);\n> >>+                        mask &= UINT32_MAX >> zero_bits;\n> >>+                    }\n> >>+\n> >>+                    *dst_m |= mask;\n> >>+                    *dst |= keys->val & mask;\n> >>+                }\n> >>+            }\n> >\n> >If I understand the above correctly it is designed to make\n> >pedit actions disjoint. If so, why is that necessary? >\n> \n> It's not, as a single flower key rewrite can be split to multiple pedit\n> actions it finds the overlap between a flower key and a pedit action, if\n> they do overlap it translates it to the correct offset and masks it out.\n\nThanks, understood.\n\n> \n> >>+        } else {\n> >>+            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n> >>+                        nl_attr_type(nla));\n> >>+            return EOPNOTSUPP;\n> >>+        }\n> >\n> >I think the code could exit early here as\n> >nl_msg_put_flower_rewrite_pedits() does below.\n> >\n> \n> Sorry, didn't understand. can you give an example?\n> \n\nI meant something like this.\n\n            if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n                VLOG_ERR_RL(...);\n                return EOPNOTSUPP;\n            }\n\n\t    /* Overlap detection code goes here */\n\n> >\n> >>+\n> >>+        keys++;\n> >>+        i++;\n> >>+    }\n> >>+\n> >>+    flower->rewrite.rewrite = true;\n> >>+\n> >>+    return 0;\n> >>+}\n> >>+\n> >>  static const struct nl_policy tunnel_key_policy[] = {\n> >>      [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,\n> >>                                 .min_len = sizeof(struct tc_tunnel_key),\n> >>@@ -608,6 +779,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)\n> >>          nl_parse_act_vlan(act_options, flower);\n> >>      } else if (!strcmp(act_kind, \"tunnel_key\")) {\n> >>          nl_parse_act_tunnel_key(act_options, flower);\n> >>+    } else if (!strcmp(act_kind, \"pedit\")) {\n> >>+        nl_parse_act_pedit(act_options, flower);\n> >>+    } else if (!strcmp(act_kind, \"csum\")) {\n> >>+        /* not doing anything for now, ovs has an implicit csum recalculation\n> >>+         * with rewriting of packet headers (translating of pedit acts). */\n> >\n> >I wonder if the absence of a csum action when needed (by TC)\n> >should be treated as an error >\n> \n> Do you mean validating csum flags from each protocol and such (like in put)?\n\nYes, I think so.\n\nIn OvS (without TC acceleration) csum recalculation is implicit\nbut with TC an explicit csum update action is required. I see\nin your code you are handling this by adding csum actions to TC actions\nwhen translating from OvS DPIF actions. And in the reverse (above) csum\nactions are simply ignored.\n\nWhat I am wondering is if when translating TC actions to OvS DPIF actions\nyou should track if the TC actions should include a csum rule because\nof other actions and treat its absence as an error.\n\n> \n> >>      } else {\n> >>          VLOG_ERR_RL(&error_rl, \"unknown tc action kind: %s\", act_kind);\n> >>          return EINVAL;\n> >>@@ -809,6 +985,48 @@ tc_get_tc_cls_policy(enum tc_offload_policy policy)\n> >>  }\n> >>  static void\n> >>+nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags)\n> >>+{\n> >>+    size_t offset;\n> >>+\n> >>+    nl_msg_put_string(request, TCA_ACT_KIND, \"csum\");\n> >>+    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n> >>+    {\n> >>+        struct tc_csum parm = { .action = TC_ACT_PIPE,\n> >>+                                .update_flags = flags };\n> >>+\n> >>+        nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);\n> >>+    }\n> >>+    nl_msg_end_nested(request, offset);\n> >>+}\n> >>+\n> >>+static void\n> >>+nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,\n> >>+                     struct tc_pedit_key_ex *ex)\n> >>+{\n> >>+    size_t ksize = sizeof *parm + (parm->nkeys * sizeof(struct tc_pedit_key));\n> >\n> >Are there unnecessary () on the line above?\n> No, I'll remove them.\n> \n> >\n> >>+    size_t offset, offset_keys_ex, offset_key;\n> >>+    int i;\n> >>+\n> >>+    nl_msg_put_string(request, TCA_ACT_KIND, \"pedit\");\n> >>+    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n> >>+    {\n> >>+        parm->action = TC_ACT_PIPE;\n> >>+\n> >>+        nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);\n> >>+        offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);\n> >>+        for (i = 0; i < parm->nkeys; i++, ex++) {\n> >>+            offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);\n> >>+            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);\n> >>+            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);\n> >>+            nl_msg_end_nested(request, offset_key);\n> >>+        }\n> >>+        nl_msg_end_nested(request, offset_keys_ex);\n> >>+    }\n> >>+    nl_msg_end_nested(request, offset);\n> >>+}\n> >>+\n> >>+static void\n> >>  nl_msg_put_act_push_vlan(struct ofpbuf *request, uint16_t vid, uint8_t prio)\n> >>  {\n> >>      size_t offset;\n> >>@@ -930,7 +1148,127 @@ nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {\n> >>      }\n> >>  }\n> >>+/* Given flower, a key_to_pedit map entry, calculates the rest,\n> >>+ * where:\n> >>+ *\n> >>+ * mask, data - pointers of where read the first word of flower->key/mask.\n> >>+ * current_offset - which offset to use for the first pedit action.\n> >>+ * cnt - max pedits actions to use.\n> >>+ * first_word_mask/last_word_mask - the mask to use for the first/last read\n> >>+ * (as we read entire words). */\n> >>  static void\n> >>+calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m,\n> >>+             int *cur_offset, int *cnt, uint32_t *last_word_mask,\n> >>+             uint32_t *first_word_mask, uint32_t **mask, uint32_t **data)\n> >>+{\n> >>+    int start_offset, max_offset, total_size;\n> >>+    int diff, right_zero_bits, left_zero_bits;\n> >>+    char *rewrite_key = (void *) &flower->rewrite.key;\n> >>+    char *rewrite_mask = (void *) &flower->rewrite.mask;\n> >>+\n> >>+    max_offset = m->offset + m->size;\n> >>+    start_offset = ROUND_DOWN(m->offset, 4);\n> >>+    diff = m->offset - start_offset;\n> >>+    total_size = max_offset - start_offset;\n> >>+    right_zero_bits = 8 * (4 - (max_offset % 4));\n> >>+    left_zero_bits = 8 * (m->offset - start_offset);\n> >>+\n> >>+    *cur_offset = start_offset;\n> >>+    *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);\n> >>+    *last_word_mask = UINT32_MAX >> right_zero_bits;\n> >>+    *first_word_mask = UINT32_MAX << left_zero_bits;\n> >>+    *data = (void *) (rewrite_key + m->flower_offset - diff);\n> >>+    *mask = (void *) (rewrite_mask + m->flower_offset - diff);\n> >\n> >The type of *data and *mask is uint32_t *.\n> >Why not cast to that type?\n> \n> It's to avoid warning of increasing pointer alignment (-Wcast-align).\n\nIt sounds like the warning should be addressed rather than overridden using\na cast.\n\n> >\n> >>+}\n> >>+\n> >>+static inline void\n> >>+csum_update_flag(struct tc_flower *flower,\n> >>+                 enum pedit_header_type htype) {\n> >\n> >I think the above two lines could be one.\n> >\n> >>+    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4) {\n> >\n> >A case statement might be nicer here.\n> \n> Right, thanks.\n> \n> >\n> >>+        flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;\n> >>+    }\n> >>+    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4\n> >>+        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP6\n> >>+        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_TCP\n> >>+        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_UDP) {\n> >>+        if (flower->key.ip_proto == IPPROTO_TCP) {\n> >>+            flower->mask.ip_proto = UINT8_MAX;\n> >\n> >What if the mask was not UINT8_MAX to start with?\n> >Doesn't this create a different flow?\n> \n> This is so the checksum will be strict (not setting/recalc udp checksum on\n> non udp packets). It creates a more specific flow, a subset of the original.\n> This is fine as datapath is free to ignore a mask, which is the same as a\n> full mask we've set.\n\nI'm not sure that I understand why its fine for the datapath to ignore the\nmask.\n\n> >>+            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;\n> >>+        } else if (flower->key.ip_proto == IPPROTO_UDP) {\n> >>+            flower->mask.ip_proto = UINT8_MAX;\n> >>+            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;\n> >>+        } else if (flower->key.ip_proto == IPPROTO_ICMP\n> >>+                   || flower->key.ip_proto == IPPROTO_ICMPV6) {\n> >>+            flower->mask.ip_proto = UINT8_MAX;\n> >>+            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;\n> >>+        }\n> >>+    }\n> >>+}\n> >>+\n> >>+static int\n> >>+nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,\n> >>+                                 struct tc_flower *flower)\n> >>+{\n> >>+    struct {\n> >>+        struct tc_pedit sel;\n> >>+        struct tc_pedit_key keys[MAX_PEDIT_OFFSETS];\n> >>+        struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];\n> >>+    } sel = {\n> >>+        .sel = {\n> >>+            .nkeys = 0\n> >>+        }\n> >>+    };\n> >>+    int i, j;\n> >>+\n> >>+    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {\n> >>+        struct flower_key_to_pedit *m = &flower_pedit_map[i];\n> >>+        struct tc_pedit_key *pedit_key = NULL;\n> >>+        struct tc_pedit_key_ex *pedit_key_ex = NULL;\n> >>+        uint32_t *mask, *data, first_word_mask, last_word_mask;\n> >>+        int cnt = 0, cur_offset = 0;\n> >>+\n> >>+        if (!m->size) {\n> >>+            continue;\n> >>+        }\n> >>+\n> >>+        calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask,\n> >>+                     &first_word_mask, &mask, &data);\n> >>+\n> >>+        for (j = 0; j < cnt; j++,  mask++, data++, cur_offset += 4) {\n> >>+            uint32_t mask_word = *mask;\n> >>+\n> >>+            if (j == 0) {\n> >>+                mask_word &= first_word_mask;\n> >>+            }\n> >>+            if (j == cnt - 1) {\n> >>+                mask_word &= last_word_mask;\n> >>+            }\n> >>+            if (!mask_word) {\n> >>+                continue;\n> >>+            }\n> >>+            if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {\n> >>+                VLOG_WARN_RL(&error_rl, \"reached too many pedit offsets: %d\",\n> >>+                             MAX_PEDIT_OFFSETS);\n> >>+                return EOPNOTSUPP;\n> >>+            }\n> >>+\n> >>+            pedit_key = &sel.keys[sel.sel.nkeys];\n> >>+            pedit_key_ex = &sel.keys_ex[sel.sel.nkeys];\n> >>+            pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;\n> >>+            pedit_key_ex->htype = m->htype;\n> >>+            pedit_key->off = cur_offset;\n> >>+            pedit_key->mask = ~mask_word;\n> >>+            pedit_key->val = *data & mask_word;\n> >>+            sel.sel.nkeys++;\n> >>+            csum_update_flag(flower, m->htype);\n> >>+        }\n> >>+    }\n> >>+    nl_msg_put_act_pedit(request, &sel.sel, sel.keys_ex);\n> >>+\n> >>+    return 0;\n> >>+}\n> >>+\n> >>+static int\n> >>  nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> >>  {\n> >>      size_t offset;\n> >>@@ -939,7 +1277,20 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> >>      offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);\n> >>      {\n> >>          uint16_t act_index = 1;\n> >>+        int error;\n> >>+        if (flower->rewrite.rewrite) {\n> >>+            act_offset = nl_msg_start_nested(request, act_index++);\n> >>+            error = nl_msg_put_flower_rewrite_pedits(request, flower);\n> >>+            if (error) {\n> >>+                return error;\n> >>+            }\n> >>+            nl_msg_end_nested(request, act_offset);\n> >>+\n> >>+            act_offset = nl_msg_start_nested(request, act_index++);\n> >>+            nl_msg_put_act_csum(request, flower->csum_update_flags);\n> >>+            nl_msg_end_nested(request, act_offset);\n> >>+        }\n> >>          if (flower->set.set) {\n> >>              act_offset = nl_msg_start_nested(request, act_index++);\n> >>              nl_msg_put_act_tunnel_key_set(request, flower->set.id,\n> >>@@ -980,6 +1331,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> >>          }\n> >>      }\n> >>      nl_msg_end_nested(request, offset);\n> >>+\n> >>+    return 0;\n> >>  }\n> >>  static void\n> >>@@ -1021,11 +1374,19 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)\n> >>      nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \\\n> >>                              &flower->mask.member, sizeof flower->key.member)\n> >>-static void\n> >>+static int\n> >>  nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n> >>  {\n> >>+\n> >>      uint16_t host_eth_type = ntohs(flower->key.eth_type);\n> >>      bool is_vlan = (host_eth_type == ETH_TYPE_VLAN);\n> >>+    int err;\n> >>+\n> >>+    /* need to parse acts first as some acts require changing the matching */\n> >\n> >This seems strange to me.\n> \n> from the strict (normalized?) header checksum.\n\nI think this code relates to setting flower->key.ip_proto == IPPROTO_TCP\nabove. Is that correct. Are there any other cases?\n\n> \n> >\n> >>+    err  = nl_msg_put_flower_acts(request, flower);\n> >>+    if (err) {\n> >>+        return err;\n> >>+    }\n> >>      if (is_vlan) {\n> >>          host_eth_type = ntohs(flower->key.encap_eth_type);\n> >>@@ -1083,7 +1444,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n> >>          nl_msg_put_flower_tunnel(request, flower);\n> >>      }\n> >>-    nl_msg_put_flower_acts(request, flower);\n> >>+    return 0;\n> >>  }\n> >>  int\n> >>@@ -1106,7 +1467,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n> >>      nl_msg_put_string(&request, TCA_KIND, \"flower\");\n> >>      basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);\n> >>      {\n> >>-        nl_msg_put_flower_options(&request, flower);\n> >>+        error = nl_msg_put_flower_options(&request, flower);\n> >>+\n> >>+        if (error) {\n> >>+            ofpbuf_uninit(&request);\n> >>+            return error;\n> >>+        }\n> >>      }\n> >>      nl_msg_end_nested(&request, basic_offset);\n> >>diff --git a/lib/tc.h b/lib/tc.h\n> >>index 6c69b79..7876051 100644\n> >>--- a/lib/tc.h\n> >>+++ b/lib/tc.h\n> >>@@ -96,6 +96,7 @@ struct tc_flower_key {\n> >>      struct {\n> >>          ovs_be32 ipv4_src;\n> >>          ovs_be32 ipv4_dst;\n> >>+        uint8_t rewrite_ttl;\n> >>      } ipv4;\n> >>      struct {\n> >>          struct in6_addr ipv6_src;\n> >>@@ -120,6 +121,14 @@ struct tc_flower {\n> >>      uint64_t lastused;\n> >>      struct {\n> >>+        bool rewrite;\n> >>+        struct tc_flower_key key;\n> >>+        struct tc_flower_key mask;\n> >>+    } rewrite;\n> >>+\n> >>+    uint32_t csum_update_flags;\n> >>+\n> >>+    struct {\n> >>          bool set;\n> >>          ovs_be64 id;\n> >>          ovs_be16 tp_src;\n> >>@@ -152,6 +161,13 @@ struct tc_flower {\n> >>      struct tc_cookie act_cookie;\n> >>  };\n> >>+/* assert that if we overflow with a masked write of uint32_t to the last byte\n> >>+ * of flower.rewrite we overflow inside struct flower.\n> >>+ * shouldn't happen unless someone moves rewrite to the end of flower */\n> >>+BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)\n> >>+                  + MEMBER_SIZEOF(struct tc_flower, rewrite)\n> >>+                  + sizeof(uint32_t) - 2 < sizeof(struct tc_flower));\n> >>+\n> >>  int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n> >>                        struct tc_flower *flower);\n> >>  int tc_del_filter(int ifindex, int prio, int handle);\n> >>-- \n> >>2.7.5\n> >>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=netronome-com.20150623.gappssmtp.com\n\theader.i=@netronome-com.20150623.gappssmtp.com\n\theader.b=\"iy41NQiS\"; dkim-atps=neutral"],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y2BnR3yG5z9tXG\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 27 Sep 2017 19:08:27 +1000 (AEST)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 8CC70927;\n\tWed, 27 Sep 2017 09:08:25 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id A25DA412\n\tfor <dev@openvswitch.org>; Wed, 27 Sep 2017 09:08:24 +0000 (UTC)","from mail-wr0-f169.google.com (mail-wr0-f169.google.com\n\t[209.85.128.169])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 0415E1A6\n\tfor <dev@openvswitch.org>; Wed, 27 Sep 2017 09:08:22 +0000 (UTC)","by mail-wr0-f169.google.com with SMTP id m18so15234440wrm.2\n\tfor <dev@openvswitch.org>; Wed, 27 Sep 2017 02:08:22 -0700 (PDT)","from vergenet.net ([217.111.208.18])\n\tby smtp.gmail.com with ESMTPSA id\n\t30sm16341175wry.34.2017.09.27.02.08.20\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);\n\tWed, 27 Sep 2017 02:08:20 -0700 (PDT)"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=netronome-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=Dp51X1rAHHUKsZRf74UxwrQoIN8ZQtRhT0jRf6oRN4c=;\n\tb=iy41NQiSb96528ZXgl9NAzYWJ06RNuTHUINmKtu78ZP/2MZlv8RlRXK9+G+vLI52/W\n\tgPeqApWboefqoECfBf2vfAL58zHoUPtD5ycBvSkjcEGq5y0bzd+jzjyftx6EM1goid58\n\tPuN037j1bsqDXV0hdVWKSxjQimrNH57KDzpoj4eAueHD7RlVHhQ0txZ8Lj7Z+xeDnzqv\n\ty5O8fIcMb1BZk4z02ntESyy+oC3ACq9FX5zGDmGgCzKo2V1yemcqZyTXeEQFfHxIC14M\n\tFLP215W4NqkZwvoaOLBGpKiasiX+Dk8i1imEN7STHAX/t/Kdn0aYZ4C94fU+BvpFj2Lm\n\tTHCA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=Dp51X1rAHHUKsZRf74UxwrQoIN8ZQtRhT0jRf6oRN4c=;\n\tb=WaDX2PV5m6+u7tQ5qfM2f9CtAkFchBFVAMmJ/KIp57dadD5AfkvBU1dCnIua8+fku6\n\t56EbhSgYWPQ658bpDxH2dPT5e/pOGTQpn8ZXdbrXPTR2YiPLCCAg+8/qS0ZGq05IV1Z4\n\tMT5YfMKqUREEWtqFTOTaCmO0m2GwyXSo4rz3bW9QUORcmyeoRUgMXp3AcJ86+ixK+/8N\n\t+WNw41g2JIU2Fjp/DZ4DZRS9z/OtXca+FD3zqji4EyJHqn4bBopyRB1Xr+TEheUcce2N\n\tQbapS0RX1sZePxreGuXjAjXUhmjxz+D8zB6aoYMs3J36SOyk2lBdwPJjRIfDgWaaka41\n\tE2qw==","X-Gm-Message-State":"AHPjjUimPj2OfoBckCpqSuAudh+ZdTAeIo1yLxlKefltf6zWp5NkAUDa\n\tf+qnw1MP6C96c+6SCqZ5dDdTeHZZYOk=","X-Google-Smtp-Source":"AOwi7QATi2JHqZ4gYoi4iBA3UFO5NEKbk9H5tAagotn6jHNKX54IIHoulWvFmvTIo7u4DSLthkv9Cw==","X-Received":"by 10.223.177.222 with SMTP id r30mr718563wra.128.1506503301312; \n\tWed, 27 Sep 2017 02:08:21 -0700 (PDT)","Date":"Wed, 27 Sep 2017 11:08:18 +0200","From":"Simon Horman <simon.horman@netronome.com>","To":"Paul Blakey <paulb@mellanox.com>","Message-ID":"<20170927090817.GB25449@vergenet.net>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>","User-Agent":"Mutt/1.5.23 (2014-03-12)","X-Spam-Status":"No, score=0.5 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tRCVD_IN_DNSWL_NONE,\n\tRCVD_IN_SORBS_SPAM autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1793701,"web_url":"http://patchwork.ozlabs.org/comment/1793701/","msgid":"<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>","list_archive_url":null,"date":"2017-10-25T11:24:15","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":70307,"url":"http://patchwork.ozlabs.org/api/people/70307/","name":"Roi Dayan","email":"roid@mellanox.com"},"content":"On 27/09/2017 12:08, Simon Horman wrote:\n> On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n>>\n>>\n>> On 18/09/2017 18:01, Simon Horman wrote:\n>>> On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n>>>> From: Paul Blakey <paulb@mellanox.com>\n>>>>\n>>>> To be later used to implement ovs action set offloading.\n>>>>\n>>>> Signed-off-by: Paul Blakey <paulb@mellanox.com>\n>>>> Reviewed-by: Roi Dayan <roid@mellanox.com>\n>>>> ---\n>>>>   lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n>>>>   lib/tc.h |  16 +++\n>>>>   2 files changed, 385 insertions(+), 3 deletions(-)\n>>>>\n>>>> diff --git a/lib/tc.c b/lib/tc.c\n>>>> index c9cada2..743b2ee 100644\n>>>> --- a/lib/tc.c\n>>>> +++ b/lib/tc.c\n>>>> @@ -21,8 +21,10 @@\n>>>>   #include <errno.h>\n>>>>   #include <linux/if_ether.h>\n>>>>   #include <linux/rtnetlink.h>\n>>>> +#include <linux/tc_act/tc_csum.h>\n>>>>   #include <linux/tc_act/tc_gact.h>\n>>>>   #include <linux/tc_act/tc_mirred.h>\n>>>> +#include <linux/tc_act/tc_pedit.h>\n>>>>   #include <linux/tc_act/tc_tunnel_key.h>\n>>>>   #include <linux/tc_act/tc_vlan.h>\n>>>>   #include <linux/gen_stats.h>\n>>>> @@ -33,11 +35,14 @@\n>>>>   #include \"netlink-socket.h\"\n>>>>   #include \"netlink.h\"\n>>>>   #include \"openvswitch/ofpbuf.h\"\n>>>> +#include \"openvswitch/util.h\"\n>>>>   #include \"openvswitch/vlog.h\"\n>>>>   #include \"packets.h\"\n>>>>   #include \"timeval.h\"\n>>>>   #include \"unaligned.h\"\n>>>> +#define MAX_PEDIT_OFFSETS 8\n>>>\n>>> Why 8?\n>> We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n>> pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n>> that's makes sens. do you suggest we increase it? to what?\n> \n> It seems strange to me to place a somewhat arbitrary small limit\n> when none exists in the pedit API being used. I would at prefer if\n> it was at least a bigger, say 16 or 32.\n\n\nHi Simon,\n\nSorry for the late reply due to holidays and vacations.\nMe & Paul going to go over this and do the fixes needed and\nalso rebase over latest master and run tests again.\n\nI'll answer what I'm more familiar with now and Paul will continue.\nThe 8 here is too low and you right. We used this definition\nfor allocation of the pedit keys on the stack in\nnl_msg_put_flower_rewrite_pedits()\n\nIt was for convenience instead of calculating the maximum possible\nkeys that could exists and allocating it there and freeing it at\nthe end.\n\nIncreasing it to 32 is probably more than enough and wont waste much.\n\n\n> \n>>>>   VLOG_DEFINE_THIS_MODULE(tc);\n>>>>   static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);\n>>>> @@ -50,6 +55,82 @@ enum tc_offload_policy {\n>>>>   static enum tc_offload_policy tc_policy = TC_POLICY_NONE;\n>>>> +struct tc_pedit_key_ex {\n>>>> +    enum pedit_header_type htype;\n>>>> +    enum pedit_cmd cmd;\n>>>> +};\n>>>> +\n>>>> +struct flower_key_to_pedit {\n>>>> +    enum pedit_header_type htype;\n>>>> +    int flower_offset;\n>>>> +    int offset;\n>>>> +    int size;\n>>>> +};\n>>>> +\n>>>> +static struct flower_key_to_pedit flower_pedit_map[] = {\n>>>> +    {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>>>> +        12,\n>>>> +        offsetof(struct tc_flower_key, ipv4.ipv4_src),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>>>> +        16,\n>>>> +        offsetof(struct tc_flower_key, ipv4.ipv4_dst),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>>>> +        8,\n>>>> +        offsetof(struct tc_flower_key, ipv4.rewrite_ttl),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n>>>> +        8,\n>>>> +        offsetof(struct tc_flower_key, ipv6.ipv6_src),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n>>>> +        24,\n>>>> +        offsetof(struct tc_flower_key, ipv6.ipv6_dst),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>>>> +        6,\n>>>> +        offsetof(struct tc_flower_key, src_mac),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, src_mac)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>>>> +        0,\n>>>> +        offsetof(struct tc_flower_key, dst_mac),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, dst_mac)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>>>> +        12,\n>>>> +        offsetof(struct tc_flower_key, eth_type),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, eth_type)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n>>>> +        0,\n>>>> +        offsetof(struct tc_flower_key, tcp_src),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, tcp_src)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n>>>> +        2,\n>>>> +        offsetof(struct tc_flower_key, tcp_dst),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n>>>> +        0,\n>>>> +        offsetof(struct tc_flower_key, udp_src),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, udp_src)\n>>>> +    }, {\n>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n>>>> +        2,\n>>>> +        offsetof(struct tc_flower_key, udp_dst),\n>>>> +        MEMBER_SIZEOF(struct tc_flower_key, udp_dst)\n>>>> +    },\n>>>> +};\n>>>> +\n>>>>   struct tcmsg *\n>>>>   tc_make_request(int ifindex, int type, unsigned int flags,\n>>>>                   struct ofpbuf *request)\n>>>> @@ -365,6 +446,96 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {\n>>>>       }\n>>>>   }\n>>>> +static const struct nl_policy pedit_policy[] = {\n>>>> +            [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,\n>>>> +                                     .min_len = sizeof(struct tc_pedit),\n>>>> +                                     .optional = false, },\n>>>> +            [TCA_PEDIT_KEYS_EX]   = { .type = NL_A_NESTED,\n>>>> +                                      .optional = false, },\n>>>> +};\n>>>> +\n>>>> +static int\n>>>> +nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)\n>>>> +{\n>>>> +    struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];\n>>>> +    const struct tc_pedit *pe;\n>>>> +    const struct tc_pedit_key *keys;\n>>>> +    const struct nlattr *nla, *keys_ex, *ex_type;\n>>>> +    const void *keys_attr;\n>>>> +    char *rewrite_key = (void *) &flower->rewrite.key;\n>>>> +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n>>>> +    size_t keys_ex_size, left;\n>>>> +    int type, i = 0;\n>>>> +\n>>>> +    if (!nl_parse_nested(options, pedit_policy, pe_attrs,\n>>>> +                         ARRAY_SIZE(pedit_policy))) {\n>>>> +        VLOG_ERR_RL(&error_rl, \"failed to parse pedit action options\");\n>>>> +        return EPROTO;\n>>>> +    }\n>>>> +\n>>>> +    pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);\n>>>> +    keys = pe->keys;\n>>>> +    keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];\n>>>> +    keys_ex = nl_attr_get(keys_attr);\n>>>> +    keys_ex_size = nl_attr_get_size(keys_attr);\n>>>> +\n>>>> +    NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {\n>>>> +        if (i >= pe->nkeys) {\n>>>> +            break;\n>>>> +        }\n>>>> +\n>>>> +        if (nl_attr_type(nla) == TCA_PEDIT_KEY_EX) {\n>>>> +            ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);\n>>>> +            type = nl_attr_get_u16(ex_type);\n>>>> +\n>>>> +            for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {\n>>>> +                struct flower_key_to_pedit *m = &flower_pedit_map[j];\n>>>> +                int flower_off = m->flower_offset;\n>>>> +                int sz = m->size;\n>>>> +                int mf = m->offset;\n>>>> +\n>>>> +                if (m->htype != type) {\n>>>> +                   continue;\n>>>> +                }\n>>>> +\n>>>> +                /* check overlap between current pedit key, which is always\n>>>> +                 * 4 bytes (range [off, off + 3]), and a map entry in\n>>>> +                 * flower_pedit_map (range [mf, mf + sz - 1]) */\n>>>> +                if ((keys->off >= mf && keys->off < mf + sz)\n>>>> +                    || (keys->off + 3 >= mf && keys->off + 3 < mf + sz)) {\n>>>> +                    int diff = flower_off + (keys->off - mf);\n>>>> +                    uint32_t *dst = (void *) (rewrite_key + diff);\n>>>> +                    uint32_t *dst_m = (void *) (rewrite_mask + diff);\n>>>> +                    uint32_t mask = ~(keys->mask);\n>>>> +                    uint32_t zero_bits;\n>>>> +\n>>>> +                    if (keys->off < mf) {\n>>>> +                        zero_bits = 8 * (mf - keys->off);\n>>>> +                        mask &= UINT32_MAX << zero_bits;\n>>>> +                    } else if (keys->off + 4 > mf + m->size) {\n>>>> +                        zero_bits = 8 * (keys->off + 4 - mf - m->size);\n>>>> +                        mask &= UINT32_MAX >> zero_bits;\n>>>> +                    }\n>>>> +\n>>>> +                    *dst_m |= mask;\n>>>> +                    *dst |= keys->val & mask;\n>>>> +                }\n>>>> +            }\n>>>\n>>> If I understand the above correctly it is designed to make\n>>> pedit actions disjoint. If so, why is that necessary? >\n>>\n>> It's not, as a single flower key rewrite can be split to multiple pedit\n>> actions it finds the overlap between a flower key and a pedit action, if\n>> they do overlap it translates it to the correct offset and masks it out.\n> \n> Thanks, understood.\n> \n>>\n>>>> +        } else {\n>>>> +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n>>>> +                        nl_attr_type(nla));\n>>>> +            return EOPNOTSUPP;\n>>>> +        }\n>>>\n>>> I think the code could exit early here as\n>>> nl_msg_put_flower_rewrite_pedits() does below.\n>>>\n>>\n>> Sorry, didn't understand. can you give an example?\n>>\n> \n> I meant something like this.\n> \n>              if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n>                  VLOG_ERR_RL(...);\n>                  return EOPNOTSUPP;\n>              }\n\nunderstood. we'll do that. thanks.\n\n> \n> \t    /* Overlap detection code goes here */\n> \n>>>\n>>>> +\n>>>> +        keys++;\n>>>> +        i++;\n>>>> +    }\n>>>> +\n>>>> +    flower->rewrite.rewrite = true;\n>>>> +\n>>>> +    return 0;\n>>>> +}\n>>>> +\n>>>>   static const struct nl_policy tunnel_key_policy[] = {\n>>>>       [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,\n>>>>                                  .min_len = sizeof(struct tc_tunnel_key),\n>>>> @@ -608,6 +779,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)\n>>>>           nl_parse_act_vlan(act_options, flower);\n>>>>       } else if (!strcmp(act_kind, \"tunnel_key\")) {\n>>>>           nl_parse_act_tunnel_key(act_options, flower);\n>>>> +    } else if (!strcmp(act_kind, \"pedit\")) {\n>>>> +        nl_parse_act_pedit(act_options, flower);\n>>>> +    } else if (!strcmp(act_kind, \"csum\")) {\n>>>> +        /* not doing anything for now, ovs has an implicit csum recalculation\n>>>> +         * with rewriting of packet headers (translating of pedit acts). */\n>>>\n>>> I wonder if the absence of a csum action when needed (by TC)\n>>> should be treated as an error >\n>>\n>> Do you mean validating csum flags from each protocol and such (like in put)?\n> \n> Yes, I think so.\n> \n> In OvS (without TC acceleration) csum recalculation is implicit\n> but with TC an explicit csum update action is required. I see\n> in your code you are handling this by adding csum actions to TC actions\n> when translating from OvS DPIF actions. And in the reverse (above) csum\n> actions are simply ignored.\n> \n> What I am wondering is if when translating TC actions to OvS DPIF actions\n> you should track if the TC actions should include a csum rule because\n> of other actions and treat its absence as an error.\n> \n>>\n>>>>       } else {\n>>>>           VLOG_ERR_RL(&error_rl, \"unknown tc action kind: %s\", act_kind);\n>>>>           return EINVAL;\n>>>> @@ -809,6 +985,48 @@ tc_get_tc_cls_policy(enum tc_offload_policy policy)\n>>>>   }\n>>>>   static void\n>>>> +nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags)\n>>>> +{\n>>>> +    size_t offset;\n>>>> +\n>>>> +    nl_msg_put_string(request, TCA_ACT_KIND, \"csum\");\n>>>> +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n>>>> +    {\n>>>> +        struct tc_csum parm = { .action = TC_ACT_PIPE,\n>>>> +                                .update_flags = flags };\n>>>> +\n>>>> +        nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);\n>>>> +    }\n>>>> +    nl_msg_end_nested(request, offset);\n>>>> +}\n>>>> +\n>>>> +static void\n>>>> +nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,\n>>>> +                     struct tc_pedit_key_ex *ex)\n>>>> +{\n>>>> +    size_t ksize = sizeof *parm + (parm->nkeys * sizeof(struct tc_pedit_key));\n>>>\n>>> Are there unnecessary () on the line above?\n>> No, I'll remove them.\n>>\n>>>\n>>>> +    size_t offset, offset_keys_ex, offset_key;\n>>>> +    int i;\n>>>> +\n>>>> +    nl_msg_put_string(request, TCA_ACT_KIND, \"pedit\");\n>>>> +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n>>>> +    {\n>>>> +        parm->action = TC_ACT_PIPE;\n>>>> +\n>>>> +        nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);\n>>>> +        offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);\n>>>> +        for (i = 0; i < parm->nkeys; i++, ex++) {\n>>>> +            offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);\n>>>> +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);\n>>>> +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);\n>>>> +            nl_msg_end_nested(request, offset_key);\n>>>> +        }\n>>>> +        nl_msg_end_nested(request, offset_keys_ex);\n>>>> +    }\n>>>> +    nl_msg_end_nested(request, offset);\n>>>> +}\n>>>> +\n>>>> +static void\n>>>>   nl_msg_put_act_push_vlan(struct ofpbuf *request, uint16_t vid, uint8_t prio)\n>>>>   {\n>>>>       size_t offset;\n>>>> @@ -930,7 +1148,127 @@ nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {\n>>>>       }\n>>>>   }\n>>>> +/* Given flower, a key_to_pedit map entry, calculates the rest,\n>>>> + * where:\n>>>> + *\n>>>> + * mask, data - pointers of where read the first word of flower->key/mask.\n>>>> + * current_offset - which offset to use for the first pedit action.\n>>>> + * cnt - max pedits actions to use.\n>>>> + * first_word_mask/last_word_mask - the mask to use for the first/last read\n>>>> + * (as we read entire words). */\n>>>>   static void\n>>>> +calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m,\n>>>> +             int *cur_offset, int *cnt, uint32_t *last_word_mask,\n>>>> +             uint32_t *first_word_mask, uint32_t **mask, uint32_t **data)\n>>>> +{\n>>>> +    int start_offset, max_offset, total_size;\n>>>> +    int diff, right_zero_bits, left_zero_bits;\n>>>> +    char *rewrite_key = (void *) &flower->rewrite.key;\n>>>> +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n>>>> +\n>>>> +    max_offset = m->offset + m->size;\n>>>> +    start_offset = ROUND_DOWN(m->offset, 4);\n>>>> +    diff = m->offset - start_offset;\n>>>> +    total_size = max_offset - start_offset;\n>>>> +    right_zero_bits = 8 * (4 - (max_offset % 4));\n>>>> +    left_zero_bits = 8 * (m->offset - start_offset);\n>>>> +\n>>>> +    *cur_offset = start_offset;\n>>>> +    *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);\n>>>> +    *last_word_mask = UINT32_MAX >> right_zero_bits;\n>>>> +    *first_word_mask = UINT32_MAX << left_zero_bits;\n>>>> +    *data = (void *) (rewrite_key + m->flower_offset - diff);\n>>>> +    *mask = (void *) (rewrite_mask + m->flower_offset - diff);\n>>>\n>>> The type of *data and *mask is uint32_t *.\n>>> Why not cast to that type?\n>>\n>> It's to avoid warning of increasing pointer alignment (-Wcast-align).\n> \n> It sounds like the warning should be addressed rather than overridden using\n> a cast.\n> \n>>>\n>>>> +}\n>>>> +\n>>>> +static inline void\n>>>> +csum_update_flag(struct tc_flower *flower,\n>>>> +                 enum pedit_header_type htype) {\n>>>\n>>> I think the above two lines could be one.\n>>>\n>>>> +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4) {\n>>>\n>>> A case statement might be nicer here.\n>>\n>> Right, thanks.\n>>\n>>>\n>>>> +        flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;\n>>>> +    }\n>>>> +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4\n>>>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP6\n>>>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_TCP\n>>>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_UDP) {\n>>>> +        if (flower->key.ip_proto == IPPROTO_TCP) {\n>>>> +            flower->mask.ip_proto = UINT8_MAX;\n>>>\n>>> What if the mask was not UINT8_MAX to start with?\n>>> Doesn't this create a different flow?\n>>\n>> This is so the checksum will be strict (not setting/recalc udp checksum on\n>> non udp packets). It creates a more specific flow, a subset of the original.\n>> This is fine as datapath is free to ignore a mask, which is the same as a\n>> full mask we've set.\n> \n> I'm not sure that I understand why its fine for the datapath to ignore the\n> mask.\n\nI'll try to explain.\nWhen we want the HW to recalc the csum we need to also do matching on\nit. We do that for TCP, UDP, ICMP.\n\n> \n>>>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;\n>>>> +        } else if (flower->key.ip_proto == IPPROTO_UDP) {\n>>>> +            flower->mask.ip_proto = UINT8_MAX;\n>>>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;\n>>>> +        } else if (flower->key.ip_proto == IPPROTO_ICMP\n>>>> +                   || flower->key.ip_proto == IPPROTO_ICMPV6) {\n>>>> +            flower->mask.ip_proto = UINT8_MAX;\n>>>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;\n>>>> +        }\n>>>> +    }\n>>>> +}\n>>>> +\n>>>> +static int\n>>>> +nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,\n>>>> +                                 struct tc_flower *flower)\n>>>> +{\n>>>> +    struct {\n>>>> +        struct tc_pedit sel;\n>>>> +        struct tc_pedit_key keys[MAX_PEDIT_OFFSETS];\n>>>> +        struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];\n>>>> +    } sel = {\n>>>> +        .sel = {\n>>>> +            .nkeys = 0\n>>>> +        }\n>>>> +    };\n>>>> +    int i, j;\n>>>> +\n>>>> +    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {\n>>>> +        struct flower_key_to_pedit *m = &flower_pedit_map[i];\n>>>> +        struct tc_pedit_key *pedit_key = NULL;\n>>>> +        struct tc_pedit_key_ex *pedit_key_ex = NULL;\n>>>> +        uint32_t *mask, *data, first_word_mask, last_word_mask;\n>>>> +        int cnt = 0, cur_offset = 0;\n>>>> +\n>>>> +        if (!m->size) {\n>>>> +            continue;\n>>>> +        }\n>>>> +\n>>>> +        calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask,\n>>>> +                     &first_word_mask, &mask, &data);\n>>>> +\n>>>> +        for (j = 0; j < cnt; j++,  mask++, data++, cur_offset += 4) {\n>>>> +            uint32_t mask_word = *mask;\n>>>> +\n>>>> +            if (j == 0) {\n>>>> +                mask_word &= first_word_mask;\n>>>> +            }\n>>>> +            if (j == cnt - 1) {\n>>>> +                mask_word &= last_word_mask;\n>>>> +            }\n>>>> +            if (!mask_word) {\n>>>> +                continue;\n>>>> +            }\n>>>> +            if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {\n>>>> +                VLOG_WARN_RL(&error_rl, \"reached too many pedit offsets: %d\",\n>>>> +                             MAX_PEDIT_OFFSETS);\n>>>> +                return EOPNOTSUPP;\n>>>> +            }\n>>>> +\n>>>> +            pedit_key = &sel.keys[sel.sel.nkeys];\n>>>> +            pedit_key_ex = &sel.keys_ex[sel.sel.nkeys];\n>>>> +            pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;\n>>>> +            pedit_key_ex->htype = m->htype;\n>>>> +            pedit_key->off = cur_offset;\n>>>> +            pedit_key->mask = ~mask_word;\n>>>> +            pedit_key->val = *data & mask_word;\n>>>> +            sel.sel.nkeys++;\n>>>> +            csum_update_flag(flower, m->htype);\n>>>> +        }\n>>>> +    }\n>>>> +    nl_msg_put_act_pedit(request, &sel.sel, sel.keys_ex);\n>>>> +\n>>>> +    return 0;\n>>>> +}\n>>>> +\n>>>> +static int\n>>>>   nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>>>   {\n>>>>       size_t offset;\n>>>> @@ -939,7 +1277,20 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>>>       offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);\n>>>>       {\n>>>>           uint16_t act_index = 1;\n>>>> +        int error;\n>>>> +        if (flower->rewrite.rewrite) {\n>>>> +            act_offset = nl_msg_start_nested(request, act_index++);\n>>>> +            error = nl_msg_put_flower_rewrite_pedits(request, flower);\n>>>> +            if (error) {\n>>>> +                return error;\n>>>> +            }\n>>>> +            nl_msg_end_nested(request, act_offset);\n>>>> +\n>>>> +            act_offset = nl_msg_start_nested(request, act_index++);\n>>>> +            nl_msg_put_act_csum(request, flower->csum_update_flags);\n>>>> +            nl_msg_end_nested(request, act_offset);\n>>>> +        }\n>>>>           if (flower->set.set) {\n>>>>               act_offset = nl_msg_start_nested(request, act_index++);\n>>>>               nl_msg_put_act_tunnel_key_set(request, flower->set.id,\n>>>> @@ -980,6 +1331,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>>>           }\n>>>>       }\n>>>>       nl_msg_end_nested(request, offset);\n>>>> +\n>>>> +    return 0;\n>>>>   }\n>>>>   static void\n>>>> @@ -1021,11 +1374,19 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)\n>>>>       nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \\\n>>>>                               &flower->mask.member, sizeof flower->key.member)\n>>>> -static void\n>>>> +static int\n>>>>   nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n>>>>   {\n>>>> +\n>>>>       uint16_t host_eth_type = ntohs(flower->key.eth_type);\n>>>>       bool is_vlan = (host_eth_type == ETH_TYPE_VLAN);\n>>>> +    int err;\n>>>> +\n>>>> +    /* need to parse acts first as some acts require changing the matching */\n>>>\n>>> This seems strange to me.\n>>\n>> from the strict (normalized?) header checksum.\n> \n> I think this code relates to setting flower->key.ip_proto == IPPROTO_TCP\n> above. Is that correct. Are there any other cases?\n\nyes and also for UDP and ICMP. as explained above.\nSo going over the acts in header rewrite case we might want to signal \nthe HW recalc csum and we need matching on those fields that require new\ncsum so the matching mask being updated. this is why we parse the acts\nfirst.\n\n\n> \n>>\n>>>\n>>>> +    err  = nl_msg_put_flower_acts(request, flower);\n>>>> +    if (err) {\n>>>> +        return err;\n>>>> +    }\n>>>>       if (is_vlan) {\n>>>>           host_eth_type = ntohs(flower->key.encap_eth_type);\n>>>> @@ -1083,7 +1444,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n>>>>           nl_msg_put_flower_tunnel(request, flower);\n>>>>       }\n>>>> -    nl_msg_put_flower_acts(request, flower);\n>>>> +    return 0;\n>>>>   }\n>>>>   int\n>>>> @@ -1106,7 +1467,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n>>>>       nl_msg_put_string(&request, TCA_KIND, \"flower\");\n>>>>       basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);\n>>>>       {\n>>>> -        nl_msg_put_flower_options(&request, flower);\n>>>> +        error = nl_msg_put_flower_options(&request, flower);\n>>>> +\n>>>> +        if (error) {\n>>>> +            ofpbuf_uninit(&request);\n>>>> +            return error;\n>>>> +        }\n>>>>       }\n>>>>       nl_msg_end_nested(&request, basic_offset);\n>>>> diff --git a/lib/tc.h b/lib/tc.h\n>>>> index 6c69b79..7876051 100644\n>>>> --- a/lib/tc.h\n>>>> +++ b/lib/tc.h\n>>>> @@ -96,6 +96,7 @@ struct tc_flower_key {\n>>>>       struct {\n>>>>           ovs_be32 ipv4_src;\n>>>>           ovs_be32 ipv4_dst;\n>>>> +        uint8_t rewrite_ttl;\n>>>>       } ipv4;\n>>>>       struct {\n>>>>           struct in6_addr ipv6_src;\n>>>> @@ -120,6 +121,14 @@ struct tc_flower {\n>>>>       uint64_t lastused;\n>>>>       struct {\n>>>> +        bool rewrite;\n>>>> +        struct tc_flower_key key;\n>>>> +        struct tc_flower_key mask;\n>>>> +    } rewrite;\n>>>> +\n>>>> +    uint32_t csum_update_flags;\n>>>> +\n>>>> +    struct {\n>>>>           bool set;\n>>>>           ovs_be64 id;\n>>>>           ovs_be16 tp_src;\n>>>> @@ -152,6 +161,13 @@ struct tc_flower {\n>>>>       struct tc_cookie act_cookie;\n>>>>   };\n>>>> +/* assert that if we overflow with a masked write of uint32_t to the last byte\n>>>> + * of flower.rewrite we overflow inside struct flower.\n>>>> + * shouldn't happen unless someone moves rewrite to the end of flower */\n>>>> +BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)\n>>>> +                  + MEMBER_SIZEOF(struct tc_flower, rewrite)\n>>>> +                  + sizeof(uint32_t) - 2 < sizeof(struct tc_flower));\n>>>> +\n>>>>   int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n>>>>                         struct tc_flower *flower);\n>>>>   int tc_del_filter(int ifindex, int prio, int handle);\n>>>> -- \n>>>> 2.7.5\n>>>>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=Mellanox.com header.i=@Mellanox.com\n\theader.b=\"AYP1GEZF\"; dkim-atps=neutral","spf=none (sender IP is )\n\tsmtp.mailfrom=roid@mellanox.com; "],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3yMSTX5V4Zz9sRV\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed, 25 Oct 2017 22:24:32 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 2908992F;\n\tWed, 25 Oct 2017 11:24:27 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id A35A7AE7\n\tfor <dev@openvswitch.org>; Wed, 25 Oct 2017 11:24:25 +0000 (UTC)","from EUR01-DB5-obe.outbound.protection.outlook.com\n\t(mail-db5eur01on0088.outbound.protection.outlook.com [104.47.2.88])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 93BFA1DF\n\tfor <dev@openvswitch.org>; Wed, 25 Oct 2017 11:24:23 +0000 (UTC)","from [10.223.0.122] (193.47.165.251) by\n\tVI1PR0501MB2256.eurprd05.prod.outlook.com (2603:10a6:800:2b::27) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.156.4;\n\tWed, 25 Oct 2017 11:24:20 +0000"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com;\n\ts=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version;\n\tbh=kPNnsMkwNfsBopm3V9rhKdqLwcqZ6ONDMVZXctvNBAk=;\n\tb=AYP1GEZFpHCT4RcQzOqV/ZE3I4FHdu6VFSaJAZMan4SgnuQmxCqXLyp9QccCu9pVXx3WLSywFTZBUoqNAeVg8esaYIO65kF1tMZYBSFcFGn8GypfvGQhHvWmfgKjxAzpcrrZ1hCrKHMf0DycGvxQVAHxPd32gjExhyBPvx/gT9g=","To":"Simon Horman <simon.horman@netronome.com>,\n\tPaul Blakey <paulb@mellanox.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>","From":"Roi Dayan <roid@mellanox.com>","Message-ID":"<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>","Date":"Wed, 25 Oct 2017 14:24:15 +0300","User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101\n\tThunderbird/52.4.0","MIME-Version":"1.0","In-Reply-To":"<20170927090817.GB25449@vergenet.net>","Content-Language":"en-US","X-Originating-IP":"[193.47.165.251]","X-ClientProxiedBy":"AM5PR0502CA0015.eurprd05.prod.outlook.com\n\t(2603:10a6:203:91::25) To VI1PR0501MB2256.eurprd05.prod.outlook.com\n\t(2603:10a6:800:2b::27)","X-MS-PublicTrafficType":"Email","X-MS-Office365-Filtering-Correlation-Id":"cc7aaf84-6586-4bab-ce74-08d51b9aefee","X-MS-Office365-Filtering-HT":"Tenant","X-Microsoft-Antispam":"UriScan:; BCL:0; PCL:0;\n\tRULEID:(22001)(48565401081)(4534020)(4602075)(4627075)(201703031133081)(201702281549075)(2017052603199);\n\tSRVR:VI1PR0501MB2256; ","X-Microsoft-Exchange-Diagnostics":["1; VI1PR0501MB2256;\n\t3:Mba2bXfPH9VyRLNXL2l/38KtBZFg8ux2k+Tj5h4d0THO2TPrqm4FMmjvaPIH8de+oWhYa54DWUtFeC4Q8SdmP1luvHZB3wKljz/BTkJTc93acjyqnIQyhTFb44eSoXEpGfaea1IpJLWm4icMigmpubj0asHCn8rt9cQ+n14wZ5gjcIhAd/BuLADZA+9YFo9stuO99kbXgn6E1je11iUW1OMMfiNlannfRgik9qv1Mszk3tEHFTMV+05j+LTQpzLU;\n\t25:lescnjwlVKiM1BHnMvmclFZLGhA7YqLLz77GhoZ4uxWzJEOS7LJDgEd/wI0MbOo8zrwk5vOGusP2ck4Lwv+TRwZEjnS1jnoj/YACJ6M0He8Zd704iEB93KaWO7wr294zXglrNM8XMPHcfQe1SrjkYvrsuLFHJF/7yX8ZgiWMVzlDzfHJBwIF5yCuLGz4r/y/lvmksYK+aEh2WiUSNVDsYk6FL5f1QdAq75sOWd01sCzUxmfvn/LUYBG40ZrblxYBoLwZ8lRg0tSyJVOh1ZalqSn/4QwAYNtn5Xzj4kK089lw44aHLlPznrQaK1elz+tSfNW4yAb+bhiapgaT6I6mdB4+H0EHf/+mbA9+gFUsQtk=;\n\t31:qsp0eJ+6fUjgY2ZO8ynuVfvemYJBerV4muBJkyFfVgQNWQLrtxIUP7jrTi4Fzua26rak1w/mvHcD08cHygnktdKDNFxkLx7RDxd5ifrLp9ngu4TO8Y66X1VTs9LRb8rlUWyYKaOtJ9uafDOvQiA5o5ZOFuq22+6yD9L5swU69lhqPUUNe/xKGMjA724bJeuV8eEg5CF21p2QN/DLeao48CRvx70IEUcR424684IPcPw=","1; VI1PR0501MB2256;\n\t20:SUqWZBC/eCaEA5FBo9vzhwYkZ4CqMr/hr+0CTJGSesKDTn9HuE8sq+sX/Yj6LH7Q7knyI3kD6FwIpdX5cvQAY2mo+j7U7R9UMc39sVO+NVK4zb0lrIJuzlVstD429diwV6STIRGVUki6QdJLoOCinNN08k4D2ij7xwrSn5vIGq7p5fBrre3FVQHhA7n+o9K9tafzCW2uXC7JhHqMEDsc6XPI1kvD5Fmlqk8hcUu3/tCZBqyNz+hilgPNLP5Ql87uQz4yJ9NVsRggqyPufe0jiXSDB8opaH5134Vw35yRyB6HHBonlhTCs6IpkCJIBRBvzKjLpVYpfct0dpxTjAGU/osXRJdh/Adhmd7wMco2mNDKSV8cOOjgBGlVhXzpxR7N0lBGse8i1BsvR8j7R+9Lq5xNHGNHj+f4rPOECyFc88L3fX26Jzro1+zJwhjPg2kUob9QflPJTQ/Ee9njStu+QPklQX+JxhIJHX181tjxfwxoQowzebNi80Dql7ipuNJB;\n\t4:4bwbTka2MeHWORaZX5ktrQeI/J4P3lA7ZkNWhNclUWTP7JCVrhYSjmW9qXj6S2wOFYnIBSQ4bMwDAUIlNX9bfNhGS0VGXjMS1w0SqppxAtwzNN/KJZFhSLORrsde8fz432qvVGe4wHGz5E9nNhJTGuhdNB/5TWADNKDTmjNsRapxM07W9UcqWU2dJ7G2u4/RQ0gWZCia5hEt5tlPGpCaZlBQJHWxUeHjo7z5+jMQ2Qwif/lP0UnkuL355aC1wcn74e2PDPQb3vtYL4Hw/m8NOlSk6mNQ66b5vb+uY3ZE6ZE=","=?utf-8?q?1=3BVI1PR0501MB2256=3B23=3AUg?=\n\t=?utf-8?q?rAekq3Luk/AT6yfMEKPdquxXAjBdMoa5GjbpZZC6F1MtG10BnDDeSCGW?=\n\t=?utf-8?q?VPCqUMIYFUb1jaZzw3QcTDE+Wue2Q77gXi5zmZf0R/iX8sz6UySQWAJo?=\n\t=?utf-8?q?VlM8RDUnx0pquQ6IjIxJa1kWhoUDOIrmivEXas9CKwY95dlEQwd87JA7?=\n\t=?utf-8?q?Qz8H7jixGJgsM2RCla89cd/HU+TPcv/noso5ARgrvlMmLB2glR22pfeP?=\n\t=?utf-8?q?prHPuKUj8+TtE90H+mcdsHvFrwIA9TkRhF7y7KgPiLA7PH97jQKdPP1B?=\n\t=?utf-8?q?JtnupchXhFmYEuu9NLF/IV02NEVWpqGLJtOoRdfvWtFJEbjeok2qVaC4?=\n\t=?utf-8?q?u5pwReHoZCpRFI0StCkdez7gVy6zVimht1kpd/ld2jXwn0ZuTGD3nlFq?=\n\t=?utf-8?q?7glULRIGmlH2bT8Us4QAzLwEUbld469J2DqD/nkCWjsQl4VBASRCLKOp?=\n\t=?utf-8?q?vJnQZU7+2UonHQ6cigKNNq5U4/Jn8qsE7oiaJLfFAJIkFaiXOMHNw78L?=\n\t=?utf-8?q?4Q6T95j/pw6hKZVupe0Wfb4SryZTpBZXoCsZlNZ8HbTQwnkyn8M4Tp/z?=\n\t=?utf-8?q?bITQPMNUCbwIGGBmlzAaRgStUisMKvrsl5SsrZG4eLoT9PZODw38ZkFq?=\n\t=?utf-8?q?XTzCeP7cEJFjhxEj9mS8W3Igy1RfDMtn7uB1psvbQHiX9iyyh0iMb/SB?=\n\t=?utf-8?q?rEihmIXA68ffcFb/xDVflC8xiM3huS18cSvA8RVoAfsbyT5JbsG4BoVd?=\n\t=?utf-8?q?m3+9fJz/vreRyd2/i2zfw+P8/UFUBodFbwrnBBMqi2I85eVtmKhMQe2P?=\n\t=?utf-8?q?rI3wyhG2/CthiycCfYnLXEKvtGsHeusy0vKjx8QfbYXLj9VQ7blul7Nz?=\n\t=?utf-8?q?OSINzrkOeCaFM2fNt3XwdHsznfTrHXa2jMA+73gIz1vB9egOGqPNYabH?=\n\t=?utf-8?q?D8nm8x2VTzqJlhhNads3uaoPw2KIUJvHJ8b7K3EzXxBiqTd+nS8SOWcl?=\n\t=?utf-8?q?pVGr0jVUuCZYMVwwo3HSgifbeUuTa5MqWoFJRdP2LZthplAcoqwjoMDL?=\n\t=?utf-8?q?5zpw+3pwHXkLuZPCESac0a6wZARatGhCkJ7KAujlOj+earhsqn/u2rma?=\n\t=?utf-8?q?0xGnf/WeQ5gS50Q+AIenfNZFJyoeYXPjH21BdKp/wJW3gIjHChwganKc?=\n\t=?utf-8?q?s/pZdTuAmPstDLk5/vGg8dbYv5sV0Z1yrdSNIth8V/nYLR/KpioleHU8?=\n\t=?utf-8?q?+Cnqzsy8Mi1cJ77bGJwpZA6QFiB2EBySTXxzGXVay0ab/0J19crL2BEb?=\n\t=?utf-8?q?NYB53y20+Pga/60knwpo4LD1TaAPDufYrVNxJT2NE2tafHHT0Iaio/gI?=\n\t=?utf-8?q?0oAptRu9G3miuZqxPGT57aozo+YCImKB+uvIwR5TXbs/7ffvdDPFveqX?=\n\t=?utf-8?q?nNIQGNhtGMkKdK8CQHJtjivXJa4I1yu2Ztzejs2ogVjawJY9kS0l8Dge?=\n\t=?utf-8?q?RJIUGPPiO6GmvZqrjsE8mGDuvMvaqosQK0xvJr8wqxRC7z9FQH1c79A9?=\n\t=?utf-8?q?H9h0z5Mxlc9BJI?=","1; VI1PR0501MB2256;\n\t6:Oe2AveAGT5wWAm0ojRReti28qsFOzaJg6lWmYglMpyh6UJyVAm019AQ3CRJHPZToq+bp0NlOlu8VzetYnW7XWdccTTJa0lUUlxdh0B7pNaIKbN6D5AZJV7l8PmPrBjjsPce42QBqZQeMyBYp5XblOvh7AWT4nlEUzdtMUugDd/9KVytq3nW/HZONILwa5K4Gq7BZiL5FlkLjwdoVVsDIt0vfEdcGK3JfQxwyG4SMNbMQIsTOFr6B2D9xwhoK/IaJbguxRM9WFI/K7lJ8WV4za8+PSAPvt4VIdZP2+G+ZBLDTJQsyWt7Dk9TIxRwFuq8OWazYHNSyjwbI2wtRJmzL/g==;\n\t5:142AVE4j3Xi4QJXLHRAxGnMtwgYO9LEVDhw8yyoFCUodvG+UIilx37LXHoat2yDt/chfkYaCVtmppNosBXwCbmtBIzN9T9mo0n2UV+CQYJX6U5iWVM48xej6xxOqtsiL+4DiCInxQsgT6RqfH/YDjQ==;\n\t24:yLW0aaaswnunRccCzL788imFtCwxPfze9mPZql7hL2Ietwikcoh7RdbkfZfephd/ILsfd01BaO+WlHgMm4rH8nDuiXBJMNGkGuGDhS4bBrY=;\n\t7:OIsrQdhF5hH+ZtsCTSH28b1meryMXr0KO7T8LvJB3In8j0slgzk6ojxaiy9MQJ4DmX8qL3i4Wk22+CQ48GLEO6PoEyAaWMwzuodYqN8L9dtOiEYW9H7urWFKwUOJ6EgZG7smn3bZcuv7betU0AArxRAVuLARE3pO6XO8jK6Bjf7knXtLeCt6HSrTqfizmnungpAamE9p2ZDoghaKvDuQM7nzbR7KYM3ps2Rv2j3SQcw="],"X-MS-TrafficTypeDiagnostic":"VI1PR0501MB2256:","X-Exchange-Antispam-Report-Test":"UriScan:(17755550239193);","X-Microsoft-Antispam-PRVS":"<VI1PR0501MB225657249B620AE8AA9594D6B5440@VI1PR0501MB2256.eurprd05.prod.outlook.com>","X-Exchange-Antispam-Report-CFA-Test":"BCL:0; PCL:0;\n\tRULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(8121501046)(5005006)(93006095)(93001095)(100000703101)(100105400095)(10201501046)(3231020)(3002001)(6055026)(6041248)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123562025)(20161123564025)(20161123558100)(20161123560025)(20161123555025)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);\n\tSRVR:VI1PR0501MB2256; BCL:0; PCL:0;\n\tRULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);\n\tSRVR:VI1PR0501MB2256; ","X-Forefront-PRVS":"0471B73328","X-Forefront-Antispam-Report":"SFV:NSPM;\n\tSFS:(10009020)(6049001)(6009001)(39860400002)(376002)(346002)(24454002)(54094003)(199003)(189002)(31696002)(189998001)(6486002)(50986999)(4326008)(2950100002)(76176999)(6636002)(5660300001)(54356999)(229853002)(93886005)(77096006)(65806001)(39060400002)(101416001)(47776003)(6246003)(66066001)(106356001)(230700001)(53936002)(65826007)(65956001)(31686004)(33646002)(305945005)(97736004)(105586002)(50466002)(8676002)(7736002)(3846002)(6116002)(23676002)(6666003)(68736007)(81156014)(81166006)(36756003)(86362001)(3260700006)(478600001)(316002)(25786009)(2906002)(53546010)(64126003)(16526018)(58126008)(8936002)(16576012)(83506002)(110136005);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:VI1PR0501MB2256; H:[10.223.0.122];\n\tFPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; ","Received-SPF":"None (protection.outlook.com: mellanox.com does not designate\n\tpermitted sender hosts)","SpamDiagnosticOutput":"1:99","SpamDiagnosticMetadata":"NSPM","X-OriginatorOrg":"Mellanox.com","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"25 Oct 2017 11:24:20.1330\n\t(UTC)","X-MS-Exchange-CrossTenant-Network-Message-Id":"cc7aaf84-6586-4bab-ce74-08d51b9aefee","X-MS-Exchange-CrossTenant-FromEntityHeader":"Hosted","X-MS-Exchange-CrossTenant-Id":"a652971c-7d2e-4d9b-a6a4-d149256f461b","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"VI1PR0501MB2256","X-Spam-Status":"No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tDKIM_VALID_AU,RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Transfer-Encoding":"7bit","Content-Type":"text/plain; charset=\"us-ascii\"; Format=\"flowed\"","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1795942,"web_url":"http://patchwork.ozlabs.org/comment/1795942/","msgid":"<20171030134242.n6gi7mzoxxgjunhh@netronome.com>","list_archive_url":null,"date":"2017-10-30T13:42:43","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":64714,"url":"http://patchwork.ozlabs.org/api/people/64714/","name":"Simon Horman","email":"simon.horman@netronome.com"},"content":"On Wed, Oct 25, 2017 at 02:24:15PM +0300, Roi Dayan wrote:\n> \n> \n> On 27/09/2017 12:08, Simon Horman wrote:\n> > On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n> > > \n> > > \n> > > On 18/09/2017 18:01, Simon Horman wrote:\n> > > > On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n> > > > > From: Paul Blakey <paulb@mellanox.com>\n> > > > > \n> > > > > To be later used to implement ovs action set offloading.\n> > > > > \n> > > > > Signed-off-by: Paul Blakey <paulb@mellanox.com>\n> > > > > Reviewed-by: Roi Dayan <roid@mellanox.com>\n> > > > > ---\n> > > > >   lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n> > > > >   lib/tc.h |  16 +++\n> > > > >   2 files changed, 385 insertions(+), 3 deletions(-)\n> > > > > \n> > > > > diff --git a/lib/tc.c b/lib/tc.c\n> > > > > index c9cada2..743b2ee 100644\n> > > > > --- a/lib/tc.c\n> > > > > +++ b/lib/tc.c\n> > > > > @@ -21,8 +21,10 @@\n> > > > >   #include <errno.h>\n> > > > >   #include <linux/if_ether.h>\n> > > > >   #include <linux/rtnetlink.h>\n> > > > > +#include <linux/tc_act/tc_csum.h>\n> > > > >   #include <linux/tc_act/tc_gact.h>\n> > > > >   #include <linux/tc_act/tc_mirred.h>\n> > > > > +#include <linux/tc_act/tc_pedit.h>\n> > > > >   #include <linux/tc_act/tc_tunnel_key.h>\n> > > > >   #include <linux/tc_act/tc_vlan.h>\n> > > > >   #include <linux/gen_stats.h>\n> > > > > @@ -33,11 +35,14 @@\n> > > > >   #include \"netlink-socket.h\"\n> > > > >   #include \"netlink.h\"\n> > > > >   #include \"openvswitch/ofpbuf.h\"\n> > > > > +#include \"openvswitch/util.h\"\n> > > > >   #include \"openvswitch/vlog.h\"\n> > > > >   #include \"packets.h\"\n> > > > >   #include \"timeval.h\"\n> > > > >   #include \"unaligned.h\"\n> > > > > +#define MAX_PEDIT_OFFSETS 8\n> > > > \n> > > > Why 8?\n> > > We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n> > > pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n> > > that's makes sens. do you suggest we increase it? to what?\n> > \n> > It seems strange to me to place a somewhat arbitrary small limit\n> > when none exists in the pedit API being used. I would at prefer if\n> > it was at least a bigger, say 16 or 32.\n> \n> \n> Hi Simon,\n> \n> Sorry for the late reply due to holidays and vacations.\n> Me & Paul going to go over this and do the fixes needed and\n> also rebase over latest master and run tests again.\n\nLikewise, sorry for not responding earlier (same reason).\n\n> I'll answer what I'm more familiar with now and Paul will continue.\n> The 8 here is too low and you right. We used this definition\n> for allocation of the pedit keys on the stack in\n> nl_msg_put_flower_rewrite_pedits()\n> \n> It was for convenience instead of calculating the maximum possible\n> keys that could exists and allocating it there and freeing it at\n> the end.\n> \n> Increasing it to 32 is probably more than enough and wont waste much.\n\nThanks, that sounds good.\n\n> > > > >   VLOG_DEFINE_THIS_MODULE(tc);\n> > > > >   static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);\n> > > > > @@ -50,6 +55,82 @@ enum tc_offload_policy {\n> > > > >   static enum tc_offload_policy tc_policy = TC_POLICY_NONE;\n> > > > > +struct tc_pedit_key_ex {\n> > > > > +    enum pedit_header_type htype;\n> > > > > +    enum pedit_cmd cmd;\n> > > > > +};\n> > > > > +\n> > > > > +struct flower_key_to_pedit {\n> > > > > +    enum pedit_header_type htype;\n> > > > > +    int flower_offset;\n> > > > > +    int offset;\n> > > > > +    int size;\n> > > > > +};\n> > > > > +\n> > > > > +static struct flower_key_to_pedit flower_pedit_map[] = {\n> > > > > +    {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> > > > > +        12,\n> > > > > +        offsetof(struct tc_flower_key, ipv4.ipv4_src),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> > > > > +        16,\n> > > > > +        offsetof(struct tc_flower_key, ipv4.ipv4_dst),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> > > > > +        8,\n> > > > > +        offsetof(struct tc_flower_key, ipv4.rewrite_ttl),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n> > > > > +        8,\n> > > > > +        offsetof(struct tc_flower_key, ipv6.ipv6_src),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n> > > > > +        24,\n> > > > > +        offsetof(struct tc_flower_key, ipv6.ipv6_dst),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> > > > > +        6,\n> > > > > +        offsetof(struct tc_flower_key, src_mac),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, src_mac)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> > > > > +        0,\n> > > > > +        offsetof(struct tc_flower_key, dst_mac),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, dst_mac)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> > > > > +        12,\n> > > > > +        offsetof(struct tc_flower_key, eth_type),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, eth_type)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n> > > > > +        0,\n> > > > > +        offsetof(struct tc_flower_key, tcp_src),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, tcp_src)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n> > > > > +        2,\n> > > > > +        offsetof(struct tc_flower_key, tcp_dst),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n> > > > > +        0,\n> > > > > +        offsetof(struct tc_flower_key, udp_src),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, udp_src)\n> > > > > +    }, {\n> > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n> > > > > +        2,\n> > > > > +        offsetof(struct tc_flower_key, udp_dst),\n> > > > > +        MEMBER_SIZEOF(struct tc_flower_key, udp_dst)\n> > > > > +    },\n> > > > > +};\n> > > > > +\n> > > > >   struct tcmsg *\n> > > > >   tc_make_request(int ifindex, int type, unsigned int flags,\n> > > > >                   struct ofpbuf *request)\n> > > > > @@ -365,6 +446,96 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {\n> > > > >       }\n> > > > >   }\n> > > > > +static const struct nl_policy pedit_policy[] = {\n> > > > > +            [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,\n> > > > > +                                     .min_len = sizeof(struct tc_pedit),\n> > > > > +                                     .optional = false, },\n> > > > > +            [TCA_PEDIT_KEYS_EX]   = { .type = NL_A_NESTED,\n> > > > > +                                      .optional = false, },\n> > > > > +};\n> > > > > +\n> > > > > +static int\n> > > > > +nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)\n> > > > > +{\n> > > > > +    struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];\n> > > > > +    const struct tc_pedit *pe;\n> > > > > +    const struct tc_pedit_key *keys;\n> > > > > +    const struct nlattr *nla, *keys_ex, *ex_type;\n> > > > > +    const void *keys_attr;\n> > > > > +    char *rewrite_key = (void *) &flower->rewrite.key;\n> > > > > +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n> > > > > +    size_t keys_ex_size, left;\n> > > > > +    int type, i = 0;\n> > > > > +\n> > > > > +    if (!nl_parse_nested(options, pedit_policy, pe_attrs,\n> > > > > +                         ARRAY_SIZE(pedit_policy))) {\n> > > > > +        VLOG_ERR_RL(&error_rl, \"failed to parse pedit action options\");\n> > > > > +        return EPROTO;\n> > > > > +    }\n> > > > > +\n> > > > > +    pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);\n> > > > > +    keys = pe->keys;\n> > > > > +    keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];\n> > > > > +    keys_ex = nl_attr_get(keys_attr);\n> > > > > +    keys_ex_size = nl_attr_get_size(keys_attr);\n> > > > > +\n> > > > > +    NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {\n> > > > > +        if (i >= pe->nkeys) {\n> > > > > +            break;\n> > > > > +        }\n> > > > > +\n> > > > > +        if (nl_attr_type(nla) == TCA_PEDIT_KEY_EX) {\n> > > > > +            ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);\n> > > > > +            type = nl_attr_get_u16(ex_type);\n> > > > > +\n> > > > > +            for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {\n> > > > > +                struct flower_key_to_pedit *m = &flower_pedit_map[j];\n> > > > > +                int flower_off = m->flower_offset;\n> > > > > +                int sz = m->size;\n> > > > > +                int mf = m->offset;\n> > > > > +\n> > > > > +                if (m->htype != type) {\n> > > > > +                   continue;\n> > > > > +                }\n> > > > > +\n> > > > > +                /* check overlap between current pedit key, which is always\n> > > > > +                 * 4 bytes (range [off, off + 3]), and a map entry in\n> > > > > +                 * flower_pedit_map (range [mf, mf + sz - 1]) */\n> > > > > +                if ((keys->off >= mf && keys->off < mf + sz)\n> > > > > +                    || (keys->off + 3 >= mf && keys->off + 3 < mf + sz)) {\n> > > > > +                    int diff = flower_off + (keys->off - mf);\n> > > > > +                    uint32_t *dst = (void *) (rewrite_key + diff);\n> > > > > +                    uint32_t *dst_m = (void *) (rewrite_mask + diff);\n> > > > > +                    uint32_t mask = ~(keys->mask);\n> > > > > +                    uint32_t zero_bits;\n> > > > > +\n> > > > > +                    if (keys->off < mf) {\n> > > > > +                        zero_bits = 8 * (mf - keys->off);\n> > > > > +                        mask &= UINT32_MAX << zero_bits;\n> > > > > +                    } else if (keys->off + 4 > mf + m->size) {\n> > > > > +                        zero_bits = 8 * (keys->off + 4 - mf - m->size);\n> > > > > +                        mask &= UINT32_MAX >> zero_bits;\n> > > > > +                    }\n> > > > > +\n> > > > > +                    *dst_m |= mask;\n> > > > > +                    *dst |= keys->val & mask;\n> > > > > +                }\n> > > > > +            }\n> > > > \n> > > > If I understand the above correctly it is designed to make\n> > > > pedit actions disjoint. If so, why is that necessary? >\n> > > \n> > > It's not, as a single flower key rewrite can be split to multiple pedit\n> > > actions it finds the overlap between a flower key and a pedit action, if\n> > > they do overlap it translates it to the correct offset and masks it out.\n> > \n> > Thanks, understood.\n> > \n> > > \n> > > > > +        } else {\n> > > > > +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n> > > > > +                        nl_attr_type(nla));\n> > > > > +            return EOPNOTSUPP;\n> > > > > +        }\n> > > > \n> > > > I think the code could exit early here as\n> > > > nl_msg_put_flower_rewrite_pedits() does below.\n> > > > \n> > > \n> > > Sorry, didn't understand. can you give an example?\n> > > \n> > \n> > I meant something like this.\n> > \n> >              if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n> >                  VLOG_ERR_RL(...);\n> >                  return EOPNOTSUPP;\n> >              }\n> \n> understood. we'll do that. thanks.\n> \n> > \n> > \t    /* Overlap detection code goes here */\n> > \n> > > > \n> > > > > +\n> > > > > +        keys++;\n> > > > > +        i++;\n> > > > > +    }\n> > > > > +\n> > > > > +    flower->rewrite.rewrite = true;\n> > > > > +\n> > > > > +    return 0;\n> > > > > +}\n> > > > > +\n> > > > >   static const struct nl_policy tunnel_key_policy[] = {\n> > > > >       [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,\n> > > > >                                  .min_len = sizeof(struct tc_tunnel_key),\n> > > > > @@ -608,6 +779,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)\n> > > > >           nl_parse_act_vlan(act_options, flower);\n> > > > >       } else if (!strcmp(act_kind, \"tunnel_key\")) {\n> > > > >           nl_parse_act_tunnel_key(act_options, flower);\n> > > > > +    } else if (!strcmp(act_kind, \"pedit\")) {\n> > > > > +        nl_parse_act_pedit(act_options, flower);\n> > > > > +    } else if (!strcmp(act_kind, \"csum\")) {\n> > > > > +        /* not doing anything for now, ovs has an implicit csum recalculation\n> > > > > +         * with rewriting of packet headers (translating of pedit acts). */\n> > > > \n> > > > I wonder if the absence of a csum action when needed (by TC)\n> > > > should be treated as an error >\n> > > \n> > > Do you mean validating csum flags from each protocol and such (like in put)?\n> > \n> > Yes, I think so.\n> > \n> > In OvS (without TC acceleration) csum recalculation is implicit\n> > but with TC an explicit csum update action is required. I see\n> > in your code you are handling this by adding csum actions to TC actions\n> > when translating from OvS DPIF actions. And in the reverse (above) csum\n> > actions are simply ignored.\n> > \n> > What I am wondering is if when translating TC actions to OvS DPIF actions\n> > you should track if the TC actions should include a csum rule because\n> > of other actions and treat its absence as an error.\n> > \n> > > \n> > > > >       } else {\n> > > > >           VLOG_ERR_RL(&error_rl, \"unknown tc action kind: %s\", act_kind);\n> > > > >           return EINVAL;\n> > > > > @@ -809,6 +985,48 @@ tc_get_tc_cls_policy(enum tc_offload_policy policy)\n> > > > >   }\n> > > > >   static void\n> > > > > +nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags)\n> > > > > +{\n> > > > > +    size_t offset;\n> > > > > +\n> > > > > +    nl_msg_put_string(request, TCA_ACT_KIND, \"csum\");\n> > > > > +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n> > > > > +    {\n> > > > > +        struct tc_csum parm = { .action = TC_ACT_PIPE,\n> > > > > +                                .update_flags = flags };\n> > > > > +\n> > > > > +        nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);\n> > > > > +    }\n> > > > > +    nl_msg_end_nested(request, offset);\n> > > > > +}\n> > > > > +\n> > > > > +static void\n> > > > > +nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,\n> > > > > +                     struct tc_pedit_key_ex *ex)\n> > > > > +{\n> > > > > +    size_t ksize = sizeof *parm + (parm->nkeys * sizeof(struct tc_pedit_key));\n> > > > \n> > > > Are there unnecessary () on the line above?\n> > > No, I'll remove them.\n> > > \n> > > > \n> > > > > +    size_t offset, offset_keys_ex, offset_key;\n> > > > > +    int i;\n> > > > > +\n> > > > > +    nl_msg_put_string(request, TCA_ACT_KIND, \"pedit\");\n> > > > > +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n> > > > > +    {\n> > > > > +        parm->action = TC_ACT_PIPE;\n> > > > > +\n> > > > > +        nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);\n> > > > > +        offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);\n> > > > > +        for (i = 0; i < parm->nkeys; i++, ex++) {\n> > > > > +            offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);\n> > > > > +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);\n> > > > > +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);\n> > > > > +            nl_msg_end_nested(request, offset_key);\n> > > > > +        }\n> > > > > +        nl_msg_end_nested(request, offset_keys_ex);\n> > > > > +    }\n> > > > > +    nl_msg_end_nested(request, offset);\n> > > > > +}\n> > > > > +\n> > > > > +static void\n> > > > >   nl_msg_put_act_push_vlan(struct ofpbuf *request, uint16_t vid, uint8_t prio)\n> > > > >   {\n> > > > >       size_t offset;\n> > > > > @@ -930,7 +1148,127 @@ nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {\n> > > > >       }\n> > > > >   }\n> > > > > +/* Given flower, a key_to_pedit map entry, calculates the rest,\n> > > > > + * where:\n> > > > > + *\n> > > > > + * mask, data - pointers of where read the first word of flower->key/mask.\n> > > > > + * current_offset - which offset to use for the first pedit action.\n> > > > > + * cnt - max pedits actions to use.\n> > > > > + * first_word_mask/last_word_mask - the mask to use for the first/last read\n> > > > > + * (as we read entire words). */\n> > > > >   static void\n> > > > > +calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m,\n> > > > > +             int *cur_offset, int *cnt, uint32_t *last_word_mask,\n> > > > > +             uint32_t *first_word_mask, uint32_t **mask, uint32_t **data)\n> > > > > +{\n> > > > > +    int start_offset, max_offset, total_size;\n> > > > > +    int diff, right_zero_bits, left_zero_bits;\n> > > > > +    char *rewrite_key = (void *) &flower->rewrite.key;\n> > > > > +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n> > > > > +\n> > > > > +    max_offset = m->offset + m->size;\n> > > > > +    start_offset = ROUND_DOWN(m->offset, 4);\n> > > > > +    diff = m->offset - start_offset;\n> > > > > +    total_size = max_offset - start_offset;\n> > > > > +    right_zero_bits = 8 * (4 - (max_offset % 4));\n> > > > > +    left_zero_bits = 8 * (m->offset - start_offset);\n> > > > > +\n> > > > > +    *cur_offset = start_offset;\n> > > > > +    *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);\n> > > > > +    *last_word_mask = UINT32_MAX >> right_zero_bits;\n> > > > > +    *first_word_mask = UINT32_MAX << left_zero_bits;\n> > > > > +    *data = (void *) (rewrite_key + m->flower_offset - diff);\n> > > > > +    *mask = (void *) (rewrite_mask + m->flower_offset - diff);\n> > > > \n> > > > The type of *data and *mask is uint32_t *.\n> > > > Why not cast to that type?\n> > > \n> > > It's to avoid warning of increasing pointer alignment (-Wcast-align).\n> > \n> > It sounds like the warning should be addressed rather than overridden using\n> > a cast.\n> > \n> > > > \n> > > > > +}\n> > > > > +\n> > > > > +static inline void\n> > > > > +csum_update_flag(struct tc_flower *flower,\n> > > > > +                 enum pedit_header_type htype) {\n> > > > \n> > > > I think the above two lines could be one.\n> > > > \n> > > > > +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4) {\n> > > > \n> > > > A case statement might be nicer here.\n> > > \n> > > Right, thanks.\n> > > \n> > > > \n> > > > > +        flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;\n> > > > > +    }\n> > > > > +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4\n> > > > > +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP6\n> > > > > +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_TCP\n> > > > > +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_UDP) {\n> > > > > +        if (flower->key.ip_proto == IPPROTO_TCP) {\n> > > > > +            flower->mask.ip_proto = UINT8_MAX;\n> > > > \n> > > > What if the mask was not UINT8_MAX to start with?\n> > > > Doesn't this create a different flow?\n> > > \n> > > This is so the checksum will be strict (not setting/recalc udp checksum on\n> > > non udp packets). It creates a more specific flow, a subset of the original.\n> > > This is fine as datapath is free to ignore a mask, which is the same as a\n> > > full mask we've set.\n> > \n> > I'm not sure that I understand why its fine for the datapath to ignore the\n> > mask.\n> \n> I'll try to explain.\n> When we want the HW to recalc the csum we need to also do matching on\n> it. We do that for TCP, UDP, ICMP.\n\nOk, that makes sense. But I am concerned that the mask of the offloaded\nflow no longer matches the mask of the flow OvS created. What are the\nimplications of that?\n\n> > > > > +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;\n> > > > > +        } else if (flower->key.ip_proto == IPPROTO_UDP) {\n> > > > > +            flower->mask.ip_proto = UINT8_MAX;\n> > > > > +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;\n> > > > > +        } else if (flower->key.ip_proto == IPPROTO_ICMP\n> > > > > +                   || flower->key.ip_proto == IPPROTO_ICMPV6) {\n> > > > > +            flower->mask.ip_proto = UINT8_MAX;\n> > > > > +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;\n> > > > > +        }\n> > > > > +    }\n> > > > > +}\n> > > > > +\n> > > > > +static int\n> > > > > +nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,\n> > > > > +                                 struct tc_flower *flower)\n> > > > > +{\n> > > > > +    struct {\n> > > > > +        struct tc_pedit sel;\n> > > > > +        struct tc_pedit_key keys[MAX_PEDIT_OFFSETS];\n> > > > > +        struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];\n> > > > > +    } sel = {\n> > > > > +        .sel = {\n> > > > > +            .nkeys = 0\n> > > > > +        }\n> > > > > +    };\n> > > > > +    int i, j;\n> > > > > +\n> > > > > +    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {\n> > > > > +        struct flower_key_to_pedit *m = &flower_pedit_map[i];\n> > > > > +        struct tc_pedit_key *pedit_key = NULL;\n> > > > > +        struct tc_pedit_key_ex *pedit_key_ex = NULL;\n> > > > > +        uint32_t *mask, *data, first_word_mask, last_word_mask;\n> > > > > +        int cnt = 0, cur_offset = 0;\n> > > > > +\n> > > > > +        if (!m->size) {\n> > > > > +            continue;\n> > > > > +        }\n> > > > > +\n> > > > > +        calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask,\n> > > > > +                     &first_word_mask, &mask, &data);\n> > > > > +\n> > > > > +        for (j = 0; j < cnt; j++,  mask++, data++, cur_offset += 4) {\n> > > > > +            uint32_t mask_word = *mask;\n> > > > > +\n> > > > > +            if (j == 0) {\n> > > > > +                mask_word &= first_word_mask;\n> > > > > +            }\n> > > > > +            if (j == cnt - 1) {\n> > > > > +                mask_word &= last_word_mask;\n> > > > > +            }\n> > > > > +            if (!mask_word) {\n> > > > > +                continue;\n> > > > > +            }\n> > > > > +            if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {\n> > > > > +                VLOG_WARN_RL(&error_rl, \"reached too many pedit offsets: %d\",\n> > > > > +                             MAX_PEDIT_OFFSETS);\n> > > > > +                return EOPNOTSUPP;\n> > > > > +            }\n> > > > > +\n> > > > > +            pedit_key = &sel.keys[sel.sel.nkeys];\n> > > > > +            pedit_key_ex = &sel.keys_ex[sel.sel.nkeys];\n> > > > > +            pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;\n> > > > > +            pedit_key_ex->htype = m->htype;\n> > > > > +            pedit_key->off = cur_offset;\n> > > > > +            pedit_key->mask = ~mask_word;\n> > > > > +            pedit_key->val = *data & mask_word;\n> > > > > +            sel.sel.nkeys++;\n> > > > > +            csum_update_flag(flower, m->htype);\n> > > > > +        }\n> > > > > +    }\n> > > > > +    nl_msg_put_act_pedit(request, &sel.sel, sel.keys_ex);\n> > > > > +\n> > > > > +    return 0;\n> > > > > +}\n> > > > > +\n> > > > > +static int\n> > > > >   nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> > > > >   {\n> > > > >       size_t offset;\n> > > > > @@ -939,7 +1277,20 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> > > > >       offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);\n> > > > >       {\n> > > > >           uint16_t act_index = 1;\n> > > > > +        int error;\n> > > > > +        if (flower->rewrite.rewrite) {\n> > > > > +            act_offset = nl_msg_start_nested(request, act_index++);\n> > > > > +            error = nl_msg_put_flower_rewrite_pedits(request, flower);\n> > > > > +            if (error) {\n> > > > > +                return error;\n> > > > > +            }\n> > > > > +            nl_msg_end_nested(request, act_offset);\n> > > > > +\n> > > > > +            act_offset = nl_msg_start_nested(request, act_index++);\n> > > > > +            nl_msg_put_act_csum(request, flower->csum_update_flags);\n> > > > > +            nl_msg_end_nested(request, act_offset);\n> > > > > +        }\n> > > > >           if (flower->set.set) {\n> > > > >               act_offset = nl_msg_start_nested(request, act_index++);\n> > > > >               nl_msg_put_act_tunnel_key_set(request, flower->set.id,\n> > > > > @@ -980,6 +1331,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> > > > >           }\n> > > > >       }\n> > > > >       nl_msg_end_nested(request, offset);\n> > > > > +\n> > > > > +    return 0;\n> > > > >   }\n> > > > >   static void\n> > > > > @@ -1021,11 +1374,19 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)\n> > > > >       nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \\\n> > > > >                               &flower->mask.member, sizeof flower->key.member)\n> > > > > -static void\n> > > > > +static int\n> > > > >   nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n> > > > >   {\n> > > > > +\n> > > > >       uint16_t host_eth_type = ntohs(flower->key.eth_type);\n> > > > >       bool is_vlan = (host_eth_type == ETH_TYPE_VLAN);\n> > > > > +    int err;\n> > > > > +\n> > > > > +    /* need to parse acts first as some acts require changing the matching */\n> > > > \n> > > > This seems strange to me.\n> > > \n> > > from the strict (normalized?) header checksum.\n> > \n> > I think this code relates to setting flower->key.ip_proto == IPPROTO_TCP\n> > above. Is that correct. Are there any other cases?\n> \n> yes and also for UDP and ICMP. as explained above.\n> So going over the acts in header rewrite case we might want to signal the HW\n> recalc csum and we need matching on those fields that require new\n> csum so the matching mask being updated. this is why we parse the acts\n> first.\n\nThanks, understood.\n\n> > > > > +    err  = nl_msg_put_flower_acts(request, flower);\n> > > > > +    if (err) {\n> > > > > +        return err;\n> > > > > +    }\n> > > > >       if (is_vlan) {\n> > > > >           host_eth_type = ntohs(flower->key.encap_eth_type);\n> > > > > @@ -1083,7 +1444,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n> > > > >           nl_msg_put_flower_tunnel(request, flower);\n> > > > >       }\n> > > > > -    nl_msg_put_flower_acts(request, flower);\n> > > > > +    return 0;\n> > > > >   }\n> > > > >   int\n> > > > > @@ -1106,7 +1467,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n> > > > >       nl_msg_put_string(&request, TCA_KIND, \"flower\");\n> > > > >       basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);\n> > > > >       {\n> > > > > -        nl_msg_put_flower_options(&request, flower);\n> > > > > +        error = nl_msg_put_flower_options(&request, flower);\n> > > > > +\n> > > > > +        if (error) {\n> > > > > +            ofpbuf_uninit(&request);\n> > > > > +            return error;\n> > > > > +        }\n> > > > >       }\n> > > > >       nl_msg_end_nested(&request, basic_offset);\n> > > > > diff --git a/lib/tc.h b/lib/tc.h\n> > > > > index 6c69b79..7876051 100644\n> > > > > --- a/lib/tc.h\n> > > > > +++ b/lib/tc.h\n> > > > > @@ -96,6 +96,7 @@ struct tc_flower_key {\n> > > > >       struct {\n> > > > >           ovs_be32 ipv4_src;\n> > > > >           ovs_be32 ipv4_dst;\n> > > > > +        uint8_t rewrite_ttl;\n> > > > >       } ipv4;\n> > > > >       struct {\n> > > > >           struct in6_addr ipv6_src;\n> > > > > @@ -120,6 +121,14 @@ struct tc_flower {\n> > > > >       uint64_t lastused;\n> > > > >       struct {\n> > > > > +        bool rewrite;\n> > > > > +        struct tc_flower_key key;\n> > > > > +        struct tc_flower_key mask;\n> > > > > +    } rewrite;\n> > > > > +\n> > > > > +    uint32_t csum_update_flags;\n> > > > > +\n> > > > > +    struct {\n> > > > >           bool set;\n> > > > >           ovs_be64 id;\n> > > > >           ovs_be16 tp_src;\n> > > > > @@ -152,6 +161,13 @@ struct tc_flower {\n> > > > >       struct tc_cookie act_cookie;\n> > > > >   };\n> > > > > +/* assert that if we overflow with a masked write of uint32_t to the last byte\n> > > > > + * of flower.rewrite we overflow inside struct flower.\n> > > > > + * shouldn't happen unless someone moves rewrite to the end of flower */\n> > > > > +BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)\n> > > > > +                  + MEMBER_SIZEOF(struct tc_flower, rewrite)\n> > > > > +                  + sizeof(uint32_t) - 2 < sizeof(struct tc_flower));\n> > > > > +\n> > > > >   int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n> > > > >                         struct tc_flower *flower);\n> > > > >   int tc_del_filter(int ifindex, int prio, int handle);\n> > > > > -- \n> > > > > 2.7.5\n> > > > >","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=netronome-com.20150623.gappssmtp.com\n\theader.i=@netronome-com.20150623.gappssmtp.com\n\theader.b=\"qCSdUuRF\"; dkim-atps=neutral"],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3yQbJt4gCzz9sPs\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 31 Oct 2017 00:42:53 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id DAAF7BD9;\n\tMon, 30 Oct 2017 13:42:49 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 091C6416\n\tfor <dev@openvswitch.org>; Mon, 30 Oct 2017 13:42:49 +0000 (UTC)","from mail-wm0-f51.google.com (mail-wm0-f51.google.com\n\t[74.125.82.51])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 3C498484\n\tfor <dev@openvswitch.org>; Mon, 30 Oct 2017 13:42:47 +0000 (UTC)","by mail-wm0-f51.google.com with SMTP id s66so15872762wmf.5\n\tfor <dev@openvswitch.org>; Mon, 30 Oct 2017 06:42:47 -0700 (PDT)","from netronome.com ([217.111.208.18])\n\tby smtp.gmail.com with ESMTPSA id\n\ts67sm3577951wmd.23.2017.10.30.06.42.44\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tMon, 30 Oct 2017 06:42:44 -0700 (PDT)"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=netronome-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=02rZ1CWtjBXX1C6kDdqAS9O9J7jborIh/Wqpgypv/A8=;\n\tb=qCSdUuRFU/B8djtzLYV1+kbE2RZO05ooABUF0Ioh86Am9Mv6ER8bRUSY2fCVPcITbK\n\tQ9yC6YJW/Nlj1l6KhDR/znexApA809M9t3OjuEqMgZEwYtxC0M9BqIXpy9oyTIkzaPNL\n\t4UcQGBQYMSZbtUx3jMLL80CiJgmtImlLPd9tHpQTM+qLPOXaS9aIaQid+EYBwJm9yxc8\n\tR8eInTVaDpZplf18PlMklJUtSg+cs+qXidqlobgpZn8FnJLVirk4taSYolaXnyG2oJRG\n\tzyK3m9x3IQoxHtmZIfoWulkmvqIw8PZOZdBEeEyuiCrYJcpKnQIQsBj0/GPXXBRsmxE/\n\t1klA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=02rZ1CWtjBXX1C6kDdqAS9O9J7jborIh/Wqpgypv/A8=;\n\tb=WXHj7pltFGc5Z8JB66IkOl/wfAskGJ+tthZhs39pcKClHObeox0xsqHIjRvo4KxRVM\n\tmzo+Nn5ok+Roex/pFJnh/vhiIeMKrObYT4F18p2PeNdhqaz1Tm8K/htDSZt4PuKhYWRm\n\tjc9DA8Dp98/cyA21qy8CgzFEIjmTP0qFmD7xUUTYGoR0vCRh+Ji7UKsSMkFWFlAWirhd\n\tm/QP4xBTYayMK+te0Tz6ei32nST2t9LE7mSXhuAyQejshkw1DnAoX3fuMnrPUlvnNKUi\n\tvC5chDmakl6lcclNE5/UaZxCzYwN7a1lAxvDF8if1iVGL7b0Cogbk6Uyo/MJsHKBbr52\n\tDIIQ==","X-Gm-Message-State":"AMCzsaUf1t6DaOExAFG9W9v49Apm0K9gsqg2U2lSCU2mHNPypkbQmLu4\n\tPoSwPF1hYdoAxgwc2U0oj+MlGA==","X-Google-Smtp-Source":"ABhQp+SjTdVl47SeWStOlgGvnwsTYdT8FjYKpgNVSyOYle+NvSLJTJOQs6i27pu8F5FLIfGzHRDIJw==","X-Received":"by 10.28.238.74 with SMTP id m71mr3610537wmh.83.1509370965477;\n\tMon, 30 Oct 2017 06:42:45 -0700 (PDT)","Date":"Mon, 30 Oct 2017 14:42:43 +0100","From":"Simon Horman <simon.horman@netronome.com>","To":"Roi Dayan <roid@mellanox.com>","Message-ID":"<20171030134242.n6gi7mzoxxgjunhh@netronome.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>\n\t<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>","User-Agent":"NeoMutt/20170113 (1.7.2)","X-Spam-Status":"No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tRCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1796451,"web_url":"http://patchwork.ozlabs.org/comment/1796451/","msgid":"<30dcb2d7-34b0-8f84-7c17-205aabbd8238@mellanox.com>","list_archive_url":null,"date":"2017-10-31T07:20:55","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":70001,"url":"http://patchwork.ozlabs.org/api/people/70001/","name":"Paul Blakey","email":"paulb@mellanox.com"},"content":"On 30/10/2017 15:42, Simon Horman wrote:\n> On Wed, Oct 25, 2017 at 02:24:15PM +0300, Roi Dayan wrote:\n>>\n>>\n>> On 27/09/2017 12:08, Simon Horman wrote:\n>>> On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n>>>>\n>>>>\n>>>> On 18/09/2017 18:01, Simon Horman wrote:\n>>>>> On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n>>>>>> From: Paul Blakey <paulb@mellanox.com>\n>>>>>>\n>>>>>> To be later used to implement ovs action set offloading.\n>>>>>>\n>>>>>> Signed-off-by: Paul Blakey <paulb@mellanox.com>\n>>>>>> Reviewed-by: Roi Dayan <roid@mellanox.com>\n>>>>>> ---\n>>>>>>    lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n>>>>>>    lib/tc.h |  16 +++\n>>>>>>    2 files changed, 385 insertions(+), 3 deletions(-)\n>>>>>>\n>>>>>> diff --git a/lib/tc.c b/lib/tc.c\n>>>>>> index c9cada2..743b2ee 100644\n>>>>>> --- a/lib/tc.c\n>>>>>> +++ b/lib/tc.c\n>>>>>> @@ -21,8 +21,10 @@\n>>>>>>    #include <errno.h>\n>>>>>>    #include <linux/if_ether.h>\n>>>>>>    #include <linux/rtnetlink.h>\n>>>>>> +#include <linux/tc_act/tc_csum.h>\n>>>>>>    #include <linux/tc_act/tc_gact.h>\n>>>>>>    #include <linux/tc_act/tc_mirred.h>\n>>>>>> +#include <linux/tc_act/tc_pedit.h>\n>>>>>>    #include <linux/tc_act/tc_tunnel_key.h>\n>>>>>>    #include <linux/tc_act/tc_vlan.h>\n>>>>>>    #include <linux/gen_stats.h>\n>>>>>> @@ -33,11 +35,14 @@\n>>>>>>    #include \"netlink-socket.h\"\n>>>>>>    #include \"netlink.h\"\n>>>>>>    #include \"openvswitch/ofpbuf.h\"\n>>>>>> +#include \"openvswitch/util.h\"\n>>>>>>    #include \"openvswitch/vlog.h\"\n>>>>>>    #include \"packets.h\"\n>>>>>>    #include \"timeval.h\"\n>>>>>>    #include \"unaligned.h\"\n>>>>>> +#define MAX_PEDIT_OFFSETS 8\n>>>>>\n>>>>> Why 8?\n>>>> We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n>>>> pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n>>>> that's makes sens. do you suggest we increase it? to what?\n>>>\n>>> It seems strange to me to place a somewhat arbitrary small limit\n>>> when none exists in the pedit API being used. I would at prefer if\n>>> it was at least a bigger, say 16 or 32.\n>>\n>>\n>> Hi Simon,\n>>\n>> Sorry for the late reply due to holidays and vacations.\n>> Me & Paul going to go over this and do the fixes needed and\n>> also rebase over latest master and run tests again.\n> \n> Likewise, sorry for not responding earlier (same reason).\n> \n>> I'll answer what I'm more familiar with now and Paul will continue.\n>> The 8 here is too low and you right. We used this definition\n>> for allocation of the pedit keys on the stack in\n>> nl_msg_put_flower_rewrite_pedits()\n>>\n>> It was for convenience instead of calculating the maximum possible\n>> keys that could exists and allocating it there and freeing it at\n>> the end.\n>>\n>> Increasing it to 32 is probably more than enough and wont waste much.\n> \n> Thanks, that sounds good.\n> \n>>>>>>    VLOG_DEFINE_THIS_MODULE(tc);\n>>>>>>    static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);\n>>>>>> @@ -50,6 +55,82 @@ enum tc_offload_policy {\n>>>>>>    static enum tc_offload_policy tc_policy = TC_POLICY_NONE;\n>>>>>> +struct tc_pedit_key_ex {\n>>>>>> +    enum pedit_header_type htype;\n>>>>>> +    enum pedit_cmd cmd;\n>>>>>> +};\n>>>>>> +\n>>>>>> +struct flower_key_to_pedit {\n>>>>>> +    enum pedit_header_type htype;\n>>>>>> +    int flower_offset;\n>>>>>> +    int offset;\n>>>>>> +    int size;\n>>>>>> +};\n>>>>>> +\n>>>>>> +static struct flower_key_to_pedit flower_pedit_map[] = {\n>>>>>> +    {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>>>>>> +        12,\n>>>>>> +        offsetof(struct tc_flower_key, ipv4.ipv4_src),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>>>>>> +        16,\n>>>>>> +        offsetof(struct tc_flower_key, ipv4.ipv4_dst),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n>>>>>> +        8,\n>>>>>> +        offsetof(struct tc_flower_key, ipv4.rewrite_ttl),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n>>>>>> +        8,\n>>>>>> +        offsetof(struct tc_flower_key, ipv6.ipv6_src),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n>>>>>> +        24,\n>>>>>> +        offsetof(struct tc_flower_key, ipv6.ipv6_dst),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>>>>>> +        6,\n>>>>>> +        offsetof(struct tc_flower_key, src_mac),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, src_mac)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>>>>>> +        0,\n>>>>>> +        offsetof(struct tc_flower_key, dst_mac),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, dst_mac)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n>>>>>> +        12,\n>>>>>> +        offsetof(struct tc_flower_key, eth_type),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, eth_type)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n>>>>>> +        0,\n>>>>>> +        offsetof(struct tc_flower_key, tcp_src),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, tcp_src)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n>>>>>> +        2,\n>>>>>> +        offsetof(struct tc_flower_key, tcp_dst),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n>>>>>> +        0,\n>>>>>> +        offsetof(struct tc_flower_key, udp_src),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, udp_src)\n>>>>>> +    }, {\n>>>>>> +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n>>>>>> +        2,\n>>>>>> +        offsetof(struct tc_flower_key, udp_dst),\n>>>>>> +        MEMBER_SIZEOF(struct tc_flower_key, udp_dst)\n>>>>>> +    },\n>>>>>> +};\n>>>>>> +\n>>>>>>    struct tcmsg *\n>>>>>>    tc_make_request(int ifindex, int type, unsigned int flags,\n>>>>>>                    struct ofpbuf *request)\n>>>>>> @@ -365,6 +446,96 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {\n>>>>>>        }\n>>>>>>    }\n>>>>>> +static const struct nl_policy pedit_policy[] = {\n>>>>>> +            [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,\n>>>>>> +                                     .min_len = sizeof(struct tc_pedit),\n>>>>>> +                                     .optional = false, },\n>>>>>> +            [TCA_PEDIT_KEYS_EX]   = { .type = NL_A_NESTED,\n>>>>>> +                                      .optional = false, },\n>>>>>> +};\n>>>>>> +\n>>>>>> +static int\n>>>>>> +nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)\n>>>>>> +{\n>>>>>> +    struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];\n>>>>>> +    const struct tc_pedit *pe;\n>>>>>> +    const struct tc_pedit_key *keys;\n>>>>>> +    const struct nlattr *nla, *keys_ex, *ex_type;\n>>>>>> +    const void *keys_attr;\n>>>>>> +    char *rewrite_key = (void *) &flower->rewrite.key;\n>>>>>> +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n>>>>>> +    size_t keys_ex_size, left;\n>>>>>> +    int type, i = 0;\n>>>>>> +\n>>>>>> +    if (!nl_parse_nested(options, pedit_policy, pe_attrs,\n>>>>>> +                         ARRAY_SIZE(pedit_policy))) {\n>>>>>> +        VLOG_ERR_RL(&error_rl, \"failed to parse pedit action options\");\n>>>>>> +        return EPROTO;\n>>>>>> +    }\n>>>>>> +\n>>>>>> +    pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);\n>>>>>> +    keys = pe->keys;\n>>>>>> +    keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];\n>>>>>> +    keys_ex = nl_attr_get(keys_attr);\n>>>>>> +    keys_ex_size = nl_attr_get_size(keys_attr);\n>>>>>> +\n>>>>>> +    NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {\n>>>>>> +        if (i >= pe->nkeys) {\n>>>>>> +            break;\n>>>>>> +        }\n>>>>>> +\n>>>>>> +        if (nl_attr_type(nla) == TCA_PEDIT_KEY_EX) {\n>>>>>> +            ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);\n>>>>>> +            type = nl_attr_get_u16(ex_type);\n>>>>>> +\n>>>>>> +            for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {\n>>>>>> +                struct flower_key_to_pedit *m = &flower_pedit_map[j];\n>>>>>> +                int flower_off = m->flower_offset;\n>>>>>> +                int sz = m->size;\n>>>>>> +                int mf = m->offset;\n>>>>>> +\n>>>>>> +                if (m->htype != type) {\n>>>>>> +                   continue;\n>>>>>> +                }\n>>>>>> +\n>>>>>> +                /* check overlap between current pedit key, which is always\n>>>>>> +                 * 4 bytes (range [off, off + 3]), and a map entry in\n>>>>>> +                 * flower_pedit_map (range [mf, mf + sz - 1]) */\n>>>>>> +                if ((keys->off >= mf && keys->off < mf + sz)\n>>>>>> +                    || (keys->off + 3 >= mf && keys->off + 3 < mf + sz)) {\n>>>>>> +                    int diff = flower_off + (keys->off - mf);\n>>>>>> +                    uint32_t *dst = (void *) (rewrite_key + diff);\n>>>>>> +                    uint32_t *dst_m = (void *) (rewrite_mask + diff);\n>>>>>> +                    uint32_t mask = ~(keys->mask);\n>>>>>> +                    uint32_t zero_bits;\n>>>>>> +\n>>>>>> +                    if (keys->off < mf) {\n>>>>>> +                        zero_bits = 8 * (mf - keys->off);\n>>>>>> +                        mask &= UINT32_MAX << zero_bits;\n>>>>>> +                    } else if (keys->off + 4 > mf + m->size) {\n>>>>>> +                        zero_bits = 8 * (keys->off + 4 - mf - m->size);\n>>>>>> +                        mask &= UINT32_MAX >> zero_bits;\n>>>>>> +                    }\n>>>>>> +\n>>>>>> +                    *dst_m |= mask;\n>>>>>> +                    *dst |= keys->val & mask;\n>>>>>> +                }\n>>>>>> +            }\n>>>>>\n>>>>> If I understand the above correctly it is designed to make\n>>>>> pedit actions disjoint. If so, why is that necessary? >\n>>>>\n>>>> It's not, as a single flower key rewrite can be split to multiple pedit\n>>>> actions it finds the overlap between a flower key and a pedit action, if\n>>>> they do overlap it translates it to the correct offset and masks it out.\n>>>\n>>> Thanks, understood.\n>>>\n>>>>\n>>>>>> +        } else {\n>>>>>> +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n>>>>>> +                        nl_attr_type(nla));\n>>>>>> +            return EOPNOTSUPP;\n>>>>>> +        }\n>>>>>\n>>>>> I think the code could exit early here as\n>>>>> nl_msg_put_flower_rewrite_pedits() does below.\n>>>>>\n>>>>\n>>>> Sorry, didn't understand. can you give an example?\n>>>>\n>>>\n>>> I meant something like this.\n>>>\n>>>               if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n>>>                   VLOG_ERR_RL(...);\n>>>                   return EOPNOTSUPP;\n>>>               }\n>>\n>> understood. we'll do that. thanks.\n>>\n>>>\n>>> \t    /* Overlap detection code goes here */\n>>>\n>>>>>\n>>>>>> +\n>>>>>> +        keys++;\n>>>>>> +        i++;\n>>>>>> +    }\n>>>>>> +\n>>>>>> +    flower->rewrite.rewrite = true;\n>>>>>> +\n>>>>>> +    return 0;\n>>>>>> +}\n>>>>>> +\n>>>>>>    static const struct nl_policy tunnel_key_policy[] = {\n>>>>>>        [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,\n>>>>>>                                   .min_len = sizeof(struct tc_tunnel_key),\n>>>>>> @@ -608,6 +779,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)\n>>>>>>            nl_parse_act_vlan(act_options, flower);\n>>>>>>        } else if (!strcmp(act_kind, \"tunnel_key\")) {\n>>>>>>            nl_parse_act_tunnel_key(act_options, flower);\n>>>>>> +    } else if (!strcmp(act_kind, \"pedit\")) {\n>>>>>> +        nl_parse_act_pedit(act_options, flower);\n>>>>>> +    } else if (!strcmp(act_kind, \"csum\")) {\n>>>>>> +        /* not doing anything for now, ovs has an implicit csum recalculation\n>>>>>> +         * with rewriting of packet headers (translating of pedit acts). */\n>>>>>\n>>>>> I wonder if the absence of a csum action when needed (by TC)\n>>>>> should be treated as an error >\n>>>>\n>>>> Do you mean validating csum flags from each protocol and such (like in put)?\n>>>\n>>> Yes, I think so.\n>>>\n>>> In OvS (without TC acceleration) csum recalculation is implicit\n>>> but with TC an explicit csum update action is required. I see\n>>> in your code you are handling this by adding csum actions to TC actions\n>>> when translating from OvS DPIF actions. And in the reverse (above) csum\n>>> actions are simply ignored.\n>>>\n>>> What I am wondering is if when translating TC actions to OvS DPIF actions\n>>> you should track if the TC actions should include a csum rule because\n>>> of other actions and treat its absence as an error.\n>>>\n>>>>\n>>>>>>        } else {\n>>>>>>            VLOG_ERR_RL(&error_rl, \"unknown tc action kind: %s\", act_kind);\n>>>>>>            return EINVAL;\n>>>>>> @@ -809,6 +985,48 @@ tc_get_tc_cls_policy(enum tc_offload_policy policy)\n>>>>>>    }\n>>>>>>    static void\n>>>>>> +nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags)\n>>>>>> +{\n>>>>>> +    size_t offset;\n>>>>>> +\n>>>>>> +    nl_msg_put_string(request, TCA_ACT_KIND, \"csum\");\n>>>>>> +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n>>>>>> +    {\n>>>>>> +        struct tc_csum parm = { .action = TC_ACT_PIPE,\n>>>>>> +                                .update_flags = flags };\n>>>>>> +\n>>>>>> +        nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);\n>>>>>> +    }\n>>>>>> +    nl_msg_end_nested(request, offset);\n>>>>>> +}\n>>>>>> +\n>>>>>> +static void\n>>>>>> +nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,\n>>>>>> +                     struct tc_pedit_key_ex *ex)\n>>>>>> +{\n>>>>>> +    size_t ksize = sizeof *parm + (parm->nkeys * sizeof(struct tc_pedit_key));\n>>>>>\n>>>>> Are there unnecessary () on the line above?\n>>>> No, I'll remove them.\n>>>>\n>>>>>\n>>>>>> +    size_t offset, offset_keys_ex, offset_key;\n>>>>>> +    int i;\n>>>>>> +\n>>>>>> +    nl_msg_put_string(request, TCA_ACT_KIND, \"pedit\");\n>>>>>> +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n>>>>>> +    {\n>>>>>> +        parm->action = TC_ACT_PIPE;\n>>>>>> +\n>>>>>> +        nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);\n>>>>>> +        offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);\n>>>>>> +        for (i = 0; i < parm->nkeys; i++, ex++) {\n>>>>>> +            offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);\n>>>>>> +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);\n>>>>>> +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);\n>>>>>> +            nl_msg_end_nested(request, offset_key);\n>>>>>> +        }\n>>>>>> +        nl_msg_end_nested(request, offset_keys_ex);\n>>>>>> +    }\n>>>>>> +    nl_msg_end_nested(request, offset);\n>>>>>> +}\n>>>>>> +\n>>>>>> +static void\n>>>>>>    nl_msg_put_act_push_vlan(struct ofpbuf *request, uint16_t vid, uint8_t prio)\n>>>>>>    {\n>>>>>>        size_t offset;\n>>>>>> @@ -930,7 +1148,127 @@ nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {\n>>>>>>        }\n>>>>>>    }\n>>>>>> +/* Given flower, a key_to_pedit map entry, calculates the rest,\n>>>>>> + * where:\n>>>>>> + *\n>>>>>> + * mask, data - pointers of where read the first word of flower->key/mask.\n>>>>>> + * current_offset - which offset to use for the first pedit action.\n>>>>>> + * cnt - max pedits actions to use.\n>>>>>> + * first_word_mask/last_word_mask - the mask to use for the first/last read\n>>>>>> + * (as we read entire words). */\n>>>>>>    static void\n>>>>>> +calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m,\n>>>>>> +             int *cur_offset, int *cnt, uint32_t *last_word_mask,\n>>>>>> +             uint32_t *first_word_mask, uint32_t **mask, uint32_t **data)\n>>>>>> +{\n>>>>>> +    int start_offset, max_offset, total_size;\n>>>>>> +    int diff, right_zero_bits, left_zero_bits;\n>>>>>> +    char *rewrite_key = (void *) &flower->rewrite.key;\n>>>>>> +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n>>>>>> +\n>>>>>> +    max_offset = m->offset + m->size;\n>>>>>> +    start_offset = ROUND_DOWN(m->offset, 4);\n>>>>>> +    diff = m->offset - start_offset;\n>>>>>> +    total_size = max_offset - start_offset;\n>>>>>> +    right_zero_bits = 8 * (4 - (max_offset % 4));\n>>>>>> +    left_zero_bits = 8 * (m->offset - start_offset);\n>>>>>> +\n>>>>>> +    *cur_offset = start_offset;\n>>>>>> +    *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);\n>>>>>> +    *last_word_mask = UINT32_MAX >> right_zero_bits;\n>>>>>> +    *first_word_mask = UINT32_MAX << left_zero_bits;\n>>>>>> +    *data = (void *) (rewrite_key + m->flower_offset - diff);\n>>>>>> +    *mask = (void *) (rewrite_mask + m->flower_offset - diff);\n>>>>>\n>>>>> The type of *data and *mask is uint32_t *.\n>>>>> Why not cast to that type?\n>>>>\n>>>> It's to avoid warning of increasing pointer alignment (-Wcast-align).\n>>>\n>>> It sounds like the warning should be addressed rather than overridden using\n>>> a cast.\n>>>\n>>>>>\n>>>>>> +}\n>>>>>> +\n>>>>>> +static inline void\n>>>>>> +csum_update_flag(struct tc_flower *flower,\n>>>>>> +                 enum pedit_header_type htype) {\n>>>>>\n>>>>> I think the above two lines could be one.\n>>>>>\n>>>>>> +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4) {\n>>>>>\n>>>>> A case statement might be nicer here.\n>>>>\n>>>> Right, thanks.\n>>>>\n>>>>>\n>>>>>> +        flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;\n>>>>>> +    }\n>>>>>> +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4\n>>>>>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP6\n>>>>>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_TCP\n>>>>>> +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_UDP) {\n>>>>>> +        if (flower->key.ip_proto == IPPROTO_TCP) {\n>>>>>> +            flower->mask.ip_proto = UINT8_MAX;\n>>>>>\n>>>>> What if the mask was not UINT8_MAX to start with?\n>>>>> Doesn't this create a different flow?\n>>>>\n>>>> This is so the checksum will be strict (not setting/recalc udp checksum on\n>>>> non udp packets). It creates a more specific flow, a subset of the original.\n>>>> This is fine as datapath is free to ignore a mask, which is the same as a\n>>>> full mask we've set.\n>>>\n>>> I'm not sure that I understand why its fine for the datapath to ignore the\n>>> mask.\n>>\n>> I'll try to explain.\n>> When we want the HW to recalc the csum we need to also do matching on\n>> it. We do that for TCP, UDP, ICMP.\n> \n> Ok, that makes sense. But I am concerned that the mask of the offloaded\n> flow no longer matches the mask of the flow OvS created. What are the\n> implications of that?\n> \n\nHi, I remember the mask being a suggestion to the datapath (can't find \nit right now) as the datapath might not support the full mask. After the \nflow is generated from a miss upcall it will be put to the datapath and \nisn't saved anywhere, only the flow ufid (hash based on key, mask and \nsome seed, saved in ukey map at ofproto upcall...), if I recall \ncorrectly. We return the same ufid for the more specific flow that we \nput instead, so it will be aged correctly.\nOn dump it will show the more specific flow, as its a direct parse of \ndump from the datapath where there is the more specific one and not a \nsaved flow.\nOn a miss that could have been caught by the original flow, ovs will \ngenerate a new UFID, since the key is different. So we will have\nanother flow put and again a more specific flow and so on.\nThis flows will be disjointed and dumped and aged correctly.\n\n\n>>>>>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;\n>>>>>> +        } else if (flower->key.ip_proto == IPPROTO_UDP) {\n>>>>>> +            flower->mask.ip_proto = UINT8_MAX;\n>>>>>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;\n>>>>>> +        } else if (flower->key.ip_proto == IPPROTO_ICMP\n>>>>>> +                   || flower->key.ip_proto == IPPROTO_ICMPV6) {\n>>>>>> +            flower->mask.ip_proto = UINT8_MAX;\n>>>>>> +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;\n>>>>>> +        }\n>>>>>> +    }\n>>>>>> +}\n>>>>>> +\n>>>>>> +static int\n>>>>>> +nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,\n>>>>>> +                                 struct tc_flower *flower)\n>>>>>> +{\n>>>>>> +    struct {\n>>>>>> +        struct tc_pedit sel;\n>>>>>> +        struct tc_pedit_key keys[MAX_PEDIT_OFFSETS];\n>>>>>> +        struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];\n>>>>>> +    } sel = {\n>>>>>> +        .sel = {\n>>>>>> +            .nkeys = 0\n>>>>>> +        }\n>>>>>> +    };\n>>>>>> +    int i, j;\n>>>>>> +\n>>>>>> +    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {\n>>>>>> +        struct flower_key_to_pedit *m = &flower_pedit_map[i];\n>>>>>> +        struct tc_pedit_key *pedit_key = NULL;\n>>>>>> +        struct tc_pedit_key_ex *pedit_key_ex = NULL;\n>>>>>> +        uint32_t *mask, *data, first_word_mask, last_word_mask;\n>>>>>> +        int cnt = 0, cur_offset = 0;\n>>>>>> +\n>>>>>> +        if (!m->size) {\n>>>>>> +            continue;\n>>>>>> +        }\n>>>>>> +\n>>>>>> +        calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask,\n>>>>>> +                     &first_word_mask, &mask, &data);\n>>>>>> +\n>>>>>> +        for (j = 0; j < cnt; j++,  mask++, data++, cur_offset += 4) {\n>>>>>> +            uint32_t mask_word = *mask;\n>>>>>> +\n>>>>>> +            if (j == 0) {\n>>>>>> +                mask_word &= first_word_mask;\n>>>>>> +            }\n>>>>>> +            if (j == cnt - 1) {\n>>>>>> +                mask_word &= last_word_mask;\n>>>>>> +            }\n>>>>>> +            if (!mask_word) {\n>>>>>> +                continue;\n>>>>>> +            }\n>>>>>> +            if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {\n>>>>>> +                VLOG_WARN_RL(&error_rl, \"reached too many pedit offsets: %d\",\n>>>>>> +                             MAX_PEDIT_OFFSETS);\n>>>>>> +                return EOPNOTSUPP;\n>>>>>> +            }\n>>>>>> +\n>>>>>> +            pedit_key = &sel.keys[sel.sel.nkeys];\n>>>>>> +            pedit_key_ex = &sel.keys_ex[sel.sel.nkeys];\n>>>>>> +            pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;\n>>>>>> +            pedit_key_ex->htype = m->htype;\n>>>>>> +            pedit_key->off = cur_offset;\n>>>>>> +            pedit_key->mask = ~mask_word;\n>>>>>> +            pedit_key->val = *data & mask_word;\n>>>>>> +            sel.sel.nkeys++;\n>>>>>> +            csum_update_flag(flower, m->htype);\n>>>>>> +        }\n>>>>>> +    }\n>>>>>> +    nl_msg_put_act_pedit(request, &sel.sel, sel.keys_ex);\n>>>>>> +\n>>>>>> +    return 0;\n>>>>>> +}\n>>>>>> +\n>>>>>> +static int\n>>>>>>    nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>>>>>    {\n>>>>>>        size_t offset;\n>>>>>> @@ -939,7 +1277,20 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>>>>>        offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);\n>>>>>>        {\n>>>>>>            uint16_t act_index = 1;\n>>>>>> +        int error;\n>>>>>> +        if (flower->rewrite.rewrite) {\n>>>>>> +            act_offset = nl_msg_start_nested(request, act_index++);\n>>>>>> +            error = nl_msg_put_flower_rewrite_pedits(request, flower);\n>>>>>> +            if (error) {\n>>>>>> +                return error;\n>>>>>> +            }\n>>>>>> +            nl_msg_end_nested(request, act_offset);\n>>>>>> +\n>>>>>> +            act_offset = nl_msg_start_nested(request, act_index++);\n>>>>>> +            nl_msg_put_act_csum(request, flower->csum_update_flags);\n>>>>>> +            nl_msg_end_nested(request, act_offset);\n>>>>>> +        }\n>>>>>>            if (flower->set.set) {\n>>>>>>                act_offset = nl_msg_start_nested(request, act_index++);\n>>>>>>                nl_msg_put_act_tunnel_key_set(request, flower->set.id,\n>>>>>> @@ -980,6 +1331,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n>>>>>>            }\n>>>>>>        }\n>>>>>>        nl_msg_end_nested(request, offset);\n>>>>>> +\n>>>>>> +    return 0;\n>>>>>>    }\n>>>>>>    static void\n>>>>>> @@ -1021,11 +1374,19 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)\n>>>>>>        nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \\\n>>>>>>                                &flower->mask.member, sizeof flower->key.member)\n>>>>>> -static void\n>>>>>> +static int\n>>>>>>    nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n>>>>>>    {\n>>>>>> +\n>>>>>>        uint16_t host_eth_type = ntohs(flower->key.eth_type);\n>>>>>>        bool is_vlan = (host_eth_type == ETH_TYPE_VLAN);\n>>>>>> +    int err;\n>>>>>> +\n>>>>>> +    /* need to parse acts first as some acts require changing the matching */\n>>>>>\n>>>>> This seems strange to me.\n>>>>\n>>>> from the strict (normalized?) header checksum.\n>>>\n>>> I think this code relates to setting flower->key.ip_proto == IPPROTO_TCP\n>>> above. Is that correct. Are there any other cases?\n>>\n>> yes and also for UDP and ICMP. as explained above.\n>> So going over the acts in header rewrite case we might want to signal the HW\n>> recalc csum and we need matching on those fields that require new\n>> csum so the matching mask being updated. this is why we parse the acts\n>> first.\n> \n> Thanks, understood.\n> \n>>>>>> +    err  = nl_msg_put_flower_acts(request, flower);\n>>>>>> +    if (err) {\n>>>>>> +        return err;\n>>>>>> +    }\n>>>>>>        if (is_vlan) {\n>>>>>>            host_eth_type = ntohs(flower->key.encap_eth_type);\n>>>>>> @@ -1083,7 +1444,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n>>>>>>            nl_msg_put_flower_tunnel(request, flower);\n>>>>>>        }\n>>>>>> -    nl_msg_put_flower_acts(request, flower);\n>>>>>> +    return 0;\n>>>>>>    }\n>>>>>>    int\n>>>>>> @@ -1106,7 +1467,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n>>>>>>        nl_msg_put_string(&request, TCA_KIND, \"flower\");\n>>>>>>        basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);\n>>>>>>        {\n>>>>>> -        nl_msg_put_flower_options(&request, flower);\n>>>>>> +        error = nl_msg_put_flower_options(&request, flower);\n>>>>>> +\n>>>>>> +        if (error) {\n>>>>>> +            ofpbuf_uninit(&request);\n>>>>>> +            return error;\n>>>>>> +        }\n>>>>>>        }\n>>>>>>        nl_msg_end_nested(&request, basic_offset);\n>>>>>> diff --git a/lib/tc.h b/lib/tc.h\n>>>>>> index 6c69b79..7876051 100644\n>>>>>> --- a/lib/tc.h\n>>>>>> +++ b/lib/tc.h\n>>>>>> @@ -96,6 +96,7 @@ struct tc_flower_key {\n>>>>>>        struct {\n>>>>>>            ovs_be32 ipv4_src;\n>>>>>>            ovs_be32 ipv4_dst;\n>>>>>> +        uint8_t rewrite_ttl;\n>>>>>>        } ipv4;\n>>>>>>        struct {\n>>>>>>            struct in6_addr ipv6_src;\n>>>>>> @@ -120,6 +121,14 @@ struct tc_flower {\n>>>>>>        uint64_t lastused;\n>>>>>>        struct {\n>>>>>> +        bool rewrite;\n>>>>>> +        struct tc_flower_key key;\n>>>>>> +        struct tc_flower_key mask;\n>>>>>> +    } rewrite;\n>>>>>> +\n>>>>>> +    uint32_t csum_update_flags;\n>>>>>> +\n>>>>>> +    struct {\n>>>>>>            bool set;\n>>>>>>            ovs_be64 id;\n>>>>>>            ovs_be16 tp_src;\n>>>>>> @@ -152,6 +161,13 @@ struct tc_flower {\n>>>>>>        struct tc_cookie act_cookie;\n>>>>>>    };\n>>>>>> +/* assert that if we overflow with a masked write of uint32_t to the last byte\n>>>>>> + * of flower.rewrite we overflow inside struct flower.\n>>>>>> + * shouldn't happen unless someone moves rewrite to the end of flower */\n>>>>>> +BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)\n>>>>>> +                  + MEMBER_SIZEOF(struct tc_flower, rewrite)\n>>>>>> +                  + sizeof(uint32_t) - 2 < sizeof(struct tc_flower));\n>>>>>> +\n>>>>>>    int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n>>>>>>                          struct tc_flower *flower);\n>>>>>>    int tc_del_filter(int ifindex, int prio, int handle);\n>>>>>> -- \n>>>>>> 2.7.5\n>>>>>>","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=Mellanox.com header.i=@Mellanox.com\n\theader.b=\"TedCVZNe\"; dkim-atps=neutral","spf=none (sender IP is )\n\tsmtp.mailfrom=paulb@mellanox.com; "],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3yR2p06Y5dz9t2V\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 31 Oct 2017 18:21:12 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id CE8D59C0;\n\tTue, 31 Oct 2017 07:21:08 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 83118408\n\tfor <dev@openvswitch.org>; Tue, 31 Oct 2017 07:21:07 +0000 (UTC)","from EUR01-HE1-obe.outbound.protection.outlook.com\n\t(mail-he1eur01on0047.outbound.protection.outlook.com [104.47.0.47])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 5C31AF8\n\tfor <dev@openvswitch.org>; Tue, 31 Oct 2017 07:21:05 +0000 (UTC)","from [10.222.162.132] (193.47.165.251) by\n\tDB5PR05MB1639.eurprd05.prod.outlook.com (2a01:111:e400:5bb3::13) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.156.4;\n\tTue, 31 Oct 2017 07:21:00 +0000"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com;\n\ts=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version;\n\tbh=PBIEIFj8FzeyL7nJ/Sd/XOuO7/JzDTi1g1CyMMrbB/Y=;\n\tb=TedCVZNeQcplKLe619hzRtF0ZiCZ9Zgy20D2/vsDZLCi3mTmwTlXOMV5dbobWNwfG9fmq20SNzlbhCWK0zcq/rc5RG+VkKBLlMB8BBJmcD/d4a0wvE6k7W4zdeRU5z3pjdnbUKHEi5Dq7pyN1v/XhjoND2Uo7BuZn7UgaWA2iBw=","To":"Simon Horman <simon.horman@netronome.com>, Roi Dayan <roid@mellanox.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>\n\t<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>\n\t<20171030134242.n6gi7mzoxxgjunhh@netronome.com>","From":"Paul Blakey <paulb@mellanox.com>","Message-ID":"<30dcb2d7-34b0-8f84-7c17-205aabbd8238@mellanox.com>","Date":"Tue, 31 Oct 2017 09:20:55 +0200","User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101\n\tThunderbird/52.3.0","MIME-Version":"1.0","In-Reply-To":"<20171030134242.n6gi7mzoxxgjunhh@netronome.com>","Content-Language":"en-US","X-Originating-IP":"[193.47.165.251]","X-ClientProxiedBy":"DB6P193CA0015.EURP193.PROD.OUTLOOK.COM\n\t(2603:10a6:6:29::25)\n\tTo DB5PR05MB1639.eurprd05.prod.outlook.com\n\t(2a01:111:e400:5bb3::13)","X-MS-PublicTrafficType":"Email","X-MS-Office365-Filtering-Correlation-Id":"9eca1ce2-fd9a-4984-0e3f-08d5202ff032","X-MS-Office365-Filtering-HT":"Tenant","X-Microsoft-Antispam":"UriScan:; BCL:0; PCL:0;\n\tRULEID:(22001)(48565401081)(4534020)(4602075)(2017052603199);\n\tSRVR:DB5PR05MB1639; ","X-Microsoft-Exchange-Diagnostics":["1; DB5PR05MB1639;\n\t3:IGZJRkfVpXz+0JfY5Lz6JszH8Ed+PTIdV4xW1NKPpFwZim3agvPrXtZSLDCOdOoIXsI2rIlUApuByaiTFcWu2Ru9LqE8JKezPgXvBbibBpuEy675Qwjs93AEaeXm50hah7N7cAvpWnagX8wpgc6g80lxNlL6gfGpSXsItTgA36zzVPoS0N0unp/Rqm0Jq4AyJGmX+qEP/u7W5qsDt2DWv3+pWjPcuCqSpB1vvI7DjQ7tggq8koe+hEtv5QLdiOfj;\n\t25:wKA1ug95aC+mLYMqw1QOJAlVHYWAv0anObB3AcI9TCKoKic9p8QHgd9SYKr+0Ivgd+y/dNiGGy8qA+sLXxxcwdRqt5+oAmhFP4iK91OaXY3Lbz6Hl3NfDEe5WkTu4hLDNVJDT/c2Lji4xKI0hZwaRECx46yakO2pzSVGnJzgR2Akda4qjiRvDV9tTAdNzP71+2fgIdIqqMr5WKoIRDgF4iLUG+bWt5uGNxx6r9VyB03Y65/E8Rqy8z/LzZ0GXZSO4ZxT1DOpeXYOS9HJTGAS9iO3/wza7ygjclKdxOge0CEA7mpXg2AUJOK3jc0hrihoG9o3T6j6ioMB3k+2uAOXcg==;\n\t31:zy5qnWP3/wPtu3iDFljwO2SdilcfX2NQX0fT3tMHYSgAo4eEzneroyWoI1G2LfyWWD7xD8Ox4GQPwdiTrypvCLIcjCn1F39vRViOgkQwITZJISsVQmRN99AmwQUfgJATZpVMbTBoDMiPoxteezRpgq7kElV1U4yTXrVmQGhGDujb6sGHNljpEgk5XWaWIDx8Ajs2QjIHU18nZGljjI24uCACaO938WOaNTcWTz1pByY=","1; DB5PR05MB1639;\n\t20:7zNeXFkV+caRYNH2pESWsjqkWRTw80C+FndaYa97Ov5Gjpsvj9QO7Bq6CK/ZWsPLVL3bh9rgdmtgjpxMqPXEJ1ph1+YLFxD2dVlEBIwL8RC0pETl9MTxDzq0gzzUyN5678MRKtSw0OWHJY+w9/PywGZck2Nqv7Ckx5IJ5Ew84G0eNb2EPmnZgIvvzRzBsJtMlPbaxBxeHdZNwoKUVdWQaBnds9puCZk186bHT3aD6I/CbnujZX61HkpIdm0klKpB1MTXeAR07JUztFijPCHJqubTvo3ZGtPFQNkRQkaD7mFmJr8ffYiOKYb1A/lvZGZ7JjQDrHIH+bqo+3sJJ4DlmOcL0wO+vU9actVBXtll7Com7pxtwtE34og+U+UEkEmeJszwmkwsNXaRIJAUhCwFUB+jc8B2e8uv0PfkXSsMvZzf7Zf6YSLHRL/s/VCurfnGfsNqfo/wzgHWtX7s++l23QdJyMxZZvsLOQshsMVjvVZyrBQ+2TUyITIZp7IwUZjG;\n\t4:ABW9MJvNDfdWK4wxjAbhhQisQTyrOGjZ+zsPbPIeyh4yZQld/Xrdl+/zBqXoJAKLZSUQAoPtaUPRBYW6BYJjVXr1u5l1bYIng88vnEo0t0EJzKrSyWAWgON7/327WG6nop1yas7Q5XJoaKwAiG/Qf28YaBPU72aFG7PxX/Q6WwUKFN/Mvz2CPoTQkFi/SuJG5D2R9HoR/GAGhfsFOjm0h+KX01kBDrR4eAzlVft4U/JjeBBKzeFIOJdITadeyCz64Q0LR1jO8n/lgZ2wKUSkOmS6tZcFhFqoEWKK+lE6kBU=","=?windows-1255?Q?1; DB5PR05MB1639;\n\t23:5xLV+/7+Dr5kN29obaUqHyNnJxBiDo8jGF98U?=\n\t=?cp1255?q?WCet7FP0QXAGtVouZtOx38RvcSld7?=\n\t=?cp1255?q?qGCaVSDcPgLZt3XQ8iAn7Yj3onX7R5eKVxkZlZNQYo+0HX6KWuTIRnV?=\n\t=?cp1255?q?Wzath/cFHsNxxItWdYUQnom/xGQtpUpIk5yUc2jaZZzOaAXF843RA+1?=\n\t=?cp1255?q?QsV8bPBqXk8VYHIX4EGSA8cgFsa9DwaIMMKUHN5evFqNGuORECXZIJw?=\n\t=?cp1255?q?vxIElT/8knCCUZ3vkcc3Xd8sMPPFbOhAgYaI0liitXXbdN7YeSKcdZI?=\n\t=?cp1255?q?GujGVvBCY3066z63ZwUSwy9kxYEzPZUoBauC+/TM3/iKm/+065ianGw?=\n\t=?cp1255?q?MqFQCtuFCIr9kbQPjxz+odOTfuTpMARc19fTo4L/xnnPgCOkSDGuhzq?=\n\t=?cp1255?q?8Y2rYXDB8hfRcK5hnFGuhBVVQ1iDgbsS+x9kidaa9dALlPjME4oKCh8?=\n\t=?cp1255?q?22ANYozV1fynqzgwVeMp61P7Vsa28XFO88Cq2xlUzTvfj1tb+yZWLkl?=\n\t=?cp1255?q?kg3UEnzCNjkVdNCdJvMRt9Zr34Lvd+ULoF6o5CZ/dNW/LbT/Vf4ery5?=\n\t=?cp1255?q?oBOB0lG6OqYmUA2VhYcG07xZcncELqwdQjA9VpeiK3plMmgqBWDC4M+?=\n\t=?cp1255?q?7crFBtxpgx0y6u4Tc4NZOs38/2FBQWV47jeQbWSAbM2pgteP/OVSqcN?=\n\t=?cp1255?q?mtEDeA0bhR8KT2lpsUkjEXiM6wKePAEhhGHGrL52yBn/iJI5d/uYGsM?=\n\t=?cp1255?q?cqJUPBNOjYO072/g6b1HWnLiNlwAj3Vd7H9FamuMFbnsaNUZiGCwv7V?=\n\t=?cp1255?q?uRt0TATXs1fT/f6clwlT3qHPUPwB1ZuMOIEPBzHWaB1w1F+gqYI0aje?=\n\t=?cp1255?q?2Ibc2Fjl0QeN3ffbzyng1B3zYA4HmtAtHzUMfo2dcVEiowWPCrHFkAo?=\n\t=?cp1255?q?SctEnkdojgyilBTh/DK+DgPWqOxzk8rNXuN/FX/YcuvhxQRoKmA2bdd?=\n\t=?cp1255?q?qxD6+dxl8v7hrCyrwVQ0dBvdQoq0KEH2NK+fwr86TMqBPYYe7kJaOts?=\n\t=?cp1255?q?c80w+OpdXSvCOG2340pYOOtjfQ+KfQHgGjXHFt330JF4YU5AOdMnVqE?=\n\t=?cp1255?q?NBNAQ2ZQ3bcAs3GBTip0vwd4YOjgPxA4NVyGQCbjWAOd4xKTxjJxRRJ?=\n\t=?cp1255?q?GETP9uV6zHE2NClrvOcYGqZSsf2sPaW3qcNMfB4DanjH+3lsDD8Bi7n?=\n\t=?cp1255?q?vG7AgHJJRhmy78YyLqDwos677qzMT+nnOV7peWUL8A2V4P5gt6S/uku?=\n\t=?cp1255?q?Qx0TuVzN+vnkFjCRtnC3J1KgrGVTff+jNvhitpf+yDUUePAutvNZ1Zr?=\n\t=?cp1255?q?sG1X6NI/jm5ymLT9+bhZG8lGrxJJGsp2wHAahUoDSSEAxDwfbzQKJM1?=\n\t=?cp1255?q?HjHTsy4yD5Sf+RiO2FK73VP5qFD4rBI/DtCSEzSJk6GFVTYaVpnwhnn?=\n\t=?cp1255?q?7WEkE8hDYeZlLiN5F/I0a0ydzzxlqLgR4ddu7UGIjMQx+O/PD4JktHM?=\n\t=?cp1255?q?WRs1p79Gzou2U598VRRO3OKlk7JeLhl?=","1; DB5PR05MB1639;\n\t6:62GEyhpaYWUhhjSg+XbCVptknUfXqoVvI3KEiquNhss9NZRFN/TWw5AzZPaDpuQfUB8r1tlxuWTs84gpFO9pmCK6MnuNMSh00cGov4zL+UUgNCeLsdiHsVcL33OtoUdwEFcWgWhvpPR7MojBWNupySCeRqZ3bbu5CFoq9rEhbXR4zKYmlo9a48etEV0lRhlwUdexBug8fUOaIQAYfBBB5h6HFFzD80xPSTscCHi1wWgZknSHw013LUHdyGady4PV9vyvr3PJTiAv38z2vIr8+LDQseGsfKQn+wPxUq3ZJJEml8HpR1NcGkRWXjc2XFwuLloYbL/FComgb6P17opbiw==;\n\t5:avZCCbuPCR85H9KE7FTgwKtk/69H+HLHpGhPSNLFKHmbqjqaTfTpTF6chTve4AgrNDrxhIiJqd1MkqCF7PEq+JbAAX4dKAWz5STPA2jtM4mGIEsjV9/JU/5+VU9hdJINGPprO7mV5i+zdQxnPUpFxg==;\n\t24:LT3w7rxc3lKNHtIUCHJdlS7RayRbNNPl6TunE7wc8RX3GKwDBcxOehWjNn0PM1RYQSW7gUrNta2ONuwlRrT/rU34rolibijWR6C+C72+ayc=;\n\t7:Fn5v3Dnbos45+77KZ/ZXP2nXLcIcE9L8WRuufxwebp3PvUngZasbfxR0h6O2s5F0HTOWi74rjzUGBOKWSP8UwD2fA4ypJu31XpIByCr7unwrcFHuRBuNJgMyclLoBG/LV2GYkF/2M7ZVkqj+BaCtDif8gdvCcvIPj3cGmSjRI8fsOdvuVb3o10m5hU+B+CLkNPAzQfso6ar0VmnhDkGQ1VDDlW1yCmUrJ0TyOOEvVQs="],"X-MS-TrafficTypeDiagnostic":"DB5PR05MB1639:","X-Exchange-Antispam-Report-Test":"UriScan:(17755550239193);","X-Microsoft-Antispam-PRVS":"<DB5PR05MB1639BD1B58161A2774C828B6CF5E0@DB5PR05MB1639.eurprd05.prod.outlook.com>","X-Exchange-Antispam-Report-CFA-Test":"BCL:0; PCL:0;\n\tRULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(8121501046)(5005006)(100000703101)(100105400095)(3002001)(10201501046)(3231020)(93006095)(93001095)(6055026)(6041248)(20161123558100)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123560025)(20161123555025)(20161123564025)(20161123562025)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);\n\tSRVR:DB5PR05MB1639; BCL:0; PCL:0;\n\tRULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);\n\tSRVR:DB5PR05MB1639; ","X-Forefront-PRVS":"04772EA191","X-Forefront-Antispam-Report":"SFV:NSPM;\n\tSFS:(10009020)(6049001)(6009001)(376002)(39860400002)(346002)(189002)(54094003)(199003)(24454002)(305945005)(7736002)(36756003)(6246003)(81156014)(8676002)(81166006)(67846002)(8936002)(3260700006)(25786009)(53936002)(77096006)(2950100002)(86362001)(6666003)(6486002)(229853002)(6636002)(230700001)(478600001)(31686004)(76176999)(54356999)(5660300001)(101416001)(31696002)(65826007)(3846002)(6116002)(33646002)(53546010)(83506002)(16526018)(65806001)(65956001)(47776003)(50986999)(97736004)(93886005)(16576012)(50466002)(316002)(4326008)(105586002)(66066001)(58126008)(110136005)(106356001)(68736007)(39060400002)(64126003)(2906002)(189998001);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:DB5PR05MB1639; H:[10.222.162.132];\n\tFPR:; SPF:None; PTR:InfoNoRecords; MX:1; A:1; LANG:en; ","Received-SPF":"None (protection.outlook.com: mellanox.com does not designate\n\tpermitted sender hosts)","SpamDiagnosticOutput":"1:99","SpamDiagnosticMetadata":"NSPM","X-OriginatorOrg":"Mellanox.com","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"31 Oct 2017 07:21:00.2219\n\t(UTC)","X-MS-Exchange-CrossTenant-Network-Message-Id":"9eca1ce2-fd9a-4984-0e3f-08d5202ff032","X-MS-Exchange-CrossTenant-FromEntityHeader":"Hosted","X-MS-Exchange-CrossTenant-Id":"a652971c-7d2e-4d9b-a6a4-d149256f461b","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"DB5PR05MB1639","X-Spam-Status":"No, score=-0.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tDKIM_VALID_AU,RCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Transfer-Encoding":"7bit","Content-Type":"text/plain; charset=\"us-ascii\"; Format=\"flowed\"","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1796684,"web_url":"http://patchwork.ozlabs.org/comment/1796684/","msgid":"<20171031142924.qtc5dklzdfexqo5x@netronome.com>","list_archive_url":null,"date":"2017-10-31T14:29:25","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":64714,"url":"http://patchwork.ozlabs.org/api/people/64714/","name":"Simon Horman","email":"simon.horman@netronome.com"},"content":"On Tue, Oct 31, 2017 at 09:20:55AM +0200, Paul Blakey wrote:\n> \n> \n> On 30/10/2017 15:42, Simon Horman wrote:\n> > On Wed, Oct 25, 2017 at 02:24:15PM +0300, Roi Dayan wrote:\n> > > \n> > > \n> > > On 27/09/2017 12:08, Simon Horman wrote:\n> > > > On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n> > > > > \n> > > > > \n> > > > > On 18/09/2017 18:01, Simon Horman wrote:\n> > > > > > On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n> > > > > > > From: Paul Blakey <paulb@mellanox.com>\n> > > > > > > \n> > > > > > > To be later used to implement ovs action set offloading.\n> > > > > > > \n> > > > > > > Signed-off-by: Paul Blakey <paulb@mellanox.com>\n> > > > > > > Reviewed-by: Roi Dayan <roid@mellanox.com>\n> > > > > > > ---\n> > > > > > >    lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n> > > > > > >    lib/tc.h |  16 +++\n> > > > > > >    2 files changed, 385 insertions(+), 3 deletions(-)\n> > > > > > > \n> > > > > > > diff --git a/lib/tc.c b/lib/tc.c\n> > > > > > > index c9cada2..743b2ee 100644\n> > > > > > > --- a/lib/tc.c\n> > > > > > > +++ b/lib/tc.c\n> > > > > > > @@ -21,8 +21,10 @@\n> > > > > > >    #include <errno.h>\n> > > > > > >    #include <linux/if_ether.h>\n> > > > > > >    #include <linux/rtnetlink.h>\n> > > > > > > +#include <linux/tc_act/tc_csum.h>\n> > > > > > >    #include <linux/tc_act/tc_gact.h>\n> > > > > > >    #include <linux/tc_act/tc_mirred.h>\n> > > > > > > +#include <linux/tc_act/tc_pedit.h>\n> > > > > > >    #include <linux/tc_act/tc_tunnel_key.h>\n> > > > > > >    #include <linux/tc_act/tc_vlan.h>\n> > > > > > >    #include <linux/gen_stats.h>\n> > > > > > > @@ -33,11 +35,14 @@\n> > > > > > >    #include \"netlink-socket.h\"\n> > > > > > >    #include \"netlink.h\"\n> > > > > > >    #include \"openvswitch/ofpbuf.h\"\n> > > > > > > +#include \"openvswitch/util.h\"\n> > > > > > >    #include \"openvswitch/vlog.h\"\n> > > > > > >    #include \"packets.h\"\n> > > > > > >    #include \"timeval.h\"\n> > > > > > >    #include \"unaligned.h\"\n> > > > > > > +#define MAX_PEDIT_OFFSETS 8\n> > > > > > \n> > > > > > Why 8?\n> > > > > We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n> > > > > pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n> > > > > that's makes sens. do you suggest we increase it? to what?\n> > > > \n> > > > It seems strange to me to place a somewhat arbitrary small limit\n> > > > when none exists in the pedit API being used. I would at prefer if\n> > > > it was at least a bigger, say 16 or 32.\n> > > \n> > > \n> > > Hi Simon,\n> > > \n> > > Sorry for the late reply due to holidays and vacations.\n> > > Me & Paul going to go over this and do the fixes needed and\n> > > also rebase over latest master and run tests again.\n> > \n> > Likewise, sorry for not responding earlier (same reason).\n> > \n> > > I'll answer what I'm more familiar with now and Paul will continue.\n> > > The 8 here is too low and you right. We used this definition\n> > > for allocation of the pedit keys on the stack in\n> > > nl_msg_put_flower_rewrite_pedits()\n> > > \n> > > It was for convenience instead of calculating the maximum possible\n> > > keys that could exists and allocating it there and freeing it at\n> > > the end.\n> > > \n> > > Increasing it to 32 is probably more than enough and wont waste much.\n> > \n> > Thanks, that sounds good.\n> > \n> > > > > > >    VLOG_DEFINE_THIS_MODULE(tc);\n> > > > > > >    static struct vlog_rate_limit error_rl = VLOG_RATE_LIMIT_INIT(60, 5);\n> > > > > > > @@ -50,6 +55,82 @@ enum tc_offload_policy {\n> > > > > > >    static enum tc_offload_policy tc_policy = TC_POLICY_NONE;\n> > > > > > > +struct tc_pedit_key_ex {\n> > > > > > > +    enum pedit_header_type htype;\n> > > > > > > +    enum pedit_cmd cmd;\n> > > > > > > +};\n> > > > > > > +\n> > > > > > > +struct flower_key_to_pedit {\n> > > > > > > +    enum pedit_header_type htype;\n> > > > > > > +    int flower_offset;\n> > > > > > > +    int offset;\n> > > > > > > +    int size;\n> > > > > > > +};\n> > > > > > > +\n> > > > > > > +static struct flower_key_to_pedit flower_pedit_map[] = {\n> > > > > > > +    {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> > > > > > > +        12,\n> > > > > > > +        offsetof(struct tc_flower_key, ipv4.ipv4_src),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_src)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> > > > > > > +        16,\n> > > > > > > +        offsetof(struct tc_flower_key, ipv4.ipv4_dst),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.ipv4_dst)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP4,\n> > > > > > > +        8,\n> > > > > > > +        offsetof(struct tc_flower_key, ipv4.rewrite_ttl),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv4.rewrite_ttl)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n> > > > > > > +        8,\n> > > > > > > +        offsetof(struct tc_flower_key, ipv6.ipv6_src),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_src)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_IP6,\n> > > > > > > +        24,\n> > > > > > > +        offsetof(struct tc_flower_key, ipv6.ipv6_dst),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, ipv6.ipv6_dst)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> > > > > > > +        6,\n> > > > > > > +        offsetof(struct tc_flower_key, src_mac),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, src_mac)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> > > > > > > +        0,\n> > > > > > > +        offsetof(struct tc_flower_key, dst_mac),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, dst_mac)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_ETH,\n> > > > > > > +        12,\n> > > > > > > +        offsetof(struct tc_flower_key, eth_type),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, eth_type)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n> > > > > > > +        0,\n> > > > > > > +        offsetof(struct tc_flower_key, tcp_src),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, tcp_src)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_TCP,\n> > > > > > > +        2,\n> > > > > > > +        offsetof(struct tc_flower_key, tcp_dst),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, tcp_dst)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n> > > > > > > +        0,\n> > > > > > > +        offsetof(struct tc_flower_key, udp_src),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, udp_src)\n> > > > > > > +    }, {\n> > > > > > > +        TCA_PEDIT_KEY_EX_HDR_TYPE_UDP,\n> > > > > > > +        2,\n> > > > > > > +        offsetof(struct tc_flower_key, udp_dst),\n> > > > > > > +        MEMBER_SIZEOF(struct tc_flower_key, udp_dst)\n> > > > > > > +    },\n> > > > > > > +};\n> > > > > > > +\n> > > > > > >    struct tcmsg *\n> > > > > > >    tc_make_request(int ifindex, int type, unsigned int flags,\n> > > > > > >                    struct ofpbuf *request)\n> > > > > > > @@ -365,6 +446,96 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {\n> > > > > > >        }\n> > > > > > >    }\n> > > > > > > +static const struct nl_policy pedit_policy[] = {\n> > > > > > > +            [TCA_PEDIT_PARMS_EX] = { .type = NL_A_UNSPEC,\n> > > > > > > +                                     .min_len = sizeof(struct tc_pedit),\n> > > > > > > +                                     .optional = false, },\n> > > > > > > +            [TCA_PEDIT_KEYS_EX]   = { .type = NL_A_NESTED,\n> > > > > > > +                                      .optional = false, },\n> > > > > > > +};\n> > > > > > > +\n> > > > > > > +static int\n> > > > > > > +nl_parse_act_pedit(struct nlattr *options, struct tc_flower *flower)\n> > > > > > > +{\n> > > > > > > +    struct nlattr *pe_attrs[ARRAY_SIZE(pedit_policy)];\n> > > > > > > +    const struct tc_pedit *pe;\n> > > > > > > +    const struct tc_pedit_key *keys;\n> > > > > > > +    const struct nlattr *nla, *keys_ex, *ex_type;\n> > > > > > > +    const void *keys_attr;\n> > > > > > > +    char *rewrite_key = (void *) &flower->rewrite.key;\n> > > > > > > +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n> > > > > > > +    size_t keys_ex_size, left;\n> > > > > > > +    int type, i = 0;\n> > > > > > > +\n> > > > > > > +    if (!nl_parse_nested(options, pedit_policy, pe_attrs,\n> > > > > > > +                         ARRAY_SIZE(pedit_policy))) {\n> > > > > > > +        VLOG_ERR_RL(&error_rl, \"failed to parse pedit action options\");\n> > > > > > > +        return EPROTO;\n> > > > > > > +    }\n> > > > > > > +\n> > > > > > > +    pe = nl_attr_get_unspec(pe_attrs[TCA_PEDIT_PARMS_EX], sizeof *pe);\n> > > > > > > +    keys = pe->keys;\n> > > > > > > +    keys_attr = pe_attrs[TCA_PEDIT_KEYS_EX];\n> > > > > > > +    keys_ex = nl_attr_get(keys_attr);\n> > > > > > > +    keys_ex_size = nl_attr_get_size(keys_attr);\n> > > > > > > +\n> > > > > > > +    NL_ATTR_FOR_EACH (nla, left, keys_ex, keys_ex_size) {\n> > > > > > > +        if (i >= pe->nkeys) {\n> > > > > > > +            break;\n> > > > > > > +        }\n> > > > > > > +\n> > > > > > > +        if (nl_attr_type(nla) == TCA_PEDIT_KEY_EX) {\n> > > > > > > +            ex_type = nl_attr_find_nested(nla, TCA_PEDIT_KEY_EX_HTYPE);\n> > > > > > > +            type = nl_attr_get_u16(ex_type);\n> > > > > > > +\n> > > > > > > +            for (int j = 0; j < ARRAY_SIZE(flower_pedit_map); j++) {\n> > > > > > > +                struct flower_key_to_pedit *m = &flower_pedit_map[j];\n> > > > > > > +                int flower_off = m->flower_offset;\n> > > > > > > +                int sz = m->size;\n> > > > > > > +                int mf = m->offset;\n> > > > > > > +\n> > > > > > > +                if (m->htype != type) {\n> > > > > > > +                   continue;\n> > > > > > > +                }\n> > > > > > > +\n> > > > > > > +                /* check overlap between current pedit key, which is always\n> > > > > > > +                 * 4 bytes (range [off, off + 3]), and a map entry in\n> > > > > > > +                 * flower_pedit_map (range [mf, mf + sz - 1]) */\n> > > > > > > +                if ((keys->off >= mf && keys->off < mf + sz)\n> > > > > > > +                    || (keys->off + 3 >= mf && keys->off + 3 < mf + sz)) {\n> > > > > > > +                    int diff = flower_off + (keys->off - mf);\n> > > > > > > +                    uint32_t *dst = (void *) (rewrite_key + diff);\n> > > > > > > +                    uint32_t *dst_m = (void *) (rewrite_mask + diff);\n> > > > > > > +                    uint32_t mask = ~(keys->mask);\n> > > > > > > +                    uint32_t zero_bits;\n> > > > > > > +\n> > > > > > > +                    if (keys->off < mf) {\n> > > > > > > +                        zero_bits = 8 * (mf - keys->off);\n> > > > > > > +                        mask &= UINT32_MAX << zero_bits;\n> > > > > > > +                    } else if (keys->off + 4 > mf + m->size) {\n> > > > > > > +                        zero_bits = 8 * (keys->off + 4 - mf - m->size);\n> > > > > > > +                        mask &= UINT32_MAX >> zero_bits;\n> > > > > > > +                    }\n> > > > > > > +\n> > > > > > > +                    *dst_m |= mask;\n> > > > > > > +                    *dst |= keys->val & mask;\n> > > > > > > +                }\n> > > > > > > +            }\n> > > > > > \n> > > > > > If I understand the above correctly it is designed to make\n> > > > > > pedit actions disjoint. If so, why is that necessary? >\n> > > > > \n> > > > > It's not, as a single flower key rewrite can be split to multiple pedit\n> > > > > actions it finds the overlap between a flower key and a pedit action, if\n> > > > > they do overlap it translates it to the correct offset and masks it out.\n> > > > \n> > > > Thanks, understood.\n> > > > \n> > > > > \n> > > > > > > +        } else {\n> > > > > > > +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n> > > > > > > +                        nl_attr_type(nla));\n> > > > > > > +            return EOPNOTSUPP;\n> > > > > > > +        }\n> > > > > > \n> > > > > > I think the code could exit early here as\n> > > > > > nl_msg_put_flower_rewrite_pedits() does below.\n> > > > > > \n> > > > > \n> > > > > Sorry, didn't understand. can you give an example?\n> > > > > \n> > > > \n> > > > I meant something like this.\n> > > > \n> > > >               if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n> > > >                   VLOG_ERR_RL(...);\n> > > >                   return EOPNOTSUPP;\n> > > >               }\n> > > \n> > > understood. we'll do that. thanks.\n> > > \n> > > > \n> > > > \t    /* Overlap detection code goes here */\n> > > > \n> > > > > > \n> > > > > > > +\n> > > > > > > +        keys++;\n> > > > > > > +        i++;\n> > > > > > > +    }\n> > > > > > > +\n> > > > > > > +    flower->rewrite.rewrite = true;\n> > > > > > > +\n> > > > > > > +    return 0;\n> > > > > > > +}\n> > > > > > > +\n> > > > > > >    static const struct nl_policy tunnel_key_policy[] = {\n> > > > > > >        [TCA_TUNNEL_KEY_PARMS] = { .type = NL_A_UNSPEC,\n> > > > > > >                                   .min_len = sizeof(struct tc_tunnel_key),\n> > > > > > > @@ -608,6 +779,11 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)\n> > > > > > >            nl_parse_act_vlan(act_options, flower);\n> > > > > > >        } else if (!strcmp(act_kind, \"tunnel_key\")) {\n> > > > > > >            nl_parse_act_tunnel_key(act_options, flower);\n> > > > > > > +    } else if (!strcmp(act_kind, \"pedit\")) {\n> > > > > > > +        nl_parse_act_pedit(act_options, flower);\n> > > > > > > +    } else if (!strcmp(act_kind, \"csum\")) {\n> > > > > > > +        /* not doing anything for now, ovs has an implicit csum recalculation\n> > > > > > > +         * with rewriting of packet headers (translating of pedit acts). */\n> > > > > > \n> > > > > > I wonder if the absence of a csum action when needed (by TC)\n> > > > > > should be treated as an error >\n> > > > > \n> > > > > Do you mean validating csum flags from each protocol and such (like in put)?\n> > > > \n> > > > Yes, I think so.\n> > > > \n> > > > In OvS (without TC acceleration) csum recalculation is implicit\n> > > > but with TC an explicit csum update action is required. I see\n> > > > in your code you are handling this by adding csum actions to TC actions\n> > > > when translating from OvS DPIF actions. And in the reverse (above) csum\n> > > > actions are simply ignored.\n> > > > \n> > > > What I am wondering is if when translating TC actions to OvS DPIF actions\n> > > > you should track if the TC actions should include a csum rule because\n> > > > of other actions and treat its absence as an error.\n> > > > \n> > > > > \n> > > > > > >        } else {\n> > > > > > >            VLOG_ERR_RL(&error_rl, \"unknown tc action kind: %s\", act_kind);\n> > > > > > >            return EINVAL;\n> > > > > > > @@ -809,6 +985,48 @@ tc_get_tc_cls_policy(enum tc_offload_policy policy)\n> > > > > > >    }\n> > > > > > >    static void\n> > > > > > > +nl_msg_put_act_csum(struct ofpbuf *request, uint32_t flags)\n> > > > > > > +{\n> > > > > > > +    size_t offset;\n> > > > > > > +\n> > > > > > > +    nl_msg_put_string(request, TCA_ACT_KIND, \"csum\");\n> > > > > > > +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n> > > > > > > +    {\n> > > > > > > +        struct tc_csum parm = { .action = TC_ACT_PIPE,\n> > > > > > > +                                .update_flags = flags };\n> > > > > > > +\n> > > > > > > +        nl_msg_put_unspec(request, TCA_CSUM_PARMS, &parm, sizeof parm);\n> > > > > > > +    }\n> > > > > > > +    nl_msg_end_nested(request, offset);\n> > > > > > > +}\n> > > > > > > +\n> > > > > > > +static void\n> > > > > > > +nl_msg_put_act_pedit(struct ofpbuf *request, struct tc_pedit *parm,\n> > > > > > > +                     struct tc_pedit_key_ex *ex)\n> > > > > > > +{\n> > > > > > > +    size_t ksize = sizeof *parm + (parm->nkeys * sizeof(struct tc_pedit_key));\n> > > > > > \n> > > > > > Are there unnecessary () on the line above?\n> > > > > No, I'll remove them.\n> > > > > \n> > > > > > \n> > > > > > > +    size_t offset, offset_keys_ex, offset_key;\n> > > > > > > +    int i;\n> > > > > > > +\n> > > > > > > +    nl_msg_put_string(request, TCA_ACT_KIND, \"pedit\");\n> > > > > > > +    offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS);\n> > > > > > > +    {\n> > > > > > > +        parm->action = TC_ACT_PIPE;\n> > > > > > > +\n> > > > > > > +        nl_msg_put_unspec(request, TCA_PEDIT_PARMS_EX, parm, ksize);\n> > > > > > > +        offset_keys_ex = nl_msg_start_nested(request, TCA_PEDIT_KEYS_EX);\n> > > > > > > +        for (i = 0; i < parm->nkeys; i++, ex++) {\n> > > > > > > +            offset_key = nl_msg_start_nested(request, TCA_PEDIT_KEY_EX);\n> > > > > > > +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_HTYPE, ex->htype);\n> > > > > > > +            nl_msg_put_u16(request, TCA_PEDIT_KEY_EX_CMD, ex->cmd);\n> > > > > > > +            nl_msg_end_nested(request, offset_key);\n> > > > > > > +        }\n> > > > > > > +        nl_msg_end_nested(request, offset_keys_ex);\n> > > > > > > +    }\n> > > > > > > +    nl_msg_end_nested(request, offset);\n> > > > > > > +}\n> > > > > > > +\n> > > > > > > +static void\n> > > > > > >    nl_msg_put_act_push_vlan(struct ofpbuf *request, uint16_t vid, uint8_t prio)\n> > > > > > >    {\n> > > > > > >        size_t offset;\n> > > > > > > @@ -930,7 +1148,127 @@ nl_msg_put_act_cookie(struct ofpbuf *request, struct tc_cookie *ck) {\n> > > > > > >        }\n> > > > > > >    }\n> > > > > > > +/* Given flower, a key_to_pedit map entry, calculates the rest,\n> > > > > > > + * where:\n> > > > > > > + *\n> > > > > > > + * mask, data - pointers of where read the first word of flower->key/mask.\n> > > > > > > + * current_offset - which offset to use for the first pedit action.\n> > > > > > > + * cnt - max pedits actions to use.\n> > > > > > > + * first_word_mask/last_word_mask - the mask to use for the first/last read\n> > > > > > > + * (as we read entire words). */\n> > > > > > >    static void\n> > > > > > > +calc_offsets(struct tc_flower *flower, struct flower_key_to_pedit *m,\n> > > > > > > +             int *cur_offset, int *cnt, uint32_t *last_word_mask,\n> > > > > > > +             uint32_t *first_word_mask, uint32_t **mask, uint32_t **data)\n> > > > > > > +{\n> > > > > > > +    int start_offset, max_offset, total_size;\n> > > > > > > +    int diff, right_zero_bits, left_zero_bits;\n> > > > > > > +    char *rewrite_key = (void *) &flower->rewrite.key;\n> > > > > > > +    char *rewrite_mask = (void *) &flower->rewrite.mask;\n> > > > > > > +\n> > > > > > > +    max_offset = m->offset + m->size;\n> > > > > > > +    start_offset = ROUND_DOWN(m->offset, 4);\n> > > > > > > +    diff = m->offset - start_offset;\n> > > > > > > +    total_size = max_offset - start_offset;\n> > > > > > > +    right_zero_bits = 8 * (4 - (max_offset % 4));\n> > > > > > > +    left_zero_bits = 8 * (m->offset - start_offset);\n> > > > > > > +\n> > > > > > > +    *cur_offset = start_offset;\n> > > > > > > +    *cnt = (total_size / 4) + (total_size % 4 ? 1 : 0);\n> > > > > > > +    *last_word_mask = UINT32_MAX >> right_zero_bits;\n> > > > > > > +    *first_word_mask = UINT32_MAX << left_zero_bits;\n> > > > > > > +    *data = (void *) (rewrite_key + m->flower_offset - diff);\n> > > > > > > +    *mask = (void *) (rewrite_mask + m->flower_offset - diff);\n> > > > > > \n> > > > > > The type of *data and *mask is uint32_t *.\n> > > > > > Why not cast to that type?\n> > > > > \n> > > > > It's to avoid warning of increasing pointer alignment (-Wcast-align).\n> > > > \n> > > > It sounds like the warning should be addressed rather than overridden using\n> > > > a cast.\n> > > > \n> > > > > > \n> > > > > > > +}\n> > > > > > > +\n> > > > > > > +static inline void\n> > > > > > > +csum_update_flag(struct tc_flower *flower,\n> > > > > > > +                 enum pedit_header_type htype) {\n> > > > > > \n> > > > > > I think the above two lines could be one.\n> > > > > > \n> > > > > > > +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4) {\n> > > > > > \n> > > > > > A case statement might be nicer here.\n> > > > > \n> > > > > Right, thanks.\n> > > > > \n> > > > > > \n> > > > > > > +        flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;\n> > > > > > > +    }\n> > > > > > > +    if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP4\n> > > > > > > +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_IP6\n> > > > > > > +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_TCP\n> > > > > > > +        || htype == TCA_PEDIT_KEY_EX_HDR_TYPE_UDP) {\n> > > > > > > +        if (flower->key.ip_proto == IPPROTO_TCP) {\n> > > > > > > +            flower->mask.ip_proto = UINT8_MAX;\n> > > > > > \n> > > > > > What if the mask was not UINT8_MAX to start with?\n> > > > > > Doesn't this create a different flow?\n> > > > > \n> > > > > This is so the checksum will be strict (not setting/recalc udp checksum on\n> > > > > non udp packets). It creates a more specific flow, a subset of the original.\n> > > > > This is fine as datapath is free to ignore a mask, which is the same as a\n> > > > > full mask we've set.\n> > > > \n> > > > I'm not sure that I understand why its fine for the datapath to ignore the\n> > > > mask.\n> > > \n> > > I'll try to explain.\n> > > When we want the HW to recalc the csum we need to also do matching on\n> > > it. We do that for TCP, UDP, ICMP.\n> > \n> > Ok, that makes sense. But I am concerned that the mask of the offloaded\n> > flow no longer matches the mask of the flow OvS created. What are the\n> > implications of that?\n> > \n> \n> Hi, I remember the mask being a suggestion to the datapath (can't find it\n> right now) as the datapath might not support the full mask. After the flow\n> is generated from a miss upcall it will be put to the datapath and isn't\n> saved anywhere, only the flow ufid (hash based on key, mask and some seed,\n> saved in ukey map at ofproto upcall...), if I recall correctly. We return\n> the same ufid for the more specific flow that we put instead, so it will be\n> aged correctly.\n> On dump it will show the more specific flow, as its a direct parse of dump\n> from the datapath where there is the more specific one and not a saved flow.\n> On a miss that could have been caught by the original flow, ovs will\n> generate a new UFID, since the key is different. So we will have\n> another flow put and again a more specific flow and so on.\n> This flows will be disjointed and dumped and aged correctly.\n\nThanks for the explanation. I don't think I have any outstanding questions\nand I'd be happy to see a new version of this patchset.\n\n> \n> \n> > > > > > > +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;\n> > > > > > > +        } else if (flower->key.ip_proto == IPPROTO_UDP) {\n> > > > > > > +            flower->mask.ip_proto = UINT8_MAX;\n> > > > > > > +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;\n> > > > > > > +        } else if (flower->key.ip_proto == IPPROTO_ICMP\n> > > > > > > +                   || flower->key.ip_proto == IPPROTO_ICMPV6) {\n> > > > > > > +            flower->mask.ip_proto = UINT8_MAX;\n> > > > > > > +            flower->csum_update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;\n> > > > > > > +        }\n> > > > > > > +    }\n> > > > > > > +}\n> > > > > > > +\n> > > > > > > +static int\n> > > > > > > +nl_msg_put_flower_rewrite_pedits(struct ofpbuf *request,\n> > > > > > > +                                 struct tc_flower *flower)\n> > > > > > > +{\n> > > > > > > +    struct {\n> > > > > > > +        struct tc_pedit sel;\n> > > > > > > +        struct tc_pedit_key keys[MAX_PEDIT_OFFSETS];\n> > > > > > > +        struct tc_pedit_key_ex keys_ex[MAX_PEDIT_OFFSETS];\n> > > > > > > +    } sel = {\n> > > > > > > +        .sel = {\n> > > > > > > +            .nkeys = 0\n> > > > > > > +        }\n> > > > > > > +    };\n> > > > > > > +    int i, j;\n> > > > > > > +\n> > > > > > > +    for (i = 0; i < ARRAY_SIZE(flower_pedit_map); i++) {\n> > > > > > > +        struct flower_key_to_pedit *m = &flower_pedit_map[i];\n> > > > > > > +        struct tc_pedit_key *pedit_key = NULL;\n> > > > > > > +        struct tc_pedit_key_ex *pedit_key_ex = NULL;\n> > > > > > > +        uint32_t *mask, *data, first_word_mask, last_word_mask;\n> > > > > > > +        int cnt = 0, cur_offset = 0;\n> > > > > > > +\n> > > > > > > +        if (!m->size) {\n> > > > > > > +            continue;\n> > > > > > > +        }\n> > > > > > > +\n> > > > > > > +        calc_offsets(flower, m, &cur_offset, &cnt, &last_word_mask,\n> > > > > > > +                     &first_word_mask, &mask, &data);\n> > > > > > > +\n> > > > > > > +        for (j = 0; j < cnt; j++,  mask++, data++, cur_offset += 4) {\n> > > > > > > +            uint32_t mask_word = *mask;\n> > > > > > > +\n> > > > > > > +            if (j == 0) {\n> > > > > > > +                mask_word &= first_word_mask;\n> > > > > > > +            }\n> > > > > > > +            if (j == cnt - 1) {\n> > > > > > > +                mask_word &= last_word_mask;\n> > > > > > > +            }\n> > > > > > > +            if (!mask_word) {\n> > > > > > > +                continue;\n> > > > > > > +            }\n> > > > > > > +            if (sel.sel.nkeys == MAX_PEDIT_OFFSETS) {\n> > > > > > > +                VLOG_WARN_RL(&error_rl, \"reached too many pedit offsets: %d\",\n> > > > > > > +                             MAX_PEDIT_OFFSETS);\n> > > > > > > +                return EOPNOTSUPP;\n> > > > > > > +            }\n> > > > > > > +\n> > > > > > > +            pedit_key = &sel.keys[sel.sel.nkeys];\n> > > > > > > +            pedit_key_ex = &sel.keys_ex[sel.sel.nkeys];\n> > > > > > > +            pedit_key_ex->cmd = TCA_PEDIT_KEY_EX_CMD_SET;\n> > > > > > > +            pedit_key_ex->htype = m->htype;\n> > > > > > > +            pedit_key->off = cur_offset;\n> > > > > > > +            pedit_key->mask = ~mask_word;\n> > > > > > > +            pedit_key->val = *data & mask_word;\n> > > > > > > +            sel.sel.nkeys++;\n> > > > > > > +            csum_update_flag(flower, m->htype);\n> > > > > > > +        }\n> > > > > > > +    }\n> > > > > > > +    nl_msg_put_act_pedit(request, &sel.sel, sel.keys_ex);\n> > > > > > > +\n> > > > > > > +    return 0;\n> > > > > > > +}\n> > > > > > > +\n> > > > > > > +static int\n> > > > > > >    nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> > > > > > >    {\n> > > > > > >        size_t offset;\n> > > > > > > @@ -939,7 +1277,20 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> > > > > > >        offset = nl_msg_start_nested(request, TCA_FLOWER_ACT);\n> > > > > > >        {\n> > > > > > >            uint16_t act_index = 1;\n> > > > > > > +        int error;\n> > > > > > > +        if (flower->rewrite.rewrite) {\n> > > > > > > +            act_offset = nl_msg_start_nested(request, act_index++);\n> > > > > > > +            error = nl_msg_put_flower_rewrite_pedits(request, flower);\n> > > > > > > +            if (error) {\n> > > > > > > +                return error;\n> > > > > > > +            }\n> > > > > > > +            nl_msg_end_nested(request, act_offset);\n> > > > > > > +\n> > > > > > > +            act_offset = nl_msg_start_nested(request, act_index++);\n> > > > > > > +            nl_msg_put_act_csum(request, flower->csum_update_flags);\n> > > > > > > +            nl_msg_end_nested(request, act_offset);\n> > > > > > > +        }\n> > > > > > >            if (flower->set.set) {\n> > > > > > >                act_offset = nl_msg_start_nested(request, act_index++);\n> > > > > > >                nl_msg_put_act_tunnel_key_set(request, flower->set.id,\n> > > > > > > @@ -980,6 +1331,8 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)\n> > > > > > >            }\n> > > > > > >        }\n> > > > > > >        nl_msg_end_nested(request, offset);\n> > > > > > > +\n> > > > > > > +    return 0;\n> > > > > > >    }\n> > > > > > >    static void\n> > > > > > > @@ -1021,11 +1374,19 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)\n> > > > > > >        nl_msg_put_masked_value(request, type, type##_MASK, &flower->key.member, \\\n> > > > > > >                                &flower->mask.member, sizeof flower->key.member)\n> > > > > > > -static void\n> > > > > > > +static int\n> > > > > > >    nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n> > > > > > >    {\n> > > > > > > +\n> > > > > > >        uint16_t host_eth_type = ntohs(flower->key.eth_type);\n> > > > > > >        bool is_vlan = (host_eth_type == ETH_TYPE_VLAN);\n> > > > > > > +    int err;\n> > > > > > > +\n> > > > > > > +    /* need to parse acts first as some acts require changing the matching */\n> > > > > > \n> > > > > > This seems strange to me.\n> > > > > \n> > > > > from the strict (normalized?) header checksum.\n> > > > \n> > > > I think this code relates to setting flower->key.ip_proto == IPPROTO_TCP\n> > > > above. Is that correct. Are there any other cases?\n> > > \n> > > yes and also for UDP and ICMP. as explained above.\n> > > So going over the acts in header rewrite case we might want to signal the HW\n> > > recalc csum and we need matching on those fields that require new\n> > > csum so the matching mask being updated. this is why we parse the acts\n> > > first.\n> > \n> > Thanks, understood.\n> > \n> > > > > > > +    err  = nl_msg_put_flower_acts(request, flower);\n> > > > > > > +    if (err) {\n> > > > > > > +        return err;\n> > > > > > > +    }\n> > > > > > >        if (is_vlan) {\n> > > > > > >            host_eth_type = ntohs(flower->key.encap_eth_type);\n> > > > > > > @@ -1083,7 +1444,7 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)\n> > > > > > >            nl_msg_put_flower_tunnel(request, flower);\n> > > > > > >        }\n> > > > > > > -    nl_msg_put_flower_acts(request, flower);\n> > > > > > > +    return 0;\n> > > > > > >    }\n> > > > > > >    int\n> > > > > > > @@ -1106,7 +1467,12 @@ tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n> > > > > > >        nl_msg_put_string(&request, TCA_KIND, \"flower\");\n> > > > > > >        basic_offset = nl_msg_start_nested(&request, TCA_OPTIONS);\n> > > > > > >        {\n> > > > > > > -        nl_msg_put_flower_options(&request, flower);\n> > > > > > > +        error = nl_msg_put_flower_options(&request, flower);\n> > > > > > > +\n> > > > > > > +        if (error) {\n> > > > > > > +            ofpbuf_uninit(&request);\n> > > > > > > +            return error;\n> > > > > > > +        }\n> > > > > > >        }\n> > > > > > >        nl_msg_end_nested(&request, basic_offset);\n> > > > > > > diff --git a/lib/tc.h b/lib/tc.h\n> > > > > > > index 6c69b79..7876051 100644\n> > > > > > > --- a/lib/tc.h\n> > > > > > > +++ b/lib/tc.h\n> > > > > > > @@ -96,6 +96,7 @@ struct tc_flower_key {\n> > > > > > >        struct {\n> > > > > > >            ovs_be32 ipv4_src;\n> > > > > > >            ovs_be32 ipv4_dst;\n> > > > > > > +        uint8_t rewrite_ttl;\n> > > > > > >        } ipv4;\n> > > > > > >        struct {\n> > > > > > >            struct in6_addr ipv6_src;\n> > > > > > > @@ -120,6 +121,14 @@ struct tc_flower {\n> > > > > > >        uint64_t lastused;\n> > > > > > >        struct {\n> > > > > > > +        bool rewrite;\n> > > > > > > +        struct tc_flower_key key;\n> > > > > > > +        struct tc_flower_key mask;\n> > > > > > > +    } rewrite;\n> > > > > > > +\n> > > > > > > +    uint32_t csum_update_flags;\n> > > > > > > +\n> > > > > > > +    struct {\n> > > > > > >            bool set;\n> > > > > > >            ovs_be64 id;\n> > > > > > >            ovs_be16 tp_src;\n> > > > > > > @@ -152,6 +161,13 @@ struct tc_flower {\n> > > > > > >        struct tc_cookie act_cookie;\n> > > > > > >    };\n> > > > > > > +/* assert that if we overflow with a masked write of uint32_t to the last byte\n> > > > > > > + * of flower.rewrite we overflow inside struct flower.\n> > > > > > > + * shouldn't happen unless someone moves rewrite to the end of flower */\n> > > > > > > +BUILD_ASSERT_DECL(offsetof(struct tc_flower, rewrite)\n> > > > > > > +                  + MEMBER_SIZEOF(struct tc_flower, rewrite)\n> > > > > > > +                  + sizeof(uint32_t) - 2 < sizeof(struct tc_flower));\n> > > > > > > +\n> > > > > > >    int tc_replace_flower(int ifindex, uint16_t prio, uint32_t handle,\n> > > > > > >                          struct tc_flower *flower);\n> > > > > > >    int tc_del_filter(int ifindex, int prio, int handle);\n> > > > > > > -- \n> > > > > > > 2.7.5\n> > > > > > >","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=netronome-com.20150623.gappssmtp.com\n\theader.i=@netronome-com.20150623.gappssmtp.com\n\theader.b=\"Gl90obbf\"; dkim-atps=neutral"],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3yRDKz29gTz9sNw\n\tfor <incoming@patchwork.ozlabs.org>;\n\tWed,  1 Nov 2017 01:31:03 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 31CE3BC9;\n\tTue, 31 Oct 2017 14:29:32 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id D6FE095D\n\tfor <dev@openvswitch.org>; Tue, 31 Oct 2017 14:29:30 +0000 (UTC)","from mail-wm0-f47.google.com (mail-wm0-f47.google.com\n\t[74.125.82.47])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id C37E442D\n\tfor <dev@openvswitch.org>; Tue, 31 Oct 2017 14:29:28 +0000 (UTC)","by mail-wm0-f47.google.com with SMTP id r68so23672155wmr.3\n\tfor <dev@openvswitch.org>; Tue, 31 Oct 2017 07:29:28 -0700 (PDT)","from netronome.com ([217.111.208.18])\n\tby smtp.gmail.com with ESMTPSA id\n\tk130sm1267227wmg.12.2017.10.31.07.29.26\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tTue, 31 Oct 2017 07:29:26 -0700 (PDT)"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=netronome-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=d1d1/+RWmm4ruGBq+PQ/+d+lyFvp7POlt97//Kq6xak=;\n\tb=Gl90obbfAQ5384catTQ14fFcGFfM3kPGviz9+Fg5XtJRDZUKNUkGbprDqPXG3cifB+\n\tEXIV6XFrjzizOKRUA3CjyRzlhPJ6nUPIey35Jkf+64+Igvc5igR53SqQ4+TCT38sg1yK\n\tEIvx9LejAWczhxW6oEA+CZYrgWQAANjH3lSABPfWC6bn8fyAfBo9QakN489PWMmiLQjR\n\tLduQY5oMyt1mIbRkyyc2kBFIFFC3ReJzQzsU5ImzFNATJ0sqP8pakv3OscmnlG8v0X2m\n\t5Z6gND3n1lGycWYxTr3+ABoCmDa4fLw41G7wuwD++ShV8lZQgc7IdgRvZxhuf907uA49\n\tgyXA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=d1d1/+RWmm4ruGBq+PQ/+d+lyFvp7POlt97//Kq6xak=;\n\tb=NE1e5Bt1x72Or8TYvVD0PBlXiEyOVlZarIBHh4bPZnVge+rOy4QA4B3a0mpamTkOx6\n\t8Am+wt3QWEFofQlVzkPiWMTQchA450042oWFrGYsGlVrI0CLfuBLTb0OIFff4H5Jnhiv\n\tosClDTGm2gbZT5zBXTVzLXsV0Ng9M5OUfznN6itFvXb2iHLUma07X2otm+2v6mp2qt82\n\tBgFwXiFbe588gMykGp8vkSbPGQQ4lScktobOUzCYXrkYOaAi/DYAfTkPM6w8jCwNjIXm\n\tdrC6oejehAR4C2XUtud73zdxtr3cF5hE5B4DYRm53JOtvMvn2f/Vtcv020mh/VmJ0lRO\n\th+XA==","X-Gm-Message-State":"AMCzsaUxqyKpHqv1SPBo1WQU/ZiYv/GNkMW0okzRNy1lCvtJq/zmCyd1\n\tNF1EoXCKoCn8pJn1swwbOO0uBg==","X-Google-Smtp-Source":"ABhQp+SPLVdcujdGu1/U9RKJjw+J24Fa5M43/j7A//VWq9W4S4iQ3xWW/9O1N592u8PsP/nTw2K5zA==","X-Received":"by 10.28.12.193 with SMTP id 184mr2328125wmm.70.1509460167076;\n\tTue, 31 Oct 2017 07:29:27 -0700 (PDT)","Date":"Tue, 31 Oct 2017 15:29:25 +0100","From":"Simon Horman <simon.horman@netronome.com>","To":"Paul Blakey <paulb@mellanox.com>","Message-ID":"<20171031142924.qtc5dklzdfexqo5x@netronome.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>\n\t<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>\n\t<20171030134242.n6gi7mzoxxgjunhh@netronome.com>\n\t<30dcb2d7-34b0-8f84-7c17-205aabbd8238@mellanox.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<30dcb2d7-34b0-8f84-7c17-205aabbd8238@mellanox.com>","User-Agent":"NeoMutt/20170113 (1.7.2)","X-Spam-Status":"No, score=0.5 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tRCVD_IN_DNSWL_NONE,\n\tRCVD_IN_SORBS_SPAM autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1805794,"web_url":"http://patchwork.ozlabs.org/comment/1805794/","msgid":"<20171116162906.cfw46ejbz3rxm3rz@netronome.com>","list_archive_url":null,"date":"2017-11-16T16:29:08","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":64714,"url":"http://patchwork.ozlabs.org/api/people/64714/","name":"Simon Horman","email":"simon.horman@netronome.com"},"content":"On Wed, Oct 25, 2017 at 02:24:15PM +0300, Roi Dayan wrote:\n> \n> \n> On 27/09/2017 12:08, Simon Horman wrote:\n> > On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n> > > \n> > > \n> > > On 18/09/2017 18:01, Simon Horman wrote:\n> > > > On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n> > > > > From: Paul Blakey <paulb@mellanox.com>\n> > > > > \n> > > > > To be later used to implement ovs action set offloading.\n> > > > > \n> > > > > Signed-off-by: Paul Blakey <paulb@mellanox.com>\n> > > > > Reviewed-by: Roi Dayan <roid@mellanox.com>\n> > > > > ---\n> > > > >   lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n> > > > >   lib/tc.h |  16 +++\n> > > > >   2 files changed, 385 insertions(+), 3 deletions(-)\n> > > > > \n> > > > > diff --git a/lib/tc.c b/lib/tc.c\n> > > > > index c9cada2..743b2ee 100644\n> > > > > --- a/lib/tc.c\n> > > > > +++ b/lib/tc.c\n> > > > > @@ -21,8 +21,10 @@\n> > > > >   #include <errno.h>\n> > > > >   #include <linux/if_ether.h>\n> > > > >   #include <linux/rtnetlink.h>\n> > > > > +#include <linux/tc_act/tc_csum.h>\n> > > > >   #include <linux/tc_act/tc_gact.h>\n> > > > >   #include <linux/tc_act/tc_mirred.h>\n> > > > > +#include <linux/tc_act/tc_pedit.h>\n> > > > >   #include <linux/tc_act/tc_tunnel_key.h>\n> > > > >   #include <linux/tc_act/tc_vlan.h>\n> > > > >   #include <linux/gen_stats.h>\n> > > > > @@ -33,11 +35,14 @@\n> > > > >   #include \"netlink-socket.h\"\n> > > > >   #include \"netlink.h\"\n> > > > >   #include \"openvswitch/ofpbuf.h\"\n> > > > > +#include \"openvswitch/util.h\"\n> > > > >   #include \"openvswitch/vlog.h\"\n> > > > >   #include \"packets.h\"\n> > > > >   #include \"timeval.h\"\n> > > > >   #include \"unaligned.h\"\n> > > > > +#define MAX_PEDIT_OFFSETS 8\n> > > > \n> > > > Why 8?\n> > > We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n> > > pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n> > > that's makes sens. do you suggest we increase it? to what?\n> > \n> > It seems strange to me to place a somewhat arbitrary small limit\n> > when none exists in the pedit API being used. I would at prefer if\n> > it was at least a bigger, say 16 or 32.\n> \n\n> Hi Simon,\n> \n> Sorry for the late reply due to holidays and vacations.\n> Me & Paul going to go over this and do the fixes needed and\n> also rebase over latest master and run tests again.\n> \n> I'll answer what I'm more familiar with now and Paul will continue.\n> The 8 here is too low and you right. We used this definition\n> for allocation of the pedit keys on the stack in\n> nl_msg_put_flower_rewrite_pedits()\n> \n> It was for convenience instead of calculating the maximum possible\n> keys that could exists and allocating it there and freeing it at\n> the end.\n> \n> Increasing it to 32 is probably more than enough and wont waste much.\n\nI updated the value to 32 when applying the patch.\n\n...\n\n> > > > If I understand the above correctly it is designed to make\n> > > > pedit actions disjoint. If so, why is that necessary? >\n> > > \n> > > It's not, as a single flower key rewrite can be split to multiple pedit\n> > > actions it finds the overlap between a flower key and a pedit action, if\n> > > they do overlap it translates it to the correct offset and masks it out.\n> > \n> > Thanks, understood.\n> > \n> > > \n> > > > > +        } else {\n> > > > > +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n> > > > > +                        nl_attr_type(nla));\n> > > > > +            return EOPNOTSUPP;\n> > > > > +        }\n> > > > \n> > > > I think the code could exit early here as\n> > > > nl_msg_put_flower_rewrite_pedits() does below.\n> > > > \n> > > \n> > > Sorry, didn't understand. can you give an example?\n> > > \n> > \n> > I meant something like this.\n> > \n> >              if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n> >                  VLOG_ERR_RL(...);\n> >                  return EOPNOTSUPP;\n> >              }\n> \n> understood. we'll do that. thanks.\n\nI also fixed this when applying the patch.\n\n...","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=netronome-com.20150623.gappssmtp.com\n\theader.i=@netronome-com.20150623.gappssmtp.com\n\theader.b=\"Kz6LW3os\"; dkim-atps=neutral"],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3yd6C014DGz9s72\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 17 Nov 2017 03:29:15 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 48145AAE;\n\tThu, 16 Nov 2017 16:29:12 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id DAB67AAC\n\tfor <dev@openvswitch.org>; Thu, 16 Nov 2017 16:29:10 +0000 (UTC)","from mail-pg0-f50.google.com (mail-pg0-f50.google.com\n\t[74.125.83.50])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 4B30E171\n\tfor <dev@openvswitch.org>; Thu, 16 Nov 2017 16:29:10 +0000 (UTC)","by mail-pg0-f50.google.com with SMTP id r12so4180069pgu.10\n\tfor <dev@openvswitch.org>; Thu, 16 Nov 2017 08:29:10 -0800 (PST)","from netronome.com ([64.124.208.80])\n\tby smtp.gmail.com with ESMTPSA id\n\tk80sm4131408pfh.30.2017.11.16.08.29.08\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tThu, 16 Nov 2017 08:29:09 -0800 (PST)"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=netronome-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=N9fl9066dmyrw4sZnTFF+JFtXOVTqymivilDMoIuwz4=;\n\tb=Kz6LW3os9aG816U+fryQKhEVrBzrP5jJ0rS8yHHCuO7V9kdojHNk5HrxvYGZfEzKje\n\tmR7LrnzA37XjX/x5qfVV/WEDENSFSvFQXUQHU6obZYgUtyfomIch5kObJV56+D7Ihlcy\n\t7kw2NNMbMOG397ZoOxZhDm5SzQeoWtEWCSbX4b9b9tG91fBV6SKtiuTaUhWQmyrpvX3m\n\tcriulMHqz5R70iwu9SoyFP794fULZkaEalxXMcBRHVSQtptu1s/Myw8N/1nLrtzDGVBS\n\tgtSv4gWYp7kMnYcEfT9/08nlCyvZ7Bl3g1PtH3xT0OOZs59z6KBWVhdGTxlNAbCh72E/\n\t2HxA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=N9fl9066dmyrw4sZnTFF+JFtXOVTqymivilDMoIuwz4=;\n\tb=CGgIN6Oif6RD1jXbhVS7m9gQp1GxDl2+JgExhJ2F78p/ECyMHkNBdmQ7+ikxEF4WfA\n\tp0teCRKHzKld3kvPfELeVeGkqx6Xy7NJP/nVqXdhQo/uH0IDxko9dW0H9w6py3KFD98v\n\tiPbbeSP99kQkAKkfhYNdtnpQJvscV3CDSCMj/ZRSyO8Y62N/IMQJFhQpu9wW7/czT4iN\n\tXQ8QLXaOXmtWbINzSuE/74ztYq3QE9SVC2DTaODcdA3IYeTJdBBg2LWJfU7TR7tBsvW7\n\tSWQpmzqlFl8cRX63t3vM8mzFutyGwOFUUikIlUvoqFPAbeBH1irXT77hrlTx3sTANDZO\n\tAInw==","X-Gm-Message-State":"AJaThX7V//S2NyvAyJOKWg2wwajQSd1KqTEGdKC6HgB1VgikB38xeFC6\n\tEg+g2ggX9m/5e0WHsylmaPFI1g==","X-Google-Smtp-Source":"AGs4zMasgzoCVOftuFHnhUZj3nFE4Usxqrfz5L1AUPk8qdTH68eYIbEkTdciygTE3v4HmtM2lrwIaw==","X-Received":"by 10.84.168.193 with SMTP id f59mr2219093plb.22.1510849749827; \n\tThu, 16 Nov 2017 08:29:09 -0800 (PST)","Date":"Thu, 16 Nov 2017 08:29:08 -0800","From":"Simon Horman <simon.horman@netronome.com>","To":"Roi Dayan <roid@mellanox.com>","Message-ID":"<20171116162906.cfw46ejbz3rxm3rz@netronome.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>\n\t<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>","User-Agent":"NeoMutt/20170113 (1.7.2)","X-Spam-Status":"No, score=0.0 required=5.0 tests=DKIM_SIGNED,DKIM_VALID,\n\tRCVD_IN_DNSWL_NONE autolearn=disabled version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1806927,"web_url":"http://patchwork.ozlabs.org/comment/1806927/","msgid":"<88e27e92-c6d9-86dc-ad17-fec20b73e6ee@mellanox.com>","list_archive_url":null,"date":"2017-11-19T06:45:19","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":70307,"url":"http://patchwork.ozlabs.org/api/people/70307/","name":"Roi Dayan","email":"roid@mellanox.com"},"content":"On 16/11/2017 18:29, Simon Horman wrote:\n> On Wed, Oct 25, 2017 at 02:24:15PM +0300, Roi Dayan wrote:\n>>\n>>\n>> On 27/09/2017 12:08, Simon Horman wrote:\n>>> On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n>>>>\n>>>>\n>>>> On 18/09/2017 18:01, Simon Horman wrote:\n>>>>> On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n>>>>>> From: Paul Blakey <paulb@mellanox.com>\n>>>>>>\n>>>>>> To be later used to implement ovs action set offloading.\n>>>>>>\n>>>>>> Signed-off-by: Paul Blakey <paulb@mellanox.com>\n>>>>>> Reviewed-by: Roi Dayan <roid@mellanox.com>\n>>>>>> ---\n>>>>>>    lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n>>>>>>    lib/tc.h |  16 +++\n>>>>>>    2 files changed, 385 insertions(+), 3 deletions(-)\n>>>>>>\n>>>>>> diff --git a/lib/tc.c b/lib/tc.c\n>>>>>> index c9cada2..743b2ee 100644\n>>>>>> --- a/lib/tc.c\n>>>>>> +++ b/lib/tc.c\n>>>>>> @@ -21,8 +21,10 @@\n>>>>>>    #include <errno.h>\n>>>>>>    #include <linux/if_ether.h>\n>>>>>>    #include <linux/rtnetlink.h>\n>>>>>> +#include <linux/tc_act/tc_csum.h>\n>>>>>>    #include <linux/tc_act/tc_gact.h>\n>>>>>>    #include <linux/tc_act/tc_mirred.h>\n>>>>>> +#include <linux/tc_act/tc_pedit.h>\n>>>>>>    #include <linux/tc_act/tc_tunnel_key.h>\n>>>>>>    #include <linux/tc_act/tc_vlan.h>\n>>>>>>    #include <linux/gen_stats.h>\n>>>>>> @@ -33,11 +35,14 @@\n>>>>>>    #include \"netlink-socket.h\"\n>>>>>>    #include \"netlink.h\"\n>>>>>>    #include \"openvswitch/ofpbuf.h\"\n>>>>>> +#include \"openvswitch/util.h\"\n>>>>>>    #include \"openvswitch/vlog.h\"\n>>>>>>    #include \"packets.h\"\n>>>>>>    #include \"timeval.h\"\n>>>>>>    #include \"unaligned.h\"\n>>>>>> +#define MAX_PEDIT_OFFSETS 8\n>>>>>\n>>>>> Why 8?\n>>>> We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n>>>> pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n>>>> that's makes sens. do you suggest we increase it? to what?\n>>>\n>>> It seems strange to me to place a somewhat arbitrary small limit\n>>> when none exists in the pedit API being used. I would at prefer if\n>>> it was at least a bigger, say 16 or 32.\n>>\n> \n>> Hi Simon,\n>>\n>> Sorry for the late reply due to holidays and vacations.\n>> Me & Paul going to go over this and do the fixes needed and\n>> also rebase over latest master and run tests again.\n>>\n>> I'll answer what I'm more familiar with now and Paul will continue.\n>> The 8 here is too low and you right. We used this definition\n>> for allocation of the pedit keys on the stack in\n>> nl_msg_put_flower_rewrite_pedits()\n>>\n>> It was for convenience instead of calculating the maximum possible\n>> keys that could exists and allocating it there and freeing it at\n>> the end.\n>>\n>> Increasing it to 32 is probably more than enough and wont waste much.\n> \n> I updated the value to 32 when applying the patch.\n> \n> ...\n> \n>>>>> If I understand the above correctly it is designed to make\n>>>>> pedit actions disjoint. If so, why is that necessary? >\n>>>>\n>>>> It's not, as a single flower key rewrite can be split to multiple pedit\n>>>> actions it finds the overlap between a flower key and a pedit action, if\n>>>> they do overlap it translates it to the correct offset and masks it out.\n>>>\n>>> Thanks, understood.\n>>>\n>>>>\n>>>>>> +        } else {\n>>>>>> +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n>>>>>> +                        nl_attr_type(nla));\n>>>>>> +            return EOPNOTSUPP;\n>>>>>> +        }\n>>>>>\n>>>>> I think the code could exit early here as\n>>>>> nl_msg_put_flower_rewrite_pedits() does below.\n>>>>>\n>>>>\n>>>> Sorry, didn't understand. can you give an example?\n>>>>\n>>>\n>>> I meant something like this.\n>>>\n>>>               if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n>>>                   VLOG_ERR_RL(...);\n>>>                   return EOPNOTSUPP;\n>>>               }\n>>\n>> understood. we'll do that. thanks.\n> \n> I also fixed this when applying the patch.\n> \n> ...\n> \n\n\nThanks Simon. sorry we were not responsive enough with this feature.\nWe'll improve that.","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=Mellanox.com header.i=@Mellanox.com\n\theader.b=\"c5jOng/e\"; dkim-atps=neutral","spf=none (sender IP is )\n\tsmtp.mailfrom=roid@mellanox.com; "],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3yfj6R2jhFz9ryk\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSun, 19 Nov 2017 17:45:50 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 6B242722;\n\tSun, 19 Nov 2017 06:45:46 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 1A3A5516\n\tfor <dev@openvswitch.org>; Sun, 19 Nov 2017 06:45:45 +0000 (UTC)","from EUR01-HE1-obe.outbound.protection.outlook.com\n\t(mail-he1eur01on0066.outbound.protection.outlook.com [104.47.0.66])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 3C22888\n\tfor <dev@openvswitch.org>; Sun, 19 Nov 2017 06:45:43 +0000 (UTC)","from [10.223.0.122] (193.47.165.251) by\n\tDB6PR0501MB2246.eurprd05.prod.outlook.com (2603:10a6:4:4b::27) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.218.12;\n\tSun, 19 Nov 2017 06:45:38 +0000"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com;\n\ts=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version;\n\tbh=vzHkql3lKR+0WIPI5tefx0nYXuNp60wZ0apAn4Dcbvg=;\n\tb=c5jOng/eAGyIHsoI0UDsZMaTbXRSw7SNBFg36owwmJB4njppxgJXln49Gm/6L36QDcua5mbYpeAqbc1lAgthETfRuu4x7Seps3UsQPcaSbBskA5D5TcW/RZT/+xKfDaHkvD3tEwZcz9J9HfSiiWjsw78Gx1dgBRm0xu8NYjHNg4=","To":"Simon Horman <simon.horman@netronome.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>\n\t<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>\n\t<20171116162906.cfw46ejbz3rxm3rz@netronome.com>","From":"Roi Dayan <roid@mellanox.com>","Message-ID":"<88e27e92-c6d9-86dc-ad17-fec20b73e6ee@mellanox.com>","Date":"Sun, 19 Nov 2017 08:45:19 +0200","User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101\n\tThunderbird/52.4.0","MIME-Version":"1.0","In-Reply-To":"<20171116162906.cfw46ejbz3rxm3rz@netronome.com>","Content-Language":"en-US","X-Originating-IP":"[193.47.165.251]","X-ClientProxiedBy":"VI1PR0701CA0039.eurprd07.prod.outlook.com\n\t(2603:10a6:800:90::25) To DB6PR0501MB2246.eurprd05.prod.outlook.com\n\t(2603:10a6:4:4b::27)","X-MS-PublicTrafficType":"Email","X-MS-Office365-Filtering-Correlation-Id":"50531d6f-be5f-49b4-5f2f-08d52f192538","X-MS-Office365-Filtering-HT":"Tenant","X-Microsoft-Antispam":"UriScan:; BCL:0; PCL:0;\n\tRULEID:(22001)(4534020)(4602075)(4627115)(201703031133081)(201702281549075)(48565401081)(2017052603199);\n\tSRVR:DB6PR0501MB2246; ","X-Microsoft-Exchange-Diagnostics":["1; DB6PR0501MB2246;\n\t3:GEQ33gQp20PE5pUqavXxTiDDp/Qz2F8oUBqmOkhArGsvx6RUWHcuoHrLYnMED1DKrBLnb1ctwl2wqBAE+VJ+pjtPMKoFVnD5d2rh6S6Ec5jIuVHJv0epr7GFhLyJreIMTVetfgZ826P9cni22WzFoG6t83dscwElZ64NzYNwxfzh9Rc4eAknXjARzFll+VKrCmAgdIIFc6IQCiimnei/MITjYu1V1se60ro2OyR20qtmYR4V1jLK6Qz003UcKZvj;\n\t25:qygt3/VsJNAzCtvsxkIM80F7SJA78fYJ5j5efBhZqAdGfK5p/v+Y81mBrvgTDD7LRcICxu2mz2P8cuMclU4ubMlsCcEaoeeM3cj9k5oEBCkRAYPJ/ZYt9j8PiLMDQTEDDZKJjh4SvEDexmBNMYncKlDPd/eI5/9vhfvpWkQpKfi020NaZ8ZyGPn0HtELFxPRXiEBQUya9AgAa0n+uJT92hNBBAIHpFBidl0a84w8JFh/qagiGY4IfWA1ux/nhnmLa/ZY4m4CR0HEK0pzkQ5drq7K2Hypqyaa9HCu0p/tgZD3CbKimYMF7VILuPEdL744U0HXRszE8dTPHOGnIKrn0A==;\n\t31:PAfgo0uK4Jd2QXcYSnsorbSl9keC9SiPuUB5sWUnAZ326WJLlT7UoHk+AFZOVf5UvWU06hPRJas29dVUWezb3bAniC26Bj+bjqR/jSYsXPjI0XYoh+iLCO5u9S2cNfNO85mTwh7zVxzewPDLDCJQGolJLZxSRaxRRNxmsnpMDsCNj9oXEoQCRejYq2N4gMtApX8J23Bpv4xvABnS1upwH2CNTfQ/q0w3Sm2H9QeYD4Y=","1; DB6PR0501MB2246;\n\t20:t5IldfJ+DtkcP+kQF2WFiI+bXJCiQcDNB3JogE9Y49RChI3k3iiGRioiIhRzWbUbopsfYrU93J4GK+H1kmQPO3BkIVqWw4MX/BOK4XGB6/HwV3hlGDRz8CW1FNxF4y/KUUfpNKHUF2OVtIOHfR1rFPXURaejoESS8ZmL2HikggyBg+/yogWTh18/hf1JtlXr/xZRiUfXj60nG2rFnZKPRW0yA8oFBamdrrwNnhvCEzrDTO3UnjQbnJrcqPKWu1xhnbC4XMaxEtX6JoHfI6lMG8gH3ET9pj1HSxcEDYpEmy8WTwO+gKicuYXU4iRgu35tXE6LsldMiuM5tZJGi1eNRV1uEhSydQH5AYG0lWL2lrgfJvsNOLfsu2u3x3opfePIIKQgq133d6ED1pCgOwbP7jwLXqOj83NXAAEju/sZUjR4kjIRCrqcCg2176hNpSBPccD58TcCphru9wI11AxmMR3AGcuSbDFGpu79VTL+ALpunN+PBg1NkWme/wfB6TTY;\n\t4:ax28+V9043Om4eQ6yseiRX1O2uypctAiF8lsitKL9p0KPlwslME5SvuPNKiIwGFUdSs9uonl08MpHOQTeU5CAIYT9SKBCQFKNK9kGK/2NCfJavOs0/rYBAaAs/h7CdGZFRpnHKrQmX7D7KmkOspOBKbbCosuSZPJm2UHS2S7gvZ7O+EYXefftKYLnvwUkqdxbiekTS+dBcw3Ozt5We2LgMshYE5NHDhbsesGyQhSWJU+yBy4vsLSkoyFyjyG6W9IXpJLU7vtZNYegKmTD56JKg==","=?utf-8?q?1=3BDB6PR0501MB2246=3B23=3Ae0?=\n\t=?utf-8?q?U0T+x9GPY6AxKqVMBzUGyBBObtGCEbixOfwRF/4KwKZ3EKiOGeB9SRSt?=\n\t=?utf-8?q?9nRwEyMZ860ZR+LrLkOBZ5PYsAQUQiFcFzl62yHP1UkKvjJiKorbPKPm?=\n\t=?utf-8?q?lZhWXY4LKG5Wve1vKxeEagr8T/sZY88NbD68QmGFk9M7ErasPjqt0+PE?=\n\t=?utf-8?q?WHznuOUXq4Fovl0kGXWzh6jPHpK20ohL/F0fO222SY4xS24/+frCKG6I?=\n\t=?utf-8?q?PPHB1zVXq12YSlQxPey+09+4yQf0SLIz1G4p0G5TWDsTMKpeDbkDVZbO?=\n\t=?utf-8?q?ykaxpofwTrihwxhS6C3AskOtOLs1XCUKqvXcM8f+niksCYzHU6mquH3W?=\n\t=?utf-8?q?ncDJ8Txu6DNeosGS2lRtdN8FOhVDofSE8F5aViXh71PHdwj4o7cI2G1n?=\n\t=?utf-8?q?CT5dNHs1QQuLFr0auQP+IS7gI39GMFoaa15cT436ia8ZHlhOthalJ9dJ?=\n\t=?utf-8?q?StQBA29k6SmGQ6ywK6/zmSq72FrTYk26wCmbuNCpL4uUeHe75ZeBc0gB?=\n\t=?utf-8?q?nrPelfJALWepEwosAMD/4DsGpOfXFTSH5RDSs01IHb9UwxOckSeyFaq+?=\n\t=?utf-8?q?2tZrX+627AvDvu4JNuOAHETNM0L3OBcsPbWxrUo5N7jvU8hgTPG7mph/?=\n\t=?utf-8?q?Y2LWPry9l6Wg44Et9oAHzWrKsY++9xaU6/sSgYQyKa1rmQOVDyknQ7pS?=\n\t=?utf-8?q?MShdOFWKY0RO6fQFtNgiqGOWhfsHkojnS36f04fEHzCUhtzKCmZcqg5i?=\n\t=?utf-8?q?uVZeCjJMPi0FmmNkuDHfrDmShAMDQ3/eLL0OXAa6KgRNo3pNT4BBMSdl?=\n\t=?utf-8?q?XUzWrQPK/EWELo+1tfDFeewolrUg5BWIZ4cDA6wCZOVv0JQsUTFVUkTC?=\n\t=?utf-8?q?EBPcok8r9akjRhpDgwc3cf3dWcyAztY2xE3nlesm+2+hXaYgrL7tOmzJ?=\n\t=?utf-8?q?q3t4sDmdBs4zqcbYptFySfrye1A4ZzOUo7GhqGp9AUrkd/B4zpahCmHU?=\n\t=?utf-8?q?luSRIiDhKSM89YvPBeWYg2N05doDrX8LLTnkal7KFCoeFd+0OuRo3PY+?=\n\t=?utf-8?q?IrJA0+PHSV0xUwryizNtucGYrhLeBfW/x49cwKeZyaxi6ahWHcVzaYGr?=\n\t=?utf-8?q?Bho8ayjkahZBvydgAUh2z3ii0XC2m1NZC+6PAeENFtC+sWwePCuoS6Eq?=\n\t=?utf-8?q?kVR/YtFPJYorzNtkrJ7gCMeXrSiikDjEZPV4jPxfiy7qZwPHJXvqRF3Q?=\n\t=?utf-8?q?pm5z6djnO7qrOBzYIhBb8LJKGL5732/9Mo0DP+R5ajS86SBkcdUDh5eT?=\n\t=?utf-8?q?DvLCDrlxLdm6TS6ezQAqKSV0+A171K9FiLKfkYEl7R6xwv+S0Q+ovBKz?=\n\t=?utf-8?q?nUisCTlrwNb4SDuhIQfA6SO8s7ntKcMWT65Gd/+Ebo9ZAOVuT319Ob3B?=\n\t=?utf-8?q?925lu3ohF36vB84NIv3oPtq923GHc8C4ikUY3kELn2FhWV3g7YIf47zz?=\n\t=?utf-8?q?KsEXBSkSpmWTiVrkRkgW+AqkDncCyXnMrZLAh4Mjxw5PK8xK0FKFsBik?=\n\t=?utf-8?q?Ad1EG2DxCxGZ1K?=","1; DB6PR0501MB2246;\n\t6:ofur3OhqraI8MScSaLzTiDwio9WeZx2Djh78kYlBEqDU7pW6b+MkZd6P6534KIOnKeh/A/3bm1IiWGJhHpSvMYMWE0NKurgsN0co6xZWOpYR7AQduWvgTP2QVh6nYghhx0xsJe81qtN9JYu8TRKLEbMgwg+Su828xwzLnnDRzbFvWWNLMBFnv/HR7+dTw/Ihzvxzq0jl6wOHY8cADpYC5NwE/tX24T7WiyoTfML0xImewhowuacEyh5sXwQSfxMADkdTFAfPJlrBIzkL7gfG7KqVj9ka23sQE1iL6G7uO5OhwM+7oBB7746SBlFwFm3gQqCzQlr57Zt7iHn7XghSjfZkD80A41FHhoMPR7sXq/A=;\n\t5:Ctb1TKqC3kMPUKmijoW+jkGIjty3cCBjnt6hOayGqBpUbFkpdznTlsivUtd+MfSDNU4NUH6H70vOPrTXa5mM2VU7Pd0c/3i9rjD5XHHgzG/MpGM3MxsUZGT47umdVEBjTxEJkBKV5ZRHoUEdZEC791gKrrtmyqTR7yTWPEe64rY=;\n\t24:qMARGzKpYgdQulOEcTvYPg84wO31pZqekjAECXq7PQR6NhS7ED+oRP2Cfal06hsqu1U1Chy9rgs7GJ7lQ/+8o2GmSiSP9YfzWdzzR1KCad0=;\n\t7:CxZEkreNDm9cpUXuF0TlOQn4SD63Ya0hNp/lIBxTw7GZkRMAVCBZoxgfBtyGOk26MaaaVhbelzwzdmfu+4TVQaB2De2tsE5ohIST+2Fau+iXSvDxxB8YLsD1F1M8/BcIc7OZytqFUI0nWc3h8Ws5hXTGYIdvUkMETYNMg9C7ySRvWOYuCZHtQ2FV31HicvUiJn3Q9gXKjFxoEmh6Fl6xh0697V3yD/kCNld3pYgWoJW6wX/N5XOalaYjKYSHGg/D"],"X-MS-TrafficTypeDiagnostic":"DB6PR0501MB2246:","X-Microsoft-Antispam-PRVS":"<DB6PR0501MB2246E31C4873DE7701F357D4B52D0@DB6PR0501MB2246.eurprd05.prod.outlook.com>","X-Exchange-Antispam-Report-Test":"UriScan:;","X-Exchange-Antispam-Report-CFA-Test":"BCL:0; PCL:0;\n\tRULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(5005006)(8121501046)(100000703101)(100105400095)(3231022)(10201501046)(3002001)(93006095)(93001095)(6055026)(6041248)(20161123555025)(20161123560025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123564025)(20161123562025)(20161123558100)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);\n\tSRVR:DB6PR0501MB2246; BCL:0; PCL:0;\n\tRULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);\n\tSRVR:DB6PR0501MB2246; ","X-Forefront-PRVS":"0496DF6962","X-Forefront-Antispam-Report":"SFV:NSPM;\n\tSFS:(10009020)(6049001)(6009001)(39860400002)(376002)(346002)(199003)(189002)(24454002)(58126008)(64126003)(16576012)(5660300001)(316002)(65826007)(54356999)(76176999)(2950100002)(6916009)(6666003)(4326008)(31696002)(86362001)(50986999)(50466002)(101416001)(31686004)(6246003)(77096006)(6486002)(7736002)(53936002)(68736007)(229853002)(93886005)(81156014)(305945005)(39060400002)(83506002)(2906002)(36756003)(478600001)(16526018)(106356001)(97736004)(230700001)(105586002)(81166006)(47776003)(8936002)(6116002)(3846002)(33646002)(189998001)(67846002)(23676003)(54906003)(66066001)(65956001)(53546010)(3260700006)(8676002)(25786009)(65806001);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:DB6PR0501MB2246; H:[10.223.0.122];\n\tFPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; ","Received-SPF":"None (protection.outlook.com: mellanox.com does not designate\n\tpermitted sender hosts)","SpamDiagnosticOutput":"1:99","SpamDiagnosticMetadata":"NSPM","X-OriginatorOrg":"Mellanox.com","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"19 Nov 2017 06:45:38.0745\n\t(UTC)","X-MS-Exchange-CrossTenant-Network-Message-Id":"50531d6f-be5f-49b4-5f2f-08d52f192538","X-MS-Exchange-CrossTenant-FromEntityHeader":"Hosted","X-MS-Exchange-CrossTenant-Id":"a652971c-7d2e-4d9b-a6a4-d149256f461b","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"DB6PR0501MB2246","X-Spam-Status":"No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n\tDKIM_VALID, DKIM_VALID_AU,\n\tRCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Transfer-Encoding":"7bit","Content-Type":"text/plain; charset=\"us-ascii\"; Format=\"flowed\"","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1807290,"web_url":"http://patchwork.ozlabs.org/comment/1807290/","msgid":"<20171120123037.z7yx3cfje6rs5dvx@netronome.com>","list_archive_url":null,"date":"2017-11-20T12:30:38","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":64714,"url":"http://patchwork.ozlabs.org/api/people/64714/","name":"Simon Horman","email":"simon.horman@netronome.com"},"content":"On Sun, Nov 19, 2017 at 08:45:19AM +0200, Roi Dayan wrote:\n> \n> \n> On 16/11/2017 18:29, Simon Horman wrote:\n> > On Wed, Oct 25, 2017 at 02:24:15PM +0300, Roi Dayan wrote:\n> > > \n> > > \n> > > On 27/09/2017 12:08, Simon Horman wrote:\n> > > > On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n> > > > > \n> > > > > \n> > > > > On 18/09/2017 18:01, Simon Horman wrote:\n> > > > > > On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n> > > > > > > From: Paul Blakey <paulb@mellanox.com>\n> > > > > > > \n> > > > > > > To be later used to implement ovs action set offloading.\n> > > > > > > \n> > > > > > > Signed-off-by: Paul Blakey <paulb@mellanox.com>\n> > > > > > > Reviewed-by: Roi Dayan <roid@mellanox.com>\n> > > > > > > ---\n> > > > > > >    lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n> > > > > > >    lib/tc.h |  16 +++\n> > > > > > >    2 files changed, 385 insertions(+), 3 deletions(-)\n> > > > > > > \n> > > > > > > diff --git a/lib/tc.c b/lib/tc.c\n> > > > > > > index c9cada2..743b2ee 100644\n> > > > > > > --- a/lib/tc.c\n> > > > > > > +++ b/lib/tc.c\n> > > > > > > @@ -21,8 +21,10 @@\n> > > > > > >    #include <errno.h>\n> > > > > > >    #include <linux/if_ether.h>\n> > > > > > >    #include <linux/rtnetlink.h>\n> > > > > > > +#include <linux/tc_act/tc_csum.h>\n> > > > > > >    #include <linux/tc_act/tc_gact.h>\n> > > > > > >    #include <linux/tc_act/tc_mirred.h>\n> > > > > > > +#include <linux/tc_act/tc_pedit.h>\n> > > > > > >    #include <linux/tc_act/tc_tunnel_key.h>\n> > > > > > >    #include <linux/tc_act/tc_vlan.h>\n> > > > > > >    #include <linux/gen_stats.h>\n> > > > > > > @@ -33,11 +35,14 @@\n> > > > > > >    #include \"netlink-socket.h\"\n> > > > > > >    #include \"netlink.h\"\n> > > > > > >    #include \"openvswitch/ofpbuf.h\"\n> > > > > > > +#include \"openvswitch/util.h\"\n> > > > > > >    #include \"openvswitch/vlog.h\"\n> > > > > > >    #include \"packets.h\"\n> > > > > > >    #include \"timeval.h\"\n> > > > > > >    #include \"unaligned.h\"\n> > > > > > > +#define MAX_PEDIT_OFFSETS 8\n> > > > > > \n> > > > > > Why 8?\n> > > > > We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n> > > > > pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n> > > > > that's makes sens. do you suggest we increase it? to what?\n> > > > \n> > > > It seems strange to me to place a somewhat arbitrary small limit\n> > > > when none exists in the pedit API being used. I would at prefer if\n> > > > it was at least a bigger, say 16 or 32.\n> > > \n> > \n> > > Hi Simon,\n> > > \n> > > Sorry for the late reply due to holidays and vacations.\n> > > Me & Paul going to go over this and do the fixes needed and\n> > > also rebase over latest master and run tests again.\n> > > \n> > > I'll answer what I'm more familiar with now and Paul will continue.\n> > > The 8 here is too low and you right. We used this definition\n> > > for allocation of the pedit keys on the stack in\n> > > nl_msg_put_flower_rewrite_pedits()\n> > > \n> > > It was for convenience instead of calculating the maximum possible\n> > > keys that could exists and allocating it there and freeing it at\n> > > the end.\n> > > \n> > > Increasing it to 32 is probably more than enough and wont waste much.\n> > \n> > I updated the value to 32 when applying the patch.\n> > \n> > ...\n> > \n> > > > > > If I understand the above correctly it is designed to make\n> > > > > > pedit actions disjoint. If so, why is that necessary? >\n> > > > > \n> > > > > It's not, as a single flower key rewrite can be split to multiple pedit\n> > > > > actions it finds the overlap between a flower key and a pedit action, if\n> > > > > they do overlap it translates it to the correct offset and masks it out.\n> > > > \n> > > > Thanks, understood.\n> > > > \n> > > > > \n> > > > > > > +        } else {\n> > > > > > > +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n> > > > > > > +                        nl_attr_type(nla));\n> > > > > > > +            return EOPNOTSUPP;\n> > > > > > > +        }\n> > > > > > \n> > > > > > I think the code could exit early here as\n> > > > > > nl_msg_put_flower_rewrite_pedits() does below.\n> > > > > > \n> > > > > \n> > > > > Sorry, didn't understand. can you give an example?\n> > > > > \n> > > > \n> > > > I meant something like this.\n> > > > \n> > > >               if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n> > > >                   VLOG_ERR_RL(...);\n> > > >                   return EOPNOTSUPP;\n> > > >               }\n> > > \n> > > understood. we'll do that. thanks.\n> > \n> > I also fixed this when applying the patch.\n> > \n> > ...\n> > \n> \n> \n> Thanks Simon. sorry we were not responsive enough with this feature.\n> We'll improve that.\n> \n\nNo problem.\n\nCould you work on a fix for the travis failure that Eric Garver flagged?","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=netronome-com.20150623.gappssmtp.com\n\theader.i=@netronome-com.20150623.gappssmtp.com\n\theader.b=\"DY17OBBF\"; dkim-atps=neutral"],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3ygSjy5KWdz9ryQ\n\tfor <incoming@patchwork.ozlabs.org>;\n\tMon, 20 Nov 2017 23:30:46 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id BE007ABB;\n\tMon, 20 Nov 2017 12:30:43 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 42016AA6\n\tfor <dev@openvswitch.org>; Mon, 20 Nov 2017 12:30:42 +0000 (UTC)","from mail-wm0-f50.google.com (mail-wm0-f50.google.com\n\t[74.125.82.50])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 7916A113\n\tfor <dev@openvswitch.org>; Mon, 20 Nov 2017 12:30:41 +0000 (UTC)","by mail-wm0-f50.google.com with SMTP id y82so6199017wmg.1\n\tfor <dev@openvswitch.org>; Mon, 20 Nov 2017 04:30:41 -0800 (PST)","from netronome.com ([217.111.208.18])\n\tby smtp.gmail.com with ESMTPSA id\n\tp42sm23203896wrb.28.2017.11.20.04.30.39\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tMon, 20 Nov 2017 04:30:39 -0800 (PST)"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=netronome-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=JYwD7JS41ivjAV7PrdiUXjdj4htLIrRMXfZLBBRHYZs=;\n\tb=DY17OBBFatttVLJxFHfGqmjUCDHm8O3wr5T2mu8/hVSSpdMOg6l468gFSMDiIc7I40\n\tkLQ2cA5F7M1gGSWBjGEBr1D2SopEwmaRC9RWCU+xH4v06BTKy4ETHhwgd+hmXYodQ94N\n\ta/Wa1nweFW+FOXUm+49SzqQrwvw4ODeZur2ZEl7HG867Ygn/0y/ZybvsU1QmjfMdKhE8\n\tgJAxgfWznK7rpKwqM3+OP7SYiiVWHnmJdaO9BNCfX1iQn3danQwwmCe9/GdTpbNQZpeT\n\tYkkqS1s881MiOIiB4IDOrq4cU+afDWcP47nI0lUN5H21zW3y0tSJJc9LxTCXgaXyivmv\n\tDT3Q==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=JYwD7JS41ivjAV7PrdiUXjdj4htLIrRMXfZLBBRHYZs=;\n\tb=owPBQrDBFTvV2jbEMLtU0zqwDXNTcEGbs2N/2in9AshA/s0n+BCvw4d6Z53to/fjYr\n\t353eMmj1kN8oUT6xJ/bsw4qZSBo/9LPfw2bx2z+Z2qHIh92ShDwBPot5qBn4lze2PEf4\n\tYyy8NsNP4UJmX2OpGlTUKzMmBHTcmjPXSUL8/NMvxx0sbn4PqmgPqH07Ce8Mb6yQjTLx\n\tfa3h34VIPUHZ/l0P75K4BWnkvv4sJO4zDH6+ZoKubNQbWeJ3znZ8HrPMYtJ/HBP/Y9jM\n\t4q34CUF/sS0Hvzu6Etu64m7xoRo920cU46w3GIq8OsH5hZZdxniPPxdGgbSCBeuO5zuN\n\tP0dA==","X-Gm-Message-State":"AJaThX6ggSP7rm9IfZQvnR3xCAXPUCuoUeCoAggpuaBqATrj6J5NGbx1\n\tiEB5QpwpxvA3uFI59vWmvCH03A==","X-Google-Smtp-Source":"AGs4zMZAEY745xd7qxlrkjXDSyeeqM6HBnWBoaUOI4idoKhp0OMqpLGr/BBClPhhjzNYbKbQ3gNzNw==","X-Received":"by 10.28.134.73 with SMTP id i70mr9646827wmd.107.1511181040076; \n\tMon, 20 Nov 2017 04:30:40 -0800 (PST)","Date":"Mon, 20 Nov 2017 13:30:38 +0100","From":"Simon Horman <simon.horman@netronome.com>","To":"Roi Dayan <roid@mellanox.com>","Message-ID":"<20171120123037.z7yx3cfje6rs5dvx@netronome.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>\n\t<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>\n\t<20171116162906.cfw46ejbz3rxm3rz@netronome.com>\n\t<88e27e92-c6d9-86dc-ad17-fec20b73e6ee@mellanox.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<88e27e92-c6d9-86dc-ad17-fec20b73e6ee@mellanox.com>","User-Agent":"NeoMutt/20170113 (1.7.2)","X-Spam-Status":"No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n\tDKIM_VALID,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1807869,"web_url":"http://patchwork.ozlabs.org/comment/1807869/","msgid":"<b0b560a7-0e0a-b86a-1488-091f939a2b50@mellanox.com>","list_archive_url":null,"date":"2017-11-21T05:50:24","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":70307,"url":"http://patchwork.ozlabs.org/api/people/70307/","name":"Roi Dayan","email":"roid@mellanox.com"},"content":"On 20/11/2017 14:30, Simon Horman wrote:\n> On Sun, Nov 19, 2017 at 08:45:19AM +0200, Roi Dayan wrote:\n>>\n>>\n>> On 16/11/2017 18:29, Simon Horman wrote:\n>>> On Wed, Oct 25, 2017 at 02:24:15PM +0300, Roi Dayan wrote:\n>>>>\n>>>>\n>>>> On 27/09/2017 12:08, Simon Horman wrote:\n>>>>> On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n>>>>>>\n>>>>>>\n>>>>>> On 18/09/2017 18:01, Simon Horman wrote:\n>>>>>>> On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n>>>>>>>> From: Paul Blakey <paulb@mellanox.com>\n>>>>>>>>\n>>>>>>>> To be later used to implement ovs action set offloading.\n>>>>>>>>\n>>>>>>>> Signed-off-by: Paul Blakey <paulb@mellanox.com>\n>>>>>>>> Reviewed-by: Roi Dayan <roid@mellanox.com>\n>>>>>>>> ---\n>>>>>>>>     lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n>>>>>>>>     lib/tc.h |  16 +++\n>>>>>>>>     2 files changed, 385 insertions(+), 3 deletions(-)\n>>>>>>>>\n>>>>>>>> diff --git a/lib/tc.c b/lib/tc.c\n>>>>>>>> index c9cada2..743b2ee 100644\n>>>>>>>> --- a/lib/tc.c\n>>>>>>>> +++ b/lib/tc.c\n>>>>>>>> @@ -21,8 +21,10 @@\n>>>>>>>>     #include <errno.h>\n>>>>>>>>     #include <linux/if_ether.h>\n>>>>>>>>     #include <linux/rtnetlink.h>\n>>>>>>>> +#include <linux/tc_act/tc_csum.h>\n>>>>>>>>     #include <linux/tc_act/tc_gact.h>\n>>>>>>>>     #include <linux/tc_act/tc_mirred.h>\n>>>>>>>> +#include <linux/tc_act/tc_pedit.h>\n>>>>>>>>     #include <linux/tc_act/tc_tunnel_key.h>\n>>>>>>>>     #include <linux/tc_act/tc_vlan.h>\n>>>>>>>>     #include <linux/gen_stats.h>\n>>>>>>>> @@ -33,11 +35,14 @@\n>>>>>>>>     #include \"netlink-socket.h\"\n>>>>>>>>     #include \"netlink.h\"\n>>>>>>>>     #include \"openvswitch/ofpbuf.h\"\n>>>>>>>> +#include \"openvswitch/util.h\"\n>>>>>>>>     #include \"openvswitch/vlog.h\"\n>>>>>>>>     #include \"packets.h\"\n>>>>>>>>     #include \"timeval.h\"\n>>>>>>>>     #include \"unaligned.h\"\n>>>>>>>> +#define MAX_PEDIT_OFFSETS 8\n>>>>>>>\n>>>>>>> Why 8?\n>>>>>> We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n>>>>>> pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n>>>>>> that's makes sens. do you suggest we increase it? to what?\n>>>>>\n>>>>> It seems strange to me to place a somewhat arbitrary small limit\n>>>>> when none exists in the pedit API being used. I would at prefer if\n>>>>> it was at least a bigger, say 16 or 32.\n>>>>\n>>>\n>>>> Hi Simon,\n>>>>\n>>>> Sorry for the late reply due to holidays and vacations.\n>>>> Me & Paul going to go over this and do the fixes needed and\n>>>> also rebase over latest master and run tests again.\n>>>>\n>>>> I'll answer what I'm more familiar with now and Paul will continue.\n>>>> The 8 here is too low and you right. We used this definition\n>>>> for allocation of the pedit keys on the stack in\n>>>> nl_msg_put_flower_rewrite_pedits()\n>>>>\n>>>> It was for convenience instead of calculating the maximum possible\n>>>> keys that could exists and allocating it there and freeing it at\n>>>> the end.\n>>>>\n>>>> Increasing it to 32 is probably more than enough and wont waste much.\n>>>\n>>> I updated the value to 32 when applying the patch.\n>>>\n>>> ...\n>>>\n>>>>>>> If I understand the above correctly it is designed to make\n>>>>>>> pedit actions disjoint. If so, why is that necessary? >\n>>>>>>\n>>>>>> It's not, as a single flower key rewrite can be split to multiple pedit\n>>>>>> actions it finds the overlap between a flower key and a pedit action, if\n>>>>>> they do overlap it translates it to the correct offset and masks it out.\n>>>>>\n>>>>> Thanks, understood.\n>>>>>\n>>>>>>\n>>>>>>>> +        } else {\n>>>>>>>> +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n>>>>>>>> +                        nl_attr_type(nla));\n>>>>>>>> +            return EOPNOTSUPP;\n>>>>>>>> +        }\n>>>>>>>\n>>>>>>> I think the code could exit early here as\n>>>>>>> nl_msg_put_flower_rewrite_pedits() does below.\n>>>>>>>\n>>>>>>\n>>>>>> Sorry, didn't understand. can you give an example?\n>>>>>>\n>>>>>\n>>>>> I meant something like this.\n>>>>>\n>>>>>                if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n>>>>>                    VLOG_ERR_RL(...);\n>>>>>                    return EOPNOTSUPP;\n>>>>>                }\n>>>>\n>>>> understood. we'll do that. thanks.\n>>>\n>>> I also fixed this when applying the patch.\n>>>\n>>> ...\n>>>\n>>\n>>\n>> Thanks Simon. sorry we were not responsive enough with this feature.\n>> We'll improve that.\n>>\n> \n> No problem.\n> \n> Could you work on a fix for the travis failure that Eric Garver flagged?\n> \n\nyes we have a fix. we did more fixes and running some tests. we'll push\nthe fixes today.","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=Mellanox.com header.i=@Mellanox.com\n\theader.b=\"uyeCiDSQ\"; dkim-atps=neutral","spf=none (sender IP is )\n\tsmtp.mailfrom=roid@mellanox.com; "],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3ygvny5vL9z9s7B\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 21 Nov 2017 16:50:46 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id A514F9F0;\n\tTue, 21 Nov 2017 05:50:42 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id DAADE259\n\tfor <dev@openvswitch.org>; Tue, 21 Nov 2017 05:50:41 +0000 (UTC)","from EUR01-HE1-obe.outbound.protection.outlook.com\n\t(mail-he1eur01on0088.outbound.protection.outlook.com [104.47.0.88])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id BE0E714D\n\tfor <dev@openvswitch.org>; Tue, 21 Nov 2017 05:50:40 +0000 (UTC)","from [10.223.0.122] (193.47.165.251) by\n\tHE1PR0501MB2249.eurprd05.prod.outlook.com (2603:10a6:3:26::24) with\n\tMicrosoft SMTP Server (version=TLS1_2,\n\tcipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256) id 15.20.239.5;\n\tTue, 21 Nov 2017 05:50:29 +0000"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=Mellanox.com;\n\ts=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version;\n\tbh=wGI0xAliZNAH4vRhxts5uhFwKd4dUGh61RFl0Vsm6E0=;\n\tb=uyeCiDSQelUoIMofsp1zVNDfn18Lzj4c6OqK0mO0hsOjYYGt205t/WwLGlpiZFmR9P7nmFM9Xl2M1BXtIMuKQfEiODlqiwf6tvJARuv4reWGUO6MlglYe1uKBEZSMICulFqqcfBnkRm9kOLby/qfjqT/SwmpHrlQPGL/SHA6uqA=","To":"Simon Horman <simon.horman@netronome.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>\n\t<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>\n\t<20171116162906.cfw46ejbz3rxm3rz@netronome.com>\n\t<88e27e92-c6d9-86dc-ad17-fec20b73e6ee@mellanox.com>\n\t<20171120123037.z7yx3cfje6rs5dvx@netronome.com>","From":"Roi Dayan <roid@mellanox.com>","Message-ID":"<b0b560a7-0e0a-b86a-1488-091f939a2b50@mellanox.com>","Date":"Tue, 21 Nov 2017 07:50:24 +0200","User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101\n\tThunderbird/52.4.0","MIME-Version":"1.0","In-Reply-To":"<20171120123037.z7yx3cfje6rs5dvx@netronome.com>","Content-Language":"en-US","X-Originating-IP":"[193.47.165.251]","X-ClientProxiedBy":"DB6P193CA0012.EURP193.PROD.OUTLOOK.COM\n\t(2603:10a6:6:29::22)\n\tTo HE1PR0501MB2249.eurprd05.prod.outlook.com\n\t(2603:10a6:3:26::24)","X-MS-PublicTrafficType":"Email","X-MS-Office365-Filtering-Correlation-Id":"d7eba650-d775-4147-285b-08d530a3c643","X-MS-Office365-Filtering-HT":"Tenant","X-Microsoft-Antispam":"UriScan:; BCL:0; PCL:0;\n\tRULEID:(22001)(4534020)(4602075)(4627115)(201703031133081)(201702281549075)(48565401081)(2017052603258);\n\tSRVR:HE1PR0501MB2249; ","X-Microsoft-Exchange-Diagnostics":["1; HE1PR0501MB2249;\n\t3:SlfaW1VjL21Y23B9C0AsphbzrQrbuUodEcu1A2gCpU5F5gHsIRt+PZdCkUrvbRUpOjX1LzdsgaxlenkugKOgwOqZIy8FtXD3Vht14ATPYDhlyLk6CBrA9tABKd80AFS9w9uRhwOGFZQjkVlDYnLCAejQSXWMjABvVQPe0QaBkfXjqftfNqrd0kqzIeAq8I7A2hG2uk3SbMC606hgyafQHD6HvjOsJz6BR6NUV0AgcE8JKSq2hBEbeNKTp/h2nlRS;\n\t25:RqEdyqaTzTz+LYfGWqhUZKS5CPNQbWx0LUxkUeek6fnwStZtlGgBZllhGlBKlT8Hp+4kRsbEhfmYPcG6kUCNvbfaJsfgz7njet7Y8NgCYeAPjnr8EEF2ms8CHKCHjngz/1INbWeoX2U/6F6cDN0d36EhRSg3IkQheh/XiuG9hmLCKDLrgON3a8aQdwi6XgDTzmvN80PPfK7XvnsELAx0pXQ6bfxUIuz12L9d/ZcxCQa9eycmsjlk2ugF0fryj+w/J0BXB9x/mFKY0c5zC8UKFLF5tgv9CjYC+mSS7kucENe/FjsPhZOfrFiAGUrIZoKKQpyV3Q4PjdVxxcy5eCOW8A==;\n\t31:goJnRQ50KwpaQtgaCCBwRkV7j8bes+sbH+2l2BvG1JAah/WbsN/4iWOsp4kHeBlFUFD/cgBDVfCXA2TZkIYFQcxvMwb9CaRoMlrIw1oGKGK2nyDji8Je6Xl7otLp11ZaNLtHfrP4CcIi09DBeKyWSjSVoiq1UvSDkdUVysO345Ry3xdFFQv5l3GaU6264PzaZj29gHLfEaaY2OP50y0j2tg756S/XMFMbaBT688ieZc=","1; HE1PR0501MB2249;\n\t20:uLVsUp2u13hdF7EFzFFs5Ae6RXtlkccq++8t1MgndCd7n8nfIdLkmMOZjewIA0kRQScfgsS5FxyVsDL2nMZObOYwjGwVkk+eWbOKEtKIIqtEU/Qm9LTJp+KHLW1MwN9yS0F47MdTaVzk2zIiYgBVoh9S0Qq6nXgHHa1MHwyn8b6SHpEUXds0wMRhGI4XNDALZLWbX/C6wqxi2rEQJnpH3x+O+kJwnnfwuFPlPf0opubmhPEax2WDMC36ffR0dpgV0wa5wHTlsFeEfzqxRrQOBF4tAtjqzQRofVxkZPnVMr5ReOrpQjbBKkpN1h7kANDqh98KHbJ6D3SiyBGYcsR0PRSOtKrQbYbpSzSGlLG8pLn6OWwiNuegtt7ctED+fVZuP+m9dAr+K1LmpzzxqVrrSYSoqce1WQOPNyp+4KPc1C55Dnt8vn/1H0nzwHvVUZiKOYDKyxwH+aHhOIkjiQJphuUFMtXWX+45DojCW/Rve/yTq+d3J/yqsvelOau/hyWB;\n\t4:CyTOEvluaQsyIxkFt9Ma+wL3hpYnJ7//vCi9XOHIrLIHc8UxLVWoHD0AL6wf8XHoHI9qn0uKLr7Zb8ifiGCPFpliScbdXsd7W9QQCFNwtNahVPwGkYtq945mHWw/neQqDIs23gKex2GJCE9KUkTXgmkG8Dcjy0Ekz1aoZWPn94Ddq3KwyPssqWGsNchxJHrXtEOFy3Kw+Zhx3IFZ80XylgJfwIOT+AQUtCCowXIOfuR+HS7VI9BhNFrgzWiaQf4h0E+pPpL1gi4S/E1NYUiHWQ==","=?utf-8?q?1=3BHE1PR0501MB2249=3B23=3AS2?=\n\t=?utf-8?q?V2xOObZW+58K+kyvNktjVsOQLu7scPb0BhFIyOwIkzzRU18W80a5iH/s?=\n\t=?utf-8?q?3KhVnyUOxqvHl2zsun7dTCVfqYC3+6oqCRAiHbIFowDc8WmO9QAOv67J?=\n\t=?utf-8?q?Bduumj1qJrLOtL9kGSlVBpYq/VdjEV7xRnsYqxdhigecvsc5X5BZT2vt?=\n\t=?utf-8?q?fmyPHn0H1w9TvS5vnAemQrXw9HOYJZq1kky2yrecgoc8+rkzXnqhECGk?=\n\t=?utf-8?q?1pxbTgYb5OfNDde3TlI3ICwjuIFPJnJc46EraQ2wFJSy4EHrWtjxeTzP?=\n\t=?utf-8?q?KlTXXDmawflIChjXYhfP7xpDjx4pOFMw5IQ/yCiqc6c+ojpAlXm/iimA?=\n\t=?utf-8?q?mypI6XTT0nTMxZ4aCTlVmd2+cjmzapSpK2p4Qqz2wA5zuvYGsjuUD8yf?=\n\t=?utf-8?q?xvcFodpyGVF4gY9DGe31ZvPC8YcCJnQKpGVyGZxsGNOwMWnc9qWET6Ve?=\n\t=?utf-8?q?/nOK3nFBxKtqbthuRrF/tkyEFdPESDb2gaR615b4tThB5kJXGPb6ak0W?=\n\t=?utf-8?q?xNICiwSrk0Wm4iwVkUIDFm3pQoIIJ6v6zIdSd2v5npM1tb24KQu/rFbi?=\n\t=?utf-8?q?Y+sTuQHJx5C4567bBau4m7P4eMWORTShUcbIFYextoW+YmNZdRlXRFzs?=\n\t=?utf-8?q?Kd+vs6NIhP0QhVnyU0n4sudpkJO8zudCrAALIKjL4Q31w78pO2CVk6C4?=\n\t=?utf-8?q?mKcYyP/Eb/lgj6txDj4GPtRuP7H4Vbo0KacExvpKFLJTI/pgLO3c3RCn?=\n\t=?utf-8?q?lVUf9iIhVK9cwy1qs2H0QOex/iFiH/BHUPOUp+SYcBv56z52k3v23zCi?=\n\t=?utf-8?q?YOWNErblVWevgrjmOYZPgzp2Q09ZRKPqT7ZfmevpJgGUBYTwsGSz5wVJ?=\n\t=?utf-8?q?+98wPtUtdJ/UNQB5dqxcWFbMRCDzhE13Md4pq3Ms84D9ksHTplIX7BcB?=\n\t=?utf-8?q?AQ7nzg2EOdQ8EUG/7YQzTP/He3xUgJcaqa+0R/AiczOkeW0mdweMBA7J?=\n\t=?utf-8?q?blFXWPofcgullYue+B/CR9gYXlYawKsOrFb4c1GMdzCiSaoPjpcfPr2p?=\n\t=?utf-8?q?z1v0yzosPlXr6u4WEysOnGDQkjq9FyJLQRUr6JuAn7XoOHZHZIeuPGl3?=\n\t=?utf-8?q?HivrUsmaOwlD2dyi27//7qHi/kToZTmuI7H0DTJGnbtcBppxpwpffKhq?=\n\t=?utf-8?q?sbtQNBWoPKyHJOwuwgYYbF6gS+a539ZEgmvwcbSHAv5cKP3U/KmaUTPo?=\n\t=?utf-8?q?NO0jgflEZCY4xWf5FJ8bT7MURgexg7+ANwMO6wPymSldhvHWofHKsjxi?=\n\t=?utf-8?q?Pa7KqOZcgKbg/Hr2pRIkf6K82Utb6yWnRmbE3kx3DVX/56RtKdYbLWiZ?=\n\t=?utf-8?q?CA7nVttz7YSh7M3ZcnmBLu5ChvBGlSK9IN7jsIt3HcbkZxbQJvMd0QAA?=\n\t=?utf-8?q?ke9PA2dKybdZv4YXg7pXZSfD0Sf8CEb8Jn4SGFpgFz8z+756KWohJLG3?=\n\t=?utf-8?q?fzSLA753w2RjByZ+2o1sHpyOZuG/rUw8/xO0NE6XFrOCoJYdCoVnbceo?=\n\t=?utf-8?q?vQ5C21lIvupT7S?=","1; HE1PR0501MB2249;\n\t6:fEHGiFZVwjQP0DSoKYVu+3aQpiyolg5FJ0DNkF+FxRXL7gmWeTKJX0XojtWbSbn2kRuUvjA/WRT7OyImUO4OmJ1rHWAFWgOvGnmZrnSBXDOVe5BIFu4IK+qQCqYQjbQgOY0QVxVsa0pE+wTm+jV9zRPvUBXwOwqb5Eq76hlDcK+UpCe3DLi2+09FukQVq2LM2UT1j5Lr20bXRmXMk+WJdWCx8H0S3b0MeeJXRwLS6Do+EulgufYhb2PFy7e7TCI5pVncb5Ma8e2vkUFA4tN16COtL7vWW1IeL+KqbT3SpYvKGfRVc4DlmOyTQR8Xd5zlesBuS3RBSl+uqnNDgWoC44Ru1+GsP2tgXWbfiWaTxJ8=;\n\t5:nt8HY6tCmTewV/liMAIXsXlB/iSVBRO3qJYSRUJxTiCzYVm+1hSJYQyPyofaGXPDnyiDxYKnl/Y7jX4w+dnGOiutKPpmxLCwN5ABEJCNBVaPtOYpwI9sCdPXld3sc0fWwBQ3/6ebBlIYvmh75Rotg2URb12tYXamdD0L3dgzYXU=;\n\t24:vTipGpn3enNMZXv8I5lEXC6+zpUQ19mluS0VoSbYRIsQP1LBj27nHiidnuYTJ1j0HKEcyhTWiWqhNXx4FerPiFMRT6Yvt/iLGFJ8MxBYLEg=;\n\t7:PX0xR2RmbeRiqpdRIB5hYiyylON0/dOILV1ZX6eltK+VR2N0qaV13f5cIxYRvlasN+GDN4SOKyoHBZuA9u5mIXEkxgfLXalX/xv1m8tPPzCGWj7wDmvmmI34VjMnVMAlNv24TjoZvXwzN98YALwM77hijgJKbwYIT7Rl7I7+NaQEPRslh6blLro9G2Hg8ITupzUQKtQjgHKWtaN8cKgcBfhRpBi9qFFkEDEQs/5N+eDrunH42CAGD5oD5O4cEZom"],"X-MS-TrafficTypeDiagnostic":"HE1PR0501MB2249:","X-Microsoft-Antispam-PRVS":"<HE1PR0501MB22499EA918B743D1F64F4992B5230@HE1PR0501MB2249.eurprd05.prod.outlook.com>","X-Exchange-Antispam-Report-Test":"UriScan:;","X-Exchange-Antispam-Report-CFA-Test":"BCL:0; PCL:0;\n\tRULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(8121501046)(5005006)(3002001)(93006095)(93001095)(10201501046)(3231022)(100000703101)(100105400095)(6055026)(6041248)(20161123560025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123562025)(20161123558100)(20161123564025)(20161123555025)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);\n\tSRVR:HE1PR0501MB2249; BCL:0; PCL:0;\n\tRULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);\n\tSRVR:HE1PR0501MB2249; ","X-Forefront-PRVS":"049897979A","X-Forefront-Antispam-Report":"SFV:NSPM;\n\tSFS:(10009020)(6049001)(6009001)(376002)(346002)(39860400002)(199003)(189002)(24454002)(4326008)(8936002)(189998001)(77096006)(2906002)(97736004)(93886005)(50466002)(66066001)(65956001)(65806001)(33646002)(47776003)(68736007)(31696002)(2950100002)(6666003)(6486002)(230700001)(5660300001)(65826007)(229853002)(31686004)(6116002)(83506002)(6916009)(86362001)(23676003)(101416001)(81156014)(81166006)(58126008)(76176999)(54356999)(50986999)(16576012)(316002)(305945005)(7736002)(3260700006)(25786009)(3846002)(67846002)(478600001)(53546010)(105586002)(64126003)(106356001)(36756003)(39060400002)(53936002)(8676002)(54906003)(16526018)(6246003);\n\tDIR:OUT; SFP:1101; SCL:1; SRVR:HE1PR0501MB2249; H:[10.223.0.122];\n\tFPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; ","Received-SPF":"None (protection.outlook.com: mellanox.com does not designate\n\tpermitted sender hosts)","SpamDiagnosticOutput":"1:99","SpamDiagnosticMetadata":"NSPM","X-OriginatorOrg":"Mellanox.com","X-MS-Exchange-CrossTenant-OriginalArrivalTime":"21 Nov 2017 05:50:29.9698\n\t(UTC)","X-MS-Exchange-CrossTenant-Network-Message-Id":"d7eba650-d775-4147-285b-08d530a3c643","X-MS-Exchange-CrossTenant-FromEntityHeader":"Hosted","X-MS-Exchange-CrossTenant-Id":"a652971c-7d2e-4d9b-a6a4-d149256f461b","X-MS-Exchange-Transport-CrossTenantHeadersStamped":"HE1PR0501MB2249","X-Spam-Status":"No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n\tDKIM_VALID, DKIM_VALID_AU,\n\tRCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Transfer-Encoding":"7bit","Content-Type":"text/plain; charset=\"us-ascii\"; Format=\"flowed\"","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}},{"id":1807920,"web_url":"http://patchwork.ozlabs.org/comment/1807920/","msgid":"<20171121092338.idxsqk344x5wecjg@netronome.com>","list_archive_url":null,"date":"2017-11-21T09:23:39","subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","submitter":{"id":64714,"url":"http://patchwork.ozlabs.org/api/people/64714/","name":"Simon Horman","email":"simon.horman@netronome.com"},"content":"On Tue, Nov 21, 2017 at 07:50:24AM +0200, Roi Dayan wrote:\n> \n> \n> On 20/11/2017 14:30, Simon Horman wrote:\n> > On Sun, Nov 19, 2017 at 08:45:19AM +0200, Roi Dayan wrote:\n> > > \n> > > \n> > > On 16/11/2017 18:29, Simon Horman wrote:\n> > > > On Wed, Oct 25, 2017 at 02:24:15PM +0300, Roi Dayan wrote:\n> > > > > \n> > > > > \n> > > > > On 27/09/2017 12:08, Simon Horman wrote:\n> > > > > > On Mon, Sep 25, 2017 at 04:31:42PM +0300, Paul Blakey wrote:\n> > > > > > > \n> > > > > > > \n> > > > > > > On 18/09/2017 18:01, Simon Horman wrote:\n> > > > > > > > On Mon, Sep 18, 2017 at 07:16:03AM +0300, Roi Dayan wrote:\n> > > > > > > > > From: Paul Blakey <paulb@mellanox.com>\n> > > > > > > > > \n> > > > > > > > > To be later used to implement ovs action set offloading.\n> > > > > > > > > \n> > > > > > > > > Signed-off-by: Paul Blakey <paulb@mellanox.com>\n> > > > > > > > > Reviewed-by: Roi Dayan <roid@mellanox.com>\n> > > > > > > > > ---\n> > > > > > > > >     lib/tc.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n> > > > > > > > >     lib/tc.h |  16 +++\n> > > > > > > > >     2 files changed, 385 insertions(+), 3 deletions(-)\n> > > > > > > > > \n> > > > > > > > > diff --git a/lib/tc.c b/lib/tc.c\n> > > > > > > > > index c9cada2..743b2ee 100644\n> > > > > > > > > --- a/lib/tc.c\n> > > > > > > > > +++ b/lib/tc.c\n> > > > > > > > > @@ -21,8 +21,10 @@\n> > > > > > > > >     #include <errno.h>\n> > > > > > > > >     #include <linux/if_ether.h>\n> > > > > > > > >     #include <linux/rtnetlink.h>\n> > > > > > > > > +#include <linux/tc_act/tc_csum.h>\n> > > > > > > > >     #include <linux/tc_act/tc_gact.h>\n> > > > > > > > >     #include <linux/tc_act/tc_mirred.h>\n> > > > > > > > > +#include <linux/tc_act/tc_pedit.h>\n> > > > > > > > >     #include <linux/tc_act/tc_tunnel_key.h>\n> > > > > > > > >     #include <linux/tc_act/tc_vlan.h>\n> > > > > > > > >     #include <linux/gen_stats.h>\n> > > > > > > > > @@ -33,11 +35,14 @@\n> > > > > > > > >     #include \"netlink-socket.h\"\n> > > > > > > > >     #include \"netlink.h\"\n> > > > > > > > >     #include \"openvswitch/ofpbuf.h\"\n> > > > > > > > > +#include \"openvswitch/util.h\"\n> > > > > > > > >     #include \"openvswitch/vlog.h\"\n> > > > > > > > >     #include \"packets.h\"\n> > > > > > > > >     #include \"timeval.h\"\n> > > > > > > > >     #include \"unaligned.h\"\n> > > > > > > > > +#define MAX_PEDIT_OFFSETS 8\n> > > > > > > > \n> > > > > > > > Why 8?\n> > > > > > > We don't expect anything more right now (ipv6 src/dst rewrite requires 8\n> > > > > > > pedits iirc). I can't think of a larger use case, maybe ipv6 + macs if\n> > > > > > > that's makes sens. do you suggest we increase it? to what?\n> > > > > > \n> > > > > > It seems strange to me to place a somewhat arbitrary small limit\n> > > > > > when none exists in the pedit API being used. I would at prefer if\n> > > > > > it was at least a bigger, say 16 or 32.\n> > > > > \n> > > > \n> > > > > Hi Simon,\n> > > > > \n> > > > > Sorry for the late reply due to holidays and vacations.\n> > > > > Me & Paul going to go over this and do the fixes needed and\n> > > > > also rebase over latest master and run tests again.\n> > > > > \n> > > > > I'll answer what I'm more familiar with now and Paul will continue.\n> > > > > The 8 here is too low and you right. We used this definition\n> > > > > for allocation of the pedit keys on the stack in\n> > > > > nl_msg_put_flower_rewrite_pedits()\n> > > > > \n> > > > > It was for convenience instead of calculating the maximum possible\n> > > > > keys that could exists and allocating it there and freeing it at\n> > > > > the end.\n> > > > > \n> > > > > Increasing it to 32 is probably more than enough and wont waste much.\n> > > > \n> > > > I updated the value to 32 when applying the patch.\n> > > > \n> > > > ...\n> > > > \n> > > > > > > > If I understand the above correctly it is designed to make\n> > > > > > > > pedit actions disjoint. If so, why is that necessary? >\n> > > > > > > \n> > > > > > > It's not, as a single flower key rewrite can be split to multiple pedit\n> > > > > > > actions it finds the overlap between a flower key and a pedit action, if\n> > > > > > > they do overlap it translates it to the correct offset and masks it out.\n> > > > > > \n> > > > > > Thanks, understood.\n> > > > > > \n> > > > > > > \n> > > > > > > > > +        } else {\n> > > > > > > > > +            VLOG_ERR_RL(&error_rl, \"unable to parse legacy pedit type: %d\",\n> > > > > > > > > +                        nl_attr_type(nla));\n> > > > > > > > > +            return EOPNOTSUPP;\n> > > > > > > > > +        }\n> > > > > > > > \n> > > > > > > > I think the code could exit early here as\n> > > > > > > > nl_msg_put_flower_rewrite_pedits() does below.\n> > > > > > > > \n> > > > > > > \n> > > > > > > Sorry, didn't understand. can you give an example?\n> > > > > > > \n> > > > > > \n> > > > > > I meant something like this.\n> > > > > > \n> > > > > >                if (nl_attr_type(nla) != TCA_PEDIT_KEY_EX) {\n> > > > > >                    VLOG_ERR_RL(...);\n> > > > > >                    return EOPNOTSUPP;\n> > > > > >                }\n> > > > > \n> > > > > understood. we'll do that. thanks.\n> > > > \n> > > > I also fixed this when applying the patch.\n> > > > \n> > > > ...\n> > > > \n> > > \n> > > \n> > > Thanks Simon. sorry we were not responsive enough with this feature.\n> > > We'll improve that.\n> > > \n> > \n> > No problem.\n> > \n> > Could you work on a fix for the travis failure that Eric Garver flagged?\n> > \n> \n> yes we have a fix. we did more fixes and running some tests. we'll push\n> the fixes today.\n\nExcellent, please CC me.","headers":{"Return-Path":"<ovs-dev-bounces@openvswitch.org>","X-Original-To":["incoming@patchwork.ozlabs.org","dev@openvswitch.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","ovs-dev@mail.linuxfoundation.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=openvswitch.org\n\t(client-ip=140.211.169.12; helo=mail.linuxfoundation.org;\n\tenvelope-from=ovs-dev-bounces@openvswitch.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=netronome-com.20150623.gappssmtp.com\n\theader.i=@netronome-com.20150623.gappssmtp.com\n\theader.b=\"ZhX5Rmjc\"; dkim-atps=neutral"],"Received":["from mail.linuxfoundation.org (mail.linuxfoundation.org\n\t[140.211.169.12])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3yh0Wl61kTz9s5L\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 21 Nov 2017 20:23:47 +1100 (AEDT)","from mail.linux-foundation.org (localhost [127.0.0.1])\n\tby mail.linuxfoundation.org (Postfix) with ESMTP id 1FE9C927;\n\tTue, 21 Nov 2017 09:23:44 +0000 (UTC)","from smtp1.linuxfoundation.org (smtp1.linux-foundation.org\n\t[172.17.192.35])\n\tby mail.linuxfoundation.org (Postfix) with ESMTPS id 3D43F8E3\n\tfor <dev@openvswitch.org>; Tue, 21 Nov 2017 09:23:43 +0000 (UTC)","from mail-wm0-f53.google.com (mail-wm0-f53.google.com\n\t[74.125.82.53])\n\tby smtp1.linuxfoundation.org (Postfix) with ESMTPS id 7627788\n\tfor <dev@openvswitch.org>; Tue, 21 Nov 2017 09:23:42 +0000 (UTC)","by mail-wm0-f53.google.com with SMTP id 128so1785539wmo.3\n\tfor <dev@openvswitch.org>; Tue, 21 Nov 2017 01:23:42 -0800 (PST)","from netronome.com ([217.111.208.18])\n\tby smtp.gmail.com with ESMTPSA id\n\tv195sm803739wmf.25.2017.11.21.01.23.40\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tTue, 21 Nov 2017 01:23:40 -0800 (PST)"],"X-Greylist":"whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=netronome-com.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=zigO08Bvzx9poW3ybrPmlOfIDqidz8h/noorjMoD7fI=;\n\tb=ZhX5RmjcUsgtd84E7ZvbopD5C6tWcTpcKlEO95fAd187ffIz51H9nhQ1qhuY9pRTmI\n\tAbHalu45tOk0XFVxVcSL5UTmRhhTJx5hxHC4eML+ppejCCXcuLauczQrbRdTENYawi7x\n\t5Ri7O6ZGg2+2lpuipTOj91IE8BFzhnelgzm/Sxwdpcc/IWS0/aPZXprtyfzps6dXs5WF\n\tzgPYFbgyPkjtml+3iM2xIpjHp85bZlieO1Bq2cdJtlUZaWn81TNCNr83+28YPsbSoxC7\n\tB2iuEVxtuwPNdYaeyCnG2KnhceGgsPe7MNkPdpl+sHoVOlofNbmGvaE3fEaf0IHgG2e1\n\tvhIw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=zigO08Bvzx9poW3ybrPmlOfIDqidz8h/noorjMoD7fI=;\n\tb=N9fnSlcKlKumOndtatEF7HRJGtbqvGQnEacoj0/UrxdB1tA5+a5Dz1snQ88os3obt5\n\tTfqI0uEFJEnyZ3rmJCDVsF6lQDgqxMlJ39XvIMrBVB44hItX0g0EnCm6DlisIe98jNCa\n\tTOpULlfiuk5+Thu9oLdX32C2ET11YelHmi7PUYf7a3RRVpSkwuXUIIbWnzZJxsLxpQMT\n\txjJ9aESLahxu+eu4/32/s71fUn1ZKTLA/7463u388s2vpVJ6FRN7E3hgib0o7XQWnUag\n\tJahDM5Ou17nn4B8yuY89V2ViD9Vl3F2/fzavFYxhFTH4wOvrDRZsihIMVTGcoYHDpbVy\n\t6wyw==","X-Gm-Message-State":"AJaThX7CqJXSZe7s6k4ehDkb5hf9oCtLRc4muy0/0EvsCHaiMwBUbT2U\n\t1tlFfZfGr3Un5Gtq+faWG2TC2Q==","X-Google-Smtp-Source":"AGs4zMZ4TomUOst5DXe60aGn1amm1RuVPykw1psyfWYqVKCeG4HzhAu9yzXvhOLwAhdBW6xH5nCoGw==","X-Received":"by 10.28.9.195 with SMTP id 186mr687599wmj.122.1511256221015;\n\tTue, 21 Nov 2017 01:23:41 -0800 (PST)","Date":"Tue, 21 Nov 2017 10:23:39 +0100","From":"Simon Horman <simon.horman@netronome.com>","To":"Roi Dayan <roid@mellanox.com>","Message-ID":"<20171121092338.idxsqk344x5wecjg@netronome.com>","References":"<1505708164-10270-1-git-send-email-roid@mellanox.com>\n\t<1505708164-10270-4-git-send-email-roid@mellanox.com>\n\t<20170918150107.GD25154@vergenet.net>\n\t<8b6d70ff-3f36-2f35-cb51-27be59689be5@mellanox.com>\n\t<20170927090817.GB25449@vergenet.net>\n\t<6a5c89b3-b741-266c-175c-e0569705bfec@mellanox.com>\n\t<20171116162906.cfw46ejbz3rxm3rz@netronome.com>\n\t<88e27e92-c6d9-86dc-ad17-fec20b73e6ee@mellanox.com>\n\t<20171120123037.z7yx3cfje6rs5dvx@netronome.com>\n\t<b0b560a7-0e0a-b86a-1488-091f939a2b50@mellanox.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<b0b560a7-0e0a-b86a-1488-091f939a2b50@mellanox.com>","User-Agent":"NeoMutt/20170113 (1.7.2)","X-Spam-Status":"No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED,\n\tDKIM_VALID,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1","X-Spam-Checker-Version":"SpamAssassin 3.3.1 (2010-03-16) on\n\tsmtp1.linux-foundation.org","Cc":"dev@openvswitch.org","Subject":"Re: [ovs-dev] [PATCH V2 3/4] tc: Add header rewrite using tc pedit\n\taction","X-BeenThere":"ovs-dev@openvswitch.org","X-Mailman-Version":"2.1.12","Precedence":"list","List-Id":"<ovs-dev.openvswitch.org>","List-Unsubscribe":"<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>","List-Archive":"<http://mail.openvswitch.org/pipermail/ovs-dev/>","List-Post":"<mailto:ovs-dev@openvswitch.org>","List-Help":"<mailto:ovs-dev-request@openvswitch.org?subject=help>","List-Subscribe":"<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n\t<mailto:ovs-dev-request@openvswitch.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Sender":"ovs-dev-bounces@openvswitch.org","Errors-To":"ovs-dev-bounces@openvswitch.org"}}]