[ovs-dev] [PATCH v3, 7/7] ovn-northd: add IPv6 RS responder support
Zongkai LI
zealokii at gmail.com
Fri Oct 14 03:57:21 UTC 2016
This patch add support for building Router Solicitation responder flows, which
will be used to reply Router Advertisement packet from ovn-controller for
VM/VIF port.
It adds table Logical_Router_RA_Prefix_Config to define a set of ND Prefix
informations configurations(such as valid_lifetime, preferred_lifetime) for
a IPv6 prefix.
It adds table Logical_Router_Port new columns:
- ipv6_ra_prefix_configs: to refer records in Logical_Router_RA_Prefix_Config
for lrouter port to use for its networks.
- ipv6_ra_configs: to define a set of RA configurations, such as
"managed_address" flag, router_lifetime.
Signed-off-by: Zongkai LI <zealokii at gmail.com>
---
ovn/northd/ovn-northd.c | 140 ++++++++++++++++++++++++++++++++++++++++++++--
ovn/ovn-nb.ovsschema | 21 ++++++-
ovn/ovn-nb.xml | 103 ++++++++++++++++++++++++++++++++++
ovn/utilities/ovn-nbctl.c | 5 ++
tests/ovn.at | 137 +++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 398 insertions(+), 8 deletions(-)
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 093d5ff..0400dea 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -130,9 +130,10 @@ enum ovn_stage {
PIPELINE_STAGE(ROUTER, IN, DEFRAG, 2, "lr_in_defrag") \
PIPELINE_STAGE(ROUTER, IN, UNSNAT, 3, "lr_in_unsnat") \
PIPELINE_STAGE(ROUTER, IN, DNAT, 4, "lr_in_dnat") \
- PIPELINE_STAGE(ROUTER, IN, IP_ROUTING, 5, "lr_in_ip_routing") \
- PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 6, "lr_in_arp_resolve") \
- PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 7, "lr_in_arp_request") \
+ PIPELINE_STAGE(ROUTER, IN, RS_RSP, 5, "lr_in_rs_rsp") \
+ PIPELINE_STAGE(ROUTER, IN, IP_ROUTING, 6, "lr_in_ip_routing") \
+ PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 7, "lr_in_arp_resolve") \
+ PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 8, "lr_in_arp_request") \
\
/* Logical router egress stages. */ \
PIPELINE_STAGE(ROUTER, OUT, SNAT, 0, "lr_out_snat") \
@@ -4040,7 +4041,134 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
"ip", "flags.loopback = 1; ct_dnat;");
}
- /* Logical router ingress table 5: IP Routing.
+ /* Logical router ingress table 5: RS responder, reply for router port
+ * with IPv6 networks configured. (priority 50)*/
+ HMAP_FOR_EACH (op, key_node, ports) {
+ if (!op->nbrp || op->nbrp->peer || !op->peer) {
+ continue;
+ }
+
+ if (!op->lrp_networks.n_ipv6_addrs) {
+ continue;
+ }
+
+ ds_clear(&match);
+ ds_put_format(&match, "inport == %s && ip6.dst == ff02::2 && nd_rs",
+ op->json_key);
+ ds_clear(&actions);
+
+ const char *hop_lmt = smap_get(
+ &op->nbrp->ipv6_ra_configs, "cur_hop_limit");
+ const char *mgd_addr = smap_get(
+ &op->nbrp->ipv6_ra_configs, "managed_address");
+ const char *other_cfg = smap_get(
+ &op->nbrp->ipv6_ra_configs, "other_config");
+ const char *rtr_lt = smap_get(
+ &op->nbrp->ipv6_ra_configs, "router_lifetime");
+ const char *rch_t = smap_get(
+ &op->nbrp->ipv6_ra_configs, "reachable_time");
+ const char *rts_t = smap_get(
+ &op->nbrp->ipv6_ra_configs, "retrans_timer");
+ const char *mtu_s = smap_get(
+ &op->nbrp->ipv6_ra_configs, "mtu");
+
+ uint8_t managed_address_flag = ND_RA_MANAGED_ADDRESS;
+ if (mgd_addr && !strcmp(mgd_addr, "0")) {
+ managed_address_flag = 0;
+ }
+ uint8_t other_config_flag = ND_RA_OTHER_CONFIG;
+ if (other_cfg && !strcmp(other_cfg, "0")) {
+ other_config_flag = 0;
+ }
+ uint32_t mtu = (mtu_s && atoi(mtu_s) >= 1280) ? atoi(mtu_s) : 0;
+
+ ds_put_format(&actions, "nd_ra{put_nd_ra(%u, %u, %u, %u, %u); "
+ "put_nd_opt_sll(%s); ",
+ (hop_lmt && atoi(hop_lmt) > 0) ? atoi(hop_lmt) : 64,
+ managed_address_flag | other_config_flag,
+ (rtr_lt && atoi(rtr_lt) > 0) ? atoi(rtr_lt) : 10800,
+ (rch_t && atoi(rch_t) > 0) ? atoi(rch_t) : 0,
+ (rts_t && atoi(rts_t) > 0) ? atoi(rts_t) : 0,
+ op->lrp_networks.ea_s);
+ if (mtu > 0) {
+ ds_put_format(&actions, "put_nd_opt_mtu(%u); ",
+ mtu);
+ }
+ size_t prev_actions_len = actions.length;
+ struct ds lrp_prefix = DS_EMPTY_INITIALIZER;
+ for (size_t i = 0; i != op->lrp_networks.n_ipv6_addrs; i++) {
+ if (in6_is_lla(&op->lrp_networks.ipv6_addrs[i].network)) {
+ continue;
+ }
+ uint8_t onlink_flag = ND_PREFIX_ON_LINK;
+ uint8_t autonomous_address_flag = ND_PREFIX_AUTONOMOUS_ADDRESS;
+ const char *v_lt = NULL;
+ const char *p_lt = NULL;
+ ds_put_format(&lrp_prefix, "%s/%u",
+ op->lrp_networks.ipv6_addrs[i].network_s,
+ op->lrp_networks.ipv6_addrs[i].plen);
+ for (size_t j = 0; j != op->nbrp->n_ipv6_ra_prefix_configs; j++) {
+ if (!strcmp(ds_cstr(&lrp_prefix),
+ op->nbrp->ipv6_ra_prefix_configs[j]->prefix)) {
+ const char *ol = smap_get(
+ &op->nbrp->ipv6_ra_prefix_configs[j]->options,
+ "onlink");
+ const char *aa = smap_get(
+ &op->nbrp->ipv6_ra_prefix_configs[j]->options,
+ "autonomous_address");
+ v_lt = smap_get(
+ &op->nbrp->ipv6_ra_prefix_configs[j]->options,
+ "valid_lifetime");
+ p_lt = smap_get(
+ &op->nbrp->ipv6_ra_prefix_configs[j]->options,
+ "preferred_lifetime");
+ if (ol && !strcmp(ol, "0")) {
+ onlink_flag = 0;
+ }
+ if (aa && !strcmp(aa, "0")) {
+ autonomous_address_flag = 0;
+ }
+ break;
+ }
+ }
+ ds_put_format(&actions,
+ "put_nd_opt_prefix(%u, %u, %u, %u, %s); ",
+ op->lrp_networks.ipv6_addrs[i].plen,
+ (onlink_flag | autonomous_address_flag),
+ (v_lt && atoi(v_lt) > 0) ? atoi(v_lt) : 10800,
+ (p_lt && atoi(p_lt) > 0) ? atoi(p_lt) : 10800,
+ op->lrp_networks.ipv6_addrs[i].network_s);
+ ds_clear(&lrp_prefix);
+ }
+ ds_destroy(&lrp_prefix);
+
+ if (actions.length != prev_actions_len) {
+ char ip6_str[INET6_ADDRSTRLEN + 1];
+ struct in6_addr lla;
+ in6_generate_lla(op->lrp_networks.ea, &lla);
+ memset(ip6_str, 0, sizeof(ip6_str));
+ ipv6_string_mapped(ip6_str, &lla);
+ ds_put_format(&actions, "eth.src = %s; ip6.src = %s; "
+ "outport = inport; flags.loopback = 1; "
+ "output;};",
+ op->lrp_networks.ea_s,
+ ip6_str);
+ ovn_lflow_add(lflows, op->od, S_ROUTER_IN_RS_RSP, 50,
+ ds_cstr(&match), ds_cstr(&actions));
+ }
+ }
+
+ /* Logical router ingress table 5: RS responder, by default goto next.
+ * (priority 0)*/
+ HMAP_FOR_EACH (od, key_node, datapaths) {
+ if (!od->nbr) {
+ continue;
+ }
+
+ ovn_lflow_add(lflows, od, S_ROUTER_IN_RS_RSP, 0, "1", "next;");
+ }
+
+ /* Logical router ingress table 6: IP Routing.
*
* A packet that arrives at this table is an IP packet that should be
* routed to the address in 'ip[46].dst'. This table sets outport to
@@ -4082,7 +4210,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
/* XXX destination unreachable */
- /* Local router ingress table 6: ARP Resolution.
+ /* Local router ingress table 7: ARP Resolution.
*
* Any packet that reaches this table is an IP packet whose next-hop IP
* address is in reg0. (ip4.dst is the final destination.) This table
@@ -4277,7 +4405,7 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
"get_nd(outport, xxreg0); next;");
}
- /* Local router ingress table 7: ARP request.
+ /* Local router ingress table 8: ARP request.
*
* In the common case where the Ethernet destination has been resolved,
* this table outputs the packet (priority 0). Otherwise, it composes
diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema
index 865dd34..afc5489 100644
--- a/ovn/ovn-nb.ovsschema
+++ b/ovn/ovn-nb.ovsschema
@@ -1,7 +1,7 @@
{
"name": "OVN_Northbound",
- "version": "5.4.0",
- "cksum": "4176761817 11225",
+ "version": "5.5.0",
+ "cksum": "3485267177 12201",
"tables": {
"NB_Global": {
"columns": {
@@ -188,6 +188,14 @@
"mac": {"type": "string"},
"peer": {"type": {"key": "string", "min": 0, "max": 1}},
"enabled": {"type": {"key": "boolean", "min": 0, "max": 1}},
+ "ipv6_ra_configs": {
+ "type": {"key": "string", "value": "string",
+ "min": 0, "max": "unlimited"}},
+ "ipv6_ra_prefix_configs": {"type": {"key": {"type": "uuid",
+ "refTable": "Logical_Router_RA_Prefix_Config",
+ "refType": "weak"},
+ "min": 0,
+ "max": "unlimited"}},
"external_ids": {
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}},
@@ -217,6 +225,15 @@
"external_ids": {
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}},
+ "isRoot": true},
+ "Logical_Router_RA_Prefix_Config": {
+ "columns": {
+ "prefix": {"type": "string"},
+ "options": {"type": {"key": "string", "value": "string",
+ "min": 0, "max": "unlimited"}},
+ "external_ids": {
+ "type": {"key": "string", "value": "string",
+ "min": 0, "max": "unlimited"}}},
"isRoot": true}
}
}
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index e1b3136..16fec1f 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -1027,6 +1027,54 @@
The Ethernet address that belongs to this router port.
</column>
+ <group title="ipv6_ra_configs">
+ <p>
+ This column defines the IPv6 RA configurations and ND MTU Option to be
+ used by <code>ovn-northd</code> when it generates logical flows for
+ Router Solicitaion responder.
+ Please refer to RFC 4861 for more details on RA message fields and
+ ND MTU Option.
+ </p>
+
+ <column name="ipv6_ra_configs" key="cur_hop_limit">
+ Current hop limit. Default is 64.
+ </column>
+
+ <column name="ipv6_ra_configs" key="managed_address">
+ 1-bit "Managed address configuration" flag. Default is 1.
+ </column>
+
+ <column name="ipv6_ra_configs" key="other_config">
+ 1-bit "Other configuration" flag. Default is 1.
+ </column>
+
+ <column name="ipv6_ra_configs" key="router_lifetime">
+ Router lifetime. Default is 10800(seconds).
+ </column>
+
+ <column name="ipv6_ra_configs" key="reachable_time">
+ Reachable time. Default is 0.
+ </column>
+
+ <column name="ipv6_ra_configs" key="retrans_timer">
+ Retrans timer. Default is 0.
+ </column>
+
+ <column name="ipv6_ra_configs" key="mtu">
+ The recommended MTU for the link. Default is 0, which means no MTU
+ Option will be included in RA packet replied by ovn-controller.
+ Per RFC 2460, the mtu value is recommended no less than 1280, so
+ any mtu value less than 1280 will be considerred as no MTU Option.
+ </column>
+ </group>
+
+ <column name="ipv6_ra_prefix_configs">
+ This column defines the IPv6 ND Prefix Information Option configurations
+ to be used by <code>ovn-northd</code> when it generates logical flows for
+ Router Solicitaion responder.
+ Please see the <ref table="Logical_Router_RA_Prefix_Config"/> table.
+ </column>
+
<column name="enabled">
This column is used to administratively set port state. If this column
is empty or is set to <code>true</code>, the port is enabled. If this
@@ -1449,4 +1497,59 @@
</column>
</group>
</table>
+
+ <table name="Logical_Router_RA_Prefix_Config" title="Logical Router RA Prefix Config">
+ <p>
+ Each record represents a set of RA configurations for
+ Logical_Router_Port to use.
+ </p>
+
+ <column name="prefix">
+ <p>
+ The RA Prefix Information Option configurations will be used if the
+ logical router port has its network in this <ref column="prefix"/>.
+ </p>
+ </column>
+
+ <group title="configs">
+ <p>
+ The CMS should define the set of ND Prefix Information Option
+ configurations as key/value pairs in the <ref column="configs"/> column
+ of this table.
+ Records in <ref table="Logical_Router_Port"/> can refer record in this
+ table in their <ref column="ipv6_ra_prefix_configs"/> to configure Router
+ Solicitation responder. Then <code>ovn-northd</code> will build logical
+ flows per ND Prefix Information Option configurations defined in the
+ <ref column="configs"/> column.
+ </p>
+
+ <p>
+ Below are the supported ND Prefix Information Option configurations.
+ Please refer to RFC 4861 for more details.
+ </p>
+
+ <column name="options" key="onlink">
+ 1-bit on-link flag. Default is 1.
+ </column>
+
+ <column name="options" key="autonomous">
+ 1-bit autonomous address-configuration flag. Default is 1.
+ </column>
+
+ <column name="options" key="valid_lifetime">
+ Valid lifetime for on-link prefix. Default is 10800(seconds).
+ </column>
+
+ <column name="options" key="preferred_lifetime">
+ Preferred lifetime for on-link prefix. Default is 10800(seconds).
+ </column>
+ </group>
+
+ <group title="Common Columns">
+ <column name="external_ids">
+ See <em>External IDs</em> at the beginning of this document.
+ </column>
+ </group>
+ </table>
+
</database>
diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c
index ad2d2f8..62ca4cc 100644
--- a/ovn/utilities/ovn-nbctl.c
+++ b/ovn/utilities/ovn-nbctl.c
@@ -2637,6 +2637,11 @@ static const struct ctl_table_class tables[] = {
NULL},
{NULL, NULL, NULL}}},
+ {&nbrec_table_logical_router_ra_prefix_config,
+ {{&nbrec_table_logical_router_ra_prefix_config, NULL,
+ NULL},
+ {NULL, NULL, NULL}}},
+
{NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}}
};
diff --git a/tests/ovn.at b/tests/ovn.at
index 85f75d0..fc54833 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -5475,3 +5475,140 @@ check_tos 0
OVN_CLEANUP([hv])
AT_CLEANUP
+
+AT_SETUP([ovn -- nd_ra ])
+AT_KEYWORDS([ovn-nd_ra])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+ovn_start
+
+# In this test case we create 1 lswitch with 3 VIF ports attached,
+# and a lrouter connected to the lswitch.
+# Router solicitation packet we test, sent from VIF port, will be replied
+# by local ovn-controller.
+
+# Create hypervisors and logical switch lsw0, logical router lr0, attach lsw0
+# onto lr0, set Logical_Router_Port.slaac column to 'true' to allow lrp0 send
+# RA for SLAAC mode.
+ovn-nbctl ls-add lsw0
+ovn-nbctl lr-add lr0
+ovn-nbctl lrp-add lr0 lrp0 fa:16:3e:00:00:01 fdad:1234:5678::1/64
+ovn-nbctl set Logical_Router_Port lrp0 slaac="true"
+ovn-nbctl \
+ -- lsp-add lsw0 lsp0 \
+ -- set Logical_Switch_Port lsp0 type=router \
+ options:router-port=lrp0 \
+ addresses='"fa:16:3e:00:00:01 fdad:1234:5678::1"'
+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
+ovn-nbctl lsp-add lsw0 lp1
+ovn-nbctl lsp-set-addresses lp1 "fa:16:3e:00:00:02 10.0.0.12 fdad:1234:5678:0:f816:3eff:fe:2"
+ovn-nbctl lsp-set-port-security lp1 "fa:16:3e:00:00:02 10.0.0.12 fdad:1234:5678:0:f816:3eff:fe:2"
+
+# 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
+ovn-nbctl lsp-add lsw0 lp2
+ovn-nbctl lsp-set-addresses lp2 "fa:16:3e:00:00:03 10.0.0.13 fdad:1234:5678:0:f816:3eff:fe:3"
+ovn-nbctl lsp-set-port-security lp2 "fa:16:3e:00:00:03 10.0.0.13 fdad:1234:5678:0:f816:3eff:fe:3"
+
+# Add vif3 to hv1 and lsw0, turn on l2 port security on vif3.
+ovs-vsctl add-port br-int vif3 -- set Interface vif3 external-ids:iface-id=lp3 options:tx_pcap=hv1/vif3-tx.pcap options:rxq_pcap=hv1/vif3-rx.pcap
+ovn-nbctl lsp-add lsw0 lp3
+ovn-nbctl lsp-set-addresses lp3 "fa:16:3e:00:00:04 10.0.0.14 fdad:1234:5678:0:f816:3eff:fe:4"
+ovn-nbctl lsp-set-port-security lp3 "fa:16:3e:00:00:04 10.0.0.14 fdad:1234:5678:0:f816:3eff:fe:4"
+
+# 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
+ovn-nbctl acl-add lsw0 to-lport 1002 'outport == "lp3" && 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.
+trim_zeros() {
+ sed 's/\(00\)\{1,\}$//'
+}
+for i in 1 2 3; do
+ : > $i.expected
+done
+
+# This shell function sends a Router Solicitation packet and receives
+# Router Solicitation packet from vif.
+# test_ipv6_ra INPORT SRC_MAC SRC_LLA RA_CONFIG MTU RA_PREFIX_CONFIG
+test_ipv6_ra() {
+ local inport=$1 src_mac=$2 src_lla=$3 ra_config=$4 mtu=$5 ra_prefix_config=$6
+ local request=333300000002${src_mac}86dd6000000000103aff${src_lla}ff02000000000000000000000000000285000efc000000000101${src_mac}
+
+ local len=40
+ if test $mtu == 0; then
+ len=38
+ unset mtu
+ fi
+ local lrp_mac=fa163e000001
+ local lrp_lla=fe80000000000000f8163efffe000001
+ local lrp_prefix=fdad1234567800000000000000000000
+ local reply=${src_mac}${lrp_mac}86dd6000000000${len}3aff${lrp_lla}${src_lla}8600${ra_config}0101${lrp_mac}${mtu}0304${ra_prefix_config}00000000${lrp_prefix}
+
+ as hv1 ovs-appctl netdev-dummy/receive vif${inport} $request
+ echo $reply | trim_zeros >> $inport.expected
+}
+
+# No setting to lrp0 ipv6_ra_configs and ipv6_ra_prefix_configs, vif1 will get
+# a RA packet with default configs.
+default_ra_config=40c02a300000000000000000
+default_prefix_option_config=40c000002a3000002a30
+src_mac=fa163e000002
+src_lla=fe80000000000000f8163efffe000002
+test_ipv6_ra 1 $src_mac $src_lla $default_ra_config 0 $default_prefix_option_config
+
+# Set lrp0 ipv6_ra_configs, vif2 will get a configured RA packet
+ovn-nbctl add Logical_Router_Port lrp0 ipv6_ra_config managed_address="0" other_config="0" mtu="1450"
+sleep 1
+ra_config=40002a300000000000000000
+mtu_opt=05010000000005aa
+src_mac=fa163e000003
+src_lla=fe80000000000000f8163efffe000003
+test_ipv6_ra 2 $src_mac $src_lla $ra_config $mtu_opt $default_prefix_option_config
+
+# Create a Logical_Router_RA_Prefix_Config, and set lrp0.ipv6_ra_prefix_configs
+# to refer it, vif3 will get a configured RA packet with configured Prefix
+# Information Option.
+ovn-nbctl -- --id=@d1 create Logical_Router_RA_Prefix_Config prefix=\"fdad:1234:5678::/64\" \
+options="\"valid_lifetime\"="21600" \"preferred_lifetime\"="21600" \
+\"autonomous_address\"="0"" \
+-- add Logical_Router_Port lrp0 ipv6_ra_prefix_configs @d1
+sleep 1
+prefix_option_config=40800000546000005460
+src_mac=fa163e000004
+src_lla=fe80000000000000f8163efffe000004
+test_ipv6_ra 3 $src_mac $src_lla $ra_config $mtu_opt $prefix_option_config
+
+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
+as hv1 ovn-sbctl lflow-list
+
+for i in 1 2 3; do
+ file=hv1/vif$i-tx.pcap
+ echo $file
+ # Remove checksum to compare.
+ $PYTHON "$top_srcdir/utilities/ovs-pcap.in" $file | trim_zeros | cut -b 1-112,117- > $i.packets
+ cat $i.expected > expout
+ AT_CHECK([cat $i.packets], [0], [expout])
+done
+
+OVN_CLEANUP([hv1])
+
+AT_CLEANUP
--
2.7.4
More information about the dev
mailing list