On Sat, Jan 21, 2017 at 11:13 AM, Ben Pfaff <b...@ovn.org> wrote:

> This feature is useful for centralized gateways.
>
> Signed-off-by: Ben Pfaff <b...@ovn.org>
> Acked-by: Mickey Spiegel <mickeys....@gmail.com>
>

The ovn-trace.c changes look good to me. No more comments.

Thank you very much for this patch set!

Mickey

---
>  include/ovn/actions.h     | 63 ++++++++++++++++++++++++------------------
>  ovn/controller/lflow.c    |  7 +++--
>  ovn/lib/actions.c         | 70 ++++++++++++++++++++++++++++++
> ++++++++++-------
>  ovn/ovn-sb.xml            | 12 ++++++--
>  ovn/utilities/ovn-trace.c | 35 ++++++++++++++++++++++--
>  tests/ovn.at              | 22 ++++++++++++++-
>  tests/test-ovn.c          |  6 ++--
>  7 files changed, 167 insertions(+), 48 deletions(-)
>
> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
> index f392d03..6691116 100644
> --- a/include/ovn/actions.h
> +++ b/include/ovn/actions.h
> @@ -151,13 +151,15 @@ struct ovnact_next {
>      struct ovnact ovnact;
>
>      /* Arguments. */
> -    uint8_t ltable;             /* Logical table ID of next table. */
> +    uint8_t ltable;                /* Logical table ID of next table. */
> +    enum ovnact_pipeline pipeline; /* Pipeline of next table. */
>
>      /* Information about the flow that the action is in.  This does not
> affect
>       * behavior, since the implementation of "next" doesn't depend on the
>       * source table or pipeline.  It does affect how ovnacts_format()
> prints
>       * the action. */
> -    uint8_t src_ltable;            /* Logical table ID of source table. */
> +    uint8_t src_ltable;                /* Logical table ID of source
> table. */
> +    enum ovnact_pipeline src_pipeline; /* Pipeline of source table. */
>  };
>
>  /* OVNACT_LOAD. */
> @@ -402,22 +404,26 @@ struct ovnact_parse_params {
>      /* hmap of 'struct dhcp_opts_map'  to support 'put_dhcpv6_opts'
> action */
>      const struct hmap *dhcpv6_opts;
>
> -    /* OVN maps each logical flow table (ltable), one-to-one, onto a
> physical
> -     * OpenFlow flow table (ptable).  A number of parameters describe this
> -     * mapping and data related to flow tables:
> +    /* Each OVN flow exists in a logical table within a logical pipeline.
> +     * These parameters express this context for a set of OVN actions
> being
> +     * parsed:
>       *
> -     *     - 'first_ptable' and 'n_tables' define the range of OpenFlow
> tables
> -     *        to which the logical "next" action should be able to jump.
> -     *        Logical table 0 maps to OpenFlow table 'first_ptable',
> logical
> -     *        table 1 to 'first_ptable + 1', and so on.  If 'n_tables' is
> 0
> -     *        then "next" is disallowed entirely.
> +     *     - 'n_tables' is the number of tables in the logical ingress and
> +     *        egress pipelines, that is, "next" may specify a table less
> than
> +     *        or equal to 'n_tables'.  If 'n_tables' is 0 then "next" is
> +     *        disallowed entirely.
>       *
> -     *     - 'cur_ltable' is an offset from 'first_ptable' (e.g. 0 <=
> -     *       cur_ltable < n_tables) of the logical flow that contains the
> -     *       actions.  If cur_ltable + 1 < n_tables, then this defines the
> -     *       default table that "next" will jump to. */
> -    uint8_t n_tables;           /* Number of flow tables. */
> -    uint8_t cur_ltable;         /* 0 <= cur_ltable < n_tables. */
> +     *     - 'cur_ltable' is the logical table of the current flow, within
> +     *       'pipeline'.  If cur_ltable + 1 < n_tables, then this defines
> the
> +     *       default table that "next" will jump to.
> +     *
> +     *     - 'pipeline' is the logical pipeline.  It is the default
> pipeline to
> +     *       which 'next' will jump.  If 'pipeline' is OVNACT_P_EGRESS,
> then
> +     *       'next' will also be able to jump into the ingress pipeline,
> but
> +     *       the reverse is not true. */
> +    enum ovnact_pipeline pipeline; /* Logical pipeline. */
> +    uint8_t n_tables;              /* Number of logical flow tables. */
> +    uint8_t cur_ltable;            /* 0 <= cur_ltable < n_tables. */
>  };
>
>  bool ovnacts_parse(struct lexer *, const struct ovnact_parse_params *,
> @@ -448,20 +454,23 @@ struct ovnact_encode_params {
>       * OpenFlow flow table (ptable).  A number of parameters describe this
>       * mapping and data related to flow tables:
>       *
> -     *     - 'first_ptable' and 'n_tables' define the range of OpenFlow
> tables
> -     *        to which the logical "next" action should be able to jump.
> -     *        Logical table 0 maps to OpenFlow table 'first_ptable',
> logical
> -     *        table 1 to 'first_ptable + 1', and so on.  If 'n_tables' is
> 0
> -     *        then "next" is disallowed entirely.
> +     *     - 'pipeline' is the logical pipeline in which the actions are
> +     *       executing.
>       *
> -     *     - 'cur_ltable' is an offset from 'first_ptable' (e.g. 0 <=
> -     *       cur_ltable < n_ptables) of the logical flow that contains the
> -     *       actions.  If cur_ltable + 1 < n_tables, then this defines the
> -     *       default table that "next" will jump to.
> +     *     - 'ingress_ptable' is the OpenFlow table that corresponds to
> OVN
> +     *       ingress table 0.
> +     *
> +     *     - 'egress_ptable' is the OpenFlow table that corresponds to OVN
> +     *       egress table 0.
>       *
>       *     - 'output_ptable' should be the OpenFlow table to which the
> logical
> -     *       "output" action will resubmit. */
> -    uint8_t first_ptable;       /* First OpenFlow table. */
> +     *       "output" action will resubmit.
> +     *
> +     *     - 'mac_bind_ptable' should be the OpenFlow table used to track
> MAC
> +     *       bindings. */
> +    enum ovnact_pipeline pipeline; /* Logical pipeline. */
> +    uint8_t ingress_ptable;     /* First OpenFlow ingress table. */
> +    uint8_t egress_ptable;      /* First OpenFlow egress table. */
>      uint8_t output_ptable;      /* OpenFlow table for 'output' to
> resubmit. */
>      uint8_t mac_bind_ptable;    /* OpenFlow table for 'get_arp'/'get_nd'
> to
>                                     resubmit. */
> diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
> index 3d7633e..2d9213b 100644
> --- a/ovn/controller/lflow.c
> +++ b/ovn/controller/lflow.c
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2015, 2016 Nicira, Inc.
> +/* Copyright (c) 2015, 2016, 2017 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -191,6 +191,7 @@ consider_logical_flow(const struct lport_index *lports,
>          .dhcp_opts = dhcp_opts,
>          .dhcpv6_opts = dhcpv6_opts,
>
> +        .pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS,
>          .n_tables = LOG_PIPELINE_LEN,
>          .cur_ltable = lflow->table_id,
>      };
> @@ -223,7 +224,9 @@ consider_logical_flow(const struct lport_index *lports,
>          .ct_zones = ct_zones,
>          .group_table = group_table,
>
> -        .first_ptable = first_ptable,
> +        .pipeline = ingress ? OVNACT_P_INGRESS : OVNACT_P_EGRESS,
> +        .ingress_ptable = OFTABLE_LOG_INGRESS_PIPELINE,
> +        .egress_ptable = OFTABLE_LOG_EGRESS_PIPELINE,
>          .output_ptable = output_ptable,
>          .mac_bind_ptable = OFTABLE_MAC_BINDING,
>      };
> diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
> index a139ff4..186552f 100644
> --- a/ovn/lib/actions.c
> +++ b/ovn/lib/actions.c
> @@ -170,6 +170,15 @@ put_load(uint64_t value, enum mf_field_id dst, int
> ofs, int n_bits,
>      bitwise_copy(&n_value, 8, 0, sf->value, sf->field->n_bytes, ofs,
> n_bits);
>      bitwise_one(ofpact_set_field_mask(sf), sf->field->n_bytes, ofs,
> n_bits);
>  }
> +
> +static uint8_t
> +first_ptable(const struct ovnact_encode_params *ep,
> +             enum ovnact_pipeline pipeline)
> +{
> +    return (pipeline == OVNACT_P_INGRESS
> +            ? ep->ingress_ptable
> +            : ep->egress_ptable);
> +}
>
>  /* Context maintained during ovnacts_parse(). */
>  struct action_context {
> @@ -262,14 +271,48 @@ parse_NEXT(struct action_context *ctx)
>          return;
>      }
>
> +    int pipeline = ctx->pp->pipeline;
>      int table = ctx->pp->cur_ltable + 1;
> -    if (lexer_match(ctx->lexer, LEX_T_LPAREN)
> -        && (!lexer_force_int(ctx->lexer, &table) ||
> -            !lexer_force_match(ctx->lexer, LEX_T_RPAREN))) {
> -        return;
> +    if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
> +        if (lexer_is_int(ctx->lexer)) {
> +            lexer_get_int(ctx->lexer, &table);
> +        } else {
> +            do {
> +                if (lexer_match_id(ctx->lexer, "pipeline")) {
> +                    if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS)) {
> +                        return;
> +                    }
> +                    if (lexer_match_id(ctx->lexer, "ingress")) {
> +                        pipeline = OVNACT_P_INGRESS;
> +                    } else if (lexer_match_id(ctx->lexer, "egress")) {
> +                        pipeline = OVNACT_P_EGRESS;
> +                    } else {
> +                        lexer_syntax_error(
> +                            ctx->lexer, "expecting \"ingress\" or
> \"egress\"");
> +                        return;
> +                    }
> +                } else if (lexer_match_id(ctx->lexer, "table")) {
> +                    if (!lexer_force_match(ctx->lexer, LEX_T_EQUALS) ||
> +                        !lexer_force_int(ctx->lexer, &table)) {
> +                        return;
> +                    }
> +                } else {
> +                    lexer_syntax_error(ctx->lexer,
> +                                       "expecting \"pipeline\" or
> \"table\"");
> +                    return;
> +                }
> +            } while (lexer_match(ctx->lexer, LEX_T_COMMA));
> +        }
> +        if (!lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
> +            return;
> +        }
>      }
>
> -    if (table >= ctx->pp->n_tables) {
> +    if (pipeline == OVNACT_P_EGRESS && ctx->pp->pipeline ==
> OVNACT_P_INGRESS) {
> +        lexer_error(ctx->lexer,
> +                    "\"next\" action cannot advance from ingress to
> egress "
> +                    "pipeline (use \"output\" action instead)");
> +    } else if (table >= ctx->pp->n_tables) {
>          lexer_error(ctx->lexer,
>                      "\"next\" action cannot advance beyond table %d.",
>                      ctx->pp->n_tables - 1);
> @@ -277,14 +320,21 @@ parse_NEXT(struct action_context *ctx)
>      }
>
>      struct ovnact_next *next = ovnact_put_NEXT(ctx->ovnacts);
> +    next->pipeline = pipeline;
>      next->ltable = table;
> +    next->src_pipeline = ctx->pp->pipeline;
>      next->src_ltable = ctx->pp->cur_ltable;
>  }
>
>  static void
>  format_NEXT(const struct ovnact_next *next, struct ds *s)
>  {
> -    if (next->ltable != next->src_ltable + 1) {
> +    if (next->pipeline != next->src_pipeline) {
> +        ds_put_format(s, "next(pipeline=%s, table=%d);",
> +                      (next->pipeline == OVNACT_P_INGRESS
> +                       ? "ingress" : "egress"),
> +                      next->ltable);
> +    } else if (next->ltable != next->src_ltable + 1) {
>          ds_put_format(s, "next(%d);", next->ltable);
>      } else {
>          ds_put_cstr(s, "next;");
> @@ -296,7 +346,7 @@ encode_NEXT(const struct ovnact_next *next,
>              const struct ovnact_encode_params *ep,
>              struct ofpbuf *ofpacts)
>  {
> -    emit_resubmit(ofpacts, ep->first_ptable + next->ltable);
> +    emit_resubmit(ofpacts, first_ptable(ep, next->pipeline) +
> next->ltable);
>  }
>
>  static void
> @@ -541,7 +591,7 @@ encode_CT_NEXT(const struct ovnact_ct_next *ct_next,
>                  struct ofpbuf *ofpacts)
>  {
>      struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
> -    ct->recirc_table = ep->first_ptable + ct_next->ltable;
> +    ct->recirc_table = first_ptable(ep, ep->pipeline) + ct_next->ltable;
>      ct->zone_src.field = ep->is_switch ? mf_from_id(MFF_LOG_CT_ZONE)
>                              : mf_from_id(MFF_LOG_DNAT_ZONE);
>      ct->zone_src.ofs = 0;
> @@ -745,7 +795,7 @@ encode_ct_nat(const struct ovnact_ct_nat *cn,
>      ofpbuf_pull(ofpacts, ct_offset);
>
>      struct ofpact_conntrack *ct = ofpact_put_CT(ofpacts);
> -    ct->recirc_table = cn->ltable + ep->first_ptable;
> +    ct->recirc_table = cn->ltable + first_ptable(ep, ep->pipeline);
>      if (snat) {
>          ct->zone_src.field = mf_from_id(MFF_LOG_SNAT_ZONE);
>      } else {
> @@ -889,7 +939,7 @@ encode_CT_LB(const struct ovnact_ct_lb *cl,
>               const struct ovnact_encode_params *ep,
>               struct ofpbuf *ofpacts)
>  {
> -    uint8_t recirc_table = cl->ltable + ep->first_ptable;
> +    uint8_t recirc_table = cl->ltable + first_ptable(ep, ep->pipeline);
>      if (!cl->n_dsts) {
>          /* ct_lb without any destinations means that this is an
> established
>           * connection and we just need to do a NAT. */
> diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
> index a724ae6..6171f9d 100644
> --- a/ovn/ovn-sb.xml
> +++ b/ovn/ovn-sb.xml
> @@ -956,10 +956,16 @@
>
>          <dt><code>next;</code></dt>
>          <dt><code>next(<var>table</var>);</code></dt>
> +        <dt><code>next(pipeline=<var>pipeline</var>,
> table=<var>table</var>);</code></dt>
>          <dd>
> -          Executes another logical datapath table as a subroutine.  By
> default,
> -          the table after the current one is executed.  Specify
> -          <var>table</var> to jump to a specific table in the same
> pipeline.
> +          Executes the given logical datapath <var>table</var> in
> +          <var>pipeline</var> as a subroutine.  The default
> <var>table</var> is
> +          just after the current one.  If <var>pipeline</var> is
> specified, it
> +          may be <code>ingress</code> or <code>egress</code>; the default
> +          <var>pipeline</var> is the one currently executing.  Actions in
> the
> +          ingress pipeline may not use <code>next</code> to jump into the
> +          egress pipeline (use the <code>output</code> instead), but
> +          transitions in the opposite direction are allowed.
>          </dd>
>
>          <dt><code><var>field</var> = <var>constant</var>;</code></dt>
> diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
> index c201775..3212982 100644
> --- a/ovn/utilities/ovn-trace.c
> +++ b/ovn/utilities/ovn-trace.c
> @@ -409,6 +409,16 @@ ovntrace_port_find_by_key(const struct
> ovntrace_datapath *dp,
>      return NULL;
>  }
>
> +static const char *
> +ovntrace_port_key_to_name(const struct ovntrace_datapath *dp,
> +                          uint16_t key)
> +{
> +    const struct ovntrace_port *port = ovntrace_port_find_by_key(dp, key);
> +    return (port ? port->name
> +            : !key ? ""
> +            : "(unnamed)");
> +}
> +
>  static const struct ovntrace_mcgroup *
>  ovntrace_mcgroup_find_by_key(const struct ovntrace_datapath *dp,
>                               uint16_t tunnel_key)
> @@ -673,6 +683,9 @@ read_flows(void)
>              .symtab = &symtab,
>              .dhcp_opts = &dhcp_opts,
>              .dhcpv6_opts = &dhcpv6_opts,
> +            .pipeline = (!strcmp(sblf->pipeline, "ingress")
> +                         ? OVNACT_P_INGRESS
> +                         : OVNACT_P_EGRESS),
>              .n_tables = 16,
>              .cur_ltable = sblf->table_id,
>          };
> @@ -1162,8 +1175,7 @@ execute_output(const struct ovntrace_datapath *dp,
> struct flow *uflow,
>      }
>
>      uint16_t in_key = uflow->regs[MFF_LOG_INPORT - MFF_REG0];
> -    const struct ovntrace_port *inport = ovntrace_port_find_by_key(dp,
> in_key);
> -    const char *inport_name = !in_key ? "" : inport ? inport->name :
> "(unnamed)";
> +    const char *inport_name = ovntrace_port_key_to_name(dp, in_key);
>      uint32_t flags = uflow->regs[MFF_LOG_FLAGS - MFF_REG0];
>      bool allow_loopback = (flags & MLF_ALLOW_LOOPBACK) != 0;
>
> @@ -1365,6 +1377,23 @@ execute_put_dhcp_opts(const struct
> ovnact_put_dhcp_opts *pdo,
>  }
>
>  static void
> +execute_next(const struct ovnact_next *next,
> +             const struct ovntrace_datapath *dp, struct flow *uflow,
> +             enum ovnact_pipeline pipeline, struct ovs_list *super)
> +{
> +    if (pipeline != next->pipeline) {
> +        ovs_assert(next->pipeline == OVNACT_P_INGRESS);
> +
> +        uint16_t in_key = uflow->regs[MFF_LOG_INPORT - MFF_REG0];
> +        struct ovntrace_node *node = ovntrace_node_append(
> +            super, OVNTRACE_NODE_PIPELINE, "ingress(dp=\"%s\",
> inport=\"%s\")",
> +            dp->name, ovntrace_port_key_to_name(dp, in_key));
> +        super = &node->subs;
> +    }
> +    trace__(dp, uflow, next->ltable, next->pipeline, super);
> +}
> +
> +static void
>  trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
>                const struct ovntrace_datapath *dp, struct flow *uflow,
>                uint8_t table_id, enum ovnact_pipeline pipeline,
> @@ -1388,7 +1417,7 @@ trace_actions(const struct ovnact *ovnacts, size_t
> ovnacts_len,
>              break;
>
>          case OVNACT_NEXT:
> -            trace__(dp, uflow, ovnact_get_NEXT(a)->ltable, pipeline,
> super);
> +            execute_next(ovnact_get_NEXT(a), dp, uflow, pipeline, super);
>              break;
>
>          case OVNACT_LOAD:
> diff --git a/tests/ovn.at b/tests/ovn.at
> index f71a4af..ecdb2be 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -653,12 +653,32 @@ next(15);
>      encodes as resubmit(,31)
>
>  next();
> -    Syntax error at `)' expecting small integer.
> +    Syntax error at `)' expecting "pipeline" or "table".
>  next(10;
>      Syntax error at `;' expecting `)'.
>  next(16);
>      "next" action cannot advance beyond table 15.
>
> +next(table=11);
> +    formats as next;
> +    encodes as resubmit(,27)
> +next(pipeline=ingress);
> +    formats as next;
> +    encodes as resubmit(,27)
> +next(table=11, pipeline=ingress);
> +    formats as next;
> +    encodes as resubmit(,27)
> +next(pipeline=ingress, table=11);
> +    formats as next;
> +    encodes as resubmit(,27)
> +
> +next(pipeline=egress);
> +    "next" action cannot advance from ingress to egress pipeline (use
> "output" action instead)
> +
> +next(table=10);
> +    formats as next(10);
> +    encodes as resubmit(,26)
> +
>  # Loading a constant value.
>  tcp.dst=80;
>      formats as tcp.dst = 80;
> diff --git a/tests/test-ovn.c b/tests/test-ovn.c
> index e64f12f..ea7c45a 100644
> --- a/tests/test-ovn.c
> +++ b/tests/test-ovn.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2015, 2016 Nicira, Inc.
> + * Copyright (c) 2015, 2016, 2017 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -1246,7 +1246,9 @@ test_parse_actions(struct ovs_cmdl_context *ctx
> OVS_UNUSED)
>                  .ct_zones = &ct_zones,
>                  .group_table = &group_table,
>
> -                .first_ptable = 16,
> +                .pipeline = OVNACT_P_INGRESS,
> +                .ingress_ptable = 16,
> +                .egress_ptable = 48,
>                  .output_ptable = 64,
>                  .mac_bind_ptable = 65,
>              };
> --
> 2.10.2
>
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to