From patchwork Wed Nov 27 12:55:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Roi Dayan X-Patchwork-Id: 1201581 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=fraxinus.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=mellanox.com Received: from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47NLNq5Hq9z9sT7 for ; Wed, 27 Nov 2019 23:55:55 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by fraxinus.osuosl.org (Postfix) with ESMTP id 3EF27868D1; Wed, 27 Nov 2019 12:55:54 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from fraxinus.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id kx5dv3uWEmk9; Wed, 27 Nov 2019 12:55:50 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by fraxinus.osuosl.org (Postfix) with ESMTP id 093B2866E5; Wed, 27 Nov 2019 12:55:47 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 8DCC4C1DE2; Wed, 27 Nov 2019 12:55:46 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6F3A3C1DE0 for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by hemlock.osuosl.org (Postfix) with ESMTP id 5E3C38829A for ; Wed, 27 Nov 2019 12:55:38 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from hemlock.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id mUKKrXz6cSfg for ; Wed, 27 Nov 2019 12:55:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by hemlock.osuosl.org (Postfix) with ESMTP id 7AECF8829D for ; Wed, 27 Nov 2019 12:55:35 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from roid@mellanox.com) with ESMTPS (AES256-SHA encrypted); 27 Nov 2019 14:55:30 +0200 Received: from dev-r-vrt-139.mtr.labs.mlnx (dev-r-vrt-139.mtr.labs.mlnx [10.212.139.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id xARCtTRr016501; Wed, 27 Nov 2019 14:55:29 +0200 From: Roi Dayan To: dev@openvswitch.org Date: Wed, 27 Nov 2019 14:55:12 +0200 Message-Id: <20191127125516.5135-7-roid@mellanox.com> X-Mailer: git-send-email 2.8.4 In-Reply-To: <20191127125516.5135-1-roid@mellanox.com> References: <20191127125516.5135-1-roid@mellanox.com> Cc: Oz Shlomo , Simon Horman , Marcelo Ricardo Leitner , Justin Pettit Subject: [ovs-dev] [PATCH v2 06/10] netdev-offload-tc: Add conntrack support X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Paul Blakey Zone and ct_state first. Signed-off-by: Paul Blakey --- lib/dpif-netlink.c | 2 + lib/netdev-offload-tc.c | 136 ++++++++++++++++++++++++++++++++++++++++++++---- lib/tc.c | 122 +++++++++++++++++++++++++++++++++++++++++++ lib/tc.h | 11 ++++ 4 files changed, 261 insertions(+), 10 deletions(-) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 034b0acf49c4..620e94ea4bfc 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -1601,6 +1601,8 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match, .support = { .max_vlan_headers = 2, .recirc = true, + .ct_state = true, + .ct_zone = true, }, }; size_t offset; diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index 954e64a445e8..8dd48ab7c421 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -594,6 +594,35 @@ parse_tc_flower_to_match(struct tc_flower *flower, match_set_tp_dst_masked(match, key->sctp_dst, mask->sctp_dst); match_set_tp_src_masked(match, key->sctp_src, mask->sctp_src); } + + if (mask->ct_state) { + uint8_t ct_statev = 0, ct_statem = 0; + + if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_NEW) { + if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_NEW) { + ct_statev |= OVS_CS_F_NEW; + } + ct_statem |= OVS_CS_F_NEW; + } + + if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) { + if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) { + ct_statev |= OVS_CS_F_ESTABLISHED; + } + ct_statem |= OVS_CS_F_ESTABLISHED; + } + + if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED) { + if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED) { + ct_statev |= OVS_CS_F_TRACKED; + } + ct_statem |= OVS_CS_F_TRACKED; + } + + match_set_ct_state_masked(match, ct_statev, ct_statem); + } + + match_set_ct_zone_masked(match, key->ct_zone, mask->ct_zone); } if (flower->tunnel) { @@ -745,6 +774,27 @@ parse_tc_flower_to_match(struct tc_flower *flower, nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(outport)); } break; + case TC_ACT_CT: { + size_t ct_offset; + + if (action->ct.clear) { + nl_msg_put_flag(buf, OVS_ACTION_ATTR_CT_CLEAR); + break; + } + + ct_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_CT); + + if (action->ct.commit) { + nl_msg_put_flag(buf, OVS_CT_ATTR_COMMIT); + } + + if (action->ct.zone) { + nl_msg_put_u16(buf, OVS_CT_ATTR_ZONE, action->ct.zone); + } + + nl_msg_end_nested(buf, ct_offset); + } + break; case TC_ACT_GOTO: { nl_msg_put_u32(buf, OVS_ACTION_ATTR_RECIRC, action->chain); } @@ -834,6 +884,34 @@ parse_mpls_set_action(struct tc_flower *flower, struct tc_action *action, } static int +parse_put_flow_ct_action(struct tc_flower *flower, + struct tc_action *action, + const struct nlattr *ct, + size_t ct_len) +{ + const struct nlattr *ct_attr; + size_t ct_left; + int err; + + NL_ATTR_FOR_EACH_UNSAFE (ct_attr, ct_left, ct, ct_len) { + switch (nl_attr_type(ct_attr)) { + case OVS_CT_ATTR_COMMIT: { + action->ct.commit = true; + } + break; + case OVS_CT_ATTR_ZONE: { + action->ct.zone = nl_attr_get_u16(ct_attr); + } + break; + } + } + + action->type = TC_ACT_CT; + flower->action_count++; + return 0; +} + +static int parse_put_flow_set_masked_action(struct tc_flower *flower, struct tc_action *action, const struct nlattr *set, @@ -1015,16 +1093,6 @@ test_key_and_mask(struct match *match) return EOPNOTSUPP; } - if (mask->ct_state) { - VLOG_DBG_RL(&rl, "offloading attribute ct_state isn't supported"); - return EOPNOTSUPP; - } - - if (mask->ct_zone) { - VLOG_DBG_RL(&rl, "offloading attribute ct_zone isn't supported"); - return EOPNOTSUPP; - } - if (mask->ct_mark) { VLOG_DBG_RL(&rl, "offloading attribute ct_mark isn't supported"); return EOPNOTSUPP; @@ -1363,6 +1431,42 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, } } + if (mask->ct_state) { + if (mask->ct_state & OVS_CS_F_NEW) { + if (key->ct_state & OVS_CS_F_NEW) { + flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW; + } + flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW; + } + + if (mask->ct_state & OVS_CS_F_ESTABLISHED) { + if (key->ct_state & OVS_CS_F_ESTABLISHED) { + flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED; + } + flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED; + } + + if (mask->ct_state & OVS_CS_F_TRACKED) { + if (key->ct_state & OVS_CS_F_TRACKED) { + flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED; + } + flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED; + } + + if (flower.key.ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) { + flower.key.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW); + flower.mask.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW); + } + + mask->ct_state = 0; + } + + if (mask->ct_zone) { + flower.key.ct_zone = key->ct_zone; + flower.mask.ct_zone = mask->ct_zone; + mask->ct_zone = 0; + } + err = test_key_and_mask(match); if (err) { return err; @@ -1429,6 +1533,18 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match, if (err) { return err; } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) { + const struct nlattr *ct = nl_attr_get(nla); + const size_t ct_len = nl_attr_get_size(nla); + + err = parse_put_flow_ct_action(&flower, action, ct, ct_len); + if (err) { + return err; + } + } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT_CLEAR) { + action->type = TC_ACT_CT; + action->ct.clear = true; + flower.action_count++; } else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) { action->type = TC_ACT_GOTO; action->chain = nl_attr_get_u32(nla); diff --git a/lib/tc.c b/lib/tc.c index cc58320fce2c..841552e1e4a6 100644 --- a/lib/tc.c +++ b/lib/tc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -399,6 +400,10 @@ static const struct nl_policy tca_flower_policy[] = { [TCA_FLOWER_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, }, [TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NL_A_NESTED, .optional = true, }, + [TCA_FLOWER_KEY_CT_STATE] = { .type = NL_A_U16, .optional = true, }, + [TCA_FLOWER_KEY_CT_STATE_MASK] = { .type = NL_A_U16, .optional = true, }, + [TCA_FLOWER_KEY_CT_ZONE] = { .type = NL_A_U16, .optional = true, }, + [TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NL_A_U16, .optional = true, }, }; static void @@ -703,6 +708,27 @@ nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower) } static void +nl_parse_flower_ct_match(struct nlattr **attrs, struct tc_flower *flower) { + struct tc_flower_key *key = &flower->key; + struct tc_flower_key *mask = &flower->mask; + struct nlattr *attr_key, *attr_mask; + + attr_key = attrs[TCA_FLOWER_KEY_CT_STATE]; + attr_mask = attrs[TCA_FLOWER_KEY_CT_STATE_MASK]; + if (attr_mask) { + key->ct_state = nl_attr_get_u16(attr_key); + mask->ct_state = nl_attr_get_u16(attr_mask); + } + + attr_key = attrs[TCA_FLOWER_KEY_CT_ZONE]; + attr_mask = attrs[TCA_FLOWER_KEY_CT_ZONE_MASK]; + if (attrs[TCA_FLOWER_KEY_CT_ZONE_MASK]) { + key->ct_zone = nl_attr_get_u16(attr_key); + mask->ct_zone = nl_attr_get_u16(attr_mask); + } +} + +static void nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) { uint8_t ip_proto = 0; struct tc_flower_key *key = &flower->key; @@ -799,6 +825,8 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) { key->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS]); mask->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS_MASK]); } + + nl_parse_flower_ct_match(attrs, flower); } static enum tc_offloaded_state @@ -1219,6 +1247,54 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower) return 0; } +static const struct nl_policy ct_policy[] = { + [TCA_CT_PARMS] = { .type = NL_A_UNSPEC, + .min_len = sizeof(struct tc_ct), + .optional = false, }, + [TCA_CT_ACTION] = { .type = NL_A_U16, + .optional = true, }, + [TCA_CT_ZONE] = { .type = NL_A_U16, + .optional = true, }, +}; + +static int +nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower) +{ + struct nlattr *ct_attrs[ARRAY_SIZE(ct_policy)]; + const struct nlattr *ct_parms; + struct tc_action *action; + const struct tc_ct *ct; + uint16_t ct_action = 0; + + if (!nl_parse_nested(options, ct_policy, ct_attrs, + ARRAY_SIZE(ct_policy))) { + VLOG_ERR_RL(&error_rl, "failed to parse ct action options"); + return EPROTO; + } + + ct_parms = ct_attrs[TCA_CT_PARMS]; + ct = nl_attr_get_unspec(ct_parms, sizeof *ct); + + if (ct_attrs[TCA_CT_ACTION]) { + ct_action = nl_attr_get_u16(ct_attrs[TCA_CT_ACTION]); + } + + action = &flower->actions[flower->action_count++]; + action->ct.clear = ct_action & TCA_CT_ACT_CLEAR; + if (!action->ct.clear) { + struct nlattr *zone = ct_attrs[TCA_CT_ZONE]; + + action->ct.commit = ct_action & TCA_CT_ACT_COMMIT; + action->ct.force = ct_action & TCA_CT_ACT_FORCE; + + action->ct.zone = zone ? nl_attr_get_u16(zone) : 0; + + } + action->type = TC_ACT_CT; + + return 0; +} + static const struct nl_policy vlan_policy[] = { [TCA_VLAN_PARMS] = { .type = NL_A_UNSPEC, .min_len = sizeof(struct tc_vlan), @@ -1449,6 +1525,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower) nl_parse_act_csum(act_options, flower); } else if (!strcmp(act_kind, "skbedit")) { /* Added for TC rule only (not in OvS rule) so ignore. */ + } else if (!strcmp(act_kind, "ct")) { + nl_parse_act_ct(act_options, flower); } else { VLOG_ERR_RL(&error_rl, "unknown tc action kind: %s", act_kind); err = EINVAL; @@ -1904,6 +1982,40 @@ nl_msg_put_act_gact(struct ofpbuf *request, uint32_t chain) } static void +nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action) +{ + uint16_t ct_action = 0; + size_t offset; + + nl_msg_put_string(request, TCA_ACT_KIND, "ct"); + offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED); + { + struct tc_ct ct = { + .action = TC_ACT_PIPE, + }; + + if (!action->ct.clear) { + if (action->ct.zone) { + nl_msg_put_u16(request, TCA_CT_ZONE, action->ct.zone); + } + + if (action->ct.commit) { + ct_action = TCA_CT_ACT_COMMIT; + if (action->ct.force) { + ct_action |= TCA_CT_ACT_FORCE; + } + } + } else { + ct_action = TCA_CT_ACT_CLEAR; + } + + nl_msg_put_u16(request, TCA_CT_ACTION, ct_action); + nl_msg_put_unspec(request, TCA_CT_PARMS, &ct, sizeof ct); + } + nl_msg_end_nested(request, offset); +} + +static void nl_msg_put_act_skbedit_to_host(struct ofpbuf *request) { size_t offset; @@ -2250,6 +2362,13 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower) nl_msg_end_nested(request, act_offset); } break; + case TC_ACT_CT: { + act_offset = nl_msg_start_nested(request, act_index++); + nl_msg_put_act_ct(request, action); + nl_msg_put_act_cookie(request, &flower->act_cookie); + nl_msg_end_nested(request, act_offset); + } + break; } } } @@ -2417,6 +2536,9 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower) FLOWER_PUT_MASKED_VALUE(sctp_src, TCA_FLOWER_KEY_SCTP_SRC); FLOWER_PUT_MASKED_VALUE(sctp_dst, TCA_FLOWER_KEY_SCTP_DST); } + + FLOWER_PUT_MASKED_VALUE(ct_state, TCA_FLOWER_KEY_CT_STATE); + FLOWER_PUT_MASKED_VALUE(ct_zone, TCA_FLOWER_KEY_CT_ZONE); } if (host_eth_type == ETH_P_IP) { diff --git a/lib/tc.h b/lib/tc.h index 42fd1b1b9588..b1e2174b7369 100644 --- a/lib/tc.h +++ b/lib/tc.h @@ -116,6 +116,9 @@ struct tc_flower_key { uint8_t ip_ttl; uint8_t ip_tos; + uint16_t ct_state; + uint16_t ct_zone; + struct { ovs_be32 ipv4_src; ovs_be32 ipv4_dst; @@ -157,6 +160,7 @@ enum tc_action_type { TC_ACT_MPLS_PUSH, TC_ACT_MPLS_SET, TC_ACT_GOTO, + TC_ACT_CT, }; struct tc_action { @@ -200,6 +204,13 @@ struct tc_action { } ipv6; struct tun_metadata data; } encap; + + struct { + uint16_t zone; + bool clear; + bool force; + bool commit; + } ct; }; enum tc_action_type type;