[ovs-dev] [PATCH 2/5] ovn: add sfc tables to northbound schema

Flavio Fernandes flavio at flaviof.com
Sun Nov 6 03:11:28 UTC 2016


Reported-at: http://openvswitch.org/pipermail/discuss/2016-March/020628.html
Reported-at:  http://openvswitch.org/pipermail/discuss/2016-May/thread.html#21201
Co-authored-by: John McDowall <jmcdowall at paloaltonetworks.com>
Signed-off-by: Flavio Fernandes <flavio at flaviof.com>
---
 ovn/ovn-architecture.7.xml | 185 +++++++++++++++++++++++++++++++++++++++++++++
 ovn/ovn-nb.ovsschema       |  56 +++++++++++++-
 ovn/ovn-nb.xml             | 119 +++++++++++++++++++++++++++++
 3 files changed, 359 insertions(+), 1 deletion(-)

diff --git a/ovn/ovn-architecture.7.xml b/ovn/ovn-architecture.7.xml
index 95cba98..681d0c3 100644
--- a/ovn/ovn-architecture.7.xml
+++ b/ovn/ovn-architecture.7.xml
@@ -381,6 +381,13 @@
       switch.  Logical switches and routers are both implemented as logical
       datapaths.
     </li>
+
+    <li>
+      <dfn>Logical services</dfn> are logical references to virtual network functions
+      (VNF). Adding a logical service requires adding steering rules to the OVN Northbound
+      database. These are the only rules necessary to implement traffic steering for VNFs.
+      The section below "<code>Life Cycle of an inserted VNF</code>" provides more details.
+    </li>
   </ul>
 
   <h2>Life Cycle of a VIF</h2>
@@ -536,6 +543,184 @@
     </li>
   </ol>
 
+ <h2>Life Cycle of an inserted Virtual Network Function (VNF)</h2>
+
+ <p>
+   OVN provides an abstraction to enable the insertion of an arbitrary virtual network
+   function (VNF) into the path of traffic to and from an application. A VNF is different
+   from an application VM in that it acts on traffic between applications, and im most
+   cases does not terminiate a flow. Proxy functions are an exception as they terminate the
+   flow from the src and create a new flow to the dst. Examples of VNF's are security functions,
+   load balancing, and traffic enhancement services, this is not a complete list.
+ </p>
+ <p>
+   The requirements on the VNF to be inserted are minimal, it must
+   act as a <code>bump in the wire (BITW)</code> and can have one or two virtual network
+   ports for traffic. If it has two network ports traffic is directed into one and out the other,
+   if it has only one port, then traffic is bi-directional. The requirement for the VNF to act as
+   a BITW removes the need for the VNF to participate in L3/L2 networking which provides
+   improved agility and reduces the coupling between OVN and the VNF.
+ </p>
+ <p>
+   The service insertion is implemented by adding 4 new flow rules into the ovn-nb database for
+   each VNF inserted. The rules are added into the last table in the ingress path (L2_LKUP).
+   The service insertion rules have a higher priority than the standard forwarding rules.
+   This means that they override the existing forwarding rules. There are four
+   new rules added for each insertion. Two ingress and two egress, The first ingress
+   rule sends all traffic destined for the application into the VNF ingress port and the
+   second rule takes all traffic destined to the application from the VNF egress port
+   to the application, the priorities are such that the second rule is always checked
+   first. In the egress direction the rules are similar if the traffic is from the
+   application it is sent to the VNF egress port and if if is from the application
+   and is from the VNF ingress port it is delivered to the destination.
+   <!-- Should this be a new table or is it a naturally part of the L2 lookup table ? -->
+ </p>
+ <p>
+   The steps in this example refer to the details of the OVN Northbound database schema.
+   There is a new table in the OVN Northbound database to support service insertion
+   called <code>Services</code> this contains the required information for each new
+   service inserted. The same service can be used for multiple applications, as
+   there is typically a n:1 relationship between applications and VNFs. A
+   single VNF may be part of several service insertions, but each one is logically
+   separate.
+ </p>
+ <p>
+   The steps in this example refer often to details of the OVN and OVN
+   Northbound database schemas.  Please see <code>ovn-sb</code>(5) and
+   <code>ovn-nb</code>(5), respectively, for the full story on these
+   databases. The ovn-nb database has specific schema enhancements for the service
+   insertion function. The ovn-sb database has no schema changes for the
+   service insertion function.
+ </p>
+ <p>
+   The following steps are an overview to inserting a new VNF into the traffic path.
+   The sections below go into each step in more detail.
+ </p>
+ <ol>
+   <li>
+     The service insertion lifecycle begins when a CMS administrator creates a new
+     virtual network function <code>(VNF)</code> using the CMS user
+     interface or API. The CMS administrator creates the logical ports (ingress and egress)
+     for the VNF. If the CMS is Openstack this will create a reusable port-pair defining the
+     interface to the VNF. There is also typically a seperate management port for the VNF,
+     but that is not relevant to the service insertion workflow. A single VNF can
+     participate with several applications, either as a security VM, protecting multiple
+     applications or as a load balancer VM, distributing load across multiple applications.
+   </li>
+
+   <li>
+     The next step in the life cycle occurs when a CMS administrator creates a new application
+     with a VIF using the CMS user interface or API and adds it to a switch (one
+     implemented by OVN as a logical switch). Alternatively an already running application could
+     be used.
+
+     The CMS can now attach the port pair to the VIF by defining the logical port in the
+     service function classifier. This will direct traffic to the VIF to go through
+     the VNF, applying the rules discussed earlier.
+   </li>
+
+   <li>
+     While within CMS the service insertion may be broken down into multiple reusable steps
+     (as is the case with Openstack). Within OVN the creating of a new service insertion
+     is treated as an atomic operation. This enables the easy atomic insertion and deletion of
+     service insertions. This is important as it is envisioned that the number of serivce
+     insertions can easily number in the hundreds, all with separate lifecycles. For each new
+     service insertion operation a new row is added to the OVN Northbound Database. The new row is
+     only added to the ovn-nb when the VNF, application and network are enabled by the CMS.
+
+     Once the serivce insertion is applied to the ovn-nb database, the ovn-nb controller will be
+     notified of a change and the rules will be pushed down to the specific OVS instances, using
+     the existing OVN mechanisms. It is important to note here that the logical abstraction of
+     OVN enables service insertion with minimal changes.
+   </li>
+
+   <li>
+     When the application VM shuts down the classification rule should be removed, however as
+     no traffic will be destinated to the application there would be no issues. If the VM is
+     being moved and the new application VM port is used to update the service then the change
+     would be detected and the rules pushed down.
+   </li>
+   <li>
+     A VNF can be removed at any time and traffic flows will revert to the pre-VNF traffic
+     paths if it is removed from the ovn-nb database. OVN must detect that the VNF has been
+     shut-off as it must remove all the rules that are attached to that VNF. Otherwise
+     traffic loss will occur, if a failure in a VNF occurs that is not detected.
+  </li>
+
+  <li>
+    On every hypervisor, <code>ovn-controller</code> receives the
+    <code>Logical_Service</code> table updates that <code>ovn-northd</code> made
+    in the previous step.  As long as the VM that owns the VIF is powered
+    off, <code>ovn-controller</code> cannot do much; it cannot, for example,
+    arrange to send packets to or receive packets from the VIF, because the
+    VIF does not actually exist anywhere. In addition the VNF cannot be inserted
+    into the traffic path as it will have no source to forward traffic too.
+    <!-- If there is no VM then traffic cannot be sent to it therefore having the
+    rules inserted is probably not an issue? -->
+  </li>
+
+  <li>
+    Some CMS systems, including OpenStack, fully start a VM only when its
+    networking is ready.  To support this, <code>ovn-northd</code> notices
+    the <code>chassis</code> column updated for the row in
+    <code>Binding</code> table and pushes this upward by updating the
+    <ref column="up" table="Logical_Port" db="OVN_NB"/> column in the OVN
+    Northbound database's <ref table="Logical_Port" db="OVN_NB"/> table to
+    indicate that the VIF is now up.  The CMS, if it uses this feature, can
+    then react by allowing the VM's execution to proceed.
+
+    Traffic now flows into and out of the VM that has a VNF inserted in its
+    datapath. The rules are applied to direct traffic to the VNF on the way
+    into the VM and on the way out of the VM.
+  </li>
+
+  <!-- Need a section on having multiple VM's using the same VNF
+    ( physcially or logically ). Different rule sets -->
+  <!-- Need a section on distributed cases - one section for each -->
+  <li>
+    On every hypervisor but the one where the VIF resides,
+    <code>ovn-controller</code> notices the completely populated row in the
+    <code>Binding</code> table.  This provides <code>ovn-controller</code>
+    the physical location of the logical port, so each instance updates the
+    OpenFlow tables of its switch (based on logical datapath flows in the OVN
+    DB <code>Logical_Flow</code> table) so that packets to and from the VIF
+    can be properly handled via tunnels.
+  </li>
+  <!-- Current implementation is open on delete, i.e. when the VNF is removed
+    the datapath behaviour reverts to the pre-existing paths. Does this make sense?
+    - could argue that close on delete should be an option ? -->
+
+  <li>
+    Eventually, a user removes the inserted service function from the ovn nb
+    database. The rules are then updated in the southbound database and pushed
+    down to the relevant ovs. No other SIF is impacted as the row in the ovn nb
+    is independant of all the other SIF.
+    <!-- This is really important in the case where many SIF are being added
+      and removed. Without both the independance of the enteries confusion would
+      exist. Also for debugging - possible to remove/add individual VNF's to
+      determine potentail problems. -->
+  </li>
+
+  <li>
+    The CMS plugin removes the SIF from the OVN Northbound database,
+    by deleting its row in the <code>Logical_Service</code> table.
+  </li>
+
+  <li>
+    <code>ovn-northd</code> receives the OVN Northbound update and in turn
+    updates the OVN Southbound database accordingly, by removing or updating
+    the rows from the OVN Southbound database <code>Logical_Service</code> table.
+  </li>
+
+  <li>
+    On every hypervisor, <code>ovn-controller</code> receives the
+    <code>Logical_Service</code> table updates that <code>ovn-northd</code> made
+    in the previous step.  <code>ovn-controller</code> updates OpenFlow
+    tables to reflect the update. The datapath for the VM will now revert to
+    paths that existed before the VNF was inserted into the data path.
+  </li>
+</ol>
+
   <h2>Life Cycle of a Container Interface Inside a VM</h2>
 
   <p>
diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema
index ded6316..d8d05b8 100644
--- a/ovn/ovn-nb.ovsschema
+++ b/ovn/ovn-nb.ovsschema
@@ -1,7 +1,7 @@
 {
     "name": "OVN_Northbound",
     "version": "5.4.2",
-    "cksum": "2998303999 11681",
+    "cksum": "1524033812 14801",
     "tables": {
         "NB_Global": {
             "columns": {
@@ -21,6 +21,16 @@
                                            "refType": "strong"},
                                    "min": 0,
                                    "max": "unlimited"}},
+                "port_chains":  {"type": {"key": {"type": "uuid",
+                                                  "refTable": "Logical_Port_Chain",
+                                                  "refType": "strong"},
+                                          "min": 0,
+                                          "max": "unlimited"}},
+                "port_pairs":  {"type": {"key": {"type": "uuid",
+                                                 "refTable": "Logical_Port_Pair",
+                                                 "refType": "strong"},
+                                         "min": 0,
+                                         "max": "unlimited"}},
                 "acls": {"type": {"key": {"type": "uuid",
                                           "refTable": "ACL",
                                           "refType": "strong"},
@@ -89,6 +99,50 @@
                              "min": 0, "max": "unlimited"}}},
             "indexes": [["name"]],
             "isRoot": false},
+        "Logical_Port_Chain": {
+            "columns": {
+                "name": {"type": "string"},
+                "port_pair_groups":  {"type": {"key": {"type": "uuid",
+                                                       "refTable": "Logical_Port_Pair_Group",
+                                                       "refType": "strong"},
+                                               "min": 0, "max": "unlimited"}},
+                "last_hop_port": {"type": {"key": {"type": "uuid",
+                                                   "refTable": "Logical_Switch_Port",
+                                                   "refType": "strong"},
+                                           "min": 0, "max": 1}},
+                "external_ids": {
+                    "type": {"key": "string", "value": "string",
+                             "min": 0, "max": "unlimited"}}},
+            "isRoot": false},
+        "Logical_Port_Pair_Group": {
+            "columns": {
+                "name": {"type": "string"},
+                "port_pairs":  {"type": {"key": {"type": "uuid",
+                                                 "refTable": "Logical_Port_Pair",
+                                                 "refType": "strong"},
+                                         "min": 0, "max": "unlimited"}},
+                "external_ids": {
+                    "type": {"key": "string", "value": "string",
+                             "min": 0, "max": "unlimited"}},
+                "sortkey": {"type": {"key": {"type": "integer"},
+                                     "min": 0, "max": 1}}
+            },
+            "isRoot": false},
+        "Logical_Port_Pair": {
+            "columns": {
+                "name": {"type": "string"},
+                "outport": {"type": {"key": {"type": "uuid",
+                                             "refTable": "Logical_Switch_Port",
+                                             "refType": "strong"},
+                                     "min": 0, "max": 1}},
+                "inport": {"type": {"key": {"type": "uuid",
+                                            "refTable": "Logical_Switch_Port",
+                                            "refType": "strong"},
+                                    "min": 0, "max": 1}},
+                "external_ids": {
+                    "type": {"key": "string", "value": "string",
+                             "min": 0, "max": "unlimited"}}},
+            "isRoot": false},
         "Address_Set": {
             "columns": {
                 "name": {"type": "string"},
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index f2f6f74..ccbbbba 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -110,6 +110,27 @@
       </p>
     </column>
 
+    <column name="port_chains">
+      <p>
+        The logical port-chains connected to the logical switch.
+      </p>
+
+      <p>
+        It is an error for multiple logical switches to include the same
+        logical port.
+      </p>
+    </column>
+
+    <column name="port_pairs">
+      <p>
+        The logical chains that define the service path.
+      </p>
+
+      <p>
+        Logical chains cannot currently cross logical switch boundaries.
+      </p>
+    </column>
+
     <column name="load_balancer">
       Load balance a virtual ipv4 address to a set of logical port endpoint
       ipv4 addresses.
@@ -145,6 +166,104 @@
     </group>
   </table>
 
+  <table name="Logical_Port_Chain" title="Logical port chain">
+    <p>
+      Each row represents one logical port chain
+    </p>
+
+    <column name="name">
+      <p>
+        A name for the logical chain.  This name has no special meaning or purpose
+        other than to provide convenience for human interaction with the ovn-nb
+        database.  There is no requirement for the name to be unique.  The
+        logical chains's UUID should be used as the unique identifier.
+      </p>
+    </column>
+
+    <column name="port_pair_groups">
+      <p>
+        The logical list of port pairs that the flow goes through.
+      </p>
+
+      <p>
+        It is an error for a port pair group to be empty.
+      </p>
+    </column>
+
+    <column name="last_hop_port">
+      The <ref table="Logical_Switch_Port"/> to be used once packet reaches the end
+      of the chain.
+    </column>
+
+    <group title="Common Columns">
+      <column name="external_ids">
+        See <em>External IDs</em> at the beginning of this document.
+      </column>
+    </group>
+  </table>
+
+  <table name="Logical_Port_Pair_Group" title="logical port pair groups">
+    <p>
+      An ordered port pair list
+    </p>
+
+    <column name="name">
+      <p>
+        Logical port pair group name
+      </p>
+    </column>
+
+    <column name="port_pairs">
+      <p>
+        port pair for this group
+      </p>
+    </column>
+
+    <column name="sortkey">
+      <p>
+        An integer used for ordering instances of <ref table="Logical_Port_Pair_Group"/>
+        in the <ref column="port_pairs" table="Logical_Port_Chain"/> column
+        of <ref table="Logical_Port_Chain"/>.
+      </p>
+    </column>
+
+    <group title="Common Columns">
+      <column name="external_ids">
+        See <em>External IDs</em> at the beginning of this document.
+      </column>
+    </group>
+  </table>
+
+  <table name="Logical_Port_Pair" title="logical port pairs">
+    <p>
+      Ports pairs defining the service
+    </p>
+
+    <column name="name">
+      <p>
+        Logical port pair
+      </p>
+    </column>
+
+    <column name="outport">
+      <p>
+        Out logical port for this port pair. Can be the same value as inport.
+      </p>
+    </column>
+
+    <column name="inport">
+      <p>
+        In logical port for this port pair.
+      </p>
+    </column>
+
+    <group title="Common Columns">
+      <column name="external_ids">
+        See <em>External IDs</em> at the beginning of this document.
+      </column>
+    </group>
+  </table>
+
   <table name="Logical_Switch_Port" title="L2 logical switch port">
     <p>
       A port within an L2 logical switch.
-- 
2.7.4




More information about the dev mailing list