Skip to content

Commit dd41d33

Browse files
Jarno Rajahalmedavem330
authored andcommitted
openvswitch: Add force commit.
Stateful network admission policy may allow connections to one direction and reject connections initiated in the other direction. After policy change it is possible that for a new connection an overlapping conntrack entry already exists, where the original direction of the existing connection is opposed to the new connection's initial packet. Most importantly, conntrack state relating to the current packet gets the "reply" designation based on whether the original direction tuple or the reply direction tuple matched. If this "directionality" is wrong w.r.t. to the stateful network admission policy it may happen that packets in neither direction are correctly admitted. This patch adds a new "force commit" option to the OVS conntrack action that checks the original direction of an existing conntrack entry. If that direction is opposed to the current packet, the existing conntrack entry is deleted and a new one is subsequently created in the correct direction. Signed-off-by: Jarno Rajahalme <[email protected]> Acked-by: Pravin B Shelar <[email protected]> Acked-by: Joe Stringer <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 9dd7f89 commit dd41d33

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

include/uapi/linux/openvswitch.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,10 @@ struct ovs_action_hash {
674674
* @OVS_CT_ATTR_HELPER: variable length string defining conntrack ALG.
675675
* @OVS_CT_ATTR_NAT: Nested OVS_NAT_ATTR_* for performing L3 network address
676676
* translation (NAT) on the packet.
677+
* @OVS_CT_ATTR_FORCE_COMMIT: Like %OVS_CT_ATTR_COMMIT, but instead of doing
678+
* nothing if the connection is already committed will check that the current
679+
* packet is in conntrack entry's original direction. If directionality does
680+
* not match, will delete the existing conntrack entry and commit a new one.
677681
*/
678682
enum ovs_ct_attr {
679683
OVS_CT_ATTR_UNSPEC,
@@ -684,6 +688,7 @@ enum ovs_ct_attr {
684688
OVS_CT_ATTR_HELPER, /* netlink helper to assist detection of
685689
related connections. */
686690
OVS_CT_ATTR_NAT, /* Nested OVS_NAT_ATTR_* */
691+
OVS_CT_ATTR_FORCE_COMMIT, /* No argument */
687692
__OVS_CT_ATTR_MAX
688693
};
689694

net/openvswitch/conntrack.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct ovs_conntrack_info {
6565
struct nf_conn *ct;
6666
u8 commit : 1;
6767
u8 nat : 3; /* enum ovs_ct_nat */
68+
u8 force : 1;
6869
u16 family;
6970
struct md_mark mark;
7071
struct md_labels labels;
@@ -613,10 +614,13 @@ static bool skb_nfct_cached(struct net *net,
613614
*/
614615
if (!ct && key->ct.state & OVS_CS_F_TRACKED &&
615616
!(key->ct.state & OVS_CS_F_INVALID) &&
616-
key->ct.zone == info->zone.id)
617+
key->ct.zone == info->zone.id) {
617618
ct = ovs_ct_find_existing(net, &info->zone, info->family, skb,
618619
!!(key->ct.state
619620
& OVS_CS_F_NAT_MASK));
621+
if (ct)
622+
nf_ct_get(skb, &ctinfo);
623+
}
620624
if (!ct)
621625
return false;
622626
if (!net_eq(net, read_pnet(&ct->ct_net)))
@@ -630,6 +634,18 @@ static bool skb_nfct_cached(struct net *net,
630634
if (help && rcu_access_pointer(help->helper) != info->helper)
631635
return false;
632636
}
637+
/* Force conntrack entry direction to the current packet? */
638+
if (info->force && CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) {
639+
/* Delete the conntrack entry if confirmed, else just release
640+
* the reference.
641+
*/
642+
if (nf_ct_is_confirmed(ct))
643+
nf_ct_delete(ct, 0, 0);
644+
else
645+
nf_conntrack_put(&ct->ct_general);
646+
nf_ct_set(skb, NULL, 0);
647+
return false;
648+
}
633649

634650
return true;
635651
}
@@ -1207,6 +1223,7 @@ static int parse_nat(const struct nlattr *attr,
12071223

12081224
static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
12091225
[OVS_CT_ATTR_COMMIT] = { .minlen = 0, .maxlen = 0 },
1226+
[OVS_CT_ATTR_FORCE_COMMIT] = { .minlen = 0, .maxlen = 0 },
12101227
[OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16),
12111228
.maxlen = sizeof(u16) },
12121229
[OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark),
@@ -1246,6 +1263,9 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
12461263
}
12471264

12481265
switch (type) {
1266+
case OVS_CT_ATTR_FORCE_COMMIT:
1267+
info->force = true;
1268+
/* fall through. */
12491269
case OVS_CT_ATTR_COMMIT:
12501270
info->commit = true;
12511271
break;
@@ -1472,7 +1492,9 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
14721492
if (!start)
14731493
return -EMSGSIZE;
14741494

1475-
if (ct_info->commit && nla_put_flag(skb, OVS_CT_ATTR_COMMIT))
1495+
if (ct_info->commit && nla_put_flag(skb, ct_info->force
1496+
? OVS_CT_ATTR_FORCE_COMMIT
1497+
: OVS_CT_ATTR_COMMIT))
14761498
return -EMSGSIZE;
14771499
if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
14781500
nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))

0 commit comments

Comments
 (0)