Skip to content

Commit df1dc8d

Browse files
author
dean.close
committed
CLOUDSTACK-9339: Handle multiple public subnets on virtual routers
1 parent c2f0540 commit df1dc8d

File tree

3 files changed

+127
-62
lines changed

3 files changed

+127
-62
lines changed

systemvm/patches/debian/config/opt/cloud/bin/configure.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -891,6 +891,12 @@ def processStaticNatRule(self, rule):
891891
device = self.getDeviceByIp(rule["public_ip"])
892892
if device is None:
893893
raise Exception("Ip address %s has no device in the ips databag" % rule["public_ip"])
894+
self.fw.append(["mangle", "",
895+
"-A PREROUTING -s %s/32 -m state --state NEW -j MARK --set-xmark 0x%s/0xffffffff" % \
896+
(rule["internal_ip"], device[len("eth"):])])
897+
self.fw.append(["mangle", "",
898+
"-A PREROUTING -s %s/32 -m state --state NEW -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff" % \
899+
rule["internal_ip"]])
894900
self.fw.append(["nat", "front",
895901
"-A PREROUTING -d %s/32 -j DNAT --to-destination %s" % (rule["public_ip"], rule["internal_ip"])])
896902
self.fw.append(["nat", "front",

systemvm/patches/debian/config/opt/cloud/bin/cs/CsAddress.py

Lines changed: 54 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
from CsRule import CsRule
2929

3030
VRRP_TYPES = ['guest']
31-
PUBLIC_INTERFACE = ['eth1']
31+
VPC_PUBLIC_INTERFACE = ['eth1']
32+
NETWORK_PUBLIC_INTERFACE = ['eth2']
3233

3334
class CsAddress(CsDataBag):
3435

@@ -288,52 +289,62 @@ def post_configure(self, address):
288289
""" The steps that must be done after a device is configured """
289290
route = CsRoute()
290291
if not self.get_type() in ["control"]:
291-
route.add_table(self.dev)
292-
293-
CsRule(self.dev).addMark()
292+
293+
if self.dev != 'eth0':
294+
route.add_table(self.dev)
295+
CsRule(self.dev).addMark()
296+
self.set_mark()
297+
294298
self.check_is_up()
295-
self.set_mark()
296299
self.arpPing()
297-
300+
298301
CsRpsrfs(self.dev).enable()
299302
self.post_config_change("add")
300303

301304
'''For isolated/redundant and dhcpsrvr routers, call this method after the post_config is complete '''
302305
if not self.config.is_vpc():
303306
self.setup_router_control()
304-
305-
if self.config.is_vpc() or self.cl.is_redundant():
306-
# The code looks redundant here, but we actually have to cater for routers and
307-
# VPC routers in a different manner. Please do not remove this block otherwise
308-
# The VPC default route will be broken.
309-
if self.get_type() in ["public"]:
310-
gateway = str(address["gateway"])
311-
route.add_defaultroute(gateway)
307+
308+
309+
try:
310+
if str(address["gateway"]) == "None":
311+
raise ValueError
312+
except (KeyError, ValueError):
313+
logging.debug("IP %s was not provided with a gateway." % self.ip())
312314
else:
313-
# once we start processing public ip's we need to verify there
314-
# is a default route and add if needed
315-
if(self.cl.get_gateway()):
316-
route.add_defaultroute(self.cl.get_gateway())
315+
if self.get_type() in ["public"]:
316+
if self.config.is_vpc():
317+
main_public_nic = VPC_PUBLIC_INTERFACE
318+
else:
319+
main_public_nic = NETWORK_PUBLIC_INTERFACE
320+
321+
if self.dev in main_public_nic:
322+
logging.debug("IP %s has the gateway %s that should be in the main routing table." % \
323+
(self.ip(), address["gateway"]))
324+
route.add_defaultroute(address["gateway"])
325+
else:
326+
logging.debug("IP %s has the gateway %s that is not intended for the main routing table." % \
327+
(self.ip(), address["gateway"]))
317328

318329
def check_is_up(self):
319330
""" Ensure device is up """
320331
cmd = "ip link show %s | grep 'state DOWN'" % self.getDevice()
321332
for i in CsHelper.execute(cmd):
322333
if " DOWN " in i:
323334
cmd2 = "ip link set %s up" % self.getDevice()
324-
# If redundant only bring up public interfaces that are not eth1.
325-
# Reason: private gateways are public interfaces.
326-
# master.py and keepalived will deal with eth1 public interface.
327-
if self.cl.is_redundant() and (not self.is_public() or self.getDevice() not in PUBLIC_INTERFACE):
335+
# All interfaces should be up on non-redundant or master routers
336+
if not self.cl.is_redundant() or self.cl.is_master():
328337
CsHelper.execute(cmd2)
329-
# if not redundant bring everything up
330-
if not self.cl.is_redundant():
338+
# only bring up non-public interfaces on backup redundant routers
339+
elif not self.is_public():
331340
CsHelper.execute(cmd2)
332341

342+
333343
def set_mark(self):
334-
cmd = "-A PREROUTING -i %s -m state --state NEW -j CONNMARK --set-xmark %s/0xffffffff" % \
335-
(self.getDevice(), self.dnum)
336-
self.fw.append(["mangle", "", cmd])
344+
if self.get_type() in ['public']:
345+
cmd = "-A PREROUTING -i %s -m state --state NEW -j CONNMARK --set-xmark %s/0xffffffff" % \
346+
(self.getDevice(), self.dnum)
347+
self.fw.append(["mangle", "", cmd])
337348

338349
def get_type(self):
339350
""" Return the type of the IP
@@ -369,9 +380,13 @@ def setup_router_control(self):
369380
def fw_router(self):
370381
if self.config.is_vpc():
371382
return
372-
self.fw.append(["mangle", "front", "-A PREROUTING " +
383+
384+
restore_mark = ["mangle", "front", "-A PREROUTING " +
373385
"-m state --state RELATED,ESTABLISHED " +
374-
"-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"])
386+
"-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"]
387+
388+
if restore_mark not in self.fw:
389+
self.fw.append(restore_mark)
375390

376391
if self.get_type() in ["public"]:
377392
self.fw.append(["mangle", "front",
@@ -399,6 +414,10 @@ def fw_router(self):
399414
"-j CONNMARK --set-xmark %s/0xffffffff" % self.dnum])
400415
self.fw.append(
401416
["mangle", "", "-A FIREWALL_%s -j DROP" % self.address['public_ip']])
417+
self.fw.append(
418+
["filter", "", "-A FORWARD -i %s -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.dev])
419+
self.fw.append(
420+
["filter", "", "-A FORWARD -i eth0 -o %s -j FW_OUTBOUND" % self.dev])
402421

403422
self.fw.append(["filter", "", "-A INPUT -d 224.0.0.18/32 -j ACCEPT"])
404423
self.fw.append(["filter", "", "-A INPUT -d 225.0.0.50/32 -j ACCEPT"])
@@ -422,23 +441,16 @@ def fw_router(self):
422441
["filter", "", "-A FORWARD -i %s -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.dev])
423442
self.fw.append(
424443
["filter", "", "-A FORWARD -i %s -o %s -m state --state NEW -j ACCEPT" % (self.dev, self.dev)])
425-
self.fw.append(
426-
["filter", "", "-A FORWARD -i eth2 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT"])
427444
self.fw.append(
428445
["filter", "", "-A FORWARD -i eth0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT"])
429-
self.fw.append(
430-
["filter", "", "-A FORWARD -i eth0 -o eth2 -j FW_OUTBOUND"])
431-
self.fw.append(["mangle", "",
432-
"-A PREROUTING -i %s -m state --state NEW " % self.dev +
433-
"-j CONNMARK --set-xmark %s/0xffffffff" % self.dnum])
434446

435447
self.fw.append(['', 'front', '-A FORWARD -j NETWORK_STATS'])
436448
self.fw.append(['', 'front', '-A INPUT -j NETWORK_STATS'])
437449
self.fw.append(['', 'front', '-A OUTPUT -j NETWORK_STATS'])
438-
self.fw.append(['', '', '-A NETWORK_STATS -i eth0 -o eth2'])
439-
self.fw.append(['', '', '-A NETWORK_STATS -i eth2 -o eth0'])
440-
self.fw.append(['', '', '-A NETWORK_STATS -o eth2 ! -i eth0 -p tcp'])
441-
self.fw.append(['', '', '-A NETWORK_STATS -i eth2 ! -o eth0 -p tcp'])
450+
self.fw.append(['', '', '-A NETWORK_STATS -i eth0 -o %s' % self.dev])
451+
self.fw.append(['', '', '-A NETWORK_STATS -i %s -o eth0' % self.dev])
452+
self.fw.append(['', '', '-A NETWORK_STATS -o %s ! -i eth0 -p tcp' % self.dev])
453+
self.fw.append(['', '', '-A NETWORK_STATS -i %s ! -o eth0 -p tcp' % self.dev])
442454

443455
def fw_vpcrouter(self):
444456
if not self.config.is_vpc():
@@ -519,6 +531,8 @@ def post_config_change(self, method):
519531
route = CsRoute()
520532
if method == "add":
521533
route.add_table(self.dev)
534+
if "gateway" in self.address and self.address["gateway"] != "None":
535+
route.add_route(self.dev, "default via %s" % self.address["gateway"])
522536
route.add_route(self.dev, str(self.address["network"]))
523537
elif method == "delete":
524538
logging.warn("delete route not implemented")

systemvm/patches/debian/config/opt/cloud/bin/cs/CsRedundant.py

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from CsFile import CsFile
3737
from CsProcess import CsProcess
3838
from CsApp import CsPasswdSvc
39-
from CsAddress import CsDevice
39+
from CsAddress import CsDevice, VPC_PUBLIC_INTERFACE, NETWORK_PUBLIC_INTERFACE
4040
from CsRoute import CsRoute
4141
import socket
4242
from time import sleep
@@ -290,27 +290,7 @@ def set_master(self):
290290
self.set_lock()
291291
logging.debug("Setting router to master")
292292

293-
dev = ''
294-
ips = [ip for ip in self.address.get_ips() if ip.is_public()]
295-
route = CsRoute()
296-
for ip in ips:
297-
if dev == ip.get_device():
298-
continue
299-
dev = ip.get_device()
300-
logging.info("Will proceed configuring device ==> %s" % dev)
301-
cmd2 = "ip link set %s up" % dev
302-
if CsDevice(dev, self.config).waitfordevice():
303-
CsHelper.execute(cmd2)
304-
logging.info("Bringing public interface %s up" % dev)
305-
306-
try:
307-
gateway = ip.get_gateway()
308-
logging.info("Adding gateway ==> %s to device ==> %s" % (gateway, dev))
309-
route.add_defaultroute(gateway)
310-
except:
311-
logging.error("ERROR getting gateway from device %s" % dev)
312-
else:
313-
logging.error("Device %s was not ready could not bring it up" % dev)
293+
self._bring_public_interfaces_up()
314294

315295
# ip route add default via $gw table Table_$dev proto static
316296
cmd = "%s -C %s" % (self.CONNTRACKD_BIN, self.CONNTRACKD_CONF)
@@ -330,6 +310,71 @@ def set_master(self):
330310
self.release_lock()
331311
logging.info("Router switched to master mode")
332312

313+
314+
def _bring_public_interfaces_up(self):
315+
'''Brings up all public interfaces and adds routes to the
316+
relevant routing tables.
317+
'''
318+
319+
up = [] # devices we've already brought up
320+
routes = [] # routes to be added
321+
322+
is_link_up = "ip link show %s | grep 'state UP'"
323+
set_link_up = "ip link set %s up"
324+
add_route = "ip route add %s"
325+
arping = "arping -c 1 -U %s -I %s"
326+
327+
if self.config.is_vpc():
328+
default_gateway = VPC_PUBLIC_INTERFACE
329+
else:
330+
default_gateway = NETWORK_PUBLIC_INTERFACE
331+
332+
public_ips = [ip for ip in self.address.get_ips() if ip.is_public()]
333+
334+
for ip in public_ips:
335+
address = ip.get_ip()
336+
device = ip.get_device()
337+
gateway = ip.get_gateway()
338+
339+
logging.debug("Configuring device %s for IP %s" % (device, address))
340+
341+
if device in up:
342+
logging.debug("Device %s already configured. Skipping..." % device)
343+
continue
344+
345+
if not CsDevice(device, self.config).waitfordevice():
346+
logging.error("Device %s was not ready could not bring it up." % device)
347+
continue
348+
349+
if CsHelper.execute(is_link_up % device):
350+
loggind.warn("Device %s was found already up. Assuming routes need configuring.")
351+
up.append(device)
352+
else:
353+
logging.info("Bringing public interface %s up" % device)
354+
CsHelper.execute(set_link_up % device)
355+
356+
logging.debug("Collecting routes for interface %s" % device)
357+
routes.append("default via %s dev %s table Table_%s" % (gateway, device, device))
358+
359+
if device in default_gateway:
360+
logging.debug("Determined that the gateway for %s should be in the main routing table." % device)
361+
routes.insert(0, "default via %s dev %s" % (gateway, device))
362+
363+
up.append(device)
364+
365+
logging.info("Adding all collected routes.")
366+
for route in routes:
367+
CsHelper.execute(add_route % route)
368+
369+
logging.info("Sending gratuitous ARP for each Public IP...")
370+
for ip in public_ips:
371+
address = ip.get_ip()
372+
device = ip.get_device()
373+
CsHelper.execute(arping % (address, device))
374+
375+
376+
377+
333378
def _collect_ignore_ips(self):
334379
"""
335380
This returns a list of ip objects that should be ignored

0 commit comments

Comments
 (0)