From patchwork Sun Dec 25 11:39:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Blakey X-Patchwork-Id: 708704 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 3tmgXh2J8Sz9t17 for ; Sun, 25 Dec 2016 22:54:44 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 4DACEBA3; Sun, 25 Dec 2016 11:48:47 +0000 (UTC) X-Original-To: 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 5D4CEB8E for ; Sun, 25 Dec 2016 11:48:46 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by smtp1.linuxfoundation.org (Postfix) with ESMTP id E91C5139 for ; Sun, 25 Dec 2016 11:48:44 +0000 (UTC) Received: from Internal Mail-Server by MTLPINE1 (envelope-from paulb@mellanox.com) with ESMTPS (AES256-SHA encrypted); 25 Dec 2016 13:40:35 +0200 Received: from dev-r-vrt-176.mtr.labs.mlnx (dev-r-vrt-176.mtr.labs.mlnx [10.212.176.1]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id uBPBeXbB029898; Sun, 25 Dec 2016 13:40:35 +0200 From: Paul Blakey To: dev@openvswitch.org, Andy Gospodarek , Simon Horman , Jiri Pirko , John Fastabend , Lance Richardson , Marcelo Ricardo Leitner , Joe Stringer Date: Sun, 25 Dec 2016 13:39:39 +0200 Message-Id: <1482665989-791-12-git-send-email-paulb@mellanox.com> X-Mailer: git-send-email 1.8.4.3 In-Reply-To: <1482665989-791-1-git-send-email-paulb@mellanox.com> References: <1482665989-791-1-git-send-email-paulb@mellanox.com> X-Spam-Status: No, score=-5.0 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Cc: Shahar Klein , Mark Bloch , Hadar Hen Zion , Rony Efraim , Or Gerlitz Subject: [ovs-dev] [PATCH ovs V2 11/21] netdev-tc-offloads: Implement netdev flow dump api using tc interface 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: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Signed-off-by: Paul Blakey Reviewed-by: Roi Dayan --- lib/netdev-tc-offloads.c | 138 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 131 insertions(+), 7 deletions(-) diff --git a/lib/netdev-tc-offloads.c b/lib/netdev-tc-offloads.c index f470aa3..7729cfc 100644 --- a/lib/netdev-tc-offloads.c +++ b/lib/netdev-tc-offloads.c @@ -184,28 +184,152 @@ netdev_tc_flow_dump_create(struct netdev *netdev) { struct netdev_flow_dump *dump = xzalloc(sizeof *dump); + memset(dump, 0, sizeof *dump); + dump->nl_dump = xzalloc(sizeof *dump->nl_dump); dump->netdev = netdev_ref(netdev); + tc_dump_flower_start(netdev_get_ifindex(netdev), dump->nl_dump); return dump; } int netdev_tc_flow_dump_destroy(struct netdev_flow_dump *dump) { + nl_dump_done(dump->nl_dump); netdev_close(dump->netdev); + free(dump->nl_dump); free(dump); + return 0; +} + +static int +parse_tc_flow_to_match(struct tc_flow *tc_flow, + struct match *match, + struct nlattr **actions, + struct dpif_flow_stats *stats, + struct ofpbuf *buf) { + size_t act_off; + struct tc_flow_key *key = &tc_flow->key; + struct tc_flow_key *mask = &tc_flow->mask; + + match_init_catchall(match); + match_set_dl_type(match, key->eth_type); + match_set_dl_src_masked(match, key->src_mac, mask->src_mac); + match_set_dl_dst_masked(match, key->dst_mac, mask->dst_mac); + if (key->vlan_id || key->vlan_prio) { + match_set_dl_vlan(match, ntohs(key->vlan_id)); + match_set_dl_vlan_pcp(match, ntohs(key->vlan_prio)); + match_set_dl_type(match, key->encap_eth_type); + } + + if (key->ip_proto && + (key->eth_type == htons(ETH_P_IP) + || key->eth_type == htons(ETH_P_IPV6))) { + match_set_nw_proto(match, key->ip_proto); + } + match_set_nw_src_masked(match, key->ipv4.ipv4_src, mask->ipv4.ipv4_src); + match_set_nw_dst_masked(match, key->ipv4.ipv4_dst, mask->ipv4.ipv4_dst); + + match_set_tp_dst_masked(match, key->dst_port, mask->dst_port); + match_set_tp_src_masked(match, key->src_port, mask->src_port); + + if (tc_flow->tunnel.tunnel) { + match_set_tun_id(match, tc_flow->tunnel.id); + match_set_tun_src(match, tc_flow->tunnel.ipv4_src); + match_set_tun_dst(match, tc_flow->tunnel.ipv4_dst); + match_set_tp_dst(match, tc_flow->tunnel.tp_dst); + } + + act_off = nl_msg_start_nested(buf, OVS_FLOW_ATTR_ACTIONS); + { + if (tc_flow->vlan_pop) + nl_msg_put_flag(buf, OVS_ACTION_ATTR_POP_VLAN); + + if (tc_flow->vlan_push_id || tc_flow->vlan_push_prio) { + struct ovs_action_push_vlan *push; + push = nl_msg_put_unspec_zero(buf, OVS_ACTION_ATTR_PUSH_VLAN, + sizeof *push); + + push->vlan_tpid = ntohs(ETH_TYPE_VLAN); + push->vlan_tci = ntohs(tc_flow->vlan_push_id + | (tc_flow->vlan_push_prio << 13) + | VLAN_CFI); + } + + if (tc_flow->ifindex_out > 0) { + int ifx = netdev_hmap_port_get_byifidx(tc_flow->ifindex_out); + + nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, ifx ? ifx : 0xFF); + } + + if (tc_flow->set.set) { + size_t set_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_SET); + size_t tunnel_offset = nl_msg_start_nested(buf, OVS_KEY_ATTR_TUNNEL); + + nl_msg_put_be64(buf, OVS_TUNNEL_KEY_ATTR_ID, tc_flow->set.id); + nl_msg_put_be32(buf, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, tc_flow->set.ipv4_src); + nl_msg_put_be32(buf, OVS_TUNNEL_KEY_ATTR_IPV4_DST, tc_flow->set.ipv4_dst); + nl_msg_put_be16(buf, OVS_TUNNEL_KEY_ATTR_TP_DST, tc_flow->set.tp_dst); + + nl_msg_end_nested(buf, tunnel_offset); + nl_msg_end_nested(buf, set_offset); + } + } + nl_msg_end_nested(buf, act_off); + + *actions = ofpbuf_at_assert(buf, act_off, sizeof(struct nlattr)); + + if (stats) { + memset(stats, 0, sizeof *stats); + stats->n_packets = get_32aligned_u64(&tc_flow->stats.n_packets); + stats->n_bytes = get_32aligned_u64(&tc_flow->stats.n_bytes); + stats->used = tc_flow->lastused; + } return 0; } bool -netdev_tc_flow_dump_next(struct netdev_flow_dump *dump OVS_UNUSED, - struct match *match OVS_UNUSED, - struct nlattr **actions OVS_UNUSED, - struct dpif_flow_stats *stats OVS_UNUSED, - ovs_u128 *ufid OVS_UNUSED, - struct ofpbuf *rbuffer OVS_UNUSED, - struct ofpbuf *wbuffer OVS_UNUSED) +netdev_tc_flow_dump_next(struct netdev_flow_dump *dump, + struct match *match, + struct nlattr **actions, + struct dpif_flow_stats *stats, + ovs_u128 *ufid, + struct ofpbuf *rbuffer, + struct ofpbuf *wbuffer) { + struct ofpbuf nl_flow; + + for (;;) { + if (nl_dump_next(dump->nl_dump, &nl_flow, rbuffer)) { + struct tc_flow tc_flow; + struct flow *mask = &match->wc.masks; + ovs_u128 *uf; + + if (parse_tc_flow(&nl_flow, &tc_flow) == EAGAIN) { + continue; + } + + parse_tc_flow_to_match(&tc_flow, match, actions, stats, wbuffer); + + uf = find_ufid(tc_flow.prio, tc_flow.handle, dump->netdev); + if (!uf) { + VLOG_DBG("unmatched flow dumped: %d, %d %d, creating ufid", + tc_flow.prio, tc_flow.handle, + netdev_get_ifindex(dump->netdev)); + dpif_flow_hash(NULL, &match->flow, sizeof match->flow, ufid); + add_ufid_tc_mapping(ufid, tc_flow.prio, tc_flow.handle, + dump->netdev); + } else { + *ufid = *uf; + } + + match_set_in_port(match, dump->port); + memset(&mask->in_port, 0xFF, sizeof mask->in_port); + + return true; + } + break; + } return false; }