[ovs-dev] [PATCH v3] ovn: Support for taas(tap-as-a-service) function

wang.qianyu at zte.com.cn wang.qianyu at zte.com.cn
Tue Sep 19 08:38:04 UTC 2017


To support taas function, this patch add two type of logica_switch_port, 
"mirror" and "taas". port with type "mirror" is used as inport for monitor 
flow in logica_switch, and port with type "taas" is used as outport for 
monitor flow in logica_switch.

The ovn-controller will make the relations of the ports in tap_service and 
tap_flow to mirror port and taas port.

Signed-off-by: wang qianyu <wang.qianyu at zte.com.cn>
---
 ovn/controller/binding.c        |   3 +
 ovn/controller/ovn-controller.c |   2 +
 ovn/controller/physical.c       | 168 +++++++++++++++++++++++-
 ovn/northd/ovn-northd.c         | 276 
+++++++++++++++++++++++++++++++++++++++-
 ovn/ovn-nb.xml                  |  57 +++++++++
 5 files changed, 502 insertions(+), 4 deletions(-)

diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index ca1d433..bbd391f 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -437,6 +437,9 @@ consider_local_datapath(struct controller_ctx *ctx,
          * for them. */
         sset_add(local_lports, binding_rec->logical_port);
         our_chassis = false;
+    } else if (!strcmp(binding_rec->type, "mirror")) {
+        add_local_datapath(ctx, binding_rec->datapath,
+                               false, local_datapaths);
     }
 
     if (ctx->ovnsb_idl_txn) {
diff --git a/ovn/controller/ovn-controller.c 
b/ovn/controller/ovn-controller.c
index e2c9652..0a148e4 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -150,6 +150,8 @@ update_sb_monitors(struct ovsdb_idl *ovnsb_idl,
     struct ovsdb_idl_condition mg = OVSDB_IDL_CONDITION_INIT(&mg);
     struct ovsdb_idl_condition dns = OVSDB_IDL_CONDITION_INIT(&dns);
     sbrec_port_binding_add_clause_type(&pb, OVSDB_F_EQ, "patch");
+    sbrec_port_binding_add_clause_type(&pb, OVSDB_F_EQ, "mirror");
+    sbrec_port_binding_add_clause_type(&pb, OVSDB_F_EQ, "taas");
     /* XXX: We can optimize this, if we find a way to only monitor
      * ports that have a Gateway_Chassis that point's to our own
      * chassis */
diff --git a/ovn/controller/physical.c b/ovn/controller/physical.c
index df71979..9070459 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -291,9 +291,83 @@ load_logical_ingress_metadata(const struct 
sbrec_port_binding *binding,
 }
 
 static void
+taas_port_handle(const struct sbrec_port_binding *binding,
+                 struct ofpbuf *ofpacts_p,
+                 struct hmap *flow_table,
+                 uint32_t dp_key,
+                 uint32_t port_key)
+{
+    ofp_port_t ofport = u16_to_ofp(simap_get(&localvif_to_ofport,
+                                              binding->logical_port));
+    if (!ofport) {
+        VLOG_INFO("can not find ofport of %s in this switch",
+            binding->logical_port);
+        return;
+    }
+    struct match match;
+
+    /* Table 33, priority 100.
+     * =======================
+     *
+     * Implements output to local hypervisor.  Each flow matches a
+     * logical output port on the local hypervisor, and resubmits to
+     * table 34.
+     */
+    match_init_catchall(&match);
+    ofpbuf_clear(ofpacts_p);
+    match_set_metadata(&match, htonll(dp_key));
+    match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
+
+    /* Resubmit to table 34. */
+    put_resubmit(OFTABLE_CHECK_LOOPBACK, ofpacts_p);
+    ofctrl_add_flow(flow_table, OFTABLE_LOCAL_OUTPUT, 100, 0,
+                    &match, ofpacts_p);
+
+    /* Table 65, Priority 100.
+     * =======================
+     *
+     * Deliver the packet to the local vif. */
+    match_init_catchall(&match);
+    ofpbuf_clear(ofpacts_p);
+    match_set_metadata(&match, htonll(dp_key));
+    match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, port_key);
+    ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
+    ofctrl_add_flow(flow_table, OFTABLE_LOG_TO_PHY, 100, 0,
+                    &match, ofpacts_p);
+}
+
+struct mirror_port {
+    struct sbrec_port_binding *port;
+    struct ovs_list list;
+};
+
+static void
+get_mports_from_lport(struct shash *mports,
+                      char *logical_port_name,
+                      struct ovs_list *mport_list)
+{
+    struct shash_node *node, *next_node;
+    SHASH_FOR_EACH_SAFE (node, next_node, mports) {
+        struct sbrec_port_binding *binding = node->data;
+        const char *source_port_name = smap_get(&binding->options,
+                                                "source-port");
+        if (!source_port_name) {
+            continue;
+        }
+        if (strcmp(source_port_name, logical_port_name)) {
+            continue;
+        }
+        struct mirror_port *mport = xzalloc(sizeof *mport);
+        mport->port = binding;
+        ovs_list_push_back(mport_list, &mport->list);
+     }
+}
+
+static void
 consider_port_binding(struct controller_ctx *ctx,
                       enum mf_field_id mff_ovn_geneve,
                       const struct simap *ct_zones,
+                      struct shash *mports,
                       const struct chassis_index *chassis_index,
                       struct sset *active_tunnels,
                       struct hmap *local_datapaths,
@@ -360,6 +434,13 @@ consider_port_binding(struct controller_ctx *ctx,
         return;
     }
 
+    if (!strcmp(binding->type, "taas") &&
+        binding->chassis == chassis) {
+        taas_port_handle(binding, ofpacts_p, flow_table,
+                     dp_key, port_key);
+        return;
+    }
+
     struct ovs_list *gateway_chassis
         = gateway_chassis_get_ordered(binding, chassis_index);
 
@@ -531,13 +612,44 @@ consider_port_binding(struct controller_ctx *ctx,
         ofpbuf_clear(ofpacts_p);
         match_init_catchall(&match);
         match_set_in_port(&match, ofport);
+        if (tag || !strcmp(binding->type, "localnet")
+            || !strcmp(binding->type, "l2gateway")) {
+            match_set_dl_vlan(&match, htons(tag));
+        }
+
+        struct ovs_list local_mports;
+        ovs_list_init(&local_mports);
+        get_mports_from_lport(mports, binding->logical_port, 
&local_mports);
+        struct mirror_port *mp, *next;
+         /* add mirror action of flow mirrored port in table 0 */
+        LIST_FOR_EACH_SAFE (mp, next, list, &local_mports) {
+            const struct sbrec_port_binding *mirror_port = mp->port;
+            if (!mirror_port) {
+                continue;
+            }
+            const char *direction = smap_get(&mirror_port->options,
+                                         "direction");
+            if (direction && (!strcmp(direction, "from-port") ||
+                 !strcmp(direction, "both"))) {
+                size_t clone_ofs = ofpacts_p->size;
+                struct ofpact_nest *clone = ofpact_put_CLONE(ofpacts_p);
+                put_load(mirror_port->datapath->tunnel_key, 
MFF_LOG_DATAPATH,
+                    0, 64, ofpacts_p);
+                put_load(mirror_port->tunnel_key, MFF_LOG_INPORT, 0, 32,
+                    ofpacts_p);
+                put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts_p);
+
+                clone = ofpbuf_at_assert(ofpacts_p, clone_ofs, sizeof 
*clone);
+                ofpacts_p->header = clone;
+                ofpact_finish_CLONE(ofpacts_p, &clone);
+            }
+        }
 
         /* Match a VLAN tag and strip it, including stripping priority 
tags
          * (e.g. VLAN ID 0).  In the latter case we'll add a second flow
          * for frames that lack any 802.1Q header later. */
         if (tag || !strcmp(binding->type, "localnet")
             || !strcmp(binding->type, "l2gateway")) {
-            match_set_dl_vlan(&match, htons(tag));
             if (nested_container) {
                 /* When a packet comes from a container sitting behind a
                  * parent_port, we should let it loopback to other 
containers
@@ -586,6 +698,49 @@ consider_port_binding(struct controller_ctx *ctx,
             vlan_vid->push_vlan_if_needed = true;
         }
         ofpact_put_OUTPUT(ofpacts_p)->port = ofport;
+
+        /* add mirror action of flow mirrored port in table 65 */
+        LIST_FOR_EACH_SAFE (mp, next, list, &local_mports) {
+            const struct sbrec_port_binding *mirror_port = mp->port;
+            if (!mirror_port) {
+                continue;
+            }
+            const char *direction = smap_get(&mirror_port->options,
+                                         "direction");
+            if (direction && (!strcmp(direction, "to-port") ||
+                 !strcmp(direction, "both"))) {
+                size_t clone_ofs = ofpacts_p->size;
+                struct ofpact_nest *clone = ofpact_put_CLONE(ofpacts_p);
+                ofpact_put_CT_CLEAR(ofpacts_p);
+                put_load(0, MFF_LOG_DNAT_ZONE, 0, 32, ofpacts_p);
+                put_load(0, MFF_LOG_SNAT_ZONE, 0, 32, ofpacts_p);
+                put_load(0, MFF_LOG_CT_ZONE, 0, 32, ofpacts_p);
+                put_load(0, MFF_LOG_FLAGS, 0, 32, ofpacts_p);
+                put_load(0, MFF_LOG_OUTPORT, 0, 32, ofpacts_p);
+                for (int i = 0; i < MFF_N_LOG_REGS; i++) {
+                    put_load(0, MFF_LOG_REG0 + i, 0, 32, ofpacts_p);
+                }
+
+                /* taas port may have the same chassis as the src port,
+                 * so here need clear inport */
+                put_load(0, MFF_IN_PORT, 0, 16, ofpacts_p);
+                put_load(mirror_port->datapath->tunnel_key, 
MFF_LOG_DATAPATH,
+                    0, 64, ofpacts_p);
+                put_load(mirror_port->tunnel_key, MFF_LOG_INPORT,
+                    0, 32, ofpacts_p);
+                put_resubmit(OFTABLE_LOG_INGRESS_PIPELINE, ofpacts_p);
+
+                clone = ofpbuf_at_assert(ofpacts_p, clone_ofs, sizeof 
*clone);
+                ofpacts_p->header = clone;
+                ofpact_finish_CLONE(ofpacts_p, &clone);
+            }
+        }
+
+        LIST_FOR_EACH_SAFE (mp, next, list, &local_mports) {
+            ovs_list_remove(&mp->list);
+            free(mp);
+        }
+
         if (tag) {
             /* Revert the tag added to the packets headed to containers
              * in the previous step. If we don't do this, the packets
@@ -983,12 +1138,21 @@ physical_run(struct controller_ctx *ctx, enum 
mf_field_id mff_ovn_geneve,
     /* Set up flows in table 0 for physical-to-logical translation and in 
table
      * 64 for logical-to-physical translation. */
     const struct sbrec_port_binding *binding;
+
+    struct shash mports = SHASH_INITIALIZER(&mports);
+    SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
+        if (!strcmp(binding->type, "mirror")) {
+            shash_add(&mports, binding->logical_port, binding);
+        }
+    }
+
     SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
-        consider_port_binding(ctx, mff_ovn_geneve, ct_zones,
+        consider_port_binding(ctx, mff_ovn_geneve, ct_zones, &mports,
                               chassis_index, active_tunnels,
                               local_datapaths, binding, chassis,
                               &ofpacts, flow_table);
     }
+    shash_destroy(&mports);
 
     /* Handle output to multicast groups, in tables 32 and 33. */
     const struct sbrec_multicast_group *mc;
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 49e4ac3..55b4752 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -172,6 +172,8 @@ enum ovn_stage {
  * logical router dropping packets with source IP address equals
  * one of the logical router's own IP addresses. */
 #define REGBIT_EGRESS_LOOPBACK  "reg9[1]"
+/* Indicate that a packet is cloned. */
+#define REGBIT_CLONED_FLOW  "reg10[4]"
 
 /* Returns an "enum ovn_stage" built from the arguments. */
 static enum ovn_stage
@@ -1887,8 +1889,9 @@ ovn_port_update_sbrec(struct northd_context *ctx,
                     /* If we found the chassis, and the gw chassis on 
record
                      * differs from what we expect go ahead and update */
                     if (op->sb->n_gateway_chassis != 1
-                        || 
strcmp(op->sb->gateway_chassis[0]->chassis->name,
-                                  chassis->name)
+                        || (op->sb->gateway_chassis[0]->chassis &&
+ strcmp(op->sb->gateway_chassis[0]->chassis->name,
+                                  chassis->name))
                         || op->sb->gateway_chassis[0]->priority != 0) {
                         /* Construct a single Gateway_Chassis entry on 
the
                          * Port_Binding attached to the redirect_chassis
@@ -3478,6 +3481,237 @@ build_stateful(struct ovn_datapath *od, struct 
hmap *lflows)
 }
 
 static void
+build_mirror_flows(struct ovn_port *op,
+                   struct hmap *ports,
+                   struct hmap *lflows)
+{
+    struct ds match = DS_EMPTY_INITIALIZER;
+    struct ds actions = DS_EMPTY_INITIALIZER;
+
+    /* Logical switch ingress table 15: L2_LKUP. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    /* build mirror flows */
+    const char *taas_port_name =
+          smap_get(&op->nbsp->options, "taas-port");
+    if (!taas_port_name) {
+        return;
+    }
+    struct ovn_port *taas_port =
+        ovn_port_find(ports, taas_port_name);
+    if (!taas_port) {
+        return;
+    }
+    if (taas_port->od != op->od) {
+        VLOG_INFO(" in valid configuration, inport: %s and outport %s is 
"
+            "not in same logical switch", op->nbsp->name, 
taas_port_name);
+        return;
+    }
+
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_format(&actions, "outport = %s; output;", 
taas_port->json_key);
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 65535,
+          ds_cstr(&match), ds_cstr(&actions));
+
+
+    /* Logical switch ingress table 0: PORT_SEC_L2. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 1: PORT_SEC_IP. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_IP, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 2: PORT_SEC_ND. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 3: PRE_ACL. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PRE_ACL, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 4: PRE_LB. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PRE_LB, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 5: PRE_STATEFUL. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PRE_STATEFUL, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 6: ACL. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ACL, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 7: QOS_MARK. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_QOS_MARK, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 8: LB. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_LB, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 9: STATEFUL. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_STATEFUL, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 10: ARP_ND_RSP. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_ND_RSP, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 11: DHCP_OPTIONS. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_OPTIONS, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 12: DHCP_RESPONSE. (priority 65535) 
*/
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+     /* Logical switch ingress table 13: DNS_LOOKUP. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DNS_LOOKUP, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch ingress table 14: DNS_RESPONSE. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "inport == %s", op->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DNS_RESPONSE, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch egress table 0: PRE_LB. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PRE_LB, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch egress table 1: PRE_ACL. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PRE_ACL, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch egress table 2: PRE_STATEFUL. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PRE_STATEFUL, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch egress table 3: LB. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_LB, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+     /* Logical switch egress table 4: ACL. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_ACL, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch egress table 5: QOS_MARK. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_QOS_MARK, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+     /* Logical switch egress table 6: STATEFUL. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_STATEFUL, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+    /* Logical switch egress table 7: PORT_SEC_IP. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "next;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_IP, 65535,
+              ds_cstr(&match), ds_cstr(&actions));
+
+     /* Logical switch egress table 8: PORT_SEC_L2. (priority 65535) */
+    ds_clear(&match);
+    ds_clear(&actions);
+    ds_put_format(&match, "outport == %s", taas_port->json_key);
+    ds_put_cstr(&actions, "output;");
+    ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 65535,
+                  ds_cstr(&match), ds_cstr(&actions));
+
+    ds_destroy(&match);
+    ds_destroy(&actions);
+}
+static void
 build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
                     struct hmap *lflows, struct hmap *mcgroups)
 {
@@ -3533,6 +3767,20 @@ build_lswitch_flows(struct hmap *datapaths, struct 
hmap *ports,
         if (!op->nbsp) {
             continue;
         }
+        if (!strcmp(op->nbsp->type, "taas")) {
+            /* drop all packet receive from taas port */
+            ds_clear(&match);
+            ds_clear(&actions);
+            ds_put_format(&match, "inport == %s", op->json_key);
+            ds_put_cstr(&actions, "drop;");
+            ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 65535,
+                      ds_cstr(&match), ds_cstr(&actions));
+            continue;
+        }
+        if (!strcmp(op->nbsp->type, "mirror")) {
+            build_mirror_flows(op, ports, lflows);
+            continue;
+        }
 
         if (!lsp_is_enabled(op->nbsp)) {
             /* Drop packets from disabled logical ports (since logical 
flow
@@ -3578,6 +3826,10 @@ build_lswitch_flows(struct hmap *datapaths, struct 
hmap *ports,
         if (!op->nbsp) {
             continue;
         }
+        if (!strcmp(op->nbsp->type, "taas") ||
+            !strcmp(op->nbsp->type, "mirror")) {
+            continue;
+        }
 
         if ((!strcmp(op->nbsp->type, "localnet")) ||
             (!strcmp(op->nbsp->type, "vtep"))) {
@@ -3594,6 +3846,10 @@ build_lswitch_flows(struct hmap *datapaths, struct 
hmap *ports,
         if (!op->nbsp) {
             continue;
         }
+        if (!strcmp(op->nbsp->type, "taas") ||
+            !strcmp(op->nbsp->type, "mirror")) {
+            continue;
+        }
 
         /*
          * Add ARP/ND reply flows if either the
@@ -3699,6 +3955,10 @@ build_lswitch_flows(struct hmap *datapaths, struct 
hmap *ports,
         if (!op->nbsp) {
            continue;
         }
+        if (!strcmp(op->nbsp->type, "taas") ||
+            !strcmp(op->nbsp->type, "mirror")) {
+            continue;
+        }
 
         if (!lsp_is_enabled(op->nbsp) || !strcmp(op->nbsp->type, 
"router")) {
             /* Don't add the DHCP flows if the port is not enabled or if 
the
@@ -3849,6 +4109,10 @@ build_lswitch_flows(struct hmap *datapaths, struct 
hmap *ports,
         if (!op->nbsp) {
             continue;
         }
+        if (!strcmp(op->nbsp->type, "taas") ||
+            !strcmp(op->nbsp->type, "mirror")) {
+            continue;
+        }
 
         if (lsp_is_enabled(op->nbsp)) {
             ovn_multicast_add(mcgroups, &mc_flood, op);
@@ -3868,6 +4132,10 @@ build_lswitch_flows(struct hmap *datapaths, struct 
hmap *ports,
         if (!op->nbsp) {
             continue;
         }
+        if (!strcmp(op->nbsp->type, "taas") ||
+            !strcmp(op->nbsp->type, "mirror")) {
+            continue;
+        }
 
         for (size_t i = 0; i < op->nbsp->n_addresses; i++) {
             /* Addresses are owned by the logical port.
@@ -4001,6 +4269,10 @@ build_lswitch_flows(struct hmap *datapaths, struct 
hmap *ports,
         if (!op->nbsp) {
             continue;
         }
+        if (!strcmp(op->nbsp->type, "taas") ||
+            !strcmp(op->nbsp->type, "mirror")) {
+            continue;
+        }
 
         ds_clear(&match);
         ds_put_format(&match, "outport == %s", op->json_key);
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index 9869d7e..20593fa 100644
--- a/ovn/ovn-nb.xml
+++ b/ovn/ovn-nb.xml
@@ -301,6 +301,20 @@
           <dd>
             A port to a logical switch on a VTEP gateway.
           </dd>
+
+          <dt><code>mirror</code></dt>
+          <dd>
+            A port indicate the inport of mirrored flows. The user need 
to
+            create this port in the logical_switch. This port should one 
to
+            one correspondence with the the tap_flows
+          </dd>
+
+          <dt><code>taas</code></dt>
+          <dd>
+            A port indicate the outport of mirrored flows. The user need 
to
+            set the type of tap_service port to taas when create a
+            taas_service.
+          </dd>
         </dl>
       </column>
     </group>
@@ -454,6 +468,49 @@
           interface, in bits.
         </column>
       </group>
+
+      <group title="Options for mirror ports">
+        <p>
+          These options apply when <ref column="type"/> is
+          <code>mirror</code>.
+        </p>
+
+        <column name="options" key="source-port">
+          Required.  The <ref column="name"/> of the <ref
+          table="Logical_switch_Port"/> that indicates where the
+          cloned flows come from.
+        </column>
+
+        <column name="options" key="taas-port">
+          Required.  The <ref column="name"/> of the <ref
+          table="Logical_switch_Port"/> with type taas.
+        </column>
+
+        <column name="options" key="direction">
+          <p>
+            This option indicates whitch direction(from-port/to-port/all) 
of
+            packet will be cloned to the taas-port. The directions are 
defined
+            as follow:
+          </p>
+          <dl>
+            <dt><code>from-port</code></dt>
+            <dd>
+              The packets from this port will be cloned to specified 
mirror
+              port.
+            </dd>
+            <dt><code>to-port</code></dt>
+            <dd>
+              The packets to this port will be cloned to specified mirror
+              port.
+            </dd>
+            <dt><code>both</code></dt>
+            <dd>
+              The packets both from and to this port will be cloned to
+              specified mirror port.
+            </dd>
+          </dl>
+        </column>
+      </group>
     </group>
 
     <group title="Containers">
-- 
1.8.3.1


More information about the dev mailing list