Skip to content

Commit 60b44ca

Browse files
apconolekuba-moo
authored andcommitted
openvswitch: always update flow key after nat
During NAT, a tuple collision may occur. When this happens, openvswitch will make a second pass through NAT which will perform additional packet modification. This will update the skb data, but not the flow key that OVS uses. This means that future flow lookups, and packet matches will have incorrect data. This has been supported since 5d50aa8 ("openvswitch: support asymmetric conntrack"). That commit failed to properly update the sw_flow_key attributes, since it only called the ovs_ct_nat_update_key once, rather than each time ovs_ct_nat_execute was called. As these two operations are linked, the ovs_ct_nat_execute() function should always make sure that the sw_flow_key is updated after a successful call through NAT infrastructure. Fixes: 5d50aa8 ("openvswitch: support asymmetric conntrack") Cc: Dumitru Ceara <dceara@redhat.com> Cc: Numan Siddique <nusiddiq@redhat.com> Signed-off-by: Aaron Conole <aconole@redhat.com> Acked-by: Eelco Chaudron <echaudro@redhat.com> Link: https://lore.kernel.org/r/20220318124319.3056455-1-aconole@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent ed0c99d commit 60b44ca

1 file changed

Lines changed: 59 additions & 59 deletions

File tree

net/openvswitch/conntrack.c

Lines changed: 59 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -734,14 +734,65 @@ static bool skb_nfct_cached(struct net *net,
734734
}
735735

736736
#if IS_ENABLED(CONFIG_NF_NAT)
737+
static void ovs_nat_update_key(struct sw_flow_key *key,
738+
const struct sk_buff *skb,
739+
enum nf_nat_manip_type maniptype)
740+
{
741+
if (maniptype == NF_NAT_MANIP_SRC) {
742+
__be16 src;
743+
744+
key->ct_state |= OVS_CS_F_SRC_NAT;
745+
if (key->eth.type == htons(ETH_P_IP))
746+
key->ipv4.addr.src = ip_hdr(skb)->saddr;
747+
else if (key->eth.type == htons(ETH_P_IPV6))
748+
memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr,
749+
sizeof(key->ipv6.addr.src));
750+
else
751+
return;
752+
753+
if (key->ip.proto == IPPROTO_UDP)
754+
src = udp_hdr(skb)->source;
755+
else if (key->ip.proto == IPPROTO_TCP)
756+
src = tcp_hdr(skb)->source;
757+
else if (key->ip.proto == IPPROTO_SCTP)
758+
src = sctp_hdr(skb)->source;
759+
else
760+
return;
761+
762+
key->tp.src = src;
763+
} else {
764+
__be16 dst;
765+
766+
key->ct_state |= OVS_CS_F_DST_NAT;
767+
if (key->eth.type == htons(ETH_P_IP))
768+
key->ipv4.addr.dst = ip_hdr(skb)->daddr;
769+
else if (key->eth.type == htons(ETH_P_IPV6))
770+
memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr,
771+
sizeof(key->ipv6.addr.dst));
772+
else
773+
return;
774+
775+
if (key->ip.proto == IPPROTO_UDP)
776+
dst = udp_hdr(skb)->dest;
777+
else if (key->ip.proto == IPPROTO_TCP)
778+
dst = tcp_hdr(skb)->dest;
779+
else if (key->ip.proto == IPPROTO_SCTP)
780+
dst = sctp_hdr(skb)->dest;
781+
else
782+
return;
783+
784+
key->tp.dst = dst;
785+
}
786+
}
787+
737788
/* Modelled after nf_nat_ipv[46]_fn().
738789
* range is only used for new, uninitialized NAT state.
739790
* Returns either NF_ACCEPT or NF_DROP.
740791
*/
741792
static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct,
742793
enum ip_conntrack_info ctinfo,
743794
const struct nf_nat_range2 *range,
744-
enum nf_nat_manip_type maniptype)
795+
enum nf_nat_manip_type maniptype, struct sw_flow_key *key)
745796
{
746797
int hooknum, nh_off, err = NF_ACCEPT;
747798

@@ -813,58 +864,11 @@ static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct,
813864
push:
814865
skb_push_rcsum(skb, nh_off);
815866

816-
return err;
817-
}
818-
819-
static void ovs_nat_update_key(struct sw_flow_key *key,
820-
const struct sk_buff *skb,
821-
enum nf_nat_manip_type maniptype)
822-
{
823-
if (maniptype == NF_NAT_MANIP_SRC) {
824-
__be16 src;
825-
826-
key->ct_state |= OVS_CS_F_SRC_NAT;
827-
if (key->eth.type == htons(ETH_P_IP))
828-
key->ipv4.addr.src = ip_hdr(skb)->saddr;
829-
else if (key->eth.type == htons(ETH_P_IPV6))
830-
memcpy(&key->ipv6.addr.src, &ipv6_hdr(skb)->saddr,
831-
sizeof(key->ipv6.addr.src));
832-
else
833-
return;
834-
835-
if (key->ip.proto == IPPROTO_UDP)
836-
src = udp_hdr(skb)->source;
837-
else if (key->ip.proto == IPPROTO_TCP)
838-
src = tcp_hdr(skb)->source;
839-
else if (key->ip.proto == IPPROTO_SCTP)
840-
src = sctp_hdr(skb)->source;
841-
else
842-
return;
843-
844-
key->tp.src = src;
845-
} else {
846-
__be16 dst;
847-
848-
key->ct_state |= OVS_CS_F_DST_NAT;
849-
if (key->eth.type == htons(ETH_P_IP))
850-
key->ipv4.addr.dst = ip_hdr(skb)->daddr;
851-
else if (key->eth.type == htons(ETH_P_IPV6))
852-
memcpy(&key->ipv6.addr.dst, &ipv6_hdr(skb)->daddr,
853-
sizeof(key->ipv6.addr.dst));
854-
else
855-
return;
856-
857-
if (key->ip.proto == IPPROTO_UDP)
858-
dst = udp_hdr(skb)->dest;
859-
else if (key->ip.proto == IPPROTO_TCP)
860-
dst = tcp_hdr(skb)->dest;
861-
else if (key->ip.proto == IPPROTO_SCTP)
862-
dst = sctp_hdr(skb)->dest;
863-
else
864-
return;
867+
/* Update the flow key if NAT successful. */
868+
if (err == NF_ACCEPT)
869+
ovs_nat_update_key(key, skb, maniptype);
865870

866-
key->tp.dst = dst;
867-
}
871+
return err;
868872
}
869873

870874
/* Returns NF_DROP if the packet should be dropped, NF_ACCEPT otherwise. */
@@ -906,7 +910,7 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
906910
} else {
907911
return NF_ACCEPT; /* Connection is not NATed. */
908912
}
909-
err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype);
913+
err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype, key);
910914

911915
if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) {
912916
if (ct->status & IPS_SRC_NAT) {
@@ -916,17 +920,13 @@ static int ovs_ct_nat(struct net *net, struct sw_flow_key *key,
916920
maniptype = NF_NAT_MANIP_SRC;
917921

918922
err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range,
919-
maniptype);
923+
maniptype, key);
920924
} else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) {
921925
err = ovs_ct_nat_execute(skb, ct, ctinfo, NULL,
922-
NF_NAT_MANIP_SRC);
926+
NF_NAT_MANIP_SRC, key);
923927
}
924928
}
925929

926-
/* Mark NAT done if successful and update the flow key. */
927-
if (err == NF_ACCEPT)
928-
ovs_nat_update_key(key, skb, maniptype);
929-
930930
return err;
931931
}
932932
#else /* !CONFIG_NF_NAT */

0 commit comments

Comments
 (0)