[ovs-dev] [PATCH v2] ovn: Support for taas(tap-as-a-service) function
wang.qianyu at zte.com.cn
wang.qianyu at zte.com.cn
Tue Aug 15 08:28:15 UTC 2017
Taas was designed to provide tenants and service providers a means of
monitoring the traffic flowing in their Neutron provisioned virtual
networks. It is useful for network trouble-shooting, security and
analytics. The taas presentations could be found from
https://github.com/openstack/tap-as-a-service/blob/master/doc/source/presentations.rst
, and the api reference could be found from
https://github.com/openstack/tap-as-a-service/blob/master/API_REFERENCE.rst
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 | 12 ++
ovn/controller/ovn-controller.c | 2 +
ovn/controller/physical.c | 185 +++++++++++++++++++++-
ovn/lib/logical-fields.c | 4 +
ovn/lib/logical-fields.h | 4 +
ovn/northd/ovn-northd.c | 329
++++++++++++++++++++++++++++++++++++++++
ovn/ovn-nb.xml | 69 +++++++++
7 files changed, 603 insertions(+), 2 deletions(-)
diff --git a/ovn/controller/binding.c b/ovn/controller/binding.c
index 32309e9..fc74ea0 100644
--- a/ovn/controller/binding.c
+++ b/ovn/controller/binding.c
@@ -437,6 +437,18 @@ 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);
+ } else if (!strcmp(binding_rec->type, "taas")) {
+ const char *target_port_name = smap_get(&binding_rec->options,
+ "target-port");
+ if (target_port_name &&
+ sset_contains(local_lports, target_port_name)) {
+ our_chassis = true;
+ }
+ 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..7b55b04 100644
--- a/ovn/controller/physical.c
+++ b/ovn/controller/physical.c
@@ -291,9 +291,100 @@ load_logical_ingress_metadata(const struct
sbrec_port_binding *binding,
}
static void
+taas_port_handle(struct controller_ctx *ctx,
+ const struct sbrec_port_binding *binding,
+ struct ofpbuf *ofpacts_p,
+ struct hmap *flow_table,
+ uint32_t dp_key,
+ uint32_t port_key)
+{
+ const char *target_port_name = smap_get(&binding->options,
+ "target-port");
+ if (!target_port_name) {
+ VLOG_INFO("taas port %s not configure target-port",
+ binding->logical_port);
+ return;
+ }
+ const struct sbrec_port_binding *target_port = lport_lookup_by_name(
+ ctx->ovnsb_idl, target_port_name);
+ if (!target_port) {
+ VLOG_INFO("can not find target port %s in this switch",
+ target_port_name);
+ return;
+ }
+
+ ofp_port_t ofport = u16_to_ofp(simap_get(&localvif_to_ofport,
+ target_port_name));
+ if (!ofport) {
+ VLOG_INFO("can not find ofport of %s in this switch",
+ target_port_name);
+ 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);
+
+ put_load(1, MFF_LOG_FLAGS, MLF_CLONED_FLOW_BIT, 1, ofpacts_p);
+ /* 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 +451,13 @@ consider_port_binding(struct controller_ctx *ctx,
return;
}
+ if (!strcmp(binding->type, "taas") &&
+ binding->chassis == chassis) {
+ taas_port_handle(ctx, binding, ofpacts_p, flow_table,
+ dp_key, port_key);
+ return;
+ }
+
struct ovs_list *gateway_chassis
= gateway_chassis_get_ordered(binding, chassis_index);
@@ -531,13 +629,45 @@ 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(1, MFF_LOG_FLAGS, MLF_CLONED_FLOW_BIT, 1,
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 +716,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(1, MFF_LOG_FLAGS, MLF_CLONED_FLOW_BIT, 1,
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) {
+ 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,8 +1156,16 @@ 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);
diff --git a/ovn/lib/logical-fields.c b/ovn/lib/logical-fields.c
index 26e336f..511e896 100644
--- a/ovn/lib/logical-fields.c
+++ b/ovn/lib/logical-fields.c
@@ -105,6 +105,10 @@ ovn_init_symtab(struct shash *symtab)
MLF_FORCE_SNAT_FOR_LB_BIT);
expr_symtab_add_subfield(symtab, "flags.force_snat_for_lb", NULL,
flags_str);
+ snprintf(flags_str, sizeof flags_str, "flags[%d]",
+ MLF_CLONED_FLOW_BIT);
+ expr_symtab_add_subfield(symtab, "flags.cloned_flow", NULL,
+ flags_str);
/* Connection tracking state. */
expr_symtab_add_field(symtab, "ct_mark", MFF_CT_MARK, NULL, false);
diff --git a/ovn/lib/logical-fields.h b/ovn/lib/logical-fields.h
index 696c529..5e20608 100644
--- a/ovn/lib/logical-fields.h
+++ b/ovn/lib/logical-fields.h
@@ -49,6 +49,7 @@ enum mff_log_flags_bits {
MLF_RCV_FROM_VXLAN_BIT = 1,
MLF_FORCE_SNAT_FOR_DNAT_BIT = 2,
MLF_FORCE_SNAT_FOR_LB_BIT = 3,
+ MLF_CLONED_FLOW_BIT = 4,
};
/* MFF_LOG_FLAGS_REG flag assignments */
@@ -69,6 +70,9 @@ enum mff_log_flags {
/* Indicate that a packet needs a force SNAT in the gateway router
when
* load-balancing has taken place. */
MLF_FORCE_SNAT_FOR_LB = (1 << MLF_FORCE_SNAT_FOR_LB_BIT),
+
+ /* Indicate that a packet is cloned. */
+ MLF_CLONED_FLOW = (1 << MLF_CLONED_FLOW_BIT),
};
#endif /* ovn/lib/logical-fields.h */
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 49e4ac3..59c9ba2 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
@@ -3478,6 +3480,332 @@ build_stateful(struct ovn_datapath *od, struct
hmap *lflows)
}
static void
+build_mirror_flows(struct ovn_datapath *od,
+ struct hmap *ports,
+ struct hmap *lflows)
+{
+ struct ds match = DS_EMPTY_INITIALIZER;
+ struct ds actions = DS_EMPTY_INITIALIZER;
+ if (!od->nbs) {
+ return;
+ }
+ bool need_mirror = false;
+ for (size_t i = 0; i < od->nbs->n_ports; i++) {
+ const struct nbrec_logical_switch_port *nbsp
+ = od->nbs->ports[i];
+ if (strcmp(nbsp->type, "mirror")) {
+ continue;
+ }
+ struct ovn_port *op = ovn_port_find(ports, nbsp->name);
+ if (!op) {
+ continue;
+ }
+
+ /* 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( ->options, "taas-port");
+ if (!taas_port_name) {
+ continue;
+ }
+ struct ovn_port *taas_port =
+ ovn_port_find(ports, taas_port_name);
+ if (!taas_port) {
+ continue;
+ }
+ if (taas_port->od != od) {
+ VLOG_INFO(" in valid configuration, inport: %s and outport %s
is "
+ "not in same logical switch", nbsp->name,
taas_port_name);
+ continue;
+ }
+ need_mirror = true;
+
+ ds_clear(&match);
+ ds_clear(&actions);
+ ds_put_format(&match, "inport == %s", op->json_key);
+ ds_put_cstr(&match, " && flags.cloned_flow == 1");
+ ds_put_format(&actions, "outport = %s; output;",
taas_port->json_key);
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "next;");
+ ovn_lflow_add(lflows, 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(&match, " && flags.cloned_flow == 1");
+ ds_put_cstr(&actions, "output;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_PORT_SEC_L2, 65535,
+ ds_cstr(&match), ds_cstr(&actions));
+ }
+ if (need_mirror) {
+ /* drop all cloned packets to avoid the effect of normal flows */
+ /* ingress pipeline */
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_L2, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_IP, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_ND, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_LB, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_STATEFUL, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_QOS_MARK, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_LB, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_STATEFUL, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_ND_RSP, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 65534,
+ "flags.cloned_flow == 1", "drop;");
+
+ /* egress pipeline */
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_LB, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_STATEFUL, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_LB, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_QOS_MARK, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_STATEFUL, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_PORT_SEC_IP, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ ovn_lflow_add(lflows, od, S_SWITCH_OUT_PORT_SEC_L2, 65534,
+ "flags.cloned_flow == 1", "drop;");
+ }
+ ds_destroy(&match);
+ ds_destroy(&actions);
+}
+static void
build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
struct hmap *lflows, struct hmap *mcgroups)
{
@@ -3502,6 +3830,7 @@ build_lswitch_flows(struct hmap *datapaths, struct
hmap *ports,
build_qos(od, lflows);
build_lb(od, lflows);
build_stateful(od, lflows);
+ build_mirror_flows(od, ports, lflows);
}
/* Logical switch ingress table 0: Admission control framework
(priority
diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
index 31303a8..5fdd045 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
+ create this port in logical_switch. This port should one to
+ one correspondence with the the tap_service.
+ </dd>
</dl>
</column>
</group>
@@ -445,6 +459,61 @@
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 title="Options for taas ports">
+ <p>
+ These options apply when <ref column="type"/> is
<code>taas</code>.
+ </p>
+
+ <column name="options" key="target-port">
+ Required. The <ref column="name"/> of the <ref
+ table="Logical_switch_Port"/> that indicates where the
+ cloned flows come to.
+ </column>
+ </group>
</group>
<group title="Containers">
--
1.8.3.1
More information about the dev
mailing list