aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2013-01-11 10:28:19 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-01-11 10:28:19 -0500
commit734d1ece37fbf3d2ddfc71bc6c69e0fe35f02542 (patch)
treec4805dd7e746b1feb9e09e9849f3245d0b2c0c6b /net/openvswitch
parent216c82c6aba63eeb49d7654b448e0d47bea255bb (diff)
parent9931faca02c604c22335f5a935a501bb2ace6e20 (diff)
Merge tag 'v3.8-rc3' into v4l_for_linus
Linux 3.8-rc3 * tag 'v3.8-rc3': (11110 commits) Linux 3.8-rc3 mm: reinstante dropped pmd_trans_splitting() check cred: Remove tgcred pointer from struct cred drm/ttm: fix fence locking in ttm_buffer_object_transfer ARM: clps711x: Fix bad merge of clockevents setup ARM: highbank: save and restore L2 cache and GIC on suspend ARM: highbank: add a power request clear ARM: highbank: fix secondary boot and hotplug ARM: highbank: fix typos with hignbank in power request functions ARM: dts: fix highbank cpu mpidr values ARM: dts: add device_type prop to cpu nodes on Calxeda platforms drm/prime: drop reference on imported dma-buf come from gem xen/netfront: improve truesize tracking ARM: mx5: Fix MX53 flexcan2 clock ARM: OMAP2+: am33xx-hwmod: Fix wrongly terminated am33xx_usbss_mpu_irqs array sctp: fix Kconfig bug in default cookie hmac selection EDAC: Cleanup device deregistering path EDAC: Fix EDAC Kconfig menu EDAC: Fix kernel panic on module unloading ALSA: hda - add mute LED for HP Pavilion 17 (Realtek codec) ...
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/actions.c97
-rw-r--r--net/openvswitch/datapath.c27
-rw-r--r--net/openvswitch/flow.c28
-rw-r--r--net/openvswitch/flow.h8
-rw-r--r--net/openvswitch/vport-netdev.c14
-rw-r--r--net/openvswitch/vport-netdev.h3
-rw-r--r--net/openvswitch/vport.c5
7 files changed, 166 insertions, 16 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 08114478cb85..ac2defeeba83 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -28,6 +28,7 @@
28#include <linux/if_arp.h> 28#include <linux/if_arp.h>
29#include <linux/if_vlan.h> 29#include <linux/if_vlan.h>
30#include <net/ip.h> 30#include <net/ip.h>
31#include <net/ipv6.h>
31#include <net/checksum.h> 32#include <net/checksum.h>
32#include <net/dsfield.h> 33#include <net/dsfield.h>
33 34
@@ -162,6 +163,53 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
162 *addr = new_addr; 163 *addr = new_addr;
163} 164}
164 165
166static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto,
167 __be32 addr[4], const __be32 new_addr[4])
168{
169 int transport_len = skb->len - skb_transport_offset(skb);
170
171 if (l4_proto == IPPROTO_TCP) {
172 if (likely(transport_len >= sizeof(struct tcphdr)))
173 inet_proto_csum_replace16(&tcp_hdr(skb)->check, skb,
174 addr, new_addr, 1);
175 } else if (l4_proto == IPPROTO_UDP) {
176 if (likely(transport_len >= sizeof(struct udphdr))) {
177 struct udphdr *uh = udp_hdr(skb);
178
179 if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
180 inet_proto_csum_replace16(&uh->check, skb,
181 addr, new_addr, 1);
182 if (!uh->check)
183 uh->check = CSUM_MANGLED_0;
184 }
185 }
186 }
187}
188
189static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto,
190 __be32 addr[4], const __be32 new_addr[4],
191 bool recalculate_csum)
192{
193 if (recalculate_csum)
194 update_ipv6_checksum(skb, l4_proto, addr, new_addr);
195
196 skb->rxhash = 0;
197 memcpy(addr, new_addr, sizeof(__be32[4]));
198}
199
200static void set_ipv6_tc(struct ipv6hdr *nh, u8 tc)
201{
202 nh->priority = tc >> 4;
203 nh->flow_lbl[0] = (nh->flow_lbl[0] & 0x0F) | ((tc & 0x0F) << 4);
204}
205
206static void set_ipv6_fl(struct ipv6hdr *nh, u32 fl)
207{
208 nh->flow_lbl[0] = (nh->flow_lbl[0] & 0xF0) | (fl & 0x000F0000) >> 16;
209 nh->flow_lbl[1] = (fl & 0x0000FF00) >> 8;
210 nh->flow_lbl[2] = fl & 0x000000FF;
211}
212
165static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl) 213static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl)
166{ 214{
167 csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8)); 215 csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8));
@@ -195,6 +243,47 @@ static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
195 return 0; 243 return 0;
196} 244}
197 245
246static int set_ipv6(struct sk_buff *skb, const struct ovs_key_ipv6 *ipv6_key)
247{
248 struct ipv6hdr *nh;
249 int err;
250 __be32 *saddr;
251 __be32 *daddr;
252
253 err = make_writable(skb, skb_network_offset(skb) +
254 sizeof(struct ipv6hdr));
255 if (unlikely(err))
256 return err;
257
258 nh = ipv6_hdr(skb);
259 saddr = (__be32 *)&nh->saddr;
260 daddr = (__be32 *)&nh->daddr;
261
262 if (memcmp(ipv6_key->ipv6_src, saddr, sizeof(ipv6_key->ipv6_src)))
263 set_ipv6_addr(skb, ipv6_key->ipv6_proto, saddr,
264 ipv6_key->ipv6_src, true);
265
266 if (memcmp(ipv6_key->ipv6_dst, daddr, sizeof(ipv6_key->ipv6_dst))) {
267 unsigned int offset = 0;
268 int flags = IP6_FH_F_SKIP_RH;
269 bool recalc_csum = true;
270
271 if (ipv6_ext_hdr(nh->nexthdr))
272 recalc_csum = ipv6_find_hdr(skb, &offset,
273 NEXTHDR_ROUTING, NULL,
274 &flags) != NEXTHDR_ROUTING;
275
276 set_ipv6_addr(skb, ipv6_key->ipv6_proto, daddr,
277 ipv6_key->ipv6_dst, recalc_csum);
278 }
279
280 set_ipv6_tc(nh, ipv6_key->ipv6_tclass);
281 set_ipv6_fl(nh, ntohl(ipv6_key->ipv6_label));
282 nh->hop_limit = ipv6_key->ipv6_hlimit;
283
284 return 0;
285}
286
198/* Must follow make_writable() since that can move the skb data. */ 287/* Must follow make_writable() since that can move the skb data. */
199static void set_tp_port(struct sk_buff *skb, __be16 *port, 288static void set_tp_port(struct sk_buff *skb, __be16 *port,
200 __be16 new_port, __sum16 *check) 289 __be16 new_port, __sum16 *check)
@@ -339,6 +428,10 @@ static int execute_set_action(struct sk_buff *skb,
339 skb->priority = nla_get_u32(nested_attr); 428 skb->priority = nla_get_u32(nested_attr);
340 break; 429 break;
341 430
431 case OVS_KEY_ATTR_SKB_MARK:
432 skb->mark = nla_get_u32(nested_attr);
433 break;
434
342 case OVS_KEY_ATTR_ETHERNET: 435 case OVS_KEY_ATTR_ETHERNET:
343 err = set_eth_addr(skb, nla_data(nested_attr)); 436 err = set_eth_addr(skb, nla_data(nested_attr));
344 break; 437 break;
@@ -347,6 +440,10 @@ static int execute_set_action(struct sk_buff *skb,
347 err = set_ipv4(skb, nla_data(nested_attr)); 440 err = set_ipv4(skb, nla_data(nested_attr));
348 break; 441 break;
349 442
443 case OVS_KEY_ATTR_IPV6:
444 err = set_ipv6(skb, nla_data(nested_attr));
445 break;
446
350 case OVS_KEY_ATTR_TCP: 447 case OVS_KEY_ATTR_TCP:
351 err = set_tcp(skb, nla_data(nested_attr)); 448 err = set_tcp(skb, nla_data(nested_attr));
352 break; 449 break;
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 4c4b62ccc7d7..f996db343247 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -208,7 +208,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
208 int error; 208 int error;
209 int key_len; 209 int key_len;
210 210
211 stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); 211 stats = this_cpu_ptr(dp->stats_percpu);
212 212
213 /* Extract flow from 'skb' into 'key'. */ 213 /* Extract flow from 'skb' into 'key'. */
214 error = ovs_flow_extract(skb, p->port_no, &key, &key_len); 214 error = ovs_flow_extract(skb, p->port_no, &key, &key_len);
@@ -282,7 +282,7 @@ int ovs_dp_upcall(struct datapath *dp, struct sk_buff *skb,
282 return 0; 282 return 0;
283 283
284err: 284err:
285 stats = per_cpu_ptr(dp->stats_percpu, smp_processor_id()); 285 stats = this_cpu_ptr(dp->stats_percpu);
286 286
287 u64_stats_update_begin(&stats->sync); 287 u64_stats_update_begin(&stats->sync);
288 stats->n_lost++; 288 stats->n_lost++;
@@ -479,8 +479,10 @@ static int validate_set(const struct nlattr *a,
479 479
480 switch (key_type) { 480 switch (key_type) {
481 const struct ovs_key_ipv4 *ipv4_key; 481 const struct ovs_key_ipv4 *ipv4_key;
482 const struct ovs_key_ipv6 *ipv6_key;
482 483
483 case OVS_KEY_ATTR_PRIORITY: 484 case OVS_KEY_ATTR_PRIORITY:
485 case OVS_KEY_ATTR_SKB_MARK:
484 case OVS_KEY_ATTR_ETHERNET: 486 case OVS_KEY_ATTR_ETHERNET:
485 break; 487 break;
486 488
@@ -500,6 +502,25 @@ static int validate_set(const struct nlattr *a,
500 502
501 break; 503 break;
502 504
505 case OVS_KEY_ATTR_IPV6:
506 if (flow_key->eth.type != htons(ETH_P_IPV6))
507 return -EINVAL;
508
509 if (!flow_key->ip.proto)
510 return -EINVAL;
511
512 ipv6_key = nla_data(ovs_key);
513 if (ipv6_key->ipv6_proto != flow_key->ip.proto)
514 return -EINVAL;
515
516 if (ipv6_key->ipv6_frag != flow_key->ip.frag)
517 return -EINVAL;
518
519 if (ntohl(ipv6_key->ipv6_label) & 0xFFF00000)
520 return -EINVAL;
521
522 break;
523
503 case OVS_KEY_ATTR_TCP: 524 case OVS_KEY_ATTR_TCP:
504 if (flow_key->ip.proto != IPPROTO_TCP) 525 if (flow_key->ip.proto != IPPROTO_TCP)
505 return -EINVAL; 526 return -EINVAL;
@@ -675,6 +696,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
675 goto err_flow_free; 696 goto err_flow_free;
676 697
677 err = ovs_flow_metadata_from_nlattrs(&flow->key.phy.priority, 698 err = ovs_flow_metadata_from_nlattrs(&flow->key.phy.priority,
699 &flow->key.phy.skb_mark,
678 &flow->key.phy.in_port, 700 &flow->key.phy.in_port,
679 a[OVS_PACKET_ATTR_KEY]); 701 a[OVS_PACKET_ATTR_KEY]);
680 if (err) 702 if (err)
@@ -694,6 +716,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
694 716
695 OVS_CB(packet)->flow = flow; 717 OVS_CB(packet)->flow = flow;
696 packet->priority = flow->key.phy.priority; 718 packet->priority = flow->key.phy.priority;
719 packet->mark = flow->key.phy.skb_mark;
697 720
698 rcu_read_lock(); 721 rcu_read_lock();
699 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); 722 dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 733cbf49ed1f..c3294cebc4f2 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -604,6 +604,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
604 604
605 key->phy.priority = skb->priority; 605 key->phy.priority = skb->priority;
606 key->phy.in_port = in_port; 606 key->phy.in_port = in_port;
607 key->phy.skb_mark = skb->mark;
607 608
608 skb_reset_mac_header(skb); 609 skb_reset_mac_header(skb);
609 610
@@ -689,7 +690,8 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
689 } 690 }
690 } 691 }
691 692
692 } else if (key->eth.type == htons(ETH_P_ARP) && arphdr_ok(skb)) { 693 } else if ((key->eth.type == htons(ETH_P_ARP) ||
694 key->eth.type == htons(ETH_P_RARP)) && arphdr_ok(skb)) {
693 struct arp_eth_header *arp; 695 struct arp_eth_header *arp;
694 696
695 arp = (struct arp_eth_header *)skb_network_header(skb); 697 arp = (struct arp_eth_header *)skb_network_header(skb);
@@ -802,6 +804,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
802 [OVS_KEY_ATTR_ENCAP] = -1, 804 [OVS_KEY_ATTR_ENCAP] = -1,
803 [OVS_KEY_ATTR_PRIORITY] = sizeof(u32), 805 [OVS_KEY_ATTR_PRIORITY] = sizeof(u32),
804 [OVS_KEY_ATTR_IN_PORT] = sizeof(u32), 806 [OVS_KEY_ATTR_IN_PORT] = sizeof(u32),
807 [OVS_KEY_ATTR_SKB_MARK] = sizeof(u32),
805 [OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet), 808 [OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet),
806 [OVS_KEY_ATTR_VLAN] = sizeof(__be16), 809 [OVS_KEY_ATTR_VLAN] = sizeof(__be16),
807 [OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16), 810 [OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16),
@@ -987,6 +990,10 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
987 } else { 990 } else {
988 swkey->phy.in_port = DP_MAX_PORTS; 991 swkey->phy.in_port = DP_MAX_PORTS;
989 } 992 }
993 if (attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) {
994 swkey->phy.skb_mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]);
995 attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);
996 }
990 997
991 /* Data attributes. */ 998 /* Data attributes. */
992 if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET))) 999 if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET)))
@@ -1086,7 +1093,8 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
1086 if (err) 1093 if (err)
1087 return err; 1094 return err;
1088 } 1095 }
1089 } else if (swkey->eth.type == htons(ETH_P_ARP)) { 1096 } else if (swkey->eth.type == htons(ETH_P_ARP) ||
1097 swkey->eth.type == htons(ETH_P_RARP)) {
1090 const struct ovs_key_arp *arp_key; 1098 const struct ovs_key_arp *arp_key;
1091 1099
1092 if (!(attrs & (1 << OVS_KEY_ATTR_ARP))) 1100 if (!(attrs & (1 << OVS_KEY_ATTR_ARP)))
@@ -1113,6 +1121,8 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
1113 1121
1114/** 1122/**
1115 * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key. 1123 * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key.
1124 * @priority: receives the skb priority
1125 * @mark: receives the skb mark
1116 * @in_port: receives the extracted input port. 1126 * @in_port: receives the extracted input port.
1117 * @key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute 1127 * @key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
1118 * sequence. 1128 * sequence.
@@ -1122,7 +1132,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
1122 * get the metadata, that is, the parts of the flow key that cannot be 1132 * get the metadata, that is, the parts of the flow key that cannot be
1123 * extracted from the packet itself. 1133 * extracted from the packet itself.
1124 */ 1134 */
1125int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, 1135int ovs_flow_metadata_from_nlattrs(u32 *priority, u32 *mark, u16 *in_port,
1126 const struct nlattr *attr) 1136 const struct nlattr *attr)
1127{ 1137{
1128 const struct nlattr *nla; 1138 const struct nlattr *nla;
@@ -1130,6 +1140,7 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port,
1130 1140
1131 *in_port = DP_MAX_PORTS; 1141 *in_port = DP_MAX_PORTS;
1132 *priority = 0; 1142 *priority = 0;
1143 *mark = 0;
1133 1144
1134 nla_for_each_nested(nla, attr, rem) { 1145 nla_for_each_nested(nla, attr, rem) {
1135 int type = nla_type(nla); 1146 int type = nla_type(nla);
@@ -1148,6 +1159,10 @@ int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port,
1148 return -EINVAL; 1159 return -EINVAL;
1149 *in_port = nla_get_u32(nla); 1160 *in_port = nla_get_u32(nla);
1150 break; 1161 break;
1162
1163 case OVS_KEY_ATTR_SKB_MARK:
1164 *mark = nla_get_u32(nla);
1165 break;
1151 } 1166 }
1152 } 1167 }
1153 } 1168 }
@@ -1169,6 +1184,10 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
1169 nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port)) 1184 nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port))
1170 goto nla_put_failure; 1185 goto nla_put_failure;
1171 1186
1187 if (swkey->phy.skb_mark &&
1188 nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, swkey->phy.skb_mark))
1189 goto nla_put_failure;
1190
1172 nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key)); 1191 nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
1173 if (!nla) 1192 if (!nla)
1174 goto nla_put_failure; 1193 goto nla_put_failure;
@@ -1222,7 +1241,8 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
1222 ipv6_key->ipv6_tclass = swkey->ip.tos; 1241 ipv6_key->ipv6_tclass = swkey->ip.tos;
1223 ipv6_key->ipv6_hlimit = swkey->ip.ttl; 1242 ipv6_key->ipv6_hlimit = swkey->ip.ttl;
1224 ipv6_key->ipv6_frag = swkey->ip.frag; 1243 ipv6_key->ipv6_frag = swkey->ip.frag;
1225 } else if (swkey->eth.type == htons(ETH_P_ARP)) { 1244 } else if (swkey->eth.type == htons(ETH_P_ARP) ||
1245 swkey->eth.type == htons(ETH_P_RARP)) {
1226 struct ovs_key_arp *arp_key; 1246 struct ovs_key_arp *arp_key;
1227 1247
1228 nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key)); 1248 nla = nla_reserve(skb, OVS_KEY_ATTR_ARP, sizeof(*arp_key));
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index 14a324eb017b..a7bb60ff3b5b 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -43,6 +43,7 @@ struct sw_flow_actions {
43struct sw_flow_key { 43struct sw_flow_key {
44 struct { 44 struct {
45 u32 priority; /* Packet QoS priority. */ 45 u32 priority; /* Packet QoS priority. */
46 u32 skb_mark; /* SKB mark. */
46 u16 in_port; /* Input switch port (or DP_MAX_PORTS). */ 47 u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
47 } phy; 48 } phy;
48 struct { 49 struct {
@@ -144,6 +145,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
144 * ------ --- ------ ----- 145 * ------ --- ------ -----
145 * OVS_KEY_ATTR_PRIORITY 4 -- 4 8 146 * OVS_KEY_ATTR_PRIORITY 4 -- 4 8
146 * OVS_KEY_ATTR_IN_PORT 4 -- 4 8 147 * OVS_KEY_ATTR_IN_PORT 4 -- 4 8
148 * OVS_KEY_ATTR_SKB_MARK 4 -- 4 8
147 * OVS_KEY_ATTR_ETHERNET 12 -- 4 16 149 * OVS_KEY_ATTR_ETHERNET 12 -- 4 16
148 * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype) 150 * OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype)
149 * OVS_KEY_ATTR_8021Q 4 -- 4 8 151 * OVS_KEY_ATTR_8021Q 4 -- 4 8
@@ -153,14 +155,14 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
153 * OVS_KEY_ATTR_ICMPV6 2 2 4 8 155 * OVS_KEY_ATTR_ICMPV6 2 2 4 8
154 * OVS_KEY_ATTR_ND 28 -- 4 32 156 * OVS_KEY_ATTR_ND 28 -- 4 32
155 * ------------------------------------------------- 157 * -------------------------------------------------
156 * total 144 158 * total 152
157 */ 159 */
158#define FLOW_BUFSIZE 144 160#define FLOW_BUFSIZE 152
159 161
160int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); 162int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
161int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, 163int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
162 const struct nlattr *); 164 const struct nlattr *);
163int ovs_flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, 165int ovs_flow_metadata_from_nlattrs(u32 *priority, u32 *mark, u16 *in_port,
164 const struct nlattr *); 166 const struct nlattr *);
165 167
166#define MAX_ACTIONS_BUFSIZE (16 * 1024) 168#define MAX_ACTIONS_BUFSIZE (16 * 1024)
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c
index a9033481fa5e..a9327e2e48ce 100644
--- a/net/openvswitch/vport-netdev.c
+++ b/net/openvswitch/vport-netdev.c
@@ -114,6 +114,15 @@ error:
114 return ERR_PTR(err); 114 return ERR_PTR(err);
115} 115}
116 116
117static void free_port_rcu(struct rcu_head *rcu)
118{
119 struct netdev_vport *netdev_vport = container_of(rcu,
120 struct netdev_vport, rcu);
121
122 dev_put(netdev_vport->dev);
123 ovs_vport_free(vport_from_priv(netdev_vport));
124}
125
117static void netdev_destroy(struct vport *vport) 126static void netdev_destroy(struct vport *vport)
118{ 127{
119 struct netdev_vport *netdev_vport = netdev_vport_priv(vport); 128 struct netdev_vport *netdev_vport = netdev_vport_priv(vport);
@@ -122,10 +131,7 @@ static void netdev_destroy(struct vport *vport)
122 netdev_rx_handler_unregister(netdev_vport->dev); 131 netdev_rx_handler_unregister(netdev_vport->dev);
123 dev_set_promiscuity(netdev_vport->dev, -1); 132 dev_set_promiscuity(netdev_vport->dev, -1);
124 133
125 synchronize_rcu(); 134 call_rcu(&netdev_vport->rcu, free_port_rcu);
126
127 dev_put(netdev_vport->dev);
128 ovs_vport_free(vport);
129} 135}
130 136
131const char *ovs_netdev_get_name(const struct vport *vport) 137const char *ovs_netdev_get_name(const struct vport *vport)
diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h
index f7072a25c604..6478079b3417 100644
--- a/net/openvswitch/vport-netdev.h
+++ b/net/openvswitch/vport-netdev.h
@@ -20,12 +20,15 @@
20#define VPORT_NETDEV_H 1 20#define VPORT_NETDEV_H 1
21 21
22#include <linux/netdevice.h> 22#include <linux/netdevice.h>
23#include <linux/rcupdate.h>
23 24
24#include "vport.h" 25#include "vport.h"
25 26
26struct vport *ovs_netdev_get_vport(struct net_device *dev); 27struct vport *ovs_netdev_get_vport(struct net_device *dev);
27 28
28struct netdev_vport { 29struct netdev_vport {
30 struct rcu_head rcu;
31
29 struct net_device *dev; 32 struct net_device *dev;
30}; 33};
31 34
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 03779e8a2622..70af0bedbac4 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -333,8 +333,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)
333{ 333{
334 struct vport_percpu_stats *stats; 334 struct vport_percpu_stats *stats;
335 335
336 stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); 336 stats = this_cpu_ptr(vport->percpu_stats);
337
338 u64_stats_update_begin(&stats->sync); 337 u64_stats_update_begin(&stats->sync);
339 stats->rx_packets++; 338 stats->rx_packets++;
340 stats->rx_bytes += skb->len; 339 stats->rx_bytes += skb->len;
@@ -359,7 +358,7 @@ int ovs_vport_send(struct vport *vport, struct sk_buff *skb)
359 if (likely(sent)) { 358 if (likely(sent)) {
360 struct vport_percpu_stats *stats; 359 struct vport_percpu_stats *stats;
361 360
362 stats = per_cpu_ptr(vport->percpu_stats, smp_processor_id()); 361 stats = this_cpu_ptr(vport->percpu_stats);
363 362
364 u64_stats_update_begin(&stats->sync); 363 u64_stats_update_begin(&stats->sync);
365 stats->tx_packets++; 364 stats->tx_packets++;