mirror of
https://github.com/openvswitch/ovs
synced 2025-08-30 22:05:19 +00:00
netdev-offload-tc: Add conntrack support
Zone and ct_state first. Signed-off-by: Paul Blakey <paulb@mellanox.com> Reviewed-by: Roi Dayan <roid@mellanox.com> Signed-off-by: Simon Horman <simon.horman@netronome.com>
This commit is contained in:
committed by
Simon Horman
parent
b2ae40690e
commit
576126a931
@@ -1643,6 +1643,8 @@ dpif_netlink_netdev_match_to_dpif_flow(struct match *match,
|
||||
.support = {
|
||||
.max_vlan_headers = 2,
|
||||
.recirc = true,
|
||||
.ct_state = true,
|
||||
.ct_zone = true,
|
||||
},
|
||||
};
|
||||
size_t offset;
|
||||
|
@@ -595,6 +595,35 @@ parse_tc_flower_to_match(struct tc_flower *flower,
|
||||
match_set_tp_dst_masked(match, key->sctp_dst, mask->sctp_dst);
|
||||
match_set_tp_src_masked(match, key->sctp_src, mask->sctp_src);
|
||||
}
|
||||
|
||||
if (mask->ct_state) {
|
||||
uint8_t ct_statev = 0, ct_statem = 0;
|
||||
|
||||
if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_NEW) {
|
||||
if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_NEW) {
|
||||
ct_statev |= OVS_CS_F_NEW;
|
||||
}
|
||||
ct_statem |= OVS_CS_F_NEW;
|
||||
}
|
||||
|
||||
if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) {
|
||||
if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) {
|
||||
ct_statev |= OVS_CS_F_ESTABLISHED;
|
||||
}
|
||||
ct_statem |= OVS_CS_F_ESTABLISHED;
|
||||
}
|
||||
|
||||
if (mask->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED) {
|
||||
if (key->ct_state & TCA_FLOWER_KEY_CT_FLAGS_TRACKED) {
|
||||
ct_statev |= OVS_CS_F_TRACKED;
|
||||
}
|
||||
ct_statem |= OVS_CS_F_TRACKED;
|
||||
}
|
||||
|
||||
match_set_ct_state_masked(match, ct_statev, ct_statem);
|
||||
}
|
||||
|
||||
match_set_ct_zone_masked(match, key->ct_zone, mask->ct_zone);
|
||||
}
|
||||
|
||||
if (flower->tunnel) {
|
||||
@@ -746,6 +775,27 @@ parse_tc_flower_to_match(struct tc_flower *flower,
|
||||
nl_msg_put_u32(buf, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(outport));
|
||||
}
|
||||
break;
|
||||
case TC_ACT_CT: {
|
||||
size_t ct_offset;
|
||||
|
||||
if (action->ct.clear) {
|
||||
nl_msg_put_flag(buf, OVS_ACTION_ATTR_CT_CLEAR);
|
||||
break;
|
||||
}
|
||||
|
||||
ct_offset = nl_msg_start_nested(buf, OVS_ACTION_ATTR_CT);
|
||||
|
||||
if (action->ct.commit) {
|
||||
nl_msg_put_flag(buf, OVS_CT_ATTR_COMMIT);
|
||||
}
|
||||
|
||||
if (action->ct.zone) {
|
||||
nl_msg_put_u16(buf, OVS_CT_ATTR_ZONE, action->ct.zone);
|
||||
}
|
||||
|
||||
nl_msg_end_nested(buf, ct_offset);
|
||||
}
|
||||
break;
|
||||
case TC_ACT_GOTO: {
|
||||
nl_msg_put_u32(buf, OVS_ACTION_ATTR_RECIRC, action->chain);
|
||||
}
|
||||
@@ -834,6 +884,33 @@ parse_mpls_set_action(struct tc_flower *flower, struct tc_action *action,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_put_flow_ct_action(struct tc_flower *flower,
|
||||
struct tc_action *action,
|
||||
const struct nlattr *ct,
|
||||
size_t ct_len)
|
||||
{
|
||||
const struct nlattr *ct_attr;
|
||||
size_t ct_left;
|
||||
|
||||
NL_ATTR_FOR_EACH_UNSAFE (ct_attr, ct_left, ct, ct_len) {
|
||||
switch (nl_attr_type(ct_attr)) {
|
||||
case OVS_CT_ATTR_COMMIT: {
|
||||
action->ct.commit = true;
|
||||
}
|
||||
break;
|
||||
case OVS_CT_ATTR_ZONE: {
|
||||
action->ct.zone = nl_attr_get_u16(ct_attr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
action->type = TC_ACT_CT;
|
||||
flower->action_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_put_flow_set_masked_action(struct tc_flower *flower,
|
||||
struct tc_action *action,
|
||||
@@ -1016,16 +1093,6 @@ test_key_and_mask(struct match *match)
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (mask->ct_state) {
|
||||
VLOG_DBG_RL(&rl, "offloading attribute ct_state isn't supported");
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (mask->ct_zone) {
|
||||
VLOG_DBG_RL(&rl, "offloading attribute ct_zone isn't supported");
|
||||
return EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (mask->ct_mark) {
|
||||
VLOG_DBG_RL(&rl, "offloading attribute ct_mark isn't supported");
|
||||
return EOPNOTSUPP;
|
||||
@@ -1365,6 +1432,42 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
|
||||
}
|
||||
}
|
||||
|
||||
if (mask->ct_state) {
|
||||
if (mask->ct_state & OVS_CS_F_NEW) {
|
||||
if (key->ct_state & OVS_CS_F_NEW) {
|
||||
flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW;
|
||||
}
|
||||
flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_NEW;
|
||||
}
|
||||
|
||||
if (mask->ct_state & OVS_CS_F_ESTABLISHED) {
|
||||
if (key->ct_state & OVS_CS_F_ESTABLISHED) {
|
||||
flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED;
|
||||
}
|
||||
flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED;
|
||||
}
|
||||
|
||||
if (mask->ct_state & OVS_CS_F_TRACKED) {
|
||||
if (key->ct_state & OVS_CS_F_TRACKED) {
|
||||
flower.key.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
|
||||
}
|
||||
flower.mask.ct_state |= TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
|
||||
}
|
||||
|
||||
if (flower.key.ct_state & TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED) {
|
||||
flower.key.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW);
|
||||
flower.mask.ct_state &= ~(TCA_FLOWER_KEY_CT_FLAGS_NEW);
|
||||
}
|
||||
|
||||
mask->ct_state = 0;
|
||||
}
|
||||
|
||||
if (mask->ct_zone) {
|
||||
flower.key.ct_zone = key->ct_zone;
|
||||
flower.mask.ct_zone = mask->ct_zone;
|
||||
mask->ct_zone = 0;
|
||||
}
|
||||
|
||||
err = test_key_and_mask(match);
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -1431,6 +1534,18 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT) {
|
||||
const struct nlattr *ct = nl_attr_get(nla);
|
||||
const size_t ct_len = nl_attr_get_size(nla);
|
||||
|
||||
err = parse_put_flow_ct_action(&flower, action, ct, ct_len);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
} else if (nl_attr_type(nla) == OVS_ACTION_ATTR_CT_CLEAR) {
|
||||
action->type = TC_ACT_CT;
|
||||
action->ct.clear = true;
|
||||
flower.action_count++;
|
||||
} else if (nl_attr_type(nla) == OVS_ACTION_ATTR_RECIRC) {
|
||||
action->type = TC_ACT_GOTO;
|
||||
action->chain = nl_attr_get_u32(nla);
|
||||
|
122
lib/tc.c
122
lib/tc.c
@@ -30,6 +30,7 @@
|
||||
#include <linux/tc_act/tc_skbedit.h>
|
||||
#include <linux/tc_act/tc_tunnel_key.h>
|
||||
#include <linux/tc_act/tc_vlan.h>
|
||||
#include <linux/tc_act/tc_ct.h>
|
||||
#include <linux/gen_stats.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
@@ -399,6 +400,10 @@ static const struct nl_policy tca_flower_policy[] = {
|
||||
[TCA_FLOWER_KEY_ENC_OPTS] = { .type = NL_A_NESTED, .optional = true, },
|
||||
[TCA_FLOWER_KEY_ENC_OPTS_MASK] = { .type = NL_A_NESTED,
|
||||
.optional = true, },
|
||||
[TCA_FLOWER_KEY_CT_STATE] = { .type = NL_A_U16, .optional = true, },
|
||||
[TCA_FLOWER_KEY_CT_STATE_MASK] = { .type = NL_A_U16, .optional = true, },
|
||||
[TCA_FLOWER_KEY_CT_ZONE] = { .type = NL_A_U16, .optional = true, },
|
||||
[TCA_FLOWER_KEY_CT_ZONE_MASK] = { .type = NL_A_U16, .optional = true, },
|
||||
};
|
||||
|
||||
static void
|
||||
@@ -708,6 +713,27 @@ nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
nl_parse_flower_ct_match(struct nlattr **attrs, struct tc_flower *flower) {
|
||||
struct tc_flower_key *key = &flower->key;
|
||||
struct tc_flower_key *mask = &flower->mask;
|
||||
struct nlattr *attr_key, *attr_mask;
|
||||
|
||||
attr_key = attrs[TCA_FLOWER_KEY_CT_STATE];
|
||||
attr_mask = attrs[TCA_FLOWER_KEY_CT_STATE_MASK];
|
||||
if (attr_mask) {
|
||||
key->ct_state = nl_attr_get_u16(attr_key);
|
||||
mask->ct_state = nl_attr_get_u16(attr_mask);
|
||||
}
|
||||
|
||||
attr_key = attrs[TCA_FLOWER_KEY_CT_ZONE];
|
||||
attr_mask = attrs[TCA_FLOWER_KEY_CT_ZONE_MASK];
|
||||
if (attrs[TCA_FLOWER_KEY_CT_ZONE_MASK]) {
|
||||
key->ct_zone = nl_attr_get_u16(attr_key);
|
||||
mask->ct_zone = nl_attr_get_u16(attr_mask);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {
|
||||
uint8_t ip_proto = 0;
|
||||
@@ -805,6 +831,8 @@ nl_parse_flower_ip(struct nlattr **attrs, struct tc_flower *flower) {
|
||||
key->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS]);
|
||||
mask->ip_tos = nl_attr_get_u8(attrs[TCA_FLOWER_KEY_IP_TOS_MASK]);
|
||||
}
|
||||
|
||||
nl_parse_flower_ct_match(attrs, flower);
|
||||
}
|
||||
|
||||
static enum tc_offloaded_state
|
||||
@@ -1225,6 +1253,54 @@ nl_parse_act_mirred(struct nlattr *options, struct tc_flower *flower)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nl_policy ct_policy[] = {
|
||||
[TCA_CT_PARMS] = { .type = NL_A_UNSPEC,
|
||||
.min_len = sizeof(struct tc_ct),
|
||||
.optional = false, },
|
||||
[TCA_CT_ACTION] = { .type = NL_A_U16,
|
||||
.optional = true, },
|
||||
[TCA_CT_ZONE] = { .type = NL_A_U16,
|
||||
.optional = true, },
|
||||
};
|
||||
|
||||
static int
|
||||
nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
|
||||
{
|
||||
struct nlattr *ct_attrs[ARRAY_SIZE(ct_policy)];
|
||||
const struct nlattr *ct_parms;
|
||||
struct tc_action *action;
|
||||
const struct tc_ct *ct;
|
||||
uint16_t ct_action = 0;
|
||||
|
||||
if (!nl_parse_nested(options, ct_policy, ct_attrs,
|
||||
ARRAY_SIZE(ct_policy))) {
|
||||
VLOG_ERR_RL(&error_rl, "failed to parse ct action options");
|
||||
return EPROTO;
|
||||
}
|
||||
|
||||
ct_parms = ct_attrs[TCA_CT_PARMS];
|
||||
ct = nl_attr_get_unspec(ct_parms, sizeof *ct);
|
||||
|
||||
if (ct_attrs[TCA_CT_ACTION]) {
|
||||
ct_action = nl_attr_get_u16(ct_attrs[TCA_CT_ACTION]);
|
||||
}
|
||||
|
||||
action = &flower->actions[flower->action_count++];
|
||||
action->ct.clear = ct_action & TCA_CT_ACT_CLEAR;
|
||||
if (!action->ct.clear) {
|
||||
struct nlattr *zone = ct_attrs[TCA_CT_ZONE];
|
||||
|
||||
action->ct.commit = ct_action & TCA_CT_ACT_COMMIT;
|
||||
action->ct.force = ct_action & TCA_CT_ACT_FORCE;
|
||||
|
||||
action->ct.zone = zone ? nl_attr_get_u16(zone) : 0;
|
||||
|
||||
}
|
||||
action->type = TC_ACT_CT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nl_policy vlan_policy[] = {
|
||||
[TCA_VLAN_PARMS] = { .type = NL_A_UNSPEC,
|
||||
.min_len = sizeof(struct tc_vlan),
|
||||
@@ -1455,6 +1531,8 @@ nl_parse_single_action(struct nlattr *action, struct tc_flower *flower)
|
||||
nl_parse_act_csum(act_options, flower);
|
||||
} else if (!strcmp(act_kind, "skbedit")) {
|
||||
/* Added for TC rule only (not in OvS rule) so ignore. */
|
||||
} else if (!strcmp(act_kind, "ct")) {
|
||||
nl_parse_act_ct(act_options, flower);
|
||||
} else {
|
||||
VLOG_ERR_RL(&error_rl, "unknown tc action kind: %s", act_kind);
|
||||
err = EINVAL;
|
||||
@@ -1909,6 +1987,40 @@ nl_msg_put_act_gact(struct ofpbuf *request, uint32_t chain)
|
||||
nl_msg_end_nested(request, offset);
|
||||
}
|
||||
|
||||
static void
|
||||
nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action)
|
||||
{
|
||||
uint16_t ct_action = 0;
|
||||
size_t offset;
|
||||
|
||||
nl_msg_put_string(request, TCA_ACT_KIND, "ct");
|
||||
offset = nl_msg_start_nested(request, TCA_ACT_OPTIONS | NLA_F_NESTED);
|
||||
{
|
||||
struct tc_ct ct = {
|
||||
.action = TC_ACT_PIPE,
|
||||
};
|
||||
|
||||
if (!action->ct.clear) {
|
||||
if (action->ct.zone) {
|
||||
nl_msg_put_u16(request, TCA_CT_ZONE, action->ct.zone);
|
||||
}
|
||||
|
||||
if (action->ct.commit) {
|
||||
ct_action = TCA_CT_ACT_COMMIT;
|
||||
if (action->ct.force) {
|
||||
ct_action |= TCA_CT_ACT_FORCE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ct_action = TCA_CT_ACT_CLEAR;
|
||||
}
|
||||
|
||||
nl_msg_put_u16(request, TCA_CT_ACTION, ct_action);
|
||||
nl_msg_put_unspec(request, TCA_CT_PARMS, &ct, sizeof ct);
|
||||
}
|
||||
nl_msg_end_nested(request, offset);
|
||||
}
|
||||
|
||||
static void
|
||||
nl_msg_put_act_skbedit_to_host(struct ofpbuf *request)
|
||||
{
|
||||
@@ -2266,6 +2378,13 @@ nl_msg_put_flower_acts(struct ofpbuf *request, struct tc_flower *flower)
|
||||
nl_msg_end_nested(request, act_offset);
|
||||
}
|
||||
break;
|
||||
case TC_ACT_CT: {
|
||||
act_offset = nl_msg_start_nested(request, act_index++);
|
||||
nl_msg_put_act_ct(request, action);
|
||||
nl_msg_put_act_cookie(request, &flower->act_cookie);
|
||||
nl_msg_end_nested(request, act_offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2433,6 +2552,9 @@ nl_msg_put_flower_options(struct ofpbuf *request, struct tc_flower *flower)
|
||||
FLOWER_PUT_MASKED_VALUE(sctp_src, TCA_FLOWER_KEY_SCTP_SRC);
|
||||
FLOWER_PUT_MASKED_VALUE(sctp_dst, TCA_FLOWER_KEY_SCTP_DST);
|
||||
}
|
||||
|
||||
FLOWER_PUT_MASKED_VALUE(ct_state, TCA_FLOWER_KEY_CT_STATE);
|
||||
FLOWER_PUT_MASKED_VALUE(ct_zone, TCA_FLOWER_KEY_CT_ZONE);
|
||||
}
|
||||
|
||||
if (host_eth_type == ETH_P_IP) {
|
||||
|
11
lib/tc.h
11
lib/tc.h
@@ -116,6 +116,9 @@ struct tc_flower_key {
|
||||
uint8_t ip_ttl;
|
||||
uint8_t ip_tos;
|
||||
|
||||
uint16_t ct_state;
|
||||
uint16_t ct_zone;
|
||||
|
||||
struct {
|
||||
ovs_be32 ipv4_src;
|
||||
ovs_be32 ipv4_dst;
|
||||
@@ -157,6 +160,7 @@ enum tc_action_type {
|
||||
TC_ACT_MPLS_PUSH,
|
||||
TC_ACT_MPLS_SET,
|
||||
TC_ACT_GOTO,
|
||||
TC_ACT_CT,
|
||||
};
|
||||
|
||||
struct tc_action {
|
||||
@@ -200,6 +204,13 @@ struct tc_action {
|
||||
} ipv6;
|
||||
struct tun_metadata data;
|
||||
} encap;
|
||||
|
||||
struct {
|
||||
uint16_t zone;
|
||||
bool clear;
|
||||
bool force;
|
||||
bool commit;
|
||||
} ct;
|
||||
};
|
||||
|
||||
enum tc_action_type type;
|
||||
|
Reference in New Issue
Block a user