From 90e5f8ffe133bdf3bc0107f43d7b677bf9af986d Mon Sep 17 00:00:00 2001
From: Kuralamudhan Ramakrishnan <kuralamudhan.ramakrishnan@intel.com>
Date: Fri, 31 Jul 2020 07:33:08 -0700
Subject: [PATCH] adding ovn4nfv in kubespray (#6381)

Signed-off-by: Kuralamudhan Ramakrishnan <kuralamudhan.ramakrishnan@intel.com>
---
 .gitlab-ci/packet.yml                         |   5 +
 README.md                                     |   3 +
 docs/ci.md                                    |  84 +--
 docs/ovn4nfv.md                               |  49 ++
 roles/download/defaults/main.yml              |  15 +
 .../network_plugin/meta/main.yml              |   5 +
 .../network_plugin/ovn4nfv/tasks/main.yml     |   9 +
 .../node/templates/kubelet.env.v1beta1.j2     |   2 +-
 .../preinstall/tasks/0020-verify-settings.yml |   2 +-
 .../tasks/0050-create_directories.yml         |   3 +-
 roles/network_plugin/meta/main.yml            |   5 +
 .../network_plugin/ovn4nfv/defaults/main.yml  |  15 +
 roles/network_plugin/ovn4nfv/tasks/main.yml   |  15 +
 .../ovn4nfv/templates/ovn-daemonset.yml.j2    | 239 +++++++
 .../templates/ovn4nfv-k8s-plugin.yml.j2       | 608 ++++++++++++++++++
 tests/files/packet_ubuntu18-ovn4nfv.yml       |   9 +
 16 files changed, 1023 insertions(+), 45 deletions(-)
 create mode 100644 docs/ovn4nfv.md
 create mode 100644 roles/kubernetes-apps/network_plugin/ovn4nfv/tasks/main.yml
 create mode 100644 roles/network_plugin/ovn4nfv/defaults/main.yml
 create mode 100644 roles/network_plugin/ovn4nfv/tasks/main.yml
 create mode 100644 roles/network_plugin/ovn4nfv/templates/ovn-daemonset.yml.j2
 create mode 100644 roles/network_plugin/ovn4nfv/templates/ovn4nfv-k8s-plugin.yml.j2
 create mode 100644 tests/files/packet_ubuntu18-ovn4nfv.yml

diff --git a/.gitlab-ci/packet.yml b/.gitlab-ci/packet.yml
index 0d3ac7e87..9d2232958 100644
--- a/.gitlab-ci/packet.yml
+++ b/.gitlab-ci/packet.yml
@@ -110,6 +110,11 @@ packet_opensuse-canal:
   extends: .packet
   when: on_success
 
+packet_ubuntu18-ovn4nfv:
+  stage: deploy-part2
+  extends: .packet
+  when: on_success
+
 # Contiv does not work in k8s v1.16
 # packet_ubuntu16-contiv-sep:
 #   stage: deploy-part2
diff --git a/README.md b/README.md
index 7cdc0f155..00c040b08 100644
--- a/README.md
+++ b/README.md
@@ -130,6 +130,7 @@ Note: Upstart/SysV init based OS types are not supported.
   - [kube-ovn](https://github.com/alauda/kube-ovn) v1.2.1
   - [kube-router](https://github.com/cloudnativelabs/kube-router) v1.0.0
   - [multus](https://github.com/intel/multus-cni) v3.6.0
+  - [ovn4nfv](https://github.com/opnfv/ovn4nfv-k8s-plugin) v1.0.0
   - [weave](https://github.com/weaveworks/weave) v2.6.5
 - Application
   - [ambassador](https://github.com/datawire/ambassador): v1.5
@@ -180,6 +181,8 @@ You can choose between 10 network plugins. (default: `calico`, except Vagrant us
 - [contiv](docs/contiv.md): supports vlan, vxlan, bgp and Cisco SDN networking. This plugin is able to
     apply firewall policies, segregate containers in multiple network and bridging pods onto physical networks.
 
+- [ovn4nfv](docs/ovn4nfv.md): [ovn4nfv-k8s-plugins](https://github.com/opnfv/ovn4nfv-k8s-plugin) is the network controller, OVS agent and CNI server to offer basic SFC and OVN overlay networking.
+
 - [weave](docs/weave.md): Weave is a lightweight container overlay network that doesn't require an external K/V database cluster.
     (Please refer to `weave` [troubleshooting documentation](https://www.weave.works/docs/net/latest/troubleshooting/)).
 
diff --git a/docs/ci.md b/docs/ci.md
index 42da340c0..35710c5d5 100644
--- a/docs/ci.md
+++ b/docs/ci.md
@@ -4,51 +4,51 @@ To generate this Matrix run `./tests/scripts/md-table/main.py`
 
 ## docker
 
-| OS / CNI | calico | canal | cilium | contiv | flannel | kube-ovn | kube-router | macvlan | weave |
-|---| --- | --- | --- | --- | --- | --- | --- | --- | --- |
-amazon |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-centos7 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: |
-centos8 |  :white_check_mark: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: |
-debian10 |  :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: |
-debian9 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: |
-fedora31 |  :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: |
-fedora32 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: |
-opensuse |  :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-oracle7 |  :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-ubuntu16 |  :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: |
-ubuntu18 |  :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: |
-ubuntu20 |  :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: |
+| OS / CNI | calico | canal | cilium | contiv | flannel | kube-ovn | kube-router | macvlan | ovn4nfv | weave |
+|---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+amazon |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+centos7 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: |
+centos8 |  :white_check_mark: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: |
+debian10 |  :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+debian9 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: |
+fedora31 |  :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
+fedora32 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: |
+opensuse |  :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+oracle7 |  :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+ubuntu16 |  :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: |
+ubuntu18 |  :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: |
+ubuntu20 |  :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
 
 ## crio
 
-| OS / CNI | calico | canal | cilium | contiv | flannel | kube-ovn | kube-router | macvlan | weave |
-|---| --- | --- | --- | --- | --- | --- | --- | --- | --- |
-amazon |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-centos7 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-centos8 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-debian10 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-debian9 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-fedora31 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-fedora32 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-opensuse |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-oracle7 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-ubuntu16 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-ubuntu18 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-ubuntu20 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+| OS / CNI | calico | canal | cilium | contiv | flannel | kube-ovn | kube-router | macvlan | ovn4nfv | weave |
+|---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+amazon |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+centos7 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+centos8 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+debian10 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+debian9 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+fedora31 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+fedora32 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+opensuse |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+oracle7 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+ubuntu16 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+ubuntu18 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+ubuntu20 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
 
 ## containerd
 
-| OS / CNI | calico | canal | cilium | contiv | flannel | kube-ovn | kube-router | macvlan | weave |
-|---| --- | --- | --- | --- | --- | --- | --- | --- | --- |
-amazon |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-centos7 |  :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: |
-centos8 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-debian10 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-debian9 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-fedora31 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-fedora32 |  :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: |
-opensuse |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-oracle7 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-ubuntu16 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
-ubuntu18 |  :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: |
-ubuntu20 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+| OS / CNI | calico | canal | cilium | contiv | flannel | kube-ovn | kube-router | macvlan | ovn4nfv | weave |
+|---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+amazon |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+centos7 |  :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
+centos8 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+debian10 |  :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+debian9 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+fedora31 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+fedora32 |  :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: |
+opensuse |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+oracle7 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+ubuntu16 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
+ubuntu18 |  :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
+ubuntu20 |  :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: |
diff --git a/docs/ovn4nfv.md b/docs/ovn4nfv.md
new file mode 100644
index 000000000..9d120a72c
--- /dev/null
+++ b/docs/ovn4nfv.md
@@ -0,0 +1,49 @@
+# OVN4NFV-k8S-Plugin
+
+Intro to [ovn4nfv-k8s-plugin](https://github.com/opnfv/ovn4nfv-k8s-plugin)
+
+## How to use it
+
+* Enable ovn4nfv in `group_vars/k8s-cluster/k8s-cluster.yml`
+
+```yml
+...
+kube_network_plugin: ovn4nfv
+...
+```
+
+## Verifying ovn4nfv kube network plugin
+
+* ovn4nfv install ovn control plan in the master and ovn daemonset in all nodes
+* Network function Networking(nfn) operator is install in the master and nfn agent is installed in all the node
+* ovn4nfv install `ovn4nfvk8s-cni` cni shim binary in `/opt/cni/bin/` and nfn agent act as the cni server
+* All ovn4nfv pods are installed in the kube-system
+
+```ShellSession
+# From K8s client
+# kubectl get pods -n kube-system -l app=ovn-control-plane -o wide
+NAME                                 READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
+ovn-control-plane-5f8b7bcc65-w759g   1/1     Running   0          3d18h   192.168.121.25   master   <none>           <none>
+
+# kubectl get pods -n kube-system -l app=ovn-controller -o wide
+NAME                   READY   STATUS    RESTARTS   AGE     IP               NODE       NOMINATED NODE   READINESS GATES
+ovn-controller-54zzj   1/1     Running   0          3d18h   192.168.121.24   minion01   <none>           <none>
+ovn-controller-7cljt   1/1     Running   0          3d18h   192.168.121.25   master     <none>           <none>
+ovn-controller-cx46g   1/1     Running   0          3d18h   192.168.121.15   minion02   <none>           <none>
+
+# kubectl get pods -n kube-system -l name=nfn-operator -o wide
+NAME                            READY   STATUS    RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
+nfn-operator-6dc44dbf48-xk9zl   1/1     Running   0          3d18h   192.168.121.25   master   <none>           <none>
+
+# kubectl get pods -n kube-system -l app=nfn-agent -o wide
+NAME              READY   STATUS    RESTARTS   AGE     IP               NODE       NOMINATED NODE   READINESS GATES
+nfn-agent-dzlpp   1/1     Running   0          3d18h   192.168.121.15   minion02   <none>           <none>
+nfn-agent-jcdbn   1/1     Running   0          3d18h   192.168.121.25   master     <none>           <none>
+nfn-agent-lrkzk   1/1     Running   0          3d18h   192.168.121.24   minion01   <none>           <none>
+
+# kubectl get pods -n kube-system -l app=ovn4nfv -o wide
+NAME                READY   STATUS    RESTARTS   AGE     IP               NODE       NOMINATED NODE   READINESS GATES
+ovn4nfv-cni-5zdz2   1/1     Running   0          3d18h   192.168.121.24   minion01   <none>           <none>
+ovn4nfv-cni-k5wjp   1/1     Running   0          3d18h   192.168.121.25   master     <none>           <none>
+ovn4nfv-cni-t6z5b   1/1     Running   0          3d18h   192.168.121.15   minion02   <none>           <none>
+```
diff --git a/roles/download/defaults/main.yml b/roles/download/defaults/main.yml
index e120b7b59..847c7be88 100644
--- a/roles/download/defaults/main.yml
+++ b/roles/download/defaults/main.yml
@@ -83,6 +83,8 @@ cilium_version: "v1.8.1"
 kube_ovn_version: "v1.2.1"
 kube_router_version: "v1.0.0"
 multus_version: "v3.6"
+ovn4nfv_ovn_image_version: "v1.0.0"
+ovn4nfv_k8s_plugin_image_version: "v1.0.0"
 
 # Get kubernetes major version (i.e. 1.17.4 => 1.17)
 kube_major_version: "{{ kube_version | regex_replace('^v([0-9])+\\.([0-9]+)\\.[0-9]+', 'v\\1.\\2') }}"
@@ -490,6 +492,10 @@ kube_router_image_repo: "{{ docker_image_repo }}/cloudnativelabs/kube-router"
 kube_router_image_tag: "{{ kube_router_version }}"
 multus_image_repo: "{{ docker_image_repo }}/nfvpe/multus"
 multus_image_tag: "{{ multus_version }}"
+ovn4nfv_ovn_image_repo: "{{ docker_image_repo }}/integratedcloudnative/ovn-images"
+ovn4nfv_ovn_image_tag: "{{ ovn4nfv_ovn_image_version }}"
+ovn4nfv_k8s_plugin_image_repo: "{{ docker_image_repo }}/integratedcloudnative/ovn4nfv-k8s-plugin"
+ovn4nfv_k8s_plugin_image_tag: "{{ ovn4nfv_k8s_plugin_image_version }}"
 
 nginx_image_repo: "{{ docker_image_repo }}/library/nginx"
 nginx_image_tag: 1.19
@@ -812,6 +818,15 @@ downloads:
     groups:
     - k8s-cluster
 
+  ovn4nfv:
+    enabled: "{{ kube_network_plugin == 'ovn4nfv' }}"
+    container: true
+    repo: "{{ ovn4nfv_k8s_plugin_image_repo }}"
+    tag: "{{ ovn4nfv_k8s_plugin_image_tag }}"
+    sha256: "{{ ovn4nfv_k8s_plugin_digest_checksum|default(None) }}"
+    groups:
+    - k8s-cluster
+
   contiv:
     enabled: "{{ kube_network_plugin == 'contiv' }}"
     container: true
diff --git a/roles/kubernetes-apps/network_plugin/meta/main.yml b/roles/kubernetes-apps/network_plugin/meta/main.yml
index b5d1c0473..3204de10a 100644
--- a/roles/kubernetes-apps/network_plugin/meta/main.yml
+++ b/roles/kubernetes-apps/network_plugin/meta/main.yml
@@ -40,6 +40,11 @@ dependencies:
     tags:
       - kube-router
 
+  - role: kubernetes-apps/network_plugin/ovn4nfv
+    when: kube_network_plugin == 'ovn4nfv'
+    tags:
+      - ovn4nfv
+
   - role: kubernetes-apps/network_plugin/multus
     when: kube_network_plugin_multus
     tags:
diff --git a/roles/kubernetes-apps/network_plugin/ovn4nfv/tasks/main.yml b/roles/kubernetes-apps/network_plugin/ovn4nfv/tasks/main.yml
new file mode 100644
index 000000000..1262ee6b9
--- /dev/null
+++ b/roles/kubernetes-apps/network_plugin/ovn4nfv/tasks/main.yml
@@ -0,0 +1,9 @@
+---
+- name: ovn4nfv-k8s | Start Resources
+  kube:
+    name: "{{ item.item.name }}"
+    kubectl: "{{ bin_dir }}/kubectl"
+    filename: "{{ kube_config_dir }}/{{ item.item.file }}"
+    state: "latest"
+  with_items: "{{ ovn4nfv_node_manifests.results }}"
+  when: inventory_hostname == groups['kube-master'][0] and not item is skipped
diff --git a/roles/kubernetes/node/templates/kubelet.env.v1beta1.j2 b/roles/kubernetes/node/templates/kubelet.env.v1beta1.j2
index 765b5979e..9e3ed054c 100644
--- a/roles/kubernetes/node/templates/kubelet.env.v1beta1.j2
+++ b/roles/kubernetes/node/templates/kubelet.env.v1beta1.j2
@@ -37,7 +37,7 @@ KUBELET_ARGS="{{ kubelet_args_base }} {% if node_taints|default([]) %}--register
 {% if kubelet_flexvolumes_plugins_dir is defined %}
 KUBELET_VOLUME_PLUGIN="--volume-plugin-dir={{ kubelet_flexvolumes_plugins_dir }}"
 {% endif %}
-{% if kube_network_plugin is defined and kube_network_plugin in ["calico", "canal", "cni", "flannel", "weave", "contiv", "cilium", "kube-ovn", "kube-router", "macvlan"] %}
+{% if kube_network_plugin is defined and kube_network_plugin in ["calico", "canal", "cni", "flannel", "weave", "contiv", "cilium", "kube-ovn", "ovn4nfv", "kube-router", "macvlan"] %}
 KUBELET_NETWORK_PLUGIN="--network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin"
 {% elif kube_network_plugin is defined and kube_network_plugin == "cloud" %}
 KUBELET_NETWORK_PLUGIN="--hairpin-mode=promiscuous-bridge --network-plugin=kubenet"
diff --git a/roles/kubernetes/preinstall/tasks/0020-verify-settings.yml b/roles/kubernetes/preinstall/tasks/0020-verify-settings.yml
index 599289d90..1722a299d 100644
--- a/roles/kubernetes/preinstall/tasks/0020-verify-settings.yml
+++ b/roles/kubernetes/preinstall/tasks/0020-verify-settings.yml
@@ -22,7 +22,7 @@
 
 - name: Stop if unknown network plugin
   assert:
-    that: kube_network_plugin in ['calico', 'canal', 'flannel', 'weave', 'cloud', 'cilium', 'cni', 'contiv', 'kube-ovn', 'kube-router', 'macvlan']
+    that: kube_network_plugin in ['calico', 'canal', 'flannel', 'weave', 'cloud', 'cilium', 'cni', 'contiv', 'ovn4nfv','kube-ovn', 'kube-router', 'macvlan']
     msg: "{{ kube_network_plugin }} is not supported"
   when:
     - kube_network_plugin is defined
diff --git a/roles/kubernetes/preinstall/tasks/0050-create_directories.yml b/roles/kubernetes/preinstall/tasks/0050-create_directories.yml
index 3fe882308..d3e44d2c8 100644
--- a/roles/kubernetes/preinstall/tasks/0050-create_directories.yml
+++ b/roles/kubernetes/preinstall/tasks/0050-create_directories.yml
@@ -52,7 +52,7 @@
     - "/opt/cni/bin"
     - "/var/lib/calico"
   when:
-    - kube_network_plugin in ["calico", "weave", "canal", "flannel", "contiv", "cilium", "kube-ovn", "kube-router", "macvlan"]
+    - kube_network_plugin in ["calico", "weave", "canal", "flannel", "contiv", "cilium", "kube-ovn", "ovn4nfv", "kube-router", "macvlan"]
     - inventory_hostname in groups['k8s-cluster']
   tags:
     - network
@@ -61,6 +61,7 @@
     - weave
     - canal
     - contiv
+    - ovn4nfv
     - kube-ovn
     - kube-router
     - bootstrap-os
diff --git a/roles/network_plugin/meta/main.yml b/roles/network_plugin/meta/main.yml
index 66b283e33..52f482830 100644
--- a/roles/network_plugin/meta/main.yml
+++ b/roles/network_plugin/meta/main.yml
@@ -50,6 +50,11 @@ dependencies:
     tags:
       - kube-router
 
+  - role: network_plugin/ovn4nfv
+    when: kube_network_plugin == 'ovn4nfv'
+    tags:
+      - ovn4nfv
+
   - role: network_plugin/multus
     when: kube_network_plugin_multus
     tags:
diff --git a/roles/network_plugin/ovn4nfv/defaults/main.yml b/roles/network_plugin/ovn4nfv/defaults/main.yml
new file mode 100644
index 000000000..a7550753d
--- /dev/null
+++ b/roles/network_plugin/ovn4nfv/defaults/main.yml
@@ -0,0 +1,15 @@
+---
+ovn_control_plane_cpu_request: 500m
+ovn_control_plane_memory_request: 300Mi
+ovn_controller_cpu_request: 200m
+ovn_controller_memory_request: 300Mi
+ovn_controller_cpu_limit: 1000m
+ovn_controller_memory_limit: 800Mi
+ovn4nfv_cni_cpu_request: 100m
+ovn4nfv_cni_memory_request: 50Mi
+ovn4nfv_cni_cpu_limit: 100m
+ovn4nfv_cni_memory_limit: 50Mi
+nfn_agent_cpu_request: 100m
+nfn_agent_memory_request: 50Mi
+nfn_agent_cpu_limit: 100m
+nfn_agent_memory_limit: 50Mi
diff --git a/roles/network_plugin/ovn4nfv/tasks/main.yml b/roles/network_plugin/ovn4nfv/tasks/main.yml
new file mode 100644
index 000000000..32a4c2dc5
--- /dev/null
+++ b/roles/network_plugin/ovn4nfv/tasks/main.yml
@@ -0,0 +1,15 @@
+---
+- name: ovn4nfv | Label control-plane node
+  command: >-
+    {{ bin_dir }}/kubectl label --overwrite node {{ groups['kube-master'] | first }} ovn4nfv-k8s-plugin=ovn-control-plane
+  when:
+    - inventory_hostname == groups['kube-master'][0]
+
+- name: ovn4nfv | Create ovn4nfv-k8s manifests
+  template:
+    src: "{{ item.file }}.j2"
+    dest: "{{ kube_config_dir }}/{{ item.file }}"
+  with_items:
+    - {name: ovn-daemonset, file: ovn-daemonset.yml}
+    - {name: ovn4nfv-k8s-plugin, file: ovn4nfv-k8s-plugin.yml}
+  register: ovn4nfv_node_manifests
diff --git a/roles/network_plugin/ovn4nfv/templates/ovn-daemonset.yml.j2 b/roles/network_plugin/ovn4nfv/templates/ovn-daemonset.yml.j2
new file mode 100644
index 000000000..3cc1b4f87
--- /dev/null
+++ b/roles/network_plugin/ovn4nfv/templates/ovn-daemonset.yml.j2
@@ -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: {{ ovn4nfv_ovn_image_repo }}:{{ ovn4nfv_ovn_image_tag }}
+          imagePullPolicy: {{ k8s_image_pull_policy }}
+          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: {{ ovn_control_plane_cpu_request }}
+              memory: {{ ovn_control_plane_memory_request }}
+          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: {{ ovn4nfv_ovn_image_repo }}:{{ ovn4nfv_ovn_image_tag }}
+          imagePullPolicy: {{ k8s_image_pull_policy }}
+          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: {{ ovn_controller_cpu_request }}
+              memory: {{ ovn_controller_memory_request }}
+            limits:
+              cpu: {{ ovn_controller_cpu_limit }}
+              memory: {{ ovn_controller_memory_limit }}
+      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/roles/network_plugin/ovn4nfv/templates/ovn4nfv-k8s-plugin.yml.j2 b/roles/network_plugin/ovn4nfv/templates/ovn4nfv-k8s-plugin.yml.j2
new file mode 100644
index 000000000..76f0a010d
--- /dev/null
+++ b/roles/network_plugin/ovn4nfv/templates/ovn4nfv-k8s-plugin.yml.j2
@@ -0,0 +1,608 @@
+
+---
+
+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: "{{ kube_pods_subnet }}"
+  OVN_GATEWAYIP: "{{ kube_pods_subnet|ipaddr('net')|ipaddr(1) }}"
+
+---
+
+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: {{ ovn4nfv_k8s_plugin_image_repo }}:{{ ovn4nfv_k8s_plugin_image_tag }}
+          command: ["/usr/local/bin/entrypoint", "operator"]
+          imagePullPolicy: {{ k8s_image_pull_policy }}
+          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: {{ ovn4nfv_k8s_plugin_image_repo }}:{{ ovn4nfv_k8s_plugin_image_tag }}
+        command: ["/usr/local/bin/entrypoint", "cni"]
+        imagePullPolicy: {{ k8s_image_pull_policy }}
+        resources:
+          requests:
+            cpu: {{ ovn4nfv_cni_cpu_request }}
+            memory: {{ ovn4nfv_cni_memory_request }}
+          limits:
+            cpu: {{ ovn4nfv_cni_cpu_limit }}
+            memory: {{ ovn4nfv_cni_memory_limit }}
+        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: {{ ovn4nfv_k8s_plugin_image_repo }}:{{ ovn4nfv_k8s_plugin_image_tag }}
+        command: ["/usr/local/bin/entrypoint", "agent"]
+        imagePullPolicy: {{ k8s_image_pull_policy }}
+        resources:
+          requests:
+            cpu: {{ nfn_agent_cpu_request }}
+            memory: {{ nfn_agent_memory_request }}
+          limits:
+            cpu: {{ nfn_agent_cpu_limit }}
+            memory: {{ nfn_agent_memory_limit }}
+        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/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
diff --git a/tests/files/packet_ubuntu18-ovn4nfv.yml b/tests/files/packet_ubuntu18-ovn4nfv.yml
new file mode 100644
index 000000000..85af6baa5
--- /dev/null
+++ b/tests/files/packet_ubuntu18-ovn4nfv.yml
@@ -0,0 +1,9 @@
+---
+# Instance settings
+cloud_image: ubuntu-1804
+mode: default
+
+# Kubespray settings
+kube_network_plugin: ovn4nfv
+deploy_netchecker: true
+dns_min_replicas: 1
-- 
GitLab