On Wed, Nov 11, 2020 at 4:13 PM Eelco Chaudron <echau...@redhat.com> wrote:
>
> Add support for the dec_ttl action. Instead of programming the datapath with
> a flow that matches the packet TTL and an IP set, use a single dec_ttl action.
>
> The old behavior is kept if the new action is not supported by the datapath.
>
>   # ovs-ofctl dump-flows br0
>    cookie=0x0, duration=12.538s, table=0, n_packets=4, n_bytes=392, ip 
> actions=dec_ttl,NORMAL
>    cookie=0x0, duration=12.536s, table=0, n_packets=4, n_bytes=168, 
> actions=NORMAL
>
>   # ping -c1 -t 20 192.168.0.2
>   PING 192.168.0.2 (192.168.0.2) 56(84) bytes of data.
>   IP (tos 0x0, ttl 19, id 45336, offset 0, flags [DF], proto ICMP (1), length 
> 84)
>       192.168.0.1 > 192.168.0.2: ICMP echo request, id 8865, seq 1, length 64
>
> Linux netlink datapath support depends on upstream Linux commit:
>   744676e77720 ("openvswitch: add TTL decrement action")
>
>
> Note that in the Linux kernel tree the OVS_ACTION_ATTR_ADD_MPLS has been
> defined, and to make sure the IDs are in sync, it had to be added to the
> OVS source tree. This required some additional case statements, which
> should be revisited once the OVS implementation is added.
>
>
> Co-developed-by: Matteo Croce <mcr...@linux.microsoft.com>
> Co-developed-by: Bindiya Kurle <bindiyaku...@gmail.com>
> Signed-off-by: Eelco Chaudron <echau...@redhat.com>
> ---
>  datapath/linux/compat/include/linux/openvswitch.h |    8 ++
>  lib/dpif-netdev.c                                 |    4 +
>  lib/dpif.c                                        |    4 +
>  lib/odp-execute.c                                 |  102 
> ++++++++++++++++++++-
>  lib/odp-execute.h                                 |    2
>  lib/odp-util.c                                    |   55 +++++++++++
>  lib/packets.h                                     |   13 ++-
>  ofproto/ofproto-dpif-ipfix.c                      |    2
>  ofproto/ofproto-dpif-sflow.c                      |    2
>  ofproto/ofproto-dpif-xlate.c                      |   54 +++++++++--
>  ofproto/ofproto-dpif.c                            |   37 ++++++++
>  ofproto/ofproto-dpif.h                            |    6 +
>  12 files changed, 266 insertions(+), 23 deletions(-)
>
> diff --git a/datapath/linux/compat/include/linux/openvswitch.h 
> b/datapath/linux/compat/include/linux/openvswitch.h
> index 2d884312f..66c386462 100644
> --- a/datapath/linux/compat/include/linux/openvswitch.h
> +++ b/datapath/linux/compat/include/linux/openvswitch.h
> @@ -1021,6 +1021,8 @@ enum ovs_action_attr {
>         OVS_ACTION_ATTR_METER,        /* u32 meter number. */
>         OVS_ACTION_ATTR_CLONE,        /* Nested OVS_CLONE_ATTR_*.  */
>         OVS_ACTION_ATTR_CHECK_PKT_LEN, /* Nested OVS_CHECK_PKT_LEN_ATTR_*. */
> +       OVS_ACTION_ATTR_ADD_MPLS,      /* struct ovs_action_add_mpls. */
> +       OVS_ACTION_ATTR_DEC_TTL,       /* Nested OVS_DEC_TTL_ATTR_*. */
>
>  #ifndef __KERNEL__
>         OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
> @@ -1040,6 +1042,12 @@ enum ovs_action_attr {
>
>  #define OVS_ACTION_ATTR_MAX (__OVS_ACTION_ATTR_MAX - 1)
>
> +enum ovs_dec_ttl_attr {
> +       OVS_DEC_TTL_ATTR_UNSPEC,
> +       OVS_DEC_TTL_ATTR_ACTION,        /* Nested struct nlattr. */
> +       __OVS_DEC_TTL_ATTR_MAX
> +};
> +
>  /* Meters. */
>  #define OVS_METER_FAMILY  "ovs_meter"
>  #define OVS_METER_MCGROUP "ovs_meter"
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index 300861ca5..35c6560c3 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -7975,6 +7975,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
> *packets_,
>      case OVS_ACTION_ATTR_CT_CLEAR:
>      case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>      case OVS_ACTION_ATTR_DROP:
> +    case OVS_ACTION_ATTR_DEC_TTL:
> +    case OVS_ACTION_ATTR_ADD_MPLS:
>      case __OVS_ACTION_ATTR_MAX:
>          OVS_NOT_REACHED();
>      }
> @@ -7991,7 +7993,7 @@ dp_netdev_execute_actions(struct dp_netdev_pmd_thread 
> *pmd,
>      struct dp_netdev_execute_aux aux = { pmd, flow };
>
>      odp_execute_actions(&aux, packets, should_steal, actions,
> -                        actions_len, dp_execute_cb);
> +                        actions_len, dp_execute_cb, false);
>  }
>
>  struct dp_netdev_ct_dump {
> diff --git a/lib/dpif.c b/lib/dpif.c
> index ac2860764..644d32d47 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -1273,6 +1273,8 @@ dpif_execute_helper_cb(void *aux_, struct 
> dp_packet_batch *packets_,
>      case OVS_ACTION_ATTR_UNSPEC:
>      case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>      case OVS_ACTION_ATTR_DROP:
> +    case OVS_ACTION_ATTR_ADD_MPLS:
> +    case OVS_ACTION_ATTR_DEC_TTL:
>      case __OVS_ACTION_ATTR_MAX:
>          OVS_NOT_REACHED();
>      }
> @@ -1294,7 +1296,7 @@ dpif_execute_with_help(struct dpif *dpif, struct 
> dpif_execute *execute)
>
>      dp_packet_batch_init_packet(&pb, execute->packet);
>      odp_execute_actions(&aux, &pb, false, execute->actions,
> -                        execute->actions_len, dpif_execute_helper_cb);
> +                        execute->actions_len, dpif_execute_helper_cb, false);
>      return aux.error;
>  }
>
> diff --git a/lib/odp-execute.c b/lib/odp-execute.c
> index 6eeda2a61..237776448 100644
> --- a/lib/odp-execute.c
> +++ b/lib/odp-execute.c
> @@ -716,7 +716,58 @@ odp_execute_sample(void *dp, struct dp_packet *packet, 
> bool steal,
>      }
>      dp_packet_batch_init_packet(&pb, packet);
>      odp_execute_actions(dp, &pb, true, nl_attr_get(subactions),
> -                        nl_attr_get_size(subactions), dp_execute_action);
> +                        nl_attr_get_size(subactions), dp_execute_action,
> +                        false);
> +}
> +
> +static bool execute_dec_ttl(struct dp_packet *packet)
> +{
> +    struct eth_header *eth = dp_packet_eth(packet);
> +
> +    if (dl_type_is_ipv4(eth->eth_type)) {
> +        struct ip_header *nh = dp_packet_l3(packet);
> +        uint8_t old_ttl = nh->ip_ttl;
> +
> +        if (old_ttl <= 1) {
> +            return true;
> +        }
> +
> +        nh->ip_ttl--;
> +        nh->ip_csum = recalc_csum16(nh->ip_csum, htons(old_ttl << 8),
> +                                    htons(nh->ip_ttl << 8));
> +    } else if (dl_type_is_ipv6(eth->eth_type)) {
> +        struct ovs_16aligned_ip6_hdr *nh = dp_packet_l3(packet);
> +
> +        if (nh->ip6_hlim <= 1) {
> +            return true;
> +        }
> +
> +        nh->ip6_hlim--;
> +    }
> +
> +    return false;
> +}
> +
> +static void odp_dec_ttl_exception_handler(void *dp,
> +                                          struct dp_packet_batch *batch,
> +                                          const struct nlattr *action,
> +                                          odp_execute_cb dp_execute_action)
> +{
> +    const struct nlattr *a;
> +    const struct nlattr *subaction = NULL;
> +    size_t left;
> +
> +    if (nl_attr_is_valid(action, nl_attr_get_size(action))) {
> +        dp_packet_delete_batch(batch, true);
> +        return;
> +    }
> +
> +    NL_NESTED_FOR_EACH_UNSAFE (a, left, action) {
> +        subaction = a;
> +        odp_execute_actions(dp, batch, true, subaction,
> +                            nl_attr_get_size(subaction),
> +                            dp_execute_action, true);
> +    }
>  }
>
>  static void
> @@ -734,11 +785,13 @@ odp_execute_clone(void *dp, struct dp_packet_batch 
> *batch, bool steal,
>          dp_packet_batch_clone(&clone_pkt_batch, batch);
>          dp_packet_batch_reset_cutlen(batch);
>          odp_execute_actions(dp, &clone_pkt_batch, true, nl_attr_get(actions),
> -                        nl_attr_get_size(actions), dp_execute_action);
> +                            nl_attr_get_size(actions), dp_execute_action,
> +                            false);
>      }
>      else {
>          odp_execute_actions(dp, batch, true, nl_attr_get(actions),
> -                            nl_attr_get_size(actions), dp_execute_action);
> +                            nl_attr_get_size(actions), dp_execute_action,
> +                            false);
>      }
>  }
>
> @@ -783,7 +836,7 @@ odp_execute_check_pkt_len(void *dp, struct dp_packet 
> *packet, bool steal,
>       * odp_execute_actions. */
>      dp_packet_batch_init_packet(&pb, packet);
>      odp_execute_actions(dp, &pb, true, nl_attr_get(a), nl_attr_get_size(a),
> -                        dp_execute_action);
> +                        dp_execute_action, false);
>  }
>
>  static bool
> @@ -820,6 +873,8 @@ requires_datapath_assistance(const struct nlattr *a)
>      case OVS_ACTION_ATTR_CT_CLEAR:
>      case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>      case OVS_ACTION_ATTR_DROP:
> +    case OVS_ACTION_ATTR_ADD_MPLS:
> +    case OVS_ACTION_ATTR_DEC_TTL:
>          return false;
>
>      case OVS_ACTION_ATTR_UNSPEC:
> @@ -846,7 +901,7 @@ requires_datapath_assistance(const struct nlattr *a)
>  void
>  odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
>                      const struct nlattr *actions, size_t actions_len,
> -                    odp_execute_cb dp_execute_action)
> +                    odp_execute_cb dp_execute_action, bool force_last)
>  {
>      struct dp_packet *packet;
>      const struct nlattr *a;
> @@ -864,7 +919,8 @@ odp_execute_actions(void *dp, struct dp_packet_batch 
> *batch, bool steal,
>
>                  dp_execute_action(dp, batch, a, should_steal);
>
> -                if (last_action || dp_packet_batch_is_empty(batch)) {
> +                if (last_action || dp_packet_batch_is_empty(batch) ||
> +                    force_last) {
>                      /* We do not need to free the packets.
>                       * Either dp_execute_actions() has stolen them
>                       * or the batch is freed due to errors. In either

I don't remember the whole story, but I think that Ilya had some
concerns about force_last being redundant for 'steal'.
Sort of. Ilya, what's your opinion here?

> @@ -979,6 +1035,39 @@ odp_execute_actions(void *dp, struct dp_packet_batch 
> *batch, bool steal,
>              }
>              break;
>
> +        case OVS_ACTION_ATTR_DEC_TTL: {
> +            const size_t cnt = dp_packet_batch_size(batch);
> +            struct dp_packet_batch invalid_ttl;
> +            size_t i;
> +
> +            /* Make batch for invalid ttl packets. */
> +            dp_packet_batch_init(&invalid_ttl);
> +            invalid_ttl.trunc = batch->trunc;
> +            invalid_ttl.do_not_steal = batch->do_not_steal;
> +
> +            /* Add packets with ttl <=1 to the invalid_ttl batch
> +             * and remove it from the batch. */
> +            DP_PACKET_BATCH_REFILL_FOR_EACH (i, cnt, packet, batch) {
> +                if (execute_dec_ttl(packet)) {
> +                    dp_packet_batch_add(&invalid_ttl, packet);
> +                } else {
> +                    dp_packet_batch_refill(batch, packet, i);
> +                }
> +            }
> +
> +            /* Execute action on packets with ttl <= 1. */
> +            if (invalid_ttl.count > 0) {
> +                odp_dec_ttl_exception_handler(dp, &invalid_ttl, a,
> +                                              dp_execute_action);
> +            }
> +
> +            if (last_action || !batch->count) {
> +                /* We do not need to free the packets. */
> +                return;
> +            }
> +            break;
> +        }
> +
>          case OVS_ACTION_ATTR_TRUNC: {
>              const struct ovs_action_trunc *trunc =
>                          nl_attr_get_unspec(a, sizeof *trunc);
> @@ -1077,6 +1166,7 @@ odp_execute_actions(void *dp, struct dp_packet_batch 
> *batch, bool steal,
>          case OVS_ACTION_ATTR_RECIRC:
>          case OVS_ACTION_ATTR_CT:
>          case OVS_ACTION_ATTR_UNSPEC:
> +        case OVS_ACTION_ATTR_ADD_MPLS:
>          case __OVS_ACTION_ATTR_MAX:
>              OVS_NOT_REACHED();
>          }
> diff --git a/lib/odp-execute.h b/lib/odp-execute.h
> index a3578a575..3e80ed906 100644
> --- a/lib/odp-execute.h
> +++ b/lib/odp-execute.h
> @@ -38,5 +38,5 @@ typedef void (*odp_execute_cb)(void *dp, struct 
> dp_packet_batch *batch,
>  void odp_execute_actions(void *dp, struct dp_packet_batch *batch,
>                           bool steal,
>                           const struct nlattr *actions, size_t actions_len,
> -                         odp_execute_cb dp_execute_action);
> +                         odp_execute_cb dp_execute_action, bool force_last);
>  #endif
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index 0bd2f9aa8..62b7739de 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -143,8 +143,10 @@ odp_action_len(uint16_t type)
>      case OVS_ACTION_ATTR_POP_NSH: return 0;
>      case OVS_ACTION_ATTR_CHECK_PKT_LEN: return ATTR_LEN_VARIABLE;
>      case OVS_ACTION_ATTR_DROP: return sizeof(uint32_t);
> +    case OVS_ACTION_ATTR_DEC_TTL: return ATTR_LEN_VARIABLE;
>
>      case OVS_ACTION_ATTR_UNSPEC:
> +    case OVS_ACTION_ATTR_ADD_MPLS:
>      case __OVS_ACTION_ATTR_MAX:
>          return ATTR_LEN_INVALID;
>      }
> @@ -1108,6 +1110,38 @@ format_odp_check_pkt_len_action(struct ds *ds, const 
> struct nlattr *attr,
>                             portno_names);
>      ds_put_cstr(ds, "))");
>  }
> +static void
> +format_dec_ttl_action(struct ds *ds,const struct nlattr *attr,
> +                      const struct hmap *portno_names OVS_UNUSED)
> +{
> +    const struct nlattr *nla_acts = NULL;
> +    bool is_dp_netdev = false;
> +
> +    if (attr->nla_len == 4) {
> +        is_dp_netdev = true;
> +    } else {
> +        nla_acts = nl_attr_get(attr);
> +        if (nla_acts->nla_type != 1) {
> +            is_dp_netdev = true;
> +        }
> +    }
> +
> +    ds_put_cstr(ds,"dec_ttl(ttl<=1(");
> +    if (is_dp_netdev) {

Isn't it possible to encode the user and kernel actions in the same way?

> +        if (attr->nla_len == 4) {
> +            ds_put_format(ds, "drop");
> +        } else {
> +            format_odp_actions(ds, nla_acts, nla_acts->nla_len, 
> portno_names);
> +        }
> +    } else {
> +        int len = nl_attr_get_size(attr);
> +
> +        len -= nl_attr_len_pad(nla_acts, len);
> +        nla_acts = nl_attr_next(nla_acts);
> +        format_odp_actions(ds, nla_acts, len, portno_names);
> +    }
> +    ds_put_format(ds, "))");
> +}
>
>  static void
>  format_odp_action(struct ds *ds, const struct nlattr *a,
> @@ -1256,7 +1290,11 @@ format_odp_action(struct ds *ds, const struct nlattr 
> *a,
>      case OVS_ACTION_ATTR_DROP:
>          ds_put_cstr(ds, "drop");
>          break;
> +    case OVS_ACTION_ATTR_DEC_TTL:
> +        format_dec_ttl_action(ds, a, portno_names);
> +        break;
>      case OVS_ACTION_ATTR_UNSPEC:
> +    case OVS_ACTION_ATTR_ADD_MPLS:
>      case __OVS_ACTION_ATTR_MAX:
>      default:
>          format_generic_odp_action(ds, a);
> @@ -2498,6 +2536,23 @@ parse_odp_action__(struct parse_odp_context *context, 
> const char *s,
>              return n + 1;
>          }
>      }
> +    {
> +        if (!strncmp(s, "dec_ttl(ttl<=1(", 15)) {
> +            size_t actions_ofs;
> +            int n = 15;
> +
> +            actions_ofs = nl_msg_start_nested(actions,
> +                                              OVS_ACTION_ATTR_DEC_TTL);
> +            int retval = parse_action_list(context, s + n, actions);
> +            if (retval < 0) {
> +                return retval;
> +            }
> +
> +            n += retval;
> +            nl_msg_end_nested(actions, actions_ofs);
> +            return n + 1;
> +        }
> +    }
>
>      {
>          if (!strncmp(s, "push_nsh(", 9)) {
> diff --git a/lib/packets.h b/lib/packets.h
> index 481bc22fa..b7fa7b121 100644
> --- a/lib/packets.h
> +++ b/lib/packets.h
> @@ -1211,10 +1211,19 @@ bool in6_is_lla(struct in6_addr *addr);
>  void ipv6_multicast_to_ethernet(struct eth_addr *eth,
>                                  const struct in6_addr *ip6);
>
> +static inline bool dl_type_is_ipv4(ovs_be16 dl_type)
> +{
> +    return dl_type == htons(ETH_TYPE_IP);
> +}
> +
> +static inline bool dl_type_is_ipv6(ovs_be16 dl_type)
> +{
> +    return dl_type == htons(ETH_TYPE_IPV6);
> +}
> +
>  static inline bool dl_type_is_ip_any(ovs_be16 dl_type)
>  {
> -    return dl_type == htons(ETH_TYPE_IP)
> -        || dl_type == htons(ETH_TYPE_IPV6);
> +    return dl_type_is_ipv4(dl_type) || dl_type_is_ipv6(dl_type);
>  }
>
>  /* Tunnel header */
> diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
> index 796eb6f88..1c8e7ae26 100644
> --- a/ofproto/ofproto-dpif-ipfix.c
> +++ b/ofproto/ofproto-dpif-ipfix.c
> @@ -3018,6 +3018,8 @@ dpif_ipfix_read_actions(const struct flow *flow,
>          case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>          case OVS_ACTION_ATTR_UNSPEC:
>          case OVS_ACTION_ATTR_DROP:
> +        case OVS_ACTION_ATTR_ADD_MPLS:
> +        case OVS_ACTION_ATTR_DEC_TTL:
>          case __OVS_ACTION_ATTR_MAX:
>          default:
>              break;
> diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
> index fdcb9eabb..c8bf6bee4 100644
> --- a/ofproto/ofproto-dpif-sflow.c
> +++ b/ofproto/ofproto-dpif-sflow.c
> @@ -1178,6 +1178,7 @@ dpif_sflow_read_actions(const struct flow *flow,
>          case OVS_ACTION_ATTR_CT_CLEAR:
>          case OVS_ACTION_ATTR_METER:
>          case OVS_ACTION_ATTR_LB_OUTPUT:
> +        case OVS_ACTION_ATTR_DEC_TTL:
>              break;
>
>          case OVS_ACTION_ATTR_SET_MASKED:
> @@ -1226,6 +1227,7 @@ dpif_sflow_read_actions(const struct flow *flow,
>          case OVS_ACTION_ATTR_UNSPEC:
>          case OVS_ACTION_ATTR_CHECK_PKT_LEN:
>          case OVS_ACTION_ATTR_DROP:
> +        case OVS_ACTION_ATTR_ADD_MPLS:
>          case __OVS_ACTION_ATTR_MAX:
>          default:
>              break;
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index 11aa20754..a1fd1c752 100644
> --- a/ofproto/ofproto-dpif-xlate.c
> +++ b/ofproto/ofproto-dpif-xlate.c
> @@ -4839,9 +4839,12 @@ xlate_controller_action(struct xlate_ctx *ctx, int len,
>                          enum ofp_packet_in_reason reason,
>                          uint16_t controller_id,
>                          uint32_t provider_meter_id,
> -                        const uint8_t *userdata, size_t userdata_len)
> +                        const uint8_t *userdata, size_t userdata_len,
> +                        bool commit)
>  {
> -    xlate_commit_actions(ctx);
> +    if (commit) {
> +        xlate_commit_actions(ctx);
> +    }
>
>      /* A packet sent by an action in a table-miss rule is considered an
>       * explicit table miss.  OpenFlow before 1.3 doesn't have that concept so
> @@ -5087,7 +5090,8 @@ compose_dec_ttl(struct xlate_ctx *ctx, struct 
> ofpact_cnt_ids *ids)
>
>          for (i = 0; i < ids->n_controllers; i++) {
>              xlate_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL,
> -                                    ids->cnt_ids[i], UINT32_MAX, NULL, 0);
> +                                    ids->cnt_ids[i], UINT32_MAX, NULL, 0,
> +                                    true);
>          }
>
>          /* Stop processing for current table. */
> @@ -5128,7 +5132,7 @@ compose_dec_nsh_ttl_action(struct xlate_ctx *ctx)
>              return false;
>          } else {
>              xlate_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL,
> -                                    0, UINT32_MAX, NULL, 0);
> +                                    0, UINT32_MAX, NULL, 0, true);
>          }
>      }
>
> @@ -5161,7 +5165,7 @@ compose_dec_mpls_ttl_action(struct xlate_ctx *ctx)
>              return false;
>          } else {
>              xlate_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0,
> -                                    UINT32_MAX, NULL, 0);
> +                                    UINT32_MAX, NULL, 0, true);
>          }
>      }
>
> @@ -5185,6 +5189,37 @@ xlate_delete_field(struct xlate_ctx *ctx,
>      ds_destroy(&s);
>  }
>
> +/* New handling for dec_ttl action. */
> +static void
> +xlate_dec_ttl_action(struct xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
> +{
> +    struct flow *flow = &ctx->xin->flow;
> +    struct flow_wildcards *wc = ctx->wc;
> +    size_t offset;
> +    size_t i;
> +
> +    if (!is_ip_any(flow)) {
> +        return;
> +    }
> +
> +    if (!ctx->xbridge->support.dec_ttl_action) {
> +        wc->masks.nw_ttl = 0xff;
> +        compose_dec_ttl(ctx, ids);
> +        return;
> +    }
> +
> +    xlate_commit_actions(ctx);
> +    offset = nl_msg_start_nested(ctx->odp_actions, OVS_ACTION_ATTR_DEC_TTL);
> +
> +    for (i = 0; i < ids->n_controllers; i++) {
> +        xlate_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL,
> +                                ids->cnt_ids[i], UINT32_MAX, NULL, 0, false);
> +    }
> +
> +    nl_msg_end_nested(ctx->odp_actions, offset);
> +    xlate_commit_actions(ctx);
> +}
> +
>  /* Emits an action that outputs to 'port', within 'ctx'.
>   *
>   * 'controller_len' affects only packets sent to an OpenFlow controller.  It
> @@ -5235,7 +5270,7 @@ xlate_output_action(struct xlate_ctx *ctx, ofp_port_t 
> port,
>                                   : group_bucket_action ? OFPR_GROUP
>                                   : ctx->in_action_set ? OFPR_ACTION_SET
>                                   : OFPR_ACTION),
> -                                0, UINT32_MAX, NULL, 0);
> +                                0, UINT32_MAX, NULL, 0, true);
>          break;
>      case OFPP_NONE:
>          break;
> @@ -6796,7 +6831,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
> ofpacts_len,
>                                          controller->controller_id,
>                                          controller->provider_meter_id,
>                                          controller->userdata,
> -                                        controller->userdata_len);
> +                                        controller->userdata_len, true);
>              }
>              break;
>
> @@ -7004,10 +7039,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t 
> ofpacts_len,
>              break;
>
>          case OFPACT_DEC_TTL:
> -            wc->masks.nw_ttl = 0xff;
> -            if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
> -                return;
> -            }
> +            xlate_dec_ttl_action(ctx, ofpact_get_DEC_TTL(a));
>              break;
>
>          case OFPACT_NOTE:
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index fd0b2fdea..68e161e5f 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -1186,6 +1186,42 @@ check_trunc_action(struct dpif_backer *backer)
>      return !error;
>  }
>
> +/* Tests whether 'dpif' datapath supports decrement of the IP TTL via
> + * OVS_ACTION_DEC_TTL. */
> +static bool
> +check_dec_ttl_action(struct dpif *dpif)
> +{
> +    uint8_t actbuf[NL_A_FLAG_SIZE];
> +    struct odputil_keybuf keybuf;
> +    struct flow flow = { 0 };
> +    struct ofpbuf actions;
> +    struct ofpbuf key;
> +    bool supported;
> +
> +    struct odp_flow_key_parms odp_parms = {
> +        .flow = &flow,
> +        .probe = true,
> +    };
> +
> +    ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
> +    odp_flow_key_from_flow(&odp_parms, &key);
> +
> +    ofpbuf_use_stack(&actions, &actbuf, sizeof actbuf);
> +    nl_msg_put_flag(&actions, OVS_ACTION_ATTR_DEC_TTL);
> +
> +    supported = dpif_probe_feature(dpif, "dec_ttl", &key, &actions, NULL);
> +
> +    if (supported) {
> +        VLOG_INFO("%s: Datapath supports dec_ttl action",
> +                  dpif_name(dpif));
> +    } else {
> +        VLOG_INFO("%s: Datapath does not support dec_ttl action",
> +                  dpif_name(dpif));
> +    }
> +
> +    return supported;
> +}
> +
>  /* Tests whether 'backer''s datapath supports the clone action
>   * OVS_ACTION_ATTR_CLONE.   */
>  static bool
> @@ -1590,6 +1626,7 @@ check_support(struct dpif_backer *backer)
>          dpif_supports_explicit_drop_action(backer->dpif);
>      backer->rt_support.lb_output_action=
>          dpif_supports_lb_output_action(backer->dpif);
> +    backer->rt_support.dec_ttl_action = check_dec_ttl_action(backer->dpif);
>
>      /* Flow fields. */
>      backer->rt_support.odp.ct_state = check_ct_state(backer);
> diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
> index b41c3d82a..f4d1152bc 100644
> --- a/ofproto/ofproto-dpif.h
> +++ b/ofproto/ofproto-dpif.h
> @@ -204,7 +204,11 @@ struct group_dpif *group_dpif_lookup(struct ofproto_dpif 
> *,
>      DPIF_SUPPORT_FIELD(bool, explicit_drop_action, "Explicit Drop action")  \
>                                                                              \
>      /* True if the datapath supports balance_tcp optimization */            \
> -    DPIF_SUPPORT_FIELD(bool, lb_output_action, "Optimized Balance TCP mode")
> +    DPIF_SUPPORT_FIELD(bool, lb_output_action, "Optimized Balance TCP mode")\
> +                                                                            \
> +    /* True if the datapath supports dec_ttl action. */                     \
> +    DPIF_SUPPORT_FIELD(bool, dec_ttl_action, "Decrement TTL action")
> +
>
>
>  /* Stores the various features which the corresponding backer supports. */
>

For the remaining part, LGTM.

Regards,
-- 
per aspera ad upstream
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to