Thanks for updating this! This looks closer to what I was hoping for. It will most likely be next week before I can complete a detailed review, though.
On Tue, Aug 15, 2017 at 4:28 AM, <wang.qia...@zte.com.cn> wrote: > 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.qia...@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 > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev -- Russell Bryant _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev