| # Licensed to the Apache Software Foundation (ASF) under one | |
| # or more contributor license agreements. See the NOTICE file | |
| # distributed with this work for additional information | |
| # regarding copyright ownership. The ASF licenses this file | |
| # to you under the Apache License, Version 2.0 (the | |
| # "License"); you may not use this file except in compliance | |
| # with the License. You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, | |
| # software distributed under the License is distributed on an | |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| # KIND, either express or implied. See the License for the | |
| # specific language governing permissions and limitations | |
| # under the License. | |
| from .utilities import bash | |
| from .cloudException import CloudRuntimeException, CloudInternalException | |
| import logging | |
| import os | |
| import re | |
| import subprocess | |
| class networkConfig: | |
| class devInfo: | |
| def __init__(self, macAddr, ipAddr, netmask, gateway, type, name): | |
| self.name = name | |
| self.macAdrr = macAddr | |
| self.ipAddr = ipAddr | |
| self.netmask = netmask | |
| self.gateway = gateway | |
| self.type = type | |
| self.name = name | |
| #dhcp or static | |
| self.method = None | |
| @staticmethod | |
| def listNetworks(): | |
| devs = os.listdir("/sys/class/net/") | |
| devs = list(filter(networkConfig.isBridge, devs)) | |
| return devs | |
| @staticmethod | |
| def getDefaultNetwork(): | |
| cmd = bash("ip route show default | awk \'{print $3,$5}\'") | |
| if not cmd.isSuccess(): | |
| logging.debug("Failed to get default route") | |
| raise CloudRuntimeException("Failed to get default route") | |
| output = cmd.getStdout().strip() | |
| result = output.split(" ") | |
| if len(result) < 2: | |
| logging.debug("Output for the default route incomplete: %s. It should have been '<GATEWAY> <DEVICE>'" % output) | |
| raise CloudRuntimeException("Output for the default route incomplete") | |
| gateway = result[0] | |
| dev = result[1] | |
| pdi = networkConfig.getDevInfo(dev) | |
| logging.debug("Found default network device:%s"%pdi.name) | |
| pdi.gateway = gateway | |
| return pdi | |
| @staticmethod | |
| def createBridge(dev, brName): | |
| if not networkConfig.isBridgeSupported(): | |
| logging.debug("bridge is not supported") | |
| return False | |
| if networkConfig.isBridgeEnslavedWithDevices(brName): | |
| logging.debug("bridge: %s has devices enslaved"%brName) | |
| return False | |
| cmds = "" | |
| if not networkConfig.isBridge(brName): | |
| cmds = "ip link add name %s type bridge ;"%brName | |
| cmds += "ifconfig %s up;"%brName | |
| cmds += "ip link set dev %s master %s"%(dev, brName) | |
| return bash(cmds).isSuccess() | |
| @staticmethod | |
| def isBridgeEnslavedWithDevices(brName): | |
| if not networkConfig.isBridge(brName): | |
| return False | |
| if not os.listdir("/sys/class/net/%s/brif"%brName): | |
| return False | |
| return True | |
| @staticmethod | |
| def isBridgeSupported(): | |
| if os.path.exists("/proc/sys/net/bridge"): | |
| return True | |
| return bash("modprobe -b bridge").isSuccess() | |
| @staticmethod | |
| def isNetworkDev(devName): | |
| return os.path.exists("/sys/class/net/%s" % devName) | |
| @staticmethod | |
| def isBridgePort(devName): | |
| return os.path.exists("/sys/class/net/%s/brport" % devName) | |
| @staticmethod | |
| def isBridge(devName): | |
| return os.path.exists("/sys/class/net/%s/bridge" % devName) | |
| @staticmethod | |
| def isOvsBridge(devName): | |
| cmd = bash("which ovs-vsctl") | |
| if not cmd.isSuccess(): | |
| return False | |
| try: | |
| return 0==subprocess.check_call(("ovs-vsctl", "br-exists", devName)) | |
| except subprocess.CalledProcessError: | |
| return False | |
| @staticmethod | |
| def getBridge(devName): | |
| bridgeName = None | |
| if os.path.exists("/sys/class/net/%s/brport/bridge"%devName): | |
| realPath = os.path.realpath("/sys/class/net/%s/brport/bridge"%devName) | |
| bridgeName = realPath.split("/")[-1] | |
| return bridgeName | |
| @staticmethod | |
| def getEnslavedDev(br, brPort): | |
| if not networkConfig.isBridgeEnslavedWithDevices(br): | |
| return None | |
| for dev in os.listdir("/sys/class/net/%s/brif"%br): | |
| br_port = int(open("/sys/class/net/%s/brif/%s/port_no"%(br,dev)).readline().strip("\n"), 16) | |
| if br_port == brPort: | |
| return dev | |
| return None | |
| @staticmethod | |
| def getDevInfo(dev): | |
| if not networkConfig.isNetworkDev(dev): | |
| logging.debug("dev: " + dev + " is not a network device") | |
| raise CloudInternalException("dev: " + dev + " is not a network device") | |
| netmask = None | |
| ipAddr = None | |
| macAddr = None | |
| cmd = bash("ifconfig " + dev) | |
| if not cmd.isSuccess(): | |
| logging.debug("Failed to get address from ifconfig") | |
| raise CloudInternalException("Failed to get network info by ifconfig %s"%dev) | |
| for line in cmd.getLines(): | |
| if line.find("HWaddr") != -1: | |
| macAddr = line.split("HWaddr ")[1].strip(" ") | |
| elif line.find("inet ") != -1: | |
| m = re.search(r"addr:([^\s]+)\s*Bcast:([^\s]+)\s*Mask:([^\s]+)", line) | |
| if m is not None: | |
| ipAddr = m.group(1).strip() | |
| netmask = m.group(3).strip() | |
| if networkConfig.isBridgePort(dev): | |
| type = "brport" | |
| elif networkConfig.isBridge(dev) or networkConfig.isOvsBridge(dev): | |
| type = "bridge" | |
| else: | |
| type = "dev" | |
| return networkConfig.devInfo(macAddr, ipAddr, netmask, None, type, dev) |