Blob Blame History Raw
From bc1ad5fdcdff10be1c87364413d13cd47f76f4ea Mon Sep 17 00:00:00 2001
From: Oliver Kurz <okurz@suse.de>
Date: Sun, 12 Jul 2020 21:17:41 +0200
Subject: [PATCH] Make local VM host IPs '10.0.2.2' configurable

Related progress issue: https://progress.opensuse.org/issues/68851
---
 doc/backend_vars.asciidoc |  1 +
 doc/networking.md         | 20 +++++++++++++-------
 os-autoinst-openvswitch   | 28 +++++++++++++++++-----------
 t/03-testapi.t            |  2 ++
 testapi.pm                |  4 ++--
 5 files changed, 35 insertions(+), 20 deletions(-)

diff --git a/doc/backend_vars.asciidoc b/doc/backend_vars.asciidoc
index db6fe323..0eabe0c7 100644
--- a/doc/backend_vars.asciidoc
+++ b/doc/backend_vars.asciidoc
@@ -107,6 +107,7 @@ QEMUVGA;see qemu -device ?;cirrus;VGA device to use with VM
 QEMU_COMPRESS_QCOW2;boolean;1;compress qcow2 images intended for upload
 QEMU_IMG_CREATE_TRIES;integer;3;Define number of tries for qemu-img commands
 QEMU_HUGE_PAGES_PATH;string;undef;Define a path to use huge pages (e.g. /dev/hugepages/)
+QEMU_HOST_IP;string;10.0.2.2;The VM host IP used in usermode networking. Set `NICTYPE=user` and NICTYPE_USER_OPTIONS accordingly to match following https://wiki.qemu.org/Documentation/Networking#User_Networking_.28SLIRP.29
 QEMU_MAX_MIGRATION_TIME;integer;240;Maximum time in seconds a migration to file may take for example for snapshot creation before being forcefully aborted.
 QEMU_NO_FDC_SET;boolean;0;Don't disable the floppy drive.
 QEMU_NO_KVM;boolean;0;Don't use KVM acceleration.
diff --git a/doc/networking.md b/doc/networking.md
index fcc332d0..0a123586 100644
--- a/doc/networking.md
+++ b/doc/networking.md
@@ -13,13 +13,19 @@ limitation - only TCP and UDP are supported. However no additional configuration
 If options for "user" mode are required, they can be set in NICTYPE_USER_OPTIONS variable.
 
 ## TAP device support
-When advanced configurations, routing or better performance is required, NICTYPE can be set to
-"tap". In this case, preconfigured TAP device on host system is used as VM network device.
-Which TAP device is used depends on TAPDEV variable which is automatically set to "tap" + worker id - 1,
-i.e. worker1 uses tap0, worker 6 uses tap5. This mode requires the system administrator to create
-a TAP device for each running worker and to manually prepare any routing or bridging before "tap"
-networking can be used. TAP devices need to be created with proper permissions so VMs can access
-them, e.g. "tunctl -u _openqa-worker -p -t tap0".
+
+When advanced configurations, routing or better performance is required,
+NICTYPE can be set to "tap". In this case, preconfigured TAP device on host
+system is used as VM network device.  Which TAP device is used depends on
+TAPDEV variable which is automatically set to "tap" + worker id - 1, i.e.
+worker1 uses tap0, worker 6 uses tap5. This mode requires the system
+administrator to create a TAP device for each running worker and to manually
+prepare any routing or bridging before "tap" networking can be used. TAP
+devices need to be created with proper permissions so VMs can access them,
+e.g. "tunctl -u _openqa-worker -p -t tap0".
+
+Some configuration can also be configured by environment variables as defined
+in the script `os-autoinst-openvswitch`.
 
 ## Multiple network devices
 To create multiple network devices, one can set multiple, comma-separated MAC addresses
diff --git a/os-autoinst-openvswitch b/os-autoinst-openvswitch
index f7f98762..d251e802 100755
--- a/os-autoinst-openvswitch
+++ b/os-autoinst-openvswitch
@@ -41,16 +41,22 @@ sub init_switch {
     die "can't parse bridge local port MAC" unless $self->{MAC};
     die "can't parse bridge local port IP"  unless $self->{IP};
 
+    my $local_ip = $ENV{OS_AUTOINST_BRIDGE_LOCAL_IP} // '10.0.2.2';
+    my $netmask = $ENV{OS_AUTOINST_BRIDGE_NETMASK} // 15;
+    my $rewrite_target = $ENV{OS_AUTOINST_BRIDGE_REWRITE_TARGET} // '10.1.0.0';
+    # we also need a hex-converted form of the rewrite target, thanks
+    # https://www.perlmonks.org/?node_id=704295
+    my $rewrite_target_hex = unpack('H*', pack('C*', split ('\.', $rewrite_target)));
 
     # the VM have unique MAC that differs in the last 16 bits (see /usr/lib/os-autoinst/backend/qemu.pm)
     # the IP can conflict across vlans
-    # to allow connection from VM  to host os-autoinst (10.0.2.2), we have to do some IP translation
-    # we use simple scheme:
+    # to allow connection from VM  to host os-autoinst ($local_ip), we have to do some IP translation
+    # we use simple scheme, e.g.:
     # MAC 52:54:00:12:XX:YY -> IP 10.1.XX.YY
 
-    # br0 has IP 10.0.2.2 and netmask /15 that covers 10.0.0.0 and 10.1.0.0 ranges
+    # br0 has IP $local_ip and netmask $netmask. E.g. '/15' covers 10.0.2.2 and 10.1.0.0 ranges
     # this should be also configured permanently in /etc/sysconfig/network
-    die "bridge local port IP is expected to be 10.0.2.2/15" unless $self->{IP} eq '10.0.2.2/15';
+    die "bridge local port IP is expected to be $local_ip/$netmask" unless $self->{IP} eq "$local_ip/$netmask";
 
     # openflow rules don't survive reboot so they must be installed on each startup
     for my $rule (
@@ -64,23 +70,23 @@ sub init_switch {
         # reply packets from local port are handled by learned rules in table 1
         'table=0,priority=1,in_port=LOCAL,actions=resubmit(,1)',
 
-        # arp 10.0.2.2 - learn rule for handling replies, rewrite ARP sender IP to 10.1.x.x range and send to local
+        # arp e.g. 10.0.2.2 - learn rule for handling replies, rewrite ARP sender IP to e.g. 10.1.x.x range and send to local
         # the learned rule rewrites ARP target to the original IP and sends the packet to the original port
-        'table=0,priority=100,dl_type=0x0806,nw_dst=10.0.2.2,actions=' .                                                                                                   #
+        "table=0,priority=100,dl_type=0x0806,nw_dst=$local_ip,actions=" .                                                                                                  #
         'learn(table=1,priority=100,in_port=LOCAL,dl_type=0x0806,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],output:NXM_OF_IN_PORT[]),' .    #
-        'load:0xa010000->NXM_OF_ARP_SPA[],move:NXM_OF_ETH_SRC[0..15]->NXM_OF_ARP_SPA[0..15],' .                                                                            #
+        "load:0x$rewrite_target_hex->NXM_OF_ARP_SPA[],move:NXM_OF_ETH_SRC[0..$netmask]->NXM_OF_ARP_SPA[0..$netmask]," .                                                                #
         'local',
 
-        # tcp to $self->{MAC} syn - learn rule for handling replies, rewrite source IP to 10.1.x.x range and send to local
+        # tcp to $self->{MAC} syn - learn rule for handling replies, rewrite source IP to e.g. 10.1.x.x range and send to local
         # the learned rule rewrites DST to the original IP and sends the packet to the original port
         "table=0,priority=100,dl_type=0x0800,tcp_flags=+syn-ack,dl_dst=$self->{MAC},actions=" .                                                                          #
         'learn(table=1,priority=100,in_port=LOCAL,dl_type=0x0800,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IP_SRC[]->NXM_OF_IP_DST[],output:NXM_OF_IN_PORT[]),' .    #
-        'mod_nw_src:10.1.0.0,move:NXM_OF_ETH_SRC[0..15]->NXM_OF_IP_SRC[0..15],' .                                                                                        #
+        "mod_nw_src:$rewrite_target,move:NXM_OF_ETH_SRC[0..$netmask]->NXM_OF_IP_SRC[0..$netmask]," .                                                                            #
         'local',
 
-        # tcp to $self->{MAC} other - rewrite source IP to 10.1.x.x range and send to local
+        # tcp to $self->{MAC} other - rewrite source IP to e.g. 10.1.x.x range and send to local
         "table=0,priority=99,dl_type=0x0800,dl_dst=$self->{MAC},actions=" .                                                                                              #
-        'mod_nw_src:10.1.0.0,move:NXM_OF_ETH_SRC[0..15]->NXM_OF_IP_SRC[0..15],local',
+        "mod_nw_src:$rewrite_target,move:NXM_OF_ETH_SRC[0..$netmask]->NXM_OF_IP_SRC[0..$netmask],local",
       )
     {
         system('ovs-ofctl', 'add-flow', $self->{BRIDGE}, $rule);
diff --git a/t/03-testapi.t b/t/03-testapi.t
index 205c5098..d53aa125 100755
--- a/t/03-testapi.t
+++ b/t/03-testapi.t
@@ -677,6 +677,8 @@ subtest 'autoinst_url' => sub {
     is(autoinst_url('foo'), 'http://my_worker_host:1/foo', 'autoinst_url returns reasonable URL based on WORKER_HOSTNAME');
     $bmwqemu::vars{BACKEND} = 'qemu';
     is(autoinst_url('foo'), 'http://10.0.2.2:1/foo', 'autoinst_url returns static IP for qemu');
+    $bmwqemu::vars{QEMU_HOST_IP} = '192.168.42.1';
+    is(autoinst_url('foo'), 'http://192.168.42.1:1/foo', 'autoinst_url returns configured static IP');
     $bmwqemu::vars{AUTOINST_URL_HOSTNAME} = 'localhost';
     is(autoinst_url('foo'), 'http://localhost:1/foo', 'we can configure the hostname that autoinst_url returns');
 };
diff --git a/testapi.pm b/testapi.pm
index c7551650..ed94bd58 100755
--- a/testapi.pm
+++ b/testapi.pm
@@ -2012,10 +2012,10 @@ sub diag {
 =for stopwords kvm VM
 
     Return VM's host IP
-    in a kvm instance you reach the VM's host under 10.0.2.2
+    in a kvm instance you reach the VM's host under default 10.0.2.2
 =cut
 sub host_ip {
-    return check_var('BACKEND', 'qemu') ? '10.0.2.2' : get_required_var('WORKER_HOSTNAME');
+    return check_var('BACKEND', 'qemu') ? get_var('QEMU_HOST_IP', '10.0.2.2') : get_required_var('WORKER_HOSTNAME');
 }
 
 =head2 autoinst_url
-- 
2.28.0.rc1