aboutsummaryrefslogtreecommitdiffstats
path: root/emulators/py-nova
diff options
context:
space:
mode:
authornovel <novel@FreeBSD.org>2016-12-18 14:30:58 +0800
committernovel <novel@FreeBSD.org>2016-12-18 14:30:58 +0800
commit5cd571fce2370f3b35dd7eb241dc5e8c7b43e8f4 (patch)
tree55bfb76270b1d02dea6f42d78e0c7b0c20fe637d /emulators/py-nova
parentb7437dc88ef9ee693e676aa457b38aa98cff2a45 (diff)
downloadfreebsd-ports-gnome-5cd571fce2370f3b35dd7eb241dc5e8c7b43e8f4.tar.gz
freebsd-ports-gnome-5cd571fce2370f3b35dd7eb241dc5e8c7b43e8f4.tar.zst
freebsd-ports-gnome-5cd571fce2370f3b35dd7eb241dc5e8c7b43e8f4.zip
Add emulators/py-nova 14.0.2, Openstack Compute Service
Please note that this is a development version of nova. Many features are not available. Currently nova works on FreeBSD 11 and supports QEMU and Xen. Common issues: - Security groups are not implemented - ARP spoofing, DHCP isolation protection are not implemented - Nova services work from the root user - No IPv6 support QEMU issues: - Need to enable serialconsole (TCP) - Need to disable online CPU tracking - Cannot mount cinder volumes Xen issues: - Live snapshots don't work - No support for cinder volume hot-plugging - XENBUS delay (5 min) when using qemu driver and COW images - Some Linux images cannot be booted For further FreeBSD specific notes please refer to port's pkg-message. PR: 215151 Submitted by: Alexander Nusov (alexander.nusov@nfvexpress.com)
Diffstat (limited to 'emulators/py-nova')
-rw-r--r--emulators/py-nova/Makefile141
-rw-r--r--emulators/py-nova/distinfo3
-rw-r--r--emulators/py-nova/files/01-firewall-manager.patch60
-rw-r--r--emulators/py-nova/files/02-freebsd-l3.patch90
-rw-r--r--emulators/py-nova/files/03-nova-conf.patch51
-rw-r--r--emulators/py-nova/files/04-xen-phy.patch42
-rw-r--r--emulators/py-nova/files/05-online-cpus.patch63
-rw-r--r--emulators/py-nova/files/06-freebsd-net.patch1245
-rw-r--r--emulators/py-nova/files/nova-api.in53
-rw-r--r--emulators/py-nova/files/nova-cells.in53
-rw-r--r--emulators/py-nova/files/nova-cert.in53
-rw-r--r--emulators/py-nova/files/nova-compute.conf.sample15
-rw-r--r--emulators/py-nova/files/nova-compute.in53
-rw-r--r--emulators/py-nova/files/nova-conductor.in53
-rw-r--r--emulators/py-nova/files/nova-consoleauth.in53
-rw-r--r--emulators/py-nova/files/nova-network.in53
-rw-r--r--emulators/py-nova/files/nova-scheduler.in53
-rw-r--r--emulators/py-nova/files/nova-serialproxy.in53
-rw-r--r--emulators/py-nova/files/nova.conf.sample80
-rw-r--r--emulators/py-nova/pkg-descr5
-rw-r--r--emulators/py-nova/pkg-message47
-rw-r--r--emulators/py-nova/pkg-plist18
22 files changed, 2337 insertions, 0 deletions
diff --git a/emulators/py-nova/Makefile b/emulators/py-nova/Makefile
new file mode 100644
index 000000000000..bf8db9b6e010
--- /dev/null
+++ b/emulators/py-nova/Makefile
@@ -0,0 +1,141 @@
+# Created by: Alexander Nusov <alexander.nusov@nfvexpress.com>
+# $FreeBSD$
+
+PORTNAME= nova
+PORTVERSION= 14.0.2
+CATEGORIES= emulators python
+MASTER_SITES= https://fossies.org/linux/misc/openstack/
+PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX}
+
+MAINTAINER= alexander.nusov@nfvexpress.com
+COMMENT= OpenStack compute service
+
+LICENSE= APACHE20
+
+BUILD_DEPENDS= ${PYTHON_PKGNAMEPREFIX}pbr>=1.6:devel/py-pbr
+
+RUN_DEPENDS:= ${BUILD_DEPENDS}
+RUN_DEPENDS+= ${PYTHON_PKGNAMEPREFIX}sqlalchemy10>=0:databases/py-sqlalchemy10 \
+ ${PYTHON_PKGNAMEPREFIX}boto>=2.32.1:devel/py-boto \
+ ${PYTHON_PKGNAMEPREFIX}decorator>=3.4.0:devel/py-decorator \
+ ${PYTHON_PKGNAMEPREFIX}eventlet>=0:net/py-eventlet \
+ ${PYTHON_PKGNAMEPREFIX}Jinja2>=2.8:devel/py-Jinja2 \
+ ${PYTHON_PKGNAMEPREFIX}keystonemiddleware>=0:devel/py-keystonemiddleware \
+ ${PYTHON_PKGNAMEPREFIX}lxml>=2.3:devel/py-lxml \
+ ${PYTHON_PKGNAMEPREFIX}routes>=0:www/py-routes \
+ ${PYTHON_PKGNAMEPREFIX}cryptography>=0:security/py-cryptography \
+ ${PYTHON_PKGNAMEPREFIX}webob>=1.2.3:www/py-webob \
+ ${PYTHON_PKGNAMEPREFIX}greenlet>=0.3.2:devel/py-greenlet \
+ ${PYTHON_PKGNAMEPREFIX}PasteDeploy>=1.5.0:www/py-pastedeploy \
+ ${PYTHON_PKGNAMEPREFIX}Paste>=0:www/py-paste \
+ ${PYTHON_PKGNAMEPREFIX}prettytable>=0:devel/py-prettytable \
+ ${PYTHON_PKGNAMEPREFIX}sqlalchemy-migrate>=0.9.6:databases/py-sqlalchemy-migrate \
+ ${PYTHON_PKGNAMEPREFIX}netaddr>=0:net/py-netaddr \
+ ${PYTHON_PKGNAMEPREFIX}netifaces>=0.10.4:net/py-netifaces \
+ ${PYTHON_PKGNAMEPREFIX}paramiko>=2.0:security/py-paramiko \
+ ${PYTHON_PKGNAMEPREFIX}Babel>=2.3.4:devel/py-babel \
+ ${PYTHON_PKGNAMEPREFIX}iso8601>=0.1.11:devel/py-iso8601 \
+ ${PYTHON_PKGNAMEPREFIX}jsonschema>=0:devel/py-jsonschema \
+ ${PYTHON_PKGNAMEPREFIX}python-cinderclient>=0:net/py-python-cinderclient \
+ ${PYTHON_PKGNAMEPREFIX}keystoneauth1>=2.10.0:devel/py-keystoneauth1 \
+ ${PYTHON_PKGNAMEPREFIX}python-neutronclient>=5.1.0:net/py-python-neutronclient \
+ ${PYTHON_PKGNAMEPREFIX}python-glanceclient>=0:net/py-python-glanceclient \
+ ${PYTHON_PKGNAMEPREFIX}requests>=2.10.0:www/py-requests \
+ ${PYTHON_PKGNAMEPREFIX}six>=1.9.0:devel/py-six \
+ ${PYTHON_PKGNAMEPREFIX}stevedore>=1.16.0:devel/py-stevedore \
+ ${PYTHON_PKGNAMEPREFIX}websockify>=0.8.0:devel/py-websockify \
+ ${PYTHON_PKGNAMEPREFIX}oslo.cache>=1.5.0:devel/py-oslo.cache \
+ ${PYTHON_PKGNAMEPREFIX}oslo.concurrency>=3.8.0:devel/py-oslo.concurrency \
+ ${PYTHON_PKGNAMEPREFIX}oslo.config>=3.14.0:devel/py-oslo.config \
+ ${PYTHON_PKGNAMEPREFIX}oslo.context>=2.9.0:devel/py-oslo.context \
+ ${PYTHON_PKGNAMEPREFIX}oslo.log>=1.14.0:devel/py-oslo.log \
+ ${PYTHON_PKGNAMEPREFIX}oslo.reports>=0.6.0:devel/py-oslo.reports \
+ ${PYTHON_PKGNAMEPREFIX}oslo.serialization>=1.10.0:devel/py-oslo.serialization \
+ ${PYTHON_PKGNAMEPREFIX}oslo.utils>=3.16.0:devel/py-oslo.utils \
+ ${PYTHON_PKGNAMEPREFIX}oslo.db>=0:devel/py-oslo.db \
+ ${PYTHON_PKGNAMEPREFIX}oslo.rootwrap>=5.0.0:devel/py-oslo.rootwrap \
+ ${PYTHON_PKGNAMEPREFIX}oslo.messaging>=5.2.0:devel/py-oslo.messaging \
+ ${PYTHON_PKGNAMEPREFIX}oslo.policy>=1.9.0:devel/py-oslo.policy \
+ ${PYTHON_PKGNAMEPREFIX}oslo.privsep>=1.9.0:devel/py-oslo.privsep \
+ ${PYTHON_PKGNAMEPREFIX}oslo.i18n>=2.1.0:devel/py-oslo.i18n \
+ ${PYTHON_PKGNAMEPREFIX}oslo.service>=1.10.0:devel/py-oslo.service \
+ ${PYTHON_PKGNAMEPREFIX}rfc3986>=0.2.2:www/py-rfc3986 \
+ ${PYTHON_PKGNAMEPREFIX}oslo.middleware>=3.0.0:devel/py-oslo.middleware \
+ ${PYTHON_PKGNAMEPREFIX}psutil121>=0:sysutils/py-psutil121 \
+ ${PYTHON_PKGNAMEPREFIX}oslo.versionedobjects>=1.13.0:devel/py-oslo.versionedobjects \
+ ${PYTHON_PKGNAMEPREFIX}os-brick>=1.6.1:devel/py-os-brick \
+ ${PYTHON_PKGNAMEPREFIX}os-vif>=1.1.0:devel/py-os-vif \
+ ${PYTHON_PKGNAMEPREFIX}os-win>=0.2.3:devel/py-os-win \
+ ${PYTHON_PKGNAMEPREFIX}castellan>=0.4.0:devel/py-castellan \
+ ${PYTHON_PKGNAMEPREFIX}microversion-parse>=0.1.2:devel/py-microversion-parse \
+ ${PYTHON_PKGNAMEPREFIX}wsgi_intercept>=0.6.1:devel/py-wsgi_intercept \
+ ${PYTHON_PKGNAMEPREFIX}sqlparse>=0:databases/py-sqlparse \
+ ${PYTHON_PKGNAMEPREFIX}libvirt>=0:devel/py-libvirt \
+ e2fsprogs>=0:sysutils/e2fsprogs \
+ arping>=0:net/arping
+
+EXTRA_PATCHES= ${FILESDIR}/01-firewall-manager.patch:-p1 \
+ ${FILESDIR}/02-freebsd-l3.patch:-p1 \
+ ${FILESDIR}/03-nova-conf.patch:-p1 \
+ ${FILESDIR}/04-xen-phy.patch:-p1 \
+ ${FILESDIR}/05-online-cpus.patch:-p1 \
+ ${FILESDIR}/06-freebsd-net.patch:-p1
+
+ONLY_FOR_ARCHS= amd64
+
+USES= python
+USE_PYTHON= autoplist distutils noegginfo
+
+USE_RC_SUBR= nova-api \
+ nova-consoleauth \
+ nova-conductor \
+ nova-scheduler \
+ nova-network \
+ nova-compute \
+ nova-cert \
+ nova-cells \
+ nova-serialproxy
+USERS= nova
+GROUPS= nova
+
+.include <bsd.port.options.mk>
+
+.if ${OPSYS} != FreeBSD
+IGNORE= only supported on FreeBSD
+.endif
+
+.if ${OSVERSION} < 1100055
+IGNORE= only supported on recent FreeBSD 11
+.endif
+
+post-extract:
+ @(cd ${WRKSRC}/etc/nova; ${MV} logging_sample.conf logging.conf.sample)
+ @(cd ${WRKSRC}/etc/nova; for f in *.conf; do ${MV} $${f} $${f}.sample; done)
+
+post-patch:
+ ${CP} ${FILESDIR}/nova.conf.sample \
+ ${WRKSRC}/etc/nova/nova.conf.sample
+ ${CP} ${FILESDIR}/nova-compute.conf.sample \
+ ${WRKSRC}/etc/nova/nova-compute.conf.sample
+ ${REINPLACE_CMD} -e "s|/etc|${PREFIX}/etc|g" \
+ ${WRKSRC}/nova/api/openstack/placement/wsgi.py \
+ ${WRKSRC}/nova/conf/base.py \
+ ${WRKSRC}/nova/conf/cloudpipe.py \
+ ${WRKSRC}/nova/conf/network.py \
+ ${WRKSRC}/nova/conf/remote_debug.py \
+ ${WRKSRC}/nova/conf/xvp.py \
+ ${WRKSRC}/nova/hacking/checks.py \
+ ${WRKSRC}/nova/network/linux_net.py \
+ ${WRKSRC}/nova/network/manager.py \
+ ${WRKSRC}/nova/virt/disk/api.py \
+ ${WRKSRC}/nova/virt/disk/vfs/guestfs.py \
+ ${WRKSRC}/nova/virt/libvirt/driver.py \
+ ${WRKSRC}/nova/virt/xenapi/agent.py \
+ ${WRKSRC}/nova/wsgi/nova-api.py \
+ ${WRKSRC}/nova/wsgi/nova-metadata.py
+
+post-install:
+ ${MKDIR} ${STAGEDIR}${ETCDIR}
+ ${CP} -R ${WRKSRC}/etc/nova/ ${STAGEDIR}${ETCDIR}
+
+.include <bsd.port.mk>
diff --git a/emulators/py-nova/distinfo b/emulators/py-nova/distinfo
new file mode 100644
index 000000000000..584c6e6b86c7
--- /dev/null
+++ b/emulators/py-nova/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1478994869
+SHA256 (nova-14.0.2.tar.gz) = e98291734b4b16615fb1518161c89749f09ad33b6344feb70d62b69e8161a50d
+SIZE (nova-14.0.2.tar.gz) = 5574197
diff --git a/emulators/py-nova/files/01-firewall-manager.patch b/emulators/py-nova/files/01-firewall-manager.patch
new file mode 100644
index 000000000000..6af08d977c4d
--- /dev/null
+++ b/emulators/py-nova/files/01-firewall-manager.patch
@@ -0,0 +1,60 @@
+From 60668a502b5f7af77861507e94a89b7f4201c2cb Mon Sep 17 00:00:00 2001
+From: Alexander Nusov <alexander.nusov@nfvexpress.com>
+Date: Tue, 8 Nov 2016 16:52:29 +0300
+Subject: [PATCH] add get_firewall_manager
+
+---
+ nova/network/linux_net.py | 4 ++++
+ nova/network/manager.py | 8 ++++----
+ 2 files changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/nova/network/linux_net.py b/nova/network/linux_net.py
+index b10fa28..2637e26 100644
+--- a/nova/network/linux_net.py
++++ b/nova/network/linux_net.py
+@@ -1898,3 +1898,7 @@ def set_vf_interface_vlan(pci_addr, mac_addr, vlan=0):
+ port_state,
+ run_as_root=True,
+ check_exit_code=exit_code)
++
++
++def get_firewall_manager():
++ return iptables_manager
+diff --git a/nova/network/manager.py b/nova/network/manager.py
+index 9de53d9..f6eb106 100644
+--- a/nova/network/manager.py
++++ b/nova/network/manager.py
+@@ -1799,13 +1799,13 @@ class FlatDHCPManager(RPCAllocateFixedIP, floating_ips.FloatingIP,
+ ctxt = context.get_admin_context()
+ networks = objects.NetworkList.get_by_host(ctxt, self.host)
+
+- self.driver.iptables_manager.defer_apply_on()
++ self.driver.get_firewall_manager().defer_apply_on()
+
+ self.l3driver.initialize(fixed_range=False, networks=networks)
+ super(FlatDHCPManager, self).init_host()
+ self.init_host_floating_ips()
+
+- self.driver.iptables_manager.defer_apply_off()
++ self.driver.get_firewall_manager().defer_apply_off()
+
+ def _setup_network_on_host(self, context, network):
+ """Sets up network on this host."""
+@@ -1887,13 +1887,13 @@ class VlanManager(RPCAllocateFixedIP, floating_ips.FloatingIP, NetworkManager):
+ ctxt = context.get_admin_context()
+ networks = objects.NetworkList.get_by_host(ctxt, self.host)
+
+- self.driver.iptables_manager.defer_apply_on()
++ self.driver.get_firewall_manager().defer_apply_on()
+
+ self.l3driver.initialize(fixed_range=False, networks=networks)
+ NetworkManager.init_host(self)
+ self.init_host_floating_ips()
+
+- self.driver.iptables_manager.defer_apply_off()
++ self.driver.get_firewall_manager().defer_apply_off()
+
+ def allocate_fixed_ip(self, context, instance_id, network, **kwargs):
+ """Gets a fixed IP from the pool."""
+--
+2.8.1
diff --git a/emulators/py-nova/files/02-freebsd-l3.patch b/emulators/py-nova/files/02-freebsd-l3.patch
new file mode 100644
index 000000000000..61677b3b6aed
--- /dev/null
+++ b/emulators/py-nova/files/02-freebsd-l3.patch
@@ -0,0 +1,90 @@
+From 2e4a0e0a2588c4d52495fad8105aa1a4609797f6 Mon Sep 17 00:00:00 2001
+From: Alexander Nusov <alexander.nusov@nfvexpress.com>
+Date: Tue, 8 Nov 2016 16:50:56 +0300
+Subject: [PATCH] add freebsd l3 driver
+
+---
+ nova/network/l3.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 61 insertions(+)
+
+diff --git a/nova/network/l3.py b/nova/network/l3.py
+index c13e6e2..a5982d5 100644
+--- a/nova/network/l3.py
++++ b/nova/network/l3.py
+@@ -16,6 +16,7 @@
+ from oslo_log import log as logging
+
+ from nova.network import linux_net
++from nova.network import freebsd_net
+ from nova import utils
+
+ LOG = logging.getLogger(__name__)
+@@ -134,6 +135,66 @@ class LinuxNetL3(L3Driver):
+ pass
+
+
++class FreeBSDNetL3(L3Driver):
++ """L3 driver that uses freebsd_net as the backend."""
++ def __init__(self):
++ self.initialized = False
++
++ def initialize(self, **kwargs):
++ if self.initialized:
++ return
++ LOG.debug("Initializing freebsd_net L3 driver")
++ fixed_range = kwargs.get('fixed_range', False)
++ networks = kwargs.get('networks', None)
++ if not fixed_range and networks is not None:
++ for network in networks:
++ if network['enable_dhcp']:
++ is_ext = (network['dhcp_server'] is not None and
++ network['dhcp_server'] != network['gateway'])
++ self.initialize_network(network['cidr'], is_ext)
++ freebsd_net.ensure_metadata_ip()
++ freebsd_net.metadata_forward()
++ self.initialized = True
++
++ def is_initialized(self):
++ return self.initialized
++
++ def initialize_network(self, cidr, is_external):
++ freebsd_net.init_host(cidr, is_external)
++
++ def initialize_gateway(self, network_ref):
++ mac_address = utils.generate_mac_address()
++ dev = freebsd_net.plug(network_ref, mac_address,
++ gateway=(network_ref['gateway'] is not None))
++ freebsd_net.initialize_gateway_device(dev, network_ref)
++
++ def remove_gateway(self, network_ref):
++ freebsd_net.unplug(network_ref)
++
++ def add_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
++ network=None):
++ freebsd_net.ensure_floating_forward(floating_ip, fixed_ip,
++ l3_interface_id, network)
++ freebsd_net.bind_floating_ip(floating_ip, l3_interface_id)
++
++ def remove_floating_ip(self, floating_ip, fixed_ip, l3_interface_id,
++ network=None):
++ freebsd_net.unbind_floating_ip(floating_ip, l3_interface_id)
++ freebsd_net.remove_floating_forward(floating_ip, fixed_ip,
++ l3_interface_id, network)
++ freebsd_net.clean_conntrack(fixed_ip)
++
++ def add_vpn(self, public_ip, port, private_ip):
++ freebsd_net.ensure_vpn_forward(public_ip, port, private_ip)
++
++ def remove_vpn(self, public_ip, port, private_ip):
++ # FreeBSD net currently doesn't implement any way of removing
++ # the VPN forwarding rules
++ pass
++
++ def teardown(self):
++ pass
++
+ class NullL3(L3Driver):
+ """The L3 driver that doesn't do anything. This class can be used when
+ nova-network should not manipulate L3 forwarding at all (e.g., in a Flat
+--
+2.8.1
diff --git a/emulators/py-nova/files/03-nova-conf.patch b/emulators/py-nova/files/03-nova-conf.patch
new file mode 100644
index 000000000000..8aa0edb08c87
--- /dev/null
+++ b/emulators/py-nova/files/03-nova-conf.patch
@@ -0,0 +1,51 @@
+diff --git a/nova/conf/network.py b/nova/conf/network.py
+index 3bb4cd9..eb57041 100644
+--- a/nova/conf/network.py
++++ b/nova/conf/network.py
+@@ -704,6 +704,30 @@ Related options:
+ """),
+ ]
+
++freebsd_net_opts = [
++ cfg.StrOpt("freebsdnet_interface_driver",
++ default="nova.network.freebsd.FreeBSDBridgeInterfaceDriver",
++ help="""
++This is the class used as the ethernet device driver for freebsdnet bridge
++operations. The default value should be all you need for most cases, but if you
++wish to use a customized class, set this option to the full dot-separated
++import path for that class.
++
++Possible values:
++
++ Any string representing a dot-separated class path that Nova can import.
++"""),
++ cfg.StrOpt("freebsdnet_ovs_integration_bridge",
++ default="br-int",
++ help="""
++The name of the Open vSwitch bridge that is used with freebsdnet when connecting
++with Open vSwitch."
++
++Possible values:
++
++ Any string representing a valid bridge name.
++"""),
++]
+
+ ldap_dns_opts = [
+ cfg.StrOpt('ldap_dns_url',
+@@ -766,12 +790,13 @@ by using this option.
+ 'some rpc network calls will be sent directly to host.'),
+ ]
+
+-ALL_DEFAULT_OPTS = (linux_net_opts + network_opts + ldap_dns_opts
++ALL_DEFAULT_OPTS = (linux_net_opts + freebsd_net_opts + network_opts + ldap_dns_opts
+ + rpcapi_opts + driver_opts)
+
+
+ def register_opts(conf):
+ conf.register_opts(linux_net_opts)
++ conf.register_opts(freebsd_net_opts)
+ conf.register_opts(network_opts)
+ conf.register_opts(ldap_dns_opts)
+ conf.register_opts(driver_opts)
+
diff --git a/emulators/py-nova/files/04-xen-phy.patch b/emulators/py-nova/files/04-xen-phy.patch
new file mode 100644
index 000000000000..84b4a07975c9
--- /dev/null
+++ b/emulators/py-nova/files/04-xen-phy.patch
@@ -0,0 +1,42 @@
+From b4e9024ac90ed0eaf155bc24ef7ee3b01112366e Mon Sep 17 00:00:00 2001
+From: Alexander Nusov <alexander.nusov@nfvexpress.com>
+Date: Tue, 15 Nov 2016 13:08:49 +0300
+Subject: [PATCH] foce xen phy option
+
+---
+ nova/conf/libvirt.py | 3 +++
+ nova/virt/libvirt/utils.py | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py
+index bfb278e..2eba080 100644
+--- a/nova/conf/libvirt.py
++++ b/nova/conf/libvirt.py
+@@ -498,6 +498,9 @@ libvirt_imagebackend_opts = [
+ help='Discard option for nova managed disks. Need'
+ ' Libvirt(1.0.6) Qemu1.5 (raw format) Qemu1.6(qcow2'
+ ' format)'),
++ cfg.BoolOpt('force_xen_phy',
++ default=False,
++ help='Force using of PHY driver in Xen'),
+ ]
+
+ libvirt_imagecache_opts = [
+diff --git a/nova/virt/libvirt/utils.py b/nova/virt/libvirt/utils.py
+index f0a4796..ff68d45 100644
+--- a/nova/virt/libvirt/utils.py
++++ b/nova/virt/libvirt/utils.py
+@@ -112,7 +112,7 @@ def pick_disk_driver_name(hypervisor_version, is_block_dev=False):
+ :returns: driver_name or None
+ """
+ if CONF.libvirt.virt_type == "xen":
+- if is_block_dev:
++ if is_block_dev or CONF.libvirt.force_xen_phy:
+ return "phy"
+ else:
+ # 4002000 == 4.2.0
+--
+2.8.1
+
+
+
diff --git a/emulators/py-nova/files/05-online-cpus.patch b/emulators/py-nova/files/05-online-cpus.patch
new file mode 100644
index 000000000000..ecc4523e0a34
--- /dev/null
+++ b/emulators/py-nova/files/05-online-cpus.patch
@@ -0,0 +1,63 @@
+From 8eb8fb92f21243ae0e41f2f626398d09582de29b Mon Sep 17 00:00:00 2001
+From: Alexander Nusov <alexander.nusov@nfvexpress.com>
+Date: Fri, 25 Nov 2016 17:36:10 +0300
+Subject: [PATCH] add online cpu tracking option
+
+---
+ nova/conf/libvirt.py | 3 +++
+ nova/virt/libvirt/driver.py | 18 +++++++++++-------
+ 2 files changed, 14 insertions(+), 7 deletions(-)
+
+diff --git a/nova/conf/libvirt.py b/nova/conf/libvirt.py
+index 2eba080..d133b03 100644
+--- a/nova/conf/libvirt.py
++++ b/nova/conf/libvirt.py
+@@ -471,6 +471,9 @@ events`, refer https://libvirt.org/formatdomain.html#elementsPerf .
+ None
+
+ """),
++ cfg.BoolOpt('online_cpu_tracking',
++ default=True,
++ help='Enable online cpu tracking'),
+ ]
+
+ libvirt_imagebackend_opts = [
+diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py
+index f9225de..f19ef70 100644
+--- a/nova/virt/libvirt/driver.py
++++ b/nova/virt/libvirt/driver.py
+@@ -5188,11 +5188,12 @@ class LibvirtDriver(driver.ComputeDriver):
+
+ cells = []
+ allowed_cpus = hardware.get_vcpu_pin_set()
+- online_cpus = self._host.get_online_cpus()
+- if allowed_cpus:
+- allowed_cpus &= online_cpus
+- else:
+- allowed_cpus = online_cpus
++ if CONF.libvirt.online_cpu_tracking:
++ online_cpus = self._host.get_online_cpus()
++ if allowed_cpus:
++ allowed_cpus &= online_cpus
++ else:
++ allowed_cpus = online_cpus
+
+ def _get_reserved_memory_for_cell(self, cell_id, page_size):
+ cell = self._reserved_hugepages.get(cell_id, {})
+@@ -5205,8 +5206,11 @@ class LibvirtDriver(driver.ComputeDriver):
+ if cpu.siblings else ()
+ for cpu in cell.cpus)
+ ))
+- cpuset &= allowed_cpus
+- siblings = [sib & allowed_cpus for sib in siblings]
++ if CONF.libvirt.online_cpu_tracking or allowed_cpus:
++ cpuset &= allowed_cpus
++ siblings = [sib & allowed_cpus for sib in siblings]
++
++
+ # Filter out singles and empty sibling sets that may be left
+ siblings = [sib for sib in siblings if len(sib) > 1]
+
+--
+2.8.1
+
diff --git a/emulators/py-nova/files/06-freebsd-net.patch b/emulators/py-nova/files/06-freebsd-net.patch
new file mode 100644
index 000000000000..365347e7e25c
--- /dev/null
+++ b/emulators/py-nova/files/06-freebsd-net.patch
@@ -0,0 +1,1245 @@
+From 2dd71331d4d204466e7b066f62952990e55c2e24 Mon Sep 17 00:00:00 2001
+From: Alexander Nusov <alexander.nusov@nfvexpress.com>
+Date: Tue, 29 Nov 2016 14:21:41 +0300
+Subject: [PATCH] add freebsd_net driver
+
+---
+ nova/network/freebsd_net.py | 1226 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 1226 insertions(+)
+ create mode 100644 nova/network/freebsd_net.py
+
+diff --git a/nova/network/freebsd_net.py b/nova/network/freebsd_net.py
+new file mode 100644
+index 0000000..b71fcf6
+--- /dev/null
++++ b/nova/network/freebsd_net.py
+@@ -0,0 +1,1226 @@
++# Copyright (c) 2011 X.commerce, a business unit of eBay Inc.
++# Copyright 2010 United States Government as represented by the
++# Administrator of the National Aeronautics and Space Administration.
++# All Rights Reserved.
++#
++# 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.
++
++"""Implements vlans, bridges, and iptables rules using linux utilities."""
++
++import calendar
++import inspect
++import os
++import re
++import time
++import json
++
++import netaddr
++import netifaces
++import socket
++import struct
++
++from oslo_concurrency import processutils
++from oslo_log import log as logging
++from oslo_serialization import jsonutils
++from oslo_utils import excutils
++from oslo_utils import fileutils
++from oslo_utils import importutils
++from oslo_utils import timeutils
++import six
++
++import nova.conf
++from nova import exception
++from nova.i18n import _, _LE, _LW
++from nova.network import model as network_model
++from nova import objects
++from nova.pci import utils as pci_utils
++from nova import utils
++
++LOG = logging.getLogger(__name__)
++
++
++CONF = nova.conf.CONF
++
++
++# NOTE(vish): Iptables supports chain names of up to 28 characters, and we
++# add up to 12 characters to binary_name which is used as a prefix,
++# so we limit it to 16 characters.
++# (max_chain_name_length - len('-POSTROUTING') == 16)
++def get_binary_name():
++ """Grab the name of the binary we're running in."""
++ return os.path.basename(inspect.stack()[-1][1])[:16]
++
++binary_name = get_binary_name()
++
++
++# NOTE(jkoelker) This is just a nice little stub point since mocking
++# builtins with mox is a nightmare
++def write_to_file(file, data, mode='w'):
++ with open(file, mode) as f:
++ f.write(data)
++
++
++def is_pid_cmdline_correct(pid, match):
++ """Ensure that the cmdline for a pid seems sane
++
++ Because pids are recycled, blindly killing by pid is something to
++ avoid. This provides the ability to include a substring that is
++ expected in the cmdline as a safety check.
++ """
++ try:
++ with open('/proc/%d/cmdline' % pid) as f:
++ cmdline = f.read()
++ return match in cmdline
++ except EnvironmentError:
++ return False
++
++
++def metadata_forward():
++ """Create forwarding rule for metadata."""
++ firewall_manager.add_rule("rdr proto tcp from any to 169.254.169.254 "
++ "port 80 -> %s port %s" %
++ (CONF.metadata_host, CONF.metadata_port))
++ firewall_manager.add_rule("pass out route-to (lo0 127.0.0.1) proto tcp "
++ "from any to 169.254.169.254 port 80")
++ firewall_manager.apply()
++
++
++def metadata_accept():
++ """Create the filter accept rule for metadata."""
++ firewall_manager.add_rule("pass in inet proto tcp from any to "
++ "169.254.169.254 port = http "
++ "flags S/SA keep state")
++ firewall_manager.apply()
++
++
++def init_host(ip_range, is_external=False):
++ """Basic networking setup goes here."""
++ # NOTE(devcamcar): Cloud public SNAT entries and the default
++ # SNAT rule for outbound traffic.
++
++ firewall_manager.add_snat_rule(ip_range, is_external)
++ if is_external:
++ for snat_range in CONF.force_snat_range:
++ firewall_manager.add_rule("pass quick inet from %s to %s" %
++ (ip_range, snat_range))
++ firewall_manager.add_rule("pass quick inet from %s to %s/32" %
++ (ip_range, CONF.metadata_host))
++ for dmz in CONF.dmz_cidr:
++ firewall_manager.add_rule("pass quick inet from %s to %s" %
++ (ip_range, dmz))
++
++ """
++ iptables_manager.ipv4['nat'].add_rule('POSTROUTING',
++ '-s %(range)s -d %(range)s '
++ '-m conntrack ! --ctstate DNAT '
++ '-j ACCEPT' %
++ {'range': ip_range})
++ """
++ firewall_manager.apply()
++
++
++def send_arp_for_ip(ip, device, count):
++ out, err = _execute('arping', '-U', '-i', device, '-c', str(count), ip,
++ run_as_root=True, check_exit_code=False)
++
++ if err:
++ LOG.debug('arping error for IP %s', ip)
++
++
++def bind_floating_ip(floating_ip, device):
++ """Bind IP to public interface."""
++ _execute('ifconfig', device, str(floating_ip) + '/32', 'add',
++ run_as_root=True, check_exit_code=0)
++
++ if CONF.send_arp_for_ha and CONF.send_arp_for_ha_count > 0:
++ send_arp_for_ip(floating_ip, device, CONF.send_arp_for_ha_count)
++
++
++def unbind_floating_ip(floating_ip, device):
++ """Unbind a public IP from public interface."""
++ _execute('ifconfig', device, str(floating_ip) + '/32', 'delete',
++ run_as_root=True, check_exit_code=0)
++
++
++def ensure_metadata_ip():
++ """Sets up local metadata IP."""
++ _execute('ifconfig', 'lo0', 'alias', '169.254.169.254/32',
++ run_as_root=True, check_exit_code=0)
++
++
++def ensure_vpn_forward(public_ip, port, private_ip):
++ """Sets up forwarding rules for vlan."""
++ firewall_manager.add_rule("pass in proto udp "
++ "from any to %s port 1194 " %
++ (private_ip))
++ firewall_manager.add_rule("rdr proto udp from any to %s port %s -> "
++ "%s port 1194" %
++ (public_ip, port, private_ip))
++ firewall_manager.apply()
++
++
++def ensure_floating_forward(floating_ip, fixed_ip, device, network):
++ """Ensure floating IP forwarding rule."""
++ firewall_manager.ensure_floating_rules(floating_ip, fixed_ip, device)
++ if device != network['bridge']:
++ firewall_manager.ensure_in_network_traffic_rules(fixed_ip, network)
++ firewall_manager.apply()
++
++
++def remove_floating_forward(floating_ip, fixed_ip, device, network):
++ """Remove forwarding for floating IP."""
++ firewall_manager.remove_floating_rules(floating_ip, fixed_ip, device)
++ if device != network['bridge']:
++ firewall_manager.remove_in_network_traffic_rules(fixed_ip, network)
++ firewall_manager.apply()
++
++
++def clean_conntrack(fixed_ip):
++ pass
++
++
++def _enable_ipv4_forwarding():
++ sysctl_key = 'net.inet.ip.forwarding'
++ stdout, stderr = _execute('sysctl', '-n', sysctl_key)
++ if stdout.strip() is not '1':
++ _execute('sysctl', '%s=1' % sysctl_key, run_as_root=True)
++
++
++@utils.synchronized('lock_gateway', external=True)
++def initialize_gateway_device(dev, network_ref):
++ if not network_ref:
++ return
++
++ _enable_ipv4_forwarding()
++
++ # NOTE(vish): The ip for dnsmasq has to be the first address on the
++ # bridge for it to respond to requests properly
++ try:
++ prefix = network_ref.cidr.prefixlen
++ except AttributeError:
++ prefix = network_ref['cidr'].rpartition('/')[2]
++
++ full_ip = '%s/%s' % (network_ref['dhcp_server'], prefix)
++ new_ip_params = [['inet', full_ip, 'broadcast', network_ref['broadcast']]]
++ old_ip_params = []
++ out, err = _execute('ifconfig', dev)
++ for line in out.split('\n'):
++ fields = line.split()
++ if fields and fields[0] == 'inet':
++ old_ip_params.append(fields)
++ if _address_to_cidr(fields[1], fields[3]) != full_ip:
++ new_ip_params.append(fields)
++ if not old_ip_params or _address_to_cidr(old_ip_params[0][1], old_ip_params[0][3]) != full_ip:
++ old_routes = []
++ result = _execute('netstat', '-nrW', '-f', 'inet')
++ if result:
++ out, err = result
++ for line in out.split('\n'):
++ fields = line.split()
++ if len(fields) > 6 and (fields[6] == dev) and ('G' in fields[2]):
++ old_routes.append(fields)
++ _execute('route', '-q', 'delete', fields[0], fields[1],
++ run_as_root=True)
++ for ip_params in old_ip_params:
++ _execute(*_ifconfig_tail_cmd(dev, ip_params, 'delete'),
++ run_as_root=True)
++ for ip_params in new_ip_params:
++ _execute(*_ifconfig_tail_cmd(dev, ip_params, 'add'),
++ run_as_root=True)
++
++ for fields in old_routes:
++ _execute('route', '-q', 'add', fields[0], fields[1],
++ run_as_root=True)
++ if CONF.send_arp_for_ha and CONF.send_arp_for_ha_count > 0:
++ send_arp_for_ip(network_ref['dhcp_server'], dev,
++ CONF.send_arp_for_ha_count)
++ if CONF.use_ipv6:
++ _execute('ifconfig', dev, 'inet6', network_ref['cidr_v6'],
++ run_as_root=True)
++
++
++def get_dhcp_leases(context, network_ref):
++ """Return a network's hosts config in dnsmasq leasefile format."""
++ hosts = []
++ host = None
++ if network_ref['multi_host']:
++ host = CONF.host
++ for fixedip in objects.FixedIPList.get_by_network(context,
++ network_ref,
++ host=host):
++ # NOTE(cfb): Don't return a lease entry if the IP isn't
++ # already leased
++ if fixedip.leased:
++ hosts.append(_host_lease(fixedip))
++
++ return '\n'.join(hosts)
++
++
++def get_dhcp_hosts(context, network_ref, fixedips):
++ """Get network's hosts config in dhcp-host format."""
++ hosts = []
++ macs = set()
++ for fixedip in fixedips:
++ if fixedip.allocated:
++ if fixedip.virtual_interface.address not in macs:
++ hosts.append(_host_dhcp(fixedip))
++ macs.add(fixedip.virtual_interface.address)
++ return '\n'.join(hosts)
++
++
++def get_dns_hosts(context, network_ref):
++ """Get network's DNS hosts in hosts format."""
++ hosts = []
++ for fixedip in objects.FixedIPList.get_by_network(context, network_ref):
++ if fixedip.allocated:
++ hosts.append(_host_dns(fixedip))
++ return '\n'.join(hosts)
++
++
++def _add_dnsmasq_accept_rules(dev):
++ """Allow DHCP and DNS traffic through to dnsmasq."""
++ for port in [67, 53]:
++ for proto in ['udp', 'tcp']:
++ firewall_manager.add_rule("pass in on %s inet proto %s "
++ "from any to any port %s" %
++ (dev, proto, port))
++ firewall_manager.apply()
++
++
++def _remove_dnsmasq_accept_rules(dev):
++ """Remove DHCP and DNS traffic allowed through to dnsmasq."""
++ for port in [67, 53]:
++ for proto in ['udp', 'tcp']:
++ firewall_manager.remove_rule("pass in on %s inet proto %s "
++ "from any to any port %s" %
++ (dev, proto, port))
++ firewall_manager.apply()
++
++
++def get_dhcp_opts(context, network_ref, fixedips):
++ """Get network's hosts config in dhcp-opts format."""
++ gateway = network_ref['gateway']
++ # NOTE(vish): if we are in multi-host mode and we are not sharing
++ # addresses, then we actually need to hand out the
++ # dhcp server address as the gateway.
++ if network_ref['multi_host'] and not (network_ref['share_address'] or
++ CONF.share_dhcp_address):
++ gateway = network_ref['dhcp_server']
++ hosts = []
++ if CONF.use_single_default_gateway:
++ for fixedip in fixedips:
++ if fixedip.allocated:
++ vif_id = fixedip.virtual_interface_id
++ if fixedip.default_route:
++ hosts.append(_host_dhcp_opts(vif_id, gateway))
++ else:
++ hosts.append(_host_dhcp_opts(vif_id))
++ else:
++ hosts.append(_host_dhcp_opts(None, gateway))
++ return '\n'.join(hosts)
++
++
++def release_dhcp(dev, address, mac_address):
++ if device_exists(dev):
++ try:
++ utils.execute('dhcp_release', dev, address, mac_address,
++ run_as_root=True)
++ except processutils.ProcessExecutionError:
++ raise exception.NetworkDhcpReleaseFailed(address=address,
++ mac_address=mac_address)
++
++
++def update_dhcp(context, dev, network_ref):
++ conffile = _dhcp_file(dev, 'conf')
++ host = None
++ if network_ref['multi_host']:
++ host = CONF.host
++ fixedips = objects.FixedIPList.get_by_network(context,
++ network_ref,
++ host=host)
++ write_to_file(conffile, get_dhcp_hosts(context, network_ref, fixedips))
++ restart_dhcp(context, dev, network_ref, fixedips)
++
++
++def update_dns(context, dev, network_ref):
++ hostsfile = _dhcp_file(dev, 'hosts')
++ host = None
++ if network_ref['multi_host']:
++ host = CONF.host
++ fixedips = objects.FixedIPList.get_by_network(context,
++ network_ref,
++ host=host)
++ write_to_file(hostsfile, get_dns_hosts(context, network_ref))
++ restart_dhcp(context, dev, network_ref, fixedips)
++
++
++def kill_dhcp(dev):
++ pid = _dnsmasq_pid_for(dev)
++ if pid:
++ # Check that the process exists and looks like a dnsmasq process
++ conffile = _dhcp_file(dev, 'conf')
++ if is_pid_cmdline_correct(pid, conffile.split('/')[-1]):
++ _execute('kill', '-9', pid, run_as_root=True)
++ else:
++ LOG.debug('Pid %d is stale, skip killing dnsmasq', pid)
++ _remove_dnsmasq_accept_rules(dev)
++
++
++# NOTE(ja): Sending a HUP only reloads the hostfile, so any
++# configuration options (like dchp-range, vlan, ...)
++# aren't reloaded.
++@utils.synchronized('dnsmasq_start')
++def restart_dhcp(context, dev, network_ref, fixedips):
++ """(Re)starts a dnsmasq server for a given network.
++
++ If a dnsmasq instance is already running then send a HUP
++ signal causing it to reload, otherwise spawn a new instance.
++
++ """
++ conffile = _dhcp_file(dev, 'conf')
++
++ optsfile = _dhcp_file(dev, 'opts')
++ write_to_file(optsfile, get_dhcp_opts(context, network_ref, fixedips))
++ os.chmod(optsfile, 0o644)
++
++ # Make sure dnsmasq can actually read it (it setuid()s to "nobody")
++ os.chmod(conffile, 0o644)
++
++ pid = _dnsmasq_pid_for(dev)
++
++ # if dnsmasq is already running, then tell it to reload
++ if pid:
++ if is_pid_cmdline_correct(pid, conffile.split('/')[-1]):
++ try:
++ _execute('kill', '-HUP', pid, run_as_root=True)
++ _add_dnsmasq_accept_rules(dev)
++ return
++ except Exception as exc:
++ LOG.error(_LE('kill -HUP dnsmasq threw %s'), exc)
++ else:
++ LOG.debug('Pid %d is stale, relaunching dnsmasq', pid)
++
++ cmd = ['env',
++ 'CONFIG_FILE=%s' % jsonutils.dumps(CONF.dhcpbridge_flagfile),
++ 'NETWORK_ID=%s' % str(network_ref['id']),
++ 'dnsmasq',
++ '--strict-order',
++ '--bind-interfaces',
++ '--conf-file=%s' % CONF.dnsmasq_config_file,
++ '--pid-file=%s' % _dhcp_file(dev, 'pid'),
++ '--dhcp-optsfile=%s' % _dhcp_file(dev, 'opts'),
++ '--listen-address=%s' % network_ref['dhcp_server'],
++ '--except-interface=lo',
++ '--dhcp-range=set:%s,%s,static,%s,%ss' %
++ (network_ref['label'],
++ network_ref['dhcp_start'],
++ network_ref['netmask'],
++ CONF.dhcp_lease_time),
++ '--dhcp-lease-max=%s' % len(netaddr.IPNetwork(network_ref['cidr'])),
++ '--dhcp-hostsfile=%s' % _dhcp_file(dev, 'conf'),
++ '--dhcp-script=%s' % CONF.dhcpbridge,
++ '--no-hosts',
++ '--leasefile-ro']
++
++ # dnsmasq currently gives an error for an empty domain,
++ # rather than ignoring. So only specify it if defined.
++ if CONF.dhcp_domain:
++ cmd.append('--domain=%s' % CONF.dhcp_domain)
++
++ dns_servers = CONF.dns_server
++ if CONF.use_network_dns_servers:
++ if network_ref.get('dns1'):
++ dns_servers.append(network_ref.get('dns1'))
++ if network_ref.get('dns2'):
++ dns_servers.append(network_ref.get('dns2'))
++ if network_ref['multi_host']:
++ cmd.append('--addn-hosts=%s' % _dhcp_file(dev, 'hosts'))
++ if dns_servers:
++ cmd.append('--no-resolv')
++ for dns_server in dns_servers:
++ cmd.append('--server=%s' % dns_server)
++
++ _execute(*cmd, run_as_root=True)
++
++ _add_dnsmasq_accept_rules(dev)
++
++
++@utils.synchronized('radvd_start')
++def update_ra(context, dev, network_ref):
++ conffile = _ra_file(dev, 'conf')
++ conf_str = """
++interface %s
++{
++ AdvSendAdvert on;
++ MinRtrAdvInterval 3;
++ MaxRtrAdvInterval 10;
++ prefix %s
++ {
++ AdvOnLink on;
++ AdvAutonomous on;
++ };
++};
++""" % (dev, network_ref['cidr_v6'])
++ write_to_file(conffile, conf_str)
++
++ # Make sure radvd can actually read it (it setuid()s to "nobody")
++ os.chmod(conffile, 0o644)
++
++ pid = _ra_pid_for(dev)
++
++ # if radvd is already running, then tell it to reload
++ if pid:
++ if is_pid_cmdline_correct(pid, conffile):
++ try:
++ _execute('kill', pid, run_as_root=True)
++ except Exception as exc:
++ LOG.error(_LE('killing radvd threw %s'), exc)
++ else:
++ LOG.debug('Pid %d is stale, relaunching radvd', pid)
++
++ cmd = ['radvd',
++ '-C', '%s' % _ra_file(dev, 'conf'),
++ '-p', '%s' % _ra_file(dev, 'pid')]
++
++ _execute(*cmd, run_as_root=True)
++
++
++def _host_lease(fixedip):
++ """Return a host string for an address in leasefile format."""
++ timestamp = timeutils.utcnow()
++ seconds_since_epoch = calendar.timegm(timestamp.utctimetuple())
++ return '%d %s %s %s *' % (seconds_since_epoch + CONF.dhcp_lease_time,
++ fixedip.virtual_interface.address,
++ fixedip.address,
++ fixedip.instance.hostname or '*')
++
++
++def _host_dhcp_network(vif_id):
++ return 'NW-%s' % vif_id
++
++
++def _host_dhcp(fixedip):
++ """Return a host string for an address in dhcp-host format."""
++ # NOTE(cfb): dnsmasq on linux only supports 64 characters in the hostname
++ # field (LP #1238910). Since the . counts as a character we need
++ # to truncate the hostname to only 63 characters.
++ hostname = fixedip.instance.hostname
++ if len(hostname) > 63:
++ LOG.warning(_LW('hostname %s too long, truncating.'), hostname)
++ hostname = fixedip.instance.hostname[:2] + '-' +\
++ fixedip.instance.hostname[-60:]
++ if CONF.use_single_default_gateway:
++ net = _host_dhcp_network(fixedip.virtual_interface_id)
++ return '%s,%s.%s,%s,net:%s' % (fixedip.virtual_interface.address,
++ hostname,
++ CONF.dhcp_domain,
++ fixedip.address,
++ net)
++ else:
++ return '%s,%s.%s,%s' % (fixedip.virtual_interface.address,
++ hostname,
++ CONF.dhcp_domain,
++ fixedip.address)
++
++
++def _host_dns(fixedip):
++ return '%s\t%s.%s' % (fixedip.address,
++ fixedip.instance.hostname,
++ CONF.dhcp_domain)
++
++
++def _host_dhcp_opts(vif_id=None, gateway=None):
++ """Return an empty gateway option."""
++ values = []
++ if vif_id is not None:
++ values.append(_host_dhcp_network(vif_id))
++ # NOTE(vish): 3 is the dhcp option for gateway.
++ values.append('3')
++ if gateway:
++ values.append('%s' % gateway)
++ return ','.join(values)
++
++
++def _execute(*cmd, **kwargs):
++ """Wrapper around utils._execute for fake_network."""
++ if CONF.fake_network:
++ LOG.debug('FAKE NET: %s', ' '.join(map(str, cmd)))
++ return 'fake', 0
++ else:
++ return utils.execute(*cmd, **kwargs)
++
++
++def device_exists(device):
++ """Check if ethernet device exists."""
++ try:
++ _execute('ifconfig', device, run_as_root=True, check_exit_code=[0])
++ except processutils.ProcessExecutionError:
++ return False
++ else:
++ return True
++
++
++def _dhcp_file(dev, kind):
++ """Return path to a pid, leases, hosts or conf file for a bridge/device."""
++ fileutils.ensure_tree(CONF.networks_path)
++ return os.path.abspath('%s/nova-%s.%s' % (CONF.networks_path,
++ dev,
++ kind))
++
++
++def _ra_file(dev, kind):
++ """Return path to a pid or conf file for a bridge/device."""
++ fileutils.ensure_tree(CONF.networks_path)
++ return os.path.abspath('%s/nova-ra-%s.%s' % (CONF.networks_path,
++ dev,
++ kind))
++
++
++def _dnsmasq_pid_for(dev):
++ """Returns the pid for prior dnsmasq instance for a bridge/device.
++
++ Returns None if no pid file exists.
++
++ If machine has rebooted pid might be incorrect (caller should check).
++
++ """
++ pid_file = _dhcp_file(dev, 'pid')
++
++ if os.path.exists(pid_file):
++ try:
++ with open(pid_file, 'r') as f:
++ return int(f.read())
++ except (ValueError, IOError):
++ return None
++
++
++def _ra_pid_for(dev):
++ """Returns the pid for prior radvd instance for a bridge/device.
++
++ Returns None if no pid file exists.
++
++ If machine has rebooted pid might be incorrect (caller should check).
++
++ """
++ pid_file = _ra_file(dev, 'pid')
++
++ if os.path.exists(pid_file):
++ with open(pid_file, 'r') as f:
++ return int(f.read())
++
++
++def _address_to_cidr(address, hexmask):
++ """Produce a CIDR format address/netmask."""
++ netmask = socket.inet_ntoa(struct.pack(">I", int(hexmask, 16)))
++ ip_cidr = netaddr.IPNetwork("%s/%s" % (address, netmask))
++ return str(ip_cidr)
++
++
++def _ifconfig_tail_cmd(netif, params, action):
++ """Construct ifconfig command"""
++ cmd = ['ifconfig', netif]
++ cmd.extend(params)
++ cmd.extend([action])
++ return cmd
++
++
++def _set_device_mtu(dev, mtu=None):
++ """Set the device MTU."""
++ if mtu:
++ utils.execute('ifconfig', dev, 'mtu', mtu,
++ run_as_root=True, check_exit_code=0)
++
++
++def _ovs_vsctl(args):
++ full_args = ['ovs-vsctl', '--timeout=%s' % CONF.ovs_vsctl_timeout] + args
++ try:
++ return utils.execute(*full_args, run_as_root=True)
++ except Exception as e:
++ LOG.error(_LE("Unable to execute %(cmd)s. Exception: %(exception)s"),
++ {'cmd': full_args, 'exception': e})
++ raise exception.OvsConfigurationFailure(inner_exception=e)
++
++
++def _create_ovs_vif_cmd(bridge, dev, iface_id, mac,
++ instance_id, interface_type=None):
++ cmd = ['--', '--if-exists', 'del-port', dev, '--',
++ 'add-port', bridge, dev,
++ '--', 'set', 'Interface', dev,
++ 'external-ids:iface-id=%s' % iface_id,
++ 'external-ids:iface-status=active',
++ 'external-ids:attached-mac=%s' % mac,
++ 'external-ids:vm-uuid=%s' % instance_id]
++ if interface_type:
++ cmd += ['type=%s' % interface_type]
++ return cmd
++
++
++def create_ovs_vif_port(bridge, dev, iface_id, mac, instance_id,
++ mtu=None, interface_type=None):
++ _ovs_vsctl(_create_ovs_vif_cmd(bridge, dev, iface_id,
++ mac, instance_id,
++ interface_type))
++ # Note at present there is no support for setting the
++ # mtu for vhost-user type ports.
++ if interface_type != network_model.OVS_VHOSTUSER_INTERFACE_TYPE:
++ _set_device_mtu(dev, mtu)
++ else:
++ LOG.debug("MTU not set on %(interface_name)s interface "
++ "of type %(interface_type)s.",
++ {'interface_name': dev,
++ 'interface_type': interface_type})
++
++
++def delete_ovs_vif_port(bridge, dev, delete_dev=True):
++ _ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev])
++ if delete_dev:
++ delete_net_dev(dev)
++
++
++def create_tap_dev(dev, mac_address=None):
++ if not device_exists(dev):
++ utils.execute('ifconfig', 'tap', 'create', 'name', dev,
++ run_as_root=True, check_exit_code=[0])
++ if mac_address:
++ utils.execute('ifconfig', dev, 'ether', mac_address,
++ run_as_root=True, check_exit_code=[0])
++ utils.execute('ifconfig', dev, 'up',
++ run_as_root=True, check_exit_code=[0])
++
++
++def delete_net_dev(dev):
++ """Delete a network device only if it exists."""
++ if device_exists(dev):
++ try:
++ utils.execute('ifconfig', dev, 'destroy',
++ run_as_root=True, check_exit_code=0)
++ LOG.debug("Net device removed: '%s'", dev)
++ except processutils.ProcessExecutionError:
++ with excutils.save_and_reraise_exception():
++ LOG.error(_LE("Failed removing net device: '%s'"), dev)
++
++
++def delete_bridge_dev(dev):
++ """Delete a network bridge."""
++ if device_exists(dev):
++ try:
++ utils.execute('ifconfig', dev, 'down', run_as_root=True)
++ utils.execute('ifconfig', dev, 'destroy', run_as_root=True)
++ except processutils.ProcessExecutionError:
++ with excutils.save_and_reraise_exception():
++ LOG.error(_LE("Failed removing bridge device: '%s'"), dev)
++
++
++# Similar to compute virt layers, the FreeBSD network node
++# code uses a flexible driver model to support different ways
++# of creating ethernet interfaces and attaching them to the network.
++# In the case of a network host, these interfaces
++# act as gateway/dhcp/vpn/etc. endpoints not VM interfaces.
++interface_driver = None
++
++
++def _get_interface_driver():
++ global interface_driver
++ if not interface_driver:
++ interface_driver = importutils.import_object(
++ CONF.freebsdnet_interface_driver)
++ return interface_driver
++
++
++def plug(network, mac_address, gateway=True):
++ return _get_interface_driver().plug(network, mac_address, gateway)
++
++
++def unplug(network):
++ return _get_interface_driver().unplug(network)
++
++
++def get_dev(network):
++ return _get_interface_driver().get_dev(network)
++
++
++class FreeBSDNetInterfaceDriver(object):
++ """Abstract class that defines generic network host API
++ for all FreeBSD interface drivers.
++ """
++
++ def plug(self, network, mac_address):
++ """Create FreeBSD device, return device name."""
++ raise NotImplementedError()
++
++ def unplug(self, network):
++ """Destroy FreeBSD device, return device name."""
++ raise NotImplementedError()
++
++ def get_dev(self, network):
++ """Get device name."""
++ raise NotImplementedError()
++
++
++# plugs interfaces using FreeBSD Bridge
++class FreeBSDBridgeInterfaceDriver(FreeBSDNetInterfaceDriver):
++
++ def plug(self, network, mac_address, gateway=True):
++ vlan = network.get('vlan')
++ if vlan is not None:
++ iface = CONF.vlan_interface or network['bridge_interface']
++ FreeBSDBridgeInterfaceDriver.ensure_vlan_bridge(
++ vlan,
++ network['bridge'],
++ iface,
++ network,
++ mac_address,
++ network.get('mtu'))
++ iface = 'vlan%s' % vlan
++ else:
++ iface = CONF.flat_interface or network['bridge_interface']
++ FreeBSDBridgeInterfaceDriver.ensure_bridge(
++ network['bridge'],
++ iface,
++ network, gateway)
++
++ if network['share_address'] or CONF.share_dhcp_address:
++ isolate_dhcp_address(iface, network['dhcp_server'])
++ # NOTE(vish): applying here so we don't get a lock conflict
++ firewall_manager.apply()
++ return network['bridge']
++
++ def unplug(self, network, gateway=True):
++ vlan = network.get('vlan')
++ if vlan is not None:
++ iface = 'vlan%s' % vlan
++ FreeBSDBridgeInterfaceDriver.remove_vlan_bridge(vlan,
++ network['bridge'])
++ else:
++ iface = CONF.flat_interface or network['bridge_interface']
++ FreeBSDBridgeInterfaceDriver.remove_bridge(network['bridge'],
++ gateway)
++
++ if network['share_address'] or CONF.share_dhcp_address:
++ remove_isolate_dhcp_address(iface, network['dhcp_server'])
++
++ firewall_manager.apply()
++ return self.get_dev(network)
++
++ def get_dev(self, network):
++ return network['bridge']
++
++ @staticmethod
++ def ensure_vlan_bridge(vlan_num, bridge, bridge_interface,
++ net_attrs=None, mac_address=None,
++ mtu=None):
++ """Create a vlan and bridge unless they already exist."""
++ interface = FreeBSDBridgeInterfaceDriver.ensure_vlan(vlan_num,
++ bridge_interface, mac_address,
++ mtu)
++ FreeBSDBridgeInterfaceDriver.ensure_bridge(bridge, interface, net_attrs)
++ return interface
++
++ @staticmethod
++ def remove_vlan_bridge(vlan_num, bridge):
++ """Delete a bridge and vlan."""
++ FreeBSDBridgeInterfaceDriver.remove_bridge(bridge)
++ FreeBSDBridgeInterfaceDriver.remove_vlan(vlan_num)
++
++ @staticmethod
++ @utils.synchronized('lock_vlan', external=True)
++ def ensure_vlan(vlan_num, bridge_interface, mac_address=None, mtu=None,
++ interface=None):
++ """Create a vlan unless it already exists."""
++ if interface is None:
++ interface = 'vlan%s' % vlan_num
++ if not device_exists(interface):
++ LOG.debug('Starting VLAN interface %s', interface)
++ out, err = _execute('ifconfig', 'vlan', 'create',
++ 'vlan', vlan_num,
++ 'vlandev', bridge_interface,
++ 'name', interface,
++ run_as_root=True)
++ if err and 'File exists' not in err:
++ msg = _('Failed to add vlan: %s') % err
++ raise exception.NovaException(msg)
++ # (danwent) the bridge will inherit this address, so we want to
++ # make sure it is the value set from the NetworkManager
++ if mac_address:
++ _execute('ifconfig', interface, 'ether', mac_address,
++ run_as_root=True)
++ _execute('ifconfig',interface, 'up',
++ run_as_root=True)
++ # NOTE(vish): set mtu every time to ensure that changes to mtu get
++ # propagated
++ _set_device_mtu(interface, mtu)
++ return interface
++
++ @staticmethod
++ @utils.synchronized('lock_vlan', external=True)
++ def remove_vlan(vlan_num):
++ """Delete a vlan."""
++ vlan_interface = 'vlan%s' % vlan_num
++ delete_net_dev(vlan_interface)
++
++ @staticmethod
++ @utils.synchronized('lock_bridge', external=True)
++ def ensure_bridge(bridge, interface, net_attrs=None, gateway=True,
++ filtering=True):
++ """Create a bridge unless it already exists.
++
++ :param interface: the interface to create the bridge on.
++ :param net_attrs: dictionary with attributes used to create bridge.
++ :param gateway: whether or not the bridge is a gateway.
++ :param filtering: whether or not to create filters on the bridge.
++
++ If net_attrs is set, it will add the net_attrs['gateway'] to the bridge
++ using net_attrs['broadcast'] and net_attrs['cidr']. It will also add
++ the ip_v6 address specified in net_attrs['cidr_v6'] if use_ipv6 is set.
++
++ The code will attempt to move any IPs that already exist on the
++ interface onto the bridge and reset the default gateway if necessary.
++
++ """
++ if not device_exists(bridge):
++ LOG.debug('Starting Bridge %s', bridge)
++ out, err = _execute('ifconfig', 'bridge', 'create', 'name', bridge,
++ check_exit_code=False, run_as_root=True)
++ if err and 'File exists' not in err:
++ msg = _('Failed to add bridge: %s') % err
++ raise exception.NovaException(msg)
++
++ _execute('ifconfig', bridge, 'up', run_as_root=True)
++
++ if interface:
++ LOG.debug('Adding interface %(interface)s to bridge %(bridge)s',
++ {'interface': interface, 'bridge': bridge})
++ out, err = _execute('ifconfig', bridge, 'addm', interface,
++ check_exit_code=False, run_as_root=True)
++ if err and 'File exists' not in err:
++ msg = _('Failed to add interface: %s') % err
++ raise exception.NovaException(msg)
++
++ # NOTE(apmelton): Linux bridge's default behavior is to use the
++ # lowest mac of all plugged interfaces. This isn't a problem when
++ # it is first created and the only interface is the bridged
++ # interface. But, as instance interfaces are plugged, there is a
++ # chance for the mac to change. So, set it here so that it won't
++ # change in the future.
++ if not CONF.fake_network:
++ interface_addrs = netifaces.ifaddresses(interface)
++ interface_mac = interface_addrs[netifaces.AF_LINK][0]['addr']
++ _execute('ifconfig', bridge, 'ether', interface_mac,
++ run_as_root=True)
++
++ out, err = _execute('ifconfig', interface, 'up',
++ check_exit_code=False, run_as_root=True)
++
++ # NOTE(vish): This will break if there is already an ip on the
++ # interface, so we move any ips to the bridge
++ # NOTE(danms): We also need to copy routes to the bridge so as
++ # not to break existing connectivity on the interface
++ old_routes = []
++ out, err = _execute('netstat', '-nrW', '-f', 'inet')
++ for line in out.split('\n'):
++ fields = line.split()
++ if len(fields) > 6 and (fields[6] == interface) and ('G' in fields[2]):
++ old_routes.append(fields)
++ _execute('route', '-q', 'delete', fields[0], fields[1],
++ run_as_root=True)
++ out, err = _execute('ifconfig', interface)
++ for line in out.split('\n'):
++ fields = line.split()
++ if fields and fields[0] == 'inet':
++ _execute(*_ifconfig_tail_cmd(interface, fields, 'delete'),
++ run_as_root=True)
++ _execute(*_ifconfig_tail_cmd(bridge, fields, 'add'),
++ run_as_root=True)
++ for fields in old_routes:
++ _execute('route', '-q', 'add', fields[0], fields[1],
++ run_as_root=True)
++
++ if filtering:
++ # Don't forward traffic unless we were told to be a gateway
++ if gateway:
++ firewall_manager.ensure_gateway_rules(bridge)
++ else:
++ firewall_manager.ensure_bridge_rules(bridge)
++
++ @staticmethod
++ @utils.synchronized('lock_bridge', external=True)
++ def remove_bridge(bridge, gateway=True, filtering=True):
++ """Delete a bridge."""
++ if not device_exists(bridge):
++ return
++ else:
++ if filtering:
++ if gateway:
++ firewall_manager.remove_gateway_rules(bridge)
++ else:
++ firewall_manager.remove_bridge_rules(bridge)
++ delete_bridge_dev(bridge)
++
++
++def isolate_dhcp_address(interface, address):
++ # block arp traffic to address across the interface
++ firewall_manager.ensure_dhcp_isolation(interface, address)
++
++
++def remove_isolate_dhcp_address(interface, address):
++ # block arp traffic to address across the interface
++ firewall_manager.remove_dhcp_isolation(interface, address)
++
++
++# plugs interfaces using Open vSwitch
++class FreeBSDOVSInterfaceDriver(FreeBSDNetInterfaceDriver):
++
++ def plug(self, network, mac_address, gateway=True):
++ dev = self.get_dev(network)
++ if not device_exists(dev):
++ bridge = CONF.freebsdnet_ovs_integration_bridge
++ _ovs_vsctl(['--', '--may-exist', 'add-port', bridge, dev,
++ '--', 'set', 'Interface', dev, 'type=internal',
++ '--', 'set', 'Interface', dev,
++ 'external-ids:iface-id=%s' % dev,
++ '--', 'set', 'Interface', dev,
++ 'external-ids:iface-status=active',
++ '--', 'set', 'Interface', dev,
++ 'external-ids:attached-mac=%s' % mac_address])
++ _execute('ifconfig', dev, 'ether', mac_address, run_as_root=True)
++ _set_device_mtu(dev, network.get('mtu'))
++ _execute('ifconfig', dev, 'up', run_as_root=True)
++ if not gateway:
++ # If we weren't instructed to act as a gateway then add the
++ # appropriate flows to block all non-dhcp traffic.
++ _execute('ovs-ofctl',
++ 'add-flow', bridge, 'priority=1,actions=drop',
++ run_as_root=True)
++ _execute('ovs-ofctl', 'add-flow', bridge,
++ 'udp,tp_dst=67,dl_dst=%s,priority=2,actions=normal' %
++ mac_address, run_as_root=True)
++ # .. and make sure iptbles won't forward it as well.
++ firewall_manager.ensure_bridge_rules(bridge)
++ else:
++ firewall_manager.ensure_gateway_rules(bridge)
++
++ return dev
++
++ def unplug(self, network):
++ dev = self.get_dev(network)
++ bridge = CONF.freebsdnet_ovs_integration_bridge
++ _ovs_vsctl(['--', '--if-exists', 'del-port', bridge, dev])
++ return dev
++
++ def get_dev(self, network):
++ dev = 'gw-' + str(network['uuid'][0:11])
++ return dev
++
++
++# plugs interfaces using FreeBSD Bridge when using NeutronManager
++class NeutronFreeBSDBridgeInterfaceDriver(FreeBSDNetInterfaceDriver):
++
++ BRIDGE_NAME_PREFIX = 'brq'
++ GATEWAY_INTERFACE_PREFIX = 'gw-'
++
++ def plug(self, network, mac_address, gateway=True):
++ dev = self.get_dev(network)
++ bridge = self.get_bridge(network)
++ if not gateway:
++ # If we weren't instructed to act as a gateway then add the
++ # appropriate flows to block all non-dhcp traffic.
++ # .. and make sure iptbles won't forward it as well.
++ firewall_manager.ensure_bridge_rules(bridge)
++ return bridge
++ else:
++ firewall_manager.ensure_gateway_rules(bridge)
++
++ create_tap_dev(dev, mac_address)
++
++ if not device_exists(bridge):
++ LOG.debug("Starting bridge %s ", bridge)
++ utils.execute('ifconfig', 'bridge', 'create', 'name', bridge, run_as_root=True)
++ utils.execute('ifconfig', bridge, 'ether', mac_address, run_as_root=True)
++ utils.execute('ifconfig', bridge, 'up', run_as_root=True)
++ LOG.debug("Done starting bridge %s", bridge)
++
++ full_ip = '%s/%s' % (network['dhcp_server'],
++ network['cidr'].rpartition('/')[2])
++ utils.execute('ifconfig', bridge, full_ip, 'add', run_as_root=True)
++
++ return dev
++
++ def unplug(self, network):
++ dev = self.get_dev(network)
++ if not device_exists(dev):
++ return None
++ else:
++ delete_net_dev(dev)
++ return dev
++
++ def get_dev(self, network):
++ dev = self.GATEWAY_INTERFACE_PREFIX + str(network['uuid'][0:11])
++ return dev
++
++ def get_bridge(self, network):
++ bridge = self.BRIDGE_NAME_PREFIX + str(network['uuid'][0:11])
++ return bridge
++
++
++class FirewallManager(object):
++ def __init__(self, execute=_execute):
++ self.execute = execute
++ self.apply_deferred = False
++ self.anchor = 'org.openstack/%s' % get_binary_name()
++ self.rules = {
++ "translation": [],
++ "filtering": []
++ }
++ self.is_dirty = False
++
++ def _get_rule_section(self, rule):
++ LOG.warning("processing rule: %s" % rule)
++ head, tail = rule.split(' ', 1)
++ if head in ('nat', 'rdr'):
++ return 'translation'
++ elif head in ('pass', 'block'):
++ return 'filtering'
++ else:
++ return None
++
++ def add_rule(self, rule):
++ cleaned_rule = rule.strip()
++ section = self._get_rule_section(cleaned_rule)
++ if section:
++ if cleaned_rule not in self.rules[section]:
++ self.rules[section].append(cleaned_rule)
++ self.is_dirty = True
++ LOG.warning("Added rule to %s: %s", section, cleaned_rule)
++
++ def remove_rule(self, rule):
++ cleaned_rule = rule.strip()
++ section = self._get_rule_section(cleaned_rule)
++ LOG.warning("Removing rule from %s: %s", section, cleaned_rule)
++ if section:
++ try:
++ self.rules[section].remove(cleaned_rule)
++ self.is_dirty = True
++ except:
++ pass
++
++ def defer_apply_on(self):
++ self.apply_deferred = True
++
++ def defer_apply_off(self):
++ self.apply_deferred = False
++ self.apply()
++
++ def dirty(self):
++ return self.is_dirty
++
++ def apply(self):
++ if self.apply_deferred:
++ return
++ if self.dirty():
++ self._apply()
++ else:
++ LOG.debug("Skipping apply due to lack of new rules")
++
++ @utils.synchronized('pfctl', external=True)
++ def _apply(self):
++ all_lines = []
++ all_lines.extend(self.rules['translation'])
++ all_lines.extend(self.rules['filtering'])
++ all_lines.extend(["\n"])
++
++ self.is_dirty = False
++ self.execute("pfctl", "-a", self.anchor, "-f", "-",
++ process_input="\n".join(all_lines),
++ run_as_root=True)
++ LOG.warning("FirewallManager.apply completed with success")
++
++ def get_gateway_rules(self, bridge):
++ LOG.warning("FirewallManager.get_gateway_rules: "
++ "Please configure rules in pf.conf")
++ return []
++
++ def ensure_gateway_rules(self, bridge):
++ for rule in self.get_gateway_rules(bridge):
++ self.add_rule(rule)
++
++ def remove_gateway_rules(self, bridge):
++ for rule in self.get_gateway_rules(bridge):
++ self.remove_rule(rule)
++
++ def ensure_bridge_rules(self, bridge):
++ LOG.warning("FirewallManager.ensure_bridge_rules: "
++ "Please configure rules in pf.conf")
++
++ def remove_bridge_rules(self, bridge):
++ LOG.warning("FirewallManager.remove_bridge_rules: "
++ "Please configure rules in pf.conf")
++
++ def ensure_dhcp_isolation(self, interface, address):
++ LOG.warning("FirewallManager.ensure_dhcp_isolation: "
++ "DHCP isolation is not yet implemented")
++
++ def remove_dhcp_isolation(self, interface, address):
++ LOG.warning("FirewallManager.remove_dhcp_isolation: "
++ "DHCP isolation is not yet implemented")
++
++ def ensure_in_network_traffic_rules(self, fixed_ip, network):
++ LOG.warning("FirewallManager.ensure_in_network_traffic_rules: "
++ "Please configure rules in pf.conf")
++
++ def remove_in_network_traffic_rules(self, fixed_ip, network):
++ LOG.warning("FirewallManager.remove_in_network_traffic_rules: "
++ "Please configure rules in pf.conf")
++
++ def floating_forward_rules(self, floating_ip, fixed_ip, device):
++ rules = []
++ rules.append("rdr inet from any to %s -> %s" % (floating_ip, fixed_ip))
++
++ return rules
++
++ def ensure_floating_rules(self, floating_ip, fixed_ip, device):
++ for rule in self.floating_forward_rules(floating_ip, fixed_ip, device):
++ self.add_rule(rule)
++
++ def remove_floating_rules(self, floating_ip, fixed_ip, device):
++ for rule in self.floating_forward_rules(floating_ip, fixed_ip, device):
++ self.remove_rule(rule)
++
++ def add_snat_rule(self, ip_range, is_external=False):
++ if CONF.routing_source_ip:
++ if is_external:
++ if CONF.force_snat_range:
++ snat_range = CONF.force_snat_range
++ else:
++ snat_range = []
++ else:
++ snat_range = ['0.0.0.0/0']
++ for dest_range in snat_range:
++ if not is_external and CONF.public_interface:
++ firewall_manager.add_rule("nat on %s inet from %s to %s -> %s" %
++ (CONF.public_interface,
++ ip_range,
++ dest_range,
++ CONF.routing_source_ip))
++ else:
++ firewall_manager.add_rule("nat inet from %s to %s -> %s" %
++ (ip_range,
++ dest_range,
++ CONF.routing_source_ip))
++ firewall_manager.apply()
++
++
++firewall_manager = FirewallManager()
++
++
++def get_firewall_manager():
++ return firewall_manager
+--
+2.8.1
+
diff --git a/emulators/py-nova/files/nova-api.in b/emulators/py-nova/files/nova-api.in
new file mode 100644
index 000000000000..163125139d74
--- /dev/null
+++ b/emulators/py-nova/files/nova-api.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_api
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_api:
+#
+# nova_api_enable="YES"
+#
+# nova_api_enable (bool):
+# Set it to "YES" to enable nova_api.
+# Default is "NO".
+#
+# nova_api_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_api_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_api_logdir}/nova-api.log"
+#
+
+. /etc/rc.subr
+
+name=nova_api
+rcvar=nova_api_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-api.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_api_enable:="NO"}
+: ${nova_api_logdir:="/var/log/nova"}
+: ${nova_api_args:="--log-file ${nova_api_logdir}/nova-api.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-api ${nova_api_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_api_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova-cells.in b/emulators/py-nova/files/nova-cells.in
new file mode 100644
index 000000000000..0e7ecd4da772
--- /dev/null
+++ b/emulators/py-nova/files/nova-cells.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_cells
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_cells:
+#
+# nova_cells_enable="YES"
+#
+# nova_cells_enable (bool):
+# Set it to "YES" to enable nova_cells.
+# Default is "NO".
+#
+# nova_cells_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_cells_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_cells_logdir}/nova-cells.log"
+#
+
+. /etc/rc.subr
+
+name=nova_cells
+rcvar=nova_cells_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-cells.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_cells_enable:="NO"}
+: ${nova_cells_logdir:="/var/log/nova"}
+: ${nova_cells_args:="--log-file ${nova_cells_logdir}/nova-cells.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-cells ${nova_cells_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_cells_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova-cert.in b/emulators/py-nova/files/nova-cert.in
new file mode 100644
index 000000000000..6c2f17692072
--- /dev/null
+++ b/emulators/py-nova/files/nova-cert.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_cert
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_cert:
+#
+# nova_cert_enable="YES"
+#
+# nova_cert_enable (bool):
+# Set it to "YES" to enable nova_cert.
+# Default is "NO".
+#
+# nova_cert_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_cert_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_cert_logdir}/nova-cert.log"
+#
+
+. /etc/rc.subr
+
+name=nova_cert
+rcvar=nova_cert_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-cert.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_cert_enable:="NO"}
+: ${nova_cert_logdir:="/var/log/nova"}
+: ${nova_cert_args:="--log-file ${nova_cert_logdir}/nova-cert.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-cert ${nova_cert_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_cert_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova-compute.conf.sample b/emulators/py-nova/files/nova-compute.conf.sample
new file mode 100644
index 000000000000..a6ae707b0407
--- /dev/null
+++ b/emulators/py-nova/files/nova-compute.conf.sample
@@ -0,0 +1,15 @@
+[DEFAULT]
+compute_driver=libvirt.LibvirtDriver
+force_raw_images = True
+use_cow_images = False
+
+[libvirt]
+virt_type=qemu
+
+# Force using PHY driver for Xen hypervisor
+force_xen_phy=True
+
+# Disable CPU tracking when using QEMU driver.
+# Change this option to True when using Xen driver.
+online_cpu_tracking=False
+
diff --git a/emulators/py-nova/files/nova-compute.in b/emulators/py-nova/files/nova-compute.in
new file mode 100644
index 000000000000..921ae615f506
--- /dev/null
+++ b/emulators/py-nova/files/nova-compute.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_compute
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_compute:
+#
+# nova_compute_enable="YES"
+#
+# nova_compute_enable (bool):
+# Set it to "YES" to enable nova_compute.
+# Default is "NO".
+#
+# nova_compute_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_compute_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_compute_logdir}/nova-compute.log"
+#
+
+. /etc/rc.subr
+
+name=nova_compute
+rcvar=nova_compute_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-compute.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_compute_enable:="NO"}
+: ${nova_compute_logdir:="/var/log/nova"}
+: ${nova_compute_args:="--log-file ${nova_compute_logdir}/nova-compute.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-compute ${nova_compute_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_compute_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova-conductor.in b/emulators/py-nova/files/nova-conductor.in
new file mode 100644
index 000000000000..8b1b7d1568bb
--- /dev/null
+++ b/emulators/py-nova/files/nova-conductor.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_conductor
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_conductor:
+#
+# nova_conductor_enable="YES"
+#
+# nova_conductor_enable (bool):
+# Set it to "YES" to enable nova_conductor.
+# Default is "NO".
+#
+# nova_conductor_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_conductor_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_conductor_logdir}/nova-conductor.log"
+#
+
+. /etc/rc.subr
+
+name=nova_conductor
+rcvar=nova_conductor_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-conductor.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_conductor_enable:="NO"}
+: ${nova_conductor_logdir:="/var/log/nova"}
+: ${nova_conductor_args:="--log-file ${nova_conductor_logdir}/nova-conductor.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-conductor ${nova_conductor_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_conductor_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova-consoleauth.in b/emulators/py-nova/files/nova-consoleauth.in
new file mode 100644
index 000000000000..93b6524ad385
--- /dev/null
+++ b/emulators/py-nova/files/nova-consoleauth.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_consoleauth
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_consoleauth:
+#
+# nova_consoleauth_enable="YES"
+#
+# nova_consoleauth_enable (bool):
+# Set it to "YES" to enable nova_consoleauth.
+# Default is "NO".
+#
+# nova_consoleauth_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_consoleauth_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_consoleauth_logdir}/nova-consoleauth.log"
+#
+
+. /etc/rc.subr
+
+name=nova_consoleauth
+rcvar=nova_consoleauth_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-consoleauth.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_consoleauth_enable:="NO"}
+: ${nova_consoleauth_logdir:="/var/log/nova"}
+: ${nova_consoleauth_args:="--log-file ${nova_consoleauth_logdir}/nova-consoleauth.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-consoleauth ${nova_consoleauth_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_consoleauth_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova-network.in b/emulators/py-nova/files/nova-network.in
new file mode 100644
index 000000000000..f2e156302d8f
--- /dev/null
+++ b/emulators/py-nova/files/nova-network.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_network
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_network:
+#
+# nova_network_enable="YES"
+#
+# nova_network_enable (bool):
+# Set it to "YES" to enable nova_network.
+# Default is "NO".
+#
+# nova_network_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_network_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_network_logdir}/nova-network.log"
+#
+
+. /etc/rc.subr
+
+name=nova_network
+rcvar=nova_network_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-network.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_network_enable:="NO"}
+: ${nova_network_logdir:="/var/log/nova"}
+: ${nova_network_args:="--log-file ${nova_network_logdir}/nova-network.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-network ${nova_network_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_network_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova-scheduler.in b/emulators/py-nova/files/nova-scheduler.in
new file mode 100644
index 000000000000..240b5ffeb5d7
--- /dev/null
+++ b/emulators/py-nova/files/nova-scheduler.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_scheduler
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_scheduler:
+#
+# nova_scheduler_enable="YES"
+#
+# nova_scheduler_enable (bool):
+# Set it to "YES" to enable nova_scheduler.
+# Default is "NO".
+#
+# nova_scheduler_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_scheduler_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_scheduler_logdir}/nova-scheduler.log"
+#
+
+. /etc/rc.subr
+
+name=nova_scheduler
+rcvar=nova_scheduler_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-scheduler.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_scheduler_enable:="NO"}
+: ${nova_scheduler_logdir:="/var/log/nova"}
+: ${nova_scheduler_args:="--log-file ${nova_scheduler_logdir}/nova-scheduler.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-scheduler ${nova_scheduler_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_scheduler_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova-serialproxy.in b/emulators/py-nova/files/nova-serialproxy.in
new file mode 100644
index 000000000000..05247b6a0bbb
--- /dev/null
+++ b/emulators/py-nova/files/nova-serialproxy.in
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# $FreeBSD$
+#
+
+# PROVIDE: nova_serialproxy
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+
+#
+# Add the following lines to /etc/rc.conf to enable nova_serialproxy:
+#
+# nova_serialproxy_enable="YES"
+#
+# nova_serialproxy_enable (bool):
+# Set it to "YES" to enable nova_serialproxy.
+# Default is "NO".
+#
+# nova_serialproxy_logdir (str):
+# Set it to chagge log directory
+# Default is "/var/log/nova"
+#
+# nova_serialproxy_args (str):
+# Set it to change command line arguments.
+# Default is "--log-file ${nova_serialproxy_logdir}/nova-serialproxy.log"
+#
+
+. /etc/rc.subr
+
+name=nova_serialproxy
+rcvar=nova_serialproxy_enable
+
+PATH=%%PREFIX%%/bin:%%PREFIX%%/sbin:$PATH
+
+pidfile="/var/run/nova-serialproxy.pid"
+procname="%%PREFIX%%/bin/python2.7"
+
+start_precmd=nova_precmd
+
+load_rc_config $name
+
+: ${nova_serialproxy_enable:="NO"}
+: ${nova_serialproxy_logdir:="/var/log/nova"}
+: ${nova_serialproxy_args:="--log-file ${nova_serialproxy_logdir}/nova-serialproxy.log"}
+
+command="/usr/sbin/daemon"
+command_args="-f -p ${pidfile} nova-serialproxy ${nova_serialproxy_args}"
+
+nova_precmd() {
+ mkdir -p ${nova_serialproxy_logdir}
+}
+
+run_rc_command "$1"
diff --git a/emulators/py-nova/files/nova.conf.sample b/emulators/py-nova/files/nova.conf.sample
new file mode 100644
index 000000000000..95dd7ea27424
--- /dev/null
+++ b/emulators/py-nova/files/nova.conf.sample
@@ -0,0 +1,80 @@
+[DEFAULT]
+dhcpbridge_flagfile=/usr/local/etc/nova/nova.conf
+dhcpbridge=/usr/local/bin/nova-dhcpbridge
+log-dir=/var/log/nova
+state_path=/var/lib/nova
+force_dhcp_release=False
+verbose=True
+ec2_private_dns_show_ip=True
+enabled_apis=osapi_compute,metadata
+rpc_backend = rabbit
+auth_strategy = keystone
+my_ip = 192.168.1.10
+use_neutron = False
+firewall_driver = nova.virt.firewall.NoopFirewallDriver
+use_ipv6 = False
+
+osapi_compute_listen="0.0.0.0"
+osapi_compute_listen_port=8774
+
+network_driver=nova.network.freebsd_net
+libvirt_vif_driver=nova.virt.libvirt.vif.LibvirtGenericVIFDriver
+freebsdnet_interface_driver=nova.network.freebsd_net.FreeBSDBridgeInterfaceDriver
+l3_lib=nova.network.l3.FreeBSDNetL3
+network_api_class=nova.network.api.API
+security_group_api=nova
+network_manager=nova.network.manager.FlatDHCPManager
+network_size=254
+allow_same_net_traffic=False
+multi_host=True
+send_arp_for_ha=False
+share_dhcp_address=True
+# specify nic for public
+public_interface=em0
+# specify any name you like for bridge
+flat_network_bridge=br100
+flat_interface=tap0
+
+[vnc]
+enabled = False
+
+[glance]
+api_servers = http://controller:9292
+
+[keystone_authtoken]
+auth_uri = http://controller:5000
+auth_url = http://controller:35357
+memcached_servers = controller:11211
+auth_type = password
+project_domain_name = default
+user_domain_name = default
+project_name = service
+username = nova
+password = nova
+
+[oslo_messaging_rabbit]
+rabbit_host = controller
+rabbit_userid = openstack
+rabbit_password = RABBIT_PASS
+
+[api_database]
+connection = mysql+pymysql://nova:NOVA_DBPASS@controller/nova_api
+
+[database]
+connection = mysql+pymysql://nova:NOVA_DBPASS@controller/nova
+
+[oslo_concurrency]
+lock_path=/var/lock/nova
+
+[libvirt]
+use_virtio_for_bridges=True
+
+# add this options when using QEMU
+cpu_mode=none
+
+[wsgi]
+api_paste_config=/usr/local/etc/nova/api-paste.ini
+
+[serial_console]
+# Enable serial console when using QEMU driver
+enabled=True
diff --git a/emulators/py-nova/pkg-descr b/emulators/py-nova/pkg-descr
new file mode 100644
index 000000000000..6c6dfe13919c
--- /dev/null
+++ b/emulators/py-nova/pkg-descr
@@ -0,0 +1,5 @@
+OpenStack Nova provides a cloud computing fabric controller, supporting a wide
+variety of compute technologies, including: libvirt (KVM, Xen, LXC and more),
+Hyper-V, VMware, XenServer and OpenStack Ironic.
+
+WWW: http://openstack.org/nova
diff --git a/emulators/py-nova/pkg-message b/emulators/py-nova/pkg-message
new file mode 100644
index 000000000000..560065737653
--- /dev/null
+++ b/emulators/py-nova/pkg-message
@@ -0,0 +1,47 @@
+Please note that this is a development version of nova.
+Many features are not available.
+
+Currently nova works on FreeBSD 11 and supports QEMU and Xen.
+
+Common issues:
+- Security groups are not implemented
+- ARP spoofing, DHCP isolation protection are not implemented
+- Nova services work from the root user
+- No IPv6 support
+
+QEMU issues:
+- Need to enable serialconsole (TCP)
+- Need to disable online CPU tracking
+- Cannot mount cinder volumes
+
+Xen issues:
+- Live snapshots doesn't work
+- No support for cinder volume hot-plugging
+- XENBUS delay (5 min) when using qemu driver and COW images
+- Some linux images cannot be booted
+
+Nova requires procfs to be mounted.
+Please add this line to /etc/fstab:
+proc /proc procfs rw 0 0
+
+Also devel/libvirt port should be installed with enabled QEMU
+backend or qemu tools installed separately.
+
+Directory to keep VM data should be created manually
+# su -m nova -c "mkdir /var/lib/nova/instances"
+
+For proper networking enable PF
+# sysrc pf_enable="YES"
+# sysrc pflog_enable="YES"
+# sysrc gateway_enable="YES"
+
+/etc/pf.conf should contain:
+rdr-anchor "org.openstack/*"
+nat-anchor "org.openstack/*"
+anchor "org.openstack/*"
+
+To boot images on Xen please specify glance metadata properties
+glance image-update b1216ff6-23ec-4a08-baee-43994760158a \
+ --property hypervisor_type=xen \
+ --property vm_mode=hvm \
+ --property hw_disk_bus=xen
diff --git a/emulators/py-nova/pkg-plist b/emulators/py-nova/pkg-plist
new file mode 100644
index 000000000000..9a5098a03183
--- /dev/null
+++ b/emulators/py-nova/pkg-plist
@@ -0,0 +1,18 @@
+@owner nova
+@dir %%ETCDIR%%
+%%ETCDIR%%/release.sample
+@sample %%ETCDIR%%/nova.conf.sample
+@sample %%ETCDIR%%/nova-compute.conf.sample
+@sample %%ETCDIR%%/logging.conf.sample
+%%ETCDIR%%/README-nova.conf.txt
+%%ETCDIR%%/api-paste.ini
+%%ETCDIR%%/cells.json
+@sample %%ETCDIR%%/nova-config-generator.conf.sample
+@sample %%ETCDIR%%/nova-policy-generator.conf.sample
+%%ETCDIR%%/policy.json
+@owner root
+@sample %%ETCDIR%%/rootwrap.conf.sample
+@dir %%ETCDIR%%/rootwrap.d
+%%ETCDIR%%/rootwrap.d/api-metadata.filters
+%%ETCDIR%%/rootwrap.d/compute.filters
+%%ETCDIR%%/rootwrap.d/network.filters