diff options
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/Kconfig | 3 | ||||
-rw-r--r-- | net/openvswitch/actions.c | 32 | ||||
-rw-r--r-- | net/openvswitch/conntrack.c | 145 | ||||
-rw-r--r-- | net/openvswitch/conntrack.h | 9 | ||||
-rw-r--r-- | net/openvswitch/datapath.c | 9 | ||||
-rw-r--r-- | net/openvswitch/datapath.h | 1 | ||||
-rw-r--r-- | net/openvswitch/flow.h | 2 | ||||
-rw-r--r-- | net/openvswitch/flow_netlink.c | 133 | ||||
-rw-r--r-- | net/openvswitch/flow_netlink.h | 6 | ||||
-rw-r--r-- | net/openvswitch/flow_table.c | 26 | ||||
-rw-r--r-- | net/openvswitch/flow_table.h | 2 | ||||
-rw-r--r-- | net/openvswitch/vport-geneve.c | 13 | ||||
-rw-r--r-- | net/openvswitch/vport-gre.c | 8 | ||||
-rw-r--r-- | net/openvswitch/vport-internal_dev.c | 46 | ||||
-rw-r--r-- | net/openvswitch/vport-vxlan.c | 19 | ||||
-rw-r--r-- | net/openvswitch/vport.c | 109 | ||||
-rw-r--r-- | net/openvswitch/vport.h | 35 |
17 files changed, 288 insertions, 310 deletions
diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index 2a071f470d57..d143aa9f6654 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig | |||
@@ -5,7 +5,8 @@ | |||
5 | config OPENVSWITCH | 5 | config OPENVSWITCH |
6 | tristate "Open vSwitch" | 6 | tristate "Open vSwitch" |
7 | depends on INET | 7 | depends on INET |
8 | depends on (!NF_CONNTRACK || NF_CONNTRACK) | 8 | depends on !NF_CONNTRACK || \ |
9 | (NF_CONNTRACK && (!NF_DEFRAG_IPV6 || NF_DEFRAG_IPV6)) | ||
9 | select LIBCRC32C | 10 | select LIBCRC32C |
10 | select MPLS | 11 | select MPLS |
11 | select NET_MPLS_GSO | 12 | select NET_MPLS_GSO |
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 315f5330b6e5..dba635d086b2 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
@@ -684,7 +684,7 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru, | |||
684 | { | 684 | { |
685 | if (skb_network_offset(skb) > MAX_L2_LEN) { | 685 | if (skb_network_offset(skb) > MAX_L2_LEN) { |
686 | OVS_NLERR(1, "L2 header too long to fragment"); | 686 | OVS_NLERR(1, "L2 header too long to fragment"); |
687 | return; | 687 | goto err; |
688 | } | 688 | } |
689 | 689 | ||
690 | if (ethertype == htons(ETH_P_IP)) { | 690 | if (ethertype == htons(ETH_P_IP)) { |
@@ -708,8 +708,7 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru, | |||
708 | struct rt6_info ovs_rt; | 708 | struct rt6_info ovs_rt; |
709 | 709 | ||
710 | if (!v6ops) { | 710 | if (!v6ops) { |
711 | kfree_skb(skb); | 711 | goto err; |
712 | return; | ||
713 | } | 712 | } |
714 | 713 | ||
715 | prepare_frag(vport, skb); | 714 | prepare_frag(vport, skb); |
@@ -728,8 +727,12 @@ static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru, | |||
728 | WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.", | 727 | WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.", |
729 | ovs_vport_name(vport), ntohs(ethertype), mru, | 728 | ovs_vport_name(vport), ntohs(ethertype), mru, |
730 | vport->dev->mtu); | 729 | vport->dev->mtu); |
731 | kfree_skb(skb); | 730 | goto err; |
732 | } | 731 | } |
732 | |||
733 | return; | ||
734 | err: | ||
735 | kfree_skb(skb); | ||
733 | } | 736 | } |
734 | 737 | ||
735 | static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, | 738 | static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, |
@@ -765,7 +768,6 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, | |||
765 | struct sw_flow_key *key, const struct nlattr *attr, | 768 | struct sw_flow_key *key, const struct nlattr *attr, |
766 | const struct nlattr *actions, int actions_len) | 769 | const struct nlattr *actions, int actions_len) |
767 | { | 770 | { |
768 | struct ip_tunnel_info info; | ||
769 | struct dp_upcall_info upcall; | 771 | struct dp_upcall_info upcall; |
770 | const struct nlattr *a; | 772 | const struct nlattr *a; |
771 | int rem; | 773 | int rem; |
@@ -793,11 +795,9 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, | |||
793 | if (vport) { | 795 | if (vport) { |
794 | int err; | 796 | int err; |
795 | 797 | ||
796 | upcall.egress_tun_info = &info; | 798 | err = dev_fill_metadata_dst(vport->dev, skb); |
797 | err = ovs_vport_get_egress_tun_info(vport, skb, | 799 | if (!err) |
798 | &upcall); | 800 | upcall.egress_tun_info = skb_tunnel_info(skb); |
799 | if (err) | ||
800 | upcall.egress_tun_info = NULL; | ||
801 | } | 801 | } |
802 | 802 | ||
803 | break; | 803 | break; |
@@ -968,7 +968,7 @@ static int execute_masked_set_action(struct sk_buff *skb, | |||
968 | case OVS_KEY_ATTR_CT_STATE: | 968 | case OVS_KEY_ATTR_CT_STATE: |
969 | case OVS_KEY_ATTR_CT_ZONE: | 969 | case OVS_KEY_ATTR_CT_ZONE: |
970 | case OVS_KEY_ATTR_CT_MARK: | 970 | case OVS_KEY_ATTR_CT_MARK: |
971 | case OVS_KEY_ATTR_CT_LABEL: | 971 | case OVS_KEY_ATTR_CT_LABELS: |
972 | err = -EINVAL; | 972 | err = -EINVAL; |
973 | break; | 973 | break; |
974 | } | 974 | } |
@@ -1099,12 +1099,18 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, | |||
1099 | break; | 1099 | break; |
1100 | 1100 | ||
1101 | case OVS_ACTION_ATTR_CT: | 1101 | case OVS_ACTION_ATTR_CT: |
1102 | if (!is_flow_key_valid(key)) { | ||
1103 | err = ovs_flow_key_update(skb, key); | ||
1104 | if (err) | ||
1105 | return err; | ||
1106 | } | ||
1107 | |||
1102 | err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key, | 1108 | err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key, |
1103 | nla_data(a)); | 1109 | nla_data(a)); |
1104 | 1110 | ||
1105 | /* Hide stolen IP fragments from user space. */ | 1111 | /* Hide stolen IP fragments from user space. */ |
1106 | if (err == -EINPROGRESS) | 1112 | if (err) |
1107 | return 0; | 1113 | return err == -EINPROGRESS ? 0 : err; |
1108 | break; | 1114 | break; |
1109 | } | 1115 | } |
1110 | 1116 | ||
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index e8e524ad8a01..50095820edb7 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c | |||
@@ -37,9 +37,9 @@ struct md_mark { | |||
37 | }; | 37 | }; |
38 | 38 | ||
39 | /* Metadata label for masked write to conntrack label. */ | 39 | /* Metadata label for masked write to conntrack label. */ |
40 | struct md_label { | 40 | struct md_labels { |
41 | struct ovs_key_ct_label value; | 41 | struct ovs_key_ct_labels value; |
42 | struct ovs_key_ct_label mask; | 42 | struct ovs_key_ct_labels mask; |
43 | }; | 43 | }; |
44 | 44 | ||
45 | /* Conntrack action context for execution. */ | 45 | /* Conntrack action context for execution. */ |
@@ -47,10 +47,10 @@ struct ovs_conntrack_info { | |||
47 | struct nf_conntrack_helper *helper; | 47 | struct nf_conntrack_helper *helper; |
48 | struct nf_conntrack_zone zone; | 48 | struct nf_conntrack_zone zone; |
49 | struct nf_conn *ct; | 49 | struct nf_conn *ct; |
50 | u32 flags; | 50 | u8 commit : 1; |
51 | u16 family; | 51 | u16 family; |
52 | struct md_mark mark; | 52 | struct md_mark mark; |
53 | struct md_label label; | 53 | struct md_labels labels; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | static u16 key_to_nfproto(const struct sw_flow_key *key) | 56 | static u16 key_to_nfproto(const struct sw_flow_key *key) |
@@ -109,21 +109,21 @@ static u32 ovs_ct_get_mark(const struct nf_conn *ct) | |||
109 | #endif | 109 | #endif |
110 | } | 110 | } |
111 | 111 | ||
112 | static void ovs_ct_get_label(const struct nf_conn *ct, | 112 | static void ovs_ct_get_labels(const struct nf_conn *ct, |
113 | struct ovs_key_ct_label *label) | 113 | struct ovs_key_ct_labels *labels) |
114 | { | 114 | { |
115 | struct nf_conn_labels *cl = ct ? nf_ct_labels_find(ct) : NULL; | 115 | struct nf_conn_labels *cl = ct ? nf_ct_labels_find(ct) : NULL; |
116 | 116 | ||
117 | if (cl) { | 117 | if (cl) { |
118 | size_t len = cl->words * sizeof(long); | 118 | size_t len = cl->words * sizeof(long); |
119 | 119 | ||
120 | if (len > OVS_CT_LABEL_LEN) | 120 | if (len > OVS_CT_LABELS_LEN) |
121 | len = OVS_CT_LABEL_LEN; | 121 | len = OVS_CT_LABELS_LEN; |
122 | else if (len < OVS_CT_LABEL_LEN) | 122 | else if (len < OVS_CT_LABELS_LEN) |
123 | memset(label, 0, OVS_CT_LABEL_LEN); | 123 | memset(labels, 0, OVS_CT_LABELS_LEN); |
124 | memcpy(label, cl->bits, len); | 124 | memcpy(labels, cl->bits, len); |
125 | } else { | 125 | } else { |
126 | memset(label, 0, OVS_CT_LABEL_LEN); | 126 | memset(labels, 0, OVS_CT_LABELS_LEN); |
127 | } | 127 | } |
128 | } | 128 | } |
129 | 129 | ||
@@ -134,7 +134,7 @@ static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state, | |||
134 | key->ct.state = state; | 134 | key->ct.state = state; |
135 | key->ct.zone = zone->id; | 135 | key->ct.zone = zone->id; |
136 | key->ct.mark = ovs_ct_get_mark(ct); | 136 | key->ct.mark = ovs_ct_get_mark(ct); |
137 | ovs_ct_get_label(ct, &key->ct.label); | 137 | ovs_ct_get_labels(ct, &key->ct.labels); |
138 | } | 138 | } |
139 | 139 | ||
140 | /* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has | 140 | /* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has |
@@ -151,6 +151,8 @@ static void ovs_ct_update_key(const struct sk_buff *skb, | |||
151 | ct = nf_ct_get(skb, &ctinfo); | 151 | ct = nf_ct_get(skb, &ctinfo); |
152 | if (ct) { | 152 | if (ct) { |
153 | state = ovs_ct_get_state(ctinfo); | 153 | state = ovs_ct_get_state(ctinfo); |
154 | if (!nf_ct_is_confirmed(ct)) | ||
155 | state |= OVS_CS_F_NEW; | ||
154 | if (ct->master) | 156 | if (ct->master) |
155 | state |= OVS_CS_F_RELATED; | 157 | state |= OVS_CS_F_RELATED; |
156 | zone = nf_ct_zone(ct); | 158 | zone = nf_ct_zone(ct); |
@@ -167,7 +169,7 @@ void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key) | |||
167 | 169 | ||
168 | int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) | 170 | int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) |
169 | { | 171 | { |
170 | if (nla_put_u8(skb, OVS_KEY_ATTR_CT_STATE, key->ct.state)) | 172 | if (nla_put_u32(skb, OVS_KEY_ATTR_CT_STATE, key->ct.state)) |
171 | return -EMSGSIZE; | 173 | return -EMSGSIZE; |
172 | 174 | ||
173 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && | 175 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && |
@@ -179,8 +181,8 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) | |||
179 | return -EMSGSIZE; | 181 | return -EMSGSIZE; |
180 | 182 | ||
181 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && | 183 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && |
182 | nla_put(skb, OVS_KEY_ATTR_CT_LABEL, sizeof(key->ct.label), | 184 | nla_put(skb, OVS_KEY_ATTR_CT_LABELS, sizeof(key->ct.labels), |
183 | &key->ct.label)) | 185 | &key->ct.labels)) |
184 | return -EMSGSIZE; | 186 | return -EMSGSIZE; |
185 | 187 | ||
186 | return 0; | 188 | return 0; |
@@ -213,18 +215,15 @@ static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key, | |||
213 | #endif | 215 | #endif |
214 | } | 216 | } |
215 | 217 | ||
216 | static int ovs_ct_set_label(struct sk_buff *skb, struct sw_flow_key *key, | 218 | static int ovs_ct_set_labels(struct sk_buff *skb, struct sw_flow_key *key, |
217 | const struct ovs_key_ct_label *label, | 219 | const struct ovs_key_ct_labels *labels, |
218 | const struct ovs_key_ct_label *mask) | 220 | const struct ovs_key_ct_labels *mask) |
219 | { | 221 | { |
220 | enum ip_conntrack_info ctinfo; | 222 | enum ip_conntrack_info ctinfo; |
221 | struct nf_conn_labels *cl; | 223 | struct nf_conn_labels *cl; |
222 | struct nf_conn *ct; | 224 | struct nf_conn *ct; |
223 | int err; | 225 | int err; |
224 | 226 | ||
225 | if (!IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS)) | ||
226 | return -ENOTSUPP; | ||
227 | |||
228 | /* The connection could be invalid, in which case set_label is no-op.*/ | 227 | /* The connection could be invalid, in which case set_label is no-op.*/ |
229 | ct = nf_ct_get(skb, &ctinfo); | 228 | ct = nf_ct_get(skb, &ctinfo); |
230 | if (!ct) | 229 | if (!ct) |
@@ -235,15 +234,15 @@ static int ovs_ct_set_label(struct sk_buff *skb, struct sw_flow_key *key, | |||
235 | nf_ct_labels_ext_add(ct); | 234 | nf_ct_labels_ext_add(ct); |
236 | cl = nf_ct_labels_find(ct); | 235 | cl = nf_ct_labels_find(ct); |
237 | } | 236 | } |
238 | if (!cl || cl->words * sizeof(long) < OVS_CT_LABEL_LEN) | 237 | if (!cl || cl->words * sizeof(long) < OVS_CT_LABELS_LEN) |
239 | return -ENOSPC; | 238 | return -ENOSPC; |
240 | 239 | ||
241 | err = nf_connlabels_replace(ct, (u32 *)label, (u32 *)mask, | 240 | err = nf_connlabels_replace(ct, (u32 *)labels, (u32 *)mask, |
242 | OVS_CT_LABEL_LEN / sizeof(u32)); | 241 | OVS_CT_LABELS_LEN / sizeof(u32)); |
243 | if (err) | 242 | if (err) |
244 | return err; | 243 | return err; |
245 | 244 | ||
246 | ovs_ct_get_label(ct, &key->ct.label); | 245 | ovs_ct_get_labels(ct, &key->ct.labels); |
247 | return 0; | 246 | return 0; |
248 | } | 247 | } |
249 | 248 | ||
@@ -275,13 +274,15 @@ static int ovs_ct_helper(struct sk_buff *skb, u16 proto) | |||
275 | case NFPROTO_IPV6: { | 274 | case NFPROTO_IPV6: { |
276 | u8 nexthdr = ipv6_hdr(skb)->nexthdr; | 275 | u8 nexthdr = ipv6_hdr(skb)->nexthdr; |
277 | __be16 frag_off; | 276 | __be16 frag_off; |
277 | int ofs; | ||
278 | 278 | ||
279 | protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), | 279 | ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, |
280 | &nexthdr, &frag_off); | 280 | &frag_off); |
281 | if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { | 281 | if (ofs < 0 || (frag_off & htons(~0x7)) != 0) { |
282 | pr_debug("proto header not found\n"); | 282 | pr_debug("proto header not found\n"); |
283 | return NF_ACCEPT; | 283 | return NF_ACCEPT; |
284 | } | 284 | } |
285 | protoff = ofs; | ||
285 | break; | 286 | break; |
286 | } | 287 | } |
287 | default: | 288 | default: |
@@ -292,6 +293,9 @@ static int ovs_ct_helper(struct sk_buff *skb, u16 proto) | |||
292 | return helper->help(skb, protoff, ct, ctinfo); | 293 | return helper->help(skb, protoff, ct, ctinfo); |
293 | } | 294 | } |
294 | 295 | ||
296 | /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero | ||
297 | * value if 'skb' is freed. | ||
298 | */ | ||
295 | static int handle_fragments(struct net *net, struct sw_flow_key *key, | 299 | static int handle_fragments(struct net *net, struct sw_flow_key *key, |
296 | u16 zone, struct sk_buff *skb) | 300 | u16 zone, struct sk_buff *skb) |
297 | { | 301 | { |
@@ -307,8 +311,8 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key, | |||
307 | return err; | 311 | return err; |
308 | 312 | ||
309 | ovs_cb.mru = IPCB(skb)->frag_max_size; | 313 | ovs_cb.mru = IPCB(skb)->frag_max_size; |
310 | } else if (key->eth.type == htons(ETH_P_IPV6)) { | ||
311 | #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) | 314 | #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) |
315 | } else if (key->eth.type == htons(ETH_P_IPV6)) { | ||
312 | enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone; | 316 | enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone; |
313 | struct sk_buff *reasm; | 317 | struct sk_buff *reasm; |
314 | 318 | ||
@@ -317,17 +321,25 @@ static int handle_fragments(struct net *net, struct sw_flow_key *key, | |||
317 | if (!reasm) | 321 | if (!reasm) |
318 | return -EINPROGRESS; | 322 | return -EINPROGRESS; |
319 | 323 | ||
320 | if (skb == reasm) | 324 | if (skb == reasm) { |
325 | kfree_skb(skb); | ||
321 | return -EINVAL; | 326 | return -EINVAL; |
327 | } | ||
328 | |||
329 | /* Don't free 'skb' even though it is one of the original | ||
330 | * fragments, as we're going to morph it into the head. | ||
331 | */ | ||
332 | skb_get(skb); | ||
333 | nf_ct_frag6_consume_orig(reasm); | ||
322 | 334 | ||
323 | key->ip.proto = ipv6_hdr(reasm)->nexthdr; | 335 | key->ip.proto = ipv6_hdr(reasm)->nexthdr; |
324 | skb_morph(skb, reasm); | 336 | skb_morph(skb, reasm); |
337 | skb->next = reasm->next; | ||
325 | consume_skb(reasm); | 338 | consume_skb(reasm); |
326 | ovs_cb.mru = IP6CB(skb)->frag_max_size; | 339 | ovs_cb.mru = IP6CB(skb)->frag_max_size; |
327 | #else | ||
328 | return -EPFNOSUPPORT; | ||
329 | #endif | 340 | #endif |
330 | } else { | 341 | } else { |
342 | kfree_skb(skb); | ||
331 | return -EPFNOSUPPORT; | 343 | return -EPFNOSUPPORT; |
332 | } | 344 | } |
333 | 345 | ||
@@ -375,7 +387,7 @@ static bool skb_nfct_cached(const struct net *net, const struct sk_buff *skb, | |||
375 | return true; | 387 | return true; |
376 | } | 388 | } |
377 | 389 | ||
378 | static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key, | 390 | static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key, |
379 | const struct ovs_conntrack_info *info, | 391 | const struct ovs_conntrack_info *info, |
380 | struct sk_buff *skb) | 392 | struct sk_buff *skb) |
381 | { | 393 | { |
@@ -406,6 +418,8 @@ static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key, | |||
406 | } | 418 | } |
407 | } | 419 | } |
408 | 420 | ||
421 | ovs_ct_update_key(skb, key, true); | ||
422 | |||
409 | return 0; | 423 | return 0; |
410 | } | 424 | } |
411 | 425 | ||
@@ -428,8 +442,6 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, | |||
428 | err = __ovs_ct_lookup(net, key, info, skb); | 442 | err = __ovs_ct_lookup(net, key, info, skb); |
429 | if (err) | 443 | if (err) |
430 | return err; | 444 | return err; |
431 | |||
432 | ovs_ct_update_key(skb, key, true); | ||
433 | } | 445 | } |
434 | 446 | ||
435 | return 0; | 447 | return 0; |
@@ -458,22 +470,23 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, | |||
458 | if (nf_conntrack_confirm(skb) != NF_ACCEPT) | 470 | if (nf_conntrack_confirm(skb) != NF_ACCEPT) |
459 | return -EINVAL; | 471 | return -EINVAL; |
460 | 472 | ||
461 | ovs_ct_update_key(skb, key, true); | ||
462 | |||
463 | return 0; | 473 | return 0; |
464 | } | 474 | } |
465 | 475 | ||
466 | static bool label_nonzero(const struct ovs_key_ct_label *label) | 476 | static bool labels_nonzero(const struct ovs_key_ct_labels *labels) |
467 | { | 477 | { |
468 | size_t i; | 478 | size_t i; |
469 | 479 | ||
470 | for (i = 0; i < sizeof(*label); i++) | 480 | for (i = 0; i < sizeof(*labels); i++) |
471 | if (label->ct_label[i]) | 481 | if (labels->ct_labels[i]) |
472 | return true; | 482 | return true; |
473 | 483 | ||
474 | return false; | 484 | return false; |
475 | } | 485 | } |
476 | 486 | ||
487 | /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero | ||
488 | * value if 'skb' is freed. | ||
489 | */ | ||
477 | int ovs_ct_execute(struct net *net, struct sk_buff *skb, | 490 | int ovs_ct_execute(struct net *net, struct sk_buff *skb, |
478 | struct sw_flow_key *key, | 491 | struct sw_flow_key *key, |
479 | const struct ovs_conntrack_info *info) | 492 | const struct ovs_conntrack_info *info) |
@@ -491,7 +504,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, | |||
491 | return err; | 504 | return err; |
492 | } | 505 | } |
493 | 506 | ||
494 | if (info->flags & OVS_CT_F_COMMIT) | 507 | if (info->commit) |
495 | err = ovs_ct_commit(net, key, info, skb); | 508 | err = ovs_ct_commit(net, key, info, skb); |
496 | else | 509 | else |
497 | err = ovs_ct_lookup(net, key, info, skb); | 510 | err = ovs_ct_lookup(net, key, info, skb); |
@@ -504,11 +517,13 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, | |||
504 | if (err) | 517 | if (err) |
505 | goto err; | 518 | goto err; |
506 | } | 519 | } |
507 | if (label_nonzero(&info->label.mask)) | 520 | if (labels_nonzero(&info->labels.mask)) |
508 | err = ovs_ct_set_label(skb, key, &info->label.value, | 521 | err = ovs_ct_set_labels(skb, key, &info->labels.value, |
509 | &info->label.mask); | 522 | &info->labels.mask); |
510 | err: | 523 | err: |
511 | skb_push(skb, nh_ofs); | 524 | skb_push(skb, nh_ofs); |
525 | if (err) | ||
526 | kfree_skb(skb); | ||
512 | return err; | 527 | return err; |
513 | } | 528 | } |
514 | 529 | ||
@@ -537,14 +552,13 @@ static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name, | |||
537 | } | 552 | } |
538 | 553 | ||
539 | static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { | 554 | static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { |
540 | [OVS_CT_ATTR_FLAGS] = { .minlen = sizeof(u32), | 555 | [OVS_CT_ATTR_COMMIT] = { .minlen = 0, .maxlen = 0 }, |
541 | .maxlen = sizeof(u32) }, | ||
542 | [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), | 556 | [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), |
543 | .maxlen = sizeof(u16) }, | 557 | .maxlen = sizeof(u16) }, |
544 | [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark), | 558 | [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark), |
545 | .maxlen = sizeof(struct md_mark) }, | 559 | .maxlen = sizeof(struct md_mark) }, |
546 | [OVS_CT_ATTR_LABEL] = { .minlen = sizeof(struct md_label), | 560 | [OVS_CT_ATTR_LABELS] = { .minlen = sizeof(struct md_labels), |
547 | .maxlen = sizeof(struct md_label) }, | 561 | .maxlen = sizeof(struct md_labels) }, |
548 | [OVS_CT_ATTR_HELPER] = { .minlen = 1, | 562 | [OVS_CT_ATTR_HELPER] = { .minlen = 1, |
549 | .maxlen = NF_CT_HELPER_NAME_LEN } | 563 | .maxlen = NF_CT_HELPER_NAME_LEN } |
550 | }; | 564 | }; |
@@ -574,8 +588,8 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, | |||
574 | } | 588 | } |
575 | 589 | ||
576 | switch (type) { | 590 | switch (type) { |
577 | case OVS_CT_ATTR_FLAGS: | 591 | case OVS_CT_ATTR_COMMIT: |
578 | info->flags = nla_get_u32(a); | 592 | info->commit = true; |
579 | break; | 593 | break; |
580 | #ifdef CONFIG_NF_CONNTRACK_ZONES | 594 | #ifdef CONFIG_NF_CONNTRACK_ZONES |
581 | case OVS_CT_ATTR_ZONE: | 595 | case OVS_CT_ATTR_ZONE: |
@@ -586,15 +600,23 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, | |||
586 | case OVS_CT_ATTR_MARK: { | 600 | case OVS_CT_ATTR_MARK: { |
587 | struct md_mark *mark = nla_data(a); | 601 | struct md_mark *mark = nla_data(a); |
588 | 602 | ||
603 | if (!mark->mask) { | ||
604 | OVS_NLERR(log, "ct_mark mask cannot be 0"); | ||
605 | return -EINVAL; | ||
606 | } | ||
589 | info->mark = *mark; | 607 | info->mark = *mark; |
590 | break; | 608 | break; |
591 | } | 609 | } |
592 | #endif | 610 | #endif |
593 | #ifdef CONFIG_NF_CONNTRACK_LABELS | 611 | #ifdef CONFIG_NF_CONNTRACK_LABELS |
594 | case OVS_CT_ATTR_LABEL: { | 612 | case OVS_CT_ATTR_LABELS: { |
595 | struct md_label *label = nla_data(a); | 613 | struct md_labels *labels = nla_data(a); |
596 | 614 | ||
597 | info->label = *label; | 615 | if (!labels_nonzero(&labels->mask)) { |
616 | OVS_NLERR(log, "ct_labels mask cannot be 0"); | ||
617 | return -EINVAL; | ||
618 | } | ||
619 | info->labels = *labels; | ||
598 | break; | 620 | break; |
599 | } | 621 | } |
600 | #endif | 622 | #endif |
@@ -631,7 +653,7 @@ bool ovs_ct_verify(struct net *net, enum ovs_key_attr attr) | |||
631 | attr == OVS_KEY_ATTR_CT_MARK) | 653 | attr == OVS_KEY_ATTR_CT_MARK) |
632 | return true; | 654 | return true; |
633 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && | 655 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && |
634 | attr == OVS_KEY_ATTR_CT_LABEL) { | 656 | attr == OVS_KEY_ATTR_CT_LABELS) { |
635 | struct ovs_net *ovs_net = net_generic(net, ovs_net_id); | 657 | struct ovs_net *ovs_net = net_generic(net, ovs_net_id); |
636 | 658 | ||
637 | return ovs_net->xt_label; | 659 | return ovs_net->xt_label; |
@@ -699,18 +721,19 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, | |||
699 | if (!start) | 721 | if (!start) |
700 | return -EMSGSIZE; | 722 | return -EMSGSIZE; |
701 | 723 | ||
702 | if (nla_put_u32(skb, OVS_CT_ATTR_FLAGS, ct_info->flags)) | 724 | if (ct_info->commit && nla_put_flag(skb, OVS_CT_ATTR_COMMIT)) |
703 | return -EMSGSIZE; | 725 | return -EMSGSIZE; |
704 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && | 726 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && |
705 | nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) | 727 | nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) |
706 | return -EMSGSIZE; | 728 | return -EMSGSIZE; |
707 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && | 729 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && ct_info->mark.mask && |
708 | nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), | 730 | nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), |
709 | &ct_info->mark)) | 731 | &ct_info->mark)) |
710 | return -EMSGSIZE; | 732 | return -EMSGSIZE; |
711 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && | 733 | if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && |
712 | nla_put(skb, OVS_CT_ATTR_LABEL, sizeof(ct_info->label), | 734 | labels_nonzero(&ct_info->labels.mask) && |
713 | &ct_info->label)) | 735 | nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels), |
736 | &ct_info->labels)) | ||
714 | return -EMSGSIZE; | 737 | return -EMSGSIZE; |
715 | if (ct_info->helper) { | 738 | if (ct_info->helper) { |
716 | if (nla_put_string(skb, OVS_CT_ATTR_HELPER, | 739 | if (nla_put_string(skb, OVS_CT_ATTR_HELPER, |
@@ -735,7 +758,7 @@ void ovs_ct_free_action(const struct nlattr *a) | |||
735 | 758 | ||
736 | void ovs_ct_init(struct net *net) | 759 | void ovs_ct_init(struct net *net) |
737 | { | 760 | { |
738 | unsigned int n_bits = sizeof(struct ovs_key_ct_label) * BITS_PER_BYTE; | 761 | unsigned int n_bits = sizeof(struct ovs_key_ct_labels) * BITS_PER_BYTE; |
739 | struct ovs_net *ovs_net = net_generic(net, ovs_net_id); | 762 | struct ovs_net *ovs_net = net_generic(net, ovs_net_id); |
740 | 763 | ||
741 | if (nf_connlabels_get(net, n_bits)) { | 764 | if (nf_connlabels_get(net, n_bits)) { |
diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h index 43f5dd7a5577..a7544f405c16 100644 --- a/net/openvswitch/conntrack.h +++ b/net/openvswitch/conntrack.h | |||
@@ -34,6 +34,10 @@ int ovs_ct_execute(struct net *, struct sk_buff *, struct sw_flow_key *, | |||
34 | void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key); | 34 | void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key); |
35 | int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb); | 35 | int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb); |
36 | void ovs_ct_free_action(const struct nlattr *a); | 36 | void ovs_ct_free_action(const struct nlattr *a); |
37 | |||
38 | #define CT_SUPPORTED_MASK (OVS_CS_F_NEW | OVS_CS_F_ESTABLISHED | \ | ||
39 | OVS_CS_F_RELATED | OVS_CS_F_REPLY_DIR | \ | ||
40 | OVS_CS_F_INVALID | OVS_CS_F_TRACKED) | ||
37 | #else | 41 | #else |
38 | #include <linux/errno.h> | 42 | #include <linux/errno.h> |
39 | 43 | ||
@@ -63,6 +67,7 @@ static inline int ovs_ct_execute(struct net *net, struct sk_buff *skb, | |||
63 | struct sw_flow_key *key, | 67 | struct sw_flow_key *key, |
64 | const struct ovs_conntrack_info *info) | 68 | const struct ovs_conntrack_info *info) |
65 | { | 69 | { |
70 | kfree_skb(skb); | ||
66 | return -ENOTSUPP; | 71 | return -ENOTSUPP; |
67 | } | 72 | } |
68 | 73 | ||
@@ -72,7 +77,7 @@ static inline void ovs_ct_fill_key(const struct sk_buff *skb, | |||
72 | key->ct.state = 0; | 77 | key->ct.state = 0; |
73 | key->ct.zone = 0; | 78 | key->ct.zone = 0; |
74 | key->ct.mark = 0; | 79 | key->ct.mark = 0; |
75 | memset(&key->ct.label, 0, sizeof(key->ct.label)); | 80 | memset(&key->ct.labels, 0, sizeof(key->ct.labels)); |
76 | } | 81 | } |
77 | 82 | ||
78 | static inline int ovs_ct_put_key(const struct sw_flow_key *key, | 83 | static inline int ovs_ct_put_key(const struct sw_flow_key *key, |
@@ -82,5 +87,7 @@ static inline int ovs_ct_put_key(const struct sw_flow_key *key, | |||
82 | } | 87 | } |
83 | 88 | ||
84 | static inline void ovs_ct_free_action(const struct nlattr *a) { } | 89 | static inline void ovs_ct_free_action(const struct nlattr *a) { } |
90 | |||
91 | #define CT_SUPPORTED_MASK 0 | ||
85 | #endif /* CONFIG_NF_CONNTRACK */ | 92 | #endif /* CONFIG_NF_CONNTRACK */ |
86 | #endif /* ovs_conntrack.h */ | 93 | #endif /* ovs_conntrack.h */ |
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 6fbd2decb19e..c5d08ee37730 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -490,9 +490,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, | |||
490 | 490 | ||
491 | if (upcall_info->egress_tun_info) { | 491 | if (upcall_info->egress_tun_info) { |
492 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY); | 492 | nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY); |
493 | err = ovs_nla_put_egress_tunnel_key(user_skb, | 493 | err = ovs_nla_put_tunnel_info(user_skb, |
494 | upcall_info->egress_tun_info, | 494 | upcall_info->egress_tun_info); |
495 | upcall_info->egress_tun_opts); | ||
496 | BUG_ON(err); | 495 | BUG_ON(err); |
497 | nla_nest_end(user_skb, nla); | 496 | nla_nest_end(user_skb, nla); |
498 | } | 497 | } |
@@ -952,7 +951,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) | |||
952 | if (error) | 951 | if (error) |
953 | goto err_kfree_flow; | 952 | goto err_kfree_flow; |
954 | 953 | ||
955 | ovs_flow_mask_key(&new_flow->key, &key, &mask); | 954 | ovs_flow_mask_key(&new_flow->key, &key, true, &mask); |
956 | 955 | ||
957 | /* Extract flow identifier. */ | 956 | /* Extract flow identifier. */ |
958 | error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID], | 957 | error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID], |
@@ -1080,7 +1079,7 @@ static struct sw_flow_actions *get_flow_actions(struct net *net, | |||
1080 | struct sw_flow_key masked_key; | 1079 | struct sw_flow_key masked_key; |
1081 | int error; | 1080 | int error; |
1082 | 1081 | ||
1083 | ovs_flow_mask_key(&masked_key, key, mask); | 1082 | ovs_flow_mask_key(&masked_key, key, true, mask); |
1084 | error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log); | 1083 | error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log); |
1085 | if (error) { | 1084 | if (error) { |
1086 | OVS_NLERR(log, | 1085 | OVS_NLERR(log, |
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index f88038a99f44..67bdecd9fdc1 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
@@ -117,7 +117,6 @@ struct ovs_skb_cb { | |||
117 | */ | 117 | */ |
118 | struct dp_upcall_info { | 118 | struct dp_upcall_info { |
119 | struct ip_tunnel_info *egress_tun_info; | 119 | struct ip_tunnel_info *egress_tun_info; |
120 | const void *egress_tun_opts; | ||
121 | const struct nlattr *userdata; | 120 | const struct nlattr *userdata; |
122 | const struct nlattr *actions; | 121 | const struct nlattr *actions; |
123 | int actions_len; | 122 | int actions_len; |
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index fe527d2dd4b7..8cfa15a08668 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h | |||
@@ -116,7 +116,7 @@ struct sw_flow_key { | |||
116 | u16 zone; | 116 | u16 zone; |
117 | u32 mark; | 117 | u32 mark; |
118 | u8 state; | 118 | u8 state; |
119 | struct ovs_key_ct_label label; | 119 | struct ovs_key_ct_labels labels; |
120 | } ct; | 120 | } ct; |
121 | 121 | ||
122 | } __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */ | 122 | } __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */ |
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index c92d6a262bc5..38536c137c54 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c | |||
@@ -57,6 +57,7 @@ struct ovs_len_tbl { | |||
57 | }; | 57 | }; |
58 | 58 | ||
59 | #define OVS_ATTR_NESTED -1 | 59 | #define OVS_ATTR_NESTED -1 |
60 | #define OVS_ATTR_VARIABLE -2 | ||
60 | 61 | ||
61 | static void update_range(struct sw_flow_match *match, | 62 | static void update_range(struct sw_flow_match *match, |
62 | size_t offset, size_t size, bool is_mask) | 63 | size_t offset, size_t size, bool is_mask) |
@@ -290,10 +291,10 @@ size_t ovs_key_attr_size(void) | |||
290 | + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ | 291 | + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ |
291 | + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */ | 292 | + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */ |
292 | + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */ | 293 | + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */ |
293 | + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */ | 294 | + nla_total_size(4) /* OVS_KEY_ATTR_CT_STATE */ |
294 | + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ | 295 | + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ |
295 | + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ | 296 | + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ |
296 | + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABEL */ | 297 | + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABELS */ |
297 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ | 298 | + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ |
298 | + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ | 299 | + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ |
299 | + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ | 300 | + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ |
@@ -304,6 +305,10 @@ size_t ovs_key_attr_size(void) | |||
304 | + nla_total_size(28); /* OVS_KEY_ATTR_ND */ | 305 | + nla_total_size(28); /* OVS_KEY_ATTR_ND */ |
305 | } | 306 | } |
306 | 307 | ||
308 | static const struct ovs_len_tbl ovs_vxlan_ext_key_lens[OVS_VXLAN_EXT_MAX + 1] = { | ||
309 | [OVS_VXLAN_EXT_GBP] = { .len = sizeof(u32) }, | ||
310 | }; | ||
311 | |||
307 | static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { | 312 | static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = { |
308 | [OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) }, | 313 | [OVS_TUNNEL_KEY_ATTR_ID] = { .len = sizeof(u64) }, |
309 | [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) }, | 314 | [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = { .len = sizeof(u32) }, |
@@ -315,8 +320,9 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] | |||
315 | [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) }, | 320 | [OVS_TUNNEL_KEY_ATTR_TP_SRC] = { .len = sizeof(u16) }, |
316 | [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) }, | 321 | [OVS_TUNNEL_KEY_ATTR_TP_DST] = { .len = sizeof(u16) }, |
317 | [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 }, | 322 | [OVS_TUNNEL_KEY_ATTR_OAM] = { .len = 0 }, |
318 | [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_NESTED }, | 323 | [OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS] = { .len = OVS_ATTR_VARIABLE }, |
319 | [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED }, | 324 | [OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = OVS_ATTR_NESTED, |
325 | .next = ovs_vxlan_ext_key_lens }, | ||
320 | }; | 326 | }; |
321 | 327 | ||
322 | /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ | 328 | /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute. */ |
@@ -343,12 +349,19 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { | |||
343 | [OVS_KEY_ATTR_TUNNEL] = { .len = OVS_ATTR_NESTED, | 349 | [OVS_KEY_ATTR_TUNNEL] = { .len = OVS_ATTR_NESTED, |
344 | .next = ovs_tunnel_key_lens, }, | 350 | .next = ovs_tunnel_key_lens, }, |
345 | [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) }, | 351 | [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) }, |
346 | [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) }, | 352 | [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u32) }, |
347 | [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) }, | 353 | [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) }, |
348 | [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) }, | 354 | [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) }, |
349 | [OVS_KEY_ATTR_CT_LABEL] = { .len = sizeof(struct ovs_key_ct_label) }, | 355 | [OVS_KEY_ATTR_CT_LABELS] = { .len = sizeof(struct ovs_key_ct_labels) }, |
350 | }; | 356 | }; |
351 | 357 | ||
358 | static bool check_attr_len(unsigned int attr_len, unsigned int expected_len) | ||
359 | { | ||
360 | return expected_len == attr_len || | ||
361 | expected_len == OVS_ATTR_NESTED || | ||
362 | expected_len == OVS_ATTR_VARIABLE; | ||
363 | } | ||
364 | |||
352 | static bool is_all_zero(const u8 *fp, size_t size) | 365 | static bool is_all_zero(const u8 *fp, size_t size) |
353 | { | 366 | { |
354 | int i; | 367 | int i; |
@@ -388,7 +401,7 @@ static int __parse_flow_nlattrs(const struct nlattr *attr, | |||
388 | } | 401 | } |
389 | 402 | ||
390 | expected_len = ovs_key_lens[type].len; | 403 | expected_len = ovs_key_lens[type].len; |
391 | if (nla_len(nla) != expected_len && expected_len != OVS_ATTR_NESTED) { | 404 | if (!check_attr_len(nla_len(nla), expected_len)) { |
392 | OVS_NLERR(log, "Key %d has unexpected len %d expected %d", | 405 | OVS_NLERR(log, "Key %d has unexpected len %d expected %d", |
393 | type, nla_len(nla), expected_len); | 406 | type, nla_len(nla), expected_len); |
394 | return -EINVAL; | 407 | return -EINVAL; |
@@ -473,29 +486,50 @@ static int genev_tun_opt_from_nlattr(const struct nlattr *a, | |||
473 | return 0; | 486 | return 0; |
474 | } | 487 | } |
475 | 488 | ||
476 | static const struct nla_policy vxlan_opt_policy[OVS_VXLAN_EXT_MAX + 1] = { | 489 | static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr, |
477 | [OVS_VXLAN_EXT_GBP] = { .type = NLA_U32 }, | ||
478 | }; | ||
479 | |||
480 | static int vxlan_tun_opt_from_nlattr(const struct nlattr *a, | ||
481 | struct sw_flow_match *match, bool is_mask, | 490 | struct sw_flow_match *match, bool is_mask, |
482 | bool log) | 491 | bool log) |
483 | { | 492 | { |
484 | struct nlattr *tb[OVS_VXLAN_EXT_MAX+1]; | 493 | struct nlattr *a; |
494 | int rem; | ||
485 | unsigned long opt_key_offset; | 495 | unsigned long opt_key_offset; |
486 | struct vxlan_metadata opts; | 496 | struct vxlan_metadata opts; |
487 | int err; | ||
488 | 497 | ||
489 | BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); | 498 | BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); |
490 | 499 | ||
491 | err = nla_parse_nested(tb, OVS_VXLAN_EXT_MAX, a, vxlan_opt_policy); | ||
492 | if (err < 0) | ||
493 | return err; | ||
494 | |||
495 | memset(&opts, 0, sizeof(opts)); | 500 | memset(&opts, 0, sizeof(opts)); |
501 | nla_for_each_nested(a, attr, rem) { | ||
502 | int type = nla_type(a); | ||
496 | 503 | ||
497 | if (tb[OVS_VXLAN_EXT_GBP]) | 504 | if (type > OVS_VXLAN_EXT_MAX) { |
498 | opts.gbp = nla_get_u32(tb[OVS_VXLAN_EXT_GBP]); | 505 | OVS_NLERR(log, "VXLAN extension %d out of range max %d", |
506 | type, OVS_VXLAN_EXT_MAX); | ||
507 | return -EINVAL; | ||
508 | } | ||
509 | |||
510 | if (!check_attr_len(nla_len(a), | ||
511 | ovs_vxlan_ext_key_lens[type].len)) { | ||
512 | OVS_NLERR(log, "VXLAN extension %d has unexpected len %d expected %d", | ||
513 | type, nla_len(a), | ||
514 | ovs_vxlan_ext_key_lens[type].len); | ||
515 | return -EINVAL; | ||
516 | } | ||
517 | |||
518 | switch (type) { | ||
519 | case OVS_VXLAN_EXT_GBP: | ||
520 | opts.gbp = nla_get_u32(a); | ||
521 | break; | ||
522 | default: | ||
523 | OVS_NLERR(log, "Unknown VXLAN extension attribute %d", | ||
524 | type); | ||
525 | return -EINVAL; | ||
526 | } | ||
527 | } | ||
528 | if (rem) { | ||
529 | OVS_NLERR(log, "VXLAN extension message has %d unknown bytes.", | ||
530 | rem); | ||
531 | return -EINVAL; | ||
532 | } | ||
499 | 533 | ||
500 | if (!is_mask) | 534 | if (!is_mask) |
501 | SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false); | 535 | SW_FLOW_KEY_PUT(match, tun_opts_len, sizeof(opts), false); |
@@ -528,8 +562,8 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, | |||
528 | return -EINVAL; | 562 | return -EINVAL; |
529 | } | 563 | } |
530 | 564 | ||
531 | if (ovs_tunnel_key_lens[type].len != nla_len(a) && | 565 | if (!check_attr_len(nla_len(a), |
532 | ovs_tunnel_key_lens[type].len != OVS_ATTR_NESTED) { | 566 | ovs_tunnel_key_lens[type].len)) { |
533 | OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d", | 567 | OVS_NLERR(log, "Tunnel attr %d has unexpected len %d expected %d", |
534 | type, nla_len(a), ovs_tunnel_key_lens[type].len); | 568 | type, nla_len(a), ovs_tunnel_key_lens[type].len); |
535 | return -EINVAL; | 569 | return -EINVAL; |
@@ -683,7 +717,7 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb, | |||
683 | if ((output->tun_flags & TUNNEL_OAM) && | 717 | if ((output->tun_flags & TUNNEL_OAM) && |
684 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM)) | 718 | nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM)) |
685 | return -EMSGSIZE; | 719 | return -EMSGSIZE; |
686 | if (tun_opts) { | 720 | if (swkey_tun_opts_len) { |
687 | if (output->tun_flags & TUNNEL_GENEVE_OPT && | 721 | if (output->tun_flags & TUNNEL_GENEVE_OPT && |
688 | nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, | 722 | nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, |
689 | swkey_tun_opts_len, tun_opts)) | 723 | swkey_tun_opts_len, tun_opts)) |
@@ -715,13 +749,12 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb, | |||
715 | return 0; | 749 | return 0; |
716 | } | 750 | } |
717 | 751 | ||
718 | int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb, | 752 | int ovs_nla_put_tunnel_info(struct sk_buff *skb, |
719 | const struct ip_tunnel_info *egress_tun_info, | 753 | struct ip_tunnel_info *tun_info) |
720 | const void *egress_tun_opts) | ||
721 | { | 754 | { |
722 | return __ipv4_tun_to_nlattr(skb, &egress_tun_info->key, | 755 | return __ipv4_tun_to_nlattr(skb, &tun_info->key, |
723 | egress_tun_opts, | 756 | ip_tunnel_info_opts(tun_info), |
724 | egress_tun_info->options_len); | 757 | tun_info->options_len); |
725 | } | 758 | } |
726 | 759 | ||
727 | static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, | 760 | static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, |
@@ -780,7 +813,13 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, | |||
780 | 813 | ||
781 | if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) && | 814 | if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) && |
782 | ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) { | 815 | ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) { |
783 | u8 ct_state = nla_get_u8(a[OVS_KEY_ATTR_CT_STATE]); | 816 | u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]); |
817 | |||
818 | if (ct_state & ~CT_SUPPORTED_MASK) { | ||
819 | OVS_NLERR(log, "ct_state flags %08x unsupported", | ||
820 | ct_state); | ||
821 | return -EINVAL; | ||
822 | } | ||
784 | 823 | ||
785 | SW_FLOW_KEY_PUT(match, ct.state, ct_state, is_mask); | 824 | SW_FLOW_KEY_PUT(match, ct.state, ct_state, is_mask); |
786 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE); | 825 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE); |
@@ -799,14 +838,14 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, | |||
799 | SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask); | 838 | SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask); |
800 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK); | 839 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK); |
801 | } | 840 | } |
802 | if (*attrs & (1 << OVS_KEY_ATTR_CT_LABEL) && | 841 | if (*attrs & (1 << OVS_KEY_ATTR_CT_LABELS) && |
803 | ovs_ct_verify(net, OVS_KEY_ATTR_CT_LABEL)) { | 842 | ovs_ct_verify(net, OVS_KEY_ATTR_CT_LABELS)) { |
804 | const struct ovs_key_ct_label *cl; | 843 | const struct ovs_key_ct_labels *cl; |
805 | 844 | ||
806 | cl = nla_data(a[OVS_KEY_ATTR_CT_LABEL]); | 845 | cl = nla_data(a[OVS_KEY_ATTR_CT_LABELS]); |
807 | SW_FLOW_KEY_MEMCPY(match, ct.label, cl->ct_label, | 846 | SW_FLOW_KEY_MEMCPY(match, ct.labels, cl->ct_labels, |
808 | sizeof(*cl), is_mask); | 847 | sizeof(*cl), is_mask); |
809 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABEL); | 848 | *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABELS); |
810 | } | 849 | } |
811 | return 0; | 850 | return 0; |
812 | } | 851 | } |
@@ -1052,10 +1091,16 @@ static void nlattr_set(struct nlattr *attr, u8 val, | |||
1052 | 1091 | ||
1053 | /* The nlattr stream should already have been validated */ | 1092 | /* The nlattr stream should already have been validated */ |
1054 | nla_for_each_nested(nla, attr, rem) { | 1093 | nla_for_each_nested(nla, attr, rem) { |
1055 | if (tbl && tbl[nla_type(nla)].len == OVS_ATTR_NESTED) | 1094 | if (tbl[nla_type(nla)].len == OVS_ATTR_NESTED) { |
1056 | nlattr_set(nla, val, tbl[nla_type(nla)].next); | 1095 | if (tbl[nla_type(nla)].next) |
1057 | else | 1096 | tbl = tbl[nla_type(nla)].next; |
1097 | nlattr_set(nla, val, tbl); | ||
1098 | } else { | ||
1058 | memset(nla_data(nla), val, nla_len(nla)); | 1099 | memset(nla_data(nla), val, nla_len(nla)); |
1100 | } | ||
1101 | |||
1102 | if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE) | ||
1103 | *(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK; | ||
1059 | } | 1104 | } |
1060 | } | 1105 | } |
1061 | 1106 | ||
@@ -1922,8 +1967,7 @@ static int validate_set(const struct nlattr *a, | |||
1922 | key_len /= 2; | 1967 | key_len /= 2; |
1923 | 1968 | ||
1924 | if (key_type > OVS_KEY_ATTR_MAX || | 1969 | if (key_type > OVS_KEY_ATTR_MAX || |
1925 | (ovs_key_lens[key_type].len != key_len && | 1970 | !check_attr_len(key_len, ovs_key_lens[key_type].len)) |
1926 | ovs_key_lens[key_type].len != OVS_ATTR_NESTED)) | ||
1927 | return -EINVAL; | 1971 | return -EINVAL; |
1928 | 1972 | ||
1929 | if (masked && !validate_masked(nla_data(ovs_key), key_len)) | 1973 | if (masked && !validate_masked(nla_data(ovs_key), key_len)) |
@@ -1937,7 +1981,7 @@ static int validate_set(const struct nlattr *a, | |||
1937 | case OVS_KEY_ATTR_PRIORITY: | 1981 | case OVS_KEY_ATTR_PRIORITY: |
1938 | case OVS_KEY_ATTR_SKB_MARK: | 1982 | case OVS_KEY_ATTR_SKB_MARK: |
1939 | case OVS_KEY_ATTR_CT_MARK: | 1983 | case OVS_KEY_ATTR_CT_MARK: |
1940 | case OVS_KEY_ATTR_CT_LABEL: | 1984 | case OVS_KEY_ATTR_CT_LABELS: |
1941 | case OVS_KEY_ATTR_ETHERNET: | 1985 | case OVS_KEY_ATTR_ETHERNET: |
1942 | break; | 1986 | break; |
1943 | 1987 | ||
@@ -2338,10 +2382,7 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) | |||
2338 | if (!start) | 2382 | if (!start) |
2339 | return -EMSGSIZE; | 2383 | return -EMSGSIZE; |
2340 | 2384 | ||
2341 | err = ipv4_tun_to_nlattr(skb, &tun_info->key, | 2385 | err = ovs_nla_put_tunnel_info(skb, tun_info); |
2342 | tun_info->options_len ? | ||
2343 | ip_tunnel_info_opts(tun_info) : NULL, | ||
2344 | tun_info->options_len); | ||
2345 | if (err) | 2386 | if (err) |
2346 | return err; | 2387 | return err; |
2347 | nla_nest_end(skb, start); | 2388 | nla_nest_end(skb, start); |
diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h index 6ca3f0baf449..47dd142eca1c 100644 --- a/net/openvswitch/flow_netlink.h +++ b/net/openvswitch/flow_netlink.h | |||
@@ -55,9 +55,9 @@ int ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb); | |||
55 | int ovs_nla_get_match(struct net *, struct sw_flow_match *, | 55 | int ovs_nla_get_match(struct net *, struct sw_flow_match *, |
56 | const struct nlattr *key, const struct nlattr *mask, | 56 | const struct nlattr *key, const struct nlattr *mask, |
57 | bool log); | 57 | bool log); |
58 | int ovs_nla_put_egress_tunnel_key(struct sk_buff *, | 58 | |
59 | const struct ip_tunnel_info *, | 59 | int ovs_nla_put_tunnel_info(struct sk_buff *skb, |
60 | const void *egress_tun_opts); | 60 | struct ip_tunnel_info *tun_info); |
61 | 61 | ||
62 | bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log); | 62 | bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log); |
63 | int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, | 63 | int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, |
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c index d22d8e948d0f..c7f74aab34b9 100644 --- a/net/openvswitch/flow_table.c +++ b/net/openvswitch/flow_table.c | |||
@@ -57,20 +57,21 @@ static u16 range_n_bytes(const struct sw_flow_key_range *range) | |||
57 | } | 57 | } |
58 | 58 | ||
59 | void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, | 59 | void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, |
60 | const struct sw_flow_mask *mask) | 60 | bool full, const struct sw_flow_mask *mask) |
61 | { | 61 | { |
62 | const long *m = (const long *)((const u8 *)&mask->key + | 62 | int start = full ? 0 : mask->range.start; |
63 | mask->range.start); | 63 | int len = full ? sizeof *dst : range_n_bytes(&mask->range); |
64 | const long *s = (const long *)((const u8 *)src + | 64 | const long *m = (const long *)((const u8 *)&mask->key + start); |
65 | mask->range.start); | 65 | const long *s = (const long *)((const u8 *)src + start); |
66 | long *d = (long *)((u8 *)dst + mask->range.start); | 66 | long *d = (long *)((u8 *)dst + start); |
67 | int i; | 67 | int i; |
68 | 68 | ||
69 | /* The memory outside of the 'mask->range' are not set since | 69 | /* If 'full' is true then all of 'dst' is fully initialized. Otherwise, |
70 | * further operations on 'dst' only uses contents within | 70 | * if 'full' is false the memory outside of the 'mask->range' is left |
71 | * 'mask->range'. | 71 | * uninitialized. This can be used as an optimization when further |
72 | * operations on 'dst' only use contents within 'mask->range'. | ||
72 | */ | 73 | */ |
73 | for (i = 0; i < range_n_bytes(&mask->range); i += sizeof(long)) | 74 | for (i = 0; i < len; i += sizeof(long)) |
74 | *d++ = *s++ & *m++; | 75 | *d++ = *s++ & *m++; |
75 | } | 76 | } |
76 | 77 | ||
@@ -92,7 +93,8 @@ struct sw_flow *ovs_flow_alloc(void) | |||
92 | 93 | ||
93 | /* Initialize the default stat node. */ | 94 | /* Initialize the default stat node. */ |
94 | stats = kmem_cache_alloc_node(flow_stats_cache, | 95 | stats = kmem_cache_alloc_node(flow_stats_cache, |
95 | GFP_KERNEL | __GFP_ZERO, 0); | 96 | GFP_KERNEL | __GFP_ZERO, |
97 | node_online(0) ? 0 : NUMA_NO_NODE); | ||
96 | if (!stats) | 98 | if (!stats) |
97 | goto err; | 99 | goto err; |
98 | 100 | ||
@@ -475,7 +477,7 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti, | |||
475 | u32 hash; | 477 | u32 hash; |
476 | struct sw_flow_key masked_key; | 478 | struct sw_flow_key masked_key; |
477 | 479 | ||
478 | ovs_flow_mask_key(&masked_key, unmasked, mask); | 480 | ovs_flow_mask_key(&masked_key, unmasked, false, mask); |
479 | hash = flow_hash(&masked_key, &mask->range); | 481 | hash = flow_hash(&masked_key, &mask->range); |
480 | head = find_bucket(ti, hash); | 482 | head = find_bucket(ti, hash); |
481 | hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) { | 483 | hlist_for_each_entry_rcu(flow, head, flow_table.node[ti->node_ver]) { |
diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h index 616eda10d955..2dd9900f533d 100644 --- a/net/openvswitch/flow_table.h +++ b/net/openvswitch/flow_table.h | |||
@@ -86,5 +86,5 @@ struct sw_flow *ovs_flow_tbl_lookup_ufid(struct flow_table *, | |||
86 | bool ovs_flow_cmp(const struct sw_flow *, const struct sw_flow_match *); | 86 | bool ovs_flow_cmp(const struct sw_flow *, const struct sw_flow_match *); |
87 | 87 | ||
88 | void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, | 88 | void ovs_flow_mask_key(struct sw_flow_key *dst, const struct sw_flow_key *src, |
89 | const struct sw_flow_mask *mask); | 89 | bool full, const struct sw_flow_mask *mask); |
90 | #endif /* flow_table.h */ | 90 | #endif /* flow_table.h */ |
diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index 2735e9c4a3b8..5f8aaaaa0785 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c | |||
@@ -52,18 +52,6 @@ static int geneve_get_options(const struct vport *vport, | |||
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
55 | static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, | ||
56 | struct dp_upcall_info *upcall) | ||
57 | { | ||
58 | struct geneve_port *geneve_port = geneve_vport(vport); | ||
59 | struct net *net = ovs_dp_get_net(vport->dp); | ||
60 | __be16 dport = htons(geneve_port->port_no); | ||
61 | __be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true); | ||
62 | |||
63 | return ovs_tunnel_get_egress_info(upcall, ovs_dp_get_net(vport->dp), | ||
64 | skb, IPPROTO_UDP, sport, dport); | ||
65 | } | ||
66 | |||
67 | static struct vport *geneve_tnl_create(const struct vport_parms *parms) | 55 | static struct vport *geneve_tnl_create(const struct vport_parms *parms) |
68 | { | 56 | { |
69 | struct net *net = ovs_dp_get_net(parms->dp); | 57 | struct net *net = ovs_dp_get_net(parms->dp); |
@@ -130,7 +118,6 @@ static struct vport_ops ovs_geneve_vport_ops = { | |||
130 | .get_options = geneve_get_options, | 118 | .get_options = geneve_get_options, |
131 | .send = ovs_netdev_send, | 119 | .send = ovs_netdev_send, |
132 | .owner = THIS_MODULE, | 120 | .owner = THIS_MODULE, |
133 | .get_egress_tun_info = geneve_get_egress_tun_info, | ||
134 | }; | 121 | }; |
135 | 122 | ||
136 | static int __init ovs_geneve_tnl_init(void) | 123 | static int __init ovs_geneve_tnl_init(void) |
diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index 4d24481669c9..64225bf5eb40 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c | |||
@@ -84,18 +84,10 @@ static struct vport *gre_create(const struct vport_parms *parms) | |||
84 | return ovs_netdev_link(vport, parms->name); | 84 | return ovs_netdev_link(vport, parms->name); |
85 | } | 85 | } |
86 | 86 | ||
87 | static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, | ||
88 | struct dp_upcall_info *upcall) | ||
89 | { | ||
90 | return ovs_tunnel_get_egress_info(upcall, ovs_dp_get_net(vport->dp), | ||
91 | skb, IPPROTO_GRE, 0, 0); | ||
92 | } | ||
93 | |||
94 | static struct vport_ops ovs_gre_vport_ops = { | 87 | static struct vport_ops ovs_gre_vport_ops = { |
95 | .type = OVS_VPORT_TYPE_GRE, | 88 | .type = OVS_VPORT_TYPE_GRE, |
96 | .create = gre_create, | 89 | .create = gre_create, |
97 | .send = ovs_netdev_send, | 90 | .send = ovs_netdev_send, |
98 | .get_egress_tun_info = gre_get_egress_tun_info, | ||
99 | .destroy = ovs_netdev_tunnel_destroy, | 91 | .destroy = ovs_netdev_tunnel_destroy, |
100 | .owner = THIS_MODULE, | 92 | .owner = THIS_MODULE, |
101 | }; | 93 | }; |
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 388b8a6bf112..b3934126daa8 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c | |||
@@ -106,12 +106,45 @@ static void internal_dev_destructor(struct net_device *dev) | |||
106 | free_netdev(dev); | 106 | free_netdev(dev); |
107 | } | 107 | } |
108 | 108 | ||
109 | static struct rtnl_link_stats64 * | ||
110 | internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats) | ||
111 | { | ||
112 | int i; | ||
113 | |||
114 | memset(stats, 0, sizeof(*stats)); | ||
115 | stats->rx_errors = dev->stats.rx_errors; | ||
116 | stats->tx_errors = dev->stats.tx_errors; | ||
117 | stats->tx_dropped = dev->stats.tx_dropped; | ||
118 | stats->rx_dropped = dev->stats.rx_dropped; | ||
119 | |||
120 | for_each_possible_cpu(i) { | ||
121 | const struct pcpu_sw_netstats *percpu_stats; | ||
122 | struct pcpu_sw_netstats local_stats; | ||
123 | unsigned int start; | ||
124 | |||
125 | percpu_stats = per_cpu_ptr(dev->tstats, i); | ||
126 | |||
127 | do { | ||
128 | start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); | ||
129 | local_stats = *percpu_stats; | ||
130 | } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start)); | ||
131 | |||
132 | stats->rx_bytes += local_stats.rx_bytes; | ||
133 | stats->rx_packets += local_stats.rx_packets; | ||
134 | stats->tx_bytes += local_stats.tx_bytes; | ||
135 | stats->tx_packets += local_stats.tx_packets; | ||
136 | } | ||
137 | |||
138 | return stats; | ||
139 | } | ||
140 | |||
109 | static const struct net_device_ops internal_dev_netdev_ops = { | 141 | static const struct net_device_ops internal_dev_netdev_ops = { |
110 | .ndo_open = internal_dev_open, | 142 | .ndo_open = internal_dev_open, |
111 | .ndo_stop = internal_dev_stop, | 143 | .ndo_stop = internal_dev_stop, |
112 | .ndo_start_xmit = internal_dev_xmit, | 144 | .ndo_start_xmit = internal_dev_xmit, |
113 | .ndo_set_mac_address = eth_mac_addr, | 145 | .ndo_set_mac_address = eth_mac_addr, |
114 | .ndo_change_mtu = internal_dev_change_mtu, | 146 | .ndo_change_mtu = internal_dev_change_mtu, |
147 | .ndo_get_stats64 = internal_get_stats, | ||
115 | }; | 148 | }; |
116 | 149 | ||
117 | static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { | 150 | static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { |
@@ -161,6 +194,11 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) | |||
161 | err = -ENOMEM; | 194 | err = -ENOMEM; |
162 | goto error_free_vport; | 195 | goto error_free_vport; |
163 | } | 196 | } |
197 | vport->dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); | ||
198 | if (!vport->dev->tstats) { | ||
199 | err = -ENOMEM; | ||
200 | goto error_free_netdev; | ||
201 | } | ||
164 | 202 | ||
165 | dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); | 203 | dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); |
166 | internal_dev = internal_dev_priv(vport->dev); | 204 | internal_dev = internal_dev_priv(vport->dev); |
@@ -173,7 +211,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) | |||
173 | rtnl_lock(); | 211 | rtnl_lock(); |
174 | err = register_netdevice(vport->dev); | 212 | err = register_netdevice(vport->dev); |
175 | if (err) | 213 | if (err) |
176 | goto error_free_netdev; | 214 | goto error_unlock; |
177 | 215 | ||
178 | dev_set_promiscuity(vport->dev, 1); | 216 | dev_set_promiscuity(vport->dev, 1); |
179 | rtnl_unlock(); | 217 | rtnl_unlock(); |
@@ -181,8 +219,10 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) | |||
181 | 219 | ||
182 | return vport; | 220 | return vport; |
183 | 221 | ||
184 | error_free_netdev: | 222 | error_unlock: |
185 | rtnl_unlock(); | 223 | rtnl_unlock(); |
224 | free_percpu(vport->dev->tstats); | ||
225 | error_free_netdev: | ||
186 | free_netdev(vport->dev); | 226 | free_netdev(vport->dev); |
187 | error_free_vport: | 227 | error_free_vport: |
188 | ovs_vport_free(vport); | 228 | ovs_vport_free(vport); |
@@ -198,7 +238,7 @@ static void internal_dev_destroy(struct vport *vport) | |||
198 | 238 | ||
199 | /* unregister_netdevice() waits for an RCU grace period. */ | 239 | /* unregister_netdevice() waits for an RCU grace period. */ |
200 | unregister_netdevice(vport->dev); | 240 | unregister_netdevice(vport->dev); |
201 | 241 | free_percpu(vport->dev->tstats); | |
202 | rtnl_unlock(); | 242 | rtnl_unlock(); |
203 | } | 243 | } |
204 | 244 | ||
diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index c11413d5075f..e1c9c0888037 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c | |||
@@ -146,31 +146,12 @@ static struct vport *vxlan_create(const struct vport_parms *parms) | |||
146 | return ovs_netdev_link(vport, parms->name); | 146 | return ovs_netdev_link(vport, parms->name); |
147 | } | 147 | } |
148 | 148 | ||
149 | static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, | ||
150 | struct dp_upcall_info *upcall) | ||
151 | { | ||
152 | struct vxlan_dev *vxlan = netdev_priv(vport->dev); | ||
153 | struct net *net = ovs_dp_get_net(vport->dp); | ||
154 | __be16 dst_port = vxlan_dev_dst_port(vxlan); | ||
155 | __be16 src_port; | ||
156 | int port_min; | ||
157 | int port_max; | ||
158 | |||
159 | inet_get_local_port_range(net, &port_min, &port_max); | ||
160 | src_port = udp_flow_src_port(net, skb, 0, 0, true); | ||
161 | |||
162 | return ovs_tunnel_get_egress_info(upcall, net, | ||
163 | skb, IPPROTO_UDP, | ||
164 | src_port, dst_port); | ||
165 | } | ||
166 | |||
167 | static struct vport_ops ovs_vxlan_netdev_vport_ops = { | 149 | static struct vport_ops ovs_vxlan_netdev_vport_ops = { |
168 | .type = OVS_VPORT_TYPE_VXLAN, | 150 | .type = OVS_VPORT_TYPE_VXLAN, |
169 | .create = vxlan_create, | 151 | .create = vxlan_create, |
170 | .destroy = ovs_netdev_tunnel_destroy, | 152 | .destroy = ovs_netdev_tunnel_destroy, |
171 | .get_options = vxlan_get_options, | 153 | .get_options = vxlan_get_options, |
172 | .send = ovs_netdev_send, | 154 | .send = ovs_netdev_send, |
173 | .get_egress_tun_info = vxlan_get_egress_tun_info, | ||
174 | }; | 155 | }; |
175 | 156 | ||
176 | static int __init ovs_vxlan_tnl_init(void) | 157 | static int __init ovs_vxlan_tnl_init(void) |
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index dc81dc619aa2..320c765ce44a 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c | |||
@@ -280,35 +280,19 @@ void ovs_vport_del(struct vport *vport) | |||
280 | */ | 280 | */ |
281 | void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) | 281 | void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) |
282 | { | 282 | { |
283 | struct net_device *dev = vport->dev; | 283 | const struct rtnl_link_stats64 *dev_stats; |
284 | int i; | 284 | struct rtnl_link_stats64 temp; |
285 | 285 | ||
286 | memset(stats, 0, sizeof(*stats)); | 286 | dev_stats = dev_get_stats(vport->dev, &temp); |
287 | stats->rx_errors = dev->stats.rx_errors; | 287 | stats->rx_errors = dev_stats->rx_errors; |
288 | stats->tx_errors = dev->stats.tx_errors; | 288 | stats->tx_errors = dev_stats->tx_errors; |
289 | stats->tx_dropped = dev->stats.tx_dropped; | 289 | stats->tx_dropped = dev_stats->tx_dropped; |
290 | stats->rx_dropped = dev->stats.rx_dropped; | 290 | stats->rx_dropped = dev_stats->rx_dropped; |
291 | 291 | ||
292 | stats->rx_dropped += atomic_long_read(&dev->rx_dropped); | 292 | stats->rx_bytes = dev_stats->rx_bytes; |
293 | stats->tx_dropped += atomic_long_read(&dev->tx_dropped); | 293 | stats->rx_packets = dev_stats->rx_packets; |
294 | 294 | stats->tx_bytes = dev_stats->tx_bytes; | |
295 | for_each_possible_cpu(i) { | 295 | stats->tx_packets = dev_stats->tx_packets; |
296 | const struct pcpu_sw_netstats *percpu_stats; | ||
297 | struct pcpu_sw_netstats local_stats; | ||
298 | unsigned int start; | ||
299 | |||
300 | percpu_stats = per_cpu_ptr(dev->tstats, i); | ||
301 | |||
302 | do { | ||
303 | start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); | ||
304 | local_stats = *percpu_stats; | ||
305 | } while (u64_stats_fetch_retry_irq(&percpu_stats->syncp, start)); | ||
306 | |||
307 | stats->rx_bytes += local_stats.rx_bytes; | ||
308 | stats->rx_packets += local_stats.rx_packets; | ||
309 | stats->tx_bytes += local_stats.tx_bytes; | ||
310 | stats->tx_packets += local_stats.tx_packets; | ||
311 | } | ||
312 | } | 296 | } |
313 | 297 | ||
314 | /** | 298 | /** |
@@ -460,6 +444,15 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb, | |||
460 | 444 | ||
461 | OVS_CB(skb)->input_vport = vport; | 445 | OVS_CB(skb)->input_vport = vport; |
462 | OVS_CB(skb)->mru = 0; | 446 | OVS_CB(skb)->mru = 0; |
447 | if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) { | ||
448 | u32 mark; | ||
449 | |||
450 | mark = skb->mark; | ||
451 | skb_scrub_packet(skb, true); | ||
452 | skb->mark = mark; | ||
453 | tun_info = NULL; | ||
454 | } | ||
455 | |||
463 | /* Extract flow from 'skb' into 'key'. */ | 456 | /* Extract flow from 'skb' into 'key'. */ |
464 | error = ovs_flow_key_extract(tun_info, skb, &key); | 457 | error = ovs_flow_key_extract(tun_info, skb, &key); |
465 | if (unlikely(error)) { | 458 | if (unlikely(error)) { |
@@ -486,61 +479,3 @@ void ovs_vport_deferred_free(struct vport *vport) | |||
486 | call_rcu(&vport->rcu, free_vport_rcu); | 479 | call_rcu(&vport->rcu, free_vport_rcu); |
487 | } | 480 | } |
488 | EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); | 481 | EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); |
489 | |||
490 | int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall, | ||
491 | struct net *net, | ||
492 | struct sk_buff *skb, | ||
493 | u8 ipproto, | ||
494 | __be16 tp_src, | ||
495 | __be16 tp_dst) | ||
496 | { | ||
497 | struct ip_tunnel_info *egress_tun_info = upcall->egress_tun_info; | ||
498 | const struct ip_tunnel_info *tun_info = skb_tunnel_info(skb); | ||
499 | const struct ip_tunnel_key *tun_key; | ||
500 | u32 skb_mark = skb->mark; | ||
501 | struct rtable *rt; | ||
502 | struct flowi4 fl; | ||
503 | |||
504 | if (unlikely(!tun_info)) | ||
505 | return -EINVAL; | ||
506 | if (ip_tunnel_info_af(tun_info) != AF_INET) | ||
507 | return -EINVAL; | ||
508 | |||
509 | tun_key = &tun_info->key; | ||
510 | |||
511 | /* Route lookup to get srouce IP address. | ||
512 | * The process may need to be changed if the corresponding process | ||
513 | * in vports ops changed. | ||
514 | */ | ||
515 | rt = ovs_tunnel_route_lookup(net, tun_key, skb_mark, &fl, ipproto); | ||
516 | if (IS_ERR(rt)) | ||
517 | return PTR_ERR(rt); | ||
518 | |||
519 | ip_rt_put(rt); | ||
520 | |||
521 | /* Generate egress_tun_info based on tun_info, | ||
522 | * saddr, tp_src and tp_dst | ||
523 | */ | ||
524 | ip_tunnel_key_init(&egress_tun_info->key, | ||
525 | fl.saddr, tun_key->u.ipv4.dst, | ||
526 | tun_key->tos, | ||
527 | tun_key->ttl, | ||
528 | tp_src, tp_dst, | ||
529 | tun_key->tun_id, | ||
530 | tun_key->tun_flags); | ||
531 | egress_tun_info->options_len = tun_info->options_len; | ||
532 | egress_tun_info->mode = tun_info->mode; | ||
533 | upcall->egress_tun_opts = ip_tunnel_info_opts(egress_tun_info); | ||
534 | return 0; | ||
535 | } | ||
536 | EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info); | ||
537 | |||
538 | int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, | ||
539 | struct dp_upcall_info *upcall) | ||
540 | { | ||
541 | /* get_egress_tun_info() is only implemented on tunnel ports. */ | ||
542 | if (unlikely(!vport->ops->get_egress_tun_info)) | ||
543 | return -EINVAL; | ||
544 | |||
545 | return vport->ops->get_egress_tun_info(vport, skb, upcall); | ||
546 | } | ||
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index a413f3ae6a7b..d341ad6f3afe 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
28 | #include <linux/spinlock.h> | 28 | #include <linux/spinlock.h> |
29 | #include <linux/u64_stats_sync.h> | 29 | #include <linux/u64_stats_sync.h> |
30 | #include <net/route.h> | ||
31 | 30 | ||
32 | #include "datapath.h" | 31 | #include "datapath.h" |
33 | 32 | ||
@@ -53,16 +52,6 @@ int ovs_vport_set_upcall_portids(struct vport *, const struct nlattr *pids); | |||
53 | int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); | 52 | int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); |
54 | u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); | 53 | u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); |
55 | 54 | ||
56 | int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall, | ||
57 | struct net *net, | ||
58 | struct sk_buff *, | ||
59 | u8 ipproto, | ||
60 | __be16 tp_src, | ||
61 | __be16 tp_dst); | ||
62 | |||
63 | int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, | ||
64 | struct dp_upcall_info *upcall); | ||
65 | |||
66 | /** | 55 | /** |
67 | * struct vport_portids - array of netlink portids of a vport. | 56 | * struct vport_portids - array of netlink portids of a vport. |
68 | * must be protected by rcu. | 57 | * must be protected by rcu. |
@@ -140,8 +129,6 @@ struct vport_parms { | |||
140 | * have any configuration. | 129 | * have any configuration. |
141 | * @send: Send a packet on the device. | 130 | * @send: Send a packet on the device. |
142 | * zero for dropped packets or negative for error. | 131 | * zero for dropped packets or negative for error. |
143 | * @get_egress_tun_info: Get the egress tunnel 5-tuple and other info for | ||
144 | * a packet. | ||
145 | */ | 132 | */ |
146 | struct vport_ops { | 133 | struct vport_ops { |
147 | enum ovs_vport_type type; | 134 | enum ovs_vport_type type; |
@@ -154,9 +141,6 @@ struct vport_ops { | |||
154 | int (*get_options)(const struct vport *, struct sk_buff *); | 141 | int (*get_options)(const struct vport *, struct sk_buff *); |
155 | 142 | ||
156 | void (*send)(struct vport *, struct sk_buff *); | 143 | void (*send)(struct vport *, struct sk_buff *); |
157 | int (*get_egress_tun_info)(struct vport *, struct sk_buff *, | ||
158 | struct dp_upcall_info *upcall); | ||
159 | |||
160 | struct module *owner; | 144 | struct module *owner; |
161 | struct list_head list; | 145 | struct list_head list; |
162 | }; | 146 | }; |
@@ -215,25 +199,6 @@ static inline const char *ovs_vport_name(struct vport *vport) | |||
215 | int ovs_vport_ops_register(struct vport_ops *ops); | 199 | int ovs_vport_ops_register(struct vport_ops *ops); |
216 | void ovs_vport_ops_unregister(struct vport_ops *ops); | 200 | void ovs_vport_ops_unregister(struct vport_ops *ops); |
217 | 201 | ||
218 | static inline struct rtable *ovs_tunnel_route_lookup(struct net *net, | ||
219 | const struct ip_tunnel_key *key, | ||
220 | u32 mark, | ||
221 | struct flowi4 *fl, | ||
222 | u8 protocol) | ||
223 | { | ||
224 | struct rtable *rt; | ||
225 | |||
226 | memset(fl, 0, sizeof(*fl)); | ||
227 | fl->daddr = key->u.ipv4.dst; | ||
228 | fl->saddr = key->u.ipv4.src; | ||
229 | fl->flowi4_tos = RT_TOS(key->tos); | ||
230 | fl->flowi4_mark = mark; | ||
231 | fl->flowi4_proto = protocol; | ||
232 | |||
233 | rt = ip_route_output_key(net, fl); | ||
234 | return rt; | ||
235 | } | ||
236 | |||
237 | static inline void ovs_vport_send(struct vport *vport, struct sk_buff *skb) | 202 | static inline void ovs_vport_send(struct vport *vport, struct sk_buff *skb) |
238 | { | 203 | { |
239 | vport->ops->send(vport, skb); | 204 | vport->ops->send(vport, skb); |