CORD-433 Add virtual fabric to CiaB

Change-Id: I8fbea8c85f309a4c226951e0cde96a9b7394d6eb
diff --git a/Vagrantfile b/Vagrantfile
index 41b96eb..26758d9 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -9,14 +9,6 @@
     config.vm.synced_folder "..", "/cord"
   end
 
-  #By default, this variable is set to 2, such that Vagrantfile allows creation
-  #of compute nodes up to 2. If the number of compute nodes to be supported more
-  #than 2, set the environment variable NUM_COMPUTE_NODES to the desired value
-  #before executing this Vagrantfile.
-  num_compute_nodes = (ENV['NUM_COMPUTE_NODES'] || 2).to_i
-  compute_ip_base = "10.6.1."
-  compute_ips = num_compute_nodes.times.collect { |n| compute_ip_base + "#{n+2}" }
-
   config.vm.define "corddev" do |d|
     d.ssh.forward_agent = true
     d.vm.box = "ubuntu/trusty64"
@@ -48,10 +40,12 @@
         libvirt__forward_mode: "none",
         libvirt__dhcp_enabled: false
     d.vm.network "private_network",
-        ip: "10.6.1.201", # To set up the 10.6.1.1 IP address on bridge
-        virtualbox__intnet: "cord-fabric-network",
-        libvirt__network_name: "cord-fabric-network",
-        libvirt__forward_mode: "nat",
+        ip: "0.1.0.0",
+        mac: "02420a060101",
+        auto_config: false,
+        virtualbox__intnet: "head-node-leaf-1",
+        libvirt__network_name: "head-node-leaf-1",
+        libvirt__forward_mode: "none",
         libvirt__dhcp_enabled: false
     d.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
     d.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/prod.yml -c local"
@@ -84,6 +78,198 @@
     end
   end
 
+  config.vm.define "leaf-1" do |s|
+    s.vm.box = "ubuntu/trusty64"
+    s.vm.hostname = "leaf-1"
+    s.vm.network "private_network",
+      #type: "dhcp",
+      ip: "0.0.0.0",
+      auto_config: false,
+      virtualbox__intnet: "cord-mgmt-network",
+      libvirt__network_name: "cord-mgmt-network",
+      mac: "cc37ab000011"
+    s.vm.network "private_network",
+      ip: "0.1.0.0",
+      auto_config: false,
+      virtualbox__intnet: "head-node-leaf-1",
+      libvirt__network_name: "head-node-leaf-1",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.network "private_network",
+      ip: "0.2.0.0",
+      auto_config: false,
+      virtualbox__intnet: "compute-node-1-leaf-1",
+      libvirt__network_name: "compute-node-1-leaf-1",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.network "private_network",
+      ip: "0.5.0.0",
+      auto_config: false,
+      virtualbox__intnet: "leaf-1-spine-1",
+      libvirt__network_name: "leaf-1-spine-1",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.network "private_network",
+      ip: "0.6.0.0",
+      auto_config: false,
+      virtualbox__intnet: "leaf-1-spine-2",
+      libvirt__network_name: "leaf-1-spine-2",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    if (ENV['FABRIC'] == "1")
+      s.vm.provision :shell, path: "scripts/install.sh", args: "-3f"
+      s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/leafswitch.yml -c local -e 'fabric=true net_prefix=10.6.1'"
+    else
+      s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/leafswitch.yml -c local -e 'net_prefix=10.6.1'"
+    end
+    s.vm.provider :libvirt do |v|
+        v.memory = 512
+        v.cpus = 1
+    end
+    s.vm.provider "virtualbox" do |v, override|
+        v.memory = 512
+        v.cpus = 1
+    end
+  end
+
+  config.vm.define "leaf-2" do |s|
+    s.vm.box = "ubuntu/trusty64"
+    s.vm.hostname = "leaf-2"
+    s.vm.network "private_network",
+      #type: "dhcp",
+      ip: "0.0.0.0",
+      auto_config: false,
+      virtualbox__intnet: "cord-mgmt-network",
+      libvirt__network_name: "cord-mgmt-network",
+      mac: "cc37ab000012"
+    s.vm.network "private_network",
+      ip: "0.3.0.0",
+      auto_config: false,
+      virtualbox__intnet: "compute-node-2-leaf-2",
+      libvirt__network_name: "compute-node-2-leaf-2",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.network "private_network",
+      ip: "0.4.0.0",
+      auto_config: false,
+      virtualbox__intnet: "compute-node-3-leaf-2",
+      libvirt__network_name: "compute-node-3-leaf-2",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.network "private_network",
+      ip: "0.7.0.0",
+      auto_config: false,
+      virtualbox__intnet: "leaf-2-spine-1",
+      libvirt__network_name: "leaf-2-spine-1",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.network "private_network",
+      ip: "0.8.0.0",
+      auto_config: false,
+      virtualbox__intnet: "leaf-2-spine-2",
+      libvirt__network_name: "leaf-2-spine-2",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    if (ENV['FABRIC'] == "1")
+      s.vm.provision :shell, path: "scripts/install.sh", args: "-3f"
+      s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/leafswitch.yml -c local -e 'fabric=true net_prefix=10.6.1'"
+    else
+      s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/leafswitch.yml -c local -e 'net_prefix=10.6.1'"
+    end
+    s.vm.provider :libvirt do |v|
+        v.memory = 512
+        v.cpus = 1
+    end
+    s.vm.provider "virtualbox" do |v, override|
+        v.memory = 512
+        v.cpus = 1
+    end
+  end
+
+  config.vm.define "spine-1" do |s|
+    s.vm.box = "ubuntu/trusty64"
+    s.vm.hostname = "spine-1"
+    s.vm.network "private_network",
+      #type: "dhcp",
+      ip: "0.0.0.0",
+      auto_config: false,
+      virtualbox__intnet: "cord-mgmt-network",
+      libvirt__network_name: "cord-mgmt-network",
+      mac: "cc37ab000021"
+    s.vm.network "private_network",
+      ip: "0.5.0.0",
+      auto_config: false,
+      virtualbox__intnet: "leaf-1-spine-1",
+      libvirt__network_name: "leaf-1-spine-1",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.network "private_network",
+      ip: "0.7.0.0",
+      auto_config: false,
+      virtualbox__intnet: "leaf-2-spine-1",
+      libvirt__network_name: "leaf-2-spine-1",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    if (ENV['FABRIC'] == "1")
+      s.vm.provision :shell, path: "scripts/install.sh", args: "-3f"
+      s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/spineswitch.yml -c local -e 'fabric=true net_prefix=10.6.1'"
+    else
+      s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/spineswitch.yml -c local -e 'net_prefix=10.6.1'"
+    end
+    s.vm.provider :libvirt do |v|
+        v.memory = 512
+        v.cpus = 1
+    end
+    s.vm.provider "virtualbox" do |v, override|
+        v.memory = 512
+        v.cpus = 1
+    end
+  end
+
+  config.vm.define "spine-2" do |s|
+    s.vm.box = "ubuntu/trusty64"
+    s.vm.hostname = "spine-2"
+    s.vm.network "private_network",
+      #type: "dhcp",
+      ip: "0.0.0.0",
+      auto_config: false,
+      virtualbox__intnet: "cord-mgmt-network",
+      libvirt__network_name: "cord-mgmt-network",
+      mac: "cc37ab000022"
+    s.vm.network "private_network",
+      ip: "0.6.0.0",
+      auto_config: false,
+      virtualbox__intnet: "leaf-1-spine-2",
+      libvirt__network_name: "leaf-1-spine-2",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.network "private_network",
+      ip: "0.8.0.0",
+      auto_config: false,
+      virtualbox__intnet: "leaf-2-spine-2",
+      libvirt__network_name: "leaf-2-spine-2",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    s.vm.provision :shell, path: "scripts/bootstrap_ansible.sh"
+    if (ENV['FABRIC'] == "1")
+      s.vm.provision :shell, path: "scripts/install.sh", args: "-3f"
+      s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/spineswitch.yml -c local -e 'fabric=true net_prefix=10.6.1'"
+    else
+      s.vm.provision :shell, inline: "PYTHONUNBUFFERED=1 ansible-playbook /cord/build/ansible/spineswitch.yml -c local -e 'net_prefix=10.6.1'"
+    end
+    s.vm.provider :libvirt do |v|
+        v.memory = 512
+        v.cpus = 1
+    end
+    s.vm.provider "virtualbox" do |v, override|
+        v.memory = 512
+        v.cpus = 1
+    end
+  end
+
   config.vm.define "testbox" do |d|
     d.vm.box = "fgrehm/trusty64-lxc"
     d.ssh.forward_agent = true
@@ -100,41 +286,105 @@
     end
   end
 
-  num_compute_nodes.times do |n|
-    config.vm.define "compute_node-#{n+1}" do |c|
-      compute_ip = compute_ips[n]
-      compute_index = n+1
-      c.vm.synced_folder '.', '/vagrant', disabled: true
-      c.vm.communicator = "none"
-      c.vm.hostname = "computenode-#{compute_index}"
-      c.vm.network "private_network",
-        adapter: 1,
-        ip: "0.0.0.0",
-        auto_config: false,
-        virtualbox__intnet: "cord-mgmt-network",
-        libvirt__network_name: "cord-mgmt-network"
-      c.vm.network "private_network",
-        adapter: 2,
-        ip: "#{compute_ip}",
-        auto_config: false,
-        virtualbox__intnet: "cord-fabric-network",
-        libvirt__network_name: "cord-fabric-network",
-        libvirt__forward_mode: "nat",
-        libvirt__dhcp_enabled: false
-      c.vm.provider :libvirt do |v|
-        v.memory = 8192
-        v.cpus = 4
-        v.machine_virtual_size = 100
-        v.storage :file, :size => '100G', :type => 'qcow2'
-        v.boot 'network'
-        v.boot 'hd'
-        v.nested = true
-      end
-      c.vm.provider "virtualbox" do |v, override|
-        override.vm.box = "clink15/pxe"
-        v.memory = 1048
-        v.gui = "true"
-      end
+  config.vm.define "compute-node-1" do |c|
+    c.vm.synced_folder '.', '/vagrant', disabled: true
+    c.vm.communicator = "none"
+    c.vm.hostname = "compute-node-1"
+    c.vm.network "private_network",
+      adapter: 1,
+      ip: "0.0.0.0",
+      auto_config: false,
+      virtualbox__intnet: "cord-mgmt-network",
+      libvirt__network_name: "cord-mgmt-network"
+    c.vm.network "private_network",
+      adapter: 2,         # The fabric interface for each node
+      ip: "0.2.0.0",
+      auto_config: false,
+      virtualbox__intnet: "compute-node-1-leaf-1",
+      libvirt__network_name: "compute-node-1-leaf-1",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    c.vm.provider :libvirt do |v|
+      v.memory = 8192
+      v.cpus = 4
+      v.machine_virtual_size = 100
+      v.storage :file, :size => '100G', :type => 'qcow2'
+      v.boot 'network'
+      v.boot 'hd'
+      v.nested = true
+    end
+    c.vm.provider "virtualbox" do |v, override|
+      override.vm.box = "clink15/pxe"
+      v.memory = 1048
+      v.gui = "true"
+    end
+  end
+
+  config.vm.define "compute-node-2" do |c|
+    c.vm.synced_folder '.', '/vagrant', disabled: true
+    c.vm.communicator = "none"
+    c.vm.hostname = "compute-node-2"
+    c.vm.network "private_network",
+      adapter: 1,
+      ip: "0.0.0.0",
+      auto_config: false,
+      virtualbox__intnet: "cord-mgmt-network",
+      libvirt__network_name: "cord-mgmt-network"
+    c.vm.network "private_network",
+      adapter: 2,         # The fabric interface for each node
+      ip: "0.3.0.0",
+      auto_config: false,
+      virtualbox__intnet: "compute-node-2-leaf-2",
+      libvirt__network_name: "compute-node-2-leaf-2",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    c.vm.provider :libvirt do |v|
+      v.memory = 8192
+      v.cpus = 4
+      v.machine_virtual_size = 100
+      v.storage :file, :size => '100G', :type => 'qcow2'
+      v.boot 'network'
+      v.boot 'hd'
+      v.nested = true
+    end
+    c.vm.provider "virtualbox" do |v, override|
+      override.vm.box = "clink15/pxe"
+      v.memory = 1048
+      v.gui = "true"
+    end
+  end
+
+  config.vm.define "compute-node-3" do |c|
+    c.vm.synced_folder '.', '/vagrant', disabled: true
+    c.vm.communicator = "none"
+    c.vm.hostname = "compute-node-3"
+    c.vm.network "private_network",
+      adapter: 1,
+      ip: "0.0.0.0",
+      auto_config: false,
+      virtualbox__intnet: "cord-mgmt-network",
+      libvirt__network_name: "cord-mgmt-network"
+    c.vm.network "private_network",
+      adapter: 2,         # The fabric interface for each node
+      ip: "0.4.0.0",
+      auto_config: false,
+      virtualbox__intnet: "compute-node-3-leaf-2",
+      libvirt__network_name: "compute-node-3-leaf-2",
+      libvirt__forward_mode: "none",
+      libvirt__dhcp_enabled: false
+    c.vm.provider :libvirt do |v|
+      v.memory = 8192
+      v.cpus = 4
+      v.machine_virtual_size = 100
+      v.storage :file, :size => '100G', :type => 'qcow2'
+      v.boot 'network'
+      v.boot 'hd'
+      v.nested = true
+    end
+    c.vm.provider "virtualbox" do |v, override|
+      override.vm.box = "clink15/pxe"
+      v.memory = 1048
+      v.gui = "true"
     end
   end
 
diff --git a/ansible/group_vars/all b/ansible/group_vars/all
index 5c59599..24935cc 100644
--- a/ansible/group_vars/all
+++ b/ansible/group_vars/all
@@ -7,3 +7,4 @@
 debian_version: trusty
 docker_cfg: docker.cfg
 docker_cfg_dest: /etc/default/docker
+fabric: false
diff --git a/ansible/leafswitch.yml b/ansible/leafswitch.yml
new file mode 100644
index 0000000..e353fde
--- /dev/null
+++ b/ansible/leafswitch.yml
@@ -0,0 +1,8 @@
+- hosts: localhost
+  remote_user: vagrant
+  serial: 1
+  roles:
+    - common
+    - fakeswitch
+    - fakeswitch-mgmt-net
+    - leafswitch
diff --git a/ansible/roles/fakeswitch-mgmt-net/files/eth1.cfg b/ansible/roles/fakeswitch-mgmt-net/files/eth1.cfg
new file mode 100644
index 0000000..dc7756f
--- /dev/null
+++ b/ansible/roles/fakeswitch-mgmt-net/files/eth1.cfg
@@ -0,0 +1,3 @@
+# The primary network interface
+auto eth1
+iface eth1 inet dhcp
\ No newline at end of file
diff --git a/ansible/roles/fakeswitch-mgmt-net/handlers/main.yml b/ansible/roles/fakeswitch-mgmt-net/handlers/main.yml
new file mode 100644
index 0000000..65e82df
--- /dev/null
+++ b/ansible/roles/fakeswitch-mgmt-net/handlers/main.yml
@@ -0,0 +1,2 @@
+- name: Bring up eth1
+  command: ifup eth1
diff --git a/ansible/roles/fakeswitch-mgmt-net/tasks/main.yml b/ansible/roles/fakeswitch-mgmt-net/tasks/main.yml
new file mode 100644
index 0000000..396312e
--- /dev/null
+++ b/ansible/roles/fakeswitch-mgmt-net/tasks/main.yml
@@ -0,0 +1,6 @@
+- name: Ensure DHCP on eth1
+  copy:
+    src: files/eth1.cfg
+    dest: /etc/network/interfaces.d/eth1.cfg
+  notify:
+    - Bring up eth1
diff --git a/ansible/roles/fakeswitch/tasks/main.yml b/ansible/roles/fakeswitch/tasks/main.yml
index 39879e9..bfeb789 100644
--- a/ansible/roles/fakeswitch/tasks/main.yml
+++ b/ansible/roles/fakeswitch/tasks/main.yml
@@ -18,7 +18,7 @@
 
 - name: Ensure Commands
   become: yes
-  template:
+  copy:
     src: files/{{ item }}
     dest: /usr/bin/{{ item }}
     owner: root
@@ -41,3 +41,11 @@
     name: ssh
     state: restarted
   #failed_when: false
+
+- name: Ensure /mnt/onl/data directory present
+  become: yes
+  file:
+    path: /mnt/onl/data
+    owner: root
+    group: root
+    state: directory
diff --git a/ansible/roles/leafswitch/tasks/bridge.yml b/ansible/roles/leafswitch/tasks/bridge.yml
new file mode 100644
index 0000000..1ee6a60
--- /dev/null
+++ b/ansible/roles/leafswitch/tasks/bridge.yml
@@ -0,0 +1,14 @@
+- name: Ensure brctl
+  apt:
+    name: bridge-utils
+    state: present
+
+- name: Ensure bridge
+  template:
+    src: templates/leafbr.cfg.j2
+    dest: /etc/network/interfaces.d/leafbr.cfg
+
+- name: Ensure bridge is up
+  command: ifup leafbr
+  tags:
+    - skip_ansible_lint # running a sub job
diff --git a/ansible/roles/leafswitch/tasks/fabric.yml b/ansible/roles/leafswitch/tasks/fabric.yml
new file mode 100644
index 0000000..98dc859
--- /dev/null
+++ b/ansible/roles/leafswitch/tasks/fabric.yml
@@ -0,0 +1,10 @@
+- name: Start ofdatapath
+  shell: pgrep ofdatapath || ofdatapath -i eth2,eth3,eth4,eth5 -d {{ ansible_eth1.macaddress | hwaddr('bare') }} --no-slicing -D punix:/var/run/cpqd.sock
+  tags:
+    - skip_ansible_lint # running a sub job
+
+# /etc/resolv.conf not set up correctly in switches, use controller IP addr instead
+- name: Start ofprotocol
+  shell: pgrep ofprotocol || ofprotocol -D --log-file=/var/log/ofprotocol.log unix:/var/run/cpqd.sock tcp:10.1.0.1:6653
+  tags:
+    - skip_ansible_lint # running a sub job
\ No newline at end of file
diff --git a/ansible/roles/leafswitch/tasks/main.yml b/ansible/roles/leafswitch/tasks/main.yml
new file mode 100644
index 0000000..5cc3a15
--- /dev/null
+++ b/ansible/roles/leafswitch/tasks/main.yml
@@ -0,0 +1,28 @@
+- name: Ensure interface config files
+  template:
+    src: templates/ethX.cfg.j2
+    dest: /etc/network/interfaces.d/{{ item }}.cfg
+  with_items:
+  - eth2
+  - eth3
+  - eth4
+  - eth5
+
+- name: Ensure interfaces are up
+  command: ifup {{ item }}
+  with_items:
+  - eth2
+  - eth3
+  - eth4
+  - eth5
+  tags:
+    - skip_ansible_lint # running a sub job
+
+- name: Ensure fabric configuration
+  include: fabric.yml
+  when: fabric
+
+- name: Ensure bridge configuration
+  include: bridge.yml
+  when: not fabric
+
diff --git a/ansible/roles/leafswitch/templates/ethX.cfg.j2 b/ansible/roles/leafswitch/templates/ethX.cfg.j2
new file mode 100644
index 0000000..424746b
--- /dev/null
+++ b/ansible/roles/leafswitch/templates/ethX.cfg.j2
@@ -0,0 +1,3 @@
+auto {{ item }}
+iface {{ item }} inet manual
+up ifconfig {{ item }} up
\ No newline at end of file
diff --git a/ansible/roles/leafswitch/templates/leafbr.cfg.j2 b/ansible/roles/leafswitch/templates/leafbr.cfg.j2
new file mode 100644
index 0000000..26a8caf
--- /dev/null
+++ b/ansible/roles/leafswitch/templates/leafbr.cfg.j2
@@ -0,0 +1,7 @@
+auto leafbr
+iface leafbr inet static
+    address {{ net_prefix }}.254
+    network {{ net_prefix }}.0
+    netmask 255.255.255.0
+    broadcast {{ net_prefix }}.255
+    bridge_ports eth2 eth3 eth4 eth5
diff --git a/ansible/roles/prod/files/fabric.cfg b/ansible/roles/prod/files/fabric.cfg
new file mode 100644
index 0000000..531ae6a
--- /dev/null
+++ b/ansible/roles/prod/files/fabric.cfg
@@ -0,0 +1,18 @@
+auto fabric
+iface fabric inet static
+    address 10.6.1.1
+    network 10.6.1.0
+    netmask 255.255.255.0
+    broadcast 10.6.1.255
+    gateway 10.6.1.1
+    bridge_ports eth3
+
+auto fabric:0
+iface fabric:0 inet static
+    address 10.6.1.129
+    netmask 255.255.255.0
+
+auto fabric:1
+iface fabric:1 inet static
+    address 10.6.1.193
+    netmask 255.255.255.0
diff --git a/ansible/roles/prod/tasks/main.yml b/ansible/roles/prod/tasks/main.yml
index 1cd9f61..fb160cc 100644
--- a/ansible/roles/prod/tasks/main.yml
+++ b/ansible/roles/prod/tasks/main.yml
@@ -16,3 +16,18 @@
   command: ifup mgmtbr
   changed_when: true
 
+- name: Ensure fabric bridge
+  copy:
+    src: fabric.cfg
+    dest: /etc/network/interfaces.d/fabric.cfg
+    owner: root
+    group: root
+    mode: 0644
+
+- name: Ensure fabric bridge
+  command: ifup {{ item }}
+  changed_when: true
+  with_items:
+  - fabric
+  - fabric:0
+  - fabric:1
diff --git a/ansible/roles/spineswitch/tasks/bridge.yml b/ansible/roles/spineswitch/tasks/bridge.yml
new file mode 100644
index 0000000..3e2cbfc
--- /dev/null
+++ b/ansible/roles/spineswitch/tasks/bridge.yml
@@ -0,0 +1,14 @@
+- name: Ensure brctl
+  apt:
+    name: bridge-utils
+    state: present
+
+- name: Ensure bridge
+  template:
+    src: templates/spinebr.cfg.j2
+    dest: /etc/network/interfaces.d/spinebr.cfg
+
+- name: Ensure bridge is up
+  command: ifup spinebr
+  tags:
+    - skip_ansible_lint # running a sub job
diff --git a/ansible/roles/spineswitch/tasks/fabric.yml b/ansible/roles/spineswitch/tasks/fabric.yml
new file mode 100644
index 0000000..02f2737
--- /dev/null
+++ b/ansible/roles/spineswitch/tasks/fabric.yml
@@ -0,0 +1,10 @@
+- name: Start ofdatapath
+  command: pgrep ofdatapath || ofdatapath -i eth2,eth3 -d {{ ansible_eth1.macaddress | hwaddr('bare') }} --no-slicing -D punix:/var/run/cpqd.sock
+  tags:
+    - skip_ansible_lint # running a sub job
+
+# /etc/resolv.conf not set up correctly in switches, use controller IP addr instead
+- name: Start ofprotocol
+  command: pgrep ofprotocol || ofprotocol -D --log-file=/var/log/ofprotocol.log unix:/var/run/cpqd.sock tcp:10.1.0.1:6653
+  tags:
+    - skip_ansible_lint # running a sub job
diff --git a/ansible/roles/spineswitch/tasks/main.yml b/ansible/roles/spineswitch/tasks/main.yml
new file mode 100644
index 0000000..ea25a5a
--- /dev/null
+++ b/ansible/roles/spineswitch/tasks/main.yml
@@ -0,0 +1,24 @@
+- name: Ensure interface config files
+  template:
+    src: templates/ethX.cfg.j2
+    dest: /etc/network/interfaces.d/{{ item }}.cfg
+  with_items:
+  - eth2
+  - eth3
+
+- name: Ensure interfaces are up
+  command: ifup {{ item }}
+  with_items:
+  - eth2
+  - eth3
+  tags:
+    - skip_ansible_lint # running a sub job
+
+- name: Ensure fabric configuration
+  include: fabric.yml
+  when: fabric
+
+- name: Ensure bridge configuration
+  include: bridge.yml
+  when: not fabric
+
diff --git a/ansible/roles/spineswitch/templates/ethX.cfg.j2 b/ansible/roles/spineswitch/templates/ethX.cfg.j2
new file mode 100644
index 0000000..424746b
--- /dev/null
+++ b/ansible/roles/spineswitch/templates/ethX.cfg.j2
@@ -0,0 +1,3 @@
+auto {{ item }}
+iface {{ item }} inet manual
+up ifconfig {{ item }} up
\ No newline at end of file
diff --git a/ansible/roles/spineswitch/templates/spinebr.cfg.j2 b/ansible/roles/spineswitch/templates/spinebr.cfg.j2
new file mode 100644
index 0000000..4f0ebe4
--- /dev/null
+++ b/ansible/roles/spineswitch/templates/spinebr.cfg.j2
@@ -0,0 +1,7 @@
+auto spinebr
+iface spinebr inet static
+    address {{ net_prefix }}.253
+    network {{ net_prefix }}.0
+    netmask 255.255.255.0
+    broadcast {{ net_prefix }}.255
+    bridge_ports eth2 eth3
diff --git a/ansible/spineswitch.yml b/ansible/spineswitch.yml
new file mode 100644
index 0000000..ab7b5e4
--- /dev/null
+++ b/ansible/spineswitch.yml
@@ -0,0 +1,8 @@
+- hosts: localhost
+  remote_user: vagrant
+  serial: 1
+  roles:
+    - common
+    - fakeswitch
+    - fakeswitch-mgmt-net
+    - spineswitch
diff --git a/scripts/cord-in-a-box.sh b/scripts/cord-in-a-box.sh
index 915eed4..bd9c997 100755
--- a/scripts/cord-in-a-box.sh
+++ b/scripts/cord-in-a-box.sh
@@ -11,6 +11,11 @@
 REPO_BRANCH="master"
 VERSION_STRING="CiaB development version"
 
+function add_box() {
+  vagrant box list | grep $1 | grep virtualbox || vagrant box add $1
+  vagrant box list | grep $1 | grep libvirt || vagrant mutate $1 libvirt --input-provider virtualbox
+}
+
 function cleanup_from_previous_test() {
   echo "## Cleanup ##"
 
@@ -60,8 +65,7 @@
   cd $CORDDIR/build
   vagrant plugin list | grep vagrant-libvirt || vagrant plugin install vagrant-libvirt --plugin-version 0.0.35
   vagrant plugin list | grep vagrant-mutate || vagrant plugin install vagrant-mutate
-  vagrant box list ubuntu/trusty64 | grep virtualbox || vagrant box add ubuntu/trusty64
-  vagrant box list ubuntu/trusty64 | grep libvirt || vagrant mutate ubuntu/trusty64 libvirt --input-provider virtualbox
+  add_box ubuntu/trusty64
 }
 
 function cloudlab_setup() {
@@ -126,25 +130,58 @@
   ssh prod "sudo chown -R maas:maas ~maas/.ssh"
 }
 
+function turn_off_learning () {
+  NET=$1
+  BRIDGE=`sudo virsh net-info $NET|grep "Bridge:"|awk '{print $2}'`
+  sudo brctl setageing $BRIDGE 0
+  sudo brctl stp $BRIDGE off
+}
+
+function leaf_spine_up() {
+  cd $CORDDIR/build
+
+  if [[ $FABRIC -ne 0 ]]
+  then
+      sudo su $USER -c "FABRIC=$FABRIC vagrant up leaf-1 leaf-2 spine-1 spine-2 --provider libvirt"
+  else
+      # Linux bridging seems to be having issues with two spine switches
+      sudo su $USER -c "FABRIC=$FABRIC vagrant up leaf-1 leaf-2 spine-1 --provider libvirt"
+  fi
+
+  # Turn off MAC learning on "links" -- i.e., bridges created by libvirt.
+  # Without this, sometimes packets are dropped because the bridges
+  # think they are not local -- this needs further investigation.
+  # A better solution might be to replace the bridges with UDP tunnels, but this
+  # is not supported with the version of libvirt available on Ubuntu 14.04.
+  turn_off_learning head-node-leaf-1
+  turn_off_learning compute-node-1-leaf-1
+  turn_off_learning compute-node-2-leaf-2
+  turn_off_learning compute-node-3-leaf-2
+  turn_off_learning leaf-1-spine-1
+  turn_off_learning leaf-1-spine-2
+  turn_off_learning leaf-2-spine-1
+  turn_off_learning leaf-2-spine-2
+}
+
 function add_compute_node() {
   echo add_compute_node: $1 $2
 
   cd $CORDDIR/build
   sudo su $USER -c "vagrant up $1 --provider libvirt"
 
-  # Change MAC address of bridge to match cord-pod service profile
-  # This change won't survive a reboot
-  BRIDGE=$( route -n | grep 10.6.1.0 | awk '{print $8}' )
-  sudo ifconfig $BRIDGE hw ether 02:42:0a:06:01:01
-
-  ip addr list | grep 10.6.1.129 || sudo ip address add 10.6.1.129 dev $BRIDGE
-  ip addr list | grep 10.6.1.193 || sudo ip address add 10.6.1.193 dev $BRIDGE
-
   # Set up power cycling for the compute node and wait for it to be provisioned
   ssh prod "cd /cord/build/ansible; ansible-playbook maas-provision.yml --extra-vars \"maas_user=maas vagrant_name=$2\""
 
   echo ""
-  echo "compute_node is fully provisioned!"
+  echo "$1 is fully provisioned!"
+}
+
+function initialize_fabric() {
+  echo "Initializing fabric"
+  ssh prod "cd /cord/build/platform-install; ansible-playbook -i /etc/maas/ansible/pod-inventory cord-refresh-fabric.yml"
+
+  echo "Fabric ping test"
+  ssh prod "cd /cord/build/platform-install; ansible-playbook -i /etc/maas/ansible/pod-inventory cord-fabric-pingtest.yml"
 }
 
 function run_e2e_test () {
@@ -168,11 +205,12 @@
 SETUP_ONLY=0
 DIAGNOSTICS=0
 CLEANUP=0
+FABRIC=0
 #By default, cord-in-a-box creates 1 compute node. If more than one compute is
 #needed, use -n option
 NUM_COMPUTE_NODES=1
 
-while getopts "b:cdhn:stv" opt; do
+while getopts "b:cdfhn:stv" opt; do
   case ${opt} in
     b ) GERRIT_BRANCHES+=("$OPTARG")
       ;;
@@ -180,12 +218,15 @@
       ;;
     d ) DIAGNOSTICS=1
       ;;
+    f ) FABRIC=1
+      ;;
     h ) echo "Usage:"
       echo "    $0                install OpenStack and prep XOS and ONOS VMs [default]"
       echo "    $0 -b <project:changeset/revision>  checkout a changesets from gerrit. Can"
       echo "                      be used multiple times."
       echo "    $0 -c             cleanup from previous test"
       echo "    $0 -d             run diagnostic collector"
+      echo "    $0 -f             use ONOS fabric (EXPERIMENTAL)"
       echo "    $0 -h             display this help message"
       echo "    $0 -n #           number of compute nodes to setup. Currently max 2 nodes can be supported"
       echo "    $0 -s             run initial setup phase only (don't start building CORD)"
@@ -230,22 +271,25 @@
 
 install_head_node
 set_up_maas_user
+leaf_spine_up
 
-#Limiting the maximum number of compute nodes that can be supported to 2. If
-#more than 2 compute nodes are needed, this script need to be enhanced to set
-#the environment variable NUM_COMPUTE_NODES before invoking the Vagrant commands
-if [[ $NUM_COMPUTE_NODES -gt 2 ]]
+if [[ $NUM_COMPUTE_NODES -gt 3 ]]
 then
-   echo "currently max only two compute nodes can be supported..."
-   NUM_COMPUTE_NODES=2
+   echo "currently max only three compute nodes can be supported..."
+   NUM_COMPUTE_NODES=3
 fi
 
 for i in `seq 1 $NUM_COMPUTE_NODES`;
 do
    echo adding the compute node: compute-node-$i
-   add_compute_node compute_node-$i build_compute_node-$i
+   add_compute_node compute-node-$i build_compute-node-$i
 done
 
+if [[ $FABRIC -ne 0 ]]
+then
+  initialize_fabric
+fi
+
 if [[ $RUN_TEST -eq 1 ]]
 then
   run_e2e_test
diff --git a/scripts/install.sh b/scripts/install.sh
new file mode 100755
index 0000000..9f29807
--- /dev/null
+++ b/scripts/install.sh
@@ -0,0 +1,800 @@
+#!/usr/bin/env bash
+
+# Mininet install script for Ubuntu (and Debian Wheezy+)
+# Brandon Heller (brandonh@stanford.edu)
+
+# Fail on error
+set -e
+
+# Fail on unset var usage
+set -o nounset
+
+# Get directory containing mininet folder
+MININET_DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )/../.." && pwd -P )"
+
+# Set up build directory, which by default is the working directory
+#  unless the working directory is a subdirectory of mininet, 
+#  in which case we use the directory containing mininet
+BUILD_DIR="$(pwd -P)"
+case $BUILD_DIR in
+  $MININET_DIR/*) BUILD_DIR=$MININET_DIR;; # currect directory is a subdirectory
+  *) BUILD_DIR=$BUILD_DIR;;
+esac
+
+# Location of CONFIG_NET_NS-enabled kernel(s)
+KERNEL_LOC=http://www.openflow.org/downloads/mininet
+
+# Attempt to identify Linux release
+
+DIST=Unknown
+RELEASE=Unknown
+CODENAME=Unknown
+ARCH=`uname -m`
+if [ "$ARCH" = "x86_64" ]; then ARCH="amd64"; fi
+if [ "$ARCH" = "i686" ]; then ARCH="i386"; fi
+
+test -e /etc/debian_version && DIST="Debian"
+grep Ubuntu /etc/lsb-release &> /dev/null && DIST="Ubuntu"
+if [ "$DIST" = "Ubuntu" ] || [ "$DIST" = "Debian" ]; then
+    install='sudo apt-get -y install'
+    remove='sudo apt-get -y remove'
+    pkginst='sudo dpkg -i'
+    # Prereqs for this script
+    if ! which lsb_release &> /dev/null; then
+        $install lsb-release
+    fi
+fi
+test -e /etc/fedora-release && DIST="Fedora"
+if [ "$DIST" = "Fedora" ]; then
+    install='sudo yum -y install'
+    remove='sudo yum -y erase'
+    pkginst='sudo rpm -ivh'
+    # Prereqs for this script
+    if ! which lsb_release &> /dev/null; then
+        $install redhat-lsb-core
+    fi
+fi
+if which lsb_release &> /dev/null; then
+    DIST=`lsb_release -is`
+    RELEASE=`lsb_release -rs`
+    CODENAME=`lsb_release -cs`
+fi
+echo "Detected Linux distribution: $DIST $RELEASE $CODENAME $ARCH"
+
+# Kernel params
+
+KERNEL_NAME=`uname -r`
+KERNEL_HEADERS=kernel-headers-${KERNEL_NAME}
+
+if ! echo $DIST | egrep 'Ubuntu|Debian|Fedora'; then
+    echo "Install.sh currently only supports Ubuntu, Debian and Fedora."
+    exit 1
+fi
+
+# More distribution info
+DIST_LC=`echo $DIST | tr [A-Z] [a-z]` # as lower case
+
+
+# Determine whether version $1 >= version $2
+# usage: if version_ge 1.20 1.2.3; then echo "true!"; fi
+function version_ge {
+    # sort -V sorts by *version number*
+    latest=`printf "$1\n$2" | sort -V | tail -1`
+    # If $1 is latest version, then $1 >= $2
+    [ "$1" == "$latest" ]
+}
+
+
+# Kernel Deb pkg to be removed:
+KERNEL_IMAGE_OLD=linux-image-2.6.26-33-generic
+
+DRIVERS_DIR=/lib/modules/${KERNEL_NAME}/kernel/drivers/net
+
+OVS_RELEASE=1.4.0
+OVS_PACKAGE_LOC=https://github.com/downloads/mininet/mininet
+OVS_BUILDSUFFIX=-ignore # was -2
+OVS_PACKAGE_NAME=ovs-$OVS_RELEASE-core-$DIST_LC-$RELEASE-$ARCH$OVS_BUILDSUFFIX.tar
+OVS_TAG=v$OVS_RELEASE
+
+OF13_SWITCH_REV=${OF13_SWITCH_REV:-""}
+
+
+function kernel {
+    echo "Install Mininet-compatible kernel if necessary"
+    sudo apt-get update
+    if ! $install linux-image-$KERNEL_NAME; then
+        echo "Could not install linux-image-$KERNEL_NAME"
+        echo "Skipping - assuming installed kernel is OK."
+    fi
+}
+
+function kernel_clean {
+    echo "Cleaning kernel..."
+
+    # To save disk space, remove previous kernel
+    if ! $remove $KERNEL_IMAGE_OLD; then
+        echo $KERNEL_IMAGE_OLD not installed.
+    fi
+
+    # Also remove downloaded packages:
+    rm -f $HOME/linux-headers-* $HOME/linux-image-*
+}
+
+# Install Mininet deps
+function mn_deps {
+    echo "Installing Mininet dependencies"
+    if [ "$DIST" = "Fedora" ]; then
+        $install gcc make socat psmisc xterm openssh-clients iperf \
+            iproute telnet python-setuptools libcgroup-tools \
+            ethtool help2man pyflakes pylint python-pep8
+    else
+        $install gcc make socat psmisc xterm ssh iperf iproute telnet \
+            python-setuptools cgroup-bin ethtool help2man \
+            pyflakes pylint pep8
+    fi
+
+    echo "Installing Mininet core"
+    pushd $MININET_DIR/mininet
+    sudo make install
+    popd
+}
+
+# Install Mininet developer dependencies
+function mn_dev {
+    echo "Installing Mininet developer dependencies"
+    $install doxygen doxypy texlive-fonts-recommended
+    if ! $install doxygen-latex; then
+        echo "doxygen-latex not needed"
+    fi
+}
+
+# The following will cause a full OF install, covering:
+# -user switch
+# The instructions below are an abbreviated version from
+# http://www.openflowswitch.org/wk/index.php/Debian_Install
+function of {
+    echo "Installing OpenFlow reference implementation..."
+    cd $BUILD_DIR
+    $install autoconf automake libtool make gcc
+    if [ "$DIST" = "Fedora" ]; then
+        $install git pkgconfig glibc-devel
+    else
+        $install git-core autotools-dev pkg-config libc6-dev
+    fi
+    git clone git://openflowswitch.org/openflow.git
+    cd $BUILD_DIR/openflow
+
+    # Patch controller to handle more than 16 switches
+    patch -p1 < $MININET_DIR/mininet/util/openflow-patches/controller.patch
+
+    # Resume the install:
+    ./boot.sh
+    ./configure
+    make
+    sudo make install
+    cd $BUILD_DIR
+}
+
+function of13 {
+    echo "Installing OpenFlow 1.3 soft switch implementation..."
+    cd $BUILD_DIR/
+    $install  git-core autoconf automake autotools-dev pkg-config \
+        make gcc g++ libtool libc6-dev cmake libpcap-dev libxerces-c2-dev  \
+        unzip libpcre3-dev flex bison libboost-dev
+
+    if [ ! -d "ofsoftswitch13" ]; then
+        git clone https://github.com/CPqD/ofsoftswitch13.git
+        if [[ -n "$OF13_SWITCH_REV" ]]; then
+            cd ofsoftswitch13
+            git checkout ${OF13_SWITCH_REV}
+            cd ..
+        fi
+    fi
+
+    # Install netbee
+    if [ "$DIST" = "Ubuntu" ] && version_ge $RELEASE 14.04; then
+        NBEESRC="nbeesrc-feb-24-2015"
+        NBEEDIR="netbee"
+    else
+        NBEESRC="nbeesrc-jan-10-2013"
+        NBEEDIR="nbeesrc-jan-10-2013"
+    fi
+
+    NBEEURL=${NBEEURL:-http://www.nbee.org/download/}
+    wget -nc ${NBEEURL}${NBEESRC}.zip
+    unzip ${NBEESRC}.zip
+    cd ${NBEEDIR}/src
+    cmake .
+    make
+    cd $BUILD_DIR/
+    sudo cp ${NBEEDIR}/bin/libn*.so /usr/local/lib
+    sudo ldconfig
+    sudo cp -R ${NBEEDIR}/include/ /usr/
+
+    # Resume the install:
+    cd $BUILD_DIR/ofsoftswitch13
+    ./boot.sh
+    ./configure
+    make
+    sudo make install
+    cd $BUILD_DIR
+}
+
+
+function install_wireshark {
+    if ! which wireshark; then
+        echo "Installing Wireshark"
+        if [ "$DIST" = "Fedora" ]; then
+            $install wireshark wireshark-gnome
+        else
+            $install wireshark tshark
+        fi
+    fi
+
+    # Copy coloring rules: OF is white-on-blue:
+    echo "Optionally installing wireshark color filters"
+    mkdir -p $HOME/.wireshark
+    cp -n $MININET_DIR/mininet/util/colorfilters $HOME/.wireshark
+
+    echo "Checking Wireshark version"
+    WSVER=`wireshark -v | egrep -o '[0-9\.]+' | head -1`
+    if version_ge $WSVER 1.12; then
+        echo "Wireshark version $WSVER >= 1.12 - returning"
+        return
+    fi
+
+    echo "Cloning LoxiGen and building openflow.lua dissector"
+    cd $BUILD_DIR
+    git clone https://github.com/floodlight/loxigen.git
+    cd loxigen
+    make wireshark
+
+    # Copy into plugin directory
+    # libwireshark0/ on 11.04; libwireshark1/ on later
+    WSDIR=`find /usr/lib -type d -name 'libwireshark*' | head -1`
+    WSPLUGDIR=$WSDIR/plugins/
+    PLUGIN=loxi_output/wireshark/openflow.lua
+    sudo cp $PLUGIN $WSPLUGDIR
+    echo "Copied openflow plugin $PLUGIN to $WSPLUGDIR"
+
+    cd $BUILD_DIR
+}
+
+
+# Install Open vSwitch specific version Ubuntu package
+function ubuntuOvs {
+    echo "Creating and Installing Open vSwitch packages..."
+
+    OVS_SRC=$BUILD_DIR/openvswitch
+    OVS_TARBALL_LOC=http://openvswitch.org/releases
+
+    if ! echo "$DIST" | egrep "Ubuntu|Debian" > /dev/null; then
+        echo "OS must be Ubuntu or Debian"
+        $cd BUILD_DIR
+        return
+    fi
+    if [ "$DIST" = "Ubuntu" ] && ! version_ge $RELEASE 12.04; then
+        echo "Ubuntu version must be >= 12.04"
+        cd $BUILD_DIR
+        return
+    fi
+    if [ "$DIST" = "Debian" ] && ! version_ge $RELEASE 7.0; then
+        echo "Debian version must be >= 7.0"
+        cd $BUILD_DIR
+        return
+    fi
+
+    rm -rf $OVS_SRC
+    mkdir -p $OVS_SRC
+    cd $OVS_SRC
+
+    if wget $OVS_TARBALL_LOC/openvswitch-$OVS_RELEASE.tar.gz 2> /dev/null; then
+        tar xzf openvswitch-$OVS_RELEASE.tar.gz
+    else
+        echo "Failed to find OVS at $OVS_TARBALL_LOC/openvswitch-$OVS_RELEASE.tar.gz"
+        cd $BUILD_DIR
+        return
+    fi
+
+    # Remove any old packages
+    $remove openvswitch-common openvswitch-datapath-dkms openvswitch-controller \
+            openvswitch-pki openvswitch-switch
+
+    # Get build deps
+    $install build-essential fakeroot debhelper autoconf automake libssl-dev \
+             pkg-config bzip2 openssl python-all procps python-qt4 \
+             python-zopeinterface python-twisted-conch dkms
+
+    # Build OVS
+    cd $BUILD_DIR/openvswitch/openvswitch-$OVS_RELEASE
+            DEB_BUILD_OPTIONS='parallel=2 nocheck' fakeroot debian/rules binary
+    cd ..
+    $pkginst openvswitch-common_$OVS_RELEASE*.deb openvswitch-datapath-dkms_$OVS_RELEASE*.deb \
+             openvswitch-pki_$OVS_RELEASE*.deb openvswitch-switch_$OVS_RELEASE*.deb
+    if $pkginst openvswitch-controller_$OVS_RELEASE*.deb; then
+        echo "Ignoring error installing openvswitch-controller"
+    fi
+
+    modinfo openvswitch
+    sudo ovs-vsctl show
+    # Switch can run on its own, but
+    # Mininet should control the controller
+    # This appears to only be an issue on Ubuntu/Debian
+    if sudo service openvswitch-controller stop; then
+        echo "Stopped running controller"
+    fi
+    if [ -e /etc/init.d/openvswitch-controller ]; then
+        sudo update-rc.d openvswitch-controller disable
+    fi
+}
+
+
+# Install Open vSwitch
+
+function ovs {
+    echo "Installing Open vSwitch..."
+
+    if [ "$DIST" == "Fedora" ]; then
+        $install openvswitch openvswitch-controller
+        return
+    fi
+
+    if [ "$DIST" = "Ubuntu" ] && ! version_ge $RELEASE 14.04; then
+        # Older Ubuntu versions need openvswitch-datapath/-dkms
+        # Manually installing openvswitch-datapath may be necessary
+        # for manually built kernel .debs using Debian's defective kernel
+        # packaging, which doesn't yield usable headers.
+        if ! dpkg --get-selections | grep openvswitch-datapath; then
+            # If you've already installed a datapath, assume you
+            # know what you're doing and don't need dkms datapath.
+            # Otherwise, install it.
+            $install openvswitch-datapath-dkms
+        fi
+    fi
+
+    $install openvswitch-switch
+    if $install openvswitch-controller; then
+        # Switch can run on its own, but
+        # Mininet should control the controller
+        # This appears to only be an issue on Ubuntu/Debian
+        if sudo service openvswitch-controller stop; then
+            echo "Stopped running controller"
+        fi
+        if [ -e /etc/init.d/openvswitch-controller ]; then
+            sudo update-rc.d openvswitch-controller disable
+        fi
+    else
+        echo "Attempting to install openvswitch-testcontroller"
+        if ! $install openvswitch-testcontroller; then
+            echo "Failed - skipping openvswitch-testcontroller"
+        fi
+    fi
+
+}
+
+function remove_ovs {
+    pkgs=`dpkg --get-selections | grep openvswitch | awk '{ print $1;}'`
+    echo "Removing existing Open vSwitch packages:"
+    echo $pkgs
+    if ! $remove $pkgs; then
+        echo "Not all packages removed correctly"
+    fi
+    # For some reason this doesn't happen
+    if scripts=`ls /etc/init.d/*openvswitch* 2>/dev/null`; then
+        echo $scripts
+        for s in $scripts; do
+            s=$(basename $s)
+            echo SCRIPT $s
+            sudo service $s stop
+            sudo rm -f /etc/init.d/$s
+            sudo update-rc.d -f $s remove
+        done
+    fi
+    echo "Done removing OVS"
+}
+
+function ivs {
+    echo "Installing Indigo Virtual Switch..."
+
+    IVS_SRC=$BUILD_DIR/ivs
+
+    # Install dependencies
+    $install git pkg-config gcc make libnl-3-dev libnl-route-3-dev libnl-genl-3-dev
+
+    # Install IVS from source
+    cd $BUILD_DIR
+    git clone git://github.com/floodlight/ivs $IVS_SRC --recursive
+    cd $IVS_SRC
+    make
+    sudo make install
+}
+
+# Install RYU
+function ryu {
+    echo "Installing RYU..."
+
+    # install Ryu dependencies"
+    $install autoconf automake g++ libtool python make
+    if [ "$DIST" = "Ubuntu" ]; then
+        $install libxml2 libxslt-dev python-pip python-dev
+        sudo pip install gevent
+    elif [ "$DIST" = "Debian" ]; then
+        $install libxml2 libxslt-dev python-pip python-dev
+        sudo pip install gevent
+    fi
+
+    # if needed, update python-six
+    SIX_VER=`pip show six | grep Version | awk '{print $2}'`
+    if version_ge 1.7.0 $SIX_VER; then
+        echo "Installing python-six version 1.7.0..."
+        sudo pip install -I six==1.7.0
+    fi
+    # fetch RYU
+    cd $BUILD_DIR/
+    git clone git://github.com/osrg/ryu.git ryu
+    cd ryu
+
+    # install ryu
+    sudo python ./setup.py install
+
+    # Add symbolic link to /usr/bin
+    sudo ln -s ./bin/ryu-manager /usr/local/bin/ryu-manager
+}
+
+# Install NOX with tutorial files
+function nox {
+    echo "Installing NOX w/tutorial files..."
+
+    # Install NOX deps:
+    $install autoconf automake g++ libtool python python-twisted \
+		swig libssl-dev make
+    if [ "$DIST" = "Debian" ]; then
+        $install libboost1.35-dev
+    elif [ "$DIST" = "Ubuntu" ]; then
+        $install python-dev libboost-dev
+        $install libboost-filesystem-dev
+        $install libboost-test-dev
+    fi
+    # Install NOX optional deps:
+    $install libsqlite3-dev python-simplejson
+
+    # Fetch NOX destiny
+    cd $BUILD_DIR/
+    git clone https://github.com/noxrepo/nox-classic.git noxcore
+    cd noxcore
+    if ! git checkout -b destiny remotes/origin/destiny ; then
+        echo "Did not check out a new destiny branch - assuming current branch is destiny"
+    fi
+
+    # Apply patches
+    git checkout -b tutorial-destiny
+    git am $MININET_DIR/mininet/util/nox-patches/*tutorial-port-nox-destiny*.patch
+    if [ "$DIST" = "Ubuntu" ] && version_ge $RELEASE 12.04; then
+        git am $MININET_DIR/mininet/util/nox-patches/*nox-ubuntu12-hacks.patch
+    fi
+
+    # Build
+    ./boot.sh
+    mkdir build
+    cd build
+    ../configure
+    make -j3
+    #make check
+
+    # Add NOX_CORE_DIR env var:
+    sed -i -e 's|# for examples$|&\nexport NOX_CORE_DIR=$BUILD_DIR/noxcore/build/src|' ~/.bashrc
+
+    # To verify this install:
+    #cd ~/noxcore/build/src
+    #./nox_core -v -i ptcp:
+}
+
+# Install NOX Classic/Zaku for OpenFlow 1.3
+function nox13 {
+    echo "Installing NOX w/tutorial files..."
+
+    # Install NOX deps:
+    $install autoconf automake g++ libtool python python-twisted \
+        swig libssl-dev make
+    if [ "$DIST" = "Debian" ]; then
+        $install libboost1.35-dev
+    elif [ "$DIST" = "Ubuntu" ]; then
+        $install python-dev libboost-dev
+        $install libboost-filesystem-dev
+        $install libboost-test-dev
+    fi
+
+    # Fetch NOX destiny
+    cd $BUILD_DIR/
+    git clone https://github.com/CPqD/nox13oflib.git
+    cd nox13oflib
+
+    # Build
+    ./boot.sh
+    mkdir build
+    cd build
+    ../configure
+    make -j3
+    #make check
+
+    # To verify this install:
+    #cd ~/nox13oflib/build/src
+    #./nox_core -v -i ptcp:
+}
+
+
+# "Install" POX
+function pox {
+    echo "Installing POX into $BUILD_DIR/pox..."
+    cd $BUILD_DIR
+    git clone https://github.com/noxrepo/pox.git
+}
+
+# Install OFtest
+function oftest {
+    echo "Installing oftest..."
+
+    # Install deps:
+    $install tcpdump python-scapy
+
+    # Install oftest:
+    cd $BUILD_DIR/
+    git clone git://github.com/floodlight/oftest
+}
+
+# Install cbench
+function cbench {
+    echo "Installing cbench..."
+
+    if [ "$DIST" = "Fedora" ]; then
+        $install net-snmp-devel libpcap-devel libconfig-devel
+    else
+        $install libsnmp-dev libpcap-dev libconfig-dev
+    fi
+    cd $BUILD_DIR/
+    git clone git://gitosis.stanford.edu/oflops.git
+    cd oflops
+    sh boot.sh || true # possible error in autoreconf, so run twice
+    sh boot.sh
+    ./configure --with-openflow-src-dir=$BUILD_DIR/openflow
+    make
+    sudo make install || true # make install fails; force past this
+}
+
+function vm_other {
+    echo "Doing other Mininet VM setup tasks..."
+
+    # Remove avahi-daemon, which may cause unwanted discovery packets to be
+    # sent during tests, near link status changes:
+    echo "Removing avahi-daemon"
+    $remove avahi-daemon
+
+    # was: Disable IPv6.  Add to /etc/modprobe.d/blacklist:
+    #echo "Attempting to disable IPv6"
+    #if [ "$DIST" = "Ubuntu" ]; then
+    #    BLACKLIST=/etc/modprobe.d/blacklist.conf
+    #else
+    #    BLACKLIST=/etc/modprobe.d/blacklist
+    #fi
+    #sudo sh -c "echo 'blacklist net-pf-10\nblacklist ipv6' >> $BLACKLIST"
+    echo "Disabling IPv6"
+    # Disable IPv6
+    if ! grep 'disable_ipv6' /etc/sysctl.conf; then
+        echo 'Disabling IPv6'
+        echo '
+# Mininet: disable IPv6
+net.ipv6.conf.all.disable_ipv6 = 1
+net.ipv6.conf.default.disable_ipv6 = 1
+net.ipv6.conf.lo.disable_ipv6 = 1' | sudo tee -a /etc/sysctl.conf > /dev/null
+    fi
+    # Since the above doesn't disable neighbor discovery, also do this:
+    if ! grep 'ipv6.disable' /etc/default/grub; then
+        sudo sed -i -e \
+        's/GRUB_CMDLINE_LINUX_DEFAULT="/GRUB_CMDLINE_LINUX_DEFAULT="ipv6.disable=1 /' \
+        /etc/default/grub
+        sudo update-grub
+    fi
+    # Disabling IPv6 breaks X11 forwarding via ssh
+    line='AddressFamily inet'
+    file='/etc/ssh/sshd_config'
+    echo "Adding $line to $file"
+    if ! grep "$line" $file > /dev/null; then
+        echo "$line" | sudo tee -a $file > /dev/null
+    fi
+
+    # Enable command auto completion using sudo; modify ~/.bashrc:
+    sed -i -e 's|# for examples$|&\ncomplete -cf sudo|' ~/.bashrc
+
+    # Install tcpdump, cmd-line packet dump tool.  Also install gitk,
+    # a graphical git history viewer.
+    $install tcpdump gitk
+
+    # Install common text editors
+    $install vim nano emacs
+
+    # Install NTP
+    $install ntp
+
+    # Install vconfig for VLAN example
+    if [ "$DIST" = "Fedora" ]; then
+        $install vconfig
+    else
+        $install vlan
+    fi
+
+    # Set git to colorize everything.
+    git config --global color.diff auto
+    git config --global color.status auto
+    git config --global color.branch auto
+
+    # Reduce boot screen opt-out delay. Modify timeout in /boot/grub/menu.lst to 1:
+    if [ "$DIST" = "Debian" ]; then
+        sudo sed -i -e 's/^timeout.*$/timeout         1/' /boot/grub/menu.lst
+    fi
+
+    # Clean unneeded debs:
+    rm -f ~/linux-headers-* ~/linux-image-*
+}
+
+# Script to copy built OVS kernel module to where modprobe will
+# find them automatically.  Removes the need to keep an environment variable
+# for insmod usage, and works nicely with multiple kernel versions.
+#
+# The downside is that after each recompilation of OVS you'll need to
+# re-run this script.  If you're using only one kernel version, then it may be
+# a good idea to use a symbolic link in place of the copy below.
+function modprobe {
+    echo "Setting up modprobe for OVS kmod..."
+    set +o nounset
+    if [ -z "$OVS_KMODS" ]; then
+      echo "OVS_KMODS not set. Aborting."
+    else
+      sudo cp $OVS_KMODS $DRIVERS_DIR
+      sudo depmod -a ${KERNEL_NAME}
+    fi
+    set -o nounset
+}
+
+function all {
+    if [ "$DIST" = "Fedora" ]; then
+        printf "\nFedora 18+ support (still work in progress):\n"
+        printf " * Fedora 18+ has kernel 3.10 RPMS in the updates repositories\n"
+        printf " * Fedora 18+ has openvswitch 1.10 RPMS in the updates repositories\n"
+        printf " * the install.sh script options [-bfnpvw] should work.\n"
+        printf " * for a basic setup just try:\n"
+        printf "       install.sh -fnpv\n\n"
+        exit 3
+    fi
+    echo "Installing all packages except for -eix (doxypy, ivs, nox-classic)..."
+    kernel
+    mn_deps
+    # Skip mn_dev (doxypy/texlive/fonts/etc.) because it's huge
+    # mn_dev
+    of
+    install_wireshark
+    ovs
+    # We may add ivs once it's more mature
+    # ivs
+    # NOX-classic is deprecated, but you can install it manually if desired.
+    # nox
+    pox
+    oftest
+    cbench
+    echo "Enjoy Mininet!"
+}
+
+# Restore disk space and remove sensitive files before shipping a VM.
+function vm_clean {
+    echo "Cleaning VM..."
+    sudo apt-get clean
+    sudo apt-get autoremove
+    sudo rm -rf /tmp/*
+    sudo rm -rf openvswitch*.tar.gz
+
+    # Remove sensistive files
+    history -c  # note this won't work if you have multiple bash sessions
+    rm -f ~/.bash_history  # need to clear in memory and remove on disk
+    rm -f ~/.ssh/id_rsa* ~/.ssh/known_hosts
+    sudo rm -f ~/.ssh/authorized_keys*
+
+    # Remove Mininet files
+    #sudo rm -f /lib/modules/python2.5/site-packages/mininet*
+    #sudo rm -f /usr/bin/mnexec
+
+    # Clear optional dev script for SSH keychain load on boot
+    rm -f ~/.bash_profile
+
+    # Clear git changes
+    git config --global user.name "None"
+    git config --global user.email "None"
+
+    # Note: you can shrink the .vmdk in vmware using
+    # vmware-vdiskmanager -k *.vmdk
+    echo "Zeroing out disk blocks for efficient compaction..."
+    time sudo dd if=/dev/zero of=/tmp/zero bs=1M
+    sync ; sleep 1 ; sync ; sudo rm -f /tmp/zero
+
+}
+
+function usage {
+    printf '\nUsage: %s [-abcdfhikmnprtvVwxy03]\n\n' $(basename $0) >&2
+
+    printf 'This install script attempts to install useful packages\n' >&2
+    printf 'for Mininet. It should (hopefully) work on Ubuntu 11.10+\n' >&2
+    printf 'If you run into trouble, try\n' >&2
+    printf 'installing one thing at a time, and looking at the \n' >&2
+    printf 'specific installation function in this script.\n\n' >&2
+
+    printf 'options:\n' >&2
+    printf -- ' -a: (default) install (A)ll packages - good luck!\n' >&2
+    printf -- ' -b: install controller (B)enchmark (oflops)\n' >&2
+    printf -- ' -c: (C)lean up after kernel install\n' >&2
+    printf -- ' -d: (D)elete some sensitive files from a VM image\n' >&2
+    printf -- ' -e: install Mininet d(E)veloper dependencies\n' >&2
+    printf -- ' -f: install Open(F)low\n' >&2
+    printf -- ' -h: print this (H)elp message\n' >&2
+    printf -- ' -i: install (I)ndigo Virtual Switch\n' >&2
+    printf -- ' -k: install new (K)ernel\n' >&2
+    printf -- ' -m: install Open vSwitch kernel (M)odule from source dir\n' >&2
+    printf -- ' -n: install Mini(N)et dependencies + core files\n' >&2
+    printf -- ' -p: install (P)OX OpenFlow Controller\n' >&2
+    printf -- ' -r: remove existing Open vSwitch packages\n' >&2
+    printf -- ' -s <dir>: place dependency (S)ource/build trees in <dir>\n' >&2
+    printf -- ' -t: complete o(T)her Mininet VM setup tasks\n' >&2
+    printf -- ' -v: install Open (V)switch\n' >&2
+    printf -- ' -V <version>: install a particular version of Open (V)switch on Ubuntu\n' >&2
+    printf -- ' -w: install OpenFlow (W)ireshark dissector\n' >&2
+    printf -- ' -y: install R(y)u Controller\n' >&2
+    printf -- ' -x: install NO(X) Classic OpenFlow controller\n' >&2
+    printf -- ' -0: (default) -0[fx] installs OpenFlow 1.0 versions\n' >&2
+    printf -- ' -3: -3[fx] installs OpenFlow 1.3 versions\n' >&2
+    exit 2
+}
+
+OF_VERSION=1.0
+
+if [ $# -eq 0 ]
+then
+    all
+else
+    while getopts 'abcdefhikmnprs:tvV:wxy03' OPTION
+    do
+      case $OPTION in
+      a)    all;;
+      b)    cbench;;
+      c)    kernel_clean;;
+      d)    vm_clean;;
+      e)    mn_dev;;
+      f)    case $OF_VERSION in
+            1.0) of;;
+            1.3) of13;;
+            *)  echo "Invalid OpenFlow version $OF_VERSION";;
+            esac;;
+      h)    usage;;
+      i)    ivs;;
+      k)    kernel;;
+      m)    modprobe;;
+      n)    mn_deps;;
+      p)    pox;;
+      r)    remove_ovs;;
+      s)    mkdir -p $OPTARG; # ensure the directory is created
+            BUILD_DIR="$( cd -P "$OPTARG" && pwd )"; # get the full path
+            echo "Dependency installation directory: $BUILD_DIR";;
+      t)    vm_other;;
+      v)    ovs;;
+      V)    OVS_RELEASE=$OPTARG;
+            ubuntuOvs;;
+      w)    install_wireshark;;
+      x)    case $OF_VERSION in
+            1.0) nox;;
+            1.3) nox13;;
+            *)  echo "Invalid OpenFlow version $OF_VERSION";;
+            esac;;
+      y)    ryu;;
+      0)    OF_VERSION=1.0;;
+      3)    OF_VERSION=1.3;;
+      ?)    usage;;
+      esac
+    done
+    shift $(($OPTIND - 1))
+fi