> On Mar 3, 2017, at 10:35 AM, Joe Stringer <[email protected]> wrote:
> 
> On 28 February 2017 at 17:17, Jarno Rajahalme <[email protected] 
> <mailto:[email protected]>> wrote:
>> Add resubmit option to use the Conntrack original direction tuple
>> swapped with the corresponding packet header fields during the lookup.
>> This could allow the same ACL table be used for admitting return
>> and/or related traffic as is used for admitting the original direction
>> traffic.
>> 
>> Signed-off-by: Jarno Rajahalme <[email protected]>
>> ---
>> include/openvswitch/ofp-actions.h |   4 +-
>> lib/ofp-actions.c                 |  82 +++++++++++++++++++------
>> ofproto/ofproto-dpif-xlate.c      |  68 ++++++++++++++++++---
>> tests/ofp-actions.at              |   6 ++
>> tests/ofproto-dpif.at             |  89 +++++++++++++++++++++------
>> tests/system-traffic.at           | 122 
>> ++++++++++++++++++++++++++++----------
>> utilities/ovs-ofctl.8.in          |  19 +++++-
>> 7 files changed, 310 insertions(+), 80 deletions(-)
>> 
>> diff --git a/include/openvswitch/ofp-actions.h 
>> b/include/openvswitch/ofp-actions.h
>> index 53d6b44..5ea0763 100644
>> --- a/include/openvswitch/ofp-actions.h
>> +++ b/include/openvswitch/ofp-actions.h
>> @@ -640,11 +640,13 @@ struct ofpact_nat {
>> 
>> /* OFPACT_RESUBMIT.
>>  *
>> - * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE. */
>> + * Used for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE, NXAST_RESUBMIT_TABLE_CT. 
>> */
>> struct ofpact_resubmit {
>>     struct ofpact ofpact;
>>     ofp_port_t in_port;
>>     uint8_t table_id;
>> +    bool with_ct_orig;   /* Resubmit with Conntrack original direction tuple
>> +                          * fields in place of IP header fields. */
>> };
>> 
>> /* Bits for 'flags' in struct nx_action_learn.
>> diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
>> index 2869e0f..4d35a77 100644
>> --- a/lib/ofp-actions.c
>> +++ b/lib/ofp-actions.c
>> @@ -265,6 +265,8 @@ enum ofp_raw_action_type {
>>     NXAST_RAW_RESUBMIT,
>>     /* NX1.0+(14): struct nx_action_resubmit. */
>>     NXAST_RAW_RESUBMIT_TABLE,
>> +    /* NX1.0+(44): struct nx_action_resubmit. */
>> +    NXAST_RAW_RESUBMIT_TABLE_CT,
>> 
>>     /* NX1.0+(2): uint32_t. */
>>     NXAST_RAW_SET_TUNNEL,
>> @@ -3850,19 +3852,20 @@ format_FIN_TIMEOUT(const struct ofpact_fin_timeout 
>> *a, struct ds *s)
>>     ds_put_format(s, "%s)%s", colors.paren, colors.end);
>> }
>> 
>> -/* Action structures for NXAST_RESUBMIT and NXAST_RESUBMIT_TABLE.
>> +/* Action structures for NXAST_RESUBMIT, NXAST_RESUBMIT_TABLE, and
>> + * NXAST_RESUBMIT_TABLE_CT.
>>  *
>>  * These actions search one of the switch's flow tables:
>>  *
>> - *    - For NXAST_RESUBMIT_TABLE only, if the 'table' member is not 255, 
>> then
>> - *      it specifies the table to search.
>> + *    - For NXAST_RESUBMIT_TABLE and NXAST_RESUBMIT_TABLE_CT only, if the
>> + *      'table' member is not 255, then it specifies the table to search.
> 
> 'only' is a bit superfluous - it's now for 2 of the 3 cases.

removed.

> 
>>  *
>> - *    - Otherwise (for NXAST_RESUBMIT_TABLE with a 'table' of 255, or for
>> - *      NXAST_RESUBMIT regardless of 'table'), it searches the current flow
>> - *      table, that is, the OpenFlow flow table that contains the flow from
>> - *      which this action was obtained.  If this action did not come from a
>> - *      flow table (e.g. it came from an OFPT_PACKET_OUT message), then 
>> table 0
>> - *      is the current table.
>> + *    - Otherwise (for NXAST_RESUBMIT_TABLE or NXAST_RESUBMIT_TABLE_CT with 
>> a
>> + *      'table' of 255, or for NXAST_RESUBMIT regardless of 'table'), it
>> + *      searches the current flow table, that is, the OpenFlow flow table 
>> that
>> + *      contains the flow from which this action was obtained.  If this 
>> action
>> + *      did not come from a flow table (e.g. it came from an OFPT_PACKET_OUT
>> + *      message), then table 0 is the current table.
>>  *
>>  * The flow table lookup uses a flow that may be slightly modified from the
>>  * original lookup:
>> @@ -3870,9 +3873,12 @@ format_FIN_TIMEOUT(const struct ofpact_fin_timeout 
>> *a, struct ds *s)
>>  *    - For NXAST_RESUBMIT, the 'in_port' member of struct nx_action_resubmit
>>  *      is used as the flow's in_port.
>>  *
>> - *    - For NXAST_RESUBMIT_TABLE, if the 'in_port' member is not 
>> OFPP_IN_PORT,
>> - *      then its value is used as the flow's in_port.  Otherwise, the 
>> original
>> - *      in_port is used.
>> + *    - For NXAST_RESUBMIT_TABLE and NXAST_RESUBMIT_TABLE_CT, if the 
>> 'in_port'
>> + *      member is not OFPP_IN_PORT, then its value is used as the flow's
>> + *      in_port.  Otherwise, the original in_port is used.
>> + *
>> + *    - For NXAST_RESUBMIT_TABLE_CT the Conntrack 5-tuple fields are used as
>> + *      the packets IP header fields during the lookup.
>>  *
>>  *    - If actions that modify the flow (e.g. OFPAT_SET_VLAN_VID) precede the
>>  *      resubmit action, then the flow is updated with the new values.
>> @@ -3905,11 +3911,12 @@ format_FIN_TIMEOUT(const struct ofpact_fin_timeout 
>> *a, struct ds *s)
>>  *      a total limit of 4,096 resubmits per flow translation (earlier 
>> versions
>>  *      did not impose any total limit).
>>  *
>> - * NXAST_RESUBMIT ignores 'table' and 'pad'.  NXAST_RESUBMIT_TABLE requires
>> - * 'pad' to be all-bits-zero.
>> + * NXAST_RESUBMIT ignores 'table' and 'pad'.  NXAST_RESUBMIT_TABLE and
>> + * NXAST_RESUBMIT_TABLE_CT require 'pad' to be all-bits-zero.
>>  *
>>  * Open vSwitch 1.0.1 and earlier did not support recursion.  Open vSwitch
>> - * before 1.2.90 did not support NXAST_RESUBMIT_TABLE.
>> + * before 1.2.90 did not support NXAST_RESUBMIT_TABLE.  Open vSwitch before
>> + * 2.7.0 did not support NXAST_RESUBMIT_TABLE_CT.
> 
> 2.8.0.
> 

OK.

>>  */
>> struct nx_action_resubmit {
>>     ovs_be16 type;                  /* OFPAT_VENDOR. */
>> @@ -3954,6 +3961,21 @@ decode_NXAST_RAW_RESUBMIT_TABLE(const struct 
>> nx_action_resubmit *nar,
>>     return 0;
>> }
>> 
>> +static enum ofperr
>> +decode_NXAST_RAW_RESUBMIT_TABLE_CT(const struct nx_action_resubmit *nar,
>> +                                   enum ofp_version ofp_version OVS_UNUSED,
>> +                                   struct ofpbuf *out)
>> +{
>> +    enum ofperr error = decode_NXAST_RAW_RESUBMIT_TABLE(nar, ofp_version, 
>> out);
>> +    if (error) {
>> +        return error;
>> +    }
>> +    struct ofpact_resubmit *resubmit = out->header;
>> +    resubmit->ofpact.raw = NXAST_RAW_RESUBMIT_TABLE_CT;
>> +    resubmit->with_ct_orig = true;
>> +    return 0;
>> +}
>> +
>> static void
>> encode_RESUBMIT(const struct ofpact_resubmit *resubmit,
>>                 enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
>> @@ -3961,10 +3983,12 @@ encode_RESUBMIT(const struct ofpact_resubmit 
>> *resubmit,
>>     uint16_t in_port = ofp_to_u16(resubmit->in_port);
>> 
>>     if (resubmit->table_id == 0xff
>> -        && resubmit->ofpact.raw != NXAST_RAW_RESUBMIT_TABLE) {
>> +        && resubmit->ofpact.raw == NXAST_RAW_RESUBMIT) {
>>         put_NXAST_RESUBMIT(out, in_port);
>>     } else {
>> -        struct nx_action_resubmit *nar = put_NXAST_RESUBMIT_TABLE(out);
>> +        struct nx_action_resubmit *nar;
>> +        nar = resubmit->with_ct_orig
>> +            ? put_NXAST_RESUBMIT_TABLE_CT(out) : 
>> put_NXAST_RESUBMIT_TABLE(out);
>>         nar->table = resubmit->table_id;
>>         nar->in_port = htons(in_port);
>>     }
>> @@ -3975,7 +3999,7 @@ parse_RESUBMIT(char *arg, struct ofpbuf *ofpacts,
>>                enum ofputil_protocol *usable_protocols OVS_UNUSED)
>> {
>>     struct ofpact_resubmit *resubmit;
>> -    char *in_port_s, *table_s;
>> +    char *in_port_s, *table_s, *ct_s;
>> 
>>     resubmit = ofpact_put_RESUBMIT(ofpacts);
>> 
>> @@ -4002,6 +4026,16 @@ parse_RESUBMIT(char *arg, struct ofpbuf *ofpacts,
>>         resubmit->table_id = 255;
>>     }
>> 
>> +    ct_s = strsep(&arg, ",");
>> +    if (ct_s && ct_s[0]) {
>> +        if (strcmp(ct_s, "ct")) {
>> +            return xasprintf("%s: unknown parameter", ct_s);
>> +        }
>> +        resubmit->with_ct_orig = true;
>> +    } else {
>> +        resubmit->with_ct_orig = false;
>> +    }
>> +
>>     if (resubmit->in_port == OFPP_IN_PORT && resubmit->table_id == 255) {
>>         return xstrdup("at least one \"in_port\" or \"table\" must be "
>>                        "specified  on resubmit");
>> @@ -4024,6 +4058,9 @@ format_RESUBMIT(const struct ofpact_resubmit *a, 
>> struct ds *s)
>>         if (a->table_id != 255) {
>>             ds_put_format(s, "%"PRIu8, a->table_id);
>>         }
>> +        if (a->with_ct_orig) {
>> +            ds_put_cstr(s, ",ct");
>> +        }
> 
> If no table is used, this could serialize two commas.
> 

We discussed this offline, the parameters can be seen as positional, so we 
leave this as it is. Besides, resubmits without a table are very rare (test 
suite has none).

>>         ds_put_format(s, "%s)%s", colors.paren, colors.end);
>>     }
>> }
>> @@ -7220,9 +7257,16 @@ ofpact_check__(enum ofputil_protocol 
>> *usable_protocols, struct ofpact *a,
>>     case OFPACT_SET_TUNNEL:
>>     case OFPACT_SET_QUEUE:
>>     case OFPACT_POP_QUEUE:
>> -    case OFPACT_RESUBMIT:
>>         return 0;
>> 
>> +    case OFPACT_RESUBMIT: {
>> +        struct ofpact_resubmit *resubmit = ofpact_get_RESUBMIT(a);
>> +
>> +        if (resubmit->with_ct_orig && !is_ct_valid(flow, &match->wc, NULL)) 
>> {
>> +            return OFPERR_OFPBAC_MATCH_INCONSISTENT;
>> +        }
>> +        return 0;
>> +    }
>>     case OFPACT_FIN_TIMEOUT:
>>         if (flow->nw_proto != IPPROTO_TCP) {
>>             inconsistent_match(usable_protocols);
>> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
>> index 0a6b730..257b736 100644
>> --- a/ofproto/ofproto-dpif-xlate.c
>> +++ b/ofproto/ofproto-dpif-xlate.c
>> @@ -483,7 +483,7 @@ static void do_xlate_actions(const struct ofpact *, 
>> size_t ofpacts_len,
>> static void xlate_normal(struct xlate_ctx *);
>> static void xlate_table_action(struct xlate_ctx *, ofp_port_t in_port,
>>                                uint8_t table_id, bool may_packet_in,
>> -                               bool honor_table_miss);
>> +                               bool honor_table_miss, bool with_ct_orig);
>> static bool input_vid_is_valid(const struct xlate_ctx *,
>>                                uint16_t vid, struct xbundle *);
>> static uint16_t input_vid_to_vlan(const struct xbundle *, uint16_t vid);
>> @@ -3204,7 +3204,8 @@ compose_output_action__(struct xlate_ctx *ctx, 
>> ofp_port_t ofp_port,
>> 
>>         if (!process_special(ctx, peer) && may_receive(peer, ctx)) {
>>             if (xport_stp_forward_state(peer) && 
>> xport_rstp_forward_state(peer)) {
>> -                xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, 
>> true);
>> +                xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, 
>> true,
>> +                                   false);
>>                 if (!ctx->freezing) {
>>                     xlate_action_set(ctx);
>>                 }
>> @@ -3218,7 +3219,8 @@ compose_output_action__(struct xlate_ctx *ctx, 
>> ofp_port_t ofp_port,
>>                 size_t old_size = ctx->odp_actions->size;
>>                 mirror_mask_t old_mirrors2 = ctx->mirrors;
>> 
>> -                xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, 
>> true);
>> +                xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, 
>> true,
>> +                                   false);
>>                 ctx->mirrors = old_mirrors2;
>>                 ctx->base_flow = old_base_flow;
>>                 ctx->odp_actions->size = old_size;
>> @@ -3473,8 +3475,50 @@ xlate_resubmit_resource_check(struct xlate_ctx *ctx)
>> }
>> 
>> static void
>> +tuple_swap(struct flow *flow, const struct flow *key)
>> +{
>> +    /* Do not swap if there is no CT tuple. */
>> +    if (flow == key && flow->ct_nw_proto == 0) {
>> +        OVS_NOT_REACHED();   /* Prerequisite check should take care of 
>> this! */
> 
> I'm not sure I follow the reasoning behind the flow / key pointer check here.
> 
> It seems to me like this function is always called if someone writes
> the resubmit(...,ct) parameter, is there a guarantee that they've run
> the connection through ct() action before running this action?

As commented, prerequisites checking should take care of that, but I agree, I’m 
making these more robust and issue a warning instead of crashing OVS if 
something unexpected happens here.

> 
>> +    }
>> +
>> +    uint8_t nw_proto = flow->nw_proto;
>> +    flow->nw_proto = flow->ct_nw_proto;
>> +    flow->ct_nw_proto = nw_proto;
>> +
>> +    if (key->dl_type == htons(ETH_TYPE_IP)) {
>> +        ovs_be32 nw_src = flow->nw_src;
>> +        flow->nw_src = flow->ct_nw_src;
>> +        flow->ct_nw_src = nw_src;
>> +
>> +        ovs_be32 nw_dst = flow->nw_dst;
>> +        flow->nw_dst = flow->ct_nw_dst;
>> +        flow->ct_nw_dst = nw_dst;
>> +    } else if (key->dl_type == htons(ETH_TYPE_IPV6)) {
>> +        struct in6_addr ipv6_src = flow->ipv6_src;
>> +        flow->ipv6_src = flow->ct_ipv6_src;
>> +        flow->ct_ipv6_src = ipv6_src;
>> +
>> +        struct in6_addr ipv6_dst = flow->ipv6_dst;
>> +        flow->ipv6_dst = flow->ct_ipv6_dst;
>> +        flow->ct_ipv6_dst = ipv6_dst;
>> +    } else {
>> +        OVS_NOT_REACHED();
> 
> Remind me, does prerequisite check ensure the ethertype will be
> IP/IPV6? - I recall CT having something like this, but this is the
> resubmit action so I'm not sure we have as many guarantees on our
> prerequisites.

Prerequisites checking ensures CT state indicates packet has been through 
conntrack and is trackable, which implies IPv4 or IPv6. I’ll make this more 
obviously robust as well.

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to