commit 5a672c3079959a10c1c383c8dbd4e7ceb251937e
Author: Manuel Franceschini <livewire@google.com>
Date:   Tue Jun 29 12:43:22 2010 +0200

    DRBD IPv6 support
    
    Support IPv6 configuration for 'drbdsetup show' parser and add unittests
    concerning that case. Renames some data files to use consistent names
    clarifying their usage.
    
    Signed-off-by: Manuel Franceschini <livewire@google.com>
    Reviewed-by: Michael Hanselmann <hansmi@google.com>

diff --git a/Makefile.am b/Makefile.am
index 4a61f51..12a4860 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -348,10 +348,11 @@ maninput = \
 	$(patsubst %.html,%.html.in,$(manhtml))
 
 TEST_FILES = \
-	test/data/bdev-both.txt \
-	test/data/bdev-8.3-both.txt \
-	test/data/bdev-disk.txt \
-	test/data/bdev-net.txt \
+	test/data/bdev-drbd-8.0.txt \
+	test/data/bdev-drbd-8.3.txt \
+	test/data/bdev-drbd-disk.txt \
+	test/data/bdev-drbd-net-ip4.txt \
+	test/data/bdev-drbd-net-ip6.txt \
 	test/data/cert1.pem \
 	test/data/proc_drbd8.txt \
 	test/data/proc_drbd80-emptyline.txt \
diff --git a/lib/bdev.py b/lib/bdev.py
index f2b96f4..e941362 100644
--- a/lib/bdev.py
+++ b/lib/bdev.py
@@ -1079,7 +1079,10 @@ class DRBD8(BaseDRBD):
     # pyparsing setup
     lbrace = pyp.Literal("{").suppress()
     rbrace = pyp.Literal("}").suppress()
+    lbracket = pyp.Literal("[").suppress()
+    rbracket = pyp.Literal("]").suppress()
     semi = pyp.Literal(";").suppress()
+    colon = pyp.Literal(":").suppress()
     # this also converts the value to an int
     number = pyp.Word(pyp.nums).setParseAction(lambda s, l, t: int(t[0]))
 
@@ -1092,19 +1095,19 @@ class DRBD8(BaseDRBD):
     # value types
     value = pyp.Word(pyp.alphanums + '_-/.:')
     quoted = dbl_quote + pyp.CharsNotIn('"') + dbl_quote
-    addr_type = (pyp.Optional(pyp.Literal("ipv4")).suppress() +
-                 pyp.Optional(pyp.Literal("ipv6")).suppress())
-    addr_port = (addr_type + pyp.Word(pyp.nums + '.') +
-                 pyp.Literal(':').suppress() + number)
+    ipv4_addr = (pyp.Optional(pyp.Literal("ipv4")).suppress() +
+                 pyp.Word(pyp.nums + ".") + colon + number)
+    ipv6_addr = (pyp.Optional(pyp.Literal("ipv6")).suppress() +
+                 pyp.Optional(lbracket) + pyp.Word(pyp.hexnums + ":") +
+                 pyp.Optional(rbracket) + colon + number)
     # meta device, extended syntax
-    meta_value = ((value ^ quoted) + pyp.Literal('[').suppress() +
-                  number + pyp.Word(']').suppress())
+    meta_value = ((value ^ quoted) + lbracket + number + rbracket)
     # device name, extended syntax
     device_value = pyp.Literal("minor").suppress() + number
 
     # a statement
     stmt = (~rbrace + keyword + ~lbrace +
-            pyp.Optional(addr_port ^ value ^ quoted ^ meta_value ^
+            pyp.Optional(ipv4_addr ^ ipv6_addr ^ value ^ quoted ^ meta_value ^
                          device_value) +
             pyp.Optional(defa) + semi +
             pyp.Optional(pyp.restOfLine).suppress())
@@ -1280,8 +1283,22 @@ class DRBD8(BaseDRBD):
     # about its peer.
     cls._SetMinorSyncSpeed(minor, constants.SYNC_SPEED)
 
+    if utils.IsValidIP6(lhost):
+      if not utils.IsValidIP6(rhost):
+        _ThrowError("drbd%d: can't connect ip %s to ip %s" %
+                    (minor, lhost, rhost))
+      family = "ipv6"
+    elif utils.IsValidIP4(lhost):
+      if not utils.IsValidIP4(rhost):
+        _ThrowError("drbd%d: can't connect ip %s to ip %s" %
+                    (minor, lhost, rhost))
+      family = "ipv4"
+    else:
+      _ThrowError("drbd%d: Invalid ip %s" % (minor, lhost))
+
     args = ["drbdsetup", cls._DevPath(minor), "net",
-            "%s:%s" % (lhost, lport), "%s:%s" % (rhost, rport), protocol,
+            "%s:%s:%s" % (family, lhost, lport),
+            "%s:%s:%s" % (family, rhost, rport), protocol,
             "-A", "discard-zero-changes",
             "-B", "consensus",
             "--create-device",
diff --git a/test/data/bdev-8.3-both.txt b/test/data/bdev-8.3-both.txt
deleted file mode 100644
index bc6e741..0000000
--- a/test/data/bdev-8.3-both.txt
+++ /dev/null
@@ -1,36 +0,0 @@
-disk {
-	size            	0s _is_default; # bytes
-	on-io-error     	detach;
-	fencing         	dont-care _is_default;
-	max-bio-bvecs   	0 _is_default;
-}
-net {
-	timeout         	60 _is_default; # 1/10 seconds
-	max-epoch-size  	2048 _is_default;
-	max-buffers     	2048 _is_default;
-	unplug-watermark	128 _is_default;
-	connect-int     	10 _is_default; # seconds
-	ping-int        	10 _is_default; # seconds
-	sndbuf-size     	131070 _is_default; # bytes
-	ko-count        	0 _is_default;
-	after-sb-0pri   	discard-zero-changes;
-	after-sb-1pri   	consensus;
-	after-sb-2pri   	disconnect _is_default;
-	rr-conflict     	disconnect _is_default;
-	ping-timeout    	5 _is_default; # 1/10 seconds
-}
-syncer {
-	rate            	61440k; # bytes/second
-	after           	-1 _is_default;
-	al-extents      	257;
-}
-protocol C;
-_this_host {
-	device			minor 0;
-	disk			"/dev/xenvg/test.data";
-	meta-disk		"/dev/xenvg/test.meta" [ 0 ];
-	address			ipv4 192.168.1.1:11000;
-}
-_remote_host {
-	address			ipv4 192.168.1.2:11000;
-}
diff --git a/test/data/bdev-both.txt b/test/data/bdev-both.txt
deleted file mode 100644
index b40f5e8..0000000
--- a/test/data/bdev-both.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-disk {
-	size            	0s _is_default; # bytes
-	on-io-error     	detach;
-	fencing         	dont-care _is_default;
-}
-net {
-	timeout         	60 _is_default; # 1/10 seconds
-	max-epoch-size  	16384;
-	max-buffers     	16384;
-	unplug-watermark	128 _is_default;
-	connect-int     	10 _is_default; # seconds
-	ping-int        	10 _is_default; # seconds
-	sndbuf-size     	8388608; # bytes
-	ko-count        	0 _is_default;
-	after-sb-0pri   	disconnect _is_default;
-	after-sb-1pri   	disconnect _is_default;
-	after-sb-2pri   	disconnect _is_default;
-	rr-conflict     	disconnect _is_default;
-	ping-timeout    	5 _is_default; # 1/10 seconds
-}
-syncer {
-	rate            	30720k; # bytes/second
-	after           	-1 _is_default;
-	al-extents      	257;
-}
-protocol A;
-_this_host {
-	device			"/dev/drbd63";
-	disk			"/dev/xenvg/test.data";
-	meta-disk		"/dev/xenvg/test.meta" [ 0 ];
-	address			192.168.1.1:11000;
-}
-_remote_host {
-	address			192.168.1.2:11000;
-}
diff --git a/test/data/bdev-disk.txt b/test/data/bdev-disk.txt
deleted file mode 100644
index caed500..0000000
--- a/test/data/bdev-disk.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-disk {
-	size            	0s _is_default; # bytes
-	on-io-error     	detach;
-	fencing         	dont-care _is_default;
-}
-syncer {
-	rate            	250k _is_default; # bytes/second
-	after           	-1 _is_default;
-	al-extents      	257;
-}
-_this_host {
-	device			"/dev/drbd58";
-	disk			"/dev/xenvg/test.data";
-	meta-disk		"/dev/xenvg/test.meta" [ 0 ];
-}
diff --git a/test/data/bdev-drbd-8.0.txt b/test/data/bdev-drbd-8.0.txt
new file mode 100644
index 0000000..b40f5e8
--- /dev/null
+++ b/test/data/bdev-drbd-8.0.txt
@@ -0,0 +1,35 @@
+disk {
+	size            	0s _is_default; # bytes
+	on-io-error     	detach;
+	fencing         	dont-care _is_default;
+}
+net {
+	timeout         	60 _is_default; # 1/10 seconds
+	max-epoch-size  	16384;
+	max-buffers     	16384;
+	unplug-watermark	128 _is_default;
+	connect-int     	10 _is_default; # seconds
+	ping-int        	10 _is_default; # seconds
+	sndbuf-size     	8388608; # bytes
+	ko-count        	0 _is_default;
+	after-sb-0pri   	disconnect _is_default;
+	after-sb-1pri   	disconnect _is_default;
+	after-sb-2pri   	disconnect _is_default;
+	rr-conflict     	disconnect _is_default;
+	ping-timeout    	5 _is_default; # 1/10 seconds
+}
+syncer {
+	rate            	30720k; # bytes/second
+	after           	-1 _is_default;
+	al-extents      	257;
+}
+protocol A;
+_this_host {
+	device			"/dev/drbd63";
+	disk			"/dev/xenvg/test.data";
+	meta-disk		"/dev/xenvg/test.meta" [ 0 ];
+	address			192.168.1.1:11000;
+}
+_remote_host {
+	address			192.168.1.2:11000;
+}
diff --git a/test/data/bdev-drbd-8.3.txt b/test/data/bdev-drbd-8.3.txt
new file mode 100644
index 0000000..bc6e741
--- /dev/null
+++ b/test/data/bdev-drbd-8.3.txt
@@ -0,0 +1,36 @@
+disk {
+	size            	0s _is_default; # bytes
+	on-io-error     	detach;
+	fencing         	dont-care _is_default;
+	max-bio-bvecs   	0 _is_default;
+}
+net {
+	timeout         	60 _is_default; # 1/10 seconds
+	max-epoch-size  	2048 _is_default;
+	max-buffers     	2048 _is_default;
+	unplug-watermark	128 _is_default;
+	connect-int     	10 _is_default; # seconds
+	ping-int        	10 _is_default; # seconds
+	sndbuf-size     	131070 _is_default; # bytes
+	ko-count        	0 _is_default;
+	after-sb-0pri   	discard-zero-changes;
+	after-sb-1pri   	consensus;
+	after-sb-2pri   	disconnect _is_default;
+	rr-conflict     	disconnect _is_default;
+	ping-timeout    	5 _is_default; # 1/10 seconds
+}
+syncer {
+	rate            	61440k; # bytes/second
+	after           	-1 _is_default;
+	al-extents      	257;
+}
+protocol C;
+_this_host {
+	device			minor 0;
+	disk			"/dev/xenvg/test.data";
+	meta-disk		"/dev/xenvg/test.meta" [ 0 ];
+	address			ipv4 192.168.1.1:11000;
+}
+_remote_host {
+	address			ipv4 192.168.1.2:11000;
+}
diff --git a/test/data/bdev-drbd-disk.txt b/test/data/bdev-drbd-disk.txt
new file mode 100644
index 0000000..caed500
--- /dev/null
+++ b/test/data/bdev-drbd-disk.txt
@@ -0,0 +1,15 @@
+disk {
+	size            	0s _is_default; # bytes
+	on-io-error     	detach;
+	fencing         	dont-care _is_default;
+}
+syncer {
+	rate            	250k _is_default; # bytes/second
+	after           	-1 _is_default;
+	al-extents      	257;
+}
+_this_host {
+	device			"/dev/drbd58";
+	disk			"/dev/xenvg/test.data";
+	meta-disk		"/dev/xenvg/test.meta" [ 0 ];
+}
diff --git a/test/data/bdev-drbd-net-ip4.txt b/test/data/bdev-drbd-net-ip4.txt
new file mode 100644
index 0000000..eae1f4c
--- /dev/null
+++ b/test/data/bdev-drbd-net-ip4.txt
@@ -0,0 +1,28 @@
+net {
+	timeout         	60 _is_default; # 1/10 seconds
+	max-epoch-size  	2048 _is_default;
+	max-buffers     	2048 _is_default;
+	unplug-watermark	128 _is_default;
+	connect-int     	10 _is_default; # seconds
+	ping-int        	10 _is_default; # seconds
+	sndbuf-size     	131070 _is_default; # bytes
+	ko-count        	0 _is_default;
+	after-sb-0pri   	disconnect _is_default;
+	after-sb-1pri   	disconnect _is_default;
+	after-sb-2pri   	disconnect _is_default;
+	rr-conflict     	disconnect _is_default;
+	ping-timeout    	5 _is_default; # 1/10 seconds
+}
+syncer {
+	rate            	250k _is_default; # bytes/second
+	after           	-1 _is_default;
+	al-extents      	127 _is_default;
+}
+protocol C;
+_this_host {
+	device			"/dev/drbd59";
+	address			192.168.1.1:11002;
+}
+_remote_host {
+	address			192.168.1.2:11002;
+}
diff --git a/test/data/bdev-drbd-net-ip6.txt b/test/data/bdev-drbd-net-ip6.txt
new file mode 100644
index 0000000..87da1a5
--- /dev/null
+++ b/test/data/bdev-drbd-net-ip6.txt
@@ -0,0 +1,31 @@
+net {
+	timeout         	60 _is_default; # 1/10 seconds
+	max-epoch-size  	2048 _is_default;
+	max-buffers     	2048 _is_default;
+	unplug-watermark	128 _is_default;
+	connect-int     	10 _is_default; # seconds
+	ping-int        	10 _is_default; # seconds
+	sndbuf-size     	0 _is_default; # bytes
+	rcvbuf-size     	0 _is_default; # bytes
+	ko-count        	0 _is_default;
+	cram-hmac-alg   	"md5";
+	shared-secret   	"a6526cb6118297c9c82c7003924e236ceac0d867";
+	after-sb-0pri   	discard-zero-changes;
+	after-sb-1pri   	consensus;
+	after-sb-2pri   	disconnect _is_default;
+	rr-conflict     	disconnect _is_default;
+	ping-timeout    	5 _is_default; # 1/10 seconds
+}
+syncer {
+	rate            	61440k; # bytes/second
+	after           	-1 _is_default;
+	al-extents      	257;
+}
+protocol C;
+_this_host {
+	device			minor 0;
+	address			ipv6 [2001:db8:65::1]:11048;
+}
+_remote_host {
+	address			ipv6 [2001:db8:66::1]:11048;
+}
diff --git a/test/data/bdev-net.txt b/test/data/bdev-net.txt
deleted file mode 100644
index eae1f4c..0000000
--- a/test/data/bdev-net.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-net {
-	timeout         	60 _is_default; # 1/10 seconds
-	max-epoch-size  	2048 _is_default;
-	max-buffers     	2048 _is_default;
-	unplug-watermark	128 _is_default;
-	connect-int     	10 _is_default; # seconds
-	ping-int        	10 _is_default; # seconds
-	sndbuf-size     	131070 _is_default; # bytes
-	ko-count        	0 _is_default;
-	after-sb-0pri   	disconnect _is_default;
-	after-sb-1pri   	disconnect _is_default;
-	after-sb-2pri   	disconnect _is_default;
-	rr-conflict     	disconnect _is_default;
-	ping-timeout    	5 _is_default; # 1/10 seconds
-}
-syncer {
-	rate            	250k _is_default; # bytes/second
-	after           	-1 _is_default;
-	al-extents      	127 _is_default;
-}
-protocol C;
-_this_host {
-	device			"/dev/drbd59";
-	address			192.168.1.1:11002;
-}
-_remote_host {
-	address			192.168.1.2:11002;
-}
diff --git a/test/ganeti.bdev_unittest.py b/test/ganeti.bdev_unittest.py
index 19e1b8a..1e44605 100755
--- a/test/ganeti.bdev_unittest.py
+++ b/test/ganeti.bdev_unittest.py
@@ -62,9 +62,9 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
     """Test drbdsetup show parser creation"""
     bdev.DRBD8._GetShowParser()
 
-  def testParserBoth80(self):
-    """Test drbdsetup show parser for disk and network"""
-    data = self._ReadTestData("bdev-both.txt")
+  def testParser80(self):
+    """Test drbdsetup show parser for disk and network version 8.0"""
+    data = self._ReadTestData("bdev-drbd-8.0.txt")
     result = bdev.DRBD8._GetDevInfo(data)
     self.failUnless(self._has_disk(result, "/dev/xenvg/test.data",
                                    "/dev/xenvg/test.meta"),
@@ -73,20 +73,20 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
                                   ("192.168.1.2", 11000)),
                     "Wrong network info (8.0.x)")
 
-  def testParserBoth83(self):
-    """Test drbdsetup show parser for disk and network"""
-    data = self._ReadTestData("bdev-8.3-both.txt")
+  def testParser83(self):
+    """Test drbdsetup show parser for disk and network version 8.3"""
+    data = self._ReadTestData("bdev-drbd-8.3.txt")
     result = bdev.DRBD8._GetDevInfo(data)
     self.failUnless(self._has_disk(result, "/dev/xenvg/test.data",
                                    "/dev/xenvg/test.meta"),
                     "Wrong local disk info")
     self.failUnless(self._has_net(result, ("192.168.1.1", 11000),
                                   ("192.168.1.2", 11000)),
-                    "Wrong network info (8.2.x)")
+                    "Wrong network info (8.0.x)")
 
-  def testParserNet(self):
-    """Test drbdsetup show parser for disk and network"""
-    data = self._ReadTestData("bdev-net.txt")
+  def testParserNetIP4(self):
+    """Test drbdsetup show parser for IPv4 network"""
+    data = self._ReadTestData("bdev-drbd-net-ip4.txt")
     result = bdev.DRBD8._GetDevInfo(data)
     self.failUnless(("local_dev" not in result and
                      "meta_dev" not in result and
@@ -94,11 +94,23 @@ class TestDRBD8Runner(testutils.GanetiTestCase):
                     "Should not find local disk info")
     self.failUnless(self._has_net(result, ("192.168.1.1", 11002),
                                   ("192.168.1.2", 11002)),
-                    "Wrong network info")
+                    "Wrong network info (IPv4)")
+
+  def testParserNetIP6(self):
+    """Test drbdsetup show parser for IPv6 network"""
+    data = self._ReadTestData("bdev-drbd-net-ip6.txt")
+    result = bdev.DRBD8._GetDevInfo(data)
+    self.failUnless(("local_dev" not in result and
+                     "meta_dev" not in result and
+                     "meta_index" not in result),
+                    "Should not find local disk info")
+    self.failUnless(self._has_net(result, ("2001:db8:65::1", 11048),
+                                  ("2001:db8:66::1", 11048)),
+                    "Wrong network info (IPv6)")
 
   def testParserDisk(self):
-    """Test drbdsetup show parser for disk and network"""
-    data = self._ReadTestData("bdev-disk.txt")
+    """Test drbdsetup show parser for disk"""
+    data = self._ReadTestData("bdev-drbd-disk.txt")
     result = bdev.DRBD8._GetDevInfo(data)
     self.failUnless(self._has_disk(result, "/dev/xenvg/test.data",
                                    "/dev/xenvg/test.meta"),
