From patchwork Mon Sep 10 11:24:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 967979 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=fail (p=none dis=none) header.from=redhat.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 4285M2745Lz9s3C for ; Mon, 10 Sep 2018 21:25:34 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 36E9DCA8; Mon, 10 Sep 2018 11:25:14 +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 2F643C9B for ; Mon, 10 Sep 2018 11:25:13 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wr1-f65.google.com (mail-wr1-f65.google.com [209.85.221.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 5FDFA766 for ; Mon, 10 Sep 2018 11:25:12 +0000 (UTC) Received: by mail-wr1-f65.google.com with SMTP id g33-v6so21546935wrd.1 for ; Mon, 10 Sep 2018 04:25:12 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=XfH3s+Bb06B/sofLzAYsWVZeCyhcISiiZmL9JQnb/fA=; b=ZNpdNs0WQQpc9Biz0R5dh0mmHOuBBYBo5Xj1QHO/NRJo0oc6Va/qTjRvRi/slbi+mX OZEWeh/VQdt9XFwjvdXAKWEPFAmv5+Wvqdf+x11tXRw2IfltQnWrgA/ZWbnk+huBzzVn TRbSGHj9QyOnsQsa4jLOgi5VK3fSbJOxXO5rVWX0vCq9qP0GgztQPlKfSnd0ZdMbuKNT uxnnvgQLE+JE6uLa5epop/P+bJHdT3z7QeTAOWC8Zeht/PsbPqDEeHzX+vqbs4ViDbtx 7JI7Kq6NSOEdvKWvXT6uMml+QPEv5ZIOKhKUm0rdixW4s98r40kM3i8Mj3/zkKMVMIdE fcRw== X-Gm-Message-State: APzg51CuSkKpyO0jHs4UCsP4g/IPY1creJkzqYTfIMpWw31sw0b6PnnT 3a15oehz+54DtWAXZEcbJnGf/5sFf1g= X-Google-Smtp-Source: ANB0VdZn3qJO4AbcDxFNowB5m2X+IMluBr/V/JImdoU70HtUeBChqfg/ZS5Dy3iK56iyVd0kmW0aCQ== X-Received: by 2002:a5d:6451:: with SMTP id d17-v6mr13580506wrw.64.1536578710644; Mon, 10 Sep 2018 04:25:10 -0700 (PDT) Received: from localhost.localdomain.com (nat-pool-mxp-t.redhat.com. [149.6.153.186]) by smtp.gmail.com with ESMTPSA id b10-v6sm15002084wrr.88.2018.09.10.04.25.09 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 10 Sep 2018 04:25:10 -0700 (PDT) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Mon, 10 Sep 2018 13:24:55 +0200 Message-Id: X-Mailer: git-send-email 2.17.1 In-Reply-To: References: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [RFC 1/2] OVN: add buffering support for ipv4 packets 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 Add buffering support for IPv4 packets that will be processed by arp {} action when L2 address is not discovered yet since otherwise the packet will be substituted with an ARP frame and this will result in the lost of the first packet of the connection Signed-off-by: Lorenzo Bianconi --- ovn/controller/pinctrl.c | 180 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 175 insertions(+), 5 deletions(-) diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index 0164696cc..3f8c0ac4e 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -61,6 +61,9 @@ static struct rconn *swconn; * rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */ static unsigned int conn_seq_no; +static void init_buffered_packets_map(void); +static void destroy_buffered_packets_map(void); + static void pinctrl_handle_put_mac_binding(const struct flow *md, const struct flow *headers, bool is_arp); @@ -108,6 +111,7 @@ static void send_ipv6_ras( ; COVERAGE_DEFINE(pinctrl_drop_put_mac_binding); +COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map); void pinctrl_init(void) @@ -117,6 +121,7 @@ pinctrl_init(void) init_put_mac_bindings(); init_send_garps(); init_ipv6_ras(); + init_buffered_packets_map(); } static ovs_be32 @@ -190,10 +195,147 @@ set_actions_and_enqueue_msg(const struct dp_packet *packet, ofpbuf_uninit(&ofpacts); } +struct buffer_info { + struct ofpbuf ofpacts; + struct dp_packet *p; +}; + +#define BUFFER_QUEUE_DEPTH 64 +struct buffered_packets { + struct hmap_node hmap_node; + + /* key */ + char ip[INET6_ADDRSTRLEN]; + + long long int timestamp; + + struct buffer_info data[BUFFER_QUEUE_DEPTH]; + int head, tail; +}; + +static struct hmap buffered_packets_map; + +static void +init_buffered_packets_map(void) +{ + hmap_init(&buffered_packets_map); +} + +static void +destroy_buffered_packets(struct buffered_packets *bp) +{ + struct buffer_info *bi; + + while (bp->head != bp->tail) { + bi = &bp->data[bp->head]; + dp_packet_uninit(bi->p); + ofpbuf_uninit(&bi->ofpacts); + + bp->head = (bp->head + 1) % BUFFER_QUEUE_DEPTH; + } + hmap_remove(&buffered_packets_map, &bp->hmap_node); + free(bp); +} + +static void +destroy_buffered_packets_map(void) +{ + struct buffered_packets *bp; + HMAP_FOR_EACH_POP (bp, hmap_node, &buffered_packets_map) { + destroy_buffered_packets(bp); + } + hmap_destroy(&buffered_packets_map); +} + +static void +buffered_push_packet(struct buffered_packets *bp, + struct dp_packet *packet, + const struct match *md) +{ + struct buffer_info *bi = &bp->data[bp->tail]; + int next = (bp->tail + 1) % BUFFER_QUEUE_DEPTH; + + ofpbuf_init(&bi->ofpacts, 4096); + + reload_metadata(&bi->ofpacts, md); + struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&bi->ofpacts); + resubmit->in_port = OFPP_CONTROLLER; + resubmit->table_id = OFTABLE_REMOTE_OUTPUT; + + bi->p = packet; + + if (next == bp->head) { + bi = &bp->data[bp->head]; + dp_packet_uninit(bi->p); + ofpbuf_uninit(&bi->ofpacts); + bp->head = (bp->head + 1) % BUFFER_QUEUE_DEPTH; + } + bp->tail = next; +} + static void -pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md, - struct ofpbuf *userdata) +buffered_send_packets(struct buffered_packets *bp, unsigned char *addr) { + enum ofp_version version = rconn_get_version(swconn); + enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); + + while (bp->head != bp->tail) { + struct buffer_info *bi = &bp->data[bp->head]; + memcpy(dp_packet_data(bi->p), addr, 6); + + struct ofputil_packet_out po = { + .packet = dp_packet_data(bi->p), + .packet_len = dp_packet_size(bi->p), + .buffer_id = UINT32_MAX, + .ofpacts = bi->ofpacts.data, + .ofpacts_len = bi->ofpacts.size, + }; + match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER); + queue_msg(ofputil_encode_packet_out(&po, proto)); + + ofpbuf_uninit(&bi->ofpacts); + dp_packet_uninit(bi->p); + + bp->head = (bp->head + 1) % BUFFER_QUEUE_DEPTH; + } +} + +#define BUFFER_MAP_TIMEOUT 30000 +static void +buffered_packets_map_gc(void) +{ + struct buffered_packets *cur_qp, *next_qp; + long long int now = time_msec(); + + HMAP_FOR_EACH_SAFE (cur_qp, next_qp, hmap_node, &buffered_packets_map) { + if (now > cur_qp->timestamp + BUFFER_MAP_TIMEOUT) { + destroy_buffered_packets(cur_qp); + } + } +} + +static struct buffered_packets * +pinctrl_find_buffered_packets(const char *ip, uint32_t hash) +{ + struct buffered_packets *qp; + + HMAP_FOR_EACH_WITH_HASH (qp, hmap_node, hash, + &buffered_packets_map) { + if (!strcmp(qp->ip, ip)) { + return qp; + } + } + return NULL; +} + +static void +pinctrl_handle_arp(const struct flow *ip_flow, struct dp_packet *pkt_in, + const struct match *md, struct ofpbuf *userdata) +{ + struct dp_packet *clone, packet; + uint64_t packet_stub[128 / 8]; + char ip[INET6_ADDRSTRLEN]; + /* This action only works for IP packets, and the switch should only send * us IP packets this way, but check here just to be sure. */ if (ip_flow->dl_type != htons(ETH_TYPE_IP)) { @@ -203,9 +345,28 @@ pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md, return; } + inet_ntop(AF_INET, &ip_flow->nw_dst, ip, sizeof(ip)); + uint32_t hash = hash_string(ip, 0); + struct buffered_packets *bp = pinctrl_find_buffered_packets(ip, hash); + if (!bp) { + if (hmap_count(&buffered_packets_map) >= 1000) { + COVERAGE_INC(pinctrl_drop_buffered_packets_map); + goto send_arp; + } + + bp = xmalloc(sizeof *bp); + hmap_insert(&buffered_packets_map, &bp->hmap_node, hash); + ovs_strlcpy_arrays(bp->ip, ip); + bp->head = bp->tail = 0; + } + bp->timestamp = time_msec(); + /* clone the packet to send it later with correct L2 address */ + clone = dp_packet_clone_data(dp_packet_data(pkt_in), + dp_packet_size(pkt_in)); + buffered_push_packet(bp, clone, md); + +send_arp: /* Compose an ARP packet. */ - uint64_t packet_stub[128 / 8]; - struct dp_packet packet; dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); compose_arp__(&packet); @@ -1152,7 +1313,7 @@ process_packet_in(const struct ofp_header *msg, switch (ntohl(ah->opcode)) { case ACTION_OPCODE_ARP: - pinctrl_handle_arp(&headers, &pin.flow_metadata, &userdata); + pinctrl_handle_arp(&headers, &packet, &pin.flow_metadata, &userdata); break; case ACTION_OPCODE_PUT_ARP: @@ -1300,6 +1461,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn, local_datapaths, active_tunnels); send_ipv6_ras(sbrec_port_binding_by_datapath, sbrec_port_binding_by_name, local_datapaths); + buffered_packets_map_gc(); } /* Table of ipv6_ra_state structures, keyed on logical port name */ @@ -1610,6 +1772,7 @@ pinctrl_destroy(void) destroy_put_mac_bindings(); destroy_send_garps(); destroy_ipv6_ras(); + destroy_buffered_packets_map(); } /* Implementation of the "put_arp" and "put_nd" OVN actions. These @@ -1676,6 +1839,7 @@ pinctrl_handle_put_mac_binding(const struct flow *md, uint32_t dp_key = ntohll(md->metadata); uint32_t port_key = md->regs[MFF_LOG_INPORT - MFF_REG0]; char ip_s[INET6_ADDRSTRLEN]; + struct buffered_packets *bp; if (is_arp) { ovs_be32 ip = htonl(md->regs[0]); @@ -1701,6 +1865,12 @@ pinctrl_handle_put_mac_binding(const struct flow *md, } pmb->timestamp = time_msec(); pmb->mac = headers->dl_src; + + /* send queued pkts */ + bp = pinctrl_find_buffered_packets(ip_s, hash_string(ip_s, 0)); + if (bp) { + buffered_send_packets(bp, pmb->mac.ea); + } } static const struct sbrec_mac_binding * From patchwork Mon Sep 10 11:24:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lorenzo Bianconi X-Patchwork-Id: 967980 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=fail (p=none dis=none) header.from=redhat.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 4285MV0THMz9s3x for ; Mon, 10 Sep 2018 21:25:58 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id EA2B3CB1; Mon, 10 Sep 2018 11:25:16 +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 D21D9C9E for ; Mon, 10 Sep 2018 11:25:14 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-wm0-f65.google.com (mail-wm0-f65.google.com [74.125.82.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 4B3ED71C for ; Mon, 10 Sep 2018 11:25:14 +0000 (UTC) Received: by mail-wm0-f65.google.com with SMTP id c14-v6so21151634wmb.4 for ; Mon, 10 Sep 2018 04:25:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=aMWa0uq5jtTN94A2wZLD8siLqCbLFeGznOnobuBtvM8=; b=ezyojK8jviKDeL+sW5t3yv66gnWaaPb3VX4V3JVwyjcRYYH8okiByeDDJ5iR57PkKE 1ikFtmOp2QOqyhjhi6DyX8LPmTS4o87N6W5QzM6fFzodzePDOam7KNm4HVdZXJ8PcG7k +/uV/Nw5/GwMHnInYXu07avpjF2CCj2HpmDjw48ZzptFgqQkku4bmSoSI2bGSsmmbg/+ zjDLXulIyhZC4l76HNR6mzTNGurgrayTfBorRsGUx0eZ2N9LLwrlyHza4ncxrMqFMdTx kjjORCiNoai96ibHy2RyH6MZne1kLScbt2AY7xE6VYFu0MDWtKLJ96vToDlZ4pteEOm+ LLAQ== X-Gm-Message-State: APzg51Dyxb1ZyEQi6TiMLVlYAKVu16PsOsUklAnx5iQhG/qc23XKJ1mO yCHpRcXFTeOeK+0jU4GF67JfMIJ/grc= X-Google-Smtp-Source: ANB0VdbwsT06OsAlzyjikUr22P5ZatjD9DTQeoYg8wt0PVemcQSlkgiYraYeRZUqWb2zzzPCiA6S+g== X-Received: by 2002:a1c:f11a:: with SMTP id p26-v6mr424940wmh.92.1536578712557; Mon, 10 Sep 2018 04:25:12 -0700 (PDT) Received: from localhost.localdomain.com (nat-pool-mxp-t.redhat.com. [149.6.153.186]) by smtp.gmail.com with ESMTPSA id b10-v6sm15002084wrr.88.2018.09.10.04.25.11 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 10 Sep 2018 04:25:12 -0700 (PDT) From: Lorenzo Bianconi To: dev@openvswitch.org Date: Mon, 10 Sep 2018 13:24:56 +0200 Message-Id: <2b1b9985bef24caf0d86abb592cae86571f45ce7.1536577990.git.lorenzo.bianconi@redhat.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [RFC 2/2] OVN: add buffering support for ipv6 packets 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 Add buffering support for IPv6 packets that will be processed by nd_ns {} action when L2 address is not discovered yet since otherwise the packet will be substituted with a Neighbor Solicitation frame and this will result in the lost of the first packet of the connection Signed-off-by: Lorenzo Bianconi --- ovn/controller/pinctrl.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index 3f8c0ac4e..6436be428 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -99,6 +99,7 @@ static void pinctrl_handle_put_nd_ra_opts( struct ofputil_packet_in *pin, struct ofpbuf *userdata, struct ofpbuf *continuation); static void pinctrl_handle_nd_ns(const struct flow *ip_flow, + struct dp_packet *pkt_in, const struct match *md, struct ofpbuf *userdata); static void init_ipv6_ras(void); @@ -1358,7 +1359,8 @@ process_packet_in(const struct ofp_header *msg, break; case ACTION_OPCODE_ND_NS: - pinctrl_handle_nd_ns(&headers, &pin.flow_metadata, &userdata); + pinctrl_handle_nd_ns(&headers, &packet, &pin.flow_metadata, + &userdata); break; case ACTION_OPCODE_ICMP: @@ -2569,9 +2571,13 @@ pinctrl_handle_nd_na(const struct flow *ip_flow, const struct match *md, } static void -pinctrl_handle_nd_ns(const struct flow *ip_flow, const struct match *md, - struct ofpbuf *userdata) +pinctrl_handle_nd_ns(const struct flow *ip_flow, struct dp_packet *pkt_in, + const struct match *md, struct ofpbuf *userdata) { + struct dp_packet *clone, packet; + uint64_t packet_stub[128 / 8]; + char ip[INET6_ADDRSTRLEN]; + /* This action only works for IPv6 packets. */ if (get_dl_type(ip_flow) != htons(ETH_TYPE_IPV6)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -2579,8 +2585,27 @@ pinctrl_handle_nd_ns(const struct flow *ip_flow, const struct match *md, return; } - uint64_t packet_stub[128 / 8]; - struct dp_packet packet; + inet_ntop(AF_INET6, &ip_flow->ipv6_dst, ip, sizeof(ip)); + uint32_t hash = hash_string(ip, 0); + struct buffered_packets *bp = pinctrl_find_buffered_packets(ip, hash); + if (!bp) { + if (hmap_count(&buffered_packets_map) >= 1000) { + COVERAGE_INC(pinctrl_drop_buffered_packets_map); + goto send_ns; + } + + bp = xmalloc(sizeof *bp); + hmap_insert(&buffered_packets_map, &bp->hmap_node, hash); + ovs_strlcpy_arrays(bp->ip, ip); + bp->head = bp->tail = 0; + } + bp->timestamp = time_msec(); + /* clone the packet to send it later with correct L2 address */ + clone = dp_packet_clone_data(dp_packet_data(pkt_in), + dp_packet_size(pkt_in)); + buffered_push_packet(bp, clone, md); + +send_ns: dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); compose_nd_ns(&packet, ip_flow->dl_src, &ip_flow->ipv6_src,