adding sfc demo with icn sdewan cnf 57/71157/7
authorKuralamudhan Ramakrishnan <kuralamudhan.ramakrishnan@intel.com>
Fri, 18 Sep 2020 07:29:11 +0000 (00:29 -0700)
committerKuralamudhan Ramakrishnan <kuralamudhan.ramakrishnan@intel.com>
Fri, 18 Sep 2020 19:04:41 +0000 (12:04 -0700)
- vagrant is used to create 5 VMs master, minion01, minion02, TM1 and TM2
- node.sh enables nested VTx
- README.md documentated all steps to bring up the sfc

Signed-off-by: Kuralamudhan Ramakrishnan <kuralamudhan.ramakrishnan@intel.com>
Change-Id: Id382f734dedb50354e7986fbf954663b374c1ff3

17 files changed:
.gitignore
demo/sfc-setup/README.md [new file with mode: 0644]
demo/sfc-setup/Vagrantfile [new file with mode: 0644]
demo/sfc-setup/config/default.yml [new file with mode: 0644]
demo/sfc-setup/demo/firewall-dyn-net-2.yaml [new file with mode: 0644]
demo/sfc-setup/demo/firewall-right-pnetwork.yaml [new file with mode: 0644]
demo/sfc-setup/demo/firewall-rule-reject-icmp-right-pnetwork.yaml [new file with mode: 0644]
demo/sfc-setup/demo/ms1.yaml [new file with mode: 0644]
demo/sfc-setup/demo/sfc-network.yaml [new file with mode: 0644]
demo/sfc-setup/demo/sfc.yaml [new file with mode: 0644]
demo/sfc-setup/demo/slb-ngfw-sdewan-cnf-deployment.yaml [new file with mode: 0644]
demo/sfc-setup/insecure_keys/key [new file with mode: 0644]
demo/sfc-setup/insecure_keys/key.pub [new file with mode: 0644]
demo/sfc-setup/node.sh [new file with mode: 0755]
demo/sfc-setup/ovn4nfv-pod-network/ovn-daemonset.yaml [new file with mode: 0644]
demo/sfc-setup/ovn4nfv-pod-network/ovn4nfv-k8s-plugin.yml [new file with mode: 0644]
demo/sfc-setup/setup.sh [new file with mode: 0755]

index 33defe4..c909adf 100644 (file)
@@ -1 +1,2 @@
 .tox/
+demo/sfc-setup/.vagrant
diff --git a/demo/sfc-setup/README.md b/demo/sfc-setup/README.md
new file mode 100644 (file)
index 0000000..6f58b82
--- /dev/null
@@ -0,0 +1,113 @@
+# Service Function Chaining(SFC) - setup
+
+## Summary
+
+This project offers a means for deploying a Kubernetes cluster
+that satisfies the requirements of ovn4nfv sfc-setup
+
+## Virtual Machines
+
+This project uses [Vagrant tool][2] for provisioning Virtual Machines
+automatically. The [setup](setup.sh) bash script contains the
+Linux instructions to install dependencies and plugins required for
+its usage. This script supports two Virtualization technologies
+(Libvirt and VirtualBox).
+
+```
+    $ sudo ./setup.sh -p libvirt
+```
+There is a `default.yml` in the `./config` directory which creates multiple vm.
+
+Once Vagrant is installed, it's possible to provision a vm using
+the following instructions:
+```
+    $ vagrant up
+```
+In-depth documentation and use cases of various Vagrant commands [Vagrant commands][3]
+is available on the Vagrant site.
+
+## Deployment
+
+### kubeadm
+
+Install the [docker](https://docs.docker.com/engine/install/ubuntu/) in the master, minion01 and minion02 vm.
+Follow the steps in [create cluster kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) to create kubernetes cluster in master
+In the master vm run the `kubeadm init` as below. The ovn4nfv uses same pod network cidr `10.244.64.0/18`
+```
+    $ kubeadm init --kubernetes-version=1.19.0 --pod-network-cidr=10.244.64.0/18 --apiserver-advertise-address=<master_eth0_ip_address>
+```
+Deploy the ovn4nfv Pod network to the cluster.
+```
+    $ kubectl apply -f ovn4nfv-pod-network/ovn-daemonset.yaml
+    $ kubectl apply -f ovn4nfv-pod-network/ovn4nfv-k8s-plugin.yaml
+```
+Join minion01 and minion02 by running the `kubeadm join` on each node as root as mentioned in [create cluster kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/)
+
+### TM1 server
+
+ssh into the TM1 vm and run the following command to attach TM1 to the left provider network.
+```
+    $ ip addr flush dev eth1
+    $ ip link add link eth1 name eth1.100 type vlan id 100
+    $ ip link set dev eth1.100 up
+    $ ip addr add 172.30.10.101/24 dev eth1.100
+    $ ip route del default
+    $ ip route add default via 172.30.10.3
+```
+### TM2 server
+
+ssh into the TM2 vm and run the following command to attach TM2 to the right provider network.
+```
+    $ ip addr flush dev eth1
+    $ ip link add link eth1 name eth1.200 type vlan id 200
+    $ ip link set dev eth1.200 up
+    $ ip addr add 172.30.20.2/24 dev eth1.200
+```
+Run the following commands to create virutal router
+```
+   $ ip route add 172.30.10.0/24 via 172.30.20.3
+   $ ip route add 172.30.33.0/24 via 172.30.20.3
+   $ ip route add 172.30.44.0/24 via 172.30.20.3
+```
+```
+   $ echo 1 > /proc/sys/net/ipv4/ip_forward
+   $ /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
+   $ iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
+   $ iptables -A FORWARD -i eth1.200 -o eth0 -j ACCEPT
+```
+## Demo
+
+Deploy the SDEWAN controller in cluster
+```
+   $ git clone https://github.com/akraino-edge-stack/icn-sdwan.git
+   $ cd icn-sdwan/platform/crd-ctrlr
+   $ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v0.11.0/cert-manager.yaml --validate=false
+   $ kubectl apply -f examples/sdewan-controller.yaml
+```
+From TM1 try to ping google.com, the ping operation will fails.
+Deploy the SFC as following
+```
+   $ kubectl apply -f sfc-network.yaml
+   $ kubectl apply -f slb-ngfw-sdewan-cnf-deployment.yaml
+   $ kubectl apply -f ms1.yaml
+```
+Pinging for goole.com or curl example.com should fail in both ms1 and TM1
+```
+   $ kubectl apply -f sfc.yaml
+```
+Pinging for google.com or curl example.com should be successful in both ms1 and TM1
+
+Let try to apply icmp reject rule in SDEWAN cnf
+```
+   $ kubectl apply -f firewall-dyn-net-2.yaml
+   $ kubectl apply -f firewall-right-pnetwork.yaml
+   $ kubectl apply -f firewall-rule-reject-icmp-right-pnetwork.yaml
+```
+Pinging for google.com will fail and curl example.com should be successful in both ms1 and TM1
+
+## License
+
+Apache-2.0
+
+[1]: https://www.vagrantup.com/
+[2]: https://www.vagrantup.com/docs/cli/
diff --git a/demo/sfc-setup/Vagrantfile b/demo/sfc-setup/Vagrantfile
new file mode 100644 (file)
index 0000000..ad11927
--- /dev/null
@@ -0,0 +1,99 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2018
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+box = {
+  :virtualbox => { :name => 'elastic/ubuntu-18.04-x86_64', :version => '20191013.0.0'},
+  :libvirt => { :name => 'intergratedcloudnative/ubuntu1804', :version => '1.0.0'}
+}
+
+require 'yaml'
+pdf = File.dirname(__FILE__) + '/config/default.yml'
+nodes = YAML.load_file(pdf)
+
+provider = (ENV['VAGRANT_DEFAULT_PROVIDER'] || :libvirt).to_sym
+puts "[INFO] Provider: #{provider} "
+
+if ENV['no_proxy'] != nil or ENV['NO_PROXY']
+  $no_proxy = ENV['NO_PROXY'] || ENV['no_proxy'] || "127.0.0.1,localhost"
+  nodes.each do |node|
+    $no_proxy += "," + node['ip']
+  end
+  $subnet = "192.168.121"
+  if provider == :virtualbox
+    $subnet = "10.0.2"
+  end
+  # NOTE: This range is based on vagrant-libvirt network definition CIDR 192.168.121.0/27
+  (1..31).each do |i|
+    $no_proxy += ",#{$subnet}.#{i}"
+  end
+end
+
+Vagrant.configure("2") do |config|
+  config.vm.box =  box[provider][:name]
+  config.vm.box_version = box[provider][:version]
+  config.ssh.insert_key = false
+
+  if ENV['http_proxy'] != nil and ENV['https_proxy'] != nil
+    if Vagrant.has_plugin?('vagrant-proxyconf')
+      config.proxy.http     = ENV['http_proxy'] || ENV['HTTP_PROXY'] || ""
+      config.proxy.https    = ENV['https_proxy'] || ENV['HTTPS_PROXY'] || ""
+      config.proxy.no_proxy = $no_proxy
+      config.proxy.enabled = { docker: false }
+    end
+  end
+  config.vm.provider 'libvirt' do |v|
+    v.nested = true
+    v.cpu_mode = 'host-passthrough'
+    v.management_network_address = "192.168.121.0/27"
+    v.random_hostname = true
+  end
+
+  sync_type = "virtualbox"
+  if provider == :libvirt
+    sync_type = "nfs"
+  end
+
+  nodes.each do |node|
+    config.vm.define node['name'] do |nodeconfig|
+      nodeconfig.vm.hostname = node['name']
+      nodeconfig.vm.network :private_network, :ip => node['ip'], :type => :static
+      nodeconfig.vm.provider 'virtualbox' do |v|
+        v.customize ["modifyvm", :id, "--memory", node['memory']]
+        v.customize ["modifyvm", :id, "--cpus", node['cpus']]
+        if node.has_key? "volumes"
+          node['volumes'].each do |volume|
+            $volume_file = "#{node['name']}-#{volume['name']}.vdi"
+            unless File.exist?($volume_file)
+              v.customize ['createmedium', 'disk', '--filename', $volume_file, '--size', volume['size']]
+            end
+            v.customize ['storageattach', :id, '--storagectl', 'IDE Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', $volume_file]
+          end
+        end
+      end
+      nodeconfig.vm.provider 'libvirt' do |v|
+        v.memory = node['memory']
+        v.cpus = node['cpus']
+        nodeconfig.vm.provision 'shell' do |sh|
+          sh.path =  "node.sh"
+          if node.has_key? "volumes"
+            $volume_mounts_dict = ''
+            node['volumes'].each do |volume|
+              $volume_mounts_dict += "#{volume['name']}=#{volume['mount']},"
+              $volume_file = "./#{node['name']}-#{volume['name']}.qcow2"
+              v.storage :file, :bus => 'sata', :device => volume['name'], :size => volume['size']
+            end
+            sh.args = ['-v', $volume_mounts_dict[0...-1]]
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/demo/sfc-setup/config/default.yml b/demo/sfc-setup/config/default.yml
new file mode 100644 (file)
index 0000000..f312a6a
--- /dev/null
@@ -0,0 +1,30 @@
+---
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2018
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+- name: "master"
+  ip: "10.10.10.13"
+  memory: 16384
+  cpus: 16
+- name: "minion01"
+  ip: "10.10.10.14"
+  memory: 18432
+  cpus: 16
+- name: "minion02"
+  ip: "10.10.10.15"
+  memory: 18432
+  cpus: 16
+- name: "tm1-node"
+  ip: "10.10.10.16"
+  memory: 512
+  cpus: 2
+- name: "tm2-node"
+  ip: "10.10.10.17"
+  memory: 512
+  cpus: 2
diff --git a/demo/sfc-setup/demo/firewall-dyn-net-2.yaml b/demo/sfc-setup/demo/firewall-dyn-net-2.yaml
new file mode 100644 (file)
index 0000000..4ceac59
--- /dev/null
@@ -0,0 +1,14 @@
+apiVersion: batch.sdewan.akraino.org/v1alpha1
+kind: FirewallZone
+metadata:
+  name: dynnet2
+  namespace: default
+  labels:
+    sdewanPurpose: cnf1
+
+spec:
+  network:
+    - dync-net2
+  input: ACCEPT
+  output: ACCEPT
+  forward: ACCEPT
diff --git a/demo/sfc-setup/demo/firewall-right-pnetwork.yaml b/demo/sfc-setup/demo/firewall-right-pnetwork.yaml
new file mode 100644 (file)
index 0000000..f7e3283
--- /dev/null
@@ -0,0 +1,16 @@
+apiVersion: batch.sdewan.akraino.org/v1alpha1
+kind: FirewallZone
+metadata:
+  name: rpnetwork
+  namespace: default
+  labels:
+    sdewanPurpose: cnf1
+
+spec:
+  network:
+    - right-pnetwork
+  input: ACCEPT
+  output: ACCEPT
+  forward: ACCEPT
+  masq: "0"
+  mtu_fix: "1"
diff --git a/demo/sfc-setup/demo/firewall-rule-reject-icmp-right-pnetwork.yaml b/demo/sfc-setup/demo/firewall-rule-reject-icmp-right-pnetwork.yaml
new file mode 100644 (file)
index 0000000..3493bb6
--- /dev/null
@@ -0,0 +1,13 @@
+apiVersion: batch.sdewan.akraino.org/v1alpha1
+kind: FirewallRule
+metadata:
+  name: firewallrule-icmp-right-pnetwork
+  namespace: default
+  labels:
+    sdewanPurpose: cnf1
+
+spec:
+  src: dynnet2
+  dest: rpnetwork
+  proto: icmp
+  target: REJECT
diff --git a/demo/sfc-setup/demo/ms1.yaml b/demo/sfc-setup/demo/ms1.yaml
new file mode 100644 (file)
index 0000000..d910257
--- /dev/null
@@ -0,0 +1,40 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: ms1
+  labels:
+    app: ms1
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: ms1
+  template:
+    metadata:
+      labels:
+        app: ms1
+      annotations:
+        k8s.plugin.opnfv.org/nfn-network: '{ "type": "ovn4nfv", "interface": [{ "name": "left-pnetwork", "interface": "net0", "defaultgateway": "true", "gwipaddress": "172.30.10.3" }]}'
+
+    spec:
+      containers:
+      - name: ms1
+        image: rkamudhan/netshoot:v1.0
+        imagePullPolicy: IfNotPresent
+        stdin: true
+        tty: true
+        securityContext:
+          privileged: true
+          capabilities:
+            add: ["NET_ADMIN"]
+      dnsPolicy: "None"
+      dnsConfig:
+        nameservers:
+          - 8.8.8.8
+        searches:
+          - default.svc.cluster.local
+          - svc.cluster.local
+          - cluster.local
+        options:
+          - name: ndots
+            value: "5"
diff --git a/demo/sfc-setup/demo/sfc-network.yaml b/demo/sfc-setup/demo/sfc-network.yaml
new file mode 100644 (file)
index 0000000..9a6aa2c
--- /dev/null
@@ -0,0 +1,67 @@
+apiVersion: k8s.plugin.opnfv.org/v1alpha1
+kind: Network
+metadata:
+  name: dync-net1
+spec:
+  cniType : ovn4nfv
+  ipv4Subnets:
+  - subnet: 172.30.33.0/24
+    name: subnet1
+    gateway: 172.30.33.1/24
+
+---
+
+apiVersion: k8s.plugin.opnfv.org/v1alpha1
+kind: Network
+metadata:
+  name: dync-net2
+spec:
+  cniType : ovn4nfv
+  ipv4Subnets:
+  - subnet: 172.30.44.0/24
+    name: subnet1
+    gateway: 172.30.44.1/24
+
+---
+
+apiVersion: k8s.plugin.opnfv.org/v1alpha1
+kind: ProviderNetwork
+metadata:
+  name: left-pnetwork
+spec:
+  cniType: ovn4nfv
+  ipv4Subnets:
+  - subnet: 172.30.10.0/24
+    name: subnet1
+    gateway: 172.30.10.1/24
+    excludeIps: 172.30.10.2
+  providerNetType: VLAN
+  vlan:
+    vlanId: "100"
+    providerInterfaceName: eth1
+    logicalInterfaceName: eth1.100
+    vlanNodeSelector: specific
+    nodeLabelList:
+    - kubernetes.io/os=linux
+
+---
+
+apiVersion: k8s.plugin.opnfv.org/v1alpha1
+kind: ProviderNetwork
+metadata:
+  name: right-pnetwork
+spec:
+  cniType: ovn4nfv
+  ipv4Subnets:
+  - subnet: 172.30.20.0/24
+    name: subnet1
+    gateway: 172.30.20.1/24
+    excludeIps: 172.30.20.2
+  providerNetType: VLAN
+  vlan:
+    vlanId: "200"
+    providerInterfaceName: eth1
+    logicalInterfaceName: eth1.200
+    vlanNodeSelector: specific
+    nodeLabelList:
+    - kubernetes.io/os=linux
diff --git a/demo/sfc-setup/demo/sfc.yaml b/demo/sfc-setup/demo/sfc.yaml
new file mode 100644 (file)
index 0000000..98af02a
--- /dev/null
@@ -0,0 +1,18 @@
+apiVersion: k8s.plugin.opnfv.org/v1alpha1\r
+kind: NetworkChaining\r
+metadata:\r
+  name: example-networkchaining\r
+spec:\r
+  # Add fields here\r
+  chainType: "Routing"\r
+  routingSpec:\r
+    namespace: "default"\r
+    networkChain: "app=slb,dync-net1,app=ngfw,dync-net2,app=sdwan"\r
+    leftNetwork:\r
+    - networkName: "right-pnetwork"\r
+      gatewayIp: "172.30.10.2"\r
+      subnet: "172.30.10.0/24"\r
+    rightNetwork:\r
+    - networkName: "left-pnetwork"\r
+      gatewayIp: "172.30.20.2"\r
+      subnet: "172.30.20.0/24"\r
diff --git a/demo/sfc-setup/demo/slb-ngfw-sdewan-cnf-deployment.yaml b/demo/sfc-setup/demo/slb-ngfw-sdewan-cnf-deployment.yaml
new file mode 100644 (file)
index 0000000..4a1a9cd
--- /dev/null
@@ -0,0 +1,200 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: slb
+  labels:
+    app: slb
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: slb
+  template:
+    metadata:
+      labels:
+        app: slb
+      annotations:
+        k8s.plugin.opnfv.org/nfn-network: '{ "type": "ovn4nfv", "interface": [{ "name": "left-pnetwork", "interface": "net0" }, { "name": "dync-net1", "interface": "net1" }]}'
+
+    spec:
+      containers:
+      - name: slb
+        image: rkamudhan/netshoot:v1.0
+        imagePullPolicy: IfNotPresent
+        stdin: true
+        tty: true
+        securityContext:
+          privileged: true
+          capabilities:
+            add: ["NET_ADMIN"]
+
+---
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: ngfw
+  labels:
+    app: ngfw
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app: ngfw
+  template:
+    metadata:
+      labels:
+        app: ngfw
+      annotations:
+        k8s.plugin.opnfv.org/nfn-network: '{ "type": "ovn4nfv", "interface": [{ "name": "dync-net1", "interface": "net0" }, { "name": "dync-net2", "interface": "net1" }]}'
+
+    spec:
+      containers:
+      - name: ngfw
+        image: rkamudhan/netshoot:v1.0
+        imagePullPolicy: IfNotPresent
+        stdin: true
+        tty: true
+        securityContext:
+          privileged: true
+          capabilities:
+            add: ["NET_ADMIN"]
+
+
+---
+
+apiVersion: v1
+data:
+  entrypoint.sh: |-
+    #!/bin/bash
+    # Always exit on errors.
+    set -ex
+    echo "" > /etc/config/network
+    cat > /etc/config/mwan3 <<EOF
+    config globals 'globals'
+        option mmx_mask '0x3F00'
+        option local_source 'lan'
+    EOF
+    eval "networks=$(grep nfn-network /tmp/podinfo/annotations | awk  -F '=' '{print $2}')"
+    for net in $(echo -e $networks | jq -c ".interface[]")
+    do
+      interface=$(echo $net | jq -r .interface)
+      ipaddr=$(ifconfig $interface | awk '/inet/{print $2}' | cut -f2 -d ":" | awk 'NR==1 {print $1}')
+      vif="$interface"
+      cat >> /etc/config/network <<EOF
+    config interface '$vif'
+        option ifname '$interface'
+        option proto 'static'
+        option ipaddr '$ipaddr'
+        option netmask '255.255.255.0'
+    EOF
+      cat >> /etc/config/mwan3 <<EOF
+    config interface '$vif'
+            option enabled '1'
+            option family 'ipv4'
+            option reliability '2'
+            option count '1'
+            option timeout '2'
+            option failure_latency '1000'
+            option recovery_latency '500'
+            option failure_loss '20'
+            option recovery_loss '5'
+            option interval '5'
+            option down '3'
+            option up '8'
+    EOF
+    done
+    /sbin/procd &
+    /sbin/ubusd &
+    iptables -t nat -L
+    sleep 1
+    /etc/init.d/rpcd start
+    /etc/init.d/dnsmasq start
+    /etc/init.d/network start
+    /etc/init.d/odhcpd start
+    /etc/init.d/uhttpd start
+    /etc/init.d/log start
+    /etc/init.d/dropbear start
+    /etc/init.d/mwan3 restart
+    /etc/init.d/firewall restart
+    echo "Entering sleep... (success)"
+    # Sleep forever.
+    while true; do sleep 100; done
+kind: ConfigMap
+metadata:
+  name: sdewan-sh
+  namespace: default
+...
+
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: sdwan
+  namespace: default
+  labels:
+    app: sdwan
+    sdewanPurpose: cnf1
+spec:
+  progressDeadlineSeconds: 600
+  replicas: 1
+  selector:
+    matchLabels:
+      app: sdwan
+      sdewanPurpose: cnf1
+  strategy:
+    rollingUpdate:
+      maxSurge: 25%
+      maxUnavailable: 25%
+    type: RollingUpdate
+  template:
+    metadata:
+      annotations:
+        k8s.plugin.opnfv.org/nfn-network: '{ "type": "ovn4nfv", "interface": [{ "name": "dync-net2", "interface": "net0" }, { "name": "right-pnetwork", "interface": "net1" }]}'
+      labels:
+        app: sdwan
+        sdewanPurpose: cnf1
+    spec:
+      containers:
+      - command:
+              #- sleep
+              #- "3600"
+        - /bin/sh
+        - /tmp/sdewan/entrypoint.sh
+        image: integratedcloudnative/openwrt:0.3.0
+        imagePullPolicy: IfNotPresent
+        name: sdewan
+        readinessProbe:
+          failureThreshold: 5
+          httpGet:
+            path: /
+            port: 80
+            scheme: HTTP
+          initialDelaySeconds: 5
+          periodSeconds: 5
+          successThreshold: 1
+          timeoutSeconds: 1
+        securityContext:
+          privileged: true
+          capabilities:
+            add: ["NET_ADMIN"]
+          procMount: Default
+        volumeMounts:
+        - mountPath: /tmp/sdewan
+          name: sdewan-sh
+          readOnly: true
+        - mountPath: /tmp/podinfo
+          name: podinfo
+          readOnly: true
+      restartPolicy: Always
+      volumes:
+      - configMap:
+          defaultMode: 420
+          name: sdewan-sh
+        name: sdewan-sh
+      - name: podinfo
+        downwardAPI:
+          items:
+            - path: "annotations"
+              fieldRef:
+                fieldPath: metadata.annotations
diff --git a/demo/sfc-setup/insecure_keys/key b/demo/sfc-setup/insecure_keys/key
new file mode 100644 (file)
index 0000000..7d6a083
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
+w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
+kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
+hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
+Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
+yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
+ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
+Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
+TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
+iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
+sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
+4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
+cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
+EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
+CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
+3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
+YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
+3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
+dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
+6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
+P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
+llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
+kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
++vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
+NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
+-----END RSA PRIVATE KEY-----
diff --git a/demo/sfc-setup/insecure_keys/key.pub b/demo/sfc-setup/insecure_keys/key.pub
new file mode 100644 (file)
index 0000000..18a9c00
--- /dev/null
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key
diff --git a/demo/sfc-setup/node.sh b/demo/sfc-setup/node.sh
new file mode 100755 (executable)
index 0000000..a51be19
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/bash
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2018
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+set -o nounset
+set -o pipefail
+
+# usage() - Prints the usage of the program
+function usage {
+    cat <<EOF
+usage: $0 [-v volumes]
+Optional Argument:
+    -v List of key pair values for volumes and mount points ( e. g. sda=/var/lib/docker/,sdb=/var/lib/libvirt/ )
+EOF
+}
+
+# mount_external_partition() - Create partition and mount the external volume
+function mount_external_partition {
+    local dev_name="/dev/$1"
+    local mount_dir=$2
+
+    sfdisk $dev_name --no-reread << EOF
+;
+EOF
+    mkfs -t ext4 ${dev_name}1
+    mkdir -p $mount_dir
+    mount ${dev_name}1 $mount_dir
+    echo "${dev_name}1 $mount_dir           ext4    errors=remount-ro,noatime,barrier=0 0       1" >> /etc/fstab
+}
+
+while getopts "h?v:" opt; do
+    case $opt in
+        v)
+            dict_volumes="$OPTARG"
+            ;;
+        h|\?)
+            usage
+            exit
+            ;;
+    esac
+done
+
+swapoff -a
+if [[ -n "${dict_volumes+x}" ]]; then
+    for kv in ${dict_volumes//,/ } ;do
+        mount_external_partition ${kv%=*} ${kv#*=}
+    done
+fi
+
+vendor_id=$(lscpu|grep "Vendor ID")
+if [[ $vendor_id == *GenuineIntel* ]]; then
+    kvm_ok=$(cat /sys/module/kvm_intel/parameters/nested)
+    if [[ $kvm_ok == 'N' ]]; then
+        echo "Enable Intel Nested-Virtualization"
+        rmmod kvm-intel
+        echo 'options kvm-intel nested=y' >> /etc/modprobe.d/dist.conf
+        modprobe kvm-intel
+        echo kvm-intel >> /etc/modules
+    fi
+else
+    kvm_ok=$(cat /sys/module/kvm_amd/parameters/nested)
+    if [[ $kvm_ok == '0' ]]; then
+        echo "Enable AMD Nested-Virtualization"
+        rmmod kvm-amd
+        sh -c "echo 'options kvm-amd nested=1' >> /etc/modprobe.d/dist.conf"
+        modprobe kvm-amd
+        echo kvm-amd >> /etc/modules
+    fi
+fi
+modprobe vhost_net
+echo vhost_net >> /etc/modules
+source /etc/os-release || source /usr/lib/os-release
+case ${ID,,} in
+    *suse)
+    ;;
+    ubuntu|debian)
+        apt-get install -y cpu-checker
+        kvm-ok
+    ;;
+    rhel|centos|fedora)
+    ;;
+esac
diff --git a/demo/sfc-setup/ovn4nfv-pod-network/ovn-daemonset.yaml b/demo/sfc-setup/ovn4nfv-pod-network/ovn-daemonset.yaml
new file mode 100644 (file)
index 0000000..677a9bc
--- /dev/null
@@ -0,0 +1,239 @@
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: ovn-nb-tcp
+  namespace: kube-system
+spec:
+  ports:
+    - name: ovn-nb-tcp
+      protocol: TCP
+      port: 6641
+      targetPort: 6641
+  type: ClusterIP
+  selector:
+    app: ovn-control-plane
+  sessionAffinity: None
+
+---
+kind: Service
+apiVersion: v1
+metadata:
+  name: ovn-sb-tcp
+  namespace: kube-system
+spec:
+  ports:
+    - name: ovn-sb-tcp
+      protocol: TCP
+      port: 6642
+      targetPort: 6642
+  type: ClusterIP
+  selector:
+    app: ovn-control-plane
+  sessionAffinity: None
+
+---
+kind: Deployment
+apiVersion: apps/v1
+metadata:
+  name: ovn-control-plane
+  namespace: kube-system
+  annotations:
+    kubernetes.io/description: |
+      OVN control plane deployment using tcp: ovn-northd-tcp, ovn-nb-tcp and ovn-sb-tcp.
+spec:
+  replicas: 1
+  strategy:
+    rollingUpdate:
+      maxSurge: 0%
+      maxUnavailable: 100%
+    type: RollingUpdate
+  selector:
+    matchLabels:
+      app: ovn-control-plane
+  template:
+    metadata:
+      labels:
+        app: ovn-control-plane
+    spec:
+      tolerations:
+      - operator: Exists
+        effect: NoSchedule
+      affinity:
+        podAntiAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            - labelSelector:
+                matchLabels:
+                  app: ovn-control-plane
+              topologyKey: kubernetes.io/hostname
+      priorityClassName: system-cluster-critical
+      hostNetwork: true
+      containers:
+        - name: ovn-control-plane
+          image: docker.io/integratedcloudnative/ovn-images:v1.0.0
+          imagePullPolicy: IfNotPresent
+          command: ["ovn4nfv-k8s", "start_ovn_control_plane"]
+          securityContext:
+            capabilities:
+              add: ["SYS_NICE"]
+          env:
+            - name: POD_IP
+              valueFrom:
+                fieldRef:
+                  fieldPath: status.podIP
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            - name: POD_NAMESPACE
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.namespace
+          resources:
+            requests:
+              cpu: 500m
+              memory: 300Mi
+          volumeMounts:
+            - mountPath: /var/run/openvswitch
+              name: host-run-ovs
+            - mountPath: /var/run/ovn
+              name: host-run-ovn
+            - mountPath: /sys
+              name: host-sys
+              readOnly: true
+            - mountPath: /etc/openvswitch
+              name: host-config-openvswitch
+            - mountPath: /var/log/openvswitch
+              name: host-log-ovs
+            - mountPath: /var/log/ovn
+              name: host-log-ovn
+          readinessProbe:
+            exec:
+              command: ["ovn4nfv-k8s", "check_ovn_control_plane"]
+            periodSeconds: 3
+          livenessProbe:
+            exec:
+              command: ["ovn4nfv-k8s", "check_ovn_control_plane"]
+            initialDelaySeconds: 30
+            periodSeconds: 7
+            failureThreshold: 5
+      nodeSelector:
+        beta.kubernetes.io/os: "linux"
+        ovn4nfv-k8s-plugin: ovn-control-plane
+      volumes:
+        - name: host-run-ovs
+          hostPath:
+            path: /run/openvswitch
+        - name: host-run-ovn
+          hostPath:
+            path: /run/ovn
+        - name: host-sys
+          hostPath:
+            path: /sys
+        - name: host-config-openvswitch
+          hostPath:
+            path: /etc/origin/openvswitch
+        - name: host-log-ovs
+          hostPath:
+            path: /var/log/openvswitch
+        - name: host-log-ovn
+          hostPath:
+            path: /var/log/ovn
+
+---
+kind: DaemonSet
+apiVersion: apps/v1
+metadata:
+  name: ovn-controller
+  namespace: kube-system
+  annotations:
+    kubernetes.io/description: |
+      OVN controller: Start ovsdb-server & ovs-vswitchd components, and ovn controller
+spec:
+  selector:
+    matchLabels:
+      app: ovn-controller
+  updateStrategy:
+    type: OnDelete
+  template:
+    metadata:
+      labels:
+        app: ovn-controller 
+    spec:
+      tolerations:
+      - operator: Exists
+        effect: NoSchedule
+      priorityClassName: system-cluster-critical
+      hostNetwork: true
+      hostPID: true
+      containers:
+        - name: ovn-controller
+          image: docker.io/integratedcloudnative/ovn-images:v1.0.0
+          imagePullPolicy: IfNotPresent
+          command: ["ovn4nfv-k8s", "start_ovn_controller"]
+          securityContext:
+            runAsUser: 0
+            privileged: true
+          env:
+            - name: POD_IP
+              valueFrom:
+                fieldRef:
+                  fieldPath: status.podIP
+          volumeMounts:
+            - mountPath: /lib/modules
+              name: host-modules
+              readOnly: true
+            - mountPath: /var/run/openvswitch
+              name: host-run-ovs
+            - mountPath: /var/run/ovn
+              name: host-run-ovn
+            - mountPath: /sys
+              name: host-sys
+              readOnly: true
+            - mountPath: /etc/openvswitch
+              name: host-config-openvswitch
+            - mountPath: /var/log/openvswitch
+              name: host-log-ovs
+            - mountPath: /var/log/ovn
+              name: host-log-ovn
+          readinessProbe:
+            exec:
+              command: ["ovn4nfv-k8s", "check_ovn_controller"]
+            periodSeconds: 5
+          livenessProbe:
+            exec:
+              command: ["ovn4nfv-k8s", "check_ovn_controller"]
+            initialDelaySeconds: 10
+            periodSeconds: 5
+            failureThreshold: 5
+          resources:
+            requests:
+              cpu: 200m
+              memory: 300Mi
+            limits:
+              cpu: 1000m
+              memory: 800Mi
+      nodeSelector:
+        beta.kubernetes.io/os: "linux"
+      volumes:
+        - name: host-modules
+          hostPath:
+            path: /lib/modules
+        - name: host-run-ovs
+          hostPath:
+            path: /run/openvswitch
+        - name: host-run-ovn
+          hostPath:
+            path: /run/ovn
+        - name: host-sys
+          hostPath:
+            path: /sys
+        - name: host-config-openvswitch
+          hostPath:
+            path: /etc/origin/openvswitch
+        - name: host-log-ovs
+          hostPath:
+            path: /var/log/openvswitch
+        - name: host-log-ovn
+          hostPath:
+            path: /var/log/ovn
diff --git a/demo/sfc-setup/ovn4nfv-pod-network/ovn4nfv-k8s-plugin.yml b/demo/sfc-setup/ovn4nfv-pod-network/ovn4nfv-k8s-plugin.yml
new file mode 100644 (file)
index 0000000..5adf786
--- /dev/null
@@ -0,0 +1,714 @@
+---
+
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: networkchainings.k8s.plugin.opnfv.org
+spec:
+  group: k8s.plugin.opnfv.org
+  names:
+    kind: NetworkChaining
+    listKind: NetworkChainingList
+    plural: networkchainings
+    singular: networkchaining
+  scope: Namespaced
+  subresources:
+    status: {}
+  validation:
+    openAPIV3Schema:
+      description: NetworkChaining is the Schema for the networkchainings API
+      properties:
+        apiVersion:
+          description: 'APIVersion defines the versioned schema of this representation
+            of an object. Servers should convert recognized schemas to the latest
+            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
+          type: string
+        kind:
+          description: 'Kind is a string value representing the REST resource this
+            object represents. Servers may infer this from the endpoint the client
+            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
+          type: string
+        metadata:
+          type: object
+        spec:
+          description: NetworkChainingSpec defines the desired state of NetworkChaining
+          properties:
+            chainType:
+              type: string
+            routingSpec:
+              properties:
+                leftNetwork:
+                  items:
+                    properties:
+                      gatewayIp:
+                        type: string
+                      networkName:
+                        type: string
+                    required:
+                    - gatewayIp
+                    - networkName
+                    type: object
+                  type: array
+                namespace:
+                  type: string
+                networkChain:
+                  type: string
+                rightNetwork:
+                  items:
+                    properties:
+                      gatewayIp:
+                        type: string
+                      networkName:
+                        type: string
+                    required:
+                    - gatewayIp
+                    - networkName
+                    type: object
+                  type: array
+              required:
+              - leftNetwork
+              - namespace
+              - networkChain
+              - rightNetwork
+              type: object
+          required:
+          - chainType
+          - routingSpec
+          type: object
+        status:
+          description: NetworkChainingStatus defines the observed state of NetworkChaining
+          properties:
+            state:
+              type: string
+          required:
+          - state
+          type: object
+      type: object
+  version: v1alpha1
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+
+---
+
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: networks.k8s.plugin.opnfv.org
+spec:
+  group: k8s.plugin.opnfv.org
+  names:
+    kind: Network
+    listKind: NetworkList
+    plural: networks
+    singular: network
+  scope: Namespaced
+  subresources:
+    status: {}
+  validation:
+    openAPIV3Schema:
+      properties:
+        apiVersion:
+          description: 'APIVersion defines the versioned schema of this representation
+            of an object. Servers should convert recognized schemas to the latest
+            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources'
+          type: string
+        kind:
+          description: 'Kind is a string value representing the REST resource this
+            object represents. Servers may infer this from the endpoint the client
+            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds'
+          type: string
+        metadata:
+          type: object
+        spec:
+          properties:
+            cniType:
+              description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+                Important: Run "operator-sdk generate k8s" to regenerate code after
+                modifying this file Add custom validation using kubebuilder tags:
+                https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+              type: string
+            dns:
+              properties:
+                domain:
+                  type: string
+                nameservers:
+                  items:
+                    type: string
+                  type: array
+                options:
+                  items:
+                    type: string
+                  type: array
+                search:
+                  items:
+                    type: string
+                  type: array
+              type: object
+            ipv4Subnets:
+              items:
+                properties:
+                  excludeIps:
+                    type: string
+                  gateway:
+                    type: string
+                  name:
+                    type: string
+                  subnet:
+                    type: string
+                required:
+                - name
+                - subnet
+                type: object
+              type: array
+            ipv6Subnets:
+              items:
+                properties:
+                  excludeIps:
+                    type: string
+                  gateway:
+                    type: string
+                  name:
+                    type: string
+                  subnet:
+                    type: string
+                required:
+                - name
+                - subnet
+                type: object
+              type: array
+            routes:
+              items:
+                properties:
+                  dst:
+                    type: string
+                  gw:
+                    type: string
+                required:
+                - dst
+                type: object
+              type: array
+          required:
+          - cniType
+          - ipv4Subnets
+          type: object
+        status:
+          properties:
+            state:
+              description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
+                of cluster Important: Run "operator-sdk generate k8s" to regenerate
+                code after modifying this file Add custom validation using kubebuilder
+                tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+              type: string
+          required:
+          - state
+          type: object
+  version: v1alpha1
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+
+
+---
+apiVersion: apiextensions.k8s.io/v1beta1
+kind: CustomResourceDefinition
+metadata:
+  name: providernetworks.k8s.plugin.opnfv.org
+spec:
+  group: k8s.plugin.opnfv.org
+  names:
+    kind: ProviderNetwork
+    listKind: ProviderNetworkList
+    plural: providernetworks
+    singular: providernetwork
+  scope: Namespaced
+  subresources:
+    status: {}
+  validation:
+    openAPIV3Schema:
+      description: ProviderNetwork is the Schema for the providernetworks API
+      properties:
+        apiVersion:
+          description: 'APIVersion defines the versioned schema of this representation
+            of an object. Servers should convert recognized schemas to the latest
+            internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+          type: string
+        kind:
+          description: 'Kind is a string value representing the REST resource this
+            object represents. Servers may infer this from the endpoint the client
+            submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+          type: string
+        metadata:
+          type: object
+        spec:
+          description: ProviderNetworkSpec defines the desired state of ProviderNetwork
+          properties:
+            cniType:
+              description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
+                Important: Run "operator-sdk generate k8s" to regenerate code after
+                modifying this file Add custom validation using kubebuilder tags:
+                https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+              type: string
+            direct:
+              properties:
+                directNodeSelector:
+                  type: string
+                nodeLabelList:
+                  items:
+                    type: string
+                  type: array
+                providerInterfaceName:
+                  type: string
+              required:
+              - directNodeSelector
+              - providerInterfaceName
+              type: object
+            dns:
+              properties:
+                domain:
+                  type: string
+                nameservers:
+                  items:
+                    type: string
+                  type: array
+                options:
+                  items:
+                    type: string
+                  type: array
+                search:
+                  items:
+                    type: string
+                  type: array
+              type: object
+            ipv4Subnets:
+              items:
+                properties:
+                  excludeIps:
+                    type: string
+                  gateway:
+                    type: string
+                  name:
+                    type: string
+                  subnet:
+                    type: string
+                required:
+                - name
+                - subnet
+                type: object
+              type: array
+            ipv6Subnets:
+              items:
+                properties:
+                  excludeIps:
+                    type: string
+                  gateway:
+                    type: string
+                  name:
+                    type: string
+                  subnet:
+                    type: string
+                required:
+                - name
+                - subnet
+                type: object
+              type: array
+            providerNetType:
+              type: string
+            routes:
+              items:
+                properties:
+                  dst:
+                    type: string
+                  gw:
+                    type: string
+                required:
+                - dst
+                type: object
+              type: array
+            vlan:
+              properties:
+                logicalInterfaceName:
+                  type: string
+                nodeLabelList:
+                  items:
+                    type: string
+                  type: array
+                providerInterfaceName:
+                  type: string
+                vlanId:
+                  type: string
+                vlanNodeSelector:
+                  type: string
+              required:
+              - providerInterfaceName
+              - vlanId
+              - vlanNodeSelector
+              type: object
+          required:
+          - cniType
+          - ipv4Subnets
+          - providerNetType
+          type: object
+        status:
+          description: ProviderNetworkStatus defines the observed state of ProviderNetwork
+          properties:
+            state:
+              description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
+                of cluster Important: Run "operator-sdk generate k8s" to regenerate
+                code after modifying this file Add custom validation using kubebuilder
+                tags: https://book-v1.book.kubebuilder.io/beyond_basics/generating_crd.html'
+              type: string
+          required:
+          - state
+          type: object
+      type: object
+  version: v1alpha1
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+---
+
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: k8s-nfn-sa
+  namespace: kube-system
+
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  creationTimestamp: null
+  name: k8s-nfn-cr
+rules:
+- apiGroups:
+  - ""
+  resources:
+  - pods
+  - pods/status
+  - services
+  - endpoints
+  - persistentvolumeclaims
+  - events
+  - configmaps
+  - secrets
+  - nodes
+  verbs:
+  - '*'
+- apiGroups:
+  - apps
+  resources:
+  - deployments
+  - daemonsets
+  - replicasets
+  - statefulsets
+  verbs:
+  - '*'
+- apiGroups:
+  - monitoring.coreos.com
+  resources:
+  - servicemonitors
+  verbs:
+  - get
+  - create
+- apiGroups:
+  - apps
+  resourceNames:
+  - nfn-operator
+  resources:
+  - deployments/finalizers
+  verbs:
+  - update
+- apiGroups:
+  - k8s.plugin.opnfv.org
+  resources:
+  - '*'
+  - providernetworks
+  verbs:
+  - '*'
+
+---
+
+kind: ClusterRoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: k8s-nfn-crb
+subjects:
+- kind: Group
+  name: system:serviceaccounts
+  apiGroup: rbac.authorization.k8s.io
+roleRef:
+  kind: ClusterRole
+  name: k8s-nfn-cr
+  apiGroup: rbac.authorization.k8s.io
+
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+  name: nfn-operator
+  namespace: kube-system
+spec:
+  type: NodePort
+  ports:
+  - port: 50000
+    protocol: TCP
+    targetPort: 50000
+  selector:
+    name: nfn-operator
+
+
+---
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: ovn-controller-network
+  namespace: kube-system
+data:
+  OVN_SUBNET: "10.233.64.0/18"
+  OVN_GATEWAYIP: "10.233.64.1/18"
+
+---
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: nfn-operator
+  namespace: kube-system
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      name: nfn-operator
+  template:
+    metadata:
+      labels:
+        name: nfn-operator
+    spec:
+      hostNetwork: true
+      affinity:
+        nodeAffinity:
+          requiredDuringSchedulingIgnoredDuringExecution:
+            nodeSelectorTerms:
+            - matchExpressions:
+              - key: ovn4nfv-k8s-plugin
+                operator: In
+                values:
+                - ovn-control-plane
+      tolerations:
+       - key: "node-role.kubernetes.io/master"
+         effect: "NoSchedule"
+         operator: "Exists"
+      serviceAccountName: k8s-nfn-sa
+      containers:
+        - name: nfn-operator
+          image: docker.io/rkamudhan/ovn4nfv-k8s-plugin:alpha-v0.0.5.4
+          command: ["/usr/local/bin/entrypoint", "operator"]
+          imagePullPolicy: IfNotPresent
+          envFrom:
+          - configMapRef:
+              name: ovn-controller-network
+          ports:
+          - containerPort: 50000
+            protocol: TCP
+          env:
+            - name: POD_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: metadata.name
+            - name: OPERATOR_NAME
+              value: "nfn-operator"
+
+---
+kind: ConfigMap
+apiVersion: v1
+metadata:
+  name: ovn4nfv-cni-config
+  namespace: kube-system
+  labels:
+    app: ovn4nfv
+data:
+  ovn4nfv_k8s.conf: |
+          [logging]
+          loglevel=5
+          logfile=/var/log/openvswitch/ovn4k8s.log
+
+          [cni]
+          conf-dir=/etc/cni/net.d
+          plugin=ovn4nfvk8s-cni
+
+          [kubernetes]
+          kubeconfig=/etc/cni/net.d/ovn4nfv-k8s.d/ovn4nfv-k8s.kubeconfig
+  00-network.conf: |
+          {
+            "name": "ovn4nfv-k8s-plugin",
+            "type": "ovn4nfvk8s-cni",
+            "cniVersion": "0.3.1"
+          }
+
+---
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+  name: ovn4nfv-cni
+  namespace: kube-system
+  labels:
+    app: ovn4nfv
+spec:
+  updateStrategy:
+    type: RollingUpdate
+  selector:
+    matchLabels:
+      app: ovn4nfv
+  template:
+    metadata:
+      labels:
+        app: ovn4nfv
+    spec:
+      hostNetwork: true
+      nodeSelector:
+        beta.kubernetes.io/arch: amd64
+      tolerations:
+      - operator: Exists
+        effect: NoSchedule
+      serviceAccountName: k8s-nfn-sa
+      containers:
+      - name: ovn4nfv
+        image: docker.io/rkamudhan/ovn4nfv-k8s-plugin:alpha-v0.0.5.4
+        command: ["/usr/local/bin/entrypoint", "cni"]
+        imagePullPolicy: IfNotPresent
+        resources:
+          requests:
+            cpu: 100m
+            memory: 50Mi
+          limits:
+            cpu: 100m
+            memory: 50Mi
+        securityContext:
+          privileged: true
+        volumeMounts:
+        - name: cni
+          mountPath: /host/etc/cni/net.d
+        - name: cnibin
+          mountPath: /host/opt/cni/bin
+        - name: cniconf
+          mountPath: /host/etc/openvswitch
+        - name: ovn4nfv-cfg
+          mountPath: /tmp/ovn4nfv-conf
+        - name: ovn4nfv-cni-net-conf
+          mountPath: /tmp/ovn4nfv-cni
+      volumes:
+        - name: cni
+          hostPath:
+            path: /etc/cni/net.d
+        - name: cnibin
+          hostPath:
+            path: /opt/cni/bin
+        - name: cniconf
+          hostPath:
+            path: /etc/openvswitch
+        - name: ovn4nfv-cfg
+          configMap:
+            name: ovn4nfv-cni-config
+            items:
+            - key: ovn4nfv_k8s.conf
+              path: ovn4nfv_k8s.conf
+        - name: ovn4nfv-cni-net-conf
+          configMap:
+            name: ovn4nfv-cni-config
+            items:
+            - key: 00-network.conf
+              path: 00-network.conf
+---
+apiVersion: apps/v1
+kind: DaemonSet
+metadata:
+  name: nfn-agent
+  namespace: kube-system
+  labels:
+    app: nfn-agent
+spec:
+  selector:
+    matchLabels:
+      app: nfn-agent
+  updateStrategy:
+    type: RollingUpdate
+  template:
+    metadata:
+      labels:
+        app: nfn-agent
+    spec:
+      hostNetwork: true
+      hostPID: true
+      nodeSelector:
+        beta.kubernetes.io/arch: amd64
+      tolerations:
+      - operator: Exists
+        effect: NoSchedule
+      serviceAccountName: k8s-nfn-sa
+      containers:
+      - name: nfn-agent
+        image: docker.io/rkamudhan/ovn4nfv-k8s-plugin:alpha-v0.0.5.4
+        command: ["/usr/local/bin/entrypoint", "agent"]
+        imagePullPolicy: IfNotPresent
+        resources:
+          requests:
+            cpu: 100m
+            memory: 50Mi
+          limits:
+            cpu: 100m
+            memory: 50Mi
+        env:
+          - name: NFN_NODE_NAME
+            valueFrom:
+              fieldRef:
+                fieldPath: spec.nodeName
+        securityContext:
+          runAsUser: 0
+          capabilities:
+            add: ["NET_ADMIN", "SYS_ADMIN", "SYS_PTRACE"]
+          privileged: true
+        volumeMounts:
+        - mountPath: /var/run/dbus/
+          name: host-var-run-dbus
+          readOnly: true
+        - mountPath: /run/openvswitch
+          name: host-run-ovs
+        - mountPath: /var/run/openvswitch
+          name: host-var-run-ovs
+        - mountPath: /var/run
+          name: host-var-run
+        - mountPath: /host/proc
+          name: host-proc
+        - mountPath: /host/sys
+          name: host-sys
+        - mountPath: /var/run/ovn4nfv-k8s-plugin
+          name: host-var-cniserver-socket-dir
+      volumes:
+      - name: host-run-ovs
+        hostPath:
+          path: /run/openvswitch
+      - name: host-var-run-ovs
+        hostPath:
+          path: /var/run/openvswitch
+      - name: host-var-run-dbus
+        hostPath:
+          path: /var/run/dbus
+      - name: host-var-cniserver-socket-dir
+        hostPath:
+          path: /var/run/ovn4nfv-k8s-plugin
+      - name: host-var-run
+        hostPath:
+          path: /var/run
+      - name: host-proc
+        hostPath:
+          path: /proc
+      - name: host-sys
+        hostPath:
+          path: /sys
diff --git a/demo/sfc-setup/setup.sh b/demo/sfc-setup/setup.sh
new file mode 100755 (executable)
index 0000000..79bf60c
--- /dev/null
@@ -0,0 +1,201 @@
+#!/bin/bash
+# SPDX-license-identifier: Apache-2.0
+##############################################################################
+# Copyright (c) 2018
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+##############################################################################
+
+set -o nounset
+set -o pipefail
+
+vagrant_version=2.2.4
+if ! vagrant version &>/dev/null; then
+    enable_vagrant_install=true
+else
+    if [[ "$vagrant_version" != "$(vagrant version | awk 'NR==1{print $3}')" ]]; then
+        enable_vagrant_install=true
+    fi
+fi
+
+function usage {
+    cat <<EOF
+usage: $0 -p <PROVIDER>
+Installation of vagrant and its dependencies in Linux OS
+
+Argument:
+    -p  Vagrant provider
+EOF
+}
+
+while getopts ":p:" OPTION; do
+    case $OPTION in
+    p)
+        provider=$OPTARG
+        ;;
+    \?)
+        usage
+        exit 1
+        ;;
+    esac
+done
+if [[ -z "${provider+x}" ]]; then
+    usage
+    exit 1
+fi
+
+case $provider in
+    "virtualbox" | "libvirt" )
+        export VAGRANT_DEFAULT_PROVIDER=${provider}
+        ;;
+    * )
+        usage
+        exit 1
+esac
+source /etc/os-release || source /usr/lib/os-release
+
+libvirt_group="libvirt"
+packages=()
+case ${ID,,} in
+    *suse)
+    INSTALLER_CMD="sudo -H -E zypper -q install -y --no-recommends"
+    packages+=(python-devel)
+
+    # Vagrant installation
+    if [[ "${enable_vagrant_install+x}" ]]; then
+        vagrant_pgp="pgp_keys.asc"
+        wget -q https://keybase.io/hashicorp/$vagrant_pgp
+        wget -q https://releases.hashicorp.com/vagrant/$vagrant_version/vagrant_${vagrant_version}_x86_64.rpm
+        gpg --quiet --with-fingerprint $vagrant_pgp
+        sudo rpm --import $vagrant_pgp
+        sudo rpm --checksig vagrant_${vagrant_version}_x86_64.rpm
+        sudo rpm --install vagrant_${vagrant_version}_x86_64.rpm
+        rm vagrant_${vagrant_version}_x86_64.rpm
+        rm $vagrant_pgp
+    fi
+
+    case $VAGRANT_DEFAULT_PROVIDER in
+        virtualbox)
+        wget -q "http://download.virtualbox.org/virtualbox/rpm/opensuse/$VERSION/virtualbox.repo" -P /etc/zypp/repos.d/
+        $INSTALLER_CMD --enablerepo=epel dkms
+        wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | rpm --import -
+        packages+=(VirtualBox-5.1)
+        ;;
+        libvirt)
+        # vagrant-libvirt dependencies
+        packages+=(qemu libvirt libvirt-devel ruby-devel gcc qemu-kvm zlib-devel libxml2-devel libxslt-devel make)
+        # NFS
+        packages+=(nfs-kernel-server)
+        ;;
+    esac
+    sudo zypper -n ref
+    ;;
+
+    ubuntu|debian)
+    libvirt_group="libvirtd"
+    INSTALLER_CMD="sudo -H -E apt-get -y -q=3 install"
+    packages+=(python-dev)
+
+    # Vagrant installation
+    if [[ "${enable_vagrant_install+x}" ]]; then
+        wget -q https://releases.hashicorp.com/vagrant/$vagrant_version/vagrant_${vagrant_version}_x86_64.deb
+        sudo dpkg -i vagrant_${vagrant_version}_x86_64.deb
+        rm vagrant_${vagrant_version}_x86_64.deb
+    fi
+
+    case $VAGRANT_DEFAULT_PROVIDER in
+        virtualbox)
+        echo "deb http://download.virtualbox.org/virtualbox/debian bionic contrib" >> /etc/apt/sources.list
+        wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -
+        wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | sudo apt-key add -
+        packages+=(virtualbox-5.1 dkms)
+        ;;
+        libvirt)
+        # vagrant-libvirt dependencies
+        packages+=(qemu libvirt-bin ebtables dnsmasq libxslt-dev libxml2-dev libvirt-dev zlib1g-dev ruby-dev cpu-checker)
+        # NFS
+        packages+=(nfs-kernel-server)
+        ;;
+    esac
+    sudo apt-get update
+    ;;
+
+    rhel|centos|fedora)
+    PKG_MANAGER=$(which dnf || which yum)
+    sudo "$PKG_MANAGER" updateinfo
+    INSTALLER_CMD="sudo -H -E ${PKG_MANAGER} -q -y install"
+    packages+=(python-devel)
+
+    # Vagrant installation
+    if [[ "${enable_vagrant_install+x}" ]]; then
+        wget -q https://releases.hashicorp.com/vagrant/$vagrant_version/vagrant_${vagrant_version}_x86_64.rpm
+        $INSTALLER_CMD vagrant_${vagrant_version}_x86_64.rpm
+        rm vagrant_${vagrant_version}_x86_64.rpm
+    fi
+
+    case $VAGRANT_DEFAULT_PROVIDER in
+        virtualbox)
+        wget -q http://download.virtualbox.org/virtualbox/rpm/rhel/virtualbox.repo -P /etc/yum.repos.d
+        $INSTALLER_CMD --enablerepo=epel dkms
+        wget -q https://www.virtualbox.org/download/oracle_vbox.asc -O- | rpm --import -
+        packages+=(VirtualBox-5.1)
+        ;;
+        libvirt)
+        # vagrant-libvirt dependencies
+        packages+=(qemu libvirt libvirt-devel ruby-devel gcc qemu-kvm)
+        # NFS
+        packages+=(nfs-utils nfs-utils-lib)
+        ;;
+    esac
+    ;;
+
+esac
+
+# Enable Nested-Virtualization
+vendor_id=$(lscpu|grep "Vendor ID")
+if [[ $vendor_id == *GenuineIntel* ]]; then
+    kvm_ok=$(cat /sys/module/kvm_intel/parameters/nested)
+    if [[ $kvm_ok == 'N' ]]; then
+        echo "Enable Intel Nested-Virtualization"
+        sudo rmmod kvm-intel
+        echo 'options kvm-intel nested=y' | sudo tee --append /etc/modprobe.d/dist.conf
+        sudo modprobe kvm-intel
+    fi
+else
+    kvm_ok=$(cat /sys/module/kvm_amd/parameters/nested)
+    if [[ $kvm_ok == '0' ]]; then
+        echo "Enable AMD Nested-Virtualization"
+        sudo rmmod kvm-amd
+        echo 'options kvm-amd nested=1' | sudo tee --append /etc/modprobe.d/dist.conf
+        sudo modprobe kvm-amd
+    fi
+fi
+sudo modprobe vhost_net
+
+${INSTALLER_CMD} "${packages[@]}"
+if ! which pip; then
+    curl -sL https://bootstrap.pypa.io/get-pip.py | sudo python
+else
+    sudo -H -E pip install --no-cache-dir --upgrade pip
+fi
+sudo -H -E pip install --no-cache-dir tox
+if [[ ${http_proxy+x} ]]; then
+    vagrant plugin install vagrant-proxyconf
+fi
+if [ "$VAGRANT_DEFAULT_PROVIDER" == libvirt ]; then
+    vagrant plugin install vagrant-libvirt
+    sudo usermod -a -G $libvirt_group "$USER" # This might require to reload user's group assigments
+    sudo systemctl restart libvirtd
+
+    # Start statd service to prevent NFS lock errors
+    sudo systemctl enable rpc-statd
+    sudo systemctl start rpc-statd
+
+    case ${ID,,} in
+        ubuntu|debian)
+        kvm-ok
+        ;;
+    esac
+fi