Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 18 Dec 2016 06:30:58 +0000 (UTC)
From:      Roman Bogorodskiy <novel@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r428837 - in head: . emulators emulators/py-nova emulators/py-nova/files
Message-ID:  <201612180630.uBI6UwYP013550@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: novel
Date: Sun Dec 18 06:30:58 2016
New Revision: 428837
URL: https://svnweb.freebsd.org/changeset/ports/428837

Log:
  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)

Added:
  head/emulators/py-nova/
  head/emulators/py-nova/Makefile   (contents, props changed)
  head/emulators/py-nova/distinfo   (contents, props changed)
  head/emulators/py-nova/files/
  head/emulators/py-nova/files/01-firewall-manager.patch   (contents, props changed)
  head/emulators/py-nova/files/02-freebsd-l3.patch   (contents, props changed)
  head/emulators/py-nova/files/03-nova-conf.patch   (contents, props changed)
  head/emulators/py-nova/files/04-xen-phy.patch   (contents, props changed)
  head/emulators/py-nova/files/05-online-cpus.patch   (contents, props changed)
  head/emulators/py-nova/files/06-freebsd-net.patch   (contents, props changed)
  head/emulators/py-nova/files/nova-api.in   (contents, props changed)
  head/emulators/py-nova/files/nova-cells.in   (contents, props changed)
  head/emulators/py-nova/files/nova-cert.in   (contents, props changed)
  head/emulators/py-nova/files/nova-compute.conf.sample   (contents, props changed)
  head/emulators/py-nova/files/nova-compute.in   (contents, props changed)
  head/emulators/py-nova/files/nova-conductor.in   (contents, props changed)
  head/emulators/py-nova/files/nova-consoleauth.in   (contents, props changed)
  head/emulators/py-nova/files/nova-network.in   (contents, props changed)
  head/emulators/py-nova/files/nova-scheduler.in   (contents, props changed)
  head/emulators/py-nova/files/nova-serialproxy.in   (contents, props changed)
  head/emulators/py-nova/files/nova.conf.sample   (contents, props changed)
  head/emulators/py-nova/pkg-descr   (contents, props changed)
  head/emulators/py-nova/pkg-message   (contents, props changed)
  head/emulators/py-nova/pkg-plist   (contents, props changed)
Modified:
  head/GIDs
  head/UIDs
  head/emulators/Makefile

Modified: head/GIDs
==============================================================================
--- head/GIDs	Sun Dec 18 06:10:44 2016	(r428836)
+++ head/GIDs	Sun Dec 18 06:30:58 2016	(r428837)
@@ -137,7 +137,7 @@ moinmoin:*:192:
 cups:*:193:
 saned:*:194:
 radns:*:195:
-# free: 196
+nova:*:196:
 # free: 197
 # free: 198
 mcserver:*:199:

Modified: head/UIDs
==============================================================================
--- head/UIDs	Sun Dec 18 06:10:44 2016	(r428836)
+++ head/UIDs	Sun Dec 18 06:30:58 2016	(r428837)
@@ -142,7 +142,7 @@ moinmoin:*:192:192::0:0:MoinMoin User:/n
 cups:*:193:193::0:0:Cups Owner:/nonexistent:/usr/sbin/nologin
 saned:*:194:194::0:0:SANE Scanner Daemon:/nonexistent:/bin/sh
 radns:*:195:195::0:0:radns user:/nonexistent:/usr/sbin/nologin
-# free: 196
+nova:*:196:196::0:0:Nova daemon pseudo-user:/var/lib/nova:/usr/sbin/nologin
 # free: 197
 # free: 198
 mcserver:*:199:199::0:0:Minecraft Server:/nonexistent:/bin/sh

Modified: head/emulators/Makefile
==============================================================================
--- head/emulators/Makefile	Sun Dec 18 06:10:44 2016	(r428836)
+++ head/emulators/Makefile	Sun Dec 18 06:30:58 2016	(r428837)
@@ -115,6 +115,7 @@
     SUBDIR += ppsspp-qt4
     SUBDIR += ppsspp-qt5
     SUBDIR += py-gns3-converter
+    SUBDIR += py-nova
     SUBDIR += q4wine
     SUBDIR += qemu
     SUBDIR += qemu-cheri

Added: head/emulators/py-nova/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/emulators/py-nova/Makefile	Sun Dec 18 06:30:58 2016	(r428837)
@@ -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>

Added: head/emulators/py-nova/distinfo
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/emulators/py-nova/distinfo	Sun Dec 18 06:30:58 2016	(r428837)
@@ -0,0 +1,3 @@
+TIMESTAMP = 1478994869
+SHA256 (nova-14.0.2.tar.gz) = e98291734b4b16615fb1518161c89749f09ad33b6344feb70d62b69e8161a50d
+SIZE (nova-14.0.2.tar.gz) = 5574197

Added: head/emulators/py-nova/files/01-firewall-manager.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/emulators/py-nova/files/01-firewall-manager.patch	Sun Dec 18 06:30:58 2016	(r428837)
@@ -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

Added: head/emulators/py-nova/files/02-freebsd-l3.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/emulators/py-nova/files/02-freebsd-l3.patch	Sun Dec 18 06:30:58 2016	(r428837)
@@ -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

Added: head/emulators/py-nova/files/03-nova-conf.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/emulators/py-nova/files/03-nova-conf.patch	Sun Dec 18 06:30:58 2016	(r428837)
@@ -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)
+

Added: head/emulators/py-nova/files/04-xen-phy.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/emulators/py-nova/files/04-xen-phy.patch	Sun Dec 18 06:30:58 2016	(r428837)
@@ -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
+
+
+

Added: head/emulators/py-nova/files/05-online-cpus.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/emulators/py-nova/files/05-online-cpus.patch	Sun Dec 18 06:30:58 2016	(r428837)
@@ -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
+

Added: head/emulators/py-nova/files/06-freebsd-net.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/emulators/py-nova/files/06-freebsd-net.patch	Sun Dec 18 06:30:58 2016	(r428837)
@@ -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)
++

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612180630.uBI6UwYP013550>