Skip to content

Commit

Permalink
datapath: Add a new action dec_ttl
Browse files Browse the repository at this point in the history
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 <mcroce@linux.microsoft.com>
Co-developed-by: Bindiya Kurle <bindiyakurle@gmail.com>
Signed-off-by: Eelco Chaudron <echaudro@redhat.com>
Signed-off-by: 0-day Robot <robot@bytheb.org>
  • Loading branch information
chaudron authored and ovsrobot committed Nov 11, 2020
1 parent 193995f commit 3c0c8ad
Show file tree
Hide file tree
Showing 12 changed files with 266 additions and 23 deletions.
8 changes: 8 additions & 0 deletions datapath/linux/compat/include/linux/openvswitch.h
Expand Up @@ -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*/
Expand All @@ -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"
Expand Down
4 changes: 3 additions & 1 deletion lib/dpif-netdev.c
Expand Up @@ -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();
}
Expand All @@ -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 {
Expand Down
4 changes: 3 additions & 1 deletion lib/dpif.c
Expand Up @@ -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();
}
Expand All @@ -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;
}

Expand Down
102 changes: 96 additions & 6 deletions lib/odp-execute.c
Expand Up @@ -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
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion lib/odp-execute.h
Expand Up @@ -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
55 changes: 55 additions & 0 deletions lib/odp-util.c
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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) {
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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)) {
Expand Down
13 changes: 11 additions & 2 deletions lib/packets.h
Expand Up @@ -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 */
Expand Down
2 changes: 2 additions & 0 deletions ofproto/ofproto-dpif-ipfix.c
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions ofproto/ofproto-dpif-sflow.c
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 3c0c8ad

Please sign in to comment.