tunneling: Enable IPv6 tuneling.
authorPravin B Shelar <pshelar@ovn.org>
Thu, 24 Mar 2016 16:30:57 +0000 (09:30 -0700)
committerPravin B Shelar <pshelar@ovn.org>
Thu, 24 Mar 2016 16:30:57 +0000 (09:30 -0700)
There is check to disable IPv6 tunneling. Following patch
removes it and reintroduces the tunneling automake tests.

This reverts mostly commit 250bd94d1e500a89c76cac944e660bd9c07ac364.
There are couple of new autotests and updated documentation
related to ipv6 tunneling added in this patch.

Signed-off-by: Pravin B Shelar <pshelar@ovn.org>
Acked-by: Ben Pfaff <blp@ovn.org>
NEWS
lib/netdev-vport.c
ofproto/tunnel.c
tests/tunnel-push-pop-ipv6.at
tests/tunnel-push-pop.at
utilities/ovs-ofctl.8.in
vswitchd/vswitch.xml

diff --git a/NEWS b/NEWS
index 81489ab..f0d0adb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,10 @@ Post-v2.5.0
      * Introduced SELinux policy package.
    - Datapath Linux kernel compatibility.
      * Dropped support for kernel older than 3.10.
+   - Tunnels:
+     * Flow based tunnel match and action can be used for IPv6 address using
+       tun_ipv6_src, tun_ipv6_dst fields.
+     * Added support for IPv6 tunnels to native tunneling.
 
 v2.5.0 - 26 Feb 2016
 ---------------------
index faf000f..3d81c6c 100644 (file)
@@ -504,10 +504,6 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
                           name, node->value);
                 return EINVAL;
             }
-            if (dst_proto == ETH_TYPE_IPV6) {
-                VLOG_WARN("%s: IPv6 'remote_ip' is not supported", name);
-                return EOPNOTSUPP;
-            }
         } else if (!strcmp(node->key, "local_ip")) {
             int err;
             err = parse_tunnel_ip(node->value, true, &tnl_cfg.ip_src_flow,
@@ -517,10 +513,6 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
                 VLOG_WARN("%s: bad %s 'local_ip'", name, type);
                 break;
             }
-            if (src_proto == ETH_TYPE_IPV6) {
-                VLOG_WARN("%s: IPv6 'local_ip' is not supported", name);
-                return EOPNOTSUPP;
-            }
         } else if (!strcmp(node->key, "tos")) {
             if (!strcmp(node->value, "inherit")) {
                 tnl_cfg.tos_inherit = true;
index 551334f..6f307ff 100644 (file)
@@ -427,14 +427,6 @@ tnl_port_send(const struct ofport_dpif *ofport, struct flow *flow,
             flow->tunnel.ipv6_dst = tnl_port->match.ipv6_dst;
         }
     }
-    if (ipv6_addr_is_set(&flow->tunnel.ipv6_dst) ||
-        ipv6_addr_is_set(&flow->tunnel.ipv6_src)) {
-        out_port = ODPP_NONE;
-        VLOG_WARN_RL(&rl, "port (%s): IPv6 tunnel endpoint is not supported",
-                     netdev_get_name(tnl_port->netdev));
-        goto out;
-    }
-
     flow->pkt_mark = tnl_port->match.pkt_mark;
 
     if (!cfg->out_key_flow) {
index d3b09b8..94e6159 100644 (file)
@@ -10,10 +10,158 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \
                        options:remote_ip=2001:cafe::92 options:key=456 ofport_request=3\
                     -- add-port int-br t3 -- set Interface t3 type=vxlan \
                        options:remote_ip=2001:cafe::93 options:out_key=flow options:csum=true ofport_request=4\
-                       ], [0], [], [dnl
-ovs-vsctl: Error detected while setting up 't2', 't1', 't3'.  See ovs-vswitchd log for details.
+                    -- add-port int-br t4 -- set Interface t4 type=geneve \
+                       options:remote_ip=flow options:key=123 ofport_request=5\
+                       ], [0])
+
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+dummy@ovs-dummy: hit:0 missed:0
+       br0:
+               br0 65534/100: (dummy)
+               p0 1/1: (dummy)
+       int-br:
+               int-br 65534/2: (dummy)
+               t1 3/3: (gre: key=456, remote_ip=2001:cafe::92)
+               t2 2/4789: (vxlan: key=123, remote_ip=2001:cafe::92)
+               t3 4/4789: (vxlan: csum=true, out_key=flow, remote_ip=2001:cafe::93)
+               t4 5/6081: (geneve: key=123, remote_ip=flow)
+])
+
+dnl First setup dummy interface IP address, then add the route
+dnl so that tnl-port table can get valid IP address for the device.
+AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::88/24], [0], [OK
+])
+AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/24], [0], [OK
+])
+AT_CHECK([ovs-appctl ovs/route/add 2001:cafe::92/24 br0], [0], [OK
+])
+
+AT_CHECK([ovs-ofctl add-flow br0 action=normal])
+
+dnl Check Neighbour discovery.
+AT_CHECK([ovs-vsctl -- set Interface p0 options:pcap=p0.pcap])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive int-br 'in_port(2),eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'])
+AT_CHECK([tcpdump -vntr p0.pcap > p0.pcap.txt 2>&1])
+
+AT_CHECK([cat p0.pcap.txt | grep ff02::1:ff00:92 | uniq], [0], [dnl
+IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) 2001:cafe::88 > ff02::1:ff00:92: [[icmp6 sum ok]] ICMP6, neighbor solicitation, length 32, who has 2001:cafe::92
+])
+AT_CHECK([cat p0.pcap.txt | grep ff02::1:ff00:93 | uniq], [0], [dnl
+IP6 (hlim 255, next-header ICMPv6 (58) payload length: 32) 2001:cafe::88 > ff02::1:ff00:93: [[icmp6 sum ok]] ICMP6, neighbor solicitation, length 32, who has 2001:cafe::93
+])
+
+dnl Check ARP Snoop
+AT_CHECK([ovs-appctl netdev-dummy/receive br0 'in_port(100),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::94,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::92,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:b6)'])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive br0 'in_port(100),eth(src=f8:bc:12:44:34:b7,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::93,dst=2001:cafe::94,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::93,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:b7)'])
+
+AT_CHECK([ovs-appctl tnl/arp/show], [0], [dnl
+IP                                            MAC                 Bridge
+==========================================================================
+2001:cafe::92                                 f8:bc:12:44:34:b6   br0
+2001:cafe::93                                 f8:bc:12:44:34:b7   br0
+])
+
+AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl
+Listening ports:
+genev_sys_6081 (6081)
+gre_sys (3)
+vxlan_sys_4789 (4789)
+])
+
+dnl Check VXLAN tunnel pop
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=51283,dst=4789)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_pop(4789)
+])
+
+dnl Check GRE tunnel pop
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=47,tclass=0x0,hlimit=64)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_pop(3)
+])
+
+dnl Check Geneve tunnel pop
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=51283,dst=6081)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_pop(6081)
+])
+
+dnl Check VXLAN tunnel push
+AT_CHECK([ovs-ofctl add-flow int-br action=2])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7b)),out_port(100))
+])
+
+dnl Check VXLAN tunnel push set tunnel id by flow and checksum
+AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_push(tnl_port(4789),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::93,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100))
+])
+
+dnl Check GRE tunnel push
+AT_CHECK([ovs-ofctl add-flow int-br action=3])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_push(tnl_port(3),header(size=62,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100))
+])
+
+dnl Check Geneve tunnel push
+AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,5"])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_push(tnl_port(6081),header(size=70,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x7b)),out_port(100))
+])
+
+dnl Check Geneve tunnel push with options
+AT_CHECK([ovs-ofctl add-tlv-map int-br "{class=0xffff,type=0x80,len=4}->tun_metadata0"])
+AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,set_field:0xa->tun_metadata0,5"])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: tnl_push(tnl_port(6081),header(size=78,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(crit,vni=0x7b,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(100))
+])
+
+dnl Check decapsulation of GRE packet
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6486dd60000000006a2f402001cafe0000000000000000000000922001cafe00000000000000000000008820006558000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  3'], [0], [dnl
+  port  3: rx pkts=1, bytes=98, drop=0, errs=0, frame=0, over=0, crc=0
+])
+
+dnl Check GRE only accepts encapsulated Ethernet frames
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6486dd60000000006a2f402001cafe0000000000000000000000922001cafe00000000000000000000008820000800000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  3'], [0], [dnl
+  port  3: rx pkts=1, bytes=98, drop=0, errs=0, frame=0, over=0, crc=0
+])
+
+dnl Check decapsulation of Geneve packet with options
+AT_CAPTURE_FILE([ofctl_monitor.log])
+AT_CHECK([ovs-ofctl monitor int-br 65534 --detach --no-chdir --pidfile 2> ofctl_monitor.log])
+
+AT_CHECK([ovs-ofctl del-flows int-br])
+AT_CHECK([ovs-ofctl add-flow int-br "tun_metadata0=0xa/0xf,actions=5,controller"])
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6486dd60000000008211402001cafe0000000000000000000000922001cafe000000000000000000000088308817c1008200000400655800007b00ffff80010000000affff00010000000bfe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
+
+OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 2])
+OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
+
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN2 (xid=0x0): cookie=0x0 total_len=98 tun_id=0x7b,tun_ipv6_src=2001:cafe::92,tun_ipv6_dst=2001:cafe::88,tun_metadata0=0xa,in_port=5 (via action) data_len=98 (unbuffered)
+icmp,vlan_tci=0x0000,dl_src=be:b6:f4:e1:49:4a,dl_dst=fe:71:d8:83:72:4f,nw_src=30.0.0.1,nw_dst=30.0.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,icmp_type=0,icmp_code=0 icmp_csum:4227
+])
+
+AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  5'], [0], [dnl
+  port  5: rx pkts=1, bytes=98, drop=0, errs=0, frame=0, over=0, crc=0
+])
+AT_CHECK([ovs-appctl dpif/dump-flows int-br], [0], [dnl
+tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),skb_mark(0),recirc_id(0),in_port(6081),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:userspace(pid=0,slow_path(controller))
 ])
 
-OVS_VSWITCHD_STOP(["/remote_ip/d
-/could not set configuration/d"])
+OVS_VSWITCHD_STOP
 AT_CLEANUP
index a6118a8..ed249da 100644 (file)
@@ -31,11 +31,27 @@ dnl First setup dummy interface IP address, then add the route
 dnl so that tnl-port table can get valid IP address for the device.
 AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 1.1.2.88/24], [0], [OK
 ])
+AT_CHECK([ovs-appctl netdev-dummy/ip6addr br0 2001:cafe::88/24], [0], [OK
+])
+
 AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0], [0], [OK
 ])
 
 AT_CHECK([ovs-ofctl add-flow br0 action=normal])
 
+dnl Check ARP request
+AT_CHECK([ovs-vsctl -- set Interface p0 options:pcap=p0.pcap])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive int-br 'in_port(2),eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'])
+AT_CHECK([tcpdump -vntr p0.pcap > p0.pcap.txt 2>&1])
+
+AT_CHECK([cat p0.pcap.txt | grep 1.1.2.92 | uniq], [0], [dnl
+ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 1.1.2.92 tell 1.1.2.88, length 28
+])
+AT_CHECK([cat p0.pcap.txt | grep 1.1.2.93 | uniq], [0], [dnl
+ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 1.1.2.93 tell 1.1.2.88, length 28
+])
+
 dnl Check ARP Snoop
 AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)'])
 AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b7,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.93,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:b7,tha=00:00:00:00:00:00)'])
index 9156782..6e26132 100644 (file)
@@ -1218,13 +1218,15 @@ For non-tunneled packets, the value is 0.
 .IP
 This field was introduced in Open vSwitch 2.5.
 .
-.IP \fBtun_src=\fIip\fR[\fB/\fInetmask\fR]
-.IQ \fBtun_dst=\fIip\fR[\fB/\fInetmask\fR]
-Matches tunnel IPv4 source (or destination) address \fIip\fR. Only packets
+.IP \fBtun_src=\fIipv4\fR[\fB/\fInetmask\fR]
+.IQ \fBtun_dst=\fIipv4\fR[\fB/\fInetmask\fR]
+.IQ \fBtun_ipv6_src=\fIipv6\fR[\fB/\fInetmask\fR]
+.IQ \fBtun_ipv6_dst=\fIipv6\fR[\fB/\fInetmask\fR]
+Matches tunnel IP source (or destination) address \fIip\fR. Only packets
 that arrive over a tunnel will have nonzero tunnel addresses.
 The address may be specified as an IP address or host name
 (e.g. \fB192.168.1.1\fR or \fBwww.example.com\fR).  The optional
-\fInetmask\fR allows restricting a match to a masked IPv4 address.
+\fInetmask\fR allows restricting a match to a masked IP address.
 The netmask may be specified as a dotted quad
 (e.g. \fB192.168.1.0/255.255.255.0\fR) or as a CIDR block
 (e.g. \fB192.168.1.0/24\fR).
index f7b7b9c..0998584 100644 (file)
           <dt><code>geneve</code></dt>
           <dd>
             An Ethernet over Geneve (<code>http://tools.ietf.org/html/draft-ietf-nvo3-geneve-00</code>)
-            IPv4 tunnel.
+            IPv4/IPv6 tunnel.
 
             A description of how to match and set Geneve options can be found
             in the <code>ovs-ofctl</code> manual page.
 
           <dt><code>gre</code></dt>
           <dd>
-            An Ethernet over RFC 2890 Generic Routing Encapsulation over IPv4
+            An Ethernet over RFC 2890 Generic Routing Encapsulation over IPv4/IPv6
             tunnel.
           </dd>
 
           <dt><code>ipsec_gre</code></dt>
           <dd>
-            An Ethernet over RFC 2890 Generic Routing Encapsulation over IPv4
+            An Ethernet over RFC 2890 Generic Routing Encapsulation over IPv4/IPv6
             IPsec tunnel.
           </dd>
 
 
         <ul>
           <li>
-            An IPv4 address (not a DNS name), e.g. <code>192.168.0.123</code>.
+            An IPv4 or IPv6 address (not a DNS name), e.g. <code>192.168.0.123</code>.
             Only unicast endpoints are supported.
           </li>
           <li>
             The word <code>flow</code>.  The tunnel accepts packets from any
             remote tunnel endpoint.  To process only packets from a specific
             remote tunnel endpoint, the flow entries may match on the
-            <code>tun_src</code> field.  When sending packets to a
-            <code>remote_ip=flow</code> tunnel, the flow actions must
-            explicitly set the <code>tun_dst</code> field to the IP address of
-            the desired remote tunnel endpoint, e.g. with a
-            <code>set_field</code> action.
+            <code>tun_src</code> or <code>tun_ipv6_src</code>field.  When
+            sending packets to a <code>remote_ip=flow</code> tunnel, the flow
+            actions must explicitly set the <code>tun_dst</code> or
+            <code>tun_ipv6_dst</code> field to the IP address of the desired
+            remote tunnel endpoint, e.g. with a <code>set_field</code> action.
           </li>
         </ul>
 
 
         <ul>
           <li>
-            An IPv4 address (not a DNS name), e.g. <code>192.168.12.3</code>.
+            An IPv4/IPv6 address (not a DNS name), e.g. <code>192.168.12.3</code>.
           </li>
           <li>
             The word <code>flow</code>.  The tunnel accepts packets sent to any
             of the local IP addresses of the system running OVS.  To process
             only packets sent to a specific IP address, the flow entries may
-            match on the <code>tun_dst</code> field.  When sending packets to a
-            <code>local_ip=flow</code> tunnel, the flow actions may
-            explicitly set the <code>tun_src</code> field to the desired IP
-            address, e.g. with a <code>set_field</code> action.  However, while
-            routing the tunneled packet out, the local system may override the
-            specified address with the local IP address configured for the
+            match on the <code>tun_dst</code> or <code>tun_ipv6_dst</code> field.
+            When sending packets to a <code>local_ip=flow</code> tunnel, the flow
+            actions may explicitly set the <code>tun_src</code> or <code>tun_ipv6_src</code>
+            field to the desired IP address, e.g. with a <code>set_field</code> action.
+            However, while routing the tunneled packet out, the local system may
+            override the specified address with the local IP address configured for the
             outgoing system interface.
 
             <p>
 
         <p>
           The tunnel destination IP address for any packet received from a
-          tunnel is available in the <code>tun_dst</code> field for matching in
-          the flow table.
+          tunnel is available in the <code>tun_dst</code> or <code>tun_ipv6_dst</code>
+          field for matching in the flow table.
         </p>
       </column>
 
       </column>
 
       <column name="status" key="source_ip">
-        The source IP address used for an IPv4 tunnel end-point, such as
+        The source IP address used for an IPv4/IPv6 tunnel end-point, such as
         <code>gre</code>.
       </column>
 
         <p>
           The supported fields are: <code>tun_id</code>,
           <code>tun_src</code>, <code>tun_dst</code>,
+          <code>tun_ipv6_src</code>, <code>tun_ipv6_dst</code>,
           <code>nw_src</code>, <code>nw_dst</code> (or aliases
           <code>ip_src</code> and <code>ip_dst</code>),
           <code>ipv6_src</code>, and <code>ipv6_dst</code>.  (Using this