SCAN-Listener and NAT

Network Address Translation (NAT) and SCAN listener are not working out of the box, because the scan redirect to the local_listener value, usually a IP and not a DNS name. failed

DNS name Clinet entry Server enrty
scan.mydomain 192.168.1.20 10.0.0.20
rac1-vip.mydomain 192.168.1.21 10.0.0.21
rac2-vip.mydomain 192.168.1.22 10.0.0.22

If you’re using admin managed database, the solution is quiet easy. Set the local listener parameter on each instance from an IP  to a DNS name. In case of policy managed databases it’s not. Per default the cluster automatically set the parameter always to  IP and the instance could move from one host to an other, therefore you can’t set the local listener parameter to a fixed value. But there is a other solution! Set the local listener parameter to a tns alias and resolve the tns alias to different DNS names on each host. Please ensure that your TNS_ADMIN is set to a local not shared filesystem.

SQL>show spparameter local_listener

SID NAME TYPE VALUE
-------- ----------------------------- ----------- ----------------------------
* local_listener string nodevip
SQL> !cat $TNS_ADMIN/tnsnames.ora
NODEVIP.world = 
 (DESCRIPTION = (ADDRESS_LIST=
 (ADDRESS = (PROTOCOL= TCP)(Host=rac1-vip.internal.unicreditgroup.eu)(Port= 1521))
 ) )

on the second Instance:

SQL> !cat $TNS_ADMIN/tnsnames.ora
NODEVIP.world = 
 (DESCRIPTION = (ADDRESS_LIST=
 (ADDRESS = (PROTOCOL= TCP)(Host=rac2-vip.internal.unicreditgroup.eu)(Port= 1521))
 ) )

Now it works:

working

A little bit more in detail, the instance register on the remote listener(s) with the information where it could reached, described in the value of local_listener and the scan listener takes this value into it’s redirect. You can check with tcpdump or oracle net trace. The first package is the request to the scan listener and second the redirect. After the @ is the redirect described and after the . ist the connect data included the listener your coming from. The important part is marked bold. If it’s still an ip its wrong it should be a dns name.  I deleted the dots and replaced the names and ports for the readability.

$ sudo tcpdump -i bond0 -A ip host <IP scan1>
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on bond0, link-type EN10MB (Ethernet), capture size 65535 bytes
23:02:27.816931 IP client > scan: 
...(DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=testdb1)
(CID=(PROGRAM=sqlplus)(HOST=client)(USER=oracle)))
(ADDRESS=(PROTOCOL=TCP)(HOST=<IP scan1>)(PORT=1521)))
23:02:27.817176 IP scan > client: 
...@(ADDRESS=(PROTOCOL=TCP)(HOST=scan.mydomain)(PORT=1521)).
(DESCRIPTION=(CONNECT_DATA=(SERVICE_NAME=testdb1)
(CID=(PROGRAM=sqlplus)(HOST=client)(USER=oracle))
(SERVER=dedicated)(INSTANCE_NAME=testdb1_1))
(ADDRESS=(PROTOCOL=TCP)(HOST=<IP scan1>)(PORT=1521)))
12 packets captured
12 packets received by filter
0 packets dropped by kernel

With 12c are several scan listener are supported which could be configured with the parameter listener_networks. The primary network is still configured with the parameter local and remote_listener. For the other networks use listener networks.
A really simple example:

(
(NAME=net2)
(REMOTE_LISTENER=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=scan2)(PORT=1521))))
(LOCAL_LISTENER=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=rac1-vip2)(PORT=1521))))
)

The solution and behavior is the same, also if it’s not described here.
Be careful .. the parameter is limited to 255 characters. If it’s not enough you can use tns aliases 😉

ORA-32021: parameter value longer than 255 characters
Advertisements