From patchwork Mon Jan 14 12:12:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wangyunjian X-Patchwork-Id: 1024459 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=huawei.com Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43dXnq18djz9s4s for ; Mon, 14 Jan 2019 23:28:46 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 6F4A02CC6; Mon, 14 Jan 2019 12:28:42 +0000 (UTC) X-Original-To: ovs-dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 09A742C5A; Mon, 14 Jan 2019 12:12:47 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from huawei.com (szxga08-in.huawei.com [45.249.212.255]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 9F44B2C3; Mon, 14 Jan 2019 12:12:45 +0000 (UTC) Received: from DGGEMM404-HUB.china.huawei.com (unknown [172.30.72.53]) by Forcepoint Email with ESMTP id 35A27367A579ADD31432; Mon, 14 Jan 2019 20:12:43 +0800 (CST) Received: from DGGEMM422-HUB.china.huawei.com (10.1.198.39) by DGGEMM404-HUB.china.huawei.com (10.3.20.212) with Microsoft SMTP Server (TLS) id 14.3.408.0; Mon, 14 Jan 2019 20:12:42 +0800 Received: from DGGEMM533-MBX.china.huawei.com ([169.254.5.107]) by dggemm422-hub.china.huawei.com ([10.1.198.39]) with mapi id 14.03.0415.000; Mon, 14 Jan 2019 20:12:35 +0800 From: wangyunjian To: "ovs-dev@openvswitch.org" , "ovs-discuss@openvswitch.org" Thread-Topic: [ovs-discuss] a problem the userspace datapath failed to create a new datapath flow for the QinQ packet Thread-Index: AdSsAJaxpDxZTq2yTNSRFrOoPR2zSA== Date: Mon, 14 Jan 2019 12:12:34 +0000 Message-ID: <34EFBCA9F01B0748BEB6B629CE643AE60C9DA075@DGGEMM533-MBX.china.huawei.com> Accept-Language: en-US Content-Language: zh-CN X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.177.24.66] MIME-Version: 1.0 X-CFilter-Loop: Reflected X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: "eric@garver.life" Subject: [ovs-dev] [ovs-discuss] a problem the userspace datapath failed to create a new datapath flow for the QinQ packet X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Hi, I found a problem the userspace datapath failed to create a new datapath flow for the QinQ packet. When getting mask from nlattrs with the mask include ip,udp,etc, it parsed 802.1Q header wrongly. This patch fixes it. Any ideas? Regards Yunjian err log: log_odp_key_attributes[4709]|93701|odp_util(handler18)|: present but not expected: ipv4 icmp: skb_priority(0),tunnel(ttl=0,flags(0)),skb_mark(0xffffffff),ct_state(0),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0xffffffff),dp_hash(0),in_port(4294967295),eth(src=ff:ff:ff:ff:ff:ff,dst=ff:ff:ff:ff:ff:ff),eth_type(0xffff),vlan(vid=4095,pcp=7),encap(eth_type(0xffff),ipv4(src=255.255.0.0,dst=0.0.0.0,proto=0,tos=0,ttl=0,frag=),icmp(type=0,code=0) lib/odp-util.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 238 insertions(+), 1 deletion(-) diff --git a/lib/odp-util.c b/lib/odp-util.c index 1e8c5f1..7ad8cc6 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -6322,6 +6322,240 @@ parse_ethertype(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], return true; } +static bool +parse_l2_5(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], + uint64_t present_attrs, uint64_t *expected_attrs, + struct flow *flow, const struct flow *src_flow) +{ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + bool is_mask = src_flow != flow; + const void *check_start = NULL; + size_t check_len = 0; + enum ovs_key_attr expected_bit = 0xff; + + if (eth_type_mpls(src_flow->dl_type)) { + if (!is_mask || present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_MPLS)) { + *expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_MPLS); + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_MPLS)) { + size_t size = nl_attr_get_size(attrs[OVS_KEY_ATTR_MPLS]); + const ovs_be32 *mpls_lse = nl_attr_get(attrs[OVS_KEY_ATTR_MPLS]); + int n = size / sizeof(ovs_be32); + int i; + + if (!size || size % sizeof(ovs_be32)) { + return false; + } + if (flow->mpls_lse[0] && flow->dl_type != htons(0xffff)) { + return false; + } + + for (i = 0; i < n && i < FLOW_MAX_MPLS_LABELS; i++) { + flow->mpls_lse[i] = mpls_lse[i]; + } + if (n > FLOW_MAX_MPLS_LABELS) { + return false; + } + + if (!is_mask) { + /* BOS may be set only in the innermost label. */ + for (i = 0; i < n - 1; i++) { + if (flow->mpls_lse[i] & htonl(MPLS_BOS_MASK)) { + return false; + } + } + + /* BOS must be set in the innermost label. */ + if (n < FLOW_MAX_MPLS_LABELS + && !(flow->mpls_lse[n - 1] & htonl(MPLS_BOS_MASK))) { + return false; + } + } + } + + return true; + } else if (src_flow->dl_type == htons(ETH_TYPE_IP)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IPV4; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) { + const struct ovs_key_ipv4 *ipv4_key; + + ipv4_key = nl_attr_get(attrs[OVS_KEY_ATTR_IPV4]); + put_ipv4_key(ipv4_key, flow, is_mask); + if (flow->nw_frag > FLOW_NW_FRAG_MASK) { + return false; + } + if (is_mask) { + check_start = ipv4_key; + check_len = sizeof *ipv4_key; + expected_bit = OVS_KEY_ATTR_IPV4; + } + } + } else if (src_flow->dl_type == htons(ETH_TYPE_IPV6)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IPV6; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) { + const struct ovs_key_ipv6 *ipv6_key; + + ipv6_key = nl_attr_get(attrs[OVS_KEY_ATTR_IPV6]); + put_ipv6_key(ipv6_key, flow, is_mask); + if (flow->nw_frag > FLOW_NW_FRAG_MASK) { + return false; + } + if (is_mask) { + check_start = ipv6_key; + check_len = sizeof *ipv6_key; + expected_bit = OVS_KEY_ATTR_IPV6; + } + } + } else if (src_flow->dl_type == htons(ETH_TYPE_ARP) || + src_flow->dl_type == htons(ETH_TYPE_RARP)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ARP; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) { + const struct ovs_key_arp *arp_key; + + arp_key = nl_attr_get(attrs[OVS_KEY_ATTR_ARP]); + if (!is_mask && (arp_key->arp_op & htons(0xff00))) { + VLOG_ERR_RL(&rl, "unsupported ARP opcode %"PRIu16" in flow " + "key", ntohs(arp_key->arp_op)); + return false; + } + put_arp_key(arp_key, flow); + if (is_mask) { + check_start = arp_key; + check_len = sizeof *arp_key; + expected_bit = OVS_KEY_ATTR_ARP; + } + } + } else { + return true; + } + if (check_len > 0) { /* Happens only when 'is_mask'. */ + if (!is_all_zeros(check_start, check_len) && + flow->dl_type != htons(0xffff)) { + return false; + } else { + *expected_attrs |= UINT64_C(1) << expected_bit; + } + } + + expected_bit = OVS_KEY_ATTR_UNSPEC; + if (src_flow->nw_proto == IPPROTO_TCP + && (src_flow->dl_type == htons(ETH_TYPE_IP) || + src_flow->dl_type == htons(ETH_TYPE_IPV6)) + && !(src_flow->nw_frag & FLOW_NW_FRAG_LATER)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TCP; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TCP)) { + const union ovs_key_tp *tcp_key; + + tcp_key = nl_attr_get(attrs[OVS_KEY_ATTR_TCP]); + put_tp_key(tcp_key, flow); + expected_bit = OVS_KEY_ATTR_TCP; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TCP_FLAGS)) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TCP_FLAGS; + flow->tcp_flags = nl_attr_get_be16(attrs[OVS_KEY_ATTR_TCP_FLAGS]); + } + } else if (src_flow->nw_proto == IPPROTO_UDP + && (src_flow->dl_type == htons(ETH_TYPE_IP) || + src_flow->dl_type == htons(ETH_TYPE_IPV6)) + && !(src_flow->nw_frag & FLOW_NW_FRAG_LATER)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_UDP; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_UDP)) { + const union ovs_key_tp *udp_key; + + udp_key = nl_attr_get(attrs[OVS_KEY_ATTR_UDP]); + put_tp_key(udp_key, flow); + expected_bit = OVS_KEY_ATTR_UDP; + } + } else if (src_flow->nw_proto == IPPROTO_SCTP + && (src_flow->dl_type == htons(ETH_TYPE_IP) || + src_flow->dl_type == htons(ETH_TYPE_IPV6)) + && !(src_flow->nw_frag & FLOW_NW_FRAG_LATER)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_SCTP; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_SCTP)) { + const union ovs_key_tp *sctp_key; + + sctp_key = nl_attr_get(attrs[OVS_KEY_ATTR_SCTP]); + put_tp_key(sctp_key, flow); + expected_bit = OVS_KEY_ATTR_SCTP; + } + } else if (src_flow->nw_proto == IPPROTO_ICMP + && src_flow->dl_type == htons(ETH_TYPE_IP) + && !(src_flow->nw_frag & FLOW_NW_FRAG_LATER)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ICMP; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ICMP)) { + const struct ovs_key_icmp *icmp_key; + + icmp_key = nl_attr_get(attrs[OVS_KEY_ATTR_ICMP]); + flow->tp_src = htons(icmp_key->icmp_type); + flow->tp_dst = htons(icmp_key->icmp_code); + expected_bit = OVS_KEY_ATTR_ICMP; + } + } else if (src_flow->nw_proto == IPPROTO_ICMPV6 + && src_flow->dl_type == htons(ETH_TYPE_IPV6) + && !(src_flow->nw_frag & FLOW_NW_FRAG_LATER)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ICMPV6; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ICMPV6)) { + const struct ovs_key_icmpv6 *icmpv6_key; + + icmpv6_key = nl_attr_get(attrs[OVS_KEY_ATTR_ICMPV6]); + flow->tp_src = htons(icmpv6_key->icmpv6_type); + flow->tp_dst = htons(icmpv6_key->icmpv6_code); + expected_bit = OVS_KEY_ATTR_ICMPV6; + if (is_nd(src_flow, NULL)) { + if (!is_mask) { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ND; + } + if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ND)) { + const struct ovs_key_nd *nd_key; + + nd_key = nl_attr_get(attrs[OVS_KEY_ATTR_ND]); + flow->nd_target = nd_key->nd_target; + flow->arp_sha = nd_key->nd_sll; + flow->arp_tha = nd_key->nd_tll; + if (is_mask) { + /* Even though 'tp_src' and 'tp_dst' are 16 bits wide, + * ICMP type and code are 8 bits wide. Therefore, an + * exact match looks like htons(0xff), not + * htons(0xffff). See xlate_wc_finish() for details. + * */ + if (!is_all_zeros(nd_key, sizeof *nd_key) && + (flow->tp_src != htons(0xff) || + flow->tp_dst != htons(0xff))) { + return false; + } else { + *expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ND; + } + } + } + } + } + } + if (is_mask && expected_bit != OVS_KEY_ATTR_UNSPEC) { + if ((flow->tp_src || flow->tp_dst) && flow->nw_proto != 0xff) { + return false; + } else { + *expected_attrs |= UINT64_C(1) << expected_bit; + } + } + return true; +} + static enum odp_key_fitness parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], uint64_t present_attrs, int out_of_range_attr, @@ -6658,7 +6892,10 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], flow, src_flow)) { return ODP_FIT_ERROR; } - + if (!parse_l2_5(attrs, present_attrs, &expected_attrs, + flow, src_flow)) { + return ODP_FIT_ERROR; + } encaps++; }