Merged tutorial
diff --git a/.gitignore b/.gitignore
index 4adf44a..7813bf4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,4 +15,5 @@
 npm-debug.log
 xos/core/static/*.css
 !xos/core/static/xos.css
-.DS_Store
\ No newline at end of file
+.DS_Store
+xos/configurations/setup
diff --git a/apiary.apib b/apiary.apib
new file mode 100644
index 0000000..43a81c7
--- /dev/null
+++ b/apiary.apib
@@ -0,0 +1,461 @@
+FORMAT: 1A
+
+# XOS
+ 
+ 
+# Group ONOS Services
+
+## ONOS Services Collection [/api/service/onos/]
+
+### List all ONOS Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "service_ONOS_vBNG",
+                "id": 5,
+                "rest_hostname": "",
+                "rest_port": "8181",
+                "no_container": false,
+                "node_key": ""
+            }
+        ]
+ 
+ 
+# Group vSG
+
+## vSG Collection [/api/service/vsg/]
+
+### List all vSGs [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "service_vsg",
+                "id": 2,
+                "wan_container_gateway_ip": "",
+                "wan_container_gateway_mac": "",
+                "dns_servers": "8.8.8.8",
+                "url_filter_kind": null,
+                "node_label": null
+            }
+        ]
+ 
+ 
+# Group Subscribers
+
+Resource related to the CORD Subscribers.
+
+## Subscribers Collection [/api/tenant/cord/subscriber/]
+
+### List All Subscribers [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "cordSubscriber-1",
+                "id": 1,
+                "features": {
+                    "cdn": false,
+                    "uplink_speed": 1000000000,
+                    "downlink_speed": 1000000000,
+                    "uverse": false,
+                    "status": "enabled"
+                },
+                "identity": {
+                    "account_num": "123",
+                    "name": "My House"
+                },
+                "related": {
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "compute_node_name": "node2.opencloud.us",
+                    "c_tag": "432",
+                    "instance_id": 1,
+                    "wan_container_ip": null,
+                    "volt_id": 3,
+                    "s_tag": "222"
+                }
+            }
+        ]
+
+## Subscriber Detail [/api/tenant/cord/subscriber/{subscriber_id}/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+### View a Subscriber Detail [GET]
+
++ Response 200 (application/json)
+ 
+        {
+            "humanReadableName": "cordSubscriber-1", 
+            "id": 1, 
+            "features": { 
+                "cdn": false, 
+                "uplink_speed": 1000000000, 
+                "downlink_speed": 1000000000, 
+                "uverse": false, 
+                "status": "enabled" 
+            }, 
+            "identity": { 
+                "account_num": "123",
+                "name": "My House"
+            }, 
+            "related": { 
+                "instance_name": "mysite_vcpe", 
+                "vsg_id": 4, 
+                "compute_node_name": "node2.opencloud.us",
+                "c_tag": "432", 
+                "instance_id": 1, 
+                "wan_container_ip": null, 
+                "volt_id": 3, 
+                "s_tag": "222" 
+            } 
+        }
+
+### Delete a Subscriber [DELETE]
+
++ Response 204
+
+### Subscriber features [/api/tenant/cord/subscriber/{subscriber_id}/features/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+### View a Subscriber Features Detail [GET]
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false, 
+            "uplink_speed": 1000000000, 
+            "downlink_speed": 1000000000, 
+            "uverse": true, 
+            "status": "enabled"
+        }
+
+#### Subscriber features uplink_speed [/api/tenant/cord/subscriber/{subscriber_id}/features/uplink_speed/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber uplink_speed [GET]
+
++ Response 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
+#### Update Subscriber uplink_speed [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
++ Response 200 (application/json)
+
+        {
+            "uplink_speed": 1000000000
+        }
+
+#### Subscriber features downlink_speed [/api/tenant/cord/subscriber/{subscriber_id}/features/downlink_speed/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber downlink_speed [GET]
+
++ Response 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
+#### Update Subscriber downlink_speed [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
++ Response 200 (application/json)
+
+        {
+            "downlink_speed": 1000000000
+        }
+
+#### Subscriber features cdn [/api/tenant/cord/subscriber/{subscriber_id}/features/cdn/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber cdn [GET]
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
+#### Update Subscriber cdn [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
++ Response 200 (application/json)
+
+        {
+            "cdn": false
+        }
+
+#### Subscriber features uverse [/api/tenant/cord/subscriber/{subscriber_id}/features/uverse/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber uverse [GET]
+
++ Response 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
+#### Update Subscriber uverse [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
++ Response 200 (application/json)
+
+        {
+            "uverse": false
+        }
+
+#### Subscriber features status [/api/tenant/cord/subscriber/{subscriber_id}/features/status/]
+
++ Parameters
+    + subscriber_id: 1 (number) - ID of the Subscriber in the form of an integer
+
+#### Read Subscriber status [GET]
+
++ Response 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
+
+#### Update Subscriber status [PUT]
+
++ Request 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
+
++ Response 200 (application/json)
+
+        {
+            "status": "enabled"
+        }
+ 
+ 
+# Group Truckroll
+
+Virtual Truckroll, enable to perform basic test on user connectivity such as ping, traceroute and tcpdump.
+
+## Truckroll Collection [/api/tenant/truckroll/]
+
+### List all Truckroll [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "vTR-tenant-9",
+                "id": 9,
+                "provider_service": 6,
+                "target_id": 2,
+                "scope": "container",
+                "test": "ping",
+                "argument": "8.8.8.8",
+                "result": "",
+                "result_code": "",
+                "is_synced": false,
+                "backend_status": "2 - Exception('Unreachable results in ansible recipe',)"
+            }
+        ]
+
+### Create a Truckroll [POST]
+
++ Request (application/json)
+
+        {
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8"
+        }
+
++ Response 201 (application/json)
+
+        {
+            "humanReadableName": "vTR-tenant-1",
+            "id": 1,
+            "provider_service": 6,
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8",
+            "result": null,
+            "result_code": null,
+            "is_synced": false,
+            "backend_status": "0 - Provisioning in progress"
+        }
+
+## Truckroll Detail [/api/tenant/truckroll/{truckroll_id}/]
+
+A virtual truckroll is complete once is_synced equal true
+
++ Parameters
+    + truckroll_id: 1 (number) - ID of the Truckroll in the form of an integer
+
+### View a Truckroll Detail [GET]
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "vTR-tenant-10",
+            "id": 10,
+            "provider_service": 6,
+            "target_id": 2,
+            "scope": "container",
+            "test": "ping",
+            "argument": "8.8.8.8",
+            "result": null,
+            "result_code": null,
+            "is_synced": false,
+            "backend_status": "0 - Provisioning in progress"
+        }
+
+### Delete a Truckroll Detail [DELETE]
+
++ Response 204
+
+ 
+ 
+# Group vOLT
+
+OLT devices aggregate a set of subscriber connections
+
+## vOLT Collection [/api/tenant/cord/volt/]
+
+### List all vOLT [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "vOLT-tenant-1",
+                "id": 1,
+                "service_specific_id": "123",
+                "s_tag": "222",
+                "c_tag": "432",
+                "subscriber": 1,
+                "related": {
+                    "instance_id": 1,
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "wan_container_ip": null,
+                    "compute_node_name": "node2.opencloud.us"
+                }
+            }
+        ]
+
+### Create a vOLT [POST]
+
++ Request (application/json)
+
+        {
+            "s_tag": "222",
+            "c_tag": "432",
+            "subscriber": 1
+        }
+
++ Response 201 (application/json)
+
+        {
+                "humanReadableName": "vOLT-tenant-1",
+                "id": 1,
+                "service_specific_id": "123",
+                "s_tag": "222",
+                "c_tag": "432",
+                "subscriber": 1,
+                "related": {
+                    "instance_id": 1,
+                    "instance_name": "mysite_vcpe",
+                    "vsg_id": 4,
+                    "wan_container_ip": null,
+                    "compute_node_name": "node2.opencloud.us"
+                }
+            }
+
+## vOLT Detail [/api/tenant/cord/volt/{volt_id}/]
+
+A virtual volt is complete once is_synced equal true
+
++ Parameters
+    + volt_id: 1 (number) - ID of the vOLT in the form of an integer
+
+### View a vOLT Detail [GET]
+
++ Response 200 (application/json)
+
+        {
+            "humanReadableName": "vOLT-tenant-1",
+            "id": 1,
+            "service_specific_id": "123",
+            "s_tag": "222",
+            "c_tag": "432",
+            "subscriber": 1,
+            "related": {
+                "instance_id": 1,
+                "instance_name": "mysite_vcpe",
+                "vsg_id": 4,
+                "wan_container_ip": null,
+                "compute_node_name": "node2.opencloud.us"
+            }
+        }
+
+ 
+ 
+# Group ONOS Apps
+
+## app Collection [/api/tenant/onos/app/]
+
+### List all apps [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "onos-tenant-7",
+                "id": 7,
+                "name": "vBNG_ONOS_app",
+                "dependencies": "org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd"
+            }
+        ]
\ No newline at end of file
diff --git a/xos/configurations/cord/Dockerfile.cord b/xos/configurations/cord-deprecated/Dockerfile.cord
similarity index 100%
rename from xos/configurations/cord/Dockerfile.cord
rename to xos/configurations/cord-deprecated/Dockerfile.cord
diff --git a/xos/configurations/cord/Makefile b/xos/configurations/cord-deprecated/Makefile
similarity index 100%
rename from xos/configurations/cord/Makefile
rename to xos/configurations/cord-deprecated/Makefile
diff --git a/xos/configurations/cord/Makefile.inside b/xos/configurations/cord-deprecated/Makefile.inside
similarity index 100%
rename from xos/configurations/cord/Makefile.inside
rename to xos/configurations/cord-deprecated/Makefile.inside
diff --git a/xos/configurations/cord/README-VTN.md b/xos/configurations/cord-deprecated/README-VTN.md
similarity index 100%
rename from xos/configurations/cord/README-VTN.md
rename to xos/configurations/cord-deprecated/README-VTN.md
diff --git a/xos/configurations/cord/README.md b/xos/configurations/cord-deprecated/README.md
similarity index 95%
rename from xos/configurations/cord/README.md
rename to xos/configurations/cord-deprecated/README.md
index 606f12a..64075d9 100644
--- a/xos/configurations/cord/README.md
+++ b/xos/configurations/cord-deprecated/README.md
@@ -7,8 +7,10 @@
 * Brings up ONOS apps for controlling the dataplane: virtualbng, olt
 * Configures XOS with the CORD services: vCPE, vBNG, vOLT
 
-**NOTE:** This configuration is under **active development** and is not yet finished!  Some features are not
-fully working yet.
+**NOTE: This configuration is stale and likely not working at present.  If you are looking to evaluate 
+and/or contribute to [CORD](http://opencord.org/), 
+you should look instead at the [cord-pod](../cord-pod) configuration. Almost
+all CORD developers have transitioned to [cord-pod](../cord-pod).**
 
 ## End-to-end dataplane
 
diff --git a/xos/configurations/cord/ceilometer.yaml b/xos/configurations/cord-deprecated/ceilometer.yaml
similarity index 100%
rename from xos/configurations/cord/ceilometer.yaml
rename to xos/configurations/cord-deprecated/ceilometer.yaml
diff --git a/xos/configurations/cord/cord.yaml b/xos/configurations/cord-deprecated/cord.yaml
similarity index 100%
rename from xos/configurations/cord/cord.yaml
rename to xos/configurations/cord-deprecated/cord.yaml
diff --git a/xos/configurations/cord/dataplane/ansible.cfg b/xos/configurations/cord-deprecated/dataplane/ansible.cfg
similarity index 100%
rename from xos/configurations/cord/dataplane/ansible.cfg
rename to xos/configurations/cord-deprecated/dataplane/ansible.cfg
diff --git a/xos/configurations/cord/dataplane/change_controller.sh b/xos/configurations/cord-deprecated/dataplane/change_controller.sh
similarity index 100%
rename from xos/configurations/cord/dataplane/change_controller.sh
rename to xos/configurations/cord-deprecated/dataplane/change_controller.sh
diff --git a/xos/configurations/cord/dataplane/cleanup.sh b/xos/configurations/cord-deprecated/dataplane/cleanup.sh
similarity index 100%
rename from xos/configurations/cord/dataplane/cleanup.sh
rename to xos/configurations/cord-deprecated/dataplane/cleanup.sh
diff --git a/xos/configurations/cord/dataplane/dataplane-bm.yaml b/xos/configurations/cord-deprecated/dataplane/dataplane-bm.yaml
similarity index 100%
rename from xos/configurations/cord/dataplane/dataplane-bm.yaml
rename to xos/configurations/cord-deprecated/dataplane/dataplane-bm.yaml
diff --git a/xos/configurations/cord/dataplane/dataplane-vtn.yaml b/xos/configurations/cord-deprecated/dataplane/dataplane-vtn.yaml
similarity index 100%
rename from xos/configurations/cord/dataplane/dataplane-vtn.yaml
rename to xos/configurations/cord-deprecated/dataplane/dataplane-vtn.yaml
diff --git a/xos/configurations/cord/dataplane/dataplane.yaml b/xos/configurations/cord-deprecated/dataplane/dataplane.yaml
similarity index 100%
rename from xos/configurations/cord/dataplane/dataplane.yaml
rename to xos/configurations/cord-deprecated/dataplane/dataplane.yaml
diff --git a/xos/configurations/cord/dataplane/gen-etc-hosts.sh b/xos/configurations/cord-deprecated/dataplane/gen-etc-hosts.sh
similarity index 100%
rename from xos/configurations/cord/dataplane/gen-etc-hosts.sh
rename to xos/configurations/cord-deprecated/dataplane/gen-etc-hosts.sh
diff --git a/xos/configurations/cord/dataplane/gen-inventory.sh b/xos/configurations/cord-deprecated/dataplane/gen-inventory.sh
similarity index 100%
rename from xos/configurations/cord/dataplane/gen-inventory.sh
rename to xos/configurations/cord-deprecated/dataplane/gen-inventory.sh
diff --git a/xos/configurations/cord/dataplane/generate-bm.sh b/xos/configurations/cord-deprecated/dataplane/generate-bm.sh
similarity index 100%
rename from xos/configurations/cord/dataplane/generate-bm.sh
rename to xos/configurations/cord-deprecated/dataplane/generate-bm.sh
diff --git a/xos/configurations/cord/dataplane/scripts/if_from_ip.py b/xos/configurations/cord-deprecated/dataplane/scripts/if_from_ip.py
similarity index 100%
rename from xos/configurations/cord/dataplane/scripts/if_from_ip.py
rename to xos/configurations/cord-deprecated/dataplane/scripts/if_from_ip.py
diff --git a/xos/configurations/cord/dataplane/scripts/restart-vcpes.sh b/xos/configurations/cord-deprecated/dataplane/scripts/restart-vcpes.sh
similarity index 100%
rename from xos/configurations/cord/dataplane/scripts/restart-vcpes.sh
rename to xos/configurations/cord-deprecated/dataplane/scripts/restart-vcpes.sh
diff --git a/xos/configurations/cord/docker-compose.yml b/xos/configurations/cord-deprecated/docker-compose.yml
similarity index 100%
rename from xos/configurations/cord/docker-compose.yml
rename to xos/configurations/cord-deprecated/docker-compose.yml
diff --git a/xos/configurations/cord/make-virtualbng-json.sh b/xos/configurations/cord-deprecated/make-virtualbng-json.sh
similarity index 100%
rename from xos/configurations/cord/make-virtualbng-json.sh
rename to xos/configurations/cord-deprecated/make-virtualbng-json.sh
diff --git a/xos/configurations/cord/make-vtn-networkconfig-json.sh b/xos/configurations/cord-deprecated/make-vtn-networkconfig-json.sh
similarity index 100%
rename from xos/configurations/cord/make-vtn-networkconfig-json.sh
rename to xos/configurations/cord-deprecated/make-vtn-networkconfig-json.sh
diff --git a/xos/configurations/cord/xos_cord_config b/xos/configurations/cord-deprecated/xos_cord_config
similarity index 100%
copy from xos/configurations/cord/xos_cord_config
copy to xos/configurations/cord-deprecated/xos_cord_config
diff --git a/xos/configurations/cord-pod/Makefile b/xos/configurations/cord-pod/Makefile
index 49a1c98..9296f10 100644
--- a/xos/configurations/cord-pod/Makefile
+++ b/xos/configurations/cord-pod/Makefile
@@ -6,7 +6,7 @@
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/nodes.yaml
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/images.yaml
 
-vtn: vtn_network_cfg_json
+vtn:
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/vtn-external.yaml
 
 cord: virtualbng_json
@@ -15,7 +15,7 @@
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/cord-vtn-vsg.yaml
 
 exampleservice:
-	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/pod-exampleservice.yaml 
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/pod-exampleservice.yaml
 
 cord-ceilometer: ceilometer_custom_images cord
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /root/setup/ceilometer.yaml
diff --git a/xos/configurations/cord-pod/README-Tutorial.md b/xos/configurations/cord-pod/README-Tutorial.md
index 1e3def3..805812f 100644
--- a/xos/configurations/cord-pod/README-Tutorial.md
+++ b/xos/configurations/cord-pod/README-Tutorial.md
@@ -75,24 +75,7 @@
 
 ## Bring up XOS
 
-Under the `cord-pod` configuration, edit file `make-vtn-networkconfig-json.sh`.
-Change the definition of `"publicGateways"` so that it looks like this (adding
-  a second gatewayIp and gatewayMac):
-
-```
-"publicGateways": [
-    {
-        "gatewayIp": "10.168.0.1",
-        "gatewayMac": "02:42:0a:a8:00:01"
-    },
-    {
-        "gatewayIp": "10.168.1.1",
-        "gatewayMac": "02:42:0a:a8:00:01"
-    }
-],
-```
-
-Now run the `make` commands described in the [README.md](./README.md) file:
+Run the `make` commands described in the [README.md](./README.md) file:
 
 ```
 ubuntu@xos:~/xos/xos/configurations/cord-pod$ make
diff --git a/xos/configurations/cord-pod/README.md b/xos/configurations/cord-pod/README.md
index e9b1327..b47a915 100644
--- a/xos/configurations/cord-pod/README.md
+++ b/xos/configurations/cord-pod/README.md
@@ -28,9 +28,13 @@
 
 ### Install OpenStack
 
-Follow the instructions in the [README.md](https://github.com/open-cloud/openstack-cluster-setup/blob/master/README.md)
+To set up OpenStack, follow the instructions in the
+[README.md](https://github.com/open-cloud/openstack-cluster-setup/blob/master/README.md)
 file of the [open-cloud/openstack-cluster-setup](https://github.com/open-cloud/openstack-cluster-setup/)
-repository.
+repository.  If you're just getting started with CORD, it's probably best to begin with the 
+single-node CORD test environment to familiarize yourself with the overall setup.
+
+**NOTE: In order to use the cord-pod configuration, you must set up OpenStack using the above recipe.**
 
 ### Set up ONOS VTN
 
@@ -77,22 +81,39 @@
 
 They will have been put there for you by the cluster installation scripts.
 
-If your setup uses the CORD fabric, you need to edit `make-vtn-networkconfig-json.sh`
-and `cord-vtn-vsg.yml` as appropriate.  Specifically, in
-`make-vtn-networkconfig-json.sh` you need to set these parameters for VTN:
- * gatewayIp
- * gatewayMac
- * PHYPORT
+**If your setup uses the CORD fabric**, you need to modify the autogenerated VTN
+configuration and node tags, and edit `cord-vtn-vsg.yml` as follows.
 
-And in `cord-vtn-vsg.yml`:
- * public_addresses -> properties -> addresses
- * service_vsg -> properties -> wan_container_gateway_ip
- * service_vsg -> properties -> wan_container_gateway_mac
- * service_vsg -> properties -> wan_container_netbits
+ 1. The VTN app configuration is autogenerated by XOS.  For more information
+about the configuration, see [this page on the ONOS Wiki](https://wiki.onosproject.org/display/ONOS/CORD+VTN),
+under the **ONOS Settings** heading.  To see the generated
+configuration, go to http://xos/admin/onos/onosapp/, click on
+*VTN_ONOS_app*, then the *Attributes* tab, and look for the
+`rest_onos/v1/network/configuration/` attribute.  You can edit this
+configuration after deleting the `autogenerate` attribute (otherwise XOS will
+overwrite your changes), or you can change the other
+attributes and delete  `rest_onos/v1/network/configuration/` in order
+to get XOS to regenerate it.
+
+ 2. The process of autoconfiguring VTN also assigns some default values to per-node parameters.  Go to
+ http://xos/admin/core/node/, select a node, then select the *Tags* tab.  Configure the following:
+  * `bridgeId` (the ID to set on the node's br-int)
+  * `dataPlaneIntf` (the data plane interface for the fabric on the node)
+  * `dataPlaneIp` (the IP address for the node on the fabric)
+
+ 3. Modify `cord-vtn-vsg.yml` and set these parameters to the
+appropriate values for the fabric:
+  * `addresses_vsg:properties:addresses` (IP address block of fabric)
+  * `addresses_vsg:properties:gateway_ip` 
+  * `addresses_vsg:properties:gateway_mac`
+  * `service_vsg:properties:wan_container_gateway_ip` (same as `gateway_ip` above and same as `publicGateway:gatewayIp` from VTN configuration)
+  * `service_vsg:properties:wan_container_gateway_mac` (same as `gateway_mac` above and same as `publicGateway:gatewayMac` from VTN configuration)
+  * `service_vsg:properties:wan_container_netbits` (bits in fabric IP address block netmask)
+
 
 If you're not using the fabric then the default values should be OK.  
 
-XOS can then be brought up for CORD by running a few 'make' commands:
+XOS can then be brought up for CORD by running a few `make` commands:
 ```
 ubuntu@xos:~/xos/xos/configurations/cord-pod$ make
 ubuntu@xos:~/xos/xos/configurations/cord-pod$ make vtn
@@ -101,3 +122,36 @@
 
 After the first 'make' command above, you will be able to login to XOS at
 *http://xos/* using username/password `padmin@vicci.org/letmein`.
+
+### Inspecting the vSG
+
+The above series of `make` commands will spin up a vSG for a sample subscriber.  The
+vSG is implemented as a Docker container (using the
+[andybavier/docker-vcpe](https://hub.docker.com/r/andybavier/docker-vcpe/) image
+hosted on Docker Hub) running inside an Ubuntu VM.  Once the VM is created, you
+can login as the `ubuntu` user at the management network IP (172.27.0.x) on the compute node
+hosting the VM, using the private key generated on the head node by the install process.
+For example, in the single-node development POD configuration, you can login to the VM
+with management IP 172.27.0.2 using a ProxyCommand as follows:
+
+```
+ubuntu@pod:~$ ssh -o ProxyCommand="ssh -W %h:%p ubuntu@nova-compute" ubuntu@172.27.0.2
+```
+
+Alternatively, you could copy the generated private key to the compute node
+and login from there:
+
+```
+ubuntu@pod:~$ scp ~/.ssh/id_rsa ubuntu@nova-compute:~/.ssh
+ubuntu@pod:~$ ssh ubuntu@nova-compute
+ubuntu@nova-compute:~$ ssh ubuntu@172.27.0.2
+```
+
+Once logged in to the VM, you can run `sudo docker ps` to see the running
+vSG containers:
+
+```
+ubuntu@mysite-vsg-1:~$ sudo docker ps
+CONTAINER ID        IMAGE                    COMMAND             CREATED             STATUS              PORTS               NAMES
+2b0bfb3662c7        andybavier/docker-vcpe   "/sbin/my_init"     5 days ago          Up 5 days                               vcpe-222-111
+```
diff --git a/xos/configurations/cord-pod/cord-vtn-vsg.yaml b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
index f29e257..c8c6ceb 100644
--- a/xos/configurations/cord-pod/cord-vtn-vsg.yaml
+++ b/xos/configurations/cord-pod/cord-vtn-vsg.yaml
@@ -24,16 +24,25 @@
           view_url: /admin/cord/voltservice/$id$/
           kind: vOLT
 
-    public_addresses:
+    addresses_vsg:
       type: tosca.nodes.AddressPool
       properties:
           addresses: 10.168.0.0/24
+          gateway_ip: 10.168.0.1
+          gateway_mac: 02:42:0a:a8:00:01
+
+    addresses_exampleservice-public:
+      type: tosca.nodes.AddressPool
+      properties:
+          addresses: 10.168.1.0/24
+          gateway_ip: 10.168.1.1
+          gateway_mac: 02:42:0a:a8:00:01
 
     service_vsg:
       type: tosca.nodes.VSGService
       requirements:
-          - vbng_tenant:
-              node: service_vbng
+          - vrouter_tenant:
+              node: service_vrouter
               relationship: tosca.relationships.TenantOfService
       properties:
           view_url: /admin/cord/vsgservice/$id$/
@@ -47,13 +56,17 @@
       artifacts:
           pubkey: /opt/xos/synchronizers/vcpe/vcpe_public_key
 
-    service_vbng:
-      type: tosca.nodes.VBNGService
+    service_vrouter:
+      type: tosca.nodes.VRouterService
       properties:
-          view_url: /admin/cord/vbngservice/$id$/
-# if unspecified, vbng observer will look for an ONOSApp Tenant and
-# generate a URL from its IP address
-#          vbng_url: http://10.11.10.24:8181/onos/virtualbng/
+          view_url: /admin/vrouter/vrouterservice/$id$/
+      requirements:
+          - addresses_vsg:
+              node: addresses_vsg
+              relationship: tosca.relationships.ProvidesAddresses
+          - addresses_service1:
+              node: addresses_exampleservice-public
+              relationship: tosca.relationships.ProvidesAddresses
 
     Private:
       type: tosca.nodes.NetworkTemplate
diff --git a/xos/configurations/cord-pod/docker-compose.yml b/xos/configurations/cord-pod/docker-compose.yml
index cb7194f..234fd43 100644
--- a/xos/configurations/cord-pod/docker-compose.yml
+++ b/xos/configurations/cord-pod/docker-compose.yml
@@ -13,7 +13,7 @@
         - xos_db
     volumes:
         - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
-        - ../cord//xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
         - .:/root/setup:ro
         - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
         - ./images:/opt/xos/images:ro
@@ -96,7 +96,7 @@
     volumes:
         - .:/root/setup:ro
         - ../common/xos_common_config:/opt/xos/xos_configuration/xos_common_config:ro
-        - ../cord/xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
+        - xos_cord_config:/opt/xos/xos_configuration/xos_cord_config:ro
         - ../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro
         - ./id_rsa.pub:/opt/xos/synchronizers/onos/onos_key.pub:ro
         - ./id_rsa.pub:/opt/xos/synchronizers/vcpe/vcpe_public_key:ro
diff --git a/xos/configurations/cord-pod/images/.gitignore b/xos/configurations/cord-pod/images/.gitignore
new file mode 100644
index 0000000..6949d1f
--- /dev/null
+++ b/xos/configurations/cord-pod/images/.gitignore
@@ -0,0 +1,3 @@
+*.img
+*.qcow2
+*.qcow
diff --git a/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh b/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh
deleted file mode 100755
index a1e5137..0000000
--- a/xos/configurations/cord-pod/make-vtn-networkconfig-json.sh
+++ /dev/null
@@ -1,83 +0,0 @@
-FN=$SETUPDIR/vtn-network-cfg.json
-
-echo "Writing to $FN"
-
-rm -f $FN
-
-cat >> $FN <<EOF
-{
-    "apps" : {
-        "org.onosproject.cordvtn" : {
-            "cordvtn" : {
-                "privateGatewayMac" : "00:00:00:00:00:01",
-                "localManagementIp": "172.27.0.1/24",
-                "ovsdbPort": "6641",
-                "sshPort": "22",
-                "sshUser": "root",
-                "sshKeyFile": "/root/node_key",
-                "publicGateways": [
-                    {
-                        "gatewayIp": "10.168.0.1",
-                        "gatewayMac": "02:42:0a:a8:00:01"
-                    }
-                ],
-                "nodes" : [
-EOF
-
-NODES=$( sudo bash -c "source $SETUPDIR/admin-openrc.sh ; nova hypervisor-list" |grep -v ID|grep -v +|awk '{print $4}' )
-
-# XXX disabled - we don't need or want the nm node at this time
-# also configure ONOS to manage the nm node
-#NM="neutron-gateway"
-#NODES="$NODES $NM"
-
-NODECOUNT=0
-for NODE in $NODES; do
-    ((NODECOUNT++))
-done
-
-I=0
-for NODE in $NODES; do
-    echo $NODE
-    NODEIP=`getent hosts $NODE | awk '{ print $1 }'`
-
-    PHYPORT=veth1
-    # How to set LOCALIP?
-    LOCALIPNET="192.168.199"
-
-    ((I++))
-    cat >> $FN <<EOF
-                    {
-                      "hostname": "$NODE",
-                      "hostManagementIp": "$NODEIP/24",
-                      "bridgeId": "of:000000000000000$I",
-                      "dataPlaneIntf": "$PHYPORT",
-                      "dataPlaneIp": "$LOCALIPNET.$I/24"
-EOF
-    if [[ "$I" -lt "$NODECOUNT" ]]; then
-        echo "                    }," >> $FN
-    else
-        echo "                    }" >> $FN
-    fi
-done
-
-# get the openstack admin password and username
-source $SETUPDIR/admin-openrc.sh
-NEUTRON_URL=`keystone endpoint-get --service network|grep publicURL|awk '{print $4}'`
-
-cat >> $FN <<EOF
-                ]
-            }
-        },
-        "org.onosproject.openstackinterface" : {
-            "openstackinterface" : {
-                 "do_not_push_flows" : "true",
-                 "neutron_server" : "$NEUTRON_URL/v2.0/",
-                 "keystone_server" : "$OS_AUTH_URL/",
-                 "user_name" : "$OS_USERNAME",
-                 "password" : "$OS_PASSWORD"
-             }
-        }
-    }
-}
-EOF
diff --git a/xos/configurations/cord-pod/pod-exampleservice.yaml b/xos/configurations/cord-pod/pod-exampleservice.yaml
index 59a9c8f..4e4835c 100644
--- a/xos/configurations/cord-pod/pod-exampleservice.yaml
+++ b/xos/configurations/cord-pod/pod-exampleservice.yaml
@@ -18,11 +18,17 @@
           no-delete: true
           no-update: true
 
+    service_vrouter:
+      type: tosca.nodes.Service
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
     exampleservice-public:
       type: tosca.nodes.network.Network
       properties:
           ip_version: 4
-          cidr: 10.168.1.0/24
       requirements:
           - network_template:
               node: Private
@@ -33,6 +39,9 @@
           - connection:
               node: mysite_exampleservice
               relationship: tosca.relationships.ConnectsToSlice
+          - vrouter_tenant:
+              node: service_vrouter
+              relationship: tosca.relationships.TenantOfService
 
     mysite:
       type: tosca.nodes.Site
diff --git a/xos/configurations/cord-pod/vtn-external.yaml b/xos/configurations/cord-pod/vtn-external.yaml
index 0aaee67..74e7ef7 100644
--- a/xos/configurations/cord-pod/vtn-external.yaml
+++ b/xos/configurations/cord-pod/vtn-external.yaml
@@ -25,6 +25,4 @@
               relationship: tosca.relationships.TenantOfService
       properties:
           dependencies: org.onosproject.drivers, org.onosproject.drivers.ovsdb, org.onosproject.openflow-base, org.onosproject.ovsdb-base, org.onosproject.dhcp, org.onosproject.cordvtn, org.onosproject.olt, org.onosproject.igmp, org.onosproject.cordmcast
-          rest_onos/v1/network/configuration/: { get_artifact: [ SELF, vtn_network_cfg_json, LOCAL_FILE ] }
-      artifacts:
-          vtn_network_cfg_json: /root/setup/vtn-network-cfg.json
+          autogenerate: vtn-network-cfg
diff --git a/xos/configurations/cord/xos_cord_config b/xos/configurations/cord-pod/xos_cord_config
similarity index 100%
rename from xos/configurations/cord/xos_cord_config
rename to xos/configurations/cord-pod/xos_cord_config
diff --git a/xos/configurations/cord/ceilometer-plugins b/xos/configurations/cord/ceilometer-plugins
deleted file mode 160000
index 87cd53b..0000000
--- a/xos/configurations/cord/ceilometer-plugins
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 87cd53b99e43b12f2a175a65440f02f53b564069
diff --git a/xos/configurations/devel/README.md b/xos/configurations/devel/README.md
index df9f999..5dbad10 100644
--- a/xos/configurations/devel/README.md
+++ b/xos/configurations/devel/README.md
@@ -4,6 +4,9 @@
 XOS in three Docker containers (development GUI, Synchronizer, database) and configures XOS
 to talk to an OpenStack backend.  *docker-compose* is used to manage the containers.
 
+**NOTE: If your goal is to create a development environment for [CORD](http://opencord.org/), 
+this configuration is not what you want.  Look at the [cord-pod](../cord-pod) configuration instead!**
+
 ## How to run it
 
 The configuration can be either run on [CloudLab](http://cloudlab.us) (controlling
@@ -41,8 +44,6 @@
 This setup has been run successfully in a VirtualBox VM with 2 CPUs and 4096 GB RAM.
 However it is recommended to use a dedicated server with more resources.
 
-**NOTE: If your goal is to create a development environment for [CORD](http://opencord.org/), 
-DevStack is not what you want.  Look at the [cord-pod](../cord-pod) configuration instead!**
 
 ## What you get
 
diff --git a/xos/configurations/frontend/Makefile b/xos/configurations/frontend/Makefile
index 2b46441..ee2739c 100644
--- a/xos/configurations/frontend/Makefile
+++ b/xos/configurations/frontend/Makefile
@@ -32,3 +32,11 @@
 	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/frontend/mocks/cord.yaml
 	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord/xos_cord_config /opt/xos/xos_configuration/
 	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
+
+mock-cord-pod:
+	echo "make sure to add '../vtn/files/xos_vtn_config:/opt/xos/xos_configuration/xos_vtn_config:ro' to volumes section of docker-compose.yml"
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/common/fixtures.yaml
+	sudo docker-compose run xos python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/mgmt-net.yaml
+	sudo docker-compose run xos bash -c "echo somekey > /opt/xos/synchronizers/vcpe/vcpe_public_key; python /opt/xos/tosca/run.py padmin@vicci.org /opt/xos/configurations/cord-pod/cord-vtn-vsg.yaml"
+	sudo docker exec frontend_xos_1 cp /opt/xos/configurations/cord/xos_cord_config /opt/xos/xos_configuration/
+	sudo docker exec frontend_xos_1 touch /opt/xos/xos/settings.py
diff --git a/xos/configurations/setup/admin-openrc.sh b/xos/configurations/setup/admin-openrc.sh
deleted file mode 100644
index 84e53f6..0000000
--- a/xos/configurations/setup/admin-openrc.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-export OS_PROJECT_DOMAIN_ID=default
-export OS_USER_DOMAIN_ID=default
-export OS_PROJECT_NAME=admin
-export OS_TENANT_NAME=admin
-export OS_USERNAME=adminapi
-export OS_PASSWORD=765e8807825bbd087333
-export OS_AUTH_URL=http://ctl:35357/v3
-export OS_IDENTITY_API_VERSION=3
diff --git a/xos/configurations/setup/ceilometer_url b/xos/configurations/setup/ceilometer_url
deleted file mode 100644
index 586594e..0000000
--- a/xos/configurations/setup/ceilometer_url
+++ /dev/null
@@ -1 +0,0 @@
-http://130.127.133.45/xosmetering/
diff --git a/xos/configurations/setup/controller_settings b/xos/configurations/setup/controller_settings
deleted file mode 100644
index a4f0fab..0000000
--- a/xos/configurations/setup/controller_settings
+++ /dev/null
@@ -1,48 +0,0 @@
-GENIUSER=1
-CONTROLLER="ctl"
-NETWORKMANAGER="nm"
-STORAGEHOST="ctl"
-OBJECTHOST="ctl"
-COMPUTENODES="cp-1 cp-2 "
-DB_ROOT_PASS="f638fdd304e96fe6f264"
-RABBIT_USER="openstack"
-RABBIT_PASS="b3df6035e70fab63fafe"
-ADMIN_API="adminapi"
-ADMIN_API_PASS="765e8807825bbd087333"
-KEYSTONE_DBPASS="0785387a67431d0e679a"
-GLANCE_DBPASS="b8f8af1dbed9ef7c9672"
-GLANCE_PASS="070f62b5aae7bfcb82b1"
-NOVA_DBPASS="000c2e0391b6e6c1efe1"
-NOVA_PASS="4e5cd858d46a773490ac"
-NOVA_COMPUTENODES_DONE="1"
-NEUTRON_DBPASS="2c00ab52cd022784ab1c"
-NEUTRON_PASS="a54a81b15d2a86da80cf"
-NEUTRON_METADATA_SECRET="bace09098263e43cad83"
-NEUTRON_NETWORKMANAGER_DONE="1"
-NEUTRON_COMPUTENODES_DONE="1"
-NEUTRON_NETWORKS_DONE="1"
-DASHBOARD_DONE="1"
-CINDER_DBPASS="9b7303ea7e149a6f37f3"
-CINDER_PASS="1605df1e285197ec716e"
-STORAGE_HOST_DONE="1"
-SWIFT_PASS="bdfcbd193b99e4d53878"
-SWIFT_HASH_PATH_PREFIX="6622bbfb9a47a85353dc"
-SWIFT_HASH_PATH_SUFFIX="860e0d7ecfd3b622b7ff"
-OBJECT_HOST_DONE="1"
-OBJECT_RING_DONE="1"
-HEAT_DBPASS="b478c3dc47d08e5a2dd0"
-HEAT_PASS="e6a1ad28e1585e2d1dc5"
-HEAT_DOMAIN_PASS="0c499d0fd9cb03ef74fe"
-CEILOMETER_DBPASS="909b521d60d942f674df"
-CEILOMETER_PASS="e859d8ba439d808a0b0f"
-CEILOMETER_SECRET="9978523d156d88591b1c"
-TELEMETRY_COMPUTENODES_DONE="1"
-TELEMETRY_GLANCE_DONE="1"
-TELEMETRY_CINDER_DONE="1"
-TELEMETRY_SWIFT_DONE="1"
-TROVE_DBPASS="9df003b06314d65ef2be"
-TROVE_PASS="61be0107aab4211919a2"
-SAHARA_DBPASS="c5a218e87b1fd83c36bc"
-SAHARA_PASS="eb2133117dd1e48d9419"
-SETUP_BASIC_DONE="1"
-CONTROLLER_FLAT_LAN_IP=10.11.10.1
diff --git a/xos/configurations/setup/flat-lan-cp-1.cord.xos-pg0.clemson.cloudlab.us b/xos/configurations/setup/flat-lan-cp-1.cord.xos-pg0.clemson.cloudlab.us
deleted file mode 100644
index 5db289f..0000000
--- a/xos/configurations/setup/flat-lan-cp-1.cord.xos-pg0.clemson.cloudlab.us
+++ /dev/null
@@ -1,8 +0,0 @@
-DATABRIDGE=br-flat-lan-1
-DATAIP=10.11.10.3
-DATANETMASK=255.255.0.0
-DATAVLAN=0
-DATAVLANTAG=0
-DATAVLANDEV=
-DATAMAC=008cfa5b088a
-DATADEV=enp130s0f0
diff --git a/xos/configurations/setup/flat-lan-cp-2.cord.xos-pg0.clemson.cloudlab.us b/xos/configurations/setup/flat-lan-cp-2.cord.xos-pg0.clemson.cloudlab.us
deleted file mode 100644
index f7943d8..0000000
--- a/xos/configurations/setup/flat-lan-cp-2.cord.xos-pg0.clemson.cloudlab.us
+++ /dev/null
@@ -1,8 +0,0 @@
-DATABRIDGE=br-flat-lan-1
-DATAIP=10.11.10.4
-DATANETMASK=255.255.0.0
-DATAVLAN=0
-DATAVLANTAG=0
-DATAVLANDEV=
-DATAMAC=008cfa5b088c
-DATADEV=enp130s0f0
diff --git a/xos/configurations/setup/flat_net_name b/xos/configurations/setup/flat_net_name
deleted file mode 100644
index 09246fa..0000000
--- a/xos/configurations/setup/flat_net_name
+++ /dev/null
@@ -1 +0,0 @@
-flat-lan-1-net
\ No newline at end of file
diff --git a/xos/configurations/setup/id_rsa b/xos/configurations/setup/id_rsa
deleted file mode 100644
index 3678ee0..0000000
--- a/xos/configurations/setup/id_rsa
+++ /dev/null
@@ -1,27 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIEpAIBAAKCAQEAsTKLFAqVd6Co8xXihfuFzyilUpufjy01tVmVwIssmZRgWNlZ
-EvD7L+pAVMoQDEPLmv3jF/+u7QHoIN/KOniC2SzYLuqTbFZ2lYhb7Qbnq/gFzqbn
-aKelUqD/BCPi+FmZuOWrzHr80UApwD0rfwJSHdkFPooz9ADBVr739EFnwhywJdDc
-6fT8GLfr8au6FXiPMQMd1y+DxoYvBqC1yRW8aJ/+jHeJ6+8A0eLlHpAohx1GewhL
-ilI/doswoC+pxyoES3/6BApGZcp6xvmRrLTvvC8Nao3bMBvVOu91SFGUptj/gNse
-lhv7g1eDChn/sjnQ580lG/a9Lki427i0l1VIWQIDAQABAoIBAHkLnug85qfGr0MH
-Qyvlix3dlTneJ1xmNNdCcEMMj5YGPt7S8r82sVClA/cn5ViLg23IW7aMKhGriMfU
-OFBC/Jegw7kg8z5BvlYdxTYgzmeyUT0+1LuwMgZFBo/sd+LRSmp9MiPILCZBX4P8
-BVeI3VGYa7WyMRVQ4sIASF+pwlhdn5SJt7rUrNHPgztHkuWn9jaC0TYDCINFGAiU
-D1XgOkh9fils+gbeW1BVy03MwFJrpf2qFe3BA/hF51dUdH4+62aOb7OlBj3KE/K1
-1L3EkZLD8yTGjV5S2RxR9/7szh2XOPlct3TaWaqeplG40UOAToTqjFQKVzhnKvLD
-JSbAbCUCgYEA1jhsyyCrKgUdY50Ybx8KqYvs+Y80iDOmc7Be2cubvg7VrhPD/zkS
-gy/WLSnL3bEU3rB2PZ7B0M3w3gGjK8BzedoLKOQ77OM+qlYax/a7GIQvF+jNGM8n
-4w7S4L9svoTmukqjSCjOlCx0E1G7PvP1xyE2GCqX2TXD0hJpO7hHA6sCgYEA08Gj
-kDUwdNxYq2m4+CTcupEPn+BRlpUFQkWt9pSRAjHsij5M1XcwcegabthRdTf8ix9d
-rAB80IZRJJMf+mwuT7hHFi1h+mkyAr7YcZ4uOTu1PraervdLs40GImHPk2d3ggWe
-28amqCCUmW7CJzfQsI72bHli/S8Y+TAlkzi4YAsCgYEAuaOSHAFGcxaVnlJv7zQO
-UFky1h1Un8dqsoyf1cuNPomqgL0eN1llAox85Qx4X7hqZoSzIrkmKmWdGzZ+CZcw
-OuNKkngeui0/i+ssMCdPgXJjQSv8OEikvy6EbkFU4lFXhQ7TKuA6DMvtFyTXyDkv
-vw23y/91McVW2gAcc6VA3RsCgYBWyYor1GDjxFtjBZWVviXpIQLyV5GY0cKyArTl
-1sYHzEZR8m6zHoJwbNxIicf47tVGf7h4gkqlfCdNgi8dB7GDYtdfs4Hwi6S/k1BK
-YLY5JsuFxHsM4rXYBPh6pvPYShOk6oDNOoGbbp74s3hHcozJkA5XLvjvI5psptr/
-l8OZOQKBgQCu64v70zDXaaeDnbHfnABuo00YBgjOVXa8YwVUYdP/qpYR7vKLdrvx
-lT/658Lup7vD+9xTWqaLlp5KehyFXNBARGl7oNRWQjZbIWWVVGwx4WjcmEk93BjV
-cogv+YEeGyzsDHDYu7VmoPYc/WAugGD/c9btLFU2QMKQV4vvmf1+cg==
------END RSA PRIVATE KEY-----
diff --git a/xos/configurations/setup/id_rsa.pub b/xos/configurations/setup/id_rsa.pub
deleted file mode 100644
index cc8fa0d..0000000
--- a/xos/configurations/setup/id_rsa.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxMosUCpV3oKjzFeKF+4XPKKVSm5+PLTW1WZXAiyyZlGBY2VkS8Psv6kBUyhAMQ8ua/eMX/67tAegg38o6eILZLNgu6pNsVnaViFvtBuer+AXOpudop6VSoP8EI+L4WZm45avMevzRQCnAPSt/AlId2QU+ijP0AMFWvvf0QWfCHLAl0Nzp9PwYt+vxq7oVeI8xAx3XL4PGhi8GoLXJFbxon/6Md4nr7wDR4uUekCiHHUZ7CEuKUj92izCgL6nHKgRLf/oECkZlynrG+ZGstO+8Lw1qjdswG9U673VIUZSm2P+A2x6WG/uDV4MKGf+yOdDnzSUb9r0uSLjbuLSXVUhZ teone@ctl.cord.xos-pg0.clemson.cloudlab.us
diff --git a/xos/configurations/setup/node_key b/xos/configurations/setup/node_key
deleted file mode 100644
index c6bd19b..0000000
--- a/xos/configurations/setup/node_key
+++ /dev/null
@@ -1,16 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQDKuGcchWTf4G/UXCzbKgKEnca8HvNv1nUW/h0NyZtXDFSpBldu
-dsXn5qPkeFkhvGz26KnuD+VOAV2eLfzRWdwkj3+GX8V18ifcm3j8j6Zxur7KQzPk
-P2SXRdFhKMv0iBVvu1qBg176TcqJBwBCNi9wVJV6RzYaY7LzhyNIn+SBWwIDAQAB
-AoGAFzYmGE3tzvST2Wz0dePJhgXKy59/oD6eCZPvH7UF5GG1D+V5/Vv8LSFrgq2F
-ByfcEilxy6BmURg27/W0DQSNAC5wx5wpt/dBFfaoYx9jC4vtXliFa2fwQLisE2mj
-htz36oMQplsOpbnJbFvuDvGb5ATZe44QR2ZSadLFLIEB9IECQQDv+qeAdrBLzc3T
-4kvwJaIdq/0C8G1Nq5HoMuI/o7UeyjDzbv8yL3ICVE/CbvwY6e96dM2RAVrZW3S1
-xMASQge3AkEA2ED60IZOn34toOPdqansCEzbPfOjP2FkCasvBdmhGaSCFzttLP1J
-x/Ff1wsr7N4lq9D3x9CsNfKCdj9x9n0rfQJBAN3NYVXF3YoirNPiu+c5EU61cQNv
-bsc0BYaEyUKir7vGi1nkRHCBE7H9dT6zT8RDK/mVzY3xn6N3+TYrpI77gp8CQHMD
-3GIbjKV3Tn1LtBEQtuCTP+frNN/4xGQAD7pkzTH+NNJ2YNKUxDD7R6Xv4yTP4elH
-8wDrEyx+FrUdeVdHq2ECQQDaQLzVDsBGDWgKh8ljoLgNCgp8QD8ykYe5xifWsr0r
-R2Eh7n1YMbS4S3Duomz3k2S6LdIwJaKVxK1Ak+2lvF0z
------END RSA PRIVATE KEY-----
-
diff --git a/xos/configurations/setup/node_key.pub b/xos/configurations/setup/node_key.pub
deleted file mode 100644
index b917c9e..0000000
--- a/xos/configurations/setup/node_key.pub
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDKuGcchWTf4G/UXCzbKgKEnca8HvNv1nUW/h0NyZtXDFSpBldudsXn5qPkeFkhvGz26KnuD+VOAV2eLfzRWdwkj3+GX8V18ifcm3j8j6Zxur7KQzPkP2SXRdFhKMv0iBVvu1qBg176TcqJBwBCNi9wVJV6RzYaY7LzhyNIn+SBWw==
diff --git a/xos/configurations/setup/nodes.yaml b/xos/configurations/setup/nodes.yaml
deleted file mode 100644
index f9ceb0e..0000000
--- a/xos/configurations/setup/nodes.yaml
+++ /dev/null
@@ -1,31 +0,0 @@
-tosca_definitions_version: tosca_simple_yaml_1_0
-
-imports:
-   - custom_types/xos.yaml
-
-description: autogenerated nodes file
-
-topology_template:
-  node_templates:
-    MyDeployment:
-        type: tosca.nodes.Deployment
-    mysite:
-        type: tosca.nodes.Site
-    cp-1.cord.xos-pg0.clemson.cloudlab.us:
-      type: tosca.nodes.Node
-      requirements:
-        - site:
-            node: mysite
-            relationship: tosca.relationships.MemberOfSite
-        - deployment:
-            node: MyDeployment
-            relationship: tosca.relationships.MemberOfDeployment
-    cp-2.cord.xos-pg0.clemson.cloudlab.us:
-      type: tosca.nodes.Node
-      requirements:
-        - site:
-            node: mysite
-            relationship: tosca.relationships.MemberOfSite
-        - deployment:
-            node: MyDeployment
-            relationship: tosca.relationships.MemberOfDeployment
diff --git a/xos/configurations/setup/padmin_public_key b/xos/configurations/setup/padmin_public_key
deleted file mode 100644
index cc8fa0d..0000000
--- a/xos/configurations/setup/padmin_public_key
+++ /dev/null
@@ -1 +0,0 @@
-ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxMosUCpV3oKjzFeKF+4XPKKVSm5+PLTW1WZXAiyyZlGBY2VkS8Psv6kBUyhAMQ8ua/eMX/67tAegg38o6eILZLNgu6pNsVnaViFvtBuer+AXOpudop6VSoP8EI+L4WZm45avMevzRQCnAPSt/AlId2QU+ijP0AMFWvvf0QWfCHLAl0Nzp9PwYt+vxq7oVeI8xAx3XL4PGhi8GoLXJFbxon/6Md4nr7wDR4uUekCiHHUZ7CEuKUj92izCgL6nHKgRLf/oECkZlynrG+ZGstO+8Lw1qjdswG9U673VIUZSm2P+A2x6WG/uDV4MKGf+yOdDnzSUb9r0uSLjbuLSXVUhZ teone@ctl.cord.xos-pg0.clemson.cloudlab.us
diff --git a/xos/configurations/setup/virtualbng.json b/xos/configurations/setup/virtualbng.json
deleted file mode 100644
index 843ac04..0000000
--- a/xos/configurations/setup/virtualbng.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "localPublicIpPrefixes" : [
-        "10.254.0.128/25"
-    ],
-    "nextHopIpAddress" : "10.254.0.1",
-    "publicFacingMac" : "00:00:00:00:00:66",
-    "xosIpAddress" : "10.11.10.1",
-    "xosRestPort" : "9999",
-    "hosts" : {
-      "cp-1.cord.xos-pg0.clemson.cloudlab.us" : "of:0000000000000001/1",
-      "cp-2.cord.xos-pg0.clemson.cloudlab.us" : "of:0000000000000001/1"
-    }
-}
diff --git a/xos/configurations/setup/vtn-network-cfg.json b/xos/configurations/setup/vtn-network-cfg.json
deleted file mode 100644
index 4d7ab07..0000000
--- a/xos/configurations/setup/vtn-network-cfg.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
-    "apps" : {
-        "org.onosproject.cordvtn" : {
-            "cordvtn" : {
-                "privateGatewayMac" : "00:00:00:00:00:01",
-                "localManagementIp": "172.27.0.1/24",
-                "ovsdbPort": "6641",
-                "sshPort": "22",
-                "sshUser": "root",
-                "sshKeyFile": "/root/node_key",
-                "publicGateways": [
-                    {
-                        "gatewayIp": "10.123.0.1",
-                        "gatewayMac": "00:8c:fa:5b:09:d8"
-                    }
-                ],
-                "nodes" : [
-                    {
-                      "hostname": "cp-1.cord.xos-pg0.clemson.cloudlab.us",
-                      "hostManagementIp": "130.127.133.46/24",
-                      "bridgeId": "of:0000000000000001",
-                      "dataPlaneIntf": "enp130s0f0",
-                      "dataPlaneIp": "10.11.10.3/24"
-                    },
-                    {
-                      "hostname": "cp-2.cord.xos-pg0.clemson.cloudlab.us",
-                      "hostManagementIp": "130.127.133.39/24",
-                      "bridgeId": "of:0000000000000002",
-                      "dataPlaneIntf": "enp130s0f0",
-                      "dataPlaneIp": "10.11.10.4/24"
-                    }
-                ]
-            }
-        },
-        "org.onosproject.openstackinterface" : {
-            "openstackinterface" : {
-                 "do_not_push_flows" : "true",
-                 "neutron_server" : "http://130.127.133.45:9696/v2.0/",
-                 "keystone_server" : "http://130.127.133.45:5000/v2.0/",
-                 "user_name" : "adminapi",
-                 "password" : "765e8807825bbd087333"
-             }
-        }
-    }
-}
diff --git a/xos/core/admin.py b/xos/core/admin.py
index 7a88d0e..ee6c6bf 100644
--- a/xos/core/admin.py
+++ b/xos/core/admin.py
@@ -2109,6 +2109,39 @@
 
         return tabs
 
+class AddressPoolForm(forms.ModelForm):
+    class Meta:
+        model = Program
+        widgets = {
+            'addresses': UploadTextareaWidget(attrs={'rows': 20, 'cols': 80, 'class': "input-xxlarge"}),
+        }
+
+class AddressPoolAdmin(XOSBaseAdmin):
+    list_display = ("name", "cidr")
+    list_display_links = ('name',)
+
+    form=AddressPoolForm
+
+    fieldsets = [
+        (None, {'fields': ['name', 'cidr', 'gateway_ip', 'gateway_mac', 'addresses', 'inuse', 'service'],
+                'classes':['suit-tab suit-tab-general']}),
+                ]
+
+    readonly_fields = ("status",)
+
+    @property
+    def suit_form_tabs(self):
+        tabs=[('general','Program Details'),
+              ('contents','Program Source'),
+              ('messages','Messages'),
+        ]
+
+#        request=getattr(_thread_locals, "request", None)
+#        if request and request.user.is_admin:
+#            tabs.append( ('admin-only', 'Admin-Only') )
+
+        return tabs
+
 # Now register the new UserAdmin...
 admin.site.register(User, UserAdmin)
 # ... and, since we're not using Django's builtin permissions,
@@ -2151,5 +2184,5 @@
     admin.site.register(TenantRoot, TenantRootAdmin)
     admin.site.register(TenantRootRole, TenantRootRoleAdmin)
     admin.site.register(TenantAttribute, TenantAttributeAdmin)
-#    admin.site.register(Container, ContainerAdmin)
+    admin.site.register(AddressPool, AddressPoolAdmin)
 
diff --git a/xos/core/models/network.py b/xos/core/models/network.py
index 6af72bf..8373814 100644
--- a/xos/core/models/network.py
+++ b/xos/core/models/network.py
@@ -2,7 +2,7 @@
 import socket
 import sys
 from django.db import models, transaction
-from core.models import PlCoreBase, Site, Slice, Instance, Controller
+from core.models import PlCoreBase, Site, Slice, Instance, Controller, Service
 from core.models import ControllerLinkManager,ControllerLinkDeletionManager
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes import generic
@@ -350,7 +350,11 @@
 class AddressPool(PlCoreBase):
     name = models.CharField(max_length=32)
     addresses = models.TextField(blank=True, null=True)
+    gateway_ip = models.CharField(max_length=32, null=True)
+    gateway_mac = models.CharField(max_length=32, null=True)
+    cidr = models.CharField(max_length=32, null=True)
     inuse = models.TextField(blank=True, null=True)
+    service = models.ForeignKey(Service, related_name="addresspools", null=True, blank=True)
 
     def __unicode__(self): return u'%s' % (self.name)
 
diff --git a/xos/core/models/plcorebase.py b/xos/core/models/plcorebase.py
index 4170697..c8c25a7 100644
--- a/xos/core/models/plcorebase.py
+++ b/xos/core/models/plcorebase.py
@@ -211,7 +211,8 @@
     deleted = models.BooleanField(default=False)
     write_protect = models.BooleanField(default=False)
     lazy_blocked = models.BooleanField(default=False)
-    no_sync = models.BooleanField(default=False)
+    no_sync = models.BooleanField(default=False)     # prevent object sync
+    no_policy = models.BooleanField(default=False)   # prevent model_policy run
 
     class Meta:
         # Changing abstract to False would require the managers of subclasses of
diff --git a/xos/core/models/service.py b/xos/core/models/service.py
index aca4bb0..920bc3b 100644
--- a/xos/core/models/service.py
+++ b/xos/core/models/service.py
@@ -188,6 +188,9 @@
 #                if ns.network.template.access in ["direct", "indirect"]:
 #                    # skip access networks; we want to use the private network
 #                    continue
+                if "management" in ns.network.name:
+                    # don't try to connect the management network to anything
+                    continue
                 if ns.network.name in ["wan_network", "lan_network"]:
                     # we don't want to attach to the vCPE's lan or wan network
                     # we only want to attach to its private network
@@ -365,10 +368,12 @@
 
     # The next four things are the various type of objects that can be subscribers of this Tenancy
     # relationship. One and only one can be used at a time.
+    # XXX these should really be changed to GenericForeignKey
     subscriber_service = models.ForeignKey(Service, related_name='subscribed_tenants', blank=True, null=True)
     subscriber_tenant = models.ForeignKey("Tenant", related_name='subscribed_tenants', blank=True, null=True)
     subscriber_user = models.ForeignKey("User", related_name='subscribed_tenants', blank=True, null=True)
     subscriber_root = models.ForeignKey("TenantRoot", related_name="subscribed_tenants", blank=True, null=True)
+    subscriber_network = models.ForeignKey("Network", related_name="subscribed_tenants", blank=True, null=True)
 
     # Service_specific_attribute and service_specific_id are opaque to XOS
     service_specific_id = StrippedCharField(max_length=30, blank=True, null=True)
diff --git a/xos/core/models/user.py b/xos/core/models/user.py
index 0b8e3af..4acad99 100644
--- a/xos/core/models/user.py
+++ b/xos/core/models/user.py
@@ -127,6 +127,9 @@
                                       default="Provisioning in progress")
     deleted = models.BooleanField(default=False)
     write_protect = models.BooleanField(default=False)
+    lazy_blocked = models.BooleanField(default=False)
+    no_sync = models.BooleanField(default=False)     # prevent object sync
+    no_policy = models.BooleanField(default=False)   # prevent model_policy run
 
     timezone = TimeZoneField()
 
diff --git a/xos/services/cord/models.py b/xos/services/cord/models.py
index 07c169d..0da4809 100644
--- a/xos/services/cord/models.py
+++ b/xos/services/cord/models.py
@@ -8,6 +8,7 @@
 from operator import itemgetter, attrgetter, methodcaller
 from core.models import Tag
 from core.models.service import LeastLoadedNodeScheduler
+from services.vrouter.models import VRouterService, VRouterTenant
 import traceback
 from xos.exceptions import *
 from xos.config import Config
@@ -448,6 +449,7 @@
     def __init__(self, *args, **kwargs):
         super(VSGTenant, self).__init__(*args, **kwargs)
         self.cached_vbng=None
+        self.cached_vrouter=None
 
     @property
     def vbng(self):
@@ -468,6 +470,24 @@
         raise XOSConfigurationError("vCPE.vBNG cannot be set this way -- create a new vBNG object and set it's subscriber_tenant instead")
 
     @property
+    def vrouter(self):
+        vrouter = self.get_newest_subscribed_tenant(VRouterTenant)
+        if not vrouter:
+            return None
+
+        # always return the same object when possible
+        if (self.cached_vrouter) and (self.cached_vrouter.id == vrouter.id):
+            return self.cached_vrouter
+
+        vrouter.caller = self.creator
+        self.cached_vrouter = vrouter
+        return vrouter
+
+    @vrouter.setter
+    def vrouter(self, value):
+        raise XOSConfigurationError("vCPE.vRouter cannot be set this way -- create a new vRuter object and set its subscriber_tenant instead")
+
+    @property
     def volt(self):
         if not self.subscriber_tenant:
             return None
@@ -559,21 +579,20 @@
 
     @property
     def wan_container_ip(self):
-        if CORD_USE_VTN:
-            # When using VTN, wan_container_ip is stored and maintained inside
-            # of the vSG object.
-            return self.get_attribute("wan_container_ip", self.default_attributes["wan_container_ip"])
+        if self.vrouter:
+            return self.vrouter.public_ip
         else:
-            # When not using VTN, wan_container_ip is the same as wan_ip.
-            # XXX Is this broken for multiple-containers-per-VM?
-            return self.wan_ip
+            if  (CORD_USE_VTN):
+                # Should this be an error?
+                return None
+            else:
+                # When not using VTN, wan_container_ip is the same as wan_ip.
+                # XXX Is this broken for multiple-containers-per-VM?
+                return self.wan_ip
 
     @wan_container_ip.setter
     def wan_container_ip(self, value):
-        if CORD_USE_VTN:
-            self.set_attribute("wan_container_ip", value)
-        else:
-            raise Exception("wan_container_ip.setter called on non-VTN CORD")
+        raise Exception("wan_container_ip is not settable")
 
     def ip_to_mac(self, ip):
         (a, b, c, d) = ip.split('.')
@@ -582,9 +601,38 @@
     # Generate the MAC for the container interface connected to WAN
     @property
     def wan_container_mac(self):
-        if not self.wan_container_ip:
-            return None
-        return self.ip_to_mac(self.wan_container_ip)
+        if self.vrouter:
+            return self.vrouter.public_mac
+        else:
+            if (CORD_USE_VTN):
+                # Should this be an error?
+                return None
+            else:
+                return self.ip_to_mac(self.wan_container_ip)
+
+    @property
+    def wan_vm_ip(self):
+        tags = Tag.select_by_content_object(self.instance).filter(name="vm_vrouter_tenant")
+        if tags:
+            tenant = VRouterTenant.objects.get(id=tags[0].value)
+            return tenant.public_ip
+        else:
+            if CORD_USE_VTN:
+                raise Exception("no vm_vrouter_tenant tag for instance %s" % o.instance)
+            else:
+                return ""
+
+    @property
+    def wan_vm_mac(self):
+        tags = Tag.select_by_content_object(self.instance).filter(name="vm_vrouter_tenant")
+        if tags:
+            tenant = VRouterTenant.objects.get(id=tags[0].value)
+            return tenant.public_mac
+        else:
+            if CORD_USE_VTN:
+                raise Exception("no vm_vrouter_tenant tag for instance %s" % o.instance)
+            else:
+                return ""
 
     @property
     def private_ip(self):
@@ -631,6 +679,28 @@
             # print "XXX cleanup vnbg", self.vbng
             self.vbng.delete()
 
+    def get_vrouter_service(self):
+        vrouterServices = VRouterService.get_service_objects().all()
+        if not vrouterServices:
+            raise XOSConfigurationError("No VROUTER Services available")
+        return vrouterServices[0]
+
+    def manage_vrouter(self):
+        # Each vCPE object owns exactly one vRouterTenant object
+
+        if self.deleted:
+            return
+
+        if self.vrouter is None:
+            vrouter = self.get_vrouter_service().get_tenant(address_pool_name="addresses_vsg", subscriber_tenant = self)
+            vrouter.caller = self.creator
+            vrouter.save()
+
+    def cleanup_vrouter(self):
+        if self.vrouter:
+            # print "XXX cleanup vrouter", self.vrouter
+            self.vrouter.delete()
+
     def cleanup_orphans(self):
         # ensure vCPE only has one vBNG
         cur_vbng = self.vbng
@@ -639,6 +709,13 @@
                 # print "XXX clean up orphaned vbng", vbng
                 vbng.delete()
 
+        # ensure vCPE only has one vRouter
+        cur_vrouter = self.vrouter
+        for vrouter in list(self.get_subscribed_tenants(VRouterTenant)):
+            if (not cur_vrouter) or (vrouter.id != cur_vrouter.id):
+                # print "XXX clean up orphaned vrouter", vrouter
+                vrouter.delete()
+
         if self.orig_instance_id and (self.orig_instance_id != self.get_attribute("instance_id")):
             instances=Instance.objects.filter(id=self.orig_instance_id)
             if instances:
@@ -741,33 +818,6 @@
                 self.bbs_account = None
                 super(VSGTenant, self).save()
 
-    def get_wan_address_from_pool(self):
-        ap = AddressPool.objects.filter(name="public_addresses")
-        if not ap:
-            raise Exception("AddressPool 'public_addresses' does not exist. Please configure it.")
-        ap = ap[0]
-
-        addr = ap.get_address()
-        if not addr:
-            raise Exception("AddressPool 'public_addresses' has run out of addresses.")
-        return addr
-
-    def put_wan_address_to_pool(self, addr):
-        AddressPool.objects.filter(name="public_addresses")[0].put_address(addr)
-
-    def manage_wan_container_ip(self):
-        if CORD_USE_VTN:
-            if not self.wan_container_ip:
-                addr = self.get_wan_address_from_pool()
-
-                self.wan_container_ip = addr
-                super(TenantWithContainer, self).save()
-
-    def cleanup_wan_container_ip(self):
-        if CORD_USE_VTN and self.wan_container_ip:
-            self.put_wan_address_to_pool(self.wan_container_ip)
-            self.wan_container_ip = None
-
     def find_or_make_port(self, instance, network, **kwargs):
         port = Port.objects.filter(instance=instance, network=network)
         if port:
@@ -829,10 +879,12 @@
             # VTN-CORD needs a WAN address for the VM, so that the VM can
             # be configured.
             if CORD_USE_VTN:
-                tags = Tag.select_by_content_object(instance).filter(name="vm_wan_addr")
+                tags = Tag.select_by_content_object(instance).filter(name="vm_vrouter_tenant")
                 if not tags:
-                    address = self.get_wan_address_from_pool()
-                    tag = Tag(service=self.provider_service, content_object=instance, name="vm_wan_addr", value="%s,%s,%s" % ("public_addresses", address, self.ip_to_mac(address)))
+                    vrouter = self.get_vrouter_service().get_tenant(address_pool_name="addresses_vsg", subscriber_service = self.provider_service)
+                    vrouter.set_attribute("tenant_for_instance_id", instance.id)
+                    vrouter.save()
+                    tag = Tag(service=self.provider_service, content_object=instance, name="vm_vrouter_tenant", value="%d" % vrouter.id)
                     tag.save()
 
     def save(self, *args, **kwargs):
@@ -849,8 +901,8 @@
 
     def delete(self, *args, **kwargs):
         self.cleanup_vbng()
+        self.cleanup_vrouter()
         self.cleanup_container()
-        self.cleanup_wan_container_ip()
         super(VSGTenant, self).delete(*args, **kwargs)
 
 def model_policy_vcpe(pk):
@@ -860,9 +912,9 @@
         if not vcpe:
             return
         vcpe = vcpe[0]
-        vcpe.manage_wan_container_ip()
         vcpe.manage_container()
-        vcpe.manage_vbng()
+        vcpe.manage_vrouter()
+        #vcpe.manage_vbng()
         vcpe.manage_bbs_account()
         vcpe.cleanup_orphans()
 
diff --git a/xos/services/vrouter/__init__.py b/xos/services/vrouter/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/xos/services/vrouter/__init__.py
@@ -0,0 +1 @@
+
diff --git a/xos/services/vrouter/admin.py b/xos/services/vrouter/admin.py
new file mode 100644
index 0000000..318b3dc
--- /dev/null
+++ b/xos/services/vrouter/admin.py
@@ -0,0 +1,113 @@
+from django.contrib import admin
+
+from services.vrouter.models import *
+from django import forms
+from django.utils.safestring import mark_safe
+from django.contrib.auth.admin import UserAdmin
+from django.contrib.admin.widgets import FilteredSelectMultiple
+from django.contrib.auth.forms import ReadOnlyPasswordHashField
+from django.contrib.auth.signals import user_logged_in
+from django.utils import timezone
+from django.contrib.contenttypes import generic
+from suit.widgets import LinkedSelect
+from core.models import AddressPool
+from core.admin import ServiceAppAdmin,SliceInline,ServiceAttrAsTabInline, ReadOnlyAwareAdmin, XOSTabularInline, ServicePrivilegeInline, TenantRootTenantInline, TenantRootPrivilegeInline
+from core.middleware import get_request
+
+from functools import update_wrapper
+from django.contrib.admin.views.main import ChangeList
+from django.core.urlresolvers import reverse
+from django.contrib.admin.utils import quote
+
+class VRouterServiceForm(forms.ModelForm):
+    def __init__(self,*args,**kwargs):
+        super (VRouterServiceForm,self ).__init__(*args,**kwargs)
+
+    def save(self, commit=True):
+        return super(VRouterServiceForm, self).save(commit=commit)
+
+    class Meta:
+        model = VRouterService
+
+class VRouterServiceAdmin(ReadOnlyAwareAdmin):
+    model = VRouterService
+    verbose_name = "vRouter Service"
+    verbose_name_plural = "vRouter Service"
+    list_display = ("backend_status_icon", "name", "enabled")
+    list_display_links = ('backend_status_icon', 'name', )
+    fieldsets = [(None, {'fields': ['backend_status_text', 'name','enabled','versionNumber', 'description', "view_url", "icon_url", ],
+                         'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', )
+    inlines = [SliceInline,ServiceAttrAsTabInline,ServicePrivilegeInline]
+    form = VRouterServiceForm
+
+    extracontext_registered_admins = True
+
+    user_readonly_fields = ["name", "enabled", "versionNumber", "description"]
+
+    suit_form_tabs =(('general', 'vRouter Service Details'),
+        ('administration', 'Administration'),
+        #('tools', 'Tools'),
+        ('slices','Slices'),
+        ('serviceattrs','Additional Attributes'),
+        ('serviceprivileges','Privileges'),
+    )
+
+    suit_form_includes = (('vrouteradmin.html', 'top', 'administration'),
+                           ) #('hpctools.html', 'top', 'tools') )
+
+    def queryset(self, request):
+        return VRouterService.get_service_objects_by_user(request.user)
+
+class VRouterTenantForm(forms.ModelForm):
+    public_ip = forms.CharField(required=True)
+    public_mac = forms.CharField(required=True)
+    gateway_ip = forms.CharField(required=False)
+    gateway_mac = forms.CharField(required=False)
+    cidr = forms.CharField(required=False)
+    address_pool = forms.ModelChoiceField(queryset=AddressPool.objects.all(),required=False)
+
+    def __init__(self,*args,**kwargs):
+        super (VRouterTenantForm,self ).__init__(*args,**kwargs)
+        self.fields['kind'].widget.attrs['readonly'] = True
+        self.fields['provider_service'].queryset = VRouterService.get_service_objects().all()
+        if self.instance:
+            # fields for the attributes
+            self.fields['address_pool'].initial = self.instance.address_pool
+            self.fields['public_ip'].initial = self.instance.public_ip
+            self.fields['public_mac'].initial = self.instance.public_mac
+            self.fields['gateway_ip'].initial = self.instance.gateway_ip
+            self.fields['gateway_mac'].initial = self.instance.gateway_mac
+            self.fields['cidr'].initial = self.instance.cidr
+        if (not self.instance) or (not self.instance.pk):
+            # default fields for an 'add' form
+            self.fields['kind'].initial = VROUTER_KIND
+            if VRouterService.get_service_objects().exists():
+               self.fields["provider_service"].initial = VRouterService.get_service_objects().all()[0]
+
+    def save(self, commit=True):
+        self.instance.public_ip = self.cleaned_data.get("public_ip")
+        self.instance.public_mac = self.cleaned_data.get("public_mac")
+        self.instance.address_pool = self.cleaned_data.get("address_pool")
+        return super(VRouterTenantForm, self).save(commit=commit)
+
+    class Meta:
+        model = VRouterTenant
+
+class VRouterTenantAdmin(ReadOnlyAwareAdmin):
+    list_display = ('backend_status_icon', 'id', 'subscriber_tenant', 'public_ip' )
+    list_display_links = ('backend_status_icon', 'id')
+    fieldsets = [ (None, {'fields': ['backend_status_text', 'kind', 'provider_service', 'subscriber_tenant', 'subscriber_service',
+                                     'address_pool', 'public_ip', 'public_mac', 'gateway_ip', 'gateway_mac', 'cidr'],
+                          'classes':['suit-tab suit-tab-general']})]
+    readonly_fields = ('backend_status_text', 'service_specific_attribute', 'gateway_ip', 'gateway_mac', 'cidr')
+    form = VRouterTenantForm
+
+    suit_form_tabs = (('general','Details'),)
+
+    def queryset(self, request):
+        return VRouterTenant.get_tenant_objects_by_user(request.user)
+
+admin.site.register(VRouterService, VRouterServiceAdmin)
+admin.site.register(VRouterTenant, VRouterTenantAdmin)
+
diff --git a/xos/services/vrouter/models.py b/xos/services/vrouter/models.py
new file mode 100644
index 0000000..5dba838
--- /dev/null
+++ b/xos/services/vrouter/models.py
@@ -0,0 +1,130 @@
+from django.db import models
+from core.models import Service, PlCoreBase, Slice, Instance, Tenant, TenantWithContainer, Node, Image, User, Flavor, Subscriber, NetworkParameter, NetworkParameterType, Port, AddressPool
+from core.models.plcorebase import StrippedCharField
+import os
+from django.db import models, transaction
+from django.forms.models import model_to_dict
+from django.db.models import Q
+from operator import itemgetter, attrgetter, methodcaller
+from core.models import Tag
+from core.models.service import LeastLoadedNodeScheduler
+import traceback
+from xos.exceptions import *
+from xos.config import Config
+
+class ConfigurationError(Exception):
+    pass
+
+VROUTER_KIND = "vROUTER"
+
+CORD_USE_VTN = getattr(Config(), "networking_use_vtn", False)
+
+class VRouterService(Service):
+    KIND = VROUTER_KIND
+
+    class Meta:
+        app_label = "vrouter"
+        verbose_name = "vRouter Service"
+        proxy = True
+
+    def ip_to_mac(self, ip):
+        (a, b, c, d) = ip.split('.')
+        return "02:42:%02x:%02x:%02x:%02x" % (int(a), int(b), int(c), int(d))
+
+    def get_gateways(self):
+        gateways=[]
+
+        aps = self.addresspools.all()
+        for ap in aps:
+            gateways.append( {"gateway_ip": ap.gateway_ip, "gateway_mac": ap.gateway_mac} )
+
+        return gateways
+
+    def get_address_pool(self, name):
+        ap = AddressPool.objects.filter(name=name, service=self)
+        if not ap:
+            raise Exception("vRouter unable to find addresspool %s" % name)
+        return ap[0]
+
+    def get_tenant(self, **kwargs):
+        address_pool_name = kwargs.pop("address_pool_name")
+
+        ap = self.get_address_pool(address_pool_name)
+
+        ip = ap.get_address()
+        if not ip:
+            raise Exception("AddressPool '%s' has run out of addresses." % ap.name)
+
+        t = VRouterTenant(provider_service=self, **kwargs)
+        t.public_ip = ip
+        t.public_mac = self.ip_to_mac(ip)
+        t.address_pool_id = ap.id
+        t.save()
+
+        return t
+
+#VRouterService.setup_simple_attributes()
+
+class VRouterTenant(Tenant):
+    class Meta:
+        proxy = True
+
+    KIND = VROUTER_KIND
+
+    simple_attributes = ( ("public_ip", None),
+                          ("public_mac", None),
+                          ("address_pool_id", None),
+                          )
+
+    @property
+    def gateway_ip(self):
+        if not self.address_pool:
+            return None
+        return self.address_pool.gateway_ip
+
+    @property
+    def gateway_mac(self):
+        if not self.address_pool:
+            return None
+        return self.address_pool.gateway_mac
+
+    @property
+    def cidr(self):
+        if not self.address_pool:
+            return None
+        return self.address_pool.cidr
+
+    @property
+    def address_pool(self):
+        if getattr(self, "cached_address_pool", None):
+            return self.cached_address_pool
+        if not self.address_pool_id:
+            return None
+        aps=AddressPool.objects.filter(id=self.address_pool_id)
+        if not aps:
+            return None
+        ap=aps[0]
+        self.cached_address_pool = ap
+        return ap
+
+    @address_pool.setter
+    def address_pool(self, value):
+        if value:
+            value = value.id
+        if (value != self.get_attribute("address_pool_id", None)):
+            self.cached_address_pool=None
+        self.set_attribute("address_pool_id", value)
+
+    def cleanup_addresspool(self):
+        if self.address_pool_id:
+            ap = AddressPool.objects.filter(id=self.address_pool_id)
+            if ap:
+                ap[0].put_address(self.public_ip)
+                self.public_ip = None
+
+    def delete(self, *args, **kwargs):
+        self.cleanup_addresspool()
+        super(VRouterTenant, self).delete(*args, **kwargs)
+
+VRouterTenant.setup_simple_attributes()
+
diff --git a/xos/synchronizers/model_policy.py b/xos/synchronizers/model_policy.py
index e2121ec..8faae81 100644
--- a/xos/synchronizers/model_policy.py
+++ b/xos/synchronizers/model_policy.py
@@ -110,7 +110,7 @@
         deleted_objects = []
 
         for m in models:
-            res = m.objects.filter(Q(policed__lt=F('updated')) | Q(policed=None))
+            res = m.objects.filter((Q(policed__lt=F('updated')) | Q(policed=None)) & Q(no_policy=False))
             objects.extend(res)
             res = m.deleted_objects.filter(Q(policed__lt=F('updated')) | Q(policed=None))
             deleted_objects.extend(res)
diff --git a/xos/synchronizers/onos/steps/sync_onosapp.py b/xos/synchronizers/onos/steps/sync_onosapp.py
index 2dfdfbd..77c9e91 100644
--- a/xos/synchronizers/onos/steps/sync_onosapp.py
+++ b/xos/synchronizers/onos/steps/sync_onosapp.py
@@ -1,7 +1,6 @@
 import hashlib
 import os
 import socket
-import socket
 import sys
 import base64
 import time
@@ -14,9 +13,10 @@
 from synchronizers.base.syncstep import SyncStep
 from synchronizers.base.ansible import run_template_ssh
 from synchronizers.base.SyncInstanceUsingAnsible import SyncInstanceUsingAnsible
-from core.models import Service, Slice, ControllerSlice, ControllerUser
+from core.models import Service, Slice, Controller, ControllerSlice, ControllerUser, Node, TenantAttribute, Tag
 from services.onos.models import ONOSService, ONOSApp
 from xos.logger import Logger, logging
+from services.vrouter.models import VRouterService
 
 # hpclibrary will be in steps/..
 parentdir = os.path.join(os.path.dirname(__file__),"..")
@@ -117,6 +117,130 @@
                 raise Exception("Controller user object for %s does not exist" % instance.creator)
             return cuser.kuser_id
 
+
+    def node_tag_default(self, o, node, tagname, default):
+        tags = Tag.select_by_content_object(node).filter(name=tagname)
+        if tags:
+            value = tags[0].value
+        else:
+            value = default
+            logger.info("node %s: saving default value %s for tag %s" % (node.name, value, tagname))
+            service = self.get_onos_service(o)
+            tag = Tag(service=service, content_object=node, name=tagname, value=value)
+            tag.save()
+        return value
+
+    # Scan attrs for attribute name
+    # If it's not present, save it as a TenantAttribute
+    def attribute_default(self, tenant, attrs, name, default):
+        if name in attrs:
+            value = attrs[name]
+        else:
+            value = default
+            logger.info("saving default value %s for attribute %s" % (value, name))
+            ta = TenantAttribute(tenant=tenant, name=name, value=value)
+            ta.save()
+        return value
+
+    # This function currently assumes a single Deployment and Site
+    def get_vtn_config(self, o, attrs):
+
+        # The "attrs" argument contains a list of all service and tenant attributes
+        # If an attribute is present, use it in the configuration
+        # Otherwise save the attriute with a reasonable (for a CORD devel pod) default value
+        # The admin will see all possible configuration values and the assigned defaults
+        privateGatewayMac = self.attribute_default(o, attrs, "privateGatewayMac", "00:00:00:00:00:01")
+        localManagementIp = self.attribute_default(o, attrs, "localManagementIp", "172.27.0.1/24")
+        ovsdbPort = self.attribute_default(o, attrs, "ovsdbPort", "6641")
+        sshPort = self.attribute_default(o, attrs, "sshPort", "22")
+        sshUser = self.attribute_default(o, attrs, "sshUser", "root")
+        sshKeyFile = self.attribute_default(o, attrs, "sshKeyFile", "/root/node_key")
+
+        # OpenStack endpoints and credentials
+        keystone_server = "http://keystone:5000/v2.0/"
+        user_name = "admin"
+        password = "ADMIN_PASS"
+        controllers = Controller.objects.all()
+        if controllers:
+            controller = controllers[0]
+            keystone_server = controller.auth_url
+            user_name = controller.admin_user
+            password = controller.admin_password
+
+        # Put this in the controller object?  Or fetch it from Keystone?
+        # Seems like VTN should be pulling it from Keystone
+        # For now let it be specified by a service / tenant attribute
+        neutron_server = self.attribute_default(o, attrs, "neutron_server", "http://neutron-api:9696/v2.0/")
+
+        data = {
+            "apps" : {
+                "org.onosproject.cordvtn" : {
+                    "cordvtn" : {
+                        "privateGatewayMac" : privateGatewayMac,
+                        "localManagementIp": localManagementIp,
+                        "ovsdbPort": ovsdbPort,
+                        "sshPort": sshPort,
+                        "sshUser": sshUser,
+                        "sshKeyFile": sshKeyFile,
+                        "publicGateways": [],
+                        "nodes" : []
+                    }
+                },
+                "org.onosproject.openstackinterface" : {
+                    "openstackinterface" : {
+                        "do_not_push_flows" : "true",
+                        "neutron_server" : neutron_server,
+                        "keystone_server" : keystone_server,
+                        "user_name" : user_name,
+                        "password" : password
+                    }
+                }
+            }
+        }
+
+        # Generate apps->org.onosproject.cordvtn->cordvtn->nodes
+
+        # We need to generate a CIDR address for the physical node's
+        # address on the management network
+        mgmtSubnetBits = self.attribute_default(o, attrs, "mgmtSubnetBits", "24")
+
+        nodes = Node.objects.all()
+        for node in nodes:
+            nodeip = socket.gethostbyname(node.name)
+
+            try:
+                bridgeId = self.node_tag_default(o, node, "bridgeId", "of:0000000000000001")
+                dataPlaneIntf = self.node_tag_default(o, node, "dataPlaneIntf", "veth1")
+                # This should be generated from the AddressPool if not present
+                dataPlaneIp = self.node_tag_default(o, node, "dataPlaneIp", "192.168.199.1/24")
+            except:
+                logger.error("not adding node %s to the VTN configuration" % node.name)
+                continue
+
+            node_dict = {
+                "hostname": node.name,
+                "hostManagementIp": "%s/%s" % (nodeip, mgmtSubnetBits),
+                "bridgeId": bridgeId,
+                "dataPlaneIntf": dataPlaneIntf,
+                "dataPlaneIp": dataPlaneIp
+            }
+            data["apps"]["org.onosproject.cordvtn"]["cordvtn"]["nodes"].append(node_dict)
+
+        # Generate apps->org.onosproject.cordvtn->cordvtn->publicGateways
+        # Pull the gateway information from vRouter
+        vrouters = VRouterService.get_service_objects().all()
+        if vrouters:
+            for gateway in vrouters[0].get_gateways():
+                gatewayIp = gateway['gateway_ip'].split('/',1)[0]
+                gatewayMac = gateway['gateway_mac']
+                gateway_dict = {
+                    "gatewayIp": gatewayIp,
+                    "gatewayMac": gatewayMac
+                }
+                data["apps"]["org.onosproject.cordvtn"]["cordvtn"]["publicGateways"].append(gateway_dict)
+
+        return json.dumps(data, indent=4, sort_keys=True)
+
     def write_configs(self, o):
         o.config_fns = []
         o.rest_configs = []
@@ -153,6 +277,33 @@
             file(os.path.join(o.files_dir, fn),"w").write(" " +value)
             o.early_rest_configs.append( {"endpoint": endpoint, "fn": fn} )
 
+        # Generate config files and save them to the appropriate tenant attributes
+        autogen = []
+        for key, value in attrs.iteritems():
+            if key == "autogenerate" and value:
+                autogen.append(value)
+        for label in autogen:
+            config = None
+            value = None
+            if label == "vtn-network-cfg":
+            # Generate the VTN config file... where should this live?
+                config = "rest_onos/v1/network/configuration/"
+                value = self.get_vtn_config(o, attrs)
+            if config:
+                tas = TenantAttribute.objects.filter(tenant=o, name=config)
+                if tas:
+                    ta = tas[0]
+                    if ta.value != value:
+                        logger.info("updating %s with autogenerated config" % config)
+                        ta.value = value
+                        ta.save()
+                        attrs[config] = value
+                else:
+                    logger.info("saving autogenerated config %s" % config)
+                    ta = TenantAttribute(tenant=o, name=config, value=value)
+                    ta.save()
+                    attrs[config] = value
+
         for name in attrs.keys():
             value = attrs[name]
             if name.startswith("config_"):
diff --git a/xos/synchronizers/openstack/steps/sync_images.py b/xos/synchronizers/openstack/steps/sync_images.py
index 8049ac1..1638fd0 100644
--- a/xos/synchronizers/openstack/steps/sync_images.py
+++ b/xos/synchronizers/openstack/steps/sync_images.py
@@ -27,7 +27,7 @@
         if os.path.exists(images_path):
             for f in os.listdir(images_path):
                 filename = os.path.join(images_path, f)
-                if os.path.isfile(filename):
+                if os.path.isfile(filename) and filename.endswith(".img"):
                     available_images[f] = filename
 
         logger.info("SyncImages: available_images = %s" % str(available_images))
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
index d52f075..c28b3c1 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant.py
@@ -153,18 +153,8 @@
                         if mac:
                             safe_macs.append(mac)
 
-        wan_vm_ip=""
-        wan_vm_mac=""
-        tags = Tag.select_by_content_object(o.instance).filter(name="vm_wan_addr")
-        if tags:
-            parts=tags[0].value.split(",")
-            if len(parts)!=3:
-                raise Exception("vm_wan_addr tag is malformed: %s" % value)
-            wan_vm_ip = parts[1]
-            wan_vm_mac = parts[2]
-        else:
-            if CORD_USE_VTN:
-                raise Exception("no vm_wan_addr tag for instance %s" % o.instance)
+        wan_vm_ip=o.wan_vm_ip
+        wan_vm_mac=o.wan_vm_mac
 
         fields = {"vlan_ids": vlan_ids,   # XXX remove this
                 "s_tags": s_tags,
diff --git a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
index 04521dc..618e9de 100644
--- a/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
+++ b/xos/synchronizers/vcpe/steps/sync_vcpetenant_vtn.yaml
@@ -294,7 +294,7 @@
     service: name={{ container_name }} state=started
 
   - name: reload ufw
-    shell: docker exec {{ container_name }} bash -c "/sbin/iptables -t nat -F PREROUTING; /usr/sbin/ufw reload"
+    shell: docker exec {{ container_name }} bash -c "/sbin/iptables -t nat -F PREROUTING; /sbin/iptables -t nat -F POSTROUTING; /usr/sbin/ufw reload"
 
   - name: rerun /etc/rc.local
     shell: docker exec {{ container_name }} bash -c "/etc/rc.local"
diff --git a/xos/synchronizers/vtn/steps/sync_port_addresses.py b/xos/synchronizers/vtn/steps/sync_port_addresses.py
index 6b48911..bbc6c99 100644
--- a/xos/synchronizers/vtn/steps/sync_port_addresses.py
+++ b/xos/synchronizers/vtn/steps/sync_port_addresses.py
@@ -70,14 +70,11 @@
 
             # now do the VM_WAN_IP from the instance
             if vsg.instance:
-                tags=Tag.select_by_content_object(vsg.instance).filter(name="vm_wan_addr")
-                if tags:
-                    parts=tags[0].value.split(",")
-                    if len(parts)!=3:
-                        raise Exception("vm_wan_addr tag is malformed: %s" % value)
-                    entry = {"mac_address": parts[2], "ip_address": parts[1]}
-                    if not entry in addr_pairs:
-                        addr_pairs.append(entry)
+                wan_vm_ip = vsg.wan_vm_ip
+                wan_vm_mac = vsg.wan_vm_mac
+                entry = {"mac_address": wan_vm_mac, "ip_address": wan_vm_ip}
+                if not entry in addr_pairs:
+                    addr_pairs.append(entry)
 
         # Get all ports in all controllers
         ports_by_id = {}
diff --git a/xos/tests/api/.gitignore b/xos/tests/api/.gitignore
deleted file mode 100644
index 3c3629e..0000000
--- a/xos/tests/api/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-node_modules
diff --git a/xos/tests/api/apiary.apib b/xos/tests/api/apiary.apib
index 6cbfac9..9e09605 100644
--- a/xos/tests/api/apiary.apib
+++ b/xos/tests/api/apiary.apib
@@ -46,6 +46,23 @@
         
  
  
+# Group Example
+
+## Example Services Collection [/api/service/exampleservice/]
+
+### List all Example Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "MyExample",
+                "id": 1,
+                "service_message": "This is the test message"
+            }
+        ]
+ 
+ 
 # Group ONOS Services
 
 List of the active onos services
@@ -89,24 +106,6 @@
         ]
  
  
-# Group ONOS Apps
-
-## ONOS App Collection [/api/tenant/onos/app/]
-
-### List all apps [GET]
-
-+ Response 200 (application/json)
-
-        [
-            {
-                "humanReadableName": "onos-tenant-7",
-                "id": 7,
-                "name": "vBNG_ONOS_app",
-                "dependencies": "org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd"
-            }
-        ]
- 
- 
 # Group Subscribers
 
 Resource related to the CORD Subscribers.
@@ -503,3 +502,22 @@
                 "compute_node_name": "node2.opencloud.us"
             }
         }
+
+ 
+ 
+# Group ONOS Apps
+
+## ONOS App Collection [/api/tenant/onos/app/]
+
+### List all apps [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "onos-tenant-7",
+                "id": 7,
+                "name": "vBNG_ONOS_app",
+                "dependencies": "org.onosproject.proxyarp, org.onosproject.virtualbng, org.onosproject.openflow, org.onosproject.fwd"
+            }
+        ]
\ No newline at end of file
diff --git a/xos/tests/api/helpers/subscriber.py b/xos/tests/api/helpers/subscriber.py
index 0ff02c2..4ede030 100644
--- a/xos/tests/api/helpers/subscriber.py
+++ b/xos/tests/api/helpers/subscriber.py
@@ -60,6 +60,9 @@
     for s in NetworkSlice.objects.all():
         s.delete(purge=True)
 
+    for s in AddressPool.objects.all():
+        s.delete(purge=True)
+
     print 'DB Cleaned'
 
 
@@ -79,6 +82,22 @@
     subscriber = CordSubscriberRoot(name='Test Subscriber 1', id=1)
     subscriber.save()
 
+    # vRouter service
+    vrouter_service = VRouterService()
+    vrouter_service.name = 'service_vrouter'
+    vrouter_service.save()
+
+    # address pools
+    ap_vsg = AddressPool()
+    ap_vsg.service = vrouter_service
+    ap_vsg.name = 'addresses_vsg'
+    ap_vsg.addresses = '10.168.0.0'
+    ap_vsg.gateway_ip = '10.168.0.1'
+    ap_vsg.gateway_mac = '02:42:0a:a8:00:01'
+    ap_vsg.save()
+
+    print 'vRouter created'
+
     # Site
     site = Site.objects.get(name='MySite')
 
@@ -102,6 +121,7 @@
     volt_service.name = 'service_volt'
     volt_service.save()
 
+
     # vcpe slice
     vcpe_slice = Slice()
     vcpe_slice.name = site.login_base + "_testVcpe"
@@ -110,7 +130,7 @@
     vcpe_slice.caller = user
     vcpe_slice.save()
 
-    print 'vcpe_slice created'
+    # print 'vcpe_slice created'
 
     # create a lan network
     lan_net = Network()
@@ -119,7 +139,7 @@
     lan_net.template = private_template
     lan_net.save()
 
-    print 'lan_network created'
+    # print 'lan_network created'
 
     # add relation between vcpe slice and lan network
     vcpe_network = NetworkSlice()
@@ -127,14 +147,14 @@
     vcpe_network.slice = vcpe_slice
     vcpe_network.save()
 
-    print 'vcpe network relation added'
+    # print 'vcpe network relation added'
 
     # vbng service
     vbng_service = VBNGService()
     vbng_service.name = 'service_vbng'
     vbng_service.save()
 
-    print 'vbng_service creater'
+    # print 'vbng_service creater'
 
     # volt tenant
     vt = VOLTTenant(subscriber=subscriber.id, id=1)
diff --git a/xos/tests/api/hooks.py b/xos/tests/api/hooks.py
index 562798a..ccf0c6c 100644
--- a/xos/tests/api/hooks.py
+++ b/xos/tests/api/hooks.py
@@ -51,6 +51,9 @@
     for s in NetworkSlice.objects.all():
         s.delete(purge=True)
 
+    for s in AddressPool.objects.all():
+        s.delete(purge=True)
+
     # print 'DB Cleaned'
 
 
@@ -70,6 +73,22 @@
     subscriber = CordSubscriberRoot(name='Test Subscriber 1', id=1)
     subscriber.save()
 
+    # vRouter service
+    vrouter_service = VRouterService()
+    vrouter_service.name = 'service_vrouter'
+    vrouter_service.save()
+
+    # address pools
+    ap_vsg = AddressPool()
+    ap_vsg.service = vrouter_service
+    ap_vsg.name = 'addresses_vsg'
+    ap_vsg.addresses = '10.168.0.0'
+    ap_vsg.gateway_ip = '10.168.0.1'
+    ap_vsg.gateway_mac = '02:42:0a:a8:00:01'
+    ap_vsg.save()
+
+    # print 'vRouter created'
+
     # Site
     site = Site.objects.get(name='MySite')
 
@@ -164,6 +183,7 @@
 @hooks.before_each
 def my_before_each_hook(transaction):
     # print "-------------------------------- Before Each Hook --------------------------------"
+    # print transaction['name']
     auth = doLogin('padmin@vicci.org', 'letmein')
     transaction['request']['headers']['X-CSRFToken'] = auth['token']
     transaction['request']['headers']['Cookie'] = "xossessionid=%s; xoscsrftoken=%s" % (auth['sessionid'], auth['token'])
@@ -192,3 +212,8 @@
 def test4(transaction):
     # transaction['skip'] = True
     VOLTTenant.objects.get(kind='vOLT').delete()
+
+
+@hooks.before("Example > Example Services Collection > List all Example Services")
+def exampleTest(transaction):
+    transaction['skip'] = True
diff --git a/xos/tests/api/source/service/exampleservice.md b/xos/tests/api/source/service/exampleservice.md
new file mode 100644
index 0000000..96a19c7
--- /dev/null
+++ b/xos/tests/api/source/service/exampleservice.md
@@ -0,0 +1,15 @@
+# Group Example
+
+## Example Services Collection [/api/service/exampleservice/]
+
+### List all Example Services [GET]
+
++ Response 200 (application/json)
+
+        [
+            {
+                "humanReadableName": "MyExample",
+                "id": 1,
+                "service_message": "This is the test message"
+            }
+        ]
\ No newline at end of file
diff --git a/xos/tools/xos-manage b/xos/tools/xos-manage
index 5410f37..23cda72 100755
--- a/xos/tools/xos-manage
+++ b/xos/tools/xos-manage
@@ -147,6 +147,7 @@
     python ./manage.py makemigrations helloworldservice_complete
     python ./manage.py makemigrations onos
     python ./manage.py makemigrations vtr
+    python ./manage.py makemigrations vrouter
     #python ./manage.py makemigrations servcomp
 }
 
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index d903190..fd4f8ec 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -204,6 +204,9 @@
             rest_onos/v1/network/configuration/:
                 type: string
                 required: false
+            autogenerate:
+                type: string
+                required: false
 
     tosca.nodes.VSGService:
         description: >
@@ -248,6 +251,16 @@
                 required: false
                 description: URL of REST API endpoint for vBNG Service.
 
+    tosca.nodes.VRouterService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vRouter Service.
+        capabilities:
+            xos_base_service_caps
+        properties:
+            xos_base_props
+            xos_base_service_props
+
     tosca.nodes.CDNService:
         derived_from: tosca.nodes.Root
         description: >
@@ -553,12 +566,23 @@
         derived_from: tosca.nodes.Root
         description: >
             A pool of addresses
+        capabilities:
+            addresspool:
+                type: tosca.capabilities.xos.AddressPool
         properties:
             xos_base_props
             addresses:
                 type: string
                 required: false
                 description: space-separated list of addresses
+            gateway_ip:
+                type: string
+                required: false
+                description: gateway ip address
+            gateway_mac:
+                type: string
+                required: false
+                description: gateway mac address
 
     tosca.nodes.Image:
         derived_from: tosca.nodes.Root
@@ -877,6 +901,10 @@
         derived_from: tosca.relationships.Root
         valid_target_types: [ tosca.capabilities.xos.NodeLabel ]
 
+    tosca.relationships.ProvidesAddresses:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.AddressPool ]
+
     tosca.relationships.DependsOn:
         derived_from: tosca.relationships.Root
 
@@ -939,3 +967,7 @@
     tosca.capabilities.xos.NetworkParameterType:
         derived_from: tosca.capabilities.Root
         description: An XOS NetworkParameterType
+
+    tosca.capabilities.xos.AddressPool:
+        derived_from: tosca.capabilities.Root
+        description: An XOS AddressPool
diff --git a/xos/tosca/custom_types/xos.yaml b/xos/tosca/custom_types/xos.yaml
index adc1bf1..9bdcfc3 100644
--- a/xos/tosca/custom_types/xos.yaml
+++ b/xos/tosca/custom_types/xos.yaml
@@ -262,6 +262,9 @@
             rest_onos/v1/network/configuration/:
                 type: string
                 required: false
+            autogenerate:
+                type: string
+                required: false
 
     tosca.nodes.VSGService:
         description: >
@@ -394,6 +397,60 @@
                 required: false
                 description: URL of REST API endpoint for vBNG Service.
 
+    tosca.nodes.VRouterService:
+        derived_from: tosca.nodes.Root
+        description: >
+            CORD: The vRouter Service.
+        capabilities:
+            scalable:
+                type: tosca.capabilities.Scalable
+            service:
+                type: tosca.capabilities.xos.Service
+        properties:
+            no-delete:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to delete this object
+            no-create:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to create this object
+            no-update:
+                type: boolean
+                default: false
+                description: Do not allow Tosca to update this object
+            kind:
+                type: string
+                default: generic
+                description: Type of service.
+            view_url:
+                type: string
+                required: false
+                description: URL to follow when icon is clicked in the Service Directory.
+            icon_url:
+                type: string
+                required: false
+                description: ICON to display in the Service Directory.
+            enabled:
+                type: boolean
+                default: true
+            published:
+                type: boolean
+                default: true
+                description: If True then display this Service in the Service Directory.
+            public_key:
+                type: string
+                required: false
+                description: Public key to install into Instances to allows Services to SSH into them.
+            private_key_fn:
+                type: string
+                required: false
+                description: Location of private key file
+            versionNumber:
+                type: string
+                required: false
+                description: Version number of Service.
+
     tosca.nodes.CDNService:
         derived_from: tosca.nodes.Root
         description: >
@@ -832,6 +889,9 @@
         derived_from: tosca.nodes.Root
         description: >
             A pool of addresses
+        capabilities:
+            addresspool:
+                type: tosca.capabilities.xos.AddressPool
         properties:
             no-delete:
                 type: boolean
@@ -849,6 +909,14 @@
                 type: string
                 required: false
                 description: space-separated list of addresses
+            gateway_ip:
+                type: string
+                required: false
+                description: gateway ip address
+            gateway_mac:
+                type: string
+                required: false
+                description: gateway mac address
 
     tosca.nodes.Image:
         derived_from: tosca.nodes.Root
@@ -1233,6 +1301,10 @@
         derived_from: tosca.relationships.Root
         valid_target_types: [ tosca.capabilities.xos.NodeLabel ]
 
+    tosca.relationships.ProvidesAddresses:
+        derived_from: tosca.relationships.Root
+        valid_target_types: [ tosca.capabilities.xos.AddressPool ]
+
     tosca.relationships.DependsOn:
         derived_from: tosca.relationships.Root
 
@@ -1295,3 +1367,7 @@
     tosca.capabilities.xos.NetworkParameterType:
         derived_from: tosca.capabilities.Root
         description: An XOS NetworkParameterType
+
+    tosca.capabilities.xos.AddressPool:
+        derived_from: tosca.capabilities.Root
+        description: An XOS AddressPool
diff --git a/xos/tosca/resources/addresspool.py b/xos/tosca/resources/addresspool.py
index e8577a2..8cd3e83 100644
--- a/xos/tosca/resources/addresspool.py
+++ b/xos/tosca/resources/addresspool.py
@@ -14,7 +14,7 @@
 class XOSAddressPool(XOSResource):
     provides = "tosca.nodes.AddressPool"
     xos_model = AddressPool
-    copyin_props = ["addresses"]
+    copyin_props = ["addresses", "gateway_ip", "gateway_mac"]
 
     def expand_cidr(self, cidr):
         (network, bits) = cidr.split("/")
@@ -31,20 +31,31 @@
             ip = ip & netmask | i
             dest.append( socket.inet_ntoa(struct.pack("!L", ip)) )
 
-        return dest
+        return (dest, bits)
 
     def get_xos_args(self):
         args = super(XOSAddressPool, self).get_xos_args()
 
         if "addresses" in args:
-            dest = []
-            for addr in args["addresses"].split():
-                addr=addr.strip()
-                if "/" in addr:
-                    dest.extend(self.expand_cidr(addr))
-                else:
-                    dest.append(addr)
-            args["addresses"] = " ".join(dest)
+            addr = args["addresses"]
+            if "," in addr:
+                raise Exception("Only one cidr per AddressPool")
+            if not "/" in addr:
+                raise Exception("AddressPool addresses must be a cidr")
+            (cidr_addrs, cidr_netbits) = self.expand_cidr(addr)
+            args["addresses"] = " ".join(cidr_addrs)
+            args["cidr"] = addr
+
+#        if "addresses" in args:
+#            dest = []
+#            for addr in args["addresses"].split():
+#                addr=addr.strip()
+#                if "/" in addr:
+#                    (cidr_addrs, cidr_netbits) = self.expand_cidr(addr)
+#                    dest.extend(cidr_addrs)
+#                else:
+#                    dest.append(addr)
+#            args["addresses"] = " ".join(dest)
 
         return args
 
diff --git a/xos/tosca/resources/network.py b/xos/tosca/resources/network.py
index 7b513c3..32e3fc1 100644
--- a/xos/tosca/resources/network.py
+++ b/xos/tosca/resources/network.py
@@ -6,7 +6,7 @@
 from translator.toscalib.tosca_template import ToscaTemplate
 import pdb
 
-from core.models import Slice,User,Network,NetworkTemplate,NetworkSlice
+from core.models import Slice,User,Network,NetworkTemplate,NetworkSlice,Service,Tenant
 
 from xosresource import XOSResource
 
@@ -35,7 +35,7 @@
                 if v:
                     args[prop] = v
         else:
-            # tosca.nodes.network.Netwrok is not as rich as an XOS network. So
+            # tosca.nodes.network.Network is not as rich as an XOS network. So
             # we have to manually fill in some defaults.
             args["permit_all_slices"] = True
 
@@ -54,6 +54,24 @@
                 ns = NetworkSlice(network = obj, slice=slice)
                 ns.save()
 
+        # this is really for vRouter
+        for provider_service_name in self.get_requirements("tosca.relationships.TenantOfService"):
+            provider_service = self.get_xos_object(Service, name=provider_service_name)
+
+            existing_tenancy = Tenant.objects.filter(provider_service = provider_service, subscriber_network = obj)
+            if existing_tenancy:
+                self.info("Tenancy relationship from %s to %s already exists" % (str(obj), str(provider_service)))
+            else:
+                from services.vrouter.models import VROUTER_KIND, VRouterService
+                if provider_service.kind == VROUTER_KIND:
+                    tenancy = VRouterService.objects.get(id=provider_service.id).get_tenant(address_pool_name="addresses_"+obj.name, subscriber_network=obj)
+                    tenancy.save()
+                    obj.subnet = tenancy.cidr
+                else:
+                    raise Exception("The only network tenancy relationships that are allowed are to vRouter services")
+
+                self.info("Created Tenancy relationship from %s to %s" % (str(obj), str(provider_service)))
+
 #        v = self.get_property("permitted_slices")
 #        if v:
 #            for slicename in v.split(","):
@@ -72,12 +90,21 @@
         if not xos_args.get("template", None):
             raise Exception("Must specify network template when creating network")
 
+        # XXX TODO: investigate using transaction.atomic instead of setting
+        #   no_sync and no_policy
+
         network = Network(**xos_args)
         network.caller = self.user
+        network.no_sync = True        # postprocess might set the cidr
+        network.no_policy = True
         network.save()
 
         self.postprocess(network)
 
+        network.no_sync = False
+        network.no_policy = False
+        network.save()
+
         self.info("Created Network '%s' owned by Slice '%s'" % (str(network), str(network.owner)))
 
     def delete(self, obj):
diff --git a/xos/tosca/resources/onosapp.py b/xos/tosca/resources/onosapp.py
index 321600d..72511b3 100644
--- a/xos/tosca/resources/onosapp.py
+++ b/xos/tosca/resources/onosapp.py
@@ -61,7 +61,8 @@
                 self.set_tenant_attr(obj, k, v)
             elif k.startswith("component_config"):
                 self.set_tenant_attr(obj, k, v)
+            elif k == "autogenerate":
+                self.set_tenant_attr(obj, k, v)
 
     def can_delete(self, obj):
         return super(XOSONOSApp, self).can_delete(obj)
-
diff --git a/xos/tosca/resources/service.py b/xos/tosca/resources/service.py
index 247be08..5a57418 100644
--- a/xos/tosca/resources/service.py
+++ b/xos/tosca/resources/service.py
@@ -6,7 +6,7 @@
 from translator.toscalib.tosca_template import ToscaTemplate
 import pdb
 
-from core.models import Service,User,CoarseTenant
+from core.models import Service,User,CoarseTenant,AddressPool
 
 from xosresource import XOSResource
 
@@ -29,6 +29,11 @@
 
                 self.info("Created Tenancy relationship  from %s to %s" % (str(obj), str(provider_service)))
 
+        for ap_name in self.get_requirements("tosca.relationships.ProvidesAddresses"):
+            ap = self.get_xos_object(AddressPool, name=ap_name)
+            ap.service = obj
+            ap.save()
+
     def can_delete(self, obj):
         if obj.slices.exists():
             self.info("Service %s has active slices; skipping delete" % obj.name)
diff --git a/xos/tosca/resources/vrouterservice.py b/xos/tosca/resources/vrouterservice.py
new file mode 100644
index 0000000..14dabcc
--- /dev/null
+++ b/xos/tosca/resources/vrouterservice.py
@@ -0,0 +1,16 @@
+import os
+import pdb
+import sys
+import tempfile
+sys.path.append("/opt/tosca")
+from translator.toscalib.tosca_template import ToscaTemplate
+
+from services.vrouter.models import VRouterService
+
+from service import XOSService
+
+class XOSVRouterService(XOSService):
+    provides = "tosca.nodes.VRouterService"
+    xos_model = VRouterService
+    copyin_props = ["view_url", "icon_url", "enabled", "published", "public_key", "versionNumber"]
+
diff --git a/xos/tosca/samples/vtn-service-chain.yaml b/xos/tosca/samples/vtn-service-chain.yaml
new file mode 100644
index 0000000..51933d6
--- /dev/null
+++ b/xos/tosca/samples/vtn-service-chain.yaml
@@ -0,0 +1,157 @@
+tosca_definitions_version: tosca_simple_yaml_1_0
+
+description: Two services "service_one" and "service_two" with a tenancy relationship.
+
+imports:
+   - custom_types/xos.yaml
+
+topology_template:
+  node_templates:
+
+    Private-Indirect:
+      type: tosca.nodes.NetworkTemplate
+      properties:
+          access: indirect
+
+    management:
+      type: tosca.nodes.network.Network.XOS
+      properties:
+          no-create: true
+          no-delete: true
+          no-update: true
+
+    mysite:
+      type: tosca.nodes.Site
+
+    trusty-server-multi-nic:
+      type: tosca.nodes.Image
+
+    service_vsg:
+      type: tosca.nodes.VSGService
+      requirements:
+          - one_tenant:
+              node: service_one
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          no-create: true
+          no-delete: true
+
+    service_one:
+      type: tosca.nodes.Service
+      requirements:
+          - two_tenant:
+              node: service_two
+              relationship: tosca.relationships.TenantOfService
+      properties:
+          kind: one
+
+    service_two:
+      type: tosca.nodes.Service
+      properties:
+          kind: two
+
+    mysite_one:
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - service:
+              node: service_one
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
+    mysite_two:
+      type: tosca.nodes.Slice
+      properties:
+          network: noauto
+      requirements:
+          - service:
+              node: service_two
+              relationship: tosca.relationships.MemberOfService
+          - site:
+              node: mysite
+              relationship: tosca.relationships.MemberOfSite
+          - management:
+              node: management
+              relationship: tosca.relationships.ConnectsToNetwork
+
+    one_access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private-Indirect
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_one
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_one
+              relationship: tosca.relationships.ConnectsToSlice
+
+    two_access:
+      type: tosca.nodes.network.Network
+      properties:
+          ip_version: 4
+      requirements:
+          - network_template:
+              node: Private-Indirect
+              relationship: tosca.relationships.UsesNetworkTemplate
+          - owner:
+              node: mysite_two
+              relationship: tosca.relationships.MemberOfSlice
+          - connection:
+              node: mysite_two
+              relationship: tosca.relationships.ConnectsToSlice
+
+    # Virtual machines
+    one_instance:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_one
+                relationship: tosca.relationships.MemberOfSlice
+
+    # Virtual machines
+    two_instance:
+      type: tosca.nodes.Compute
+      capabilities:
+        # Host container properties
+        host:
+         properties:
+           num_cpus: 1
+           disk_size: 10 GB
+           mem_size: 4 MB
+        # Guest Operating System properties
+        os:
+          properties:
+            # host Operating System image properties
+            architecture: x86_64
+            type: linux
+            distribution: Ubuntu
+            version: 14.10
+      requirements:
+          - slice:
+                node: mysite_two
+                relationship: tosca.relationships.MemberOfSlice
diff --git a/xos/xos/settings.py b/xos/xos/settings.py
index aa50e7d..f457476 100644
--- a/xos/xos/settings.py
+++ b/xos/xos/settings.py
@@ -181,6 +181,7 @@
     'services.requestrouter',
     'services.syndicate_storage',
     'services.vtr',
+    'services.vrouter',
     'geoposition',
     'rest_framework_swagger',
 )