Per-subnet routing with Solaris 10 non-global zones

I had the chance to finally tinker with Solaris 10 zones the other day. They are impressive - very easy to setup! One of my biggest gripes about Solaris is that they've fallen way behind in the area of advanced IP routing. If you want to do things like policy routing in Solaris, you have to install ipfilter, which is no easy task. There is no alternative to iproute2 in Linux. Read after the jump to find a quick hack to setup proper routing for non-global zones on multiple subnets.

Update: If you are using Solaris 10 Update 4 or newer, you may be able to use set ip-type=exclusive in your zone config. This will give you what I've hacked together here. Note, that you must have a dedicated interface for the zone in order to use it, and there are some other limitations, described here. Keep an eye on project Crossbow, which will hopefully make all of this go away.

In Solaris 10, you set the default gateway at boot time by using /etc/defaultrouter. You can add multiple default routes by adding multiple lines to that file. However, if you do that, the kernel will simply round-robin the packets between the gateways, which will light up any firewall like a Christmas tree.

Imagine the following scenario:

HostA is a Solaris 10 box with 4 bge interfaces. HostA's IP address is 192.168.20.2/24 and is assigned to bge0. The router for the 192.168.20.0/24 subnet is at 192.168.20.1.

HostB is a non-global zone residing on HostA, with an IP address of 192.168.30.2/24 and you've assigned it to bge1 via zonecfg. The router for the 192.168.30.0/24 subnet is at 192.168.30.1.

Now, non-global zones don't have their own kernel, they "share" with the global zone. IP routing is handled in the kernel, so the routing configuration for the non-global zone needs to be done in the global zone.

The first trick here is to get bge1 to come up on bootup, but not assign it an IP. Do this as root on HostA to establish that:

# echo "0.0.0.0" > /etc/hostname.bge1

This will plumb and bring up the interface, but it will not be assigned an IP. Now, remember what I said about the kernel round-robin routing packets earlier? It will only do that if both gateways are reachable. So, the trick is to make HostB's gateway unreachable from HostA, and HostA's gateway unreachable from HostB. There's a catch-22 here as well, you can only add a default route if the gateway is currently reachable. So how in the world do we get this to work???

With some nice hackery, of course! First, set HostB's configuration so that it does not boot automatically. Don't worry if you need this functionality, we've got a hack for that too:

root@HostA # zonecfg -z HostB
zonecfg:HostB> set autoboot=false
zonecfg:HostB> verify
zonecfg:HostB> commit
zonecfg:HostB> exit

Now, we are going to create our own init script that will bring up bge1 temporarily with HostB's IP, set the default route, then remove that IP. By using HostB's IP, we are allowed to set the route, but when we remove the interface, HostB's gateway becomes unreachable from HostA. Finally, we boot HostB, which sees only the default route for it's interface. Let's setup that init script:

# cat <<EOD > /etc/init.d/zoneboot
#!/usr/bin/sh

/usr/sbin/ifconfig bge1 addif 192.168.30.2/24 up
/usr/sbin/route add default 192.168.30.1
/usr/sbin/ifconfig bge1 removeif 192.168.30.2
/usr/sbin/zoneadm -z HostB boot
EOD

# ln -s /etc/init.d/zoneboot /etc/rc3.d/S99zoneboot

You can of course modify this script to work with more interfaces and zones, but you get the idea. Now, reboot HostA. HostA's routing table looks like so:

# netstat -rn

Routing Table: IPv4
  Destination           Gateway           Flags  Ref     Use     Interface
-------------------- -------------------- ----- ----- ---------- ---------
default              192.168.30.1          UG       1        119
default              192.168.20.1          UG       1        112
192.168.20.2         192.168.20.2          U        1         35 bge0
224.0.0.0            192.168.20.2          U        1          0 bge0
127.0.0.1            127.0.0.1             UH       4        113 lo0

HostA has two default gateways, but only one of them is reachable. Bingo! HostB's routing table looks like this:


Routing Table: IPv4
  Destination           Gateway           Flags  Ref     Use     Interface
-------------------- -------------------- ----- ----- ---------- ---------
default              192.168.30.1           UG      1        112
192.168.30.0         192.168.30.2           U       1         27 bge1:1
224.0.0.0            192.168.30.2           U       1          0 bge1:1
127.0.0.1            127.0.0.1              UH      4        108 lo0:2

Success! Hope you found this helpful!

Your rating: None Average: 5 (3 votes)

Comments

Thanks!! I get this problem

Thanks!!
I get this problem today with two different subnets, one for global and for non-global zone and I was looking for solution. And bingo - I found your page ! Thanks !!
Not tested yet on my system as it is working as semi-production :) - still under development but some users are already working so I need to wait till Friday afternoon :(

Glad to hear it helped. I

Glad to hear it helped. I don't think you'll have much issue with it at all. It's been running for us in a lab setting since I wrote this article up, and hasn't had any issues. Let me know how it works out!

Does this issue still

Does this issue still pertain to Solaris 10- Update 4? As of update 4, non-global zones now have their own uniques and dedicated TCP/IP stack which should allow setting default routes, ipfilters, etc on a per zone basis.

Will - I honestly have no

Will - I honestly have no idea. The machines I have are all running update 3. If what you say is true, then the issue shouldn't be present. The core cause of the issue in this post is since the non-globals run under the same kernel, they share the same routing table as the global. If in update 4 each non-global can have it's own private routing table, then this workaround is likely not needed.

I'm afraid I'm kinda short on time right now, so I can't verify that - I'd love to see a post from someone saying they've tried it.

Apparently, the exclusive IP

Apparently, the exclusive IP stacks are not a generally useful solution since they require a dedicated network interface (or at least a separate VLAN) for each local zone. Here's my gripes with that:

http://opensolaris.org/jive/thread.jspa?messageID=250299&#250299

Hi My problem is similar,

Hi

My problem is similar, but different.

In my case the 2 interfaces are ge0 and bge1.

BOTH have valid, used, IPs on different subnets.

The default route in via ge0

BUT, my zone needs to be on the same subnet as bge0, byt the systems default gateway is n the other subnet/interface.

When I boot my zone, it can see stuff on the same subnet, but it cant get out.

g;obal-zone # netstat -rn

Routing Table: IPv4
Destination Gateway Flags Ref Use Interface
-------------------- -------------------- ----- ----- ---------- ---------
x.176.19.0 x.176.19.173 U 1 1983 ge1
x.176.24.0 x.176.24.147 U 1 2088 bge0
224.0.0.0 x.176.19.173 U 1 0 ge1
default x.176.19.250 UG 1 28881
127.0.0.1 127.0.0.1 UH 8 599 lo0

global-zone # ifconfig -a
lo0: flags=2001000849 mtu 8232 index 1
inet 127.0.0.1 netmask ff000000
bge0: flags=1000843 mtu 1500 index 2
inet x.176.24.147 netmask ffffff00 broadcast x.176.24.255
ge1: flags=1000843 mtu 1500 index 3
inet x.176.19.173 netmask ffffff00 broadcast x.176.19.255

My zone needs to have IP x.176.24.16.

Seems to me your hack does not help in this case? Can it be adapted?

Kevin

Just to notice that this

Just to notice that this trick works great with zones in tagged VLAN and IP multi-pathing. I've set this up on update 3.

VLAN and IPMP set up

Would you please throw more light on implementing this procedure for tagged VLANs and IPMP interfaces at all? I would like to see a working solution for the same as I have tried it and it didn't work for me. It's quite possible that I'm not doing something right.

Cheers,

Sumit.

Kevin - the above procedure

Kevin - the above procedure should work for you too if I understand correctly.

Do you have a router on the x.176.24.x subnet? If so, then just use the example I give above, but use your ge0 for bge0 and your bge0 for bge1. With IP's set like that, I'm guessing that's a production system? If not, just give it a try - all the changes are easy enough to back out of.

Yeah, it's production. To

Yeah, it's production. To which I have only remote (ssh) access - so I need be pretty careful.

Both subnets have default gateways (.250 in both cases)

I want to keep the main systems routing much as it is, i.e. all traffic that isn't for x.176.19.250 goes via the ge1 interface and it's gateway, x.176.19.250. Would your trick work here too? - I think not but I need to wait for next downtime window to try. And by that time I probably find another solution (workaround).

The reason I think not is in the blog, as in my case both gateways need to be reachable from the global zone as in the global zone both interfaces are active. If I have 2 default routes enabled my non-global zone problem is likely solved, but my global zone will then do round-robin routing which is undesired. It's undesired specifically here as one interface is gigabit speed (ge1) and the other isn't (bge0).

Thanks for looking and answering.
Kevin

Hi Thought I would tell you

Hi

Thought I would tell you that the above work around is pretty cool it does the job.

Darren

another alternative

I'm doing heavy stuff with Trusted Extensions labeled zones, requiring routing in-and-out of the global through the labeled zone. I found it easier to create a file with the route add statements, an /etc/init.d script to perform an "at now + 5 minutes < (script name)", then create a link in /etc/rc3.d to kick off the process.
Several minutes after the zones are booted, the script runs and adds your route statements to valid interfaces and addresses. I can leave my zones autobooting. I also have to add "arp -s" statements as well.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <p> <span> <div> <h1> <h2> <h3> <h4> <h5> <h6> <img> <map> <area> <hr> <br> <br /> <ul> <ol> <li> <dl> <dt> <dd> <table> <tr> <td> <em> <b> <u> <i> <strong> <font> <del> <ins> <sub> <sup> <quote> <blockquote> <pre> <address> <code> <cite> <embed> <object> <param> <strike> <caption>
  • Lines and paragraphs break automatically.

More information about formatting options