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; 4887f8a436eSJoe Stringer 4897f8a436eSJoe Stringer /* Associate skb with specified zone. */ 4907f8a436eSJoe Stringer if (tmpl) { 4917f8a436eSJoe Stringer if (skb->nfct) 4927f8a436eSJoe Stringer nf_conntrack_put(skb->nfct); 4937f8a436eSJoe Stringer nf_conntrack_get(&tmpl->ct_general); 4947f8a436eSJoe Stringer skb->nfct = &tmpl->ct_general; 4957f8a436eSJoe Stringer skb->nfctinfo = IP_CT_NEW; 4967f8a436eSJoe Stringer } 4977f8a436eSJoe Stringer 4987f8a436eSJoe Stringer if (nf_conntrack_in(net, info->family, NF_INET_PRE_ROUTING, 4997f8a436eSJoe Stringer skb) != NF_ACCEPT) 5007f8a436eSJoe Stringer return -ENOENT; 501cae3a262SJoe Stringer 502394e910eSJarno Rajahalme ovs_ct_update_key(skb, info, key, true); 503394e910eSJarno Rajahalme 504cae3a262SJoe Stringer if (ovs_ct_helper(skb, info->family) != NF_ACCEPT) { 505cae3a262SJoe Stringer WARN_ONCE(1, "helper rejected packet"); 506cae3a262SJoe Stringer return -EINVAL; 507cae3a262SJoe Stringer } 5087f8a436eSJoe Stringer } 5097f8a436eSJoe Stringer 5107f8a436eSJoe Stringer return 0; 5117f8a436eSJoe Stringer } 5127f8a436eSJoe Stringer 5137f8a436eSJoe Stringer /* Lookup connection and read fields into key. */ 5147f8a436eSJoe Stringer static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, 5157f8a436eSJoe Stringer const struct ovs_conntrack_info *info, 5167f8a436eSJoe Stringer struct sk_buff *skb) 5177f8a436eSJoe Stringer { 5187f8a436eSJoe Stringer struct nf_conntrack_expect *exp; 5197f8a436eSJoe Stringer 5209f13ded8SJarno Rajahalme /* If we pass an expected packet through nf_conntrack_in() the 5219f13ded8SJarno Rajahalme * expectation is typically removed, but the packet could still be 5229f13ded8SJarno Rajahalme * lost in upcall processing. To prevent this from happening we 5239f13ded8SJarno Rajahalme * perform an explicit expectation lookup. Expected connections are 5249f13ded8SJarno Rajahalme * always new, and will be passed through conntrack only when they are 5259f13ded8SJarno Rajahalme * committed, as it is OK to remove the expectation at that time. 5269f13ded8SJarno Rajahalme */ 5277f8a436eSJoe Stringer exp = ovs_ct_expect_find(net, &info->zone, info->family, skb); 5287f8a436eSJoe Stringer if (exp) { 5297f8a436eSJoe Stringer u8 state; 5307f8a436eSJoe Stringer 5317f8a436eSJoe Stringer state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED; 532182e3042SJoe Stringer __ovs_ct_update_key(key, state, &info->zone, exp->master); 5337f8a436eSJoe Stringer } else { 5347f8a436eSJoe Stringer int err; 5357f8a436eSJoe Stringer 5367f8a436eSJoe Stringer err = __ovs_ct_lookup(net, key, info, skb); 5377f8a436eSJoe Stringer if (err) 5387f8a436eSJoe Stringer return err; 5397f8a436eSJoe Stringer } 5407f8a436eSJoe Stringer 5417f8a436eSJoe Stringer return 0; 5427f8a436eSJoe Stringer } 5437f8a436eSJoe Stringer 5447f8a436eSJoe Stringer /* Lookup connection and confirm if unconfirmed. */ 5457f8a436eSJoe Stringer static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, 5467f8a436eSJoe Stringer const struct ovs_conntrack_info *info, 5477f8a436eSJoe Stringer struct sk_buff *skb) 5487f8a436eSJoe Stringer { 5497f8a436eSJoe Stringer int err; 5507f8a436eSJoe Stringer 5517f8a436eSJoe Stringer err = __ovs_ct_lookup(net, key, info, skb); 5527f8a436eSJoe Stringer if (err) 5537f8a436eSJoe Stringer return err; 5549f13ded8SJarno Rajahalme /* This is a no-op if the connection has already been confirmed. */ 5557f8a436eSJoe Stringer if (nf_conntrack_confirm(skb) != NF_ACCEPT) 5567f8a436eSJoe Stringer return -EINVAL; 5577f8a436eSJoe Stringer 5587f8a436eSJoe Stringer return 0; 5597f8a436eSJoe Stringer } 5607f8a436eSJoe Stringer 56133db4125SJoe Stringer static bool labels_nonzero(const struct ovs_key_ct_labels *labels) 562c2ac6673SJoe Stringer { 563c2ac6673SJoe Stringer size_t i; 564c2ac6673SJoe Stringer 56533db4125SJoe Stringer for (i = 0; i < sizeof(*labels); i++) 56633db4125SJoe Stringer if (labels->ct_labels[i]) 567c2ac6673SJoe Stringer return true; 568c2ac6673SJoe Stringer 569c2ac6673SJoe Stringer return false; 570c2ac6673SJoe Stringer } 571c2ac6673SJoe Stringer 57274c16618SJoe Stringer /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero 57374c16618SJoe Stringer * value if 'skb' is freed. 57474c16618SJoe Stringer */ 5757f8a436eSJoe Stringer int ovs_ct_execute(struct net *net, struct sk_buff *skb, 5767f8a436eSJoe Stringer struct sw_flow_key *key, 5777f8a436eSJoe Stringer const struct ovs_conntrack_info *info) 5787f8a436eSJoe Stringer { 5797f8a436eSJoe Stringer int nh_ofs; 5807f8a436eSJoe Stringer int err; 5817f8a436eSJoe Stringer 5827f8a436eSJoe Stringer /* The conntrack module expects to be working at L3. */ 5837f8a436eSJoe Stringer nh_ofs = skb_network_offset(skb); 5847f8a436eSJoe Stringer skb_pull(skb, nh_ofs); 5857f8a436eSJoe Stringer 5867f8a436eSJoe Stringer if (key->ip.frag != OVS_FRAG_TYPE_NONE) { 5877f8a436eSJoe Stringer err = handle_fragments(net, key, info->zone.id, skb); 5887f8a436eSJoe Stringer if (err) 5897f8a436eSJoe Stringer return err; 5907f8a436eSJoe Stringer } 5917f8a436eSJoe Stringer 592ab38a7b5SJoe Stringer if (info->commit) 5937f8a436eSJoe Stringer err = ovs_ct_commit(net, key, info, skb); 5947f8a436eSJoe Stringer else 5957f8a436eSJoe Stringer err = ovs_ct_lookup(net, key, info, skb); 596182e3042SJoe Stringer if (err) 597182e3042SJoe Stringer goto err; 5987f8a436eSJoe Stringer 599c2ac6673SJoe Stringer if (info->mark.mask) { 600182e3042SJoe Stringer err = ovs_ct_set_mark(skb, key, info->mark.value, 601182e3042SJoe Stringer info->mark.mask); 602c2ac6673SJoe Stringer if (err) 603c2ac6673SJoe Stringer goto err; 604c2ac6673SJoe Stringer } 60533db4125SJoe Stringer if (labels_nonzero(&info->labels.mask)) 60633db4125SJoe Stringer err = ovs_ct_set_labels(skb, key, &info->labels.value, 60733db4125SJoe Stringer &info->labels.mask); 608182e3042SJoe Stringer err: 6097f8a436eSJoe Stringer skb_push(skb, nh_ofs); 61074c16618SJoe Stringer if (err) 61174c16618SJoe Stringer kfree_skb(skb); 6127f8a436eSJoe Stringer return err; 6137f8a436eSJoe Stringer } 6147f8a436eSJoe Stringer 615cae3a262SJoe Stringer static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name, 616cae3a262SJoe Stringer const struct sw_flow_key *key, bool log) 617cae3a262SJoe Stringer { 618cae3a262SJoe Stringer struct nf_conntrack_helper *helper; 619cae3a262SJoe Stringer struct nf_conn_help *help; 620cae3a262SJoe Stringer 621cae3a262SJoe Stringer helper = nf_conntrack_helper_try_module_get(name, info->family, 622cae3a262SJoe Stringer key->ip.proto); 623cae3a262SJoe Stringer if (!helper) { 624cae3a262SJoe Stringer OVS_NLERR(log, "Unknown helper \"%s\"", name); 625cae3a262SJoe Stringer return -EINVAL; 626cae3a262SJoe Stringer } 627cae3a262SJoe Stringer 628cae3a262SJoe Stringer help = nf_ct_helper_ext_add(info->ct, helper, GFP_KERNEL); 629cae3a262SJoe Stringer if (!help) { 630cae3a262SJoe Stringer module_put(helper->me); 631cae3a262SJoe Stringer return -ENOMEM; 632cae3a262SJoe Stringer } 633cae3a262SJoe Stringer 634cae3a262SJoe Stringer rcu_assign_pointer(help->helper, helper); 635cae3a262SJoe Stringer info->helper = helper; 636cae3a262SJoe Stringer return 0; 637cae3a262SJoe Stringer } 638cae3a262SJoe Stringer 6397f8a436eSJoe Stringer static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { 640ab38a7b5SJoe Stringer [OVS_CT_ATTR_COMMIT] = { .minlen = 0, .maxlen = 0 }, 6417f8a436eSJoe Stringer [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), 6427f8a436eSJoe Stringer .maxlen = sizeof(u16) }, 643182e3042SJoe Stringer [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark), 644182e3042SJoe Stringer .maxlen = sizeof(struct md_mark) }, 64533db4125SJoe Stringer [OVS_CT_ATTR_LABELS] = { .minlen = sizeof(struct md_labels), 64633db4125SJoe Stringer .maxlen = sizeof(struct md_labels) }, 647cae3a262SJoe Stringer [OVS_CT_ATTR_HELPER] = { .minlen = 1, 648cae3a262SJoe Stringer .maxlen = NF_CT_HELPER_NAME_LEN } 6497f8a436eSJoe Stringer }; 6507f8a436eSJoe Stringer 6517f8a436eSJoe Stringer static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, 652cae3a262SJoe Stringer const char **helper, bool log) 6537f8a436eSJoe Stringer { 6547f8a436eSJoe Stringer struct nlattr *a; 6557f8a436eSJoe Stringer int rem; 6567f8a436eSJoe Stringer 6577f8a436eSJoe Stringer nla_for_each_nested(a, attr, rem) { 6587f8a436eSJoe Stringer int type = nla_type(a); 6597f8a436eSJoe Stringer int maxlen = ovs_ct_attr_lens[type].maxlen; 6607f8a436eSJoe Stringer int minlen = ovs_ct_attr_lens[type].minlen; 6617f8a436eSJoe Stringer 6627f8a436eSJoe Stringer if (type > OVS_CT_ATTR_MAX) { 6637f8a436eSJoe Stringer OVS_NLERR(log, 6647f8a436eSJoe Stringer "Unknown conntrack attr (type=%d, max=%d)", 6657f8a436eSJoe Stringer type, OVS_CT_ATTR_MAX); 6667f8a436eSJoe Stringer return -EINVAL; 6677f8a436eSJoe Stringer } 6687f8a436eSJoe Stringer if (nla_len(a) < minlen || nla_len(a) > maxlen) { 6697f8a436eSJoe Stringer OVS_NLERR(log, 6707f8a436eSJoe Stringer "Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)", 6717f8a436eSJoe Stringer type, nla_len(a), maxlen); 6727f8a436eSJoe Stringer return -EINVAL; 6737f8a436eSJoe Stringer } 6747f8a436eSJoe Stringer 6757f8a436eSJoe Stringer switch (type) { 676ab38a7b5SJoe Stringer case OVS_CT_ATTR_COMMIT: 677ab38a7b5SJoe Stringer info->commit = true; 6787f8a436eSJoe Stringer break; 6797f8a436eSJoe Stringer #ifdef CONFIG_NF_CONNTRACK_ZONES 6807f8a436eSJoe Stringer case OVS_CT_ATTR_ZONE: 6817f8a436eSJoe Stringer info->zone.id = nla_get_u16(a); 6827f8a436eSJoe Stringer break; 6837f8a436eSJoe Stringer #endif 684182e3042SJoe Stringer #ifdef CONFIG_NF_CONNTRACK_MARK 685182e3042SJoe Stringer case OVS_CT_ATTR_MARK: { 686182e3042SJoe Stringer struct md_mark *mark = nla_data(a); 687182e3042SJoe Stringer 688e754ec69SJoe Stringer if (!mark->mask) { 689e754ec69SJoe Stringer OVS_NLERR(log, "ct_mark mask cannot be 0"); 690e754ec69SJoe Stringer return -EINVAL; 691e754ec69SJoe Stringer } 692182e3042SJoe Stringer info->mark = *mark; 693182e3042SJoe Stringer break; 694182e3042SJoe Stringer } 695182e3042SJoe Stringer #endif 696c2ac6673SJoe Stringer #ifdef CONFIG_NF_CONNTRACK_LABELS 69733db4125SJoe Stringer case OVS_CT_ATTR_LABELS: { 69833db4125SJoe Stringer struct md_labels *labels = nla_data(a); 699c2ac6673SJoe Stringer 700e754ec69SJoe Stringer if (!labels_nonzero(&labels->mask)) { 701e754ec69SJoe Stringer OVS_NLERR(log, "ct_labels mask cannot be 0"); 702e754ec69SJoe Stringer return -EINVAL; 703e754ec69SJoe Stringer } 70433db4125SJoe Stringer info->labels = *labels; 705c2ac6673SJoe Stringer break; 706c2ac6673SJoe Stringer } 707c2ac6673SJoe Stringer #endif 708cae3a262SJoe Stringer case OVS_CT_ATTR_HELPER: 709cae3a262SJoe Stringer *helper = nla_data(a); 710cae3a262SJoe Stringer if (!memchr(*helper, '\0', nla_len(a))) { 711cae3a262SJoe Stringer OVS_NLERR(log, "Invalid conntrack helper"); 712cae3a262SJoe Stringer return -EINVAL; 713cae3a262SJoe Stringer } 714cae3a262SJoe Stringer break; 7157f8a436eSJoe Stringer default: 7167f8a436eSJoe Stringer OVS_NLERR(log, "Unknown conntrack attr (%d)", 7177f8a436eSJoe Stringer type); 7187f8a436eSJoe Stringer return -EINVAL; 7197f8a436eSJoe Stringer } 7207f8a436eSJoe Stringer } 7217f8a436eSJoe Stringer 7227f8a436eSJoe Stringer if (rem > 0) { 7237f8a436eSJoe Stringer OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem); 7247f8a436eSJoe Stringer return -EINVAL; 7257f8a436eSJoe Stringer } 7267f8a436eSJoe Stringer 7277f8a436eSJoe Stringer return 0; 7287f8a436eSJoe Stringer } 7297f8a436eSJoe Stringer 730c2ac6673SJoe Stringer bool ovs_ct_verify(struct net *net, enum ovs_key_attr attr) 7317f8a436eSJoe Stringer { 7327f8a436eSJoe Stringer if (attr == OVS_KEY_ATTR_CT_STATE) 7337f8a436eSJoe Stringer return true; 7347f8a436eSJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 7357f8a436eSJoe Stringer attr == OVS_KEY_ATTR_CT_ZONE) 7367f8a436eSJoe Stringer return true; 737182e3042SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && 738182e3042SJoe Stringer attr == OVS_KEY_ATTR_CT_MARK) 739182e3042SJoe Stringer return true; 740c2ac6673SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 74133db4125SJoe Stringer attr == OVS_KEY_ATTR_CT_LABELS) { 742c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 743c2ac6673SJoe Stringer 744c2ac6673SJoe Stringer return ovs_net->xt_label; 745c2ac6673SJoe Stringer } 7467f8a436eSJoe Stringer 7477f8a436eSJoe Stringer return false; 7487f8a436eSJoe Stringer } 7497f8a436eSJoe Stringer 7507f8a436eSJoe Stringer int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, 7517f8a436eSJoe Stringer const struct sw_flow_key *key, 7527f8a436eSJoe Stringer struct sw_flow_actions **sfa, bool log) 7537f8a436eSJoe Stringer { 7547f8a436eSJoe Stringer struct ovs_conntrack_info ct_info; 755cae3a262SJoe Stringer const char *helper = NULL; 7567f8a436eSJoe Stringer u16 family; 7577f8a436eSJoe Stringer int err; 7587f8a436eSJoe Stringer 7597f8a436eSJoe Stringer family = key_to_nfproto(key); 7607f8a436eSJoe Stringer if (family == NFPROTO_UNSPEC) { 7617f8a436eSJoe Stringer OVS_NLERR(log, "ct family unspecified"); 7627f8a436eSJoe Stringer return -EINVAL; 7637f8a436eSJoe Stringer } 7647f8a436eSJoe Stringer 7657f8a436eSJoe Stringer memset(&ct_info, 0, sizeof(ct_info)); 7667f8a436eSJoe Stringer ct_info.family = family; 7677f8a436eSJoe Stringer 7687f8a436eSJoe Stringer nf_ct_zone_init(&ct_info.zone, NF_CT_DEFAULT_ZONE_ID, 7697f8a436eSJoe Stringer NF_CT_DEFAULT_ZONE_DIR, 0); 7707f8a436eSJoe Stringer 771cae3a262SJoe Stringer err = parse_ct(attr, &ct_info, &helper, log); 7727f8a436eSJoe Stringer if (err) 7737f8a436eSJoe Stringer return err; 7747f8a436eSJoe Stringer 7757f8a436eSJoe Stringer /* Set up template for tracking connections in specific zones. */ 7767f8a436eSJoe Stringer ct_info.ct = nf_ct_tmpl_alloc(net, &ct_info.zone, GFP_KERNEL); 7777f8a436eSJoe Stringer if (!ct_info.ct) { 7787f8a436eSJoe Stringer OVS_NLERR(log, "Failed to allocate conntrack template"); 7797f8a436eSJoe Stringer return -ENOMEM; 7807f8a436eSJoe Stringer } 78190c7afc9SJoe Stringer 78290c7afc9SJoe Stringer __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status); 78390c7afc9SJoe Stringer nf_conntrack_get(&ct_info.ct->ct_general); 78490c7afc9SJoe Stringer 785cae3a262SJoe Stringer if (helper) { 786cae3a262SJoe Stringer err = ovs_ct_add_helper(&ct_info, helper, key, log); 787cae3a262SJoe Stringer if (err) 788cae3a262SJoe Stringer goto err_free_ct; 789cae3a262SJoe Stringer } 7907f8a436eSJoe Stringer 7917f8a436eSJoe Stringer err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info, 7927f8a436eSJoe Stringer sizeof(ct_info), log); 7937f8a436eSJoe Stringer if (err) 7947f8a436eSJoe Stringer goto err_free_ct; 7957f8a436eSJoe Stringer 7967f8a436eSJoe Stringer return 0; 7977f8a436eSJoe Stringer err_free_ct: 7982f3ab9f9SJoe Stringer __ovs_ct_free_action(&ct_info); 7997f8a436eSJoe Stringer return err; 8007f8a436eSJoe Stringer } 8017f8a436eSJoe Stringer 8027f8a436eSJoe Stringer int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, 8037f8a436eSJoe Stringer struct sk_buff *skb) 8047f8a436eSJoe Stringer { 8057f8a436eSJoe Stringer struct nlattr *start; 8067f8a436eSJoe Stringer 8077f8a436eSJoe Stringer start = nla_nest_start(skb, OVS_ACTION_ATTR_CT); 8087f8a436eSJoe Stringer if (!start) 8097f8a436eSJoe Stringer return -EMSGSIZE; 8107f8a436eSJoe Stringer 811ab38a7b5SJoe Stringer if (ct_info->commit && nla_put_flag(skb, OVS_CT_ATTR_COMMIT)) 8127f8a436eSJoe Stringer return -EMSGSIZE; 8137f8a436eSJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 8147f8a436eSJoe Stringer nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) 8157f8a436eSJoe Stringer return -EMSGSIZE; 816e754ec69SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && ct_info->mark.mask && 817182e3042SJoe Stringer nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), 818182e3042SJoe Stringer &ct_info->mark)) 819182e3042SJoe Stringer return -EMSGSIZE; 820c2ac6673SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 821e754ec69SJoe Stringer labels_nonzero(&ct_info->labels.mask) && 82233db4125SJoe Stringer nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels), 82333db4125SJoe Stringer &ct_info->labels)) 824c2ac6673SJoe Stringer return -EMSGSIZE; 825cae3a262SJoe Stringer if (ct_info->helper) { 826cae3a262SJoe Stringer if (nla_put_string(skb, OVS_CT_ATTR_HELPER, 827cae3a262SJoe Stringer ct_info->helper->name)) 828cae3a262SJoe Stringer return -EMSGSIZE; 829cae3a262SJoe Stringer } 8307f8a436eSJoe Stringer 8317f8a436eSJoe Stringer nla_nest_end(skb, start); 8327f8a436eSJoe Stringer 8337f8a436eSJoe Stringer return 0; 8347f8a436eSJoe Stringer } 8357f8a436eSJoe Stringer 8367f8a436eSJoe Stringer void ovs_ct_free_action(const struct nlattr *a) 8377f8a436eSJoe Stringer { 8387f8a436eSJoe Stringer struct ovs_conntrack_info *ct_info = nla_data(a); 8397f8a436eSJoe Stringer 8402f3ab9f9SJoe Stringer __ovs_ct_free_action(ct_info); 8412f3ab9f9SJoe Stringer } 8422f3ab9f9SJoe Stringer 8432f3ab9f9SJoe Stringer static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info) 8442f3ab9f9SJoe Stringer { 845cae3a262SJoe Stringer if (ct_info->helper) 846cae3a262SJoe Stringer module_put(ct_info->helper->me); 8477f8a436eSJoe Stringer if (ct_info->ct) 8487f8a436eSJoe Stringer nf_ct_put(ct_info->ct); 8497f8a436eSJoe Stringer } 850c2ac6673SJoe Stringer 851c2ac6673SJoe Stringer void ovs_ct_init(struct net *net) 852c2ac6673SJoe Stringer { 85333db4125SJoe Stringer unsigned int n_bits = sizeof(struct ovs_key_ct_labels) * BITS_PER_BYTE; 854c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 855c2ac6673SJoe Stringer 856c2ac6673SJoe Stringer if (nf_connlabels_get(net, n_bits)) { 857c2ac6673SJoe Stringer ovs_net->xt_label = false; 858c2ac6673SJoe Stringer OVS_NLERR(true, "Failed to set connlabel length"); 859c2ac6673SJoe Stringer } else { 860c2ac6673SJoe Stringer ovs_net->xt_label = true; 861c2ac6673SJoe Stringer } 862c2ac6673SJoe Stringer } 863c2ac6673SJoe Stringer 864c2ac6673SJoe Stringer void ovs_ct_exit(struct net *net) 865c2ac6673SJoe Stringer { 866c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 867c2ac6673SJoe Stringer 868c2ac6673SJoe Stringer if (ovs_net->xt_label) 869c2ac6673SJoe Stringer nf_connlabels_put(net); 870c2ac6673SJoe Stringer } 871