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 */ 486*28b6e0c1SJarno Rajahalme bool cached = skb_nfct_cached(net, key, info, skb); 487*28b6e0c1SJarno Rajahalme enum ip_conntrack_info ctinfo; 488*28b6e0c1SJarno Rajahalme struct nf_conn *ct; 489*28b6e0c1SJarno Rajahalme 490*28b6e0c1SJarno Rajahalme if (!cached) { 4917f8a436eSJoe Stringer struct nf_conn *tmpl = info->ct; 4925b6b9293SJarno Rajahalme int err; 4937f8a436eSJoe Stringer 4947f8a436eSJoe Stringer /* Associate skb with specified zone. */ 4957f8a436eSJoe Stringer if (tmpl) { 4967f8a436eSJoe Stringer if (skb->nfct) 4977f8a436eSJoe Stringer nf_conntrack_put(skb->nfct); 4987f8a436eSJoe Stringer nf_conntrack_get(&tmpl->ct_general); 4997f8a436eSJoe Stringer skb->nfct = &tmpl->ct_general; 5007f8a436eSJoe Stringer skb->nfctinfo = IP_CT_NEW; 5017f8a436eSJoe Stringer } 5027f8a436eSJoe Stringer 5035b6b9293SJarno Rajahalme /* Repeat if requested, see nf_iterate(). */ 5045b6b9293SJarno Rajahalme do { 5055b6b9293SJarno Rajahalme err = nf_conntrack_in(net, info->family, 5065b6b9293SJarno Rajahalme NF_INET_PRE_ROUTING, skb); 5075b6b9293SJarno Rajahalme } while (err == NF_REPEAT); 5085b6b9293SJarno Rajahalme 5095b6b9293SJarno Rajahalme if (err != NF_ACCEPT) 5107f8a436eSJoe Stringer return -ENOENT; 511cae3a262SJoe Stringer 512394e910eSJarno Rajahalme ovs_ct_update_key(skb, info, key, true); 513*28b6e0c1SJarno Rajahalme } 514394e910eSJarno Rajahalme 515*28b6e0c1SJarno Rajahalme /* Call the helper only if: 516*28b6e0c1SJarno Rajahalme * - nf_conntrack_in() was executed above ("!cached") for a confirmed 517*28b6e0c1SJarno Rajahalme * connection, or 518*28b6e0c1SJarno Rajahalme * - When committing an unconfirmed connection. 519*28b6e0c1SJarno Rajahalme */ 520*28b6e0c1SJarno Rajahalme ct = nf_ct_get(skb, &ctinfo); 521*28b6e0c1SJarno Rajahalme if (ct && (nf_ct_is_confirmed(ct) ? !cached : info->commit) && 522*28b6e0c1SJarno Rajahalme ovs_ct_helper(skb, info->family) != NF_ACCEPT) { 523cae3a262SJoe Stringer WARN_ONCE(1, "helper rejected packet"); 524cae3a262SJoe Stringer return -EINVAL; 525cae3a262SJoe Stringer } 5267f8a436eSJoe Stringer 5277f8a436eSJoe Stringer return 0; 5287f8a436eSJoe Stringer } 5297f8a436eSJoe Stringer 5307f8a436eSJoe Stringer /* Lookup connection and read fields into key. */ 5317f8a436eSJoe Stringer static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, 5327f8a436eSJoe Stringer const struct ovs_conntrack_info *info, 5337f8a436eSJoe Stringer struct sk_buff *skb) 5347f8a436eSJoe Stringer { 5357f8a436eSJoe Stringer struct nf_conntrack_expect *exp; 5367f8a436eSJoe Stringer 5379f13ded8SJarno Rajahalme /* If we pass an expected packet through nf_conntrack_in() the 5389f13ded8SJarno Rajahalme * expectation is typically removed, but the packet could still be 5399f13ded8SJarno Rajahalme * lost in upcall processing. To prevent this from happening we 5409f13ded8SJarno Rajahalme * perform an explicit expectation lookup. Expected connections are 5419f13ded8SJarno Rajahalme * always new, and will be passed through conntrack only when they are 5429f13ded8SJarno Rajahalme * committed, as it is OK to remove the expectation at that time. 5439f13ded8SJarno Rajahalme */ 5447f8a436eSJoe Stringer exp = ovs_ct_expect_find(net, &info->zone, info->family, skb); 5457f8a436eSJoe Stringer if (exp) { 5467f8a436eSJoe Stringer u8 state; 5477f8a436eSJoe Stringer 5487f8a436eSJoe Stringer state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED; 549182e3042SJoe Stringer __ovs_ct_update_key(key, state, &info->zone, exp->master); 5507f8a436eSJoe Stringer } else { 5517f8a436eSJoe Stringer int err; 5527f8a436eSJoe Stringer 5537f8a436eSJoe Stringer err = __ovs_ct_lookup(net, key, info, skb); 5547f8a436eSJoe Stringer if (err) 5557f8a436eSJoe Stringer return err; 5567f8a436eSJoe Stringer } 5577f8a436eSJoe Stringer 5587f8a436eSJoe Stringer return 0; 5597f8a436eSJoe Stringer } 5607f8a436eSJoe Stringer 5617f8a436eSJoe Stringer /* Lookup connection and confirm if unconfirmed. */ 5627f8a436eSJoe Stringer static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, 5637f8a436eSJoe Stringer const struct ovs_conntrack_info *info, 5647f8a436eSJoe Stringer struct sk_buff *skb) 5657f8a436eSJoe Stringer { 5667f8a436eSJoe Stringer int err; 5677f8a436eSJoe Stringer 5687f8a436eSJoe Stringer err = __ovs_ct_lookup(net, key, info, skb); 5697f8a436eSJoe Stringer if (err) 5707f8a436eSJoe Stringer return err; 5719f13ded8SJarno Rajahalme /* This is a no-op if the connection has already been confirmed. */ 5727f8a436eSJoe Stringer if (nf_conntrack_confirm(skb) != NF_ACCEPT) 5737f8a436eSJoe Stringer return -EINVAL; 5747f8a436eSJoe Stringer 5757f8a436eSJoe Stringer return 0; 5767f8a436eSJoe Stringer } 5777f8a436eSJoe Stringer 57833db4125SJoe Stringer static bool labels_nonzero(const struct ovs_key_ct_labels *labels) 579c2ac6673SJoe Stringer { 580c2ac6673SJoe Stringer size_t i; 581c2ac6673SJoe Stringer 58233db4125SJoe Stringer for (i = 0; i < sizeof(*labels); i++) 58333db4125SJoe Stringer if (labels->ct_labels[i]) 584c2ac6673SJoe Stringer return true; 585c2ac6673SJoe Stringer 586c2ac6673SJoe Stringer return false; 587c2ac6673SJoe Stringer } 588c2ac6673SJoe Stringer 58974c16618SJoe Stringer /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero 59074c16618SJoe Stringer * value if 'skb' is freed. 59174c16618SJoe Stringer */ 5927f8a436eSJoe Stringer int ovs_ct_execute(struct net *net, struct sk_buff *skb, 5937f8a436eSJoe Stringer struct sw_flow_key *key, 5947f8a436eSJoe Stringer const struct ovs_conntrack_info *info) 5957f8a436eSJoe Stringer { 5967f8a436eSJoe Stringer int nh_ofs; 5977f8a436eSJoe Stringer int err; 5987f8a436eSJoe Stringer 5997f8a436eSJoe Stringer /* The conntrack module expects to be working at L3. */ 6007f8a436eSJoe Stringer nh_ofs = skb_network_offset(skb); 6017f8a436eSJoe Stringer skb_pull(skb, nh_ofs); 6027f8a436eSJoe Stringer 6037f8a436eSJoe Stringer if (key->ip.frag != OVS_FRAG_TYPE_NONE) { 6047f8a436eSJoe Stringer err = handle_fragments(net, key, info->zone.id, skb); 6057f8a436eSJoe Stringer if (err) 6067f8a436eSJoe Stringer return err; 6077f8a436eSJoe Stringer } 6087f8a436eSJoe Stringer 609ab38a7b5SJoe Stringer if (info->commit) 6107f8a436eSJoe Stringer err = ovs_ct_commit(net, key, info, skb); 6117f8a436eSJoe Stringer else 6127f8a436eSJoe Stringer err = ovs_ct_lookup(net, key, info, skb); 613182e3042SJoe Stringer if (err) 614182e3042SJoe Stringer goto err; 6157f8a436eSJoe Stringer 616c2ac6673SJoe Stringer if (info->mark.mask) { 617182e3042SJoe Stringer err = ovs_ct_set_mark(skb, key, info->mark.value, 618182e3042SJoe Stringer info->mark.mask); 619c2ac6673SJoe Stringer if (err) 620c2ac6673SJoe Stringer goto err; 621c2ac6673SJoe Stringer } 62233db4125SJoe Stringer if (labels_nonzero(&info->labels.mask)) 62333db4125SJoe Stringer err = ovs_ct_set_labels(skb, key, &info->labels.value, 62433db4125SJoe Stringer &info->labels.mask); 625182e3042SJoe Stringer err: 6267f8a436eSJoe Stringer skb_push(skb, nh_ofs); 62774c16618SJoe Stringer if (err) 62874c16618SJoe Stringer kfree_skb(skb); 6297f8a436eSJoe Stringer return err; 6307f8a436eSJoe Stringer } 6317f8a436eSJoe Stringer 632cae3a262SJoe Stringer static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name, 633cae3a262SJoe Stringer const struct sw_flow_key *key, bool log) 634cae3a262SJoe Stringer { 635cae3a262SJoe Stringer struct nf_conntrack_helper *helper; 636cae3a262SJoe Stringer struct nf_conn_help *help; 637cae3a262SJoe Stringer 638cae3a262SJoe Stringer helper = nf_conntrack_helper_try_module_get(name, info->family, 639cae3a262SJoe Stringer key->ip.proto); 640cae3a262SJoe Stringer if (!helper) { 641cae3a262SJoe Stringer OVS_NLERR(log, "Unknown helper \"%s\"", name); 642cae3a262SJoe Stringer return -EINVAL; 643cae3a262SJoe Stringer } 644cae3a262SJoe Stringer 645cae3a262SJoe Stringer help = nf_ct_helper_ext_add(info->ct, helper, GFP_KERNEL); 646cae3a262SJoe Stringer if (!help) { 647cae3a262SJoe Stringer module_put(helper->me); 648cae3a262SJoe Stringer return -ENOMEM; 649cae3a262SJoe Stringer } 650cae3a262SJoe Stringer 651cae3a262SJoe Stringer rcu_assign_pointer(help->helper, helper); 652cae3a262SJoe Stringer info->helper = helper; 653cae3a262SJoe Stringer return 0; 654cae3a262SJoe Stringer } 655cae3a262SJoe Stringer 6567f8a436eSJoe Stringer static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { 657ab38a7b5SJoe Stringer [OVS_CT_ATTR_COMMIT] = { .minlen = 0, .maxlen = 0 }, 6587f8a436eSJoe Stringer [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), 6597f8a436eSJoe Stringer .maxlen = sizeof(u16) }, 660182e3042SJoe Stringer [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark), 661182e3042SJoe Stringer .maxlen = sizeof(struct md_mark) }, 66233db4125SJoe Stringer [OVS_CT_ATTR_LABELS] = { .minlen = sizeof(struct md_labels), 66333db4125SJoe Stringer .maxlen = sizeof(struct md_labels) }, 664cae3a262SJoe Stringer [OVS_CT_ATTR_HELPER] = { .minlen = 1, 665cae3a262SJoe Stringer .maxlen = NF_CT_HELPER_NAME_LEN } 6667f8a436eSJoe Stringer }; 6677f8a436eSJoe Stringer 6687f8a436eSJoe Stringer static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, 669cae3a262SJoe Stringer const char **helper, bool log) 6707f8a436eSJoe Stringer { 6717f8a436eSJoe Stringer struct nlattr *a; 6727f8a436eSJoe Stringer int rem; 6737f8a436eSJoe Stringer 6747f8a436eSJoe Stringer nla_for_each_nested(a, attr, rem) { 6757f8a436eSJoe Stringer int type = nla_type(a); 6767f8a436eSJoe Stringer int maxlen = ovs_ct_attr_lens[type].maxlen; 6777f8a436eSJoe Stringer int minlen = ovs_ct_attr_lens[type].minlen; 6787f8a436eSJoe Stringer 6797f8a436eSJoe Stringer if (type > OVS_CT_ATTR_MAX) { 6807f8a436eSJoe Stringer OVS_NLERR(log, 6817f8a436eSJoe Stringer "Unknown conntrack attr (type=%d, max=%d)", 6827f8a436eSJoe Stringer type, OVS_CT_ATTR_MAX); 6837f8a436eSJoe Stringer return -EINVAL; 6847f8a436eSJoe Stringer } 6857f8a436eSJoe Stringer if (nla_len(a) < minlen || nla_len(a) > maxlen) { 6867f8a436eSJoe Stringer OVS_NLERR(log, 6877f8a436eSJoe Stringer "Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)", 6887f8a436eSJoe Stringer type, nla_len(a), maxlen); 6897f8a436eSJoe Stringer return -EINVAL; 6907f8a436eSJoe Stringer } 6917f8a436eSJoe Stringer 6927f8a436eSJoe Stringer switch (type) { 693ab38a7b5SJoe Stringer case OVS_CT_ATTR_COMMIT: 694ab38a7b5SJoe Stringer info->commit = true; 6957f8a436eSJoe Stringer break; 6967f8a436eSJoe Stringer #ifdef CONFIG_NF_CONNTRACK_ZONES 6977f8a436eSJoe Stringer case OVS_CT_ATTR_ZONE: 6987f8a436eSJoe Stringer info->zone.id = nla_get_u16(a); 6997f8a436eSJoe Stringer break; 7007f8a436eSJoe Stringer #endif 701182e3042SJoe Stringer #ifdef CONFIG_NF_CONNTRACK_MARK 702182e3042SJoe Stringer case OVS_CT_ATTR_MARK: { 703182e3042SJoe Stringer struct md_mark *mark = nla_data(a); 704182e3042SJoe Stringer 705e754ec69SJoe Stringer if (!mark->mask) { 706e754ec69SJoe Stringer OVS_NLERR(log, "ct_mark mask cannot be 0"); 707e754ec69SJoe Stringer return -EINVAL; 708e754ec69SJoe Stringer } 709182e3042SJoe Stringer info->mark = *mark; 710182e3042SJoe Stringer break; 711182e3042SJoe Stringer } 712182e3042SJoe Stringer #endif 713c2ac6673SJoe Stringer #ifdef CONFIG_NF_CONNTRACK_LABELS 71433db4125SJoe Stringer case OVS_CT_ATTR_LABELS: { 71533db4125SJoe Stringer struct md_labels *labels = nla_data(a); 716c2ac6673SJoe Stringer 717e754ec69SJoe Stringer if (!labels_nonzero(&labels->mask)) { 718e754ec69SJoe Stringer OVS_NLERR(log, "ct_labels mask cannot be 0"); 719e754ec69SJoe Stringer return -EINVAL; 720e754ec69SJoe Stringer } 72133db4125SJoe Stringer info->labels = *labels; 722c2ac6673SJoe Stringer break; 723c2ac6673SJoe Stringer } 724c2ac6673SJoe Stringer #endif 725cae3a262SJoe Stringer case OVS_CT_ATTR_HELPER: 726cae3a262SJoe Stringer *helper = nla_data(a); 727cae3a262SJoe Stringer if (!memchr(*helper, '\0', nla_len(a))) { 728cae3a262SJoe Stringer OVS_NLERR(log, "Invalid conntrack helper"); 729cae3a262SJoe Stringer return -EINVAL; 730cae3a262SJoe Stringer } 731cae3a262SJoe Stringer break; 7327f8a436eSJoe Stringer default: 7337f8a436eSJoe Stringer OVS_NLERR(log, "Unknown conntrack attr (%d)", 7347f8a436eSJoe Stringer type); 7357f8a436eSJoe Stringer return -EINVAL; 7367f8a436eSJoe Stringer } 7377f8a436eSJoe Stringer } 7387f8a436eSJoe Stringer 7397f8a436eSJoe Stringer if (rem > 0) { 7407f8a436eSJoe Stringer OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem); 7417f8a436eSJoe Stringer return -EINVAL; 7427f8a436eSJoe Stringer } 7437f8a436eSJoe Stringer 7447f8a436eSJoe Stringer return 0; 7457f8a436eSJoe Stringer } 7467f8a436eSJoe Stringer 747c2ac6673SJoe Stringer bool ovs_ct_verify(struct net *net, enum ovs_key_attr attr) 7487f8a436eSJoe Stringer { 7497f8a436eSJoe Stringer if (attr == OVS_KEY_ATTR_CT_STATE) 7507f8a436eSJoe Stringer return true; 7517f8a436eSJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 7527f8a436eSJoe Stringer attr == OVS_KEY_ATTR_CT_ZONE) 7537f8a436eSJoe Stringer return true; 754182e3042SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && 755182e3042SJoe Stringer attr == OVS_KEY_ATTR_CT_MARK) 756182e3042SJoe Stringer return true; 757c2ac6673SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 75833db4125SJoe Stringer attr == OVS_KEY_ATTR_CT_LABELS) { 759c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 760c2ac6673SJoe Stringer 761c2ac6673SJoe Stringer return ovs_net->xt_label; 762c2ac6673SJoe Stringer } 7637f8a436eSJoe Stringer 7647f8a436eSJoe Stringer return false; 7657f8a436eSJoe Stringer } 7667f8a436eSJoe Stringer 7677f8a436eSJoe Stringer int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, 7687f8a436eSJoe Stringer const struct sw_flow_key *key, 7697f8a436eSJoe Stringer struct sw_flow_actions **sfa, bool log) 7707f8a436eSJoe Stringer { 7717f8a436eSJoe Stringer struct ovs_conntrack_info ct_info; 772cae3a262SJoe Stringer const char *helper = NULL; 7737f8a436eSJoe Stringer u16 family; 7747f8a436eSJoe Stringer int err; 7757f8a436eSJoe Stringer 7767f8a436eSJoe Stringer family = key_to_nfproto(key); 7777f8a436eSJoe Stringer if (family == NFPROTO_UNSPEC) { 7787f8a436eSJoe Stringer OVS_NLERR(log, "ct family unspecified"); 7797f8a436eSJoe Stringer return -EINVAL; 7807f8a436eSJoe Stringer } 7817f8a436eSJoe Stringer 7827f8a436eSJoe Stringer memset(&ct_info, 0, sizeof(ct_info)); 7837f8a436eSJoe Stringer ct_info.family = family; 7847f8a436eSJoe Stringer 7857f8a436eSJoe Stringer nf_ct_zone_init(&ct_info.zone, NF_CT_DEFAULT_ZONE_ID, 7867f8a436eSJoe Stringer NF_CT_DEFAULT_ZONE_DIR, 0); 7877f8a436eSJoe Stringer 788cae3a262SJoe Stringer err = parse_ct(attr, &ct_info, &helper, log); 7897f8a436eSJoe Stringer if (err) 7907f8a436eSJoe Stringer return err; 7917f8a436eSJoe Stringer 7927f8a436eSJoe Stringer /* Set up template for tracking connections in specific zones. */ 7937f8a436eSJoe Stringer ct_info.ct = nf_ct_tmpl_alloc(net, &ct_info.zone, GFP_KERNEL); 7947f8a436eSJoe Stringer if (!ct_info.ct) { 7957f8a436eSJoe Stringer OVS_NLERR(log, "Failed to allocate conntrack template"); 7967f8a436eSJoe Stringer return -ENOMEM; 7977f8a436eSJoe Stringer } 79890c7afc9SJoe Stringer 79990c7afc9SJoe Stringer __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status); 80090c7afc9SJoe Stringer nf_conntrack_get(&ct_info.ct->ct_general); 80190c7afc9SJoe Stringer 802cae3a262SJoe Stringer if (helper) { 803cae3a262SJoe Stringer err = ovs_ct_add_helper(&ct_info, helper, key, log); 804cae3a262SJoe Stringer if (err) 805cae3a262SJoe Stringer goto err_free_ct; 806cae3a262SJoe Stringer } 8077f8a436eSJoe Stringer 8087f8a436eSJoe Stringer err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info, 8097f8a436eSJoe Stringer sizeof(ct_info), log); 8107f8a436eSJoe Stringer if (err) 8117f8a436eSJoe Stringer goto err_free_ct; 8127f8a436eSJoe Stringer 8137f8a436eSJoe Stringer return 0; 8147f8a436eSJoe Stringer err_free_ct: 8152f3ab9f9SJoe Stringer __ovs_ct_free_action(&ct_info); 8167f8a436eSJoe Stringer return err; 8177f8a436eSJoe Stringer } 8187f8a436eSJoe Stringer 8197f8a436eSJoe Stringer int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, 8207f8a436eSJoe Stringer struct sk_buff *skb) 8217f8a436eSJoe Stringer { 8227f8a436eSJoe Stringer struct nlattr *start; 8237f8a436eSJoe Stringer 8247f8a436eSJoe Stringer start = nla_nest_start(skb, OVS_ACTION_ATTR_CT); 8257f8a436eSJoe Stringer if (!start) 8267f8a436eSJoe Stringer return -EMSGSIZE; 8277f8a436eSJoe Stringer 828ab38a7b5SJoe Stringer if (ct_info->commit && nla_put_flag(skb, OVS_CT_ATTR_COMMIT)) 8297f8a436eSJoe Stringer return -EMSGSIZE; 8307f8a436eSJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 8317f8a436eSJoe Stringer nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) 8327f8a436eSJoe Stringer return -EMSGSIZE; 833e754ec69SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && ct_info->mark.mask && 834182e3042SJoe Stringer nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), 835182e3042SJoe Stringer &ct_info->mark)) 836182e3042SJoe Stringer return -EMSGSIZE; 837c2ac6673SJoe Stringer if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 838e754ec69SJoe Stringer labels_nonzero(&ct_info->labels.mask) && 83933db4125SJoe Stringer nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels), 84033db4125SJoe Stringer &ct_info->labels)) 841c2ac6673SJoe Stringer return -EMSGSIZE; 842cae3a262SJoe Stringer if (ct_info->helper) { 843cae3a262SJoe Stringer if (nla_put_string(skb, OVS_CT_ATTR_HELPER, 844cae3a262SJoe Stringer ct_info->helper->name)) 845cae3a262SJoe Stringer return -EMSGSIZE; 846cae3a262SJoe Stringer } 8477f8a436eSJoe Stringer 8487f8a436eSJoe Stringer nla_nest_end(skb, start); 8497f8a436eSJoe Stringer 8507f8a436eSJoe Stringer return 0; 8517f8a436eSJoe Stringer } 8527f8a436eSJoe Stringer 8537f8a436eSJoe Stringer void ovs_ct_free_action(const struct nlattr *a) 8547f8a436eSJoe Stringer { 8557f8a436eSJoe Stringer struct ovs_conntrack_info *ct_info = nla_data(a); 8567f8a436eSJoe Stringer 8572f3ab9f9SJoe Stringer __ovs_ct_free_action(ct_info); 8582f3ab9f9SJoe Stringer } 8592f3ab9f9SJoe Stringer 8602f3ab9f9SJoe Stringer static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info) 8612f3ab9f9SJoe Stringer { 862cae3a262SJoe Stringer if (ct_info->helper) 863cae3a262SJoe Stringer module_put(ct_info->helper->me); 8647f8a436eSJoe Stringer if (ct_info->ct) 8657f8a436eSJoe Stringer nf_ct_put(ct_info->ct); 8667f8a436eSJoe Stringer } 867c2ac6673SJoe Stringer 868c2ac6673SJoe Stringer void ovs_ct_init(struct net *net) 869c2ac6673SJoe Stringer { 87033db4125SJoe Stringer unsigned int n_bits = sizeof(struct ovs_key_ct_labels) * BITS_PER_BYTE; 871c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 872c2ac6673SJoe Stringer 873c2ac6673SJoe Stringer if (nf_connlabels_get(net, n_bits)) { 874c2ac6673SJoe Stringer ovs_net->xt_label = false; 875c2ac6673SJoe Stringer OVS_NLERR(true, "Failed to set connlabel length"); 876c2ac6673SJoe Stringer } else { 877c2ac6673SJoe Stringer ovs_net->xt_label = true; 878c2ac6673SJoe Stringer } 879c2ac6673SJoe Stringer } 880c2ac6673SJoe Stringer 881c2ac6673SJoe Stringer void ovs_ct_exit(struct net *net) 882c2ac6673SJoe Stringer { 883c2ac6673SJoe Stringer struct ovs_net *ovs_net = net_generic(net, ovs_net_id); 884c2ac6673SJoe Stringer 885c2ac6673SJoe Stringer if (ovs_net->xt_label) 886c2ac6673SJoe Stringer nf_connlabels_put(net); 887c2ac6673SJoe Stringer } 888