From patchwork Wed Jun 15 03:09:37 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zong Kai LI X-Patchwork-Id: 635680 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (archives.nicira.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id 3rTs294p2Hz9t1T for ; Wed, 15 Jun 2016 13:09:52 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=zdmHMR4g; dkim-atps=neutral Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id 99EE910660; Tue, 14 Jun 2016 20:09:51 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v3.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id 5315A1065F for ; Tue, 14 Jun 2016 20:09:50 -0700 (PDT) Received: from bar6.cudamail.com (localhost [127.0.0.1]) by mx3v3.cudamail.com (Postfix) with ESMTPS id D3FC4162223 for ; Tue, 14 Jun 2016 21:09:49 -0600 (MDT) X-ASG-Debug-ID: 1465960187-0b32373692571920001-byXFYA Received: from mx3-pf2.cudamail.com ([192.168.14.1]) by bar6.cudamail.com with ESMTP id K8oh1PUH5ndN2Efp (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 14 Jun 2016 21:09:47 -0600 (MDT) X-Barracuda-Envelope-From: zealokii@gmail.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.1 Received: from unknown (HELO mail-it0-f68.google.com) (209.85.214.68) by mx3-pf2.cudamail.com with ESMTPS (AES128-SHA encrypted); 15 Jun 2016 03:09:46 -0000 Received-SPF: pass (mx3-pf2.cudamail.com: SPF record at _netblocks.google.com designates 209.85.214.68 as permitted sender) X-Barracuda-Apparent-Source-IP: 209.85.214.68 X-Barracuda-RBL-IP: 209.85.214.68 Received: by mail-it0-f68.google.com with SMTP id e5so1577770ith.2 for ; Tue, 14 Jun 2016 20:09:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id; bh=HIQ/7QB/DbhXNk3r2PDAsq/9gMtA/Im9yPhnCudNsOc=; b=zdmHMR4gOQSGCZy+0Z9On0axlEQkqXXLGbBqI7GgMqKAuPM89g+uv+vLkknhLqiPcf zrRPIubk47FzmkHmPiPWNCyKXH1k+22V6zMo+MQdzTr8AHXhnh4ErWQ6U5dm8l83F/jc BPVsdCoN329ep+ia3j0acS7AB5SdrfPEu3NYhB9f8Zoe7OVfo8TkVws1UAhJ1ZpC7oLs 5h9kPgDJSqH3fMRSmA/VVML/EPrTAIc9N/1QACvkQkvatnatB2qgao2QPbCW2S1GtzH8 HYLOYpMWhzPIuI/SaFOFPuyH2wZOQOQ/+lXJ4DakgjuA6DCCLVM62Itj0diFyQ6xRcUT A5eA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=HIQ/7QB/DbhXNk3r2PDAsq/9gMtA/Im9yPhnCudNsOc=; b=L198Kos+Vq0u+2WEEaBh0JsyIetHHw3FfqeY288YGFqFVPLWt+kQ/6SR2/1Z2D77nS uBOMQHtVqvlJqh4I/OUISFd80vCGcstuYv51tqW6xyehIew/b/PB9TKnn3kAJYsgysrE WNC1KuoAAasEZZrPvI1DDHJMi5s1UG0af2NN/GGIfE+Uw0BirDNW1B1WR6mJiB8lIeSu RbncRxoBFyW0V1tXMdDeKdMQw+MFHJ+zZKNQyUDNxV/2wTJ7meAFkPZ7Slt+E3Tn8ZcG WxPctAG2ya9qgZQr7nhqi8Z6lmGk8s2zZ4Nme/cmLlt1WcF3p7TnhPFdOsFB+6tPegcV ciRQ== X-Gm-Message-State: ALyK8tIxtEkOg8G73HNN+aPOMjVV/ehR6+OveHYjAVX4wBLiOVDHAgdcuXZ5yZp31odTrQ== X-Received: by 10.36.95.207 with SMTP id r198mr31359319itb.49.1465960185236; Tue, 14 Jun 2016 20:09:45 -0700 (PDT) Received: from localhost.localdomain ([106.38.0.69]) by smtp.gmail.com with ESMTPSA id v84sm266410iod.43.2016.06.14.20.09.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 14 Jun 2016 20:09:44 -0700 (PDT) X-CudaMail-Envelope-Sender: zealokii@gmail.com From: Zong Kai LI To: dev@openvswitch.org X-CudaMail-MID: CM-V2-613065920 X-CudaMail-DTE: 061416 X-CudaMail-Originating-IP: 209.85.214.68 Date: Wed, 15 Jun 2016 11:09:37 +0800 X-ASG-Orig-Subj: [##CM-V2-613065920##][PATCH] [PATCH, v4, 1/2] ovn-controller: Add 'na' action for ND Message-Id: <1465960177-17056-1-git-send-email-zealokii@gmail.com> X-Mailer: git-send-email 1.9.1 X-GBUdb-Analysis: 0, 209.85.214.68, Ugly c=0.374854 p=-0.210526 Source Normal X-MessageSniffer-Rules: 0-0-0-32767-c X-Barracuda-Connect: UNKNOWN[192.168.14.1] X-Barracuda-Start-Time: 1465960187 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-Spam-Score: 1.10 X-Barracuda-Spam-Status: No, SCORE=1.10 using global scores of TAG_LEVEL=3.5 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=4.0 tests=BSF_RULE7568M, BSF_SC5_MJ1963, DKIM_SIGNED, RDNS_NONE X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.30445 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.00 DKIM_SIGNED Domain Keys Identified Mail: message has a signature 0.50 BSF_RULE7568M Custom Rule 7568M 0.10 RDNS_NONE Delivered to trusted network by a host with no rDNS 0.50 BSF_SC5_MJ1963 Custom Rule MJ1963 Cc: Zong Kai LI Subject: [ovs-dev] [PATCH] [PATCH, v4, 1/2] ovn-controller: Add 'na' action for ND X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" This patch adds a new OVN action 'na' to support ND versus ARP. When ovn-controller received a ND packet, it frames a template NA packet for reply. The NA packet will be initialized based on ND packet, such as NA packet will use: - ND packet eth.src as eth.dst, - ND packet eth.dst as eth.src, - ND packet ip6.src as ip6.dst, - ND packet nd.target as ip6.src, - ND packet eth.dst as nd.tll. Then nested actions in 'na' action will update necessary fileds for NA packet, such as: - eth.src, nd.tll - inport, outport Eg. na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; /* Allow sending out inport. */ output; }; Since patch port for IPv6 router interface is not ready yet, this patch will only try to deal with ND from VM. This patch will set RSO flags to 011 for NA packets. The next patch will do logical flows works for this action. Signed-off-by: Zong Kai LI --- lib/packets.c | 29 ++++++++++ lib/packets.h | 4 ++ ovn/controller/pinctrl.c | 134 ++++++++++++++++++++++++++++++++++++++--------- ovn/lib/actions.c | 43 +++++++++++++++ ovn/lib/actions.h | 6 +++ ovn/ovn-sb.xml | 39 ++++++++++++++ tests/ovn.at | 101 +++++++++++++++++++++++++++++++++++ 7 files changed, 331 insertions(+), 25 deletions(-) diff --git a/lib/packets.c b/lib/packets.c index 43b5a70..617ff66 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -1355,6 +1355,35 @@ compose_nd(struct dp_packet *b, const struct eth_addr eth_src, ND_MSG_LEN + ND_OPT_LEN)); } +void +compose_na(struct dp_packet *b, + const struct eth_addr eth_src, const struct eth_addr eth_dst, + const ovs_be32 ipv6_src[4], const ovs_be32 ipv6_dst[4], + ovs_be16 rco_flags) +{ + struct ovs_nd_msg *na; + struct ovs_nd_opt *nd_opt; + uint32_t icmp_csum; + + eth_compose(b, eth_dst, eth_src, ETH_TYPE_IPV6, IPV6_HEADER_LEN); + na = compose_ipv6(b, IPPROTO_ICMPV6, ipv6_src, ipv6_dst, 0, 0, 255, + ND_MSG_LEN + ND_OPT_LEN); + + na->icmph.icmp6_type = ND_NEIGHBOR_ADVERT; + na->icmph.icmp6_code = 0; + na->rco_flags.hi = rco_flags; + + nd_opt = &na->options[0]; + nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; + nd_opt->nd_opt_len = 1; + + packet_set_nd(b, ipv6_src, eth_addr_zero, eth_src); + na->icmph.icmp6_cksum = 0; + icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b)); + na->icmph.icmp6_cksum = csum_finish(csum_continue(icmp_csum, na, + ND_MSG_LEN + ND_OPT_LEN)); +} + uint32_t packet_csum_pseudoheader(const struct ip_header *ip) { diff --git a/lib/packets.h b/lib/packets.h index 5945940..55e2500 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -1069,6 +1069,10 @@ void compose_arp(struct dp_packet *, uint16_t arp_op, ovs_be32 arp_spa, ovs_be32 arp_tpa); void compose_nd(struct dp_packet *, const struct eth_addr eth_src, struct in6_addr *, struct in6_addr *); +void compose_na(struct dp_packet *, + const struct eth_addr eth_src, const struct eth_addr eth_dst, + const ovs_be32 ipv6_src[4], const ovs_be32 ipv6_dst[4], + ovs_be16 rco_flags); uint32_t packet_csum_pseudoheader(const struct ip_header *); void IP_ECN_set_ce(struct dp_packet *pkt, bool is_ipv6); diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index 116397e..00e8fde 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -23,6 +23,8 @@ #include "flow.h" #include "lport.h" #include "ovn-controller.h" +#include "lib/byte-order.h" +#include "lib/packets.h" #include "lib/sset.h" #include "openvswitch/ofp-actions.h" #include "openvswitch/ofp-msgs.h" @@ -64,6 +66,11 @@ static void send_garp_run(const struct ovsrec_bridge *, const char *chassis_id, const struct lport_index *lports, struct hmap *local_datapaths); +static void pinctrl_handle_na(const struct flow *ip_flow, + const struct match *md, + struct ofpbuf *userdata); +static void reload_metadata(struct ofpbuf *ofpacts, + const struct match *md); COVERAGE_DEFINE(pinctrl_drop_put_arp); @@ -153,31 +160,7 @@ pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md, struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); enum ofp_version version = rconn_get_version(swconn); - enum mf_field_id md_fields[] = { -#if FLOW_N_REGS == 8 - MFF_REG0, - MFF_REG1, - MFF_REG2, - MFF_REG3, - MFF_REG4, - MFF_REG5, - MFF_REG6, - MFF_REG7, -#else -#error -#endif - MFF_METADATA, - }; - for (size_t i = 0; i < ARRAY_SIZE(md_fields); i++) { - const struct mf_field *field = mf_from_id(md_fields[i]); - if (!mf_is_all_wild(field, &md->wc)) { - struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts); - sf->field = field; - sf->flow_has_vlan = false; - mf_get_value(field, &md->flow, &sf->value); - memset(&sf->mask, 0xff, field->n_bytes); - } - } + reload_metadata(&ofpacts, md); enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size, version, &ofpacts); if (error) { @@ -242,6 +225,10 @@ process_packet_in(const struct ofp_header *msg) pinctrl_handle_put_arp(&pin.flow_metadata.flow, &headers); break; + case ACTION_OPCODE_NA: + pinctrl_handle_na(&headers, &pin.flow_metadata, &userdata); + break; + default: VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32, ntohl(ah->opcode)); @@ -734,3 +721,100 @@ send_garp_run(const struct ovsrec_bridge *br_int, const char *chassis_id, sset_destroy(&localnet_vifs); simap_destroy(&localnet_ofports); } + +static void +reload_metadata(struct ofpbuf *ofpacts, const struct match *md) +{ + enum mf_field_id md_fields[] = { +#if FLOW_N_REGS == 8 + MFF_REG0, + MFF_REG1, + MFF_REG2, + MFF_REG3, + MFF_REG4, + MFF_REG5, + MFF_REG6, + MFF_REG7, +#else +#error +#endif + MFF_METADATA, + }; + for (size_t i = 0; i < ARRAY_SIZE(md_fields); i++) { + const struct mf_field *field = mf_from_id(md_fields[i]); + if (!mf_is_all_wild(field, &md->wc)) { + struct ofpact_set_field *sf = ofpact_put_SET_FIELD(ofpacts); + sf->field = field; + sf->flow_has_vlan = false; + mf_get_value(field, &md->flow, &sf->value); + memset(&sf->mask, 0xff, field->n_bytes); + } + } +} + +static void +pinctrl_handle_na(const struct flow *ip_flow, + const struct match *md, + struct ofpbuf *userdata) +{ + /* This action only works for IPv6 packets, and the switch should only send + * us IPv6 packets this way, but check here just to be sure. */ + if (ip_flow->dl_type != htons(ETH_TYPE_IPV6)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "NA action on non-IPv6 packet (Ethertype %"PRIx16")", + ntohs(ip_flow->dl_type)); + return; + } + + enum ofp_version version = rconn_get_version(swconn); + enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); + + uint64_t packet_stub[128 / 8]; + struct dp_packet packet; + dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub); + ovs_be32 ipv6_src[4], ipv6_dst[4]; + for (int i = 0; i < 4; i++) { + ipv6_dst[i] = BYTES_TO_BE32(ip_flow->ipv6_src.s6_addr[4*i], + ip_flow->ipv6_src.s6_addr[4*i+1], + ip_flow->ipv6_src.s6_addr[4*i+2], + ip_flow->ipv6_src.s6_addr[4*i+3]); + ipv6_src[i] = BYTES_TO_BE32(ip_flow->nd_target.s6_addr[4*i], + ip_flow->nd_target.s6_addr[4*i+1], + ip_flow->nd_target.s6_addr[4*i+2], + ip_flow->nd_target.s6_addr[4*i+3]); + } + /* Frame the NA packet with RSO=011. */ + compose_na(&packet, + ip_flow->dl_dst, ip_flow->dl_src, + ipv6_src, ipv6_dst, + htons(0x6000)); + + /* Reload previous packet metadata. */ + uint64_t ofpacts_stub[4096 / 8]; + struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); + reload_metadata(&ofpacts, md); + + enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size, + version, &ofpacts); + if (error) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "failed to parse actions for 'na' (%s)", + ofperr_to_string(error)); + goto exit; + } + + struct ofputil_packet_out po = { + .packet = dp_packet_data(&packet), + .packet_len = dp_packet_size(&packet), + .buffer_id = UINT32_MAX, + .in_port = OFPP_CONTROLLER, + .ofpacts = ofpacts.data, + .ofpacts_len = ofpacts.size, + }; + + queue_msg(ofputil_encode_packet_out(&po, proto)); + +exit: + dp_packet_uninit(&packet); + ofpbuf_uninit(&ofpacts); +} diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c index 5f0bf19..31a8678 100644 --- a/ovn/lib/actions.c +++ b/ovn/lib/actions.c @@ -442,6 +442,47 @@ emit_ct(struct action_context *ctx, bool recirc_next, bool commit) add_prerequisite(ctx, "ip"); } +static void +parse_na_action(struct action_context *ctx) +{ + if (!lexer_match(ctx->lexer, LEX_T_LCURLY)) { + action_syntax_error(ctx, "expecting `{'"); + return; + } + + struct ofpbuf *outer_ofpacts = ctx->ofpacts; + uint64_t inner_ofpacts_stub[1024 / 8]; + struct ofpbuf inner_ofpacts = OFPBUF_STUB_INITIALIZER(inner_ofpacts_stub); + ctx->ofpacts = &inner_ofpacts; + + /* Save prerequisites. (XXX What is the right treatment for prereqs?) */ + struct expr *outer_prereqs = ctx->prereqs; + ctx->prereqs = NULL; + + /* Parse inner actions. */ + while (!lexer_match(ctx->lexer, LEX_T_RCURLY)) { + if (!parse_action(ctx)) { + break; + } + } + + ctx->ofpacts = outer_ofpacts; + + /* controller. */ + size_t oc_offset = start_controller_op(ctx->ofpacts, ACTION_OPCODE_NA); + ofpacts_put_openflow_actions(inner_ofpacts.data, inner_ofpacts.size, + ctx->ofpacts, OFP13_VERSION); + finish_controller_op(ctx->ofpacts, oc_offset); + + /* Restore prerequisites. */ + expr_destroy(ctx->prereqs); + ctx->prereqs = outer_prereqs; + add_prerequisite(ctx, "nd"); + + /* Free memory. */ + ofpbuf_uninit(&inner_ofpacts); +} + static bool parse_action(struct action_context *ctx) { @@ -475,6 +516,8 @@ parse_action(struct action_context *ctx) parse_get_arp_action(ctx); } else if (lexer_match_id(ctx->lexer, "put_arp")) { parse_put_arp_action(ctx); + } else if (lexer_match_id(ctx->lexer, "na")) { + parse_na_action(ctx); } else { action_syntax_error(ctx, "expecting action"); } diff --git a/ovn/lib/actions.h b/ovn/lib/actions.h index 29af06f..ff964d6 100644 --- a/ovn/lib/actions.h +++ b/ovn/lib/actions.h @@ -44,6 +44,12 @@ enum action_opcode { * MFF_ETH_SRC = mac */ ACTION_OPCODE_PUT_ARP, + + /* "na { ...actions... }". + * + * The actions, in OpenFlow 1.3 format, follow the action_header. + */ + ACTION_OPCODE_NA, }; /* Header. */ diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index d877f76..e698365 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -985,6 +985,45 @@

Prerequisite: ip4

+
+ na { action; ... }; +
+ +
+

+ Temporarily replaces the IPv6 packet being processed by an NA + packet and executes each nested action on the NA + packet. Actions following the na action, if any, apply + to the original, unmodified packet. +

+ +

+ The NA packet that this action operates on is initialized based on + the IPv6 packet being processed, as follows. These are default + values that the nested actions will probably want to change: +

+ +
    +
  • eth.dst exchanged with eth.src
  • +
  • eth.type = 0x86dd
  • +
  • ip6.dst copied from ip6.src
  • +
  • ip6.src copied from nd.target
  • +
  • icmp6.type = 136 (Neighbor Advertisement)
  • +
  • nd.target unchanged
  • +
  • nd.sll = 00:00:00:00:00:00
  • +
  • nd.tll copied from eth.dst
  • +
+ +

+ The ND packet has the same VLAN header, if any, as the IPv6 packet + it replaces. +

+ +

+ Prerequisite: nd +

+
+
get_arp(P, A);
diff --git a/tests/ovn.at b/tests/ovn.at index a24e774..ba8d789 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -525,6 +525,9 @@ get_arp(reg0, ip4.dst); => Cannot use numeric field reg0 where string field is r # put_arp put_arp(inport, arp.spa, arp.sha); => actions=push:NXM_NX_REG0[],push:NXM_OF_ETH_SRC[],push:NXM_NX_ARP_SHA[],push:NXM_OF_ARP_SPA[],pop:NXM_NX_REG0[],pop:NXM_OF_ETH_SRC[],controller(userdata=00.00.00.01.00.00.00.00),pop:NXM_OF_ETH_SRC[],pop:NXM_NX_REG0[], prereqs=eth.type == 0x806 && eth.type == 0x806 +# na +na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inport; inport = ""; /* Allow sending out inport. */ output; }; => actions=controller(userdata=00.00.00.02.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.0c.04.00.01.0e.04.00.19.00.10.00.01.0c.04.00.00.00.00.00.00.00.00.00.19.00.10.00.00.00.02.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00), prereqs=nd + # Contradictionary prerequisites (allowed but not useful): ip4.src = ip6.src[0..31]; => actions=move:NXM_NX_IPV6_SRC[0..31]->NXM_OF_IP_SRC[], prereqs=eth.type == 0x800 && eth.type == 0x86dd ip4.src <-> ip6.src[0..31]; => actions=push:NXM_NX_IPV6_SRC[0..31],push:NXM_OF_IP_SRC[],pop:NXM_NX_IPV6_SRC[0..31],pop:NXM_OF_IP_SRC[], prereqs=eth.type == 0x800 && eth.type == 0x86dd @@ -3137,3 +3140,101 @@ OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) OVS_APP_EXIT_AND_WAIT([ovsdb-server]) AT_CLEANUP + +AT_SETUP([ovn -- nd ]) +AT_KEYWORDS([ovn-nd]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start + +#TODO: since patch port for IPv6 logical router port is not ready not, +# so we are not going to test vifs on different lswitches cases. Try +# to update for that once relevant stuff implemented. + +# In this test cases we create 1 lswitch, it has 2 VIF ports attached +# with. NS packet we test, from one VIF for another VIF, will be replied +# by local ovn-controller, but not by target VIF. + +# Create hypervisors and logical switch lsw0. +ovn-nbctl ls-add lsw0 +net_add n1 +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 + +# Add vif1 to hv1 and lsw0, turn on l2 port security on vif1. +ovs-vsctl add-port br-int vif1 -- set Interface vif1 external-ids:iface-id=lp1 options:tx_pcap=hv1/vif1-tx.pcap options:rxq_pcap=hv1/vif1-rx.pcap ofport-request=1 +ovn-nbctl lsp-add lsw0 lp1 +ovn-nbctl lsp-set-addresses lp1 "fa:16:3e:94:05:98 192.168.0.3 fd81:ce49:a948:0:f816:3eff:fe94:598" +ovn-nbctl lsp-set-port-security lp1 "fa:16:3e:94:05:98 192.168.0.3 fd81:ce49:a948:0:f816:3eff:fe94:598" + +# Add vif2 to hv1 and lsw0, turn on l2 port security on vif2. +ovs-vsctl add-port br-int vif2 -- set Interface vif2 external-ids:iface-id=lp2 options:tx_pcap=hv1/vif2-tx.pcap options:rxq_pcap=hv1/vif2-rx.pcap ofport-request=2 +ovn-nbctl lsp-add lsw0 lp2 +ovn-nbctl lsp-set-addresses lp2 "fa:16:3e:a1:f9:ae 192.168.0.4 fd81:ce49:a948:0:f816:3eff:fea1:f9ae" +ovn-nbctl lsp-set-port-security lp2 "fa:16:3e:a1:f9:ae 192.168.0.4 fd81:ce49:a948:0:f816:3eff:fea1:f9ae" + +# Add ACL rule for ICMPv6 on lsw0 +ovn-nbctl acl-add lsw0 from-lport 1002 'ip6 && icmp6' allow-related +ovn-nbctl acl-add lsw0 to-lport 1002 'outport == "lp1" && ip6 && icmp6' allow-related +ovn-nbctl acl-add lsw0 to-lport 1002 'outport == "lp2" && ip6 && icmp6' allow-related + +# Allow some time for ovn-northd and ovn-controller to catch up. +# XXX This should be more systematic. +sleep 1 + +# Given the name of a logical port, prints the name of the hypervisor +# on which it is located. +vif_to_hv() { + echo hv1${1%?} +} +trim_zeros() { + sed 's/\(00\)\{1,\}$//' +} +for i in 1 2; do + : > $i.expected +done + +# Complete Neighbor Solicitation packet and Neighbor Advertisement packet +# vif1 -> NS -> vif2. vif1 <- NA <- ovn-controller. +# vif2 will not receive NS packet, since ovn-controller will reply for it. +ns_packet=3333ffa1f9aefa163e94059886dd6000000000203afffd81ce49a9480000f8163efffe940598fd81ce49a9480000f8163efffea1f9ae8700e01160000000fd81ce49a9480000f8163efffea1f9ae0101fa163e940598 +na_packet=fa163e940598fa163ea1f9ae86dd6000000000203afffd81ce49a9480000f8163efffea1f9aefd81ce49a9480000f8163efffe9405988800e9ed60000000fd81ce49a9480000f8163efffea1f9ae0201fa163ea1f9ae + +as hv1 ovs-appctl netdev-dummy/receive vif1 $ns_packet +echo $na_packet | trim_zeros >> 1.expected + +sleep 1 + +echo "------ hv1 dump ------" +as hv1 ovs-vsctl show +as hv1 ovs-ofctl -O OpenFlow13 show br-int +as hv1 ovs-ofctl -O OpenFlow13 dump-flows br-int + +for i in 1 2; do + file=hv1/vif$i-tx.pcap + echo $file + $PYTHON "$top_srcdir/utilities/ovs-pcap.in" $file | trim_zeros > $i.packets + cat $i.expected > expout + AT_CHECK([cat $i.packets], [0], [expout]) +done + +as hv1 +OVS_APP_EXIT_AND_WAIT([ovn-controller]) +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as main +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +AT_CLEANUP