print "Created Virtual Port:%s " \
"on Virtual Network:%s" % (new_port, nid)
+
def delete_port(manager, *args):
tid, nid, pid = args
- manager.delete_port(tid, nid,pid)
++ manager.delete_port(tid, nid, pid)
LOG.info("Deleted Virtual Port:%s " \
"on Virtual Network:%s" % (pid, nid))
net = None
try:
net = session.query(models.Network).\
- filter_by(tenant_id=tenant_id,name=name).\
- filter_by(name=name).\
++ filter_by(tenant_id=tenant_id, name=name).\
one()
raise Exception("Network with name \"%s\" already exists" % name)
except exc.NoResultFound:
session = get_session()
try:
res = session.query(models.Network).\
- filter_by(tenant_id=tenant_id,name=new_name).\
- filter_by(name=new_name).\
++ filter_by(tenant_id=tenant_id, name=new_name).\
one()
except exc.NoResultFound:
net = network_get(net_id)
$ make agent-dist
- Copy the resulting tarball to your xenserver(s) (copy to dom0, not the nova
compute node)
-- Unpack the tarball and run install.sh. This will install all of the
+- Unpack the tarball and run xenserver_install.sh. This will install all of the
necessary pieces into /etc/xapi.d/plugins. It will also spit out the name
of the integration bridge that you'll need for your nova configuration.
+ Make sure to specify this in your nova flagfile as --flat_network_bridge.
- Run the agent [on your hypervisor (dom0)]:
$ /etc/xapi.d/plugins/ovs_quantum_agent.py /etc/xapi.d/plugins/ovs_quantum_plugin.ini
def get_port_stats(self, port_name):
return self.db_get_map("Interface", port_name, "statistics")
-
- # this is a hack that should go away once nova properly reports bindings
- # to quantum. We have this here for now as it lets us work with
+
++ # this is a hack that should go away once nova properly reports bindings
++ # to quantum. We have this here for now as it lets us work with
+ # unmodified nova
- def xapi_get_port(self, name):
- external_ids = self.db_get_map("Interface",name,"external_ids")
- if "attached-mac" not in external_ids:
- return None
- vm_uuid = external_ids.get("xs-vm-uuid", "")
- if len(vm_uuid) == 0:
- return None
- LOG.debug("iface-id not set, got xs-vm-uuid: %s" % vm_uuid)
- res = os.popen("xe vm-list uuid=%s params=name-label --minimal" \
- % vm_uuid).readline().strip()
- if len(res) == 0:
- return None
- external_ids["iface-id"] = res
- LOG.info("Setting interface \"%s\" iface-id to \"%s\"" % (name, res))
- self.set_db_attribute("Interface", name,
++ def xapi_get_port(self, name):
++ external_ids = self.db_get_map("Interface", name, "external_ids")
++ if "attached-mac" not in external_ids:
++ return None
++ vm_uuid = external_ids.get("xs-vm-uuid", "")
++ if len(vm_uuid) == 0:
++ return None
++ LOG.debug("iface-id not set, got xs-vm-uuid: %s" % vm_uuid)
++ res = os.popen("xe vm-list uuid=%s params=name-label --minimal" \
++ % vm_uuid).readline().strip()
++ if len(res) == 0:
++ return None
++ external_ids["iface-id"] = res
++ LOG.info("Setting interface \"%s\" iface-id to \"%s\"" % (name, res))
++ self.set_db_attribute("Interface", name,
+ "external-ids:iface-id", res)
- ofport = self.db_get_val("Interface",name,"ofport")
- return VifPort(name, ofport, external_ids["iface-id"],
++ ofport = self.db_get_val("Interface", name, "ofport")
++ return VifPort(name, ofport, external_ids["iface-id"],
+ external_ids["attached-mac"], self)
+
# returns a VIF object for each VIF port
def get_vif_ports(self):
edge_ports = []
port_names = self.get_port_name_list()
for name in port_names:
- external_ids = self.db_get_map("Interface",name,"external_ids")
- if "xs-vm-uuid" in external_ids:
- p = xapi_get_port(name)
- if p is not None:
- edge_ports.append(p)
+ external_ids = self.db_get_map("Interface", name, "external_ids")
- if "iface-id" in external_ids and "attached-mac" in external_ids:
- ofport = self.db_get_val("Interface", name, "ofport")
- p = VifPort(name, ofport, external_ids["iface-id"],
- external_ids["attached-mac"], self)
- edge_ports.append(p)
- else:
- # iface-id might not be set. See if we can figure it out and
- # set it here.
- external_ids = self.db_get_map("Interface", name,
- "external_ids")
- if "attached-mac" not in external_ids:
- continue
- vif_uuid = external_ids.get("xs-vif-uuid", "")
- if len(vif_uuid) == 0:
- continue
- LOG.debug("iface-id not set, got vif-uuid: %s" % vif_uuid)
- res = os.popen("xe vif-param-get param-name=other-config "
- "uuid=%s | grep nicira-iface-id | "
- "awk '{print $2}'"
- % vif_uuid).readline()
- res = res.strip()
- if len(res) == 0:
- continue
- external_ids["iface-id"] = res
- LOG.info("Setting interface \"%s\" iface-id to \"%s\""
- % (name, res))
- self.set_db_attribute("Interface", name,
- "external-ids:iface-id", res)
++ if "xs-vm-uuid" in external_ids:
++ p = xapi_get_port(name)
++ if p is not None:
++ edge_ports.append(p)
+ elif "iface-id" in external_ids and "attached-mac" in external_ids:
- ofport = self.db_get_val("Interface",name,"ofport")
+ ofport = self.db_get_val("Interface", name, "ofport")
p = VifPort(name, ofport, external_ids["iface-id"],
- external_ids["attached-mac"], self)
+ external_ids["attached-mac"], self)
edge_ports.append(p)
return edge_ports
-class OVSNaaSPlugin:
+
+class OVSQuantumAgent:
++
def __init__(self, integ_br):
self.setup_integration_br(integ_br)
def port_bound(self, port, vlan_id):
- self.int_br.set_db_attribute("Port", port.port_name,"tag",
- str(vlan_id))
- self.int_br.delete_flows(match="in_port=%s" % port.ofport)
+ self.int_br.set_db_attribute("Port", port.port_name, "tag",
- str(vlan_id))
++ str(vlan_id))
++ self.int_br.delete_flows(match="in_port=%s" % port.ofport)
def port_unbound(self, port, still_exists):
if still_exists:
def setup_integration_br(self, integ_br):
self.int_br = OVSBridge(integ_br)
self.int_br.remove_all_flows()
- # drop all traffic on the 'dead vlan'
- self.int_br.add_flow(priority=2, match="dl_vlan=4095", actions="drop")
- # switch all other traffic using L2 learning
+ # switch all traffic using L2 learning
self.int_br.add_flow(priority=1, actions="normal")
- # FIXME send broadcast everywhere, regardless of tenant
- #int_br.add_flow(priority=3, match="dl_dst=ff:ff:ff:ff:ff:ff",
- # actions="normal")
-
def daemon_loop(self, conn):
self.local_vlan_map = {}
old_local_bindings = {}
new_local_bindings[p.vif_id] = all_bindings[p.vif_id]
else:
# no binding, put him on the 'dead vlan'
- % p.vif_id)
+ LOG.info("No binding for %s, setting to dead vlan" \
++ % p.vif_id)
self.int_br.set_db_attribute("Port", p.port_name, "tag",
- "4095")
- self.int_br.add_flow(priority=2,
- match="in_port=%s" % p.ofport, actions="drop")
- old_b = old_local_bindings.get(p.vif_id,None)
- new_b = new_local_bindings.get(p.vif_id,None)
- "4095")
++ "4095")
++ self.int_br.add_flow(priority=2,
++ match="in_port=%s" % p.ofport, actions="drop")
++
+ old_b = old_local_bindings.get(p.vif_id, None)
+ new_b = new_local_bindings.get(p.vif_id, None)
++
if old_b != new_b:
if old_b is not None:
LOG.info("Removing binding to net-id = %s for %s"
vlan_id = vlan_bindings.get(all_bindings[p.vif_id],
"4095")
self.port_bound(p, vlan_id)
- "for %s on vlan %s" % (new_b, str(p),vlan_id))
+ LOG.info("Adding binding to net-id = %s " \
++ "for %s on vlan %s" % (new_b, str(p), vlan_id))
for vif_id in old_vif_ports.keys():
if vif_id not in new_vif_ports:
LOG.info("Port Disappeared: %s" % vif_id)
except exc.NoResultFound:
pass
session.flush()
-
-
-def update_network_binding(netid, ifaceid):
- session = db.get_session()
- # Add to or delete from the bindings table
- if ifaceid == None:
- try:
- binding = session.query(ovs_models.NetworkBinding).\
- filter_by(network_id=netid).\
- one()
- session.delete(binding)
- except exc.NoResultFound:
- raise Exception("No binding found with network_id = %s" % netid)
- else:
- binding = ovs_models.NetworkBinding(netid, ifaceid)
- session.add(binding)
--
- session.flush()
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relation
-
from quantum.db.models import BASE
-class NetworkBinding(BASE):
- """Represents a binding of network_id, vif_id"""
- __tablename__ = 'network_bindings'
-
- id = Column(Integer, primary_key=True, autoincrement=True)
- network_id = Column(String(255))
- vif_id = Column(String(255))
-
- def __init__(self, network_id, vif_id):
- self.network_id = network_id
- self.vif_id = vif_id
-
- def __repr__(self):
- return "<NetworkBinding(%s,%s)>" % \
- (self.network_id, self.vif_id)
-
-
+
class VlanBinding(BASE):
"""Represents a binding of network_id, vlan_id"""
__tablename__ = 'vlan_bindings'
--- /dev/null
- "Example config-string: net1=instance-1,instance-2:net2=instance-3,instance-4\n" \
- "This string would create two networks: \n" \
- "'net1' would have two ports, with iface-ids instance-1 and instance-2 attached\n" \
- "'net2' would have two ports, with iface-ids instance-3 and instance-4 attached\n"
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2011 Nicira Networks, Inc.
+#
+# Licensed 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.
+# @author: Dan Wendlandt, Nicira Networks, Inc.
+
+import httplib
+import logging as LOG
+import json
+import socket
+import sys
+import urllib
+
+from quantum.manager import QuantumManager
+from optparse import OptionParser
+from quantum.common.wsgi import Serializer
+from quantum.cli import MiniClient
+
+FORMAT = "json"
+CONTENT_TYPE = "application/" + FORMAT
+
+
+if __name__ == "__main__":
+ usagestr = "Usage: %prog [OPTIONS] <tenant-id> <config-string> [args]\n" \
- tenant_id = args[0]
- if len(args) > 1:
- config_str = args[1]
- for net_str in config_str.split(":"):
- arr = net_str.split("=")
- net_name = arr[0]
- nets[net_name] = arr[1].split(",")
-
- print "nets: %s" % str(nets)
-
++ "Example config-string: net1=instance-1,instance-2"\
++ ":net2=instance-3,instance-4\n" \
++ "This string would create two networks: \n" \
++ "'net1' would have two ports, with iface-ids "\
++ "instance-1 and instance-2 attached\n" \
++ "'net2' would have two ports, with iface-ids"\
++ " instance-3 and instance-4 attached\n"
+ parser = OptionParser(usage=usagestr)
+ parser.add_option("-H", "--host", dest="host",
+ type="string", default="127.0.0.1", help="ip address of api host")
+ parser.add_option("-p", "--port", dest="port",
+ type="int", default=9696, help="api poort")
+ parser.add_option("-s", "--ssl", dest="ssl",
+ action="store_true", default=False, help="use ssl")
+ parser.add_option("-v", "--verbose", dest="verbose",
+ action="store_true", default=False, help="turn on verbose logging")
+
+ options, args = parser.parse_args()
+
+ if options.verbose:
+ LOG.basicConfig(level=LOG.DEBUG)
+ else:
+ LOG.basicConfig(level=LOG.WARN)
+
+ if len(args) < 1:
+ parser.print_help()
+ help()
+ sys.exit(1)
+
+ nets = {}
-
++ tenant_id = args[0]
++ if len(args) > 1:
++ config_str = args[1]
++ for net_str in config_str.split(":"):
++ arr = net_str.split("=")
++ net_name = arr[0]
++ nets[net_name] = arr[1].split(",")
++
++ print "nets: %s" % str(nets)
++
+ client = MiniClient(options.host, options.port, options.ssl)
- res = client.do_request(tenant_id, 'GET',
- "/networks/%s/ports.%s" % (nid, FORMAT))
- output = res.read()
- if res.status != 200:
- LOG.error("Failed to list ports: %s" % output)
- continue
- rd = json.loads(output)
- LOG.debug(rd)
- for port in rd["ports"]:
- pid = port["id"]
- res = client.do_request(tenant_id, 'DELETE',
- "/networks/%s/ports/%s.%s" % (nid, pid, FORMAT))
- output = res.read()
- if res.status != 202:
- LOG.error("Failed to delete port: %s" % output)
- continue
- LOG.info("Deleted Virtual Port:%s " \
- "on Virtual Network:%s" % (pid, nid))
-
-
- res = client.do_request(tenant_id, 'DELETE', "/networks/" + nid + "." + FORMAT)
- status = res.status
- if status != 202:
- print "Failed to delete network: %s" % nid
- output = res.read()
- print output
- else:
- print "Deleted Virtual Network with ID:%s" % nid
-
- for net_name, iface_ids in nets.items():
- data = {'network': {'network-name': '%s' % net_name}}
- body = Serializer().serialize(data, CONTENT_TYPE)
- res = client.do_request(tenant_id, 'POST',
- "/networks." + FORMAT, body=body)
- rd = json.loads(res.read())
- LOG.debug(rd)
++
+ res = client.do_request(tenant_id, 'GET', "/networks." + FORMAT)
+ resdict = json.loads(res.read())
+ LOG.debug(resdict)
+ for n in resdict["networks"]:
+ nid = n["id"]
+
- print "Created a new Virtual Network %s with ID:%s\n" % (net_name,nid)
- for iface_id in iface_ids:
- res = client.do_request(tenant_id, 'POST',
- "/networks/%s/ports.%s" % (nid, FORMAT))
- output = res.read()
- if res.status != 200:
- LOG.error("Failed to create port: %s" % output)
- continue
- rd = json.loads(output)
- new_port_id = rd["ports"]["port"]["id"]
- print "Created Virtual Port:%s " \
- "on Virtual Network:%s" % (new_port_id, nid)
- data = {'port': {'attachment-id': '%s' % iface_id}}
- body = Serializer().serialize(data, CONTENT_TYPE)
- res = client.do_request(tenant_id, 'PUT',
- "/networks/%s/ports/%s/attachment.%s" % (nid, new_port_id, FORMAT), body=body)
- output = res.read()
- LOG.debug(output)
- if res.status != 202:
- LOG.error("Failed to plug iface \"%s\" to port \"%s\": %s" % (iface_id,new_port_id, output))
- continue
- print "Plugged interface \"%s\" to port:%s on network:%s" % (iface_id, new_port_id, nid)
-
++ res = client.do_request(tenant_id, 'GET',
++ "/networks/%s/ports.%s" % (nid, FORMAT))
++ output = res.read()
++ if res.status != 200:
++ LOG.error("Failed to list ports: %s" % output)
++ continue
++ rd = json.loads(output)
++ LOG.debug(rd)
++ for port in rd["ports"]:
++ pid = port["id"]
++ res = client.do_request(tenant_id, 'DELETE',
++ "/networks/%s/ports/%s.%s" % (nid, pid, FORMAT))
++ output = res.read()
++ if res.status != 202:
++ LOG.error("Failed to delete port: %s" % output)
++ continue
++ LOG.info("Deleted Virtual Port:%s " \
++ "on Virtual Network:%s" % (pid, nid))
++
++ res = client.do_request(tenant_id, 'DELETE',
++ "/networks/" + nid + "." + FORMAT)
++ status = res.status
++ if status != 202:
++ print "Failed to delete network: %s" % nid
++ output = res.read()
++ print output
++ else:
++ print "Deleted Virtual Network with ID:%s" % nid
++
++ for net_name, iface_ids in nets.items():
++ data = {'network': {'network-name': '%s' % net_name}}
++ body = Serializer().serialize(data, CONTENT_TYPE)
++ res = client.do_request(tenant_id, 'POST',
++ "/networks." + FORMAT, body=body)
++ rd = json.loads(res.read())
++ LOG.debug(rd)
+ nid = rd["networks"]["network"]["id"]
++ print "Created a new Virtual Network %s with ID:%s\n" % (net_name, nid)
++
++ for iface_id in iface_ids:
++ res = client.do_request(tenant_id, 'POST',
++ "/networks/%s/ports.%s" % (nid, FORMAT))
++ output = res.read()
++ if res.status != 200:
++ LOG.error("Failed to create port: %s" % output)
++ continue
++ rd = json.loads(output)
++ new_port_id = rd["ports"]["port"]["id"]
++ print "Created Virtual Port:%s " \
++ "on Virtual Network:%s" % (new_port_id, nid)
++ data = {'port': {'attachment-id': '%s' % iface_id}}
++ body = Serializer().serialize(data, CONTENT_TYPE)
++ res = client.do_request(tenant_id, 'PUT',
++ "/networks/%s/ports/%s/attachment.%s" %\
++ (nid, new_port_id, FORMAT), body=body)
++ output = res.read()
++ LOG.debug(output)
++ if res.status != 202:
++ LOG.error("Failed to plug iface \"%s\" to port \"%s\": %s" % \
++ (iface_id, new_port_id, output))
++ continue
++ print "Plugged interface \"%s\" to port:%s on network:%s" % \
++ (iface_id, new_port_id, nid)
++
+ sys.exit(0)