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