[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(&nbsp->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