History

openvswitch: Add conntrack action

Expose the kernel connection tracker via OVS. Userspace components can make use of the CT action to populate the connection state (ct_state) field for a flow. This state can be subsequently matched. Exposed connection states are OVS_CS_F_*: - NEW (0x01) - Beginning of a new connection. - ESTABLISHED (0x02) - Part of an existing connection. - RELATED (0x04) - Related to an established connection. - INVALID (0x20) - Could not track the connection for this packet. - REPLY_DIR (0x40) - This packet is in the reply direction for the flow. - TRACKED (0x80) - This packet has been sent through conntrack. When the CT action is executed by itself, it will send the packet through the connection tracker and populate the ct_state field with one or more of the connection state flags above. The CT action will always set the TRACKED bit. When the COMMIT flag is passed to the conntrack action, this specifies that information about the connection should be stored. This allows subsequent packets for the same (or related) connections to be correlated with this connection. Sending subsequent packets for the connection through conntrack allows the connection tracker to consider the packets as ESTABLISHED, RELATED, and/or REPLY_DIR. The CT action may optionally take a zone to track the flow within. This allows connections with the same 5-tuple to be kept logically separate from connections in other zones. If the zone is specified, then the "ct_zone" match field will be subsequently populated with the zone id. IP fragments are handled by transparently assembling them as part of the CT action. The maximum received unit (MRU) size is tracked so that refragmentation can occur during output. IP frag handling contributed by Andy Zhou. Based on original design by Justin Pettit.

Joe Stringer committed 11 years ago

Commit 7f8a4361 parent e79e25913 files · +877 −37Browse files

Unified · Split

13 files
  1. include/uapi/linux/openvswitch.h +40 −0
  2. net/openvswitch/Kconfig +11 −0
  3. net/openvswitch/Makefile +2 −0
  4. net/openvswitch/actions.c +169 −6
  5. net/openvswitch/conntrack.c +454 −0
  6. net/openvswitch/conntrack.h +78 −0
  7. net/openvswitch/datapath.c +50 −16
  8. net/openvswitch/datapath.h +6 −0
  9. net/openvswitch/flow.c +2 −0
  10. net/openvswitch/flow.h +6 −0
  11. net/openvswitch/flow_netlink.c +55 −14
  12. net/openvswitch/flow_netlink.h +3 −1
  13. net/openvswitch/vport.c +1 −0
include/uapi/linux/openvswitch.h+40−0
@@ -164,6 +164,9 @@ enum ovs_packet_cmd { · 163 unmodified lines
164164 * %OVS_USERSPACE_ATTR_EGRESS_TUN_PORT attribute, which is sent only if the
165165 * output port is actually a tunnel port. Contains the output tunnel key
166166 * extracted from the packet as nested %OVS_TUNNEL_KEY_ATTR_* attributes.
167+ * @OVS_PACKET_ATTR_MRU: Present for an %OVS_PACKET_CMD_ACTION and
168+ * %OVS_PACKET_ATTR_USERSPACE action specify the Maximum received fragment
169+ * size.
167170 *
168171 * These attributes follow the &struct ovs_header within the Generic Netlink
169172 * payload for %OVS_PACKET_* commands.
@@ -180,6 +183,7 @@ enum ovs_packet_attr { · 10 unmodified lines
180183 OVS_PACKET_ATTR_UNUSED2,
181184 OVS_PACKET_ATTR_PROBE, /* Packet operation is a feature probe,
182185 error logging should be suppressed. */
186+ OVS_PACKET_ATTR_MRU, /* Maximum received IP fragment size. */
183187 __OVS_PACKET_ATTR_MAX
184188 };
185189
@@ -319,6 +323,8 @@ enum ovs_key_attr { · 133 unmodified lines
319323 OVS_KEY_ATTR_MPLS, /* array of struct ovs_key_mpls.
320324 * The implementation may restrict
321325 * the accepted length of the array. */
326+ OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */
327+ OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */
322328
323329 #ifdef __KERNEL__
324330 OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */
@@ -431,6 +437,15 @@ struct ovs_key_nd { · 106 unmodified lines
431437 __u8 nd_tll[ETH_ALEN];
432438 };
433439
440+/* OVS_KEY_ATTR_CT_STATE flags */
441+#define OVS_CS_F_NEW 0x01 /* Beginning of a new connection. */
442+#define OVS_CS_F_ESTABLISHED 0x02 /* Part of an existing connection. */
443+#define OVS_CS_F_RELATED 0x04 /* Related to an established
444+ * connection. */
445+#define OVS_CS_F_INVALID 0x20 /* Could not track connection. */
446+#define OVS_CS_F_REPLY_DIR 0x40 /* Flow is in the reply direction. */
447+#define OVS_CS_F_TRACKED 0x80 /* Conntrack has occurred. */
448+
434449 /**
435450 * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands.
436451 * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow
@@ -594,6 +609,28 @@ struct ovs_action_hash { · 157 unmodified lines
594609 uint32_t hash_basis;
595610 };
596611
612+/**
613+ * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action.
614+ * @OVS_CT_ATTR_FLAGS: u32 connection tracking flags.
615+ * @OVS_CT_ATTR_ZONE: u16 connection tracking zone.
616+ */
617+enum ovs_ct_attr {
618+ OVS_CT_ATTR_UNSPEC,
619+ OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */
620+ OVS_CT_ATTR_ZONE, /* u16 zone id. */
621+ __OVS_CT_ATTR_MAX
622+};
623+
624+#define OVS_CT_ATTR_MAX (__OVS_CT_ATTR_MAX - 1)
625+
626+/*
627+ * OVS_CT_ATTR_FLAGS flags - bitmask of %OVS_CT_F_*
628+ * @OVS_CT_F_COMMIT: Commits the flow to the conntrack table. This allows
629+ * future packets for the same connection to be identified as 'established'
630+ * or 'related'.
631+ */
632+#define OVS_CT_F_COMMIT 0x01
633+
597634 /**
598635 * enum ovs_action_attr - Action types.
599636 *
@@ -623,6 +660,8 @@ struct ovs_action_hash { · 23 unmodified lines
623660 * indicate the new packet contents. This could potentially still be
624661 * %ETH_P_MPLS if the resulting MPLS label stack is not empty. If there
625662 * is no MPLS label stack, as determined by ethertype, no action is taken.
663+ * @OVS_ACTION_ATTR_CT: Track the connection. Populate the conntrack-related
664+ * entries in the flow key.
626665 *
627666 * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all
628667 * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -648,6 +687,7 @@ enum ovs_action_attr { · 19 unmodified lines
648687 * data immediately followed by a mask.
649688 * The data must be zero for the unmasked
650689 * bits. */
690+ OVS_ACTION_ATTR_CT, /* One nested OVS_CT_ATTR_* . */
651691
652692 __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted
653693 * from userspace. */
net/openvswitch/Kconfig+11−0
@@ -31,6 +31,17 @@ config OPENVSWITCH · 30 unmodified lines
3131
3232 If unsure, say N.
3333
34+config OPENVSWITCH_CONNTRACK
35+ bool "Open vSwitch conntrack action support"
36+ depends on OPENVSWITCH
37+ depends on NF_CONNTRACK
38+ default OPENVSWITCH
39+ ---help---
40+ If you say Y here, then Open vSwitch module will be able to pass
41+ packets through conntrack.
42+
43+ Say N to exclude this support and reduce the binary size.
44+
3445 config OPENVSWITCH_GRE
3546 tristate "Open vSwitch GRE tunneling support"
3647 depends on OPENVSWITCH
net/openvswitch/Makefile+2−0
@@ -15,6 +15,8 @@ openvswitch-y := \ · 14 unmodified lines
1515 vport-internal_dev.o \
1616 vport-netdev.o
1717
18+openvswitch-$(CONFIG_OPENVSWITCH_CONNTRACK) += conntrack.o
19+
1820 obj-$(CONFIG_OPENVSWITCH_VXLAN)+= vport-vxlan.o
1921 obj-$(CONFIG_OPENVSWITCH_GENEVE)+= vport-geneve.o
2022 obj-$(CONFIG_OPENVSWITCH_GRE) += vport-gre.o
net/openvswitch/actions.c+169−6
@@ -22,6 +22,7 @@ · 21 unmodified lines
2222 #include <linux/in.h>
2323 #include <linux/ip.h>
2424 #include <linux/openvswitch.h>
25+#include <linux/netfilter_ipv6.h>
2526 #include <linux/sctp.h>
2627 #include <linux/tcp.h>
2728 #include <linux/udp.h>
@@ -29,6 +30,7 @@ · 1 unmodified line
2930 #include <linux/if_arp.h>
3031 #include <linux/if_vlan.h>
3132
33+#include <net/dst.h>
3234 #include <net/ip.h>
3335 #include <net/ipv6.h>
3436 #include <net/checksum.h>
@@ -38,6 +40,7 @@ · 3 unmodified lines
3840
3941 #include "datapath.h"
4042 #include "flow.h"
43+#include "conntrack.h"
4144 #include "vport.h"
4245
4346 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
@@ -52,6 +55,20 @@ struct deferred_action { · 8 unmodified lines
5255 struct sw_flow_key pkt_key;
5356 };
5457
58+#define MAX_L2_LEN (VLAN_ETH_HLEN + 3 * MPLS_HLEN)
59+struct ovs_frag_data {
60+ unsigned long dst;
61+ struct vport *vport;
62+ struct ovs_skb_cb cb;
63+ __be16 inner_protocol;
64+ __u16 vlan_tci;
65+ __be16 vlan_proto;
66+ unsigned int l2_len;
67+ u8 l2_data[MAX_L2_LEN];
68+};
69+
70+static DEFINE_PER_CPU(struct ovs_frag_data, ovs_frag_data_storage);
71+
5572 #define DEFERRED_ACTION_FIFO_SIZE 10
5673 struct action_fifo {
5774 int head;
@@ -602,14 +619,145 @@ static int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key, · 544 unmodified lines
602619 return 0;
603620 }
604621
605−static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
622+static int ovs_vport_output(struct sock *sock, struct sk_buff *skb)
623+{
624+ struct ovs_frag_data *data = this_cpu_ptr(&ovs_frag_data_storage);
625+ struct vport *vport = data->vport;
626+
627+ if (skb_cow_head(skb, data->l2_len) < 0) {
628+ kfree_skb(skb);
629+ return -ENOMEM;
630+ }
631+
632+ __skb_dst_copy(skb, data->dst);
633+ *OVS_CB(skb) = data->cb;
634+ skb->inner_protocol = data->inner_protocol;
635+ skb->vlan_tci = data->vlan_tci;
636+ skb->vlan_proto = data->vlan_proto;
637+
638+ /* Reconstruct the MAC header. */
639+ skb_push(skb, data->l2_len);
640+ memcpy(skb->data, &data->l2_data, data->l2_len);
641+ ovs_skb_postpush_rcsum(skb, skb->data, data->l2_len);
642+ skb_reset_mac_header(skb);
643+
644+ ovs_vport_send(vport, skb);
645+ return 0;
646+}
647+
648+static unsigned int
649+ovs_dst_get_mtu(const struct dst_entry *dst)
650+{
651+ return dst->dev->mtu;
652+}
653+
654+static struct dst_ops ovs_dst_ops = {
655+ .family = AF_UNSPEC,
656+ .mtu = ovs_dst_get_mtu,
657+};
658+
659+/* prepare_frag() is called once per (larger-than-MTU) frame; its inverse is
660+ * ovs_vport_output(), which is called once per fragmented packet.
661+ */
662+static void prepare_frag(struct vport *vport, struct sk_buff *skb)
663+{
664+ unsigned int hlen = skb_network_offset(skb);
665+ struct ovs_frag_data *data;
666+
667+ data = this_cpu_ptr(&ovs_frag_data_storage);
668+ data->dst = skb->_skb_refdst;
669+ data->vport = vport;
670+ data->cb = *OVS_CB(skb);
671+ data->inner_protocol = skb->inner_protocol;
672+ data->vlan_tci = skb->vlan_tci;
673+ data->vlan_proto = skb->vlan_proto;
674+ data->l2_len = hlen;
675+ memcpy(&data->l2_data, skb->data, hlen);
676+
677+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
678+ skb_pull(skb, hlen);
679+}
680+
681+static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru,
682+ __be16 ethertype)
683+{
684+ if (skb_network_offset(skb) > MAX_L2_LEN) {
685+ OVS_NLERR(1, "L2 header too long to fragment");
686+ return;
687+ }
688+
689+ if (ethertype == htons(ETH_P_IP)) {
690+ struct dst_entry ovs_dst;
691+ unsigned long orig_dst;
692+
693+ prepare_frag(vport, skb);
694+ dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1,
695+ DST_OBSOLETE_NONE, DST_NOCOUNT);
696+ ovs_dst.dev = vport->dev;
697+
698+ orig_dst = skb->_skb_refdst;
699+ skb_dst_set_noref(skb, &ovs_dst);
700+ IPCB(skb)->frag_max_size = mru;
701+
702+ ip_do_fragment(skb->sk, skb, ovs_vport_output);
703+ refdst_drop(orig_dst);
704+ } else if (ethertype == htons(ETH_P_IPV6)) {
705+ const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops();
706+ unsigned long orig_dst;
707+ struct rt6_info ovs_rt;
708+
709+ if (!v6ops) {
710+ kfree_skb(skb);
711+ return;
712+ }
713+
714+ prepare_frag(vport, skb);
715+ memset(&ovs_rt, 0, sizeof(ovs_rt));
716+ dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1,
717+ DST_OBSOLETE_NONE, DST_NOCOUNT);
718+ ovs_rt.dst.dev = vport->dev;
719+
720+ orig_dst = skb->_skb_refdst;
721+ skb_dst_set_noref(skb, &ovs_rt.dst);
722+ IP6CB(skb)->frag_max_size = mru;
723+
724+ v6ops->fragment(skb->sk, skb, ovs_vport_output);
725+ refdst_drop(orig_dst);
726+ } else {
727+ WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
728+ ovs_vport_name(vport), ntohs(ethertype), mru,
729+ vport->dev->mtu);
730+ kfree_skb(skb);
731+ }
732+}
733+
734+static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
735+ struct sw_flow_key *key)
606736 {
607737 struct vport *vport = ovs_vport_rcu(dp, out_port);
608738
609− if (likely(vport))
610− ovs_vport_send(vport, skb);
611− else
739+ if (likely(vport)) {
740+ u16 mru = OVS_CB(skb)->mru;
741+
742+ if (likely(!mru || (skb->len <= mru + ETH_HLEN))) {
743+ ovs_vport_send(vport, skb);
744+ } else if (mru <= vport->dev->mtu) {
745+ __be16 ethertype = key->eth.type;
746+
747+ if (!is_flow_key_valid(key)) {
748+ if (eth_p_mpls(skb->protocol))
749+ ethertype = skb->inner_protocol;
750+ else
751+ ethertype = vlan_get_protocol(skb);
752+ }
753+
754+ ovs_fragment(vport, skb, mru, ethertype);
755+ } else {
756+ kfree_skb(skb);
757+ }
758+ } else {
612759 kfree_skb(skb);
760+ }
613761 }
614762
615763 static int output_userspace(struct datapath *dp, struct sk_buff *skb,
@@ -623,6 +771,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, · 7 unmodified lines
623771
624772 memset(&upcall, 0, sizeof(upcall));
625773 upcall.cmd = OVS_PACKET_CMD_ACTION;
774+ upcall.mru = OVS_CB(skb)->mru;
626775
627776 for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
628777 a = nla_next(a, &rem)) {
@@ -816,6 +965,11 @@ static int execute_masked_set_action(struct sk_buff *skb, · 187 unmodified lines
816965 err = set_mpls(skb, flow_key, nla_data(a), get_mask(a,
817966 __be32 *));
818967 break;
968+
969+ case OVS_KEY_ATTR_CT_STATE:
970+ case OVS_KEY_ATTR_CT_ZONE:
971+ err = -EINVAL;
972+ break;
819973 }
820974
821975 return err;
@@ -885,7 +1039,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, · 63 unmodified lines
8851039 struct sk_buff *out_skb = skb_clone(skb, GFP_ATOMIC);
8861040
8871041 if (out_skb)
888− do_output(dp, out_skb, prev_port);
1042+ do_output(dp, out_skb, prev_port, key);
8891043
8901044 prev_port = -1;
8911045 }
@@ -942,6 +1096,15 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, · 50 unmodified lines
9421096 case OVS_ACTION_ATTR_SAMPLE:
9431097 err = sample(dp, skb, key, a, attr, len);
9441098 break;
1099+
1100+ case OVS_ACTION_ATTR_CT:
1101+ err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key,
1102+ nla_data(a));
1103+
1104+ /* Hide stolen IP fragments from user space. */
1105+ if (err == -EINPROGRESS)
1106+ return 0;
1107+ break;
9451108 }
9461109
9471110 if (unlikely(err)) {
@@ -951,7 +1114,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, · 3 unmodified lines
9511114 }
9521115
9531116 if (prev_port != -1)
954− do_output(dp, skb, prev_port);
1117+ do_output(dp, skb, prev_port, key);
9551118 else
9561119 consume_skb(skb);
9571120
net/openvswitch/conntrack.c+454−0
@@ -0,0 +1,454 @@
1+/*
2+ * Copyright (c) 2015 Nicira, Inc.
3+ *
4+ * This program is free software; you can redistribute it and/or
5+ * modify it under the terms of version 2 of the GNU General Public
6+ * License as published by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * General Public License for more details.
12+ */
13+
14+#include <linux/module.h>
15+#include <linux/openvswitch.h>
16+#include <net/ip.h>
17+#include <net/netfilter/nf_conntrack_core.h>
18+#include <net/netfilter/nf_conntrack_zones.h>
19+#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
20+
21+#include "datapath.h"
22+#include "conntrack.h"
23+#include "flow.h"
24+#include "flow_netlink.h"
25+
26+struct ovs_ct_len_tbl {
27+ size_t maxlen;
28+ size_t minlen;
29+};
30+
31+/* Conntrack action context for execution. */
32+struct ovs_conntrack_info {
33+ struct nf_conntrack_zone zone;
34+ struct nf_conn *ct;
35+ u32 flags;
36+ u16 family;
37+};
38+
39+static u16 key_to_nfproto(const struct sw_flow_key *key)
40+{
41+ switch (ntohs(key->eth.type)) {
42+ case ETH_P_IP:
43+ return NFPROTO_IPV4;
44+ case ETH_P_IPV6:
45+ return NFPROTO_IPV6;
46+ default:
47+ return NFPROTO_UNSPEC;
48+ }
49+}
50+
51+/* Map SKB connection state into the values used by flow definition. */
52+static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo)
53+{
54+ u8 ct_state = OVS_CS_F_TRACKED;
55+
56+ switch (ctinfo) {
57+ case IP_CT_ESTABLISHED_REPLY:
58+ case IP_CT_RELATED_REPLY:
59+ case IP_CT_NEW_REPLY:
60+ ct_state |= OVS_CS_F_REPLY_DIR;
61+ break;
62+ default:
63+ break;
64+ }
65+
66+ switch (ctinfo) {
67+ case IP_CT_ESTABLISHED:
68+ case IP_CT_ESTABLISHED_REPLY:
69+ ct_state |= OVS_CS_F_ESTABLISHED;
70+ break;
71+ case IP_CT_RELATED:
72+ case IP_CT_RELATED_REPLY:
73+ ct_state |= OVS_CS_F_RELATED;
74+ break;
75+ case IP_CT_NEW:
76+ case IP_CT_NEW_REPLY:
77+ ct_state |= OVS_CS_F_NEW;
78+ break;
79+ default:
80+ break;
81+ }
82+
83+ return ct_state;
84+}
85+
86+static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,
87+ const struct nf_conntrack_zone *zone)
88+{
89+ key->ct.state = state;
90+ key->ct.zone = zone->id;
91+}
92+
93+/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has
94+ * previously sent the packet to conntrack via the ct action.
95+ */
96+static void ovs_ct_update_key(const struct sk_buff *skb,
97+ struct sw_flow_key *key, bool post_ct)
98+{
99+ const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
100+ enum ip_conntrack_info ctinfo;
101+ struct nf_conn *ct;
102+ u8 state = 0;
103+
104+ ct = nf_ct_get(skb, &ctinfo);
105+ if (ct) {
106+ state = ovs_ct_get_state(ctinfo);
107+ if (ct->master)
108+ state |= OVS_CS_F_RELATED;
109+ zone = nf_ct_zone(ct);
110+ } else if (post_ct) {
111+ state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;
112+ }
113+ __ovs_ct_update_key(key, state, zone);
114+}
115+
116+void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)
117+{
118+ ovs_ct_update_key(skb, key, false);
119+}
120+
121+int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb)
122+{
123+ if (nla_put_u8(skb, OVS_KEY_ATTR_CT_STATE, key->ct.state))
124+ return -EMSGSIZE;
125+
126+ if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
127+ nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone))
128+ return -EMSGSIZE;
129+
130+ return 0;
131+}
132+
133+static int handle_fragments(struct net *net, struct sw_flow_key *key,
134+ u16 zone, struct sk_buff *skb)
135+{
136+ struct ovs_skb_cb ovs_cb = *OVS_CB(skb);
137+
138+ if (key->eth.type == htons(ETH_P_IP)) {
139+ enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone;
140+ int err;
141+
142+ memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
143+ err = ip_defrag(skb, user);
144+ if (err)
145+ return err;
146+
147+ ovs_cb.mru = IPCB(skb)->frag_max_size;
148+ } else if (key->eth.type == htons(ETH_P_IPV6)) {
149+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
150+ enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
151+ struct sk_buff *reasm;
152+
153+ memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
154+ reasm = nf_ct_frag6_gather(skb, user);
155+ if (!reasm)
156+ return -EINPROGRESS;
157+
158+ if (skb == reasm)
159+ return -EINVAL;
160+
161+ key->ip.proto = ipv6_hdr(reasm)->nexthdr;
162+ skb_morph(skb, reasm);
163+ consume_skb(reasm);
164+ ovs_cb.mru = IP6CB(skb)->frag_max_size;
165+#else
166+ return -EPFNOSUPPORT;
167+#endif
168+ } else {
169+ return -EPFNOSUPPORT;
170+ }
171+
172+ key->ip.frag = OVS_FRAG_TYPE_NONE;
173+ skb_clear_hash(skb);
174+ skb->ignore_df = 1;
175+ *OVS_CB(skb) = ovs_cb;
176+
177+ return 0;
178+}
179+
180+static struct nf_conntrack_expect *
181+ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone,
182+ u16 proto, const struct sk_buff *skb)
183+{
184+ struct nf_conntrack_tuple tuple;
185+
186+ if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, &tuple))
187+ return NULL;
188+ return __nf_ct_expect_find(net, zone, &tuple);
189+}
190+
191+/* Determine whether skb->nfct is equal to the result of conntrack lookup. */
192+static bool skb_nfct_cached(const struct net *net, const struct sk_buff *skb,
193+ const struct ovs_conntrack_info *info)
194+{
195+ enum ip_conntrack_info ctinfo;
196+ struct nf_conn *ct;
197+
198+ ct = nf_ct_get(skb, &ctinfo);
199+ if (!ct)
200+ return false;
201+ if (!net_eq(net, read_pnet(&ct->ct_net)))
202+ return false;
203+ if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct)))
204+ return false;
205+
206+ return true;
207+}
208+
209+static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key,
210+ const struct ovs_conntrack_info *info,
211+ struct sk_buff *skb)
212+{
213+ /* If we are recirculating packets to match on conntrack fields and
214+ * committing with a separate conntrack action, then we don't need to
215+ * actually run the packet through conntrack twice unless it's for a
216+ * different zone.
217+ */
218+ if (!skb_nfct_cached(net, skb, info)) {
219+ struct nf_conn *tmpl = info->ct;
220+
221+ /* Associate skb with specified zone. */
222+ if (tmpl) {
223+ if (skb->nfct)
224+ nf_conntrack_put(skb->nfct);
225+ nf_conntrack_get(&tmpl->ct_general);
226+ skb->nfct = &tmpl->ct_general;
227+ skb->nfctinfo = IP_CT_NEW;
228+ }
229+
230+ if (nf_conntrack_in(net, info->family, NF_INET_PRE_ROUTING,
231+ skb) != NF_ACCEPT)
232+ return -ENOENT;
233+ }
234+
235+ return 0;
236+}
237+
238+/* Lookup connection and read fields into key. */
239+static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
240+ const struct ovs_conntrack_info *info,
241+ struct sk_buff *skb)
242+{
243+ struct nf_conntrack_expect *exp;
244+
245+ exp = ovs_ct_expect_find(net, &info->zone, info->family, skb);
246+ if (exp) {
247+ u8 state;
248+
249+ state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED;
250+ __ovs_ct_update_key(key, state, &info->zone);
251+ } else {
252+ int err;
253+
254+ err = __ovs_ct_lookup(net, key, info, skb);
255+ if (err)
256+ return err;
257+
258+ ovs_ct_update_key(skb, key, true);
259+ }
260+
261+ return 0;
262+}
263+
264+/* Lookup connection and confirm if unconfirmed. */
265+static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
266+ const struct ovs_conntrack_info *info,
267+ struct sk_buff *skb)
268+{
269+ u8 state;
270+ int err;
271+
272+ state = key->ct.state;
273+ if (key->ct.zone == info->zone.id &&
274+ ((state & OVS_CS_F_TRACKED) && !(state & OVS_CS_F_NEW))) {
275+ /* Previous lookup has shown that this connection is already
276+ * tracked and committed. Skip committing.
277+ */
278+ return 0;
279+ }
280+
281+ err = __ovs_ct_lookup(net, key, info, skb);
282+ if (err)
283+ return err;
284+ if (nf_conntrack_confirm(skb) != NF_ACCEPT)
285+ return -EINVAL;
286+
287+ ovs_ct_update_key(skb, key, true);
288+
289+ return 0;
290+}
291+
292+int ovs_ct_execute(struct net *net, struct sk_buff *skb,
293+ struct sw_flow_key *key,
294+ const struct ovs_conntrack_info *info)
295+{
296+ int nh_ofs;
297+ int err;
298+
299+ /* The conntrack module expects to be working at L3. */
300+ nh_ofs = skb_network_offset(skb);
301+ skb_pull(skb, nh_ofs);
302+
303+ if (key->ip.frag != OVS_FRAG_TYPE_NONE) {
304+ err = handle_fragments(net, key, info->zone.id, skb);
305+ if (err)
306+ return err;
307+ }
308+
309+ if (info->flags & OVS_CT_F_COMMIT)
310+ err = ovs_ct_commit(net, key, info, skb);
311+ else
312+ err = ovs_ct_lookup(net, key, info, skb);
313+
314+ skb_push(skb, nh_ofs);
315+ return err;
316+}
317+
318+static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
319+ [OVS_CT_ATTR_FLAGS] = { .minlen = sizeof(u32),
320+ .maxlen = sizeof(u32) },
321+ [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16),
322+ .maxlen = sizeof(u16) },
323+};
324+
325+static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
326+ bool log)
327+{
328+ struct nlattr *a;
329+ int rem;
330+
331+ nla_for_each_nested(a, attr, rem) {
332+ int type = nla_type(a);
333+ int maxlen = ovs_ct_attr_lens[type].maxlen;
334+ int minlen = ovs_ct_attr_lens[type].minlen;
335+
336+ if (type > OVS_CT_ATTR_MAX) {
337+ OVS_NLERR(log,
338+ "Unknown conntrack attr (type=%d, max=%d)",
339+ type, OVS_CT_ATTR_MAX);
340+ return -EINVAL;
341+ }
342+ if (nla_len(a) < minlen || nla_len(a) > maxlen) {
343+ OVS_NLERR(log,
344+ "Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)",
345+ type, nla_len(a), maxlen);
346+ return -EINVAL;
347+ }
348+
349+ switch (type) {
350+ case OVS_CT_ATTR_FLAGS:
351+ info->flags = nla_get_u32(a);
352+ break;
353+#ifdef CONFIG_NF_CONNTRACK_ZONES
354+ case OVS_CT_ATTR_ZONE:
355+ info->zone.id = nla_get_u16(a);
356+ break;
357+#endif
358+ default:
359+ OVS_NLERR(log, "Unknown conntrack attr (%d)",
360+ type);
361+ return -EINVAL;
362+ }
363+ }
364+
365+ if (rem > 0) {
366+ OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem);
367+ return -EINVAL;
368+ }
369+
370+ return 0;
371+}
372+
373+bool ovs_ct_verify(enum ovs_key_attr attr)
374+{
375+ if (attr == OVS_KEY_ATTR_CT_STATE)
376+ return true;
377+ if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
378+ attr == OVS_KEY_ATTR_CT_ZONE)
379+ return true;
380+
381+ return false;
382+}
383+
384+int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
385+ const struct sw_flow_key *key,
386+ struct sw_flow_actions **sfa, bool log)
387+{
388+ struct ovs_conntrack_info ct_info;
389+ u16 family;
390+ int err;
391+
392+ family = key_to_nfproto(key);
393+ if (family == NFPROTO_UNSPEC) {
394+ OVS_NLERR(log, "ct family unspecified");
395+ return -EINVAL;
396+ }
397+
398+ memset(&ct_info, 0, sizeof(ct_info));
399+ ct_info.family = family;
400+
401+ nf_ct_zone_init(&ct_info.zone, NF_CT_DEFAULT_ZONE_ID,
402+ NF_CT_DEFAULT_ZONE_DIR, 0);
403+
404+ err = parse_ct(attr, &ct_info, log);
405+ if (err)
406+ return err;
407+
408+ /* Set up template for tracking connections in specific zones. */
409+ ct_info.ct = nf_ct_tmpl_alloc(net, &ct_info.zone, GFP_KERNEL);
410+ if (!ct_info.ct) {
411+ OVS_NLERR(log, "Failed to allocate conntrack template");
412+ return -ENOMEM;
413+ }
414+
415+ err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info,
416+ sizeof(ct_info), log);
417+ if (err)
418+ goto err_free_ct;
419+
420+ __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status);
421+ nf_conntrack_get(&ct_info.ct->ct_general);
422+ return 0;
423+err_free_ct:
424+ nf_conntrack_free(ct_info.ct);
425+ return err;
426+}
427+
428+int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
429+ struct sk_buff *skb)
430+{
431+ struct nlattr *start;
432+
433+ start = nla_nest_start(skb, OVS_ACTION_ATTR_CT);
434+ if (!start)
435+ return -EMSGSIZE;
436+
437+ if (nla_put_u32(skb, OVS_CT_ATTR_FLAGS, ct_info->flags))
438+ return -EMSGSIZE;
439+ if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
440+ nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))
441+ return -EMSGSIZE;
442+
443+ nla_nest_end(skb, start);
444+
445+ return 0;
446+}
447+
448+void ovs_ct_free_action(const struct nlattr *a)
449+{
450+ struct ovs_conntrack_info *ct_info = nla_data(a);
451+
452+ if (ct_info->ct)
453+ nf_ct_put(ct_info->ct);
454+}
net/openvswitch/conntrack.h+78−0
@@ -0,0 +1,78 @@
1+/*
2+ * Copyright (c) 2015 Nicira, Inc.
3+ *
4+ * This program is free software; you can redistribute it and/or
5+ * modify it under the terms of version 2 of the GNU General Public
6+ * License as published by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * General Public License for more details.
12+ */
13+
14+#ifndef OVS_CONNTRACK_H
15+#define OVS_CONNTRACK_H 1
16+
17+#include "flow.h"
18+
19+struct ovs_conntrack_info;
20+enum ovs_key_attr;
21+
22+#if defined(CONFIG_OPENVSWITCH_CONNTRACK)
23+bool ovs_ct_verify(enum ovs_key_attr attr);
24+int ovs_ct_copy_action(struct net *, const struct nlattr *,
25+ const struct sw_flow_key *, struct sw_flow_actions **,
26+ bool log);
27+int ovs_ct_action_to_attr(const struct ovs_conntrack_info *, struct sk_buff *);
28+
29+int ovs_ct_execute(struct net *, struct sk_buff *, struct sw_flow_key *,
30+ const struct ovs_conntrack_info *);
31+
32+void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key);
33+int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb);
34+void ovs_ct_free_action(const struct nlattr *a);
35+#else
36+#include <linux/errno.h>
37+
38+static inline bool ovs_ct_verify(int attr)
39+{
40+ return false;
41+}
42+
43+static inline int ovs_ct_copy_action(struct net *net, const struct nlattr *nla,
44+ const struct sw_flow_key *key,
45+ struct sw_flow_actions **acts, bool log)
46+{
47+ return -ENOTSUPP;
48+}
49+
50+static inline int ovs_ct_action_to_attr(const struct ovs_conntrack_info *info,
51+ struct sk_buff *skb)
52+{
53+ return -ENOTSUPP;
54+}
55+
56+static inline int ovs_ct_execute(struct net *net, struct sk_buff *skb,
57+ struct sw_flow_key *key,
58+ const struct ovs_conntrack_info *info)
59+{
60+ return -ENOTSUPP;
61+}
62+
63+static inline void ovs_ct_fill_key(const struct sk_buff *skb,
64+ struct sw_flow_key *key)
65+{
66+ key->ct.state = 0;
67+ key->ct.zone = 0;
68+}
69+
70+static inline int ovs_ct_put_key(const struct sw_flow_key *key,
71+ struct sk_buff *skb)
72+{
73+ return 0;
74+}
75+
76+static inline void ovs_ct_free_action(const struct nlattr *a) { }
77+#endif
78+#endif /* ovs_conntrack.h */
net/openvswitch/datapath.c+50−16
@@ -275,6 +275,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key) · 274 unmodified lines
275275 memset(&upcall, 0, sizeof(upcall));
276276 upcall.cmd = OVS_PACKET_CMD_MISS;
277277 upcall.portid = ovs_vport_find_upcall_portid(p, skb);
278+ upcall.mru = OVS_CB(skb)->mru;
278279 error = ovs_dp_upcall(dp, skb, key, &upcall);
279280 if (unlikely(error))
280281 kfree_skb(skb);
@@ -400,9 +401,23 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info, · 119 unmodified lines
400401 if (upcall_info->actions_len)
401402 size += nla_total_size(upcall_info->actions_len);
402403
404+ /* OVS_PACKET_ATTR_MRU */
405+ if (upcall_info->mru)
406+ size += nla_total_size(sizeof(upcall_info->mru));
407+
403408 return size;
404409 }
405410
411+static void pad_packet(struct datapath *dp, struct sk_buff *skb)
412+{
413+ if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
414+ size_t plen = NLA_ALIGN(skb->len) - skb->len;
415+
416+ if (plen > 0)
417+ memset(skb_put(skb, plen), 0, plen);
418+ }
419+}
420+
406421 static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
407422 const struct sw_flow_key *key,
408423 const struct dp_upcall_info *upcall_info)
@@ -492,6 +507,16 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, · 83 unmodified lines
492507 nla_nest_cancel(user_skb, nla);
493508 }
494509
510+ /* Add OVS_PACKET_ATTR_MRU */
511+ if (upcall_info->mru) {
512+ if (nla_put_u16(user_skb, OVS_PACKET_ATTR_MRU,
513+ upcall_info->mru)) {
514+ err = -ENOBUFS;
515+ goto out;
516+ }
517+ pad_packet(dp, user_skb);
518+ }
519+
495520 /* Only reserve room for attribute header, packet data is added
496521 * in skb_zerocopy() */
497522 if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
@@ -505,12 +530,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, · 7 unmodified lines
505530 goto out;
506531
507532 /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
508− if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
509− size_t plen = NLA_ALIGN(user_skb->len) - user_skb->len;
510−
511− if (plen > 0)
512− memset(skb_put(user_skb, plen), 0, plen);
513− }
533+ pad_packet(dp, user_skb);
514534
515535 ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
516536
@@ -527,6 +547,7 @@ out: · 10 unmodified lines
527547 static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
528548 {
529549 struct ovs_header *ovs_header = info->userhdr;
550+ struct net *net = sock_net(skb->sk);
530551 struct nlattr **a = info->attrs;
531552 struct sw_flow_actions *acts;
532553 struct sk_buff *packet;
@@ -535,6 +556,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) · 2 unmodified lines
535556 struct datapath *dp;
536557 struct ethhdr *eth;
537558 struct vport *input_vport;
559+ u16 mru = 0;
538560 int len;
539561 int err;
540562 bool log = !a[OVS_PACKET_ATTR_PROBE];
@@ -564,6 +586,13 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) · 23 unmodified lines
564586 else
565587 packet->protocol = htons(ETH_P_802_2);
566588
589+ /* Set packet's mru */
590+ if (a[OVS_PACKET_ATTR_MRU]) {
591+ mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]);
592+ packet->ignore_df = 1;
593+ }
594+ OVS_CB(packet)->mru = mru;
595+
567596 /* Build an sw_flow for sending this packet. */
568597 flow = ovs_flow_alloc();
569598 err = PTR_ERR(flow);
@@ -575,7 +604,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) · 5 unmodified lines
575604 if (err)
576605 goto err_flow_free;
577606
578− err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS],
607+ err = ovs_nla_copy_actions(net, a[OVS_PACKET_ATTR_ACTIONS],
579608 &flow->key, &acts, log);
580609 if (err)
581610 goto err_flow_free;
@@ -586,7 +615,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) · 4 unmodified lines
586615 packet->mark = flow->key.phy.skb_mark;
587616
588617 rcu_read_lock();
589− dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
618+ dp = get_dp_rcu(net, ovs_header->dp_ifindex);
590619 err = -ENODEV;
591620 if (!dp)
592621 goto err_unlock;
@@ -598,6 +627,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) · 5 unmodified lines
598627 if (!input_vport)
599628 goto err_unlock;
600629
630+ packet->dev = input_vport->dev;
601631 OVS_CB(packet)->input_vport = input_vport;
602632 sf_acts = rcu_dereference(flow->sf_acts);
603633
@@ -624,6 +654,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { · 20 unmodified lines
624654 [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
625655 [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
626656 [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG },
657+ [OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 },
627658 };
628659
629660 static const struct genl_ops dp_packet_genl_ops[] = {
@@ -880,6 +911,7 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, · 250 unmodified lines
880911
881912 static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
882913 {
914+ struct net *net = sock_net(skb->sk);
883915 struct nlattr **a = info->attrs;
884916 struct ovs_header *ovs_header = info->userhdr;
885917 struct sw_flow *flow = NULL, *new_flow;
@@ -929,8 +961,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) · 43 unmodified lines
929961 goto err_kfree_flow;
930962
931963 /* Validate actions. */
932− error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key,
933− &acts, log);
964+ error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
965+ &new_flow->key, &acts, log);
934966 if (error) {
935967 OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
936968 goto err_kfree_flow;
@@ -944,7 +976,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) · 7 unmodified lines
944976 }
945977
946978 ovs_lock();
947− dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
979+ dp = get_dp(net, ovs_header->dp_ifindex);
948980 if (unlikely(!dp)) {
949981 error = -ENODEV;
950982 goto err_unlock_ovs;
@@ -1038,7 +1070,8 @@ error: · 87 unmodified lines
10381070 }
10391071
10401072 /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
1041−static struct sw_flow_actions *get_flow_actions(const struct nlattr *a,
1073+static struct sw_flow_actions *get_flow_actions(struct net *net,
1074+ const struct nlattr *a,
10421075 const struct sw_flow_key *key,
10431076 const struct sw_flow_mask *mask,
10441077 bool log)
@@ -1048,7 +1081,7 @@ static struct sw_flow_actions *get_flow_actions(const struct nlattr *a, · 3 unmodified lines
10481081 int error;
10491082
10501083 ovs_flow_mask_key(&masked_key, key, mask);
1051− error = ovs_nla_copy_actions(a, &masked_key, &acts, log);
1084+ error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log);
10521085 if (error) {
10531086 OVS_NLERR(log,
10541087 "Actions may not be safe on all matching packets");
@@ -1060,6 +1093,7 @@ static struct sw_flow_actions *get_flow_actions(const struct nlattr *a, · 5 unmodified lines
10601093
10611094 static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
10621095 {
1096+ struct net *net = sock_net(skb->sk);
10631097 struct nlattr **a = info->attrs;
10641098 struct ovs_header *ovs_header = info->userhdr;
10651099 struct sw_flow_key key;
@@ -1091,8 +1125,8 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) · 25 unmodified lines
10911125
10921126 /* Validate actions. */
10931127 if (a[OVS_FLOW_ATTR_ACTIONS]) {
1094− acts = get_flow_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, &mask,
1095− log);
1128+ acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], &key,
1129+ &mask, log);
10961130 if (IS_ERR(acts)) {
10971131 error = PTR_ERR(acts);
10981132 goto error;
@@ -1108,7 +1142,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) · 9 unmodified lines
11081142 }
11091143
11101144 ovs_lock();
1111− dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
1145+ dp = get_dp(net, ovs_header->dp_ifindex);
11121146 if (unlikely(!dp)) {
11131147 error = -ENODEV;
11141148 goto err_unlock_ovs;
net/openvswitch/datapath.h+6−0
@@ -27,6 +27,7 @@ · 26 unmodified lines
2727 #include <linux/u64_stats_sync.h>
2828 #include <net/ip_tunnels.h>
2929
30+#include "conntrack.h"
3031 #include "flow.h"
3132 #include "flow_table.h"
3233 #include "vport.h"
@@ -97,10 +98,13 @@ struct datapath { · 64 unmodified lines
9798 * NULL if the packet is not being tunneled.
9899 * @input_vport: The original vport packet came in on. This value is cached
99100 * when a packet is received by OVS.
101+ * @mru: The maximum received fragement size; 0 if the packet is not
102+ * fragmented.
100103 */
101104 struct ovs_skb_cb {
102105 struct ip_tunnel_info *egress_tun_info;
103106 struct vport *input_vport;
107+ u16 mru;
104108 };
105109 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
106110
@@ -113,6 +117,7 @@ struct ovs_skb_cb { · 6 unmodified lines
113117 * then no packet is sent and the packet is accounted in the datapath's @n_lost
114118 * counter.
115119 * @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY.
120+ * @mru: If not zero, Maximum received IP fragment size.
116121 */
117122 struct dp_upcall_info {
118123 const struct ip_tunnel_info *egress_tun_info;
@@ -121,6 +126,7 @@ struct dp_upcall_info { · 2 unmodified lines
121126 int actions_len;
122127 u32 portid;
123128 u8 cmd;
129+ u16 mru;
124130 };
125131
126132 /**
net/openvswitch/flow.c+2−0
@@ -49,6 +49,7 @@ · 48 unmodified lines
4949 #include "datapath.h"
5050 #include "flow.h"
5151 #include "flow_netlink.h"
52+#include "conntrack.h"
5253
5354 u64 ovs_flow_used_time(unsigned long flow_jiffies)
5455 {
@@ -707,6 +708,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, · 652 unmodified lines
707708 key->phy.priority = skb->priority;
708709 key->phy.in_port = OVS_CB(skb)->input_vport->port_no;
709710 key->phy.skb_mark = skb->mark;
711+ ovs_ct_fill_key(skb, key);
710712 key->ovs_flow_hash = 0;
711713 key->recirc_id = 0;
712714
net/openvswitch/flow.h+6−0
@@ -111,6 +111,12 @@ struct sw_flow_key { · 110 unmodified lines
111111 } nd;
112112 } ipv6;
113113 };
114+ struct {
115+ /* Connection tracking fields. */
116+ u16 zone;
117+ u8 state;
118+ } ct;
119+
114120 } __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */
115121
116122 struct sw_flow_key_range {
net/openvswitch/flow_netlink.c+55−14
@@ -281,7 +281,7 @@ size_t ovs_key_attr_size(void) · 280 unmodified lines
281281 /* Whenever adding new OVS_KEY_ FIELDS, we should consider
282282 * updating this function.
283283 */
284− BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 22);
284+ BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 24);
285285
286286 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
287287 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
@@ -290,6 +290,8 @@ size_t ovs_key_attr_size(void) · 2 unmodified lines
290290 + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */
291291 + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */
292292 + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */
293+ + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */
294+ + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
293295 + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
294296 + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
295297 + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
@@ -339,6 +341,8 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { · 43 unmodified lines
339341 [OVS_KEY_ATTR_TUNNEL] = { .len = OVS_ATTR_NESTED,
340342 .next = ovs_tunnel_key_lens, },
341343 [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) },
344+ [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) },
345+ [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) },
342346 };
343347
344348 static bool is_all_zero(const u8 *fp, size_t size)
@@ -768,6 +772,21 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, · 423 unmodified lines
768772 return -EINVAL;
769773 *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL);
770774 }
775+
776+ if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) &&
777+ ovs_ct_verify(OVS_KEY_ATTR_CT_STATE)) {
778+ u8 ct_state = nla_get_u8(a[OVS_KEY_ATTR_CT_STATE]);
779+
780+ SW_FLOW_KEY_PUT(match, ct.state, ct_state, is_mask);
781+ *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE);
782+ }
783+ if (*attrs & (1 << OVS_KEY_ATTR_CT_ZONE) &&
784+ ovs_ct_verify(OVS_KEY_ATTR_CT_ZONE)) {
785+ u16 ct_zone = nla_get_u16(a[OVS_KEY_ATTR_CT_ZONE]);
786+
787+ SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask);
788+ *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
789+ }
771790 return 0;
772791 }
773792
@@ -1266,6 +1285,7 @@ int ovs_nla_get_flow_metadata(const struct nlattr *attr, · 492 unmodified lines
12661285 memset(&match, 0, sizeof(match));
12671286 match.key = key;
12681287
1288+ memset(&key->ct, 0, sizeof(key->ct));
12691289 key->phy.in_port = DP_MAX_PORTS;
12701290
12711291 return metadata_from_nlattrs(&match, &attrs, a, false, log);
@@ -1314,6 +1334,9 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, · 42 unmodified lines
13141334 if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark))
13151335 goto nla_put_failure;
13161336
1337+ if (ovs_ct_put_key(output, skb))
1338+ goto nla_put_failure;
1339+
13171340 nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
13181341 if (!nla)
13191342 goto nla_put_failure;
@@ -1574,6 +1597,9 @@ void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) · 254 unmodified lines
15741597 case OVS_ACTION_ATTR_SET:
15751598 ovs_nla_free_set_action(a);
15761599 break;
1600+ case OVS_ACTION_ATTR_CT:
1601+ ovs_ct_free_action(a);
1602+ break;
15771603 }
15781604 }
15791605
@@ -1647,8 +1673,8 @@ static struct nlattr *__add_action(struct sw_flow_actions **sfa, · 67 unmodified lines
16471673 return a;
16481674 }
16491675
1650−static int add_action(struct sw_flow_actions **sfa, int attrtype,
1651− void *data, int len, bool log)
1676+int ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype, void *data,
1677+ int len, bool log)
16521678 {
16531679 struct nlattr *a;
16541680
@@ -1663,7 +1689,7 @@ static inline int add_nested_action_start(struct sw_flow_actions **sfa, · 8 unmodified lines
16631689 int used = (*sfa)->actions_len;
16641690 int err;
16651691
1666− err = add_action(sfa, attrtype, NULL, 0, log);
1692+ err = ovs_nla_add_action(sfa, attrtype, NULL, 0, log);
16671693 if (err)
16681694 return err;
16691695
@@ -1679,12 +1705,12 @@ static inline void add_nested_action_end(struct sw_flow_actions *sfa, · 9 unmodified lines
16791705 a->nla_len = sfa->actions_len - st_offset;
16801706 }
16811707
1682−static int __ovs_nla_copy_actions(const struct nlattr *attr,
1708+static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
16831709 const struct sw_flow_key *key,
16841710 int depth, struct sw_flow_actions **sfa,
16851711 __be16 eth_type, __be16 vlan_tci, bool log);
16861712
1687−static int validate_and_copy_sample(const struct nlattr *attr,
1713+static int validate_and_copy_sample(struct net *net, const struct nlattr *attr,
16881714 const struct sw_flow_key *key, int depth,
16891715 struct sw_flow_actions **sfa,
16901716 __be16 eth_type, __be16 vlan_tci, bool log)
@@ -1716,15 +1742,15 @@ static int validate_and_copy_sample(const struct nlattr *attr, · 25 unmodified lines
17161742 start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE, log);
17171743 if (start < 0)
17181744 return start;
1719− err = add_action(sfa, OVS_SAMPLE_ATTR_PROBABILITY,
1720− nla_data(probability), sizeof(u32), log);
1745+ err = ovs_nla_add_action(sfa, OVS_SAMPLE_ATTR_PROBABILITY,
1746+ nla_data(probability), sizeof(u32), log);
17211747 if (err)
17221748 return err;
17231749 st_acts = add_nested_action_start(sfa, OVS_SAMPLE_ATTR_ACTIONS, log);
17241750 if (st_acts < 0)
17251751 return st_acts;
17261752
1727− err = __ovs_nla_copy_actions(actions, key, depth + 1, sfa,
1753+ err = __ovs_nla_copy_actions(net, actions, key, depth + 1, sfa,
17281754 eth_type, vlan_tci, log);
17291755 if (err)
17301756 return err;
@@ -2058,7 +2084,7 @@ static int copy_action(const struct nlattr *from, · 327 unmodified lines
20582084 return 0;
20592085 }
20602086
2061−static int __ovs_nla_copy_actions(const struct nlattr *attr,
2087+static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
20622088 const struct sw_flow_key *key,
20632089 int depth, struct sw_flow_actions **sfa,
20642090 __be16 eth_type, __be16 vlan_tci, bool log)
@@ -2082,7 +2108,8 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, · 17 unmodified lines
20822108 [OVS_ACTION_ATTR_SET] = (u32)-1,
20832109 [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1,
20842110 [OVS_ACTION_ATTR_SAMPLE] = (u32)-1,
2085− [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash)
2111+ [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash),
2112+ [OVS_ACTION_ATTR_CT] = (u32)-1,
20862113 };
20872114 const struct ovs_action_push_vlan *vlan;
20882115 int type = nla_type(a);
@@ -2189,13 +2216,20 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, · 100 unmodified lines
21892216 break;
21902217
21912218 case OVS_ACTION_ATTR_SAMPLE:
2192− err = validate_and_copy_sample(a, key, depth, sfa,
2219+ err = validate_and_copy_sample(net, a, key, depth, sfa,
21932220 eth_type, vlan_tci, log);
21942221 if (err)
21952222 return err;
21962223 skip_copy = true;
21972224 break;
21982225
2226+ case OVS_ACTION_ATTR_CT:
2227+ err = ovs_ct_copy_action(net, a, key, sfa, log);
2228+ if (err)
2229+ return err;
2230+ skip_copy = true;
2231+ break;
2232+
21992233 default:
22002234 OVS_NLERR(log, "Unknown Action type %d", type);
22012235 return -EINVAL;
@@ -2214,7 +2248,7 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, · 12 unmodified lines
22142248 }
22152249
22162250 /* 'key' must be the masked key. */
2217−int ovs_nla_copy_actions(const struct nlattr *attr,
2251+int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
22182252 const struct sw_flow_key *key,
22192253 struct sw_flow_actions **sfa, bool log)
22202254 {
@@ -2225,7 +2259,7 @@ int ovs_nla_copy_actions(const struct nlattr *attr, · 4 unmodified lines
22252259 return PTR_ERR(*sfa);
22262260
22272261 (*sfa)->orig_len = nla_len(attr);
2228− err = __ovs_nla_copy_actions(attr, key, 0, sfa, key->eth.type,
2262+ err = __ovs_nla_copy_actions(net, attr, key, 0, sfa, key->eth.type,
22292263 key->eth.tci, log);
22302264 if (err)
22312265 ovs_nla_free_flow_actions(*sfa);
@@ -2350,6 +2384,13 @@ int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb) · 118 unmodified lines
23502384 if (err)
23512385 return err;
23522386 break;
2387+
2388+ case OVS_ACTION_ATTR_CT:
2389+ err = ovs_ct_action_to_attr(nla_data(a), skb);
2390+ if (err)
2391+ return err;
2392+ break;
2393+
23532394 default:
23542395 if (nla_put(skb, type, nla_len(a), nla_data(a)))
23552396 return -EMSGSIZE;
net/openvswitch/flow_netlink.h+3−1
@@ -62,9 +62,11 @@ int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, · 61 unmodified lines
6262 const struct sw_flow_key *key, bool log);
6363 u32 ovs_nla_get_ufid_flags(const struct nlattr *attr);
6464
65−int ovs_nla_copy_actions(const struct nlattr *attr,
65+int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr,
6666 const struct sw_flow_key *key,
6767 struct sw_flow_actions **sfa, bool log);
68+int ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype,
69+ void *data, int len, bool log);
6870 int ovs_nla_put_actions(const struct nlattr *attr,
6971 int len, struct sk_buff *skb);
7072
net/openvswitch/vport.c+1−0
@@ -484,6 +484,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, · 483 unmodified lines
484484
485485 OVS_CB(skb)->input_vport = vport;
486486 OVS_CB(skb)->egress_tun_info = NULL;
487+ OVS_CB(skb)->mru = 0;
487488 /* Extract flow from 'skb' into 'key'. */
488489 error = ovs_flow_key_extract(tun_info, skb, &key);
489490 if (unlikely(error)) {