[ovs-dev] [PATCH v3 2/3] netdev-offload-tc: Probe for support for any of the ct_state flags
Paul Blakey
paulb at nvidia.com
Sun Mar 7 14:22:02 UTC 2021
Upstream kernel now rejects unsupported ct_state flags.
Earlier kernels, ignored it but still echoed back the requested ct_state,
if ct_state was supported. ct_state initial support had trk, new, est,
and rel flags.
If kernel echos back ct_state, assume support for trk, new, est, and
rel. If kernel rejects a specific unsupported flag, continue and
use reject mechanisim to probe for flags rep and inv.
Disallow inserting rules with unnsupported ct_state flags.
Signed-off-by: Paul Blakey <paulb at nvidia.com>
Acked-by: Roi Dayan <roid at nvidia.com>
---
lib/netdev-offload-tc.c | 205 ++++++++++++++++++++++++++++++++++++------------
1 file changed, 157 insertions(+), 48 deletions(-)
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index 04b5e21..5eae09f 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -48,6 +48,7 @@ static struct hmap ufid_to_tc = HMAP_INITIALIZER(&ufid_to_tc);
static struct hmap tc_to_ufid = HMAP_INITIALIZER(&tc_to_ufid);
static bool multi_mask_per_prio = false;
static bool block_support = false;
+static uint16_t ct_state_support;
struct netlink_field {
int offset;
@@ -1456,6 +1457,66 @@ flower_match_to_tun_opt(struct tc_flower *flower, const struct flow_tnl *tnl,
flower->mask.tunnel.metadata.present.len = tnl->metadata.present.len;
}
+static void
+parse_match_ct_state_to_flower(struct tc_flower *flower, struct match *match)
+{
+ const struct flow *key = &match->flow;
+ struct flow *mask = &match->wc.masks;
+
+ if (!ct_state_support) {
+ return;
+ }
+
+ if ((ct_state_support & mask->ct_state) == 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;
+ mask->ct_state &= ~OVS_CS_F_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;
+ mask->ct_state &= ~OVS_CS_F_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;
+ mask->ct_state &= ~OVS_CS_F_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);
+ }
+ }
+
+ if (mask->ct_zone) {
+ flower->key.ct_zone = key->ct_zone;
+ flower->mask.ct_zone = mask->ct_zone;
+ mask->ct_zone = 0;
+ }
+
+ if (mask->ct_mark) {
+ flower->key.ct_mark = key->ct_mark;
+ flower->mask.ct_mark = mask->ct_mark;
+ mask->ct_mark = 0;
+ }
+
+ if (!ovs_u128_is_zero(mask->ct_label)) {
+ flower->key.ct_label = key->ct_label;
+ flower->mask.ct_label = mask->ct_label;
+ mask->ct_label = OVS_U128_ZERO;
+ }
+}
+
static int
netdev_tc_flow_put(struct netdev *netdev, struct match *match,
struct nlattr *actions, size_t actions_len,
@@ -1708,54 +1769,7 @@ 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;
- mask->ct_state &= ~OVS_CS_F_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;
- mask->ct_state &= ~OVS_CS_F_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;
- mask->ct_state &= ~OVS_CS_F_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);
- }
- }
-
- if (mask->ct_zone) {
- flower.key.ct_zone = key->ct_zone;
- flower.mask.ct_zone = mask->ct_zone;
- mask->ct_zone = 0;
- }
-
- if (mask->ct_mark) {
- flower.key.ct_mark = key->ct_mark;
- flower.mask.ct_mark = mask->ct_mark;
- mask->ct_mark = 0;
- }
-
- if (!ovs_u128_is_zero(mask->ct_label)) {
- flower.key.ct_label = key->ct_label;
- flower.mask.ct_label = mask->ct_label;
- mask->ct_label = OVS_U128_ZERO;
- }
+ parse_match_ct_state_to_flower(&flower, match);
/* ignore exact match on skb_mark of 0. */
if (mask->pkt_mark == UINT32_MAX && !key->pkt_mark) {
@@ -1837,6 +1851,10 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
const struct nlattr *ct = nl_attr_get(nla);
const size_t ct_len = nl_attr_get_size(nla);
+ if (!ct_state_support) {
+ return -EOPNOTSUPP;
+ }
+
err = parse_put_flow_ct_action(&flower, action, ct, ct_len);
if (err) {
return err;
@@ -2029,6 +2047,96 @@ out:
tc_add_del_qdisc(ifindex, false, block_id, TC_INGRESS);
}
+
+static int
+probe_insert_ct_state_rule(int ifindex, uint16_t ct_state, struct tcf_id *id)
+{
+ int prio = TC_RESERVED_PRIORITY_MAX + 1;
+ struct tc_flower flower;
+
+ memset(&flower, 0, sizeof flower);
+ flower.key.ct_state = ct_state;
+ flower.mask.ct_state = ct_state;
+ flower.tc_policy = TC_POLICY_SKIP_HW;
+ flower.key.eth_type = htons(ETH_P_IP);
+ flower.mask.eth_type = OVS_BE16_MAX;
+
+ *id = tc_make_tcf_id(ifindex, 0, prio, TC_INGRESS);
+ return tc_replace_flower(id, &flower);
+}
+
+static void
+probe_ct_state_support(int ifindex)
+{
+ struct tc_flower flower;
+ uint16_t ct_state;
+ struct tcf_id id;
+ int error;
+
+ error = tc_add_del_qdisc(ifindex, true, 0, TC_INGRESS);
+ if (error) {
+ return;
+ }
+
+ /* Test for base ct_state match support */
+ ct_state = TCA_FLOWER_KEY_CT_FLAGS_NEW | TCA_FLOWER_KEY_CT_FLAGS_TRACKED;
+ error = probe_insert_ct_state_rule(ifindex, ct_state, &id);
+ if (error) {
+ goto out;
+ }
+
+ error = tc_get_flower(&id, &flower);
+ if (error || flower.mask.ct_state != ct_state) {
+ goto out_del;
+ }
+
+ tc_del_filter(&id);
+ ct_state_support = OVS_CS_F_NEW |
+ OVS_CS_F_ESTABLISHED |
+ OVS_CS_F_TRACKED |
+ OVS_CS_F_RELATED;
+
+ /* Test for reject, ct_state >= MAX */
+ ct_state = ~0;
+ error = probe_insert_ct_state_rule(ifindex, ct_state, &id);
+ if (!error) {
+ /* No reject, can't continue probing other flags */
+ goto out_del;
+ }
+
+ tc_del_filter(&id);
+
+ /* Test for ct_state INVALID support */
+ memset(&flower, 0, sizeof flower);
+ ct_state = TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
+ TCA_FLOWER_KEY_CT_FLAGS_INVALID;
+ error = probe_insert_ct_state_rule(ifindex, ct_state, &id);
+ if (error) {
+ goto out;
+ }
+
+ tc_del_filter(&id);
+ ct_state_support |= OVS_CS_F_INVALID;
+
+ /* Test for ct_state REPLY support */
+ memset(&flower, 0, sizeof flower);
+ ct_state = TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
+ TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED |
+ TCA_FLOWER_KEY_CT_FLAGS_REPLY;
+ error = probe_insert_ct_state_rule(ifindex, ct_state, &id);
+ if (error) {
+ goto out;
+ }
+
+ ct_state_support |= OVS_CS_F_REPLY_DIR;
+
+out_del:
+ tc_del_filter(&id);
+out:
+ tc_add_del_qdisc(ifindex, false, 0, TC_INGRESS);
+ VLOG_INFO("probe tc: supported ovs ct_state bits: 0x%x", ct_state_support);
+}
+
static void
probe_tc_block_support(int ifindex)
{
@@ -2103,6 +2211,7 @@ netdev_tc_init_flow_api(struct netdev *netdev)
block_id = get_block_id_from_netdev(netdev);
probe_multi_mask_per_prio(ifindex);
+ probe_ct_state_support(ifindex);
ovsthread_once_done(&once);
}
--
1.8.3.1
More information about the dev
mailing list