Change in vdsm[master]: WIP: Multiple Gateways Feature http://www.ovirt.org/Features...

amuller at redhat.com amuller at redhat.com
Thu May 30 14:28:52 UTC 2013


Assaf Muller has uploaded a new change for review.

Change subject: WIP: Multiple Gateways Feature http://www.ovirt.org/Features/Multiple_Gateways
......................................................................

WIP: Multiple Gateways Feature
http://www.ovirt.org/Features/Multiple_Gateways

* The module currently works from the command line.
* For DHCP interfaces, a manually placed file in /etc/dhcp calls
this script whenever the interface goes up or down.
* For static interfaces, this module will be imported in vdsm code
and used as such: Create an instance of the class and call up
or down.

TODO - Improve multipleGateways.py implementation:
* Build a lightweight library to parse ip route and ip rule output
* Change from using print to logging - With either stdout for cmd,
  or vdsm log file when importing
* Use a library to deal with command line arguments

TODO - Usage of multipleGateways.py:
* Add the 'netaddr' Python library as a VDSM depedency
* Add the file to the list of files installed in /usr/share/vdsm
* Use it during addNetwork, delNetwork for static interfaces
* For DHCP interfaces - Create and delete the hook files in
  /etc/dhcp

Change-Id: I0224d896724b9cdc44215e92f0da0be71fd19038
Signed-off-by: Assaf Muller <amuller at redhat.com>
---
A vdsm/multipleGateways.py
1 file changed, 161 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/07/15207/1

diff --git a/vdsm/multipleGateways.py b/vdsm/multipleGateways.py
new file mode 100644
index 0000000..231e971
--- /dev/null
+++ b/vdsm/multipleGateways.py
@@ -0,0 +1,161 @@
+import os
+import sys
+import netaddr
+from vdsm import utils
+
+
+NETWORK_SCRIPTS = '/etc/sysconfig/network-scripts/'
+
+
+class MultipleGatewaysConfigurator(object):
+    def __init__(self, isStatic, device):
+        self.isStatic = isStatic
+        self.device = device
+
+    def _generateTableId(self):
+        #TODO: Future proof for IPv6
+        return self.ip.value
+
+    def _buildRoutes(self):
+        return ["default via %s dev %s table %s" %
+                (self.gateway, self.device, self.table),
+                "%s via %s dev %s table %s" %
+                (self.network, self.ip, self.device, self.table)]
+
+    def _buildRules(self):
+        return ["from %s table %s" % (self.network, self.table),
+                "to %s table %s" % (self.network, self.table)]
+
+    def _writeCommands(self, commands, type='route'):
+        filePath = NETWORK_SCRIPTS + '%s-%s' % (type, self.device)
+        with open(filePath, 'w') as file:
+            for command in commands:
+                file.write(command + '\n')
+
+    def _addRoutesStatic(self, routes):
+        self._writeCommands(routes, type='route')
+
+    def _addRulesStatic(self, rules):
+        self._writeCommands(rules, type='rule')
+
+    def _runCommands(self, commands):
+        for command in commands:
+            utils.execCmd(command.split())
+
+    def _addRoutesDHCP(self, routes):
+        routes = ['ip route add ' + route for route in routes]
+        self._runCommands(routes)
+
+    def _addRulesDHCP(self, rules):
+        rules = ['ip rule add ' + rule for rule in rules]
+        self._runCommands(rules)
+
+    def up(self, ip, mask, gateway):
+        try:
+            self.ip = netaddr.IPAddress(ip)
+            self.mask = netaddr.IPAddress(mask)
+            self.gateway = netaddr.IPAddress(gateway)
+        except netaddr.core.AddrFormatError:
+            print ("IP, subnet mask or gateway not properly formatted.")
+            return
+        self.table = self._generateTableId()
+        network = netaddr.IPNetwork(str(self.ip) + '/' + str(self.mask))
+        self.network = "%s/%s" % (network.network, network.prefixlen)
+
+        print (("Bringing up - ip: %s, network: %s, subnet: %s " +
+               "gateway: %s, table: %s, device: %s") %
+               (self.ip, self.network, self.mask, self.gateway, self.table,
+                self.device))
+
+        routes = self._buildRoutes()
+        rules = self._buildRules()
+
+        if self.isStatic:
+            self._addRoutesStatic(routes)
+            self._addRulesStatic(rules)
+        else:
+            self._addRoutesDHCP(routes)
+            self._addRulesDHCP(rules)
+
+    def _delTable(self, table):
+        command = "/sbin/ip route show table".split()
+        command.append(table)
+        _, output, _ = utils.execCmd(command)
+        commands = ["/sbin/ip route del %s table %s"
+                    % (line.strip(), table) for line in output if line]
+        self._runCommands(commands)
+
+    def _delRulesDHCP(self, rules):
+        rules = ['ip rule del ' + rule for rule in rules]
+        self._runCommands(rules)
+
+    def _getTable(self, rule):
+        return rule.split()[-1] if rule else None
+
+    def _getRules(self, network):
+        _, output, _ = utils.execCmd("/sbin/ip rule".split())
+        relevantLines = [line for line in output if network in line]
+        rules = [line.split(":")[1].strip() for line in relevantLines]
+        return rules
+
+    def _getNetwork(self, device):
+        _, output, _ = utils.execCmd(["/sbin/ip", "route"])
+        relevantLines = [line for line in output if self.device in line]
+
+        entry = relevantLines[0] if relevantLines else None
+        if entry:
+            network = entry.split()[0]
+            return network
+        else:
+            print "Network for given device name not found."
+            return None
+
+    def _delRoutesStatic(self):
+        os.remove(NETWORK_SCRIPTS + 'route-%s' % self.device)
+
+    def _delRulesStatic(self):
+        os.remove(NETWORK_SCRIPTS + 'rule-%s' % self.device)
+
+    def down(self):
+        print ("Bringing down - device: %s" % self.device)
+
+        if self.isStatic:
+            self._delRoutesStatic()
+            self._delRulesStatic()
+        else:
+            network = self._getNetwork(self.device)
+            rules = self._getRules(network)
+            table = self._getTable(rules[0])
+            self._delRulesDHCP(rules)
+            self._delTable(table)
+
+
+def main():
+    if (len(sys.argv) < 3 or
+            (((sys.argv[1] not in ('up', 'down')) or
+              sys.argv[2] not in ('static', 'dhcp'))) or
+        (sys.argv[1] == 'up' and len(sys.argv) != 7) or
+            (sys.argv[1] == 'down' and len(sys.argv) != 4)):
+        print ("Usage: %s up static/dhcp <ip> <mask> <gateway> <device>" %
+               sys.argv[0])
+        print ("Usage: %s down static/dhcp <device>" %
+               sys.argv[0])
+        sys.exit(1)
+
+    isUp = True if sys.argv[1] == 'up' else False
+    isStatic = True if sys.argv[2] == 'static' else False
+    device = sys.argv[6] if isUp else sys.argv[3]
+
+    gateways = MultipleGatewaysConfigurator(isStatic, device)
+
+    if isUp:
+        ip = sys.argv[3]
+        mask = sys.argv[4]
+        gateway = sys.argv[5]
+        gateways.up(ip, mask, gateway)
+    else:
+        gateways.down()
+
+
+if __name__ == "__main__":
+    main()


--
To view, visit http://gerrit.ovirt.org/15207
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I0224d896724b9cdc44215e92f0da0be71fd19038
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Assaf Muller <amuller at redhat.com>


More information about the vdsm-patches mailing list