BSP - Beratung, Schulung, Projekte


Windows and OS/390 connectivity

When you installed Hercules on your Windows machine, you did not get quite the functionality as when you had used a Linux platform. Well, you probably had your reasons... One of the things Hercules is missing on a Windows platform but what it does have in the Linux world is full network capabilities. Because of this you are able to start OS/390 under Hercules on your Windows workstation, and you will be able to use the Hercules telnet server to connect a local terminal to OS/390, but you will not be able to connect directly to the telnet server on OS/390, or to use ftp from your workstation to the TCP/IP stack on OS/390.

If you had used Linux, this would not have been a problem, because by using a tunneling device it is possible to connect to the OS/390 TCP/IP stack

Are we going to scratch all our Windows stuff now and convert to Linux? Surely not. What we need is a routing facility, which we will present in this article. With other words, it can be done

With a little help from your friends

This friend will be a separate computer in your network, running Linux. It doesn't have to be the most powerful PC in the world, I used a 266 MHz Pentium II machine with 128MB of RAM, and that was decidedly overkill. Rummage around in your closet for an old PC, and get some recent (or was that decent?) Linux distribution. Install Linux and make sure that you can connect to your Windows platform (using, e.g., ping). If you are using Linux 2.4, you are nearly set, because everything we need is already included in the kernel. Ofcourse, it isn't as easy as you might think. Someone, in his infnite wisdom and benevolence, decided to change the rules, at least for SuSE 7.2 and SuSE 7.3. Take a look at the documentation in /usr/src/linux/Documentation/networking/tuntap.txt which describes the basic differences between the tun/tap device installation in the 2.2 kernel and the newer system.

Well, I found out that Linux = Linux is not always quite true. The procedure for getting the tun/tap device on Redhat 7.1 is again somewhat different, and is described in Redhat 7.2 tun/tap installation

If on the other hand, you are using Linux 2.2, you will need to add the universal TUN/TAP driver. This is really not difficult, even I managed to do it, and it worked on the first try!

Installing the universal TUN/TAP device

One thing should be noted. I am by no means an expert in Linux (I know just enough to cause considerable harm), and to avoid any permission problems, I logged on as "root" before doing the installation. This may not be required, but it does work!

Here is what you need to do:

  1. Download the driver sources from http://vtun.sourceforge.net/tun. When I went to that site, there were two versions available, and I chose the file tun-1.1.tar.gz
  2. tar xvzf tun-1.0.tar.gz
  3. cd tun-1.1
  4. ./configure
  5. make
  6. If you didn't log on as 'root', you now need to enter
    su
    and, when prompted, the root password
  7. make install
  8. chgrp hercgrp /dev/tun*
    where hercgrp is the group under which you run Hercules
  9. chmod g+w /dev/tun*
  10. chmod o-r /dev/tun*
  11. edit the file /etc/conf.modules and add the following line:
    alias char-major-90 tun
    This causes the TUN/TAP driver to be loaded automatically when the /dev/tun device is opened

Enabling IP forwarding

You must setup your Linux system to be able to act as a router: Popular Linux distributions usually have a configuration option to enable routing or IP forwarding as it is called:

RedHat Linux
specify net.ipv4.ip_forward=1 in the /etc/sysctl.conf file.
SuSE
specify IP_FORWARD="yes" in the /etc/rc.config file.
Debian
specify ip_forward=yes in the /etc/network/options file.
Other
echo "1" > /proc/sys/net/ipv4/ip_forward
Okay, the preliminary actions are done, we can now proceed to

The Namespace

We are going to wade knee-deep in definitions of ports, addresses, whatever, and in order to make recognizing the various entities somewhat easier, I decided to set up certain rules and conventions for this article. Of course you are in no way bound by these conventions, they are just there to make my life easier:

Workstations

Guest OS running under Hercules

There can be different Operating Systems running under Hercules. Each OS needs its own IP address (and its own network). For this article we use 192.168.1#n.xxx where "n" is the OS sequence number (0 or greater) and "#" is the OS type

For the tunnel devices we use a "transport net" of 192.168.99.xxx

Ranges of CTC addresses

CTCs are needed in pairs, and will be assigned to a specific Guest OS in order to be able to easily identify the connecting Guest on the routing L390. We decide on a range of 0#20 - 0#27, 0#40 - 0#47, where # again is depending on the OS type :

Build the Connection

There are several places where we need to do some work. Let us start with the main reason for all of this, OS/390

Connecting OS/390 to another S/390 OS

OS/390 connects to the outside network world via a device called a "Channel-to-Channel-Adapter" (or CTCA for short). Actually, what we need is a pair of CTCA with adjacent address numbers, starting on an even address. According to our namespace rules we select the pair E46/E47, the highest possible pair in the standard name space. The IP address of the OS/390 system would be 192.168.100.1

This information needs now to be presented to OS/390. This is done in the TCPIP's stack profile dataset. I am assuming here a standard setup, which means that the file is called TCPIP.PROFILE.TCPIP. In your environment you might have a different high level qualifier or a different file name altogether. TCPIP should not be active when you edit this dataset. Add the following lines (the lines starting with a semi-colon are comments and can be ignored):


; +-------------------------------------------+
; !                                           !
; ! The DEVICE and LINK statements describe   !
; ! a connection to the outside world         !
; !                                           !
; +-------------------------------------------+
;
;      +--------------------- name of device
;      !        +------------ this is a CTC adapter
;      !        !    +------- even address of CTC pair
;      !        !    !   +--- restart device after failure
;      !        !    !   !
;      !        !    !   !
DEVICE CTCTL390 CTC  E46 AUTORESTART
LINK   LINKL390 CTC  1   CTCTL390
;      !        !    !   !
;      !        !    !   +--- associated device name
;      !        !    +------- 0 = even address used for reading
;      !        !    !        1 = odd address used for reading
;      !        +------------ Link across a CTC
;      +--------------------- Name of link

This is not the only change to the PROFILE dataset. Scroll down a bit until you find the HOME statement. Replace it or add


;      +--------------------- This is our IP address
;      !                 +--- For traffic on this link
;      !                 !
HOME   192.168.100.1     LINKL390
PRIMARYINTERFACE LINKL390
GATEWAY
;
; Describe the path to the Linux390 system
;
; +------------------------------- IP address of partner on
; !             +----------------- other end of this link
; !             !        +-------- 1500 bytes of data
; !             !        !    +--- This is a host
; !             !        !    !
192.168.160.1 = LINKL390 1500 HOST
;
; Anything we don't know get's routed to Linux390 system
DEFAULTNET 192.168.160.1 LINKL390 1500 0

Rather at the bottom of the PROFILE dataset you add


START CTCTL390

to start the device when TCPIP gets started.

Now you might want to update TCPIP.HOST.LOCAL and add the following entries


;      +--------------------------------------- full IP address
;      !               +----------------------- full qualified name
;      !               !                   +--- nickname(s)
;      !               !                   !
HOST : 192.168.100.1 : mvs0.mycompany.com, mvs0 ::::
HOST : 192.168.160.1 : L390c1.mycompany.com, L390c1 L390 ::::

The host and domain name of this system (MVS0) should agree with the info in TCPIP.TCPIP.DATA


; HOSTNAME specifies the TCP host name of this system.  If not
; specified, the default is the name defined in the EZAZSSI proc in
; SYS1.PROCLIB.
HOSTNAME MVS0
;
; DOMAINORIGIN specifies the domain origin that will be appended
; to host names passed to the resolver.  If a host name contains
; any dots, then the DOMAINORIGIN will not be appended to the
; host name.
DOMAINORIGIN MYCOMPANY.COM

Check member TCPIP.TCPPARMS(TCPDATA) as well, as it contains similar (and additional) information. Now change to ISPF option 6 (TSO Command Shell) and issue the command makesite hlq=tcpip to build the local TCPIP control datasets.

Connecting Linux/390 to another S/390 OS

Any Operating system running as a guest under Hercules should be able to be used as a router system. I tried it with OS/390, which definitely is overkill, but it does work. Richard Higson and I set out to do the same using Linux/390 as the guest, and this does work as well. Let's talk about the Linux/390 solution here. Why? Well, IPLing OS/390 2.9 on a Thinkpad with a 266MHz processor might easily take an hour, while IPLing Linunx/390 is done in a coupe of minutes! Is that an argument; Or isn't it? Also, you will only need about 55 MB of hard disk space for the Linux/390 system, while an OS/390 system might need 1.5 GB or more...

Linux/390 will also need CTC adapters to communicate with the outside world. Fortunately, we do not have to generate them anywhere, they will be recognized automatically if present. Which CTC adapters will we need? Well, an even/odd address pair again for each system that wnats to use us as a router. What lies closer than using the same addresses as the systems that want to connect?

In Linux/390 we have to make the appropriate definitions in the network setup. You might use YAST when using SUSE Linux/390, or the command


ifconfig ctc1 192.168.160.1 pointopoint 192.168.100.1 mtu 1500

If you are using Debian Linux/390 (the one that is available for download here), the easiest way (probably) is to update the file /etc/network/interfaces and add the lines


iface ctc1 inet static
   address 192.168.160.1
   pointopoint 192.168.100.1
   netmask 255.255.255.255
   up ifconfig ctc1 mtu 1500

Why did we use ctc1 and not ctc0 in the above commands? Well, you will see later

The picture so far...

MVS and Linux/390 are now happily connected to each other. Or are they? Did you buy a few 3088 devices? And did you hook them up to your PCs? Probably you didn't! And you don't need to, either. Hercules will quite happily provide you with all the (virtual) CTC adapters you will ever need. The CTC adapters will be defined in your Hercules configuration file. The emulated CTC adapters will be using the TCP/IP protocol (that's why they will be called CTCT in the Hercules configuration). Taking part in the TCP/IP world means that the CTCT needs to listen to incoming data on a so-called "port". Any port number can be selected by you, as long as you don't use a so-called "well-known" port or any of the reserved port numbers < 1024. We try to keep the port number > 10000, and also try to achieve a nice mapping of CTC address to port number:

     CTC                                Port
     Address                            number
     0CUU                               xx0UU
      !!                                !  !
      !+--- unit address                !  +--- unit address
      +---- Channel number              +------ channel number in decimal

      0E46         therefore maps to    14046
      0A24                              10024

To set up the CTC devices, add the following lines to the Hercules configuration file on Wxxx:


# CTC to Hercules guest on Lzzz, via CTC at 0E46
#               +-------------------- Listening port on this end
#               !     +-------------- Name (or IP address) at other end
#               !     !    +--------- Listening port on Lzzz end
#               !     !    !     +--- Transport size, > mtu
#               !     !    !     !
0E46  3088 CTCT 14046 Lzzz 14046 2000
# CTC from Hercules guest on Lzzz via CTC at 0E47
0E47  3088 CTCT 14047 Lzzz 14047 2000

Alternatively, you can place the lines


attach 0E46  3088 CTCT 14046 Lzzz 14046 2000
attach 0E47  3088 CTCT 14047 Lzzz 14047 2000
panrate 1000
panrate fast

into the resource file hercules.rc. This has the advantage that the CTCs are opened after all the dasd image files, and that you see any error messages that might crop up during open. (The two "panrate" commands are there just to slow down the message display for long enough to allow you to read the messages.) You will have to provide similar information on the Lzzz side of the connection as well. With other words, either add the following lines to Hercules.cfg on Lzzz:


# CTC from Hercules guest on Wxxx, via CTC at 0E46
0E46  3088 CTCT 14046 Lzzz 14046 2000
# CTC to Hercules guest on Wxxx via CTC at 0E47
0E47  3088 CTCT 14047 Lzzz 14047 2000

or provide these commands in hercules.rc on Lzzz:


attach 0E46  3088 CTCT 14046 Lzzz 14046 2000
attach 0E47  3088 CTCT 14047 Lzzz 14047 2000
panrate 1000
panrate fast

This is no typo. The parameters and ports are identical because of the choice of the namespace. We get the following:

Note that the CTCs and port numbers do not have to be identical, the following setup is also possible, altough not necessarily feasible:

Looking at the above picture, we seem to be all set. But one crucial element is still missing: How to we get from the Hercules guest on Lzzz to our LAN? Well, we will use the tunnel device that we installed earlier. The tunnel device looks like a CTC adapter to the Hercules guest, and like a character device on the Lzzz end of the tunnel. We will need a CTC definition in L390 for the tunnel:

Again, you might use YAST when using SUSE Linux/390, or the command


ifconfig ctc0 192.168.99.2 pointopoint 192.168.99.1 mtu 1500

If you are using Debian Linux/390 (the one that is available for download here), the easiest way (probably) is to update the file /etc/network/interfaces and add the lines


iface ctc0 inet static
   address 192.168.99.2
   pointopoint 192.168.99.1
   netmask 255.255.255.255
   up ifconfig ctc0 mtu 1500
   up route add default gw 192.168.99.1

The last line is new. It tells L390 that any traffic which it doesn't really know about should be sent via 192.168.99.1, which is the other end of our tunnel.

By the way, here you see the ctc0 device that we mentioned earlier

We are nearly done. The next thing to do is to define the CTC in the Hercules configuration file on Lzzz. We need a defintions which is different from the one used earlier, as we have to tell Hercules to connect one end of the CTC to the tunnel device. There is a special CTC support in Hercules just for this purpose. It is called CTCI and means CTC support via IP. To use this emulated CTC, you need to specify the name of the tunnel devide and the IP addresses of both end-points of the tunnel. Add the following lines to hercules.cnf on Lzzz:


# CTC from hercules to guest
#         +------------------------------------------------- CTC via IP
#         !    +-------------------------------------------- name of tunnel device
#         !    !         +---------------------------------- mtu size
#         !    !         !    +----------------------------- Lzzz end of tunnel
#         !    !         !    !            +---------------- L390 end of tunnel
#         !    !         !    !            !            +--- netmask
#         !    !         !    !            !            !
0E00 3088 CTCI /dev/tun0 1500 192.168.99.1 192.168.99.2 255.255.255.0
# CTC from guest to hercules
0E01 3088 CTCI /dev/tun0 1500 192.168.99.1 192.168.99.2 255.255.255.0

When hercules gets initialised, a special program (hercifc) will be run automagically to configure the tun device to Linux

The Full Picture

Starting up Hercules

We need to have both hercules systes up and running, and theire CTCs connected to each other, before we can use the connection between the guest operating systems. Let's start up hercules on Wxxx first. Besides the usual clutter of messages you should now see the CTC related information



HHC892I 0E46 connect to 192.168.1.108:14046 failed, starting server
HHC892I 0E47 connect to 192.168.1.108:14047 failed, starting server

This is expected, and not an error. There is no CTC on the other end (yet), and our Hercules system is now preparing to listen to incoming data as soon as his peer CTC comes to life

Note: The IP address will most probably be different in your system

You can now start Hercules on the Lzzz platform, and should see the following messages relating to out CTCT definitions:


HHC891I 0E46 connected to 192.168.1.196:14046
HHC892I 0E47 connected to 192.168.1.196:14047

Again, the IP address will probably be different in your system. It could happen, though, that you get a message like


HHC853I 0E46 cannot bind socket: Address alread in use
HHC038I Initialization failed for device 0E46

This means that the sockets (=IP address + portnumber) are in in time-out processing from a previous run. You can verify this by issuing the command


netstat --inet -n

to which you will receive a reply similar to


Proto Recv-Q Send-Q Local Address            Foreign Address          State
tcp   0      0      192.168.1.108:14046      192.168.1.196:14046      FIN_WAIT2
tcp   0      0      192.168.1.108:14047      192.168.1.196:14047      FIN_WAIT2

You can now either reboot Lzzz, or wait a few minutes and then test the status again using the netstat command.

When both Hercules engines are successfully initialized, and their CTCTs have connected, you can now proceed to start the guest operating systems. Both may start in parallel, there is no need to serialize the startup.

When starting up TCPIP on OS/390 on Wzzz, you should see the message


 EZZ4313I INITIALIZATION COMPLETE FOR DEVICE CTCTL390

This indicated that your definitions are basically okay, and that TCPIP communication across this device is possible. Is there a similar indicator on the L390 console? Sure. Look out for



CTC driver Version: 1.29  initialized
channel: 4 Parallel channel found - 0 ESCON channel found
ctc0: read dev: 0e00 irq: 0002 - write dev: 0e01 irq: 0003
ctc1: read dev: 0e46 irq: 0004 - write dev: 0e47 irq: 0005
ctc0: connected with remote side
ctc1: connected with remote side

You can try some commands on the MVS console:



 d tcpip,,netstat,devlinks
 EZZ2500I NETSTAT CS V2R8 TCPIP 397

     DEVNAME: CTCTL390          DEVTYPE: CTC       DEVNUM: 0E46
     DEVSTATUS: READY
     LNKNAME: LINKL390          LNKTYPE: CTC         LNKSTATUS: READY
       NETNUM: 1   QUESIZE: 0   BYTEIN: 0000000540   BYTEOUT: 0000000540
     BSD ROUTING PARAMETERS:
       MTU SIZE: 00000             METRIC: 00
       DESTADDR: 192.168.160.1     SUBNETMASK: 255.255.255.255
     MULTICAST SPECIFIC:
       MULTICAST CAPABILITY: YES
       GROUP             REFCNT
       -----             ------
       224.0.0.1         0000000001

d tcpip,,netstat,route
EZZ2500I NETSTAT CS V2R8 TCPIP 403
 00  DESTINATION      GATEWAY          FLAGS  REFCNT  INTERFACE
     DEFAULTNET       192.168.160.1    UG     000000  LINKL390
     192.168.160.1    0.0.0.0          UH     000000  LINKL390

And similarly on the L390 console:



ifconfig

ctc0      Link encap:Serial Line IP
          inet addr:192.168.99.2  P-t-P:192.168.99.1
          Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

ctc1      Link encap:Serial Line IP
          inet addr:192.168.160.1  P-t-P:192.168.100.1
          Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP  MTU:1500  Metric:1
          RX packets:6 errors:0 dropped:0 overruns:0 frame:0
          TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100
          RX bytes:0 (0.0 b)  TX bytes:0 (0.0 b)

netstat -rn

Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
192.168.100.1   0.0.0.0         255.255.255.255 UH        0 0          0 ctc1
192.168.99.1    0.0.0.0         255.255.255.255 UH        0 0          0 ctc0
0.0.0.0         192.168.99.1    0.0.0.0         UG        0 0          0 ctc0

Finally, you can issue a command on the Lzzz console:



ifconfig

tun0 Link encap:Point-to-Point Protocol
     inet addr:192.168.99.1  P-t-P:192.168.99.2
     Mask:255.255.255.255
     UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
     RX packets:0 errors:0 dropped:0 overruns:0 frame:0
     TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
     collisions:0 txqueuelen:10

route add 192.168.100.1 gw 192.168.99.1
netstat -rn

Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
192.168.100.1   192.168.99.1    255.255.255.255 UGH       0 0          0 tun0
192.168.99.2    0.0.0.0         255.255.255.255 UH        0 0          0 tun0
192.168.1.0     0.0.0.0         255.255.255.0   U         0 0          0 eth0
127.0.0.0       0.0.0.0         255.0.0.0       U         0 0          0 lo
0.0.0.0         192.168.1.254   0.0.0.0         UG        0 0          0 eth0

One little thing is left to be done: On your Windows workstations you need to add a route to your MVS like this



route -p add 192.168.100.1 mask 255.255.255.255 192.168.1.108
route -p add 192.168.160.1 mask 255.255.255.255 192.168.1.108

route -p print

===========================================================================
Schnittstellenliste
0x1 ........................... MS TCP Loopback interface
0x2 ...00 01 02 07 4c 6c ...... 3Com EtherLink PCI
===========================================================================
===========================================================================
Aktive Routen:
Netzwerk  Ziel             Netzmaske        Gateway       Schnittst. Metrik
          0.0.0.0          0.0.0.0    192.168.1.254   192.168.1.196       1
        127.0.0.0        255.0.0.0        127.0.0.1       127.0.0.1       1
      192.168.1.0    255.255.255.0    192.168.1.196   192.168.1.196       1
    192.168.1.196  255.255.255.255        127.0.0.1       127.0.0.1       1
    192.168.1.255  255.255.255.255    192.168.1.196   192.168.1.196       1
    192.168.100.1  255.255.255.255    192.168.1.108   192.168.1.196       1
    192.168.160.1  255.255.255.255    192.168.1.108   192.168.1.196       1
        224.0.0.0        224.0.0.0    192.168.1.196   192.168.1.196       1
  255.255.255.255  255.255.255.255    192.168.1.196   192.168.1.196       1
===========================================================================

Stšndige Routen:
  Netzwerkadresse          Netzmaske  Gateway-Adresse  Anzahl
    192.168.100.1  255.255.255.255    192.168.1.108       1
    192.168.160.1  255.255.255.255    192.168.1.108       1

Setting up OS/390 as a router

Of course, you could have placed an OS/390 system onto the Lzzz workstation as well.

The entries in TCPIP.PROFILE.TCPIP on MVS0 would than have to be


DEVICE CTCTMVS1 CTC  E46 AUTORESTART
LINK   LINKMVS1 CTC  1   CTCTMVS1
HOME   192.168.100.1     LINKMVS1
PRIMARYINTERFACE LINKMVS1
GATEWAY
192.168.101.1 = LINKMVS1 1500 HOST
;
; Anything we don't know get's routed to Linux390 system
DEFAULTNET 192.168.101.1 LINKMVS1 1500 0
START CTCTMVS1

whereas the entries in TCPIP.PROFILE.TCPIP on MVS1 would have to be


DEVICE CTCTMVS0 CTC  E46 AUTORESTART
;                    +--- Note the 0 here.  It specifies that channel
;                    !    E46 is to be used for reading, and E47
;                    !    for writing
;                    !
LINK   LINKMVS0 CTC  0   CTCTMVS0
DEVICE CTCITUN0    CTC      E44   AUTORESTART
LINK   LINKTUN0    CTC      0     CTCITUN0

HOME
192.168.101.1     LINKMVS0
192.168.99.2      LINKTUN0
PRIMARYINTERFACE LINKMVS0
GATEWAY
192.168.100.1 = LINKMVS0 1500 HOST
192.168.99.1  = LINKTUN0 1500 HOST
START CTCTMVS0
START CTCITUN0

If you have questions, remarks, contributions, whatever, drop me a line.

Enjoy your private Hercules mainframe




© BSP Beratung, Schulung, Projekte GmbH