2011-01-08 16:28:47 -08:00

546 lines
13 KiB
Python

#!/usr/bin/python
# Create flows on Open vSwitch
#
# @param: bridge name, refer to a network created by xenserver
# @param: our MAC
# @param: vlan ID
import os
import sys
from os.path import exists as _exists
from time import localtime as _localtime, asctime as _asctime
vSwitchDBPidFile = "/var/run/openvswitch/ovsdb-server.pid"
vSwitchDBDaemonName = "ovsdb-server"
vSwitchPidFile = "/var/run/openvswitch/ovs-vswitchd.pid"
vsctlPath = "/usr/bin/ovs-vsctl"
vSwitchDaemonName = "ovs-vswitchd"
logFile = "/var/log/cloud/management/vlanRemapUtils.log"
fLog = None
global result
errors = \
{"NO_DB_PID_FILE" : "NO_DB_PID_FILE", \
"DB_NOT_RUN" : "DB_NOT_RUN", \
"NO_SWITCH_PID_FILE" : "NO_SWITCH_PID_FILE", \
"SWITCH_NOT_RUN" : "SWITCH_NOT_RUN", \
"NO_VSCTL" : "NO_VSCTL", \
"COMMAND_FAILED" : "COMMAND_FAILED", \
"TUNNEL_EXISTED" : "TUNNEL_EXISTED", \
"NO_INPORT" : "NO_INPORT", \
"NO_OFPORT" : "NO_OFPORT", \
"ERR_ARGS_NUM" : "ERR_ARGS_NUM", \
"ERROR_OP" : "ERROR_OP", \
"SUCCESS" : "SUCCESS", \
}
def openLog ():
global fLog
try:
if fLog == None:
fLog = open (logFile, "a")
except IOError, e:
#print e
pass
def log (str):
global fLog
if fLog != None:
str = "[%s]:" % _asctime (_localtime()) + str + "\n"
fLog.write (str)
def closeLog ():
global fLog
if fLog != None:
fLog.close ()
def isProcessRun (pidFile, name):
try:
fpid = open (pidFile, "r")
pid = fpid.readline ()
fpid.close ()
except IOError, e:
return -1
pid = pid[:-1]
ps = os.popen ("ps -ae")
for l in ps:
if pid in l and name in l:
ps.close ()
return 0
ps.close ()
return -2
def isToolExist (name):
if _exists (name):
return 0
return -1
def checkvSwitch ():
global result
ret = isProcessRun (vSwitchDBPidFile, vSwitchDBDaemonName);
if ret < 0:
if ret == -1: result = errors["NO_DB_PID_FILE"]
if ret == -2: result = errors["DB_NOT_RUN"]
return -1
ret = isProcessRun (vSwitchPidFile, vSwitchDaemonName)
if ret < 0:
if ret == -1: result = errors["NO_SWITCH_PID_FILE"]
if ret == -2: result = errors["SWITCH_NOT_RUN"]
return -1
if isToolExist (vsctlPath) < 0:
result = errors["NO_VSCTL"]
return -1
return 0
def doCmd (cmds, lines=False):
cmd = ""
for i in cmds:
cmd += " "
cmd += i
log ("do command '%s'" % cmd)
f = os.popen (cmd)
if lines == True:
res = f.readlines ()
else:
res = f.readline ()
res = res[:-1]
f.close ()
if lines == False:
log ("command output '%s'" % res)
return res
######################## GRE creation utils ##########################
# UUID's format is 8-4-4-4-12
def isUUID (uuid):
list = uuid.split ("-")
if len (list) != 5:
return -1
if len (list[0]) != 8 or len (list[1]) != 4 \
or len (list[2]) != 4 or len (list[3]) != 4 \
or len (list[4]) != 12:
return -1
return 0
def checkGREInterface (bridge, remoteIP, greKey):
ports = getPortsOnBridge(bridge)
if ports == None:
return 0
for i in ports:
ifaces = getInterfacesOnPort(i)
if ifaces == None:
continue
for j in ifaces:
if j == '[]':
continue
options = getFieldOfInterface(j, "options")
if remoteIP in options and greKey in options:
log("WARNING: GRE tunnel for remote_ip=%s key=%s already here, \
interface(%s)" % (remoteIP, greKey, j))
return -1
return 0
def createGRE (bridge, remoteIP, greKey):
global result
name = "%sgre" % bridge
if checkGREInterface(bridge, remoteIP, greKey) < 0:
result = errors["TUNNEL_EXISTED"]
return 0
wait = [vsctlPath, "--timeout=30 wait-until bridge %s -- get bridge %s name" % \
(bridge, bridge)]
res = doCmd(wait)
if bridge not in res:
log("WARNIING:Can't find bridge %s for creating tunnel!" % bridge)
result = errors["COMMAND_FAILED"]
return -1
createInterface = [vsctlPath, "create interface", "name=%s" % name, \
'type=gre options:"remote_ip=%s key=%s"' % (remoteIP, greKey)]
ifaceUUID = doCmd (createInterface)
if isUUID (ifaceUUID) < 0:
result = errors["COMMAND_FAILED"];
return -1
createPort = [vsctlPath, "create port", "name=%s" % name, \
"interfaces=[%s]" % ifaceUUID]
portUUID = doCmd (createPort)
if isUUID (portUUID) < 0:
result = errors["COMMAND_FAILED"];
return -1
addBridge = [vsctlPath, "add bridge %s" % bridge, "ports %s" % portUUID]
doCmd (addBridge)
wait = [vsctlPath, "--timeout=5 wait-until port %s -- get port %s name" % \
(name, name)]
res = doCmd(wait)
if name in res:
result = errors["SUCCESS"]
return 0
else:
result = errors["COMMAND_FAILED"]
return -1
######################## End GRE creation utils ##########################
######################## Flow creation utils ##########################
def getPortsOnBridge(bridge):
listBr = [vsctlPath, "list br", bridge]
res = doCmd(listBr, True)
for i in res:
if "ports" in i:
(x, str) = i.split(":")
str = str.lstrip().rstrip()
str = str[1:]
str = str[:-1]
return str.split(",")
return None
def getFieldOfPort(nameOruuid, field):
listport = [vsctlPath, "list port", nameOruuid]
res = doCmd(listport, True)
for i in res:
if field in i:
(x, r) = i.split(":")
return r.lstrip().rstrip()
return None
def getFieldOfInterface(nameOruuid, field):
listIface = [vsctlPath, "list interface", nameOruuid]
res = doCmd(listIface, True)
for i in res:
if field in i:
(x, r) = i.split(":")
return r.lstrip().rstrip()
return None
def strip(str, direction="default"):
str = str.lstrip().rstrip()
if direction == "left":
return str[1:]
if direction == "right":
return str[:-1]
if direction == "both":
str = str[1:]
str = str[:-1]
return str
return str
def getVifPort(bridge, vifName):
portUuids = getPortsOnBridge(bridge)
if portUuids == None:
log("No ports on bridge %s" % bridge)
return -1
for i in portUuids:
name = getFieldOfPort(i, "name")
if name == None:
log("WARNING: no name found for %s" % name)
continue
name = strip(name, "both")
if name == vifName:
return getFieldOfInterface(vifName, "ofport")
return None
def getInterfacesOnPort(nameOruuid):
listPort = [vsctlPath, "list port", nameOruuid]
res = doCmd(listPort, True)
for i in res:
if "interfaces" in i:
(x, str) = i.split(":")
str = strip(str, "both")
return str.split(",")
return None
def getOfPortsByType(bridge, askGre):
portUuids = getPortsOnBridge(bridge)
if portUuids == None:
log("WARNING:No ports on bridge %s" % bridge)
return []
OfPorts = []
for i in portUuids:
ifaces = getInterfacesOnPort(i)
if ifaces == None:
log("WARNING:No interfaces on port %s" % i)
continue
for j in ifaces:
if j == '[]':
log("WARNING:invalid interface [] on port %s" % i)
continue
type = getFieldOfInterface(j, "type")
type = strip(type)
if askGre == True and type == "gre":
ofport = getFieldOfInterface(j, "ofport")
if ofport != '[]':OfPorts.append(strip(ofport))
elif askGre == False and type != "gre":
ofport = getFieldOfInterface(j, "ofport")
if ofport != '[]' and ofport != "65534":OfPorts.append(strip(ofport))
return OfPorts
def getNoneGreOfPort(bridge):
return getOfPortsByType(bridge, False)
def getGreOfPorts(bridge):
return getOfPortsByType(bridge, True)
def formatFlow(inPort, vlan, mac, outPut):
flow = "in_port=%s dl_vlan=%s dl_dst=%s idle_timeout=0 hard_timeout=0 \
priority=10000 actions=strip_vlan,output:%s" % (inPort, vlan, mac, outPut)
return flow
def formatDropFlow(inPort, vlan):
flow = "in_port=%s dl_vlan=%s priority=0 idle_timeout=0 hard_timeout=0 \
actions=drop" % (inPort, vlan)
return flow
def delFlow(mac):
param = "dl_dst=%s" % mac
delFlow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
doCmd(delFlow)
def delARPFlow(vlan):
param = "dl_type=0x0806 dl_vlan=%s" % vlan
delFlow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
doCmd(delFlow)
def delDHCPFlow(vlan):
param = "dl_type=0x0800 nw_proto=6 tp_src=547 dl_vlan=%s" % vlan
delFlow = ["ovs-ofctl del-flows %s" % bridge, '"%s"' % param]
doCmd(delFlow)
def formatDHCPFlow(bridge, inPort, vlan, ports):
outputs = ''
for i in ports:
str = "output:%s," % i
outputs += str
outputs = outputs[:-1]
flow = "in_port=%s dl_vlan=%s dl_type=0x0800 nw_proto=6 tp_src=547 idle_timeout=0 hard_timeout=0 \
priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs)
return flow
def formatARPFlow(bridge, inPort, vlan, ports):
outputs = ''
for i in ports:
str = "output:%s," % i
outputs += str
outputs = outputs[:-1]
flow = "in_port=%s dl_vlan=%s dl_type=0x0806 idle_timeout=0 hard_timeout=0 \
priority=10000 actions=strip_vlan,%s" % (inPort, vlan, outputs)
return flow
def createFlow (bridge, vifName, mac, remap):
global result
inport = getGreOfPorts(bridge)
if len(inport) == 0:
log("WARNING: no inport found")
result = errors["NO_INPORT"]
return -1
output = getVifPort(bridge, vifName)
if output == None:
log("WARNING: cannot find ofport for %s" % vifName)
result = errors["NO_OFPORT"]
return -1
if output == '[]':
log("WARNING: ofport is [] for %s" % vifName)
result = errors["NO_OFPORT"]
return -1
#del old flow here, if any, but in normal there should be no old flow
#maybe we need add check here
delFlow(mac)
#set remap here, remap has format e.g. [1,22,200,13,16]
remap = strip(remap)
log("")
log("Create flow for remap")
noneGreOfPorts = getNoneGreOfPort(bridge)
isARP = True
if len(noneGreOfPorts) == 0:
log("WARNING: no none GRE ofports found, no ARP flow and DHCP flow will be created")
isARP = False
for j in remap.split("/"):
delARPFlow(j)
delDHCPFlow(j)
for i in inport:
flow = formatDropFlow(i, j)
param = bridge + ' "%s"' % flow
dropflow = ["ovs-ofctl add-flow", param]
doCmd (dropflow)
flow = formatFlow(i, j, mac, output)
param = bridge + ' "%s"' % flow
addflow = ["ovs-ofctl add-flow", param]
doCmd (addflow)
if isARP == True:
flow = formatARPFlow(bridge, i, j, noneGreOfPorts)
param = bridge + ' "%s"' % flow
addflow = ["ovs-ofctl add-flow", param]
doCmd (addflow)
flow = formatDHCPFlow(bridge, i, j, noneGreOfPorts)
param = bridge + ' "%s"' % flow
addflow = ["ovs-ofctl add-flow", param]
doCmd (addflow)
result = errors["SUCCESS"]
return 0
######################## End Flow creation utils ##########################
def setTag(bridge, vifName, vlan):
# The startVM command is slow, we may wait for a while for it creates vif on
# open vswitch
log("Waiting for %s ..." % vifName)
waitPortCmd = [vsctlPath, "--timeout=10 wait-until port %s -- get port %s name" % \
(vifName, vifName)]
doCmd (waitPortCmd)
log("%s is here" % vifName)
if getVifPort(bridge, vifName) == None:
log("WARNING: %s is not on bridge %s" % (vifName, bridge))
return 0
log("Set tag")
setTagCmd = [vsctlPath, "set port", vifName, "tag=%s"%vlan]
doCmd (setTagCmd)
return 0
def doCreateGRE(bridge, remoteIP, key):
global result
if createGRE(bridge, remoteIP, key) < 0:
log("create GRE tunnel on %s for %s failed" % (bridge, \
remoteIP))
else:
log("WARNING: create GRE tunnel on %s for %s success" % (bridge, \
remoteIP))
print result
def doCreateFlow (bridge, vifName, mac, remap):
global result
if createFlow(bridge, vifName, mac, remap) < 0:
log ("Create flow failed(bridge=%s, vifName=%s, mac=%s,\
remap=%s" % (bridge, vifName, mac, remap))
else:
log ("Create flow success(bridge=%s, vifName=%s, mac=%s,\
remap=%s" % (bridge, vifName, mac, remap))
print result
def doSetTag (bridge, vifName, tag):
setTag(bridge, vifName, tag)
def doDeleteFlow(bridge, vifName, mac, remap):
delFlow(mac)
log("Delete flows for %s" % mac)
remap = strip(remap)
# remove our port from arp flow
inport = getGreOfPorts(bridge)
if len(inport) == 0:
return
mine = getVifPort(bridge, vifName)
noneGreOfPorts = getNoneGreOfPort(bridge)
noneGreOfPorts.remove(mine)
log("Delete ARP flows for(vifname=%s, ofport=%s)" % (vifName, mine))
for j in remap.split("/"):
delARPFlow(j)
for i in inport:
flow = formatARPFlow(bridge, i, j, noneGreOfPorts)
param = bridge + ' "%s"' % flow
addflow = ["ovs-ofctl add-flow", param]
doCmd (addflow)
def checkArgNum(num):
if len (sys.argv) < num:
result = errors["ERR_ARGS_NUM"]
print result
log ("Error number of arguments")
sys.exit (-1)
if __name__ == "__main__":
global result
openLog ()
if checkvSwitch () < 0:
print result
log ("Check switch failed, reason = '%s'" % result)
sys.exit (-1)
op = sys.argv[1]
if op == "createGRE":
checkArgNum(5)
bridge = sys.argv[2]
remoteIP = sys.argv[3]
key = sys.argv[4]
doCreateGRE(bridge, remoteIP, key)
sys.exit(0)
elif op == "createFlow":
checkArgNum(6)
bridge = sys.argv[2]
vifName = sys.argv[3]
mac = sys.argv[4]
remap = sys.argv[5]
doCreateFlow(bridge, vifName, mac, remap)
sys.exit(0)
elif op == "deleteFlow":
checkArgNum(6)
bridge = sys.argv[2]
vifName = sys.argv[3]
mac = sys.argv[4]
remap = sys.argv[5]
doDeleteFlow(bridge, vifName, mac, remap)
elif op == "setTag":
checkArgNum(5)
bridge = sys.argv[2]
vifName = sys.argv[3]
tag = sys.argv[4]
doSetTag(bridge, vifName, tag)
else:
log("WARNING: get an unkown op %s" % op)
result=errors["ERROR_OP"]
print result
sys.exit(-1)
result = errors["SUCCESS"]
closeLog ()
print result