17f8a436eSJoe Stringer /* 27f8a436eSJoe Stringer * Copyright (c) 2015 Nicira, Inc. 37f8a436eSJoe Stringer * 47f8a436eSJoe Stringer * This program is free software; you can redistribute it and/or 57f8a436eSJoe Stringer * modify it under the terms of version 2 of the GNU General Public 67f8a436eSJoe Stringer * License as published by the Free Software Foundation. 77f8a436eSJoe Stringer * 87f8a436eSJoe Stringer * This program is distributed in the hope that it will be useful, but 97f8a436eSJoe Stringer * WITHOUT ANY WARRANTY; without even the implied warranty of 107f8a436eSJoe Stringer * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 117f8a436eSJoe Stringer * General Public License for more details. 127f8a436eSJoe Stringer */ 137f8a436eSJoe Stringer 147f8a436eSJoe Stringer #include <linux/module.h> 157f8a436eSJoe Stringer #include <linux/openvswitch.h> 167f8a436eSJoe Stringer #include <net/ip.h> 177f8a436eSJoe Stringer #include <net/netfilter/nf_conntrack_core.h> 18cae3a262SJoe Stringer #include <net/netfilter/nf_conntrack_helper.h> 19c2ac6673SJoe Stringer #include <net/netfilter/nf_conntrack_labels.h> 207f8a436eSJoe Stringer #include <net/netfilter/nf_conntrack_zones.h> 217f8a436eSJoe Stringer #include <net/netfilter/ipv6/nf_defrag_ipv6.h> 227f8a436eSJoe Stringer 237f8a436eSJoe Stringer #include "datapath.h" 247f8a436eSJoe Stringer #include "conntrack.h" 257f8a436eSJoe Stringer #include "flow.h" 267f8a436eSJoe Stringer #include "flow_netlink.h" 277f8a436eSJoe Stringer 287f8a436eSJoe Stringer struct ovs_ct_len_tbl { 297f8a436eSJoe Stringer size_t maxlen; 307f8a436eSJoe Stringer size_t minlen; 317f8a436eSJoe Stringer }; 327f8a436eSJoe Stringer 33182e3042SJoe Stringer /* Metadata mark for masked write to conntrack mark */ 34182e3042SJoe Stringer struct md_mark { 35182e3042SJoe Stringer u32 value; 36182e3042SJoe Stringer u32 mask; 37182e3042SJoe Stringer }; 38182e3042SJoe Stringer 39c2ac6673SJoe Stringer /* Metadata label for masked write to conntrack label. */ 4033db4125SJoe Stringer struct md_labels { 4133db4125SJoe Stringer struct ovs_key_ct_labels value; 4233db4125SJoe Stringer struct ovs_key_ct_labels mask; 43c2ac6673SJoe Stringer }; 44c2ac6673SJoe Stringer 457f8a436eSJoe Stringer /* Conntrack action context for execution. */ 467f8a436eSJoe Stringer struct ovs_conntrack_info { 47cae3a262SJoe Stringer struct nf_conntrack_helper *helper; 487f8a436eSJoe Stringer struct nf_conntrack_zone zone; 497f8a436eSJoe Stringer struct nf_conn *ct; 50ab38a7b5SJoe Stringer u8 commit : 1; 517f8a436eSJoe Stringer u16 family; 52182e3042SJoe Stringer struct md_mark mark; 5333db4125SJoe Stringer struct md_labels labels; 547f8a436eSJoe Stringer }; 557f8a436eSJoe Stringer 562f3ab9f9SJoe Stringer static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info); 572f3ab9f9SJoe Stringer 587f8a436eSJoe Stringer static u16 key_to_nfproto(const struct sw_flow_key *key) 597f8a436eSJoe Stringer { 607f8a436eSJoe Stringer switch (ntohs(key->eth.type)) { 617f8a436eSJoe Stringer case ETH_P_IP: 627f8a436eSJoe Stringer return NFPROTO_IPV4; 637f8a436eSJoe Stringer case ETH_P_IPV6: 647f8a436eSJoe Stringer return NFPROTO_IPV6; 657f8a436eSJoe Stringer default: 667f8a436eSJoe Stringer return NFPROTO_UNSPEC; 677f8a436eSJoe Stringer } 687f8a436eSJoe Stringer } 697f8a436eSJoe Stringer 707f8a436eSJoe Stringer /* Map SKB connection state into the values used by flow definition. */ 717f8a436eSJoe Stringer static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo) 727f8a436eSJoe Stringer { 737f8a436eSJoe Stringer u8 ct_state = OVS_CS_F_TRACKED; 747f8a436eSJoe Stringer 757f8a436eSJoe Stringer switch (ctinfo) { 767f8a436eSJoe Stringer case IP_CT_ESTABLISHED_REPLY: 777f8a436eSJoe Stringer case IP_CT_RELATED_REPLY: 787f8a436eSJoe Stringer ct_state |= OVS_CS_F_REPLY_DIR; 797f8a436eSJoe Stringer break; 807f8a436eSJoe Stringer default: 817f8a436eSJoe Stringer break; 827f8a436eSJoe Stringer } 837f8a436eSJoe Stringer 847f8a436eSJoe Stringer switch (ctinfo) { 857f8a436eSJoe Stringer case IP_CT_ESTABLISHED: 867f8a436eSJoe Stringer case IP_CT_ESTABLISHED_REPLY: 877f8a436eSJoe Stringer ct_state |= OVS_CS_F_ESTABLISHED; 887f8a436eSJoe Stringer break; 897f8a436eSJoe Stringer case IP_CT_RELATED: 907f8a436eSJoe Stringer case IP_CT_RELATED_REPLY: 917f8a436eSJoe Stringer ct_state |= OVS_CS_F_RELATED; 927f8a436eSJoe Stringer break; 937f8a436eSJoe Stringer case IP_CT_NEW: 947f8a436eSJoe Stringer ct_state |= OVS_CS_F_NEW; 957f8a436eSJoe Stringer break; 967f8a436eSJoe Stringer default: 977f8a436eSJoe Stringer break; 987f8a436eSJoe Stringer } 997f8a436eSJoe Stringer 1007f8a436eSJoe Stringer return ct_state; 1017f8a436eSJoe Stringer } 1027f8a436eSJoe Stringer 1030d5cdef8SJoe Stringer static u32 ovs_ct_get_mark(const struct nf_conn *ct) 1040d5cdef8SJoe Stringer { 1050d5cdef8SJoe Stringer #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) 1060d5cdef8SJoe Stringer return ct ? ct->mark : 0; 1070d5cdef8SJoe Stringer #else 1080d5cdef8SJoe Stringer return 0; 1090d5cdef8SJoe Stringer #endif 1100d5cdef8SJoe Stringer } 1110d5cdef8SJoe Stringer 11233db4125SJoe Stringer static void ovs_ct_get_labels(const struct nf_conn *ct, 11333db4125SJoe Stringer struct ovs_key_ct_labels *labels) 114c2ac6673SJoe Stringer { 115c2ac6673SJoe Stringer struct nf_conn_labels *cl = ct ? nf_ct_labels_find(ct) : NULL; 116c2ac6673SJoe Stringer 117c2ac6673SJoe Stringer if (cl) { 118c2ac6673SJoe Stringer size_t len = cl->words * sizeof(long); 119c2ac6673SJoe Stringer 12033db4125SJoe Stringer if (len > OVS_CT_LABELS_LEN) 12133db4125SJoe Stringer len = OVS_CT_LABELS_LEN; 12233db4125SJoe Stringer else if (len < OVS_CT_LABELS_LEN) 12333db4125SJoe Stringer memset(labels, 0, OVS_CT_LABELS_LEN); 12433db4125SJoe Stringer memcpy(labels, cl->bits, len); 125c2ac6673SJoe Stringer } else { 12633db4125SJoe Stringer memset(labels, 0, OVS_CT_LABELS_LEN); 127c2ac6673SJoe Stringer } 128c2ac6673SJoe Stringer } 129c2ac6673SJoe Stringer 1307f8a436eSJoe Stringer static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state, 131182e3042SJoe Stringer const struct nf_conntrack_zone *zone, 132182e3042SJoe Stringer const struct nf_conn *ct) 1337f8a436eSJoe Stringer { 1347f8a436eSJoe Stringer key->ct.state = state; 1357f8a436eSJoe Stringer key->ct.zone = zone->id; 1360d5cdef8SJoe Stringer key->ct.mark = ovs_ct_get_mark(ct); 13733db4125SJoe Stringer ovs_ct_get_labels(ct, &key->ct.labels); 1387f8a436eSJoe Stringer } 1397f8a436eSJoe Stringer 1407f8a436eSJoe Stringer /* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has 1417f8a436eSJoe Stringer * previously sent the packet to conntrack via the ct action. 1427f8a436eSJoe Stringer */ 1437f8a436eSJoe Stringer static void ovs_ct_update_key(const struct sk_buff *skb, 144d110986cSJoe Stringer const struct ovs_conntrack_info *info, 1457f8a436eSJoe Stringer struct sw_flow_key *key, bool post_ct) 1467f8a436eSJoe Stringer { 1477f8a436eSJoe Stringer const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; 1487f8a436eSJoe Stringer enum ip_conntrack_info ctinfo; 1497f8a436eSJoe Stringer struct nf_conn *ct; 1507f8a436eSJoe Stringer u8 state = 0; 1517f8a436eSJoe Stringer 1527f8a436eSJoe Stringer ct = nf_ct_get(skb, &ctinfo); 1537f8a436eSJoe Stringer if (ct) { 1547f8a436eSJoe Stringer state = ovs_ct_get_state(ctinfo); 1559f13ded8SJarno Rajahalme /* All unconfirmed entries are NEW connections. */ 1564f0909eeSJoe Stringer if (!nf_ct_is_confirmed(ct)) 1574f0909eeSJoe Stringer state |= OVS_CS_F_NEW; 1589f13ded8SJarno Rajahalme /* OVS persists the related flag for the duration of the 1599f13ded8SJarno Rajahalme * connection. 1609f13ded8SJarno Rajahalme */ 1617f8a436eSJoe Stringer if (ct->master) 1627f8a436eSJoe Stringer state |= OVS_CS_F_RELATED; 1637f8a436eSJoe Stringer zone = nf_ct_zone(ct); 1647f8a436eSJoe Stringer } else if (post_ct) { 1657f8a436eSJoe Stringer state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID; 166d110986cSJoe Stringer if (info) 167d110986cSJoe Stringer zone = &info->zone; 1687f8a436eSJoe Stringer } 169182e3042SJoe Stringer __ovs_ct_update_key(key, state, zone, ct); 1707f8a436eSJoe Stringer } 1717f8a436eSJoe Stringer 1729f13ded8SJarno Rajahalme /* This is called to initialize CT key fields possibly coming in from the local 1739f13ded8SJarno Rajahalme * stack. 1749f13ded8SJarno Rajahalme */ 1757f8a436eSJoe Stringer void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key) 1767f8a436eSJoe Stringer { 177d110986cSJoe Stringer ovs_ct_update_key(skb, NULL, key, false); 1787f8a436eSJoe Stringer } 1797f8a436eSJoe Stringer 1807f8a436eSJoe Stringer int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) 1817f8a436eSJoe Stringer { 182fbccce59SJoe Stringer if (nla_put_u32(skb, OVS_KEY_ATTR_CT_STATE, key->ct.state)) 1837f8a436eSJoe Stringer return -EMSGSIZE; 1847f8a436eSJoe Stringer 1857f8a436eSJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 1867f8a436eSJoe Stringer nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone)) 1877f8a436eSJoe Stringer return -EMSGSIZE; 1887f8a436eSJoe Stringer 189182e3042SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && 190182e3042SJoe Stringer nla_put_u32(skb, OVS_KEY_ATTR_CT_MARK, key->ct.mark)) 191182e3042SJoe Stringer return -EMSGSIZE; 192182e3042SJoe Stringer 1939723e6abSValentin Rothberg if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 19433db4125SJoe Stringer nla_put(skb, OVS_KEY_ATTR_CT_LABELS, sizeof(key->ct.labels), 19533db4125SJoe Stringer &key->ct.labels)) 196c2ac6673SJoe Stringer return -EMSGSIZE; 197c2ac6673SJoe Stringer 198182e3042SJoe Stringer return 0; 199182e3042SJoe Stringer } 200182e3042SJoe Stringer 201182e3042SJoe Stringer static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key, 202182e3042SJoe Stringer u32 ct_mark, u32 mask) 203182e3042SJoe Stringer { 2040d5cdef8SJoe Stringer #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) 205182e3042SJoe Stringer enum ip_conntrack_info ctinfo; 206182e3042SJoe Stringer struct nf_conn *ct; 207182e3042SJoe Stringer u32 new_mark; 208182e3042SJoe Stringer 209182e3042SJoe Stringer /* The connection could be invalid, in which case set_mark is no-op. */ 210182e3042SJoe Stringer ct = nf_ct_get(skb, &ctinfo); 211182e3042SJoe Stringer if (!ct) 212182e3042SJoe Stringer return 0; 213182e3042SJoe Stringer 214182e3042SJoe Stringer new_mark = ct_mark | (ct->mark & ~(mask)); 215182e3042SJoe Stringer if (ct->mark != new_mark) { 216182e3042SJoe Stringer ct->mark = new_mark; 217182e3042SJoe Stringer nf_conntrack_event_cache(IPCT_MARK, ct); 218182e3042SJoe Stringer key->ct.mark = new_mark; 219182e3042SJoe Stringer } 220182e3042SJoe Stringer 2217f8a436eSJoe Stringer return 0; 2220d5cdef8SJoe Stringer #else 2230d5cdef8SJoe Stringer return -ENOTSUPP; 2240d5cdef8SJoe Stringer #endif 2257f8a436eSJoe Stringer } 2267f8a436eSJoe Stringer 22733db4125SJoe Stringer static int ovs_ct_set_labels(struct sk_buff *skb, struct sw_flow_key *key, 22833db4125SJoe Stringer const struct ovs_key_ct_labels *labels, 22933db4125SJoe Stringer const struct ovs_key_ct_labels *mask) 230c2ac6673SJoe Stringer { 231c2ac6673SJoe Stringer enum ip_conntrack_info ctinfo; 232c2ac6673SJoe Stringer struct nf_conn_labels *cl; 233c2ac6673SJoe Stringer struct nf_conn *ct; 234c2ac6673SJoe Stringer int err; 235c2ac6673SJoe Stringer 236c2ac6673SJoe Stringer /* The connection could be invalid, in which case set_label is no-op.*/ 237c2ac6673SJoe Stringer ct = nf_ct_get(skb, &ctinfo); 238c2ac6673SJoe Stringer if (!ct) 239c2ac6673SJoe Stringer return 0; 240c2ac6673SJoe Stringer 241c2ac6673SJoe Stringer cl = nf_ct_labels_find(ct); 242c2ac6673SJoe Stringer if (!cl) { 243c2ac6673SJoe Stringer nf_ct_labels_ext_add(ct); 244c2ac6673SJoe Stringer cl = nf_ct_labels_find(ct); 245c2ac6673SJoe Stringer } 24633db4125SJoe Stringer if (!cl || cl->words * sizeof(long) < OVS_CT_LABELS_LEN) 247c2ac6673SJoe Stringer return -ENOSPC; 248c2ac6673SJoe Stringer 24933db4125SJoe Stringer err = nf_connlabels_replace(ct, (u32 *)labels, (u32 *)mask, 25033db4125SJoe Stringer OVS_CT_LABELS_LEN / sizeof(u32)); 251c2ac6673SJoe Stringer if (err) 252c2ac6673SJoe Stringer return err; 253c2ac6673SJoe Stringer 25433db4125SJoe Stringer ovs_ct_get_labels(ct, &key->ct.labels); 255c2ac6673SJoe Stringer return 0; 256c2ac6673SJoe Stringer } 257c2ac6673SJoe Stringer 258cae3a262SJoe Stringer /* 'skb' should already be pulled to nh_ofs. */ 259cae3a262SJoe Stringer static int ovs_ct_helper(struct sk_buff *skb, u16 proto) 260cae3a262SJoe Stringer { 261cae3a262SJoe Stringer const struct nf_conntrack_helper *helper; 262cae3a262SJoe Stringer const struct nf_conn_help *help; 263cae3a262SJoe Stringer enum ip_conntrack_info ctinfo; 264cae3a262SJoe Stringer unsigned int protoff; 265cae3a262SJoe Stringer struct nf_conn *ct; 266cae3a262SJoe Stringer 267cae3a262SJoe Stringer ct = nf_ct_get(skb, &ctinfo); 268cae3a262SJoe Stringer if (!ct || ctinfo == IP_CT_RELATED_REPLY) 269cae3a262SJoe Stringer return NF_ACCEPT; 270cae3a262SJoe Stringer 271cae3a262SJoe Stringer help = nfct_help(ct); 272cae3a262SJoe Stringer if (!help) 273cae3a262SJoe Stringer return NF_ACCEPT; 274cae3a262SJoe Stringer 275cae3a262SJoe Stringer helper = rcu_dereference(help->helper); 276cae3a262SJoe Stringer if (!helper) 277cae3a262SJoe Stringer return NF_ACCEPT; 278cae3a262SJoe Stringer 279cae3a262SJoe Stringer switch (proto) { 280cae3a262SJoe Stringer case NFPROTO_IPV4: 281cae3a262SJoe Stringer protoff = ip_hdrlen(skb); 282cae3a262SJoe Stringer break; 283cae3a262SJoe Stringer case NFPROTO_IPV6: { 284cae3a262SJoe Stringer u8 nexthdr = ipv6_hdr(skb)->nexthdr; 285cae3a262SJoe Stringer __be16 frag_off; 286cc570605SJoe Stringer int ofs; 287cae3a262SJoe Stringer 288cc570605SJoe Stringer ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, 289cc570605SJoe Stringer &frag_off); 290cc570605SJoe Stringer if (ofs < 0 || (frag_off & htons(~0x7)) != 0) { 291cae3a262SJoe Stringer pr_debug("proto header not found\n"); 292cae3a262SJoe Stringer return NF_ACCEPT; 293cae3a262SJoe Stringer } 294cc570605SJoe Stringer protoff = ofs; 295cae3a262SJoe Stringer break; 296cae3a262SJoe Stringer } 297cae3a262SJoe Stringer default: 298cae3a262SJoe Stringer WARN_ONCE(1, "helper invoked on non-IP family!"); 299cae3a262SJoe Stringer return NF_DROP; 300cae3a262SJoe Stringer } 301cae3a262SJoe Stringer 302cae3a262SJoe Stringer return helper->help(skb, protoff, ct, ctinfo); 303cae3a262SJoe Stringer } 304cae3a262SJoe Stringer 30574c16618SJoe Stringer /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero 30674c16618SJoe Stringer * value if 'skb' is freed. 30774c16618SJoe Stringer */ 3087f8a436eSJoe Stringer static int handle_fragments(struct net *net, struct sw_flow_key *key, 3097f8a436eSJoe Stringer u16 zone, struct sk_buff *skb) 3107f8a436eSJoe Stringer { 3117f8a436eSJoe Stringer struct ovs_skb_cb ovs_cb = *OVS_CB(skb); 312daaa7d64SFlorian Westphal int err; 3137f8a436eSJoe Stringer 3147f8a436eSJoe Stringer if (key->eth.type == htons(ETH_P_IP)) { 3157f8a436eSJoe Stringer enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone; 3167f8a436eSJoe Stringer 3177f8a436eSJoe Stringer memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); 31819bcf9f2SEric W. Biederman err = ip_defrag(net, skb, user); 3197f8a436eSJoe Stringer if (err) 3207f8a436eSJoe Stringer return err; 3217f8a436eSJoe Stringer 3227f8a436eSJoe Stringer ovs_cb.mru = IPCB(skb)->frag_max_size; 3237f8a436eSJoe Stringer #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) 32474c16618SJoe Stringer } else if (key->eth.type == htons(ETH_P_IPV6)) { 3257f8a436eSJoe Stringer enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone; 3267f8a436eSJoe Stringer 3277f8a436eSJoe Stringer memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); 328daaa7d64SFlorian Westphal err = nf_ct_frag6_gather(net, skb, user); 329daaa7d64SFlorian Westphal if (err) 330daaa7d64SFlorian Westphal return err; 3317f8a436eSJoe Stringer 332daaa7d64SFlorian Westphal key->ip.proto = ipv6_hdr(skb)->nexthdr; 3337f8a436eSJoe Stringer ovs_cb.mru = IP6CB(skb)->frag_max_size; 3347f8a436eSJoe Stringer #endif 3357f8a436eSJoe Stringer } else { 33674c16618SJoe Stringer kfree_skb(skb); 3377f8a436eSJoe Stringer return -EPFNOSUPPORT; 3387f8a436eSJoe Stringer } 3397f8a436eSJoe Stringer 3407f8a436eSJoe Stringer key->ip.frag = OVS_FRAG_TYPE_NONE; 3417f8a436eSJoe Stringer skb_clear_hash(skb); 3427f8a436eSJoe Stringer skb->ignore_df = 1; 3437f8a436eSJoe Stringer *OVS_CB(skb) = ovs_cb; 3447f8a436eSJoe Stringer 3457f8a436eSJoe Stringer return 0; 3467f8a436eSJoe Stringer } 3477f8a436eSJoe Stringer 3487f8a436eSJoe Stringer static struct nf_conntrack_expect * 3497f8a436eSJoe Stringer ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone, 3507f8a436eSJoe Stringer u16 proto, const struct sk_buff *skb) 3517f8a436eSJoe Stringer { 3527f8a436eSJoe Stringer struct nf_conntrack_tuple tuple; 3537f8a436eSJoe Stringer 354a31f1adcSEric W. Biederman if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, net, &tuple)) 3557f8a436eSJoe Stringer return NULL; 3567f8a436eSJoe Stringer return __nf_ct_expect_find(net, zone, &tuple); 3577f8a436eSJoe Stringer } 3587f8a436eSJoe Stringer 359289f2253SJarno Rajahalme /* This replicates logic from nf_conntrack_core.c that is not exported. */ 360289f2253SJarno Rajahalme static enum ip_conntrack_info 361289f2253SJarno Rajahalme ovs_ct_get_info(const struct nf_conntrack_tuple_hash *h) 362289f2253SJarno Rajahalme { 363289f2253SJarno Rajahalme const struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 364289f2253SJarno Rajahalme 365289f2253SJarno Rajahalme if (NF_CT_DIRECTION(h) == IP_CT_DIR_REPLY) 366289f2253SJarno Rajahalme return IP_CT_ESTABLISHED_REPLY; 367289f2253SJarno Rajahalme /* Once we've had two way comms, always ESTABLISHED. */ 368289f2253SJarno Rajahalme if (test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) 369289f2253SJarno Rajahalme return IP_CT_ESTABLISHED; 370289f2253SJarno Rajahalme if (test_bit(IPS_EXPECTED_BIT, &ct->status)) 371289f2253SJarno Rajahalme return IP_CT_RELATED; 372289f2253SJarno Rajahalme return IP_CT_NEW; 373289f2253SJarno Rajahalme } 374289f2253SJarno Rajahalme 375289f2253SJarno Rajahalme /* Find an existing connection which this packet belongs to without 376289f2253SJarno Rajahalme * re-attributing statistics or modifying the connection state. This allows an 377289f2253SJarno Rajahalme * skb->nfct lost due to an upcall to be recovered during actions execution. 378289f2253SJarno Rajahalme * 379289f2253SJarno Rajahalme * Must be called with rcu_read_lock. 380289f2253SJarno Rajahalme * 381289f2253SJarno Rajahalme * On success, populates skb->nfct and skb->nfctinfo, and returns the 382289f2253SJarno Rajahalme * connection. Returns NULL if there is no existing entry. 383289f2253SJarno Rajahalme */ 384289f2253SJarno Rajahalme static struct nf_conn * 385289f2253SJarno Rajahalme ovs_ct_find_existing(struct net *net, const struct nf_conntrack_zone *zone, 386289f2253SJarno Rajahalme u8 l3num, struct sk_buff *skb) 387289f2253SJarno Rajahalme { 388289f2253SJarno Rajahalme struct nf_conntrack_l3proto *l3proto; 389289f2253SJarno Rajahalme struct nf_conntrack_l4proto *l4proto; 390289f2253SJarno Rajahalme struct nf_conntrack_tuple tuple; 391289f2253SJarno Rajahalme struct nf_conntrack_tuple_hash *h; 392289f2253SJarno Rajahalme enum ip_conntrack_info ctinfo; 393289f2253SJarno Rajahalme struct nf_conn *ct; 394289f2253SJarno Rajahalme unsigned int dataoff; 395289f2253SJarno Rajahalme u8 protonum; 396289f2253SJarno Rajahalme 397289f2253SJarno Rajahalme l3proto = __nf_ct_l3proto_find(l3num); 398289f2253SJarno Rajahalme if (!l3proto) { 399289f2253SJarno Rajahalme pr_debug("ovs_ct_find_existing: Can't get l3proto\n"); 400289f2253SJarno Rajahalme return NULL; 401289f2253SJarno Rajahalme } 402289f2253SJarno Rajahalme if (l3proto->get_l4proto(skb, skb_network_offset(skb), &dataoff, 403289f2253SJarno Rajahalme &protonum) <= 0) { 404289f2253SJarno Rajahalme pr_debug("ovs_ct_find_existing: Can't get protonum\n"); 405289f2253SJarno Rajahalme return NULL; 406289f2253SJarno Rajahalme } 407289f2253SJarno Rajahalme l4proto = __nf_ct_l4proto_find(l3num, protonum); 408289f2253SJarno Rajahalme if (!l4proto) { 409289f2253SJarno Rajahalme pr_debug("ovs_ct_find_existing: Can't get l4proto\n"); 410289f2253SJarno Rajahalme return NULL; 411289f2253SJarno Rajahalme } 412289f2253SJarno Rajahalme if (!nf_ct_get_tuple(skb, skb_network_offset(skb), dataoff, l3num, 413289f2253SJarno Rajahalme protonum, net, &tuple, l3proto, l4proto)) { 414289f2253SJarno Rajahalme pr_debug("ovs_ct_find_existing: Can't get tuple\n"); 415289f2253SJarno Rajahalme return NULL; 416289f2253SJarno Rajahalme } 417289f2253SJarno Rajahalme 418289f2253SJarno Rajahalme /* look for tuple match */ 419289f2253SJarno Rajahalme h = nf_conntrack_find_get(net, zone, &tuple); 420289f2253SJarno Rajahalme if (!h) 421289f2253SJarno Rajahalme return NULL; /* Not found. */ 422289f2253SJarno Rajahalme 423289f2253SJarno Rajahalme ct = nf_ct_tuplehash_to_ctrack(h); 424289f2253SJarno Rajahalme 425289f2253SJarno Rajahalme ctinfo = ovs_ct_get_info(h); 426289f2253SJarno Rajahalme if (ctinfo == IP_CT_NEW) { 427289f2253SJarno Rajahalme /* This should not happen. */ 428289f2253SJarno Rajahalme WARN_ONCE(1, "ovs_ct_find_existing: new packet for %p\n", ct); 429289f2253SJarno Rajahalme } 430289f2253SJarno Rajahalme skb->nfct = &ct->ct_general; 431289f2253SJarno Rajahalme skb->nfctinfo = ctinfo; 432289f2253SJarno Rajahalme return ct; 433289f2253SJarno Rajahalme } 434289f2253SJarno Rajahalme 4357f8a436eSJoe Stringer /* Determine whether skb->nfct is equal to the result of conntrack lookup. */ 436289f2253SJarno Rajahalme static bool skb_nfct_cached(struct net *net, 437289f2253SJarno Rajahalme const struct sw_flow_key *key, 438289f2253SJarno Rajahalme const struct ovs_conntrack_info *info, 439289f2253SJarno Rajahalme struct sk_buff *skb) 4407f8a436eSJoe Stringer { 4417f8a436eSJoe Stringer enum ip_conntrack_info ctinfo; 4427f8a436eSJoe Stringer struct nf_conn *ct; 4437f8a436eSJoe Stringer 4447f8a436eSJoe Stringer ct = nf_ct_get(skb, &ctinfo); 445289f2253SJarno Rajahalme /* If no ct, check if we have evidence that an existing conntrack entry 446289f2253SJarno Rajahalme * might be found for this skb. This happens when we lose a skb->nfct 447289f2253SJarno Rajahalme * due to an upcall. If the connection was not confirmed, it is not 448289f2253SJarno Rajahalme * cached and needs to be run through conntrack again. 449289f2253SJarno Rajahalme */ 450289f2253SJarno Rajahalme if (!ct && key->ct.state & OVS_CS_F_TRACKED && 451289f2253SJarno Rajahalme !(key->ct.state & OVS_CS_F_INVALID) && 452289f2253SJarno Rajahalme key->ct.zone == info->zone.id) 453289f2253SJarno Rajahalme ct = ovs_ct_find_existing(net, &info->zone, info->family, skb); 4547f8a436eSJoe Stringer if (!ct) 4557f8a436eSJoe Stringer return false; 4567f8a436eSJoe Stringer if (!net_eq(net, read_pnet(&ct->ct_net))) 4577f8a436eSJoe Stringer return false; 4587f8a436eSJoe Stringer if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct))) 4597f8a436eSJoe Stringer return false; 460cae3a262SJoe Stringer if (info->helper) { 461cae3a262SJoe Stringer struct nf_conn_help *help; 462cae3a262SJoe Stringer 463cae3a262SJoe Stringer help = nf_ct_ext_find(ct, NF_CT_EXT_HELPER); 464cae3a262SJoe Stringer if (help && rcu_access_pointer(help->helper) != info->helper) 465cae3a262SJoe Stringer return false; 466cae3a262SJoe Stringer } 4677f8a436eSJoe Stringer 4687f8a436eSJoe Stringer return true; 4697f8a436eSJoe Stringer } 4707f8a436eSJoe Stringer 4719f13ded8SJarno Rajahalme /* Pass 'skb' through conntrack in 'net', using zone configured in 'info', if 472394e910eSJarno Rajahalme * not done already. Update key with new CT state after passing the packet 473394e910eSJarno Rajahalme * through conntrack. 4749f13ded8SJarno Rajahalme * Note that if the packet is deemed invalid by conntrack, skb->nfct will be 4759f13ded8SJarno Rajahalme * set to NULL and 0 will be returned. 4769f13ded8SJarno Rajahalme */ 4774f0909eeSJoe Stringer static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key, 4787f8a436eSJoe Stringer const struct ovs_conntrack_info *info, 4797f8a436eSJoe Stringer struct sk_buff *skb) 4807f8a436eSJoe Stringer { 4817f8a436eSJoe Stringer /* If we are recirculating packets to match on conntrack fields and 4827f8a436eSJoe Stringer * committing with a separate conntrack action, then we don't need to 4837f8a436eSJoe Stringer * actually run the packet through conntrack twice unless it's for a 4847f8a436eSJoe Stringer * different zone. 4857f8a436eSJoe Stringer */ 486289f2253SJarno Rajahalme if (!skb_nfct_cached(net, key, info, skb)) { 4877f8a436eSJoe Stringer struct nf_conn *tmpl = info->ct; 4885b6b9293SJarno Rajahalme int err; 4897f8a436eSJoe Stringer 4907f8a436eSJoe Stringer /* Associate skb with specified zone. */ 4917f8a436eSJoe Stringer if (tmpl) { 4927f8a436eSJoe Stringer if (skb->nfct) 4937f8a436eSJoe Stringer nf_conntrack_put(skb->nfct); 4947f8a436eSJoe Stringer nf_conntrack_get(&tmpl->ct_general); 4957f8a436eSJoe Stringer skb->nfct = &tmpl->ct_general; 4967f8a436eSJoe Stringer skb->nfctinfo = IP_CT_NEW; 4977f8a436eSJoe Stringer } 4987f8a436eSJoe Stringer 4995b6b9293SJarno Rajahalme /* Repeat if requested, see nf_iterate(). */ 5005b6b9293SJarno Rajahalme do { 5015b6b9293SJarno Rajahalme err = nf_conntrack_in(net, info->family, 5025b6b9293SJarno Rajahalme NF_INET_PRE_ROUTING, skb); 5035b6b9293SJarno Rajahalme } while (err == NF_REPEAT); 5045b6b9293SJarno Rajahalme 5055b6b9293SJarno Rajahalme if (err != NF_ACCEPT) 5067f8a436eSJoe Stringer return -ENOENT; 507cae3a262SJoe Stringer 508394e910eSJarno Rajahalme ovs_ct_update_key(skb, info, key, true); 509394e910eSJarno Rajahalme 510cae3a262SJoe Stringer if (ovs_ct_helper(skb, info->family) != NF_ACCEPT) { 511cae3a262SJoe Stringer WARN_ONCE(1, "helper rejected packet"); 512cae3a262SJoe Stringer return -EINVAL; 513cae3a262SJoe Stringer } 5147f8a436eSJoe Stringer } 5157f8a436eSJoe Stringer 5167f8a436eSJoe Stringer return 0; 5177f8a436eSJoe Stringer } 5187f8a436eSJoe Stringer 5197f8a436eSJoe Stringer /* Lookup connection and read fields into key. */ 5207f8a436eSJoe Stringer static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, 5217f8a436eSJoe Stringer const struct ovs_conntrack_info *info, 5227f8a436eSJoe Stringer struct sk_buff *skb) 5237f8a436eSJoe Stringer { 5247f8a436eSJoe Stringer struct nf_conntrack_expect *exp; 5257f8a436eSJoe Stringer 5269f13ded8SJarno Rajahalme /* If we pass an expected packet through nf_conntrack_in() the 5279f13ded8SJarno Rajahalme * expectation is typically removed, but the packet could still be 5289f13ded8SJarno Rajahalme * lost in upcall processing. To prevent this from happening we 5299f13ded8SJarno Rajahalme * perform an explicit expectation lookup. Expected connections are 5309f13ded8SJarno Rajahalme * always new, and will be passed through conntrack only when they are 5319f13ded8SJarno Rajahalme * committed, as it is OK to remove the expectation at that time. 5329f13ded8SJarno Rajahalme */ 5337f8a436eSJoe Stringer exp = ovs_ct_expect_find(net, &info->zone, info->family, skb); 5347f8a436eSJoe Stringer if (exp) { 5357f8a436eSJoe Stringer u8 state; 5367f8a436eSJoe Stringer 5377f8a436eSJoe Stringer state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED; 538182e3042SJoe Stringer __ovs_ct_update_key(key, state, &info->zone, exp->master); 5397f8a436eSJoe Stringer } else { 5407f8a436eSJoe Stringer int err; 5417f8a436eSJoe Stringer 5427f8a436eSJoe Stringer err = __ovs_ct_lookup(net, key, info, skb); 5437f8a436eSJoe Stringer if (err) 5447f8a436eSJoe Stringer return err; 5457f8a436eSJoe Stringer } 5467f8a436eSJoe Stringer 5477f8a436eSJoe Stringer return 0; 5487f8a436eSJoe Stringer } 5497f8a436eSJoe Stringer 5507f8a436eSJoe Stringer /* Lookup connection and confirm if unconfirmed. */ 5517f8a436eSJoe Stringer static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, 5527f8a436eSJoe Stringer const struct ovs_conntrack_info *info, 5537f8a436eSJoe Stringer struct sk_buff *skb) 5547f8a436eSJoe Stringer { 5557f8a436eSJoe Stringer int err; 5567f8a436eSJoe Stringer 5577f8a436eSJoe Stringer err = __ovs_ct_lookup(net, key, info, skb); 5587f8a436eSJoe Stringer if (err) 5597f8a436eSJoe Stringer return err; 5609f13ded8SJarno Rajahalme /* This is a no-op if the connection has already been confirmed. */ 5617f8a436eSJoe Stringer if (nf_conntrack_confirm(skb) != NF_ACCEPT) 5627f8a436eSJoe Stringer return -EINVAL; 5637f8a436eSJoe Stringer 5647f8a436eSJoe Stringer return 0; 5657f8a436eSJoe Stringer } 5667f8a436eSJoe Stringer 56733db4125SJoe Stringer static bool labels_nonzero(const struct ovs_key_ct_labels *labels) 568c2ac6673SJoe Stringer { 569c2ac6673SJoe Stringer size_t i; 570c2ac6673SJoe Stringer 57133db4125SJoe Stringer for (i = 0; i < sizeof(*labels); i++) 57233db4125SJoe Stringer if (labels->ct_labels[i]) 573c2ac6673SJoe Stringer return true; 574c2ac6673SJoe Stringer 575c2ac6673SJoe Stringer return false; 576c2ac6673SJoe Stringer } 577c2ac6673SJoe Stringer 57874c16618SJoe Stringer /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero 57974c16618SJoe Stringer * value if 'skb' is freed. 58074c16618SJoe Stringer */ 5817f8a436eSJoe Stringer int ovs_ct_execute(struct net *net, struct sk_buff *skb, 5827f8a436eSJoe Stringer struct sw_flow_key *key, 5837f8a436eSJoe Stringer const struct ovs_conntrack_info *info) 5847f8a436eSJoe Stringer { 5857f8a436eSJoe Stringer int nh_ofs; 5867f8a436eSJoe Stringer int err; 5877f8a436eSJoe Stringer 5887f8a436eSJoe Stringer /* The conntrack module expects to be working at L3. */ 5897f8a436eSJoe Stringer nh_ofs = skb_network_offset(skb); 5907f8a436eSJoe Stringer skb_pull(skb, nh_ofs); 5917f8a436eSJoe Stringer 5927f8a436eSJoe Stringer if (key->ip.frag != OVS_FRAG_TYPE_NONE) { 5937f8a436eSJoe Stringer err = handle_fragments(net, key, info->zone.id, skb); 5947f8a436eSJoe Stringer if (err) 5957f8a436eSJoe Stringer return err; 5967f8a436eSJoe Stringer } 5977f8a436eSJoe Stringer 598ab38a7b5SJoe Stringer if (info->commit) 5997f8a436eSJoe Stringer err = ovs_ct_commit(net, key, info, skb); 6007f8a436eSJoe Stringer else 6017f8a436eSJoe Stringer err = ovs_ct_lookup(net, key, info, skb); 602182e3042SJoe Stringer if (err) 603182e3042SJoe Stringer goto err; 6047f8a436eSJoe Stringer 605c2ac6673SJoe Stringer if (info->mark.mask) { 606182e3042SJoe Stringer err = ovs_ct_set_mark(skb, key, info->mark.value, 607182e3042SJoe Stringer info->mark.mask); 608c2ac6673SJoe Stringer if (err) 609c2ac6673SJoe Stringer goto err; 610c2ac6673SJoe Stringer } 61133db4125SJoe Stringer if (labels_nonzero(&info->labels.mask)) 61233db4125SJoe Stringer err = ovs_ct_set_labels(skb, key, &info->labels.value, 61333db4125SJoe Stringer &info->labels.mask); 614182e3042SJoe Stringer err: 6157f8a436eSJoe Stringer skb_push(skb, nh_ofs); 61674c16618SJoe Stringer if (err) 61774c16618SJoe Stringer kfree_skb(skb); 6187f8a436eSJoe Stringer return err; 6197f8a436eSJoe Stringer } 6207f8a436eSJoe Stringer 621cae3a262SJoe Stringer static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name, 622cae3a262SJoe Stringer const struct sw_flow_key *key, bool log) 623cae3a262SJoe Stringer { 624cae3a262SJoe Stringer struct nf_conntrack_helper *helper; 625cae3a262SJoe Stringer struct nf_conn_help *help; 626cae3a262SJoe Stringer 627cae3a262SJoe Stringer helper = nf_conntrack_helper_try_module_get(name, info->family, 628cae3a262SJoe Stringer key->ip.proto); 629cae3a262SJoe Stringer if (!helper) { 630cae3a262SJoe Stringer OVS_NLERR(log, "Unknown helper \"%s\"", name); 631cae3a262SJoe Stringer return -EINVAL; 632cae3a262SJoe Stringer } 633cae3a262SJoe Stringer 634cae3a262SJoe Stringer help = nf_ct_helper_ext_add(info->ct, helper, GFP_KERNEL); 635cae3a262SJoe Stringer if (!help) { 636cae3a262SJoe Stringer module_put(helper->me); 637cae3a262SJoe Stringer return -ENOMEM; 638cae3a262SJoe Stringer } 639cae3a262SJoe Stringer 640cae3a262SJoe Stringer rcu_assign_pointer(help->helper, helper); 641cae3a262SJoe Stringer info->helper = helper; 642cae3a262SJoe Stringer return 0; 643cae3a262SJoe Stringer } 644cae3a262SJoe Stringer 6457f8a436eSJoe Stringer static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { 646ab38a7b5SJoe Stringer [OVS_CT_ATTR_COMMIT] = { .minlen = 0, .maxlen = 0 }, 6477f8a436eSJoe Stringer [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), 6487f8a436eSJoe Stringer .maxlen = sizeof(u16) }, 649182e3042SJoe Stringer [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark), 650182e3042SJoe Stringer .maxlen = sizeof(struct md_mark) }, 65133db4125SJoe Stringer [OVS_CT_ATTR_LABELS] = { .minlen = sizeof(struct md_labels), 65233db4125SJoe Stringer .maxlen = sizeof(struct md_labels) }, 653cae3a262SJoe Stringer [OVS_CT_ATTR_HELPER] = { .minlen = 1, 654cae3a262SJoe Stringer .maxlen = NF_CT_HELPER_NAME_LEN } 6557f8a436eSJoe Stringer }; 6567f8a436eSJoe Stringer 6577f8a436eSJoe Stringer static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, 658cae3a262SJoe Stringer const char **helper, bool log) 6597f8a436eSJoe Stringer { 6607f8a436eSJoe Stringer struct nlattr *a; 6617f8a436eSJoe Stringer int rem; 6627f8a436eSJoe Stringer 6637f8a436eSJoe Stringer nla_for_each_nested(a, attr, rem) { 6647f8a436eSJoe Stringer int type = nla_type(a); 6657f8a436eSJoe Stringer int maxlen = ovs_ct_attr_lens[type].maxlen; 6667f8a436eSJoe Stringer int minlen = ovs_ct_attr_lens[type].minlen; 6677f8a436eSJoe Stringer 6687f8a436eSJoe Stringer if (type > OVS_CT_ATTR_MAX) { 6697f8a436eSJoe Stringer OVS_NLERR(log, 6707f8a436eSJoe Stringer "Unknown conntrack attr (type=%d, max=%d)", 6717f8a436eSJoe Stringer type, OVS_CT_ATTR_MAX); 6727f8a436eSJoe Stringer return -EINVAL; 6737f8a436eSJoe Stringer } 6747f8a436eSJoe Stringer if (nla_len(a) < minlen || nla_len(a) > maxlen) { 6757f8a436eSJoe Stringer OVS_NLERR(log, 6767f8a436eSJoe Stringer "Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)", 6777f8a436eSJoe Stringer type, nla_len(a), maxlen); 6787f8a436eSJoe Stringer return -EINVAL; 6797f8a436eSJoe Stringer } 6807f8a436eSJoe Stringer 6817f8a436eSJoe Stringer switch (type) { 682ab38a7b5SJoe Stringer case OVS_CT_ATTR_COMMIT: 683ab38a7b5SJoe Stringer info->commit = true; 6847f8a436eSJoe Stringer break; 6857f8a436eSJoe Stringer #ifdef CONFIG_NF_CONNTRACK_ZONES 6867f8a436eSJoe Stringer case OVS_CT_ATTR_ZONE: 6877f8a436eSJoe Stringer info->zone.id = nla_get_u16(a); 6887f8a436eSJoe Stringer break; 6897f8a436eSJoe Stringer #endif 690182e3042SJoe Stringer #ifdef CONFIG_NF_CONNTRACK_MARK 691182e3042SJoe Stringer case OVS_CT_ATTR_MARK: { 692182e3042SJoe Stringer struct md_mark *mark = nla_data(a); 693182e3042SJoe Stringer 694e754ec69SJoe Stringer if (!mark->mask) { 695e754ec69SJoe Stringer OVS_NLERR(log, "ct_mark mask cannot be 0"); 696e754ec69SJoe Stringer return -EINVAL; 697e754ec69SJoe Stringer } 698182e3042SJoe Stringer info->mark = *mark; 699182e3042SJoe Stringer break; 700182e3042SJoe Stringer } 701182e3042SJoe Stringer #endif 702c2ac6673SJoe Stringer #ifdef CONFIG_NF_CONNTRACK_LABELS 70333db4125SJoe Stringer case OVS_CT_ATTR_LABELS: { 70433db4125SJoe Stringer struct md_labels *labels = nla_data(a); 705c2ac6673SJoe Stringer 706e754ec69SJoe Stringer if (!labels_nonzero(&labels->mask)) { 707e754ec69SJoe Stringer OVS_NLERR(log, "ct_labels mask cannot be 0"); 708e754ec69SJoe Stringer return -EINVAL; 709e754ec69SJoe Stringer } 71033db4125SJoe Stringer info->labels = *labels; 711c2ac6673SJoe Stringer break; 712c2ac6673SJoe Stringer } 713c2ac6673SJoe Stringer #endif 714cae3a262SJoe Stringer case OVS_CT_ATTR_HELPER: 715cae3a262SJoe Stringer *helper = nla_data(a); 716cae3a262SJoe Stringer if (!memchr(*helper, '\0', nla_len(a))) { 717cae3a262SJoe Stringer OVS_NLERR(log, "Invalid conntrack helper"); 718cae3a262SJoe Stringer return -EINVAL; 719cae3a262SJoe Stringer } 720cae3a262SJoe Stringer break; 7217f8a436eSJoe Stringer default: 7227f8a436eSJoe Stringer OVS_NLERR(log, "Unknown conntrack attr (%d)", 7237f8a436eSJoe Stringer type); 7247f8a436eSJoe Stringer return -EINVAL; 7257f8a436eSJoe Stringer } 7267f8a436eSJoe Stringer } 7277f8a436eSJoe Stringer 7287f8a436eSJoe Stringer if (rem > 0) { 7297f8a436eSJoe Stringer OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem); 7307f8a436eSJoe Stringer return -EINVAL; 7317f8a436eSJoe Stringer } 7327f8a436eSJoe Stringer 7337f8a436eSJoe Stringer return 0; 7347f8a436eSJoe Stringer } 7357f8a436eSJoe Stringer 736c2ac6673SJoe Stringer bool ovs_ct_verify(struct net *net, enum ovs_key_attr attr) 7377f8a436eSJoe Stringer { 7387f8a436eSJoe Stringer if (attr == OVS_KEY_ATTR_CT_STATE) 7397f8a436eSJoe Stringer return true; 7407f8a436eSJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 7417f8a436eSJoe Stringer attr == OVS_KEY_ATTR_CT_ZONE) 7427f8a436eSJoe Stringer return true; 743182e3042SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && 744182e3042SJoe Stringer attr == OVS_KEY_ATTR_CT_MARK) 745182e3042SJoe Stringer return true; 746c2ac6673SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 74733db4125SJoe Stringer attr == OVS_KEY_ATTR_CT_LABELS) { 748c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 749c2ac6673SJoe Stringer 750c2ac6673SJoe Stringer return ovs_net->xt_label; 751c2ac6673SJoe Stringer } 7527f8a436eSJoe Stringer 7537f8a436eSJoe Stringer return false; 7547f8a436eSJoe Stringer } 7557f8a436eSJoe Stringer 7567f8a436eSJoe Stringer int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, 7577f8a436eSJoe Stringer const struct sw_flow_key *key, 7587f8a436eSJoe Stringer struct sw_flow_actions **sfa, bool log) 7597f8a436eSJoe Stringer { 7607f8a436eSJoe Stringer struct ovs_conntrack_info ct_info; 761cae3a262SJoe Stringer const char *helper = NULL; 7627f8a436eSJoe Stringer u16 family; 7637f8a436eSJoe Stringer int err; 7647f8a436eSJoe Stringer 7657f8a436eSJoe Stringer family = key_to_nfproto(key); 7667f8a436eSJoe Stringer if (family == NFPROTO_UNSPEC) { 7677f8a436eSJoe Stringer OVS_NLERR(log, "ct family unspecified"); 7687f8a436eSJoe Stringer return -EINVAL; 7697f8a436eSJoe Stringer } 7707f8a436eSJoe Stringer 7717f8a436eSJoe Stringer memset(&ct_info, 0, sizeof(ct_info)); 7727f8a436eSJoe Stringer ct_info.family = family; 7737f8a436eSJoe Stringer 7747f8a436eSJoe Stringer nf_ct_zone_init(&ct_info.zone, NF_CT_DEFAULT_ZONE_ID, 7757f8a436eSJoe Stringer NF_CT_DEFAULT_ZONE_DIR, 0); 7767f8a436eSJoe Stringer 777cae3a262SJoe Stringer err = parse_ct(attr, &ct_info, &helper, log); 7787f8a436eSJoe Stringer if (err) 7797f8a436eSJoe Stringer return err; 7807f8a436eSJoe Stringer 7817f8a436eSJoe Stringer /* Set up template for tracking connections in specific zones. */ 7827f8a436eSJoe Stringer ct_info.ct = nf_ct_tmpl_alloc(net, &ct_info.zone, GFP_KERNEL); 7837f8a436eSJoe Stringer if (!ct_info.ct) { 7847f8a436eSJoe Stringer OVS_NLERR(log, "Failed to allocate conntrack template"); 7857f8a436eSJoe Stringer return -ENOMEM; 7867f8a436eSJoe Stringer } 78790c7afc9SJoe Stringer 78890c7afc9SJoe Stringer __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status); 78990c7afc9SJoe Stringer nf_conntrack_get(&ct_info.ct->ct_general); 79090c7afc9SJoe Stringer 791cae3a262SJoe Stringer if (helper) { 792cae3a262SJoe Stringer err = ovs_ct_add_helper(&ct_info, helper, key, log); 793cae3a262SJoe Stringer if (err) 794cae3a262SJoe Stringer goto err_free_ct; 795cae3a262SJoe Stringer } 7967f8a436eSJoe Stringer 7977f8a436eSJoe Stringer err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info, 7987f8a436eSJoe Stringer sizeof(ct_info), log); 7997f8a436eSJoe Stringer if (err) 8007f8a436eSJoe Stringer goto err_free_ct; 8017f8a436eSJoe Stringer 8027f8a436eSJoe Stringer return 0; 8037f8a436eSJoe Stringer err_free_ct: 8042f3ab9f9SJoe Stringer __ovs_ct_free_action(&ct_info); 8057f8a436eSJoe Stringer return err; 8067f8a436eSJoe Stringer } 8077f8a436eSJoe Stringer 8087f8a436eSJoe Stringer int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, 8097f8a436eSJoe Stringer struct sk_buff *skb) 8107f8a436eSJoe Stringer { 8117f8a436eSJoe Stringer struct nlattr *start; 8127f8a436eSJoe Stringer 8137f8a436eSJoe Stringer start = nla_nest_start(skb, OVS_ACTION_ATTR_CT); 8147f8a436eSJoe Stringer if (!start) 8157f8a436eSJoe Stringer return -EMSGSIZE; 8167f8a436eSJoe Stringer 817ab38a7b5SJoe Stringer if (ct_info->commit && nla_put_flag(skb, OVS_CT_ATTR_COMMIT)) 8187f8a436eSJoe Stringer return -EMSGSIZE; 8197f8a436eSJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 8207f8a436eSJoe Stringer nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) 8217f8a436eSJoe Stringer return -EMSGSIZE; 822e754ec69SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && ct_info->mark.mask && 823182e3042SJoe Stringer nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), 824182e3042SJoe Stringer &ct_info->mark)) 825182e3042SJoe Stringer return -EMSGSIZE; 826c2ac6673SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 827e754ec69SJoe Stringer labels_nonzero(&ct_info->labels.mask) && 82833db4125SJoe Stringer nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels), 82933db4125SJoe Stringer &ct_info->labels)) 830c2ac6673SJoe Stringer return -EMSGSIZE; 831cae3a262SJoe Stringer if (ct_info->helper) { 832cae3a262SJoe Stringer if (nla_put_string(skb, OVS_CT_ATTR_HELPER, 833cae3a262SJoe Stringer ct_info->helper->name)) 834cae3a262SJoe Stringer return -EMSGSIZE; 835cae3a262SJoe Stringer } 8367f8a436eSJoe Stringer 8377f8a436eSJoe Stringer nla_nest_end(skb, start); 8387f8a436eSJoe Stringer 8397f8a436eSJoe Stringer return 0; 8407f8a436eSJoe Stringer } 8417f8a436eSJoe Stringer 8427f8a436eSJoe Stringer void ovs_ct_free_action(const struct nlattr *a) 8437f8a436eSJoe Stringer { 8447f8a436eSJoe Stringer struct ovs_conntrack_info *ct_info = nla_data(a); 8457f8a436eSJoe Stringer 8462f3ab9f9SJoe Stringer __ovs_ct_free_action(ct_info); 8472f3ab9f9SJoe Stringer } 8482f3ab9f9SJoe Stringer 8492f3ab9f9SJoe Stringer static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info) 8502f3ab9f9SJoe Stringer { 851cae3a262SJoe Stringer if (ct_info->helper) 852cae3a262SJoe Stringer module_put(ct_info->helper->me); 8537f8a436eSJoe Stringer if (ct_info->ct) 8547f8a436eSJoe Stringer nf_ct_put(ct_info->ct); 8557f8a436eSJoe Stringer } 856c2ac6673SJoe Stringer 857c2ac6673SJoe Stringer void ovs_ct_init(struct net *net) 858c2ac6673SJoe Stringer { 85933db4125SJoe Stringer unsigned int n_bits = sizeof(struct ovs_key_ct_labels) * BITS_PER_BYTE; 860c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 861c2ac6673SJoe Stringer 862c2ac6673SJoe Stringer if (nf_connlabels_get(net, n_bits)) { 863c2ac6673SJoe Stringer ovs_net->xt_label = false; 864c2ac6673SJoe Stringer OVS_NLERR(true, "Failed to set connlabel length"); 865c2ac6673SJoe Stringer } else { 866c2ac6673SJoe Stringer ovs_net->xt_label = true; 867c2ac6673SJoe Stringer } 868c2ac6673SJoe Stringer } 869c2ac6673SJoe Stringer 870c2ac6673SJoe Stringer void ovs_ct_exit(struct net *net) 871c2ac6673SJoe Stringer { 872c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 873c2ac6673SJoe Stringer 874c2ac6673SJoe Stringer if (ovs_net->xt_label) 875c2ac6673SJoe Stringer nf_connlabels_put(net); 876c2ac6673SJoe Stringer } 877