[ovs-dev] [PATCH v2] ovn: Support for taas(tap-as-a-service) function
Russell Bryant
russell at ovn.org
Tue Aug 15 15:01:13 UTC 2017
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.qianyu at 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.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
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
--
Russell Bryant
More information about the dev
mailing list