static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key, const struct ovs_conntrack_info *info, struct sk_buff *skb) { /* If we are recirculating packets to match on conntrack fields and * committing with a separate conntrack action, then we don't need to * actually run the packet through conntrack twice unless it's for a * different zone. */ if (!skb_nfct_cached(net, skb, info)) { struct nf_conn *tmpl = info->ct; /* Associate skb with specified zone. */ if (tmpl) { if (skb->nfct) nf_conntrack_put(skb->nfct); nf_conntrack_get(&tmpl->ct_general); skb->nfct = &tmpl->ct_general; skb->nfctinfo = IP_CT_NEW; } if (nf_conntrack_in(net, info->family, NF_INET_FORWARD, skb) != NF_ACCEPT) return -ENOENT; if (ovs_ct_helper(skb, info->family) != NF_ACCEPT) { WARN_ONCE(1, "helper rejected packet"); return -EINVAL; } } ovs_ct_update_key(skb, info, key, true); return 0; }
/* Lookup connection and confirm if unconfirmed. */ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, const struct ovs_conntrack_info *info, struct sk_buff *skb) { u8 state; int err; state = key->ct.state; if (key->ct.zone == info->zone.id && ((state & OVS_CS_F_TRACKED) && !(state & OVS_CS_F_NEW))) { /* Previous lookup has shown that this connection is already * tracked and committed. Skip committing. */ return 0; } err = __ovs_ct_lookup(net, key, info, skb); if (err) return err; if (nf_conntrack_confirm(skb) != NF_ACCEPT) return -EINVAL; ovs_ct_update_key(skb, key, true); return 0; }
/* Lookup connection and read fields into key. */ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, const struct ovs_conntrack_info *info, struct sk_buff *skb) { struct nf_conntrack_expect *exp; exp = ovs_ct_expect_find(net, &info->zone, info->family, skb); if (exp) { u8 state; state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED; __ovs_ct_update_key(key, state, &info->zone, exp->master); } else { int err; err = __ovs_ct_lookup(net, key, info, skb); if (err) return err; ovs_ct_update_key(skb, key, true); } return 0; }
void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key) { ovs_ct_update_key(skb, NULL, key, false); }