diff options
Diffstat (limited to 'net/openvswitch/conntrack.c')
-rw-r--r-- | net/openvswitch/conntrack.c | 51 |
1 files changed, 36 insertions, 15 deletions
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 08679ebb3068..e3c4c6c3fef7 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c | |||
@@ -629,6 +629,34 @@ ovs_ct_find_existing(struct net *net, const struct nf_conntrack_zone *zone, | |||
629 | return ct; | 629 | return ct; |
630 | } | 630 | } |
631 | 631 | ||
632 | static | ||
633 | struct nf_conn *ovs_ct_executed(struct net *net, | ||
634 | const struct sw_flow_key *key, | ||
635 | const struct ovs_conntrack_info *info, | ||
636 | struct sk_buff *skb, | ||
637 | bool *ct_executed) | ||
638 | { | ||
639 | struct nf_conn *ct = NULL; | ||
640 | |||
641 | /* If no ct, check if we have evidence that an existing conntrack entry | ||
642 | * might be found for this skb. This happens when we lose a skb->_nfct | ||
643 | * due to an upcall, or if the direction is being forced. If the | ||
644 | * connection was not confirmed, it is not cached and needs to be run | ||
645 | * through conntrack again. | ||
646 | */ | ||
647 | *ct_executed = (key->ct_state & OVS_CS_F_TRACKED) && | ||
648 | !(key->ct_state & OVS_CS_F_INVALID) && | ||
649 | (key->ct_zone == info->zone.id); | ||
650 | |||
651 | if (*ct_executed || (!key->ct_state && info->force)) { | ||
652 | ct = ovs_ct_find_existing(net, &info->zone, info->family, skb, | ||
653 | !!(key->ct_state & | ||
654 | OVS_CS_F_NAT_MASK)); | ||
655 | } | ||
656 | |||
657 | return ct; | ||
658 | } | ||
659 | |||
632 | /* Determine whether skb->_nfct is equal to the result of conntrack lookup. */ | 660 | /* Determine whether skb->_nfct is equal to the result of conntrack lookup. */ |
633 | static bool skb_nfct_cached(struct net *net, | 661 | static bool skb_nfct_cached(struct net *net, |
634 | const struct sw_flow_key *key, | 662 | const struct sw_flow_key *key, |
@@ -637,24 +665,17 @@ static bool skb_nfct_cached(struct net *net, | |||
637 | { | 665 | { |
638 | enum ip_conntrack_info ctinfo; | 666 | enum ip_conntrack_info ctinfo; |
639 | struct nf_conn *ct; | 667 | struct nf_conn *ct; |
668 | bool ct_executed = true; | ||
640 | 669 | ||
641 | ct = nf_ct_get(skb, &ctinfo); | 670 | ct = nf_ct_get(skb, &ctinfo); |
642 | /* If no ct, check if we have evidence that an existing conntrack entry | ||
643 | * might be found for this skb. This happens when we lose a skb->_nfct | ||
644 | * due to an upcall. If the connection was not confirmed, it is not | ||
645 | * cached and needs to be run through conntrack again. | ||
646 | */ | ||
647 | if (!ct && key->ct_state & OVS_CS_F_TRACKED && | ||
648 | !(key->ct_state & OVS_CS_F_INVALID) && | ||
649 | key->ct_zone == info->zone.id) { | ||
650 | ct = ovs_ct_find_existing(net, &info->zone, info->family, skb, | ||
651 | !!(key->ct_state | ||
652 | & OVS_CS_F_NAT_MASK)); | ||
653 | if (ct) | ||
654 | nf_ct_get(skb, &ctinfo); | ||
655 | } | ||
656 | if (!ct) | 671 | if (!ct) |
672 | ct = ovs_ct_executed(net, key, info, skb, &ct_executed); | ||
673 | |||
674 | if (ct) | ||
675 | nf_ct_get(skb, &ctinfo); | ||
676 | else | ||
657 | return false; | 677 | return false; |
678 | |||
658 | if (!net_eq(net, read_pnet(&ct->ct_net))) | 679 | if (!net_eq(net, read_pnet(&ct->ct_net))) |
659 | return false; | 680 | return false; |
660 | if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct))) | 681 | if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct))) |
@@ -679,7 +700,7 @@ static bool skb_nfct_cached(struct net *net, | |||
679 | return false; | 700 | return false; |
680 | } | 701 | } |
681 | 702 | ||
682 | return true; | 703 | return ct_executed; |
683 | } | 704 | } |
684 | 705 | ||
685 | #ifdef CONFIG_NF_NAT_NEEDED | 706 | #ifdef CONFIG_NF_NAT_NEEDED |