aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
Diffstat (limited to 'net/openvswitch')
-rw-r--r--net/openvswitch/actions.c9
-rw-r--r--net/openvswitch/conntrack.c24
-rw-r--r--net/openvswitch/conntrack.h16
-rw-r--r--net/openvswitch/datapath.c5
-rw-r--r--net/openvswitch/datapath.h1
-rw-r--r--net/openvswitch/flow_netlink.c26
-rw-r--r--net/openvswitch/flow_netlink.h6
-rw-r--r--net/openvswitch/vport-geneve.c13
-rw-r--r--net/openvswitch/vport-gre.c8
-rw-r--r--net/openvswitch/vport-internal_dev.c46
-rw-r--r--net/openvswitch/vport-vxlan.c20
-rw-r--r--net/openvswitch/vport.c58
-rw-r--r--net/openvswitch/vport.h16
13 files changed, 83 insertions, 165 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index c6087233d7fc..221fa8b37a47 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -769,7 +769,6 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
769 struct sw_flow_key *key, const struct nlattr *attr, 769 struct sw_flow_key *key, const struct nlattr *attr,
770 const struct nlattr *actions, int actions_len) 770 const struct nlattr *actions, int actions_len)
771{ 771{
772 struct ip_tunnel_info info;
773 struct dp_upcall_info upcall; 772 struct dp_upcall_info upcall;
774 const struct nlattr *a; 773 const struct nlattr *a;
775 int rem; 774 int rem;
@@ -797,11 +796,9 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
797 if (vport) { 796 if (vport) {
798 int err; 797 int err;
799 798
800 upcall.egress_tun_info = &info; 799 err = dev_fill_metadata_dst(vport->dev, skb);
801 err = ovs_vport_get_egress_tun_info(vport, skb, 800 if (!err)
802 &upcall); 801 upcall.egress_tun_info = skb_tunnel_info(skb);
803 if (err)
804 upcall.egress_tun_info = NULL;
805 } 802 }
806 803
807 break; 804 break;
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index 9ed833e9bb7d..bd165ee2bb16 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -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);
@@ -222,9 +224,6 @@ static int ovs_ct_set_labels(struct sk_buff *skb, struct sw_flow_key *key,
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)
@@ -377,7 +376,7 @@ static bool skb_nfct_cached(const struct net *net, const struct sk_buff *skb,
377 return true; 376 return true;
378} 377}
379 378
380static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key, 379static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
381 const struct ovs_conntrack_info *info, 380 const struct ovs_conntrack_info *info,
382 struct sk_buff *skb) 381 struct sk_buff *skb)
383{ 382{
@@ -408,6 +407,8 @@ static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key,
408 } 407 }
409 } 408 }
410 409
410 ovs_ct_update_key(skb, key, true);
411
411 return 0; 412 return 0;
412} 413}
413 414
@@ -430,8 +431,6 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
430 err = __ovs_ct_lookup(net, key, info, skb); 431 err = __ovs_ct_lookup(net, key, info, skb);
431 if (err) 432 if (err)
432 return err; 433 return err;
433
434 ovs_ct_update_key(skb, key, true);
435 } 434 }
436 435
437 return 0; 436 return 0;
@@ -460,8 +459,6 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
460 if (nf_conntrack_confirm(skb) != NF_ACCEPT) 459 if (nf_conntrack_confirm(skb) != NF_ACCEPT)
461 return -EINVAL; 460 return -EINVAL;
462 461
463 ovs_ct_update_key(skb, key, true);
464
465 return 0; 462 return 0;
466} 463}
467 464
@@ -587,6 +584,10 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
587 case OVS_CT_ATTR_MARK: { 584 case OVS_CT_ATTR_MARK: {
588 struct md_mark *mark = nla_data(a); 585 struct md_mark *mark = nla_data(a);
589 586
587 if (!mark->mask) {
588 OVS_NLERR(log, "ct_mark mask cannot be 0");
589 return -EINVAL;
590 }
590 info->mark = *mark; 591 info->mark = *mark;
591 break; 592 break;
592 } 593 }
@@ -595,6 +596,10 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
595 case OVS_CT_ATTR_LABELS: { 596 case OVS_CT_ATTR_LABELS: {
596 struct md_labels *labels = nla_data(a); 597 struct md_labels *labels = nla_data(a);
597 598
599 if (!labels_nonzero(&labels->mask)) {
600 OVS_NLERR(log, "ct_labels mask cannot be 0");
601 return -EINVAL;
602 }
598 info->labels = *labels; 603 info->labels = *labels;
599 break; 604 break;
600 } 605 }
@@ -705,11 +710,12 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
705 if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && 710 if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
706 nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) 711 nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))
707 return -EMSGSIZE; 712 return -EMSGSIZE;
708 if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && 713 if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && ct_info->mark.mask &&
709 nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), 714 nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark),
710 &ct_info->mark)) 715 &ct_info->mark))
711 return -EMSGSIZE; 716 return -EMSGSIZE;
712 if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && 717 if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) &&
718 labels_nonzero(&ct_info->labels.mask) &&
713 nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels), 719 nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels),
714 &ct_info->labels)) 720 &ct_info->labels))
715 return -EMSGSIZE; 721 return -EMSGSIZE;
diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h
index da8714942c95..82e0dfc66028 100644
--- a/net/openvswitch/conntrack.h
+++ b/net/openvswitch/conntrack.h
@@ -35,12 +35,9 @@ void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key);
35int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb); 35int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb);
36void ovs_ct_free_action(const struct nlattr *a); 36void ovs_ct_free_action(const struct nlattr *a);
37 37
38static inline bool ovs_ct_state_supported(u32 state) 38#define CT_SUPPORTED_MASK (OVS_CS_F_NEW | OVS_CS_F_ESTABLISHED | \
39{ 39 OVS_CS_F_RELATED | OVS_CS_F_REPLY_DIR | \
40 return !(state & ~(OVS_CS_F_NEW | OVS_CS_F_ESTABLISHED | 40 OVS_CS_F_INVALID | OVS_CS_F_TRACKED)
41 OVS_CS_F_RELATED | OVS_CS_F_REPLY_DIR |
42 OVS_CS_F_INVALID | OVS_CS_F_TRACKED));
43}
44#else 41#else
45#include <linux/errno.h> 42#include <linux/errno.h>
46 43
@@ -53,11 +50,6 @@ static inline bool ovs_ct_verify(struct net *net, int attr)
53 return false; 50 return false;
54} 51}
55 52
56static inline bool ovs_ct_state_supported(u32 state)
57{
58 return false;
59}
60
61static inline int ovs_ct_copy_action(struct net *net, const struct nlattr *nla, 53static inline int ovs_ct_copy_action(struct net *net, const struct nlattr *nla,
62 const struct sw_flow_key *key, 54 const struct sw_flow_key *key,
63 struct sw_flow_actions **acts, bool log) 55 struct sw_flow_actions **acts, bool log)
@@ -94,5 +86,7 @@ static inline int ovs_ct_put_key(const struct sw_flow_key *key,
94} 86}
95 87
96static inline void ovs_ct_free_action(const struct nlattr *a) { } 88static inline void ovs_ct_free_action(const struct nlattr *a) { }
89
90#define CT_SUPPORTED_MASK 0
97#endif /* CONFIG_NF_CONNTRACK */ 91#endif /* CONFIG_NF_CONNTRACK */
98#endif /* ovs_conntrack.h */ 92#endif /* ovs_conntrack.h */
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index a75828091e21..5633172b791a 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -489,9 +489,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
489 489
490 if (upcall_info->egress_tun_info) { 490 if (upcall_info->egress_tun_info) {
491 nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY); 491 nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
492 err = ovs_nla_put_egress_tunnel_key(user_skb, 492 err = ovs_nla_put_tunnel_info(user_skb,
493 upcall_info->egress_tun_info, 493 upcall_info->egress_tun_info);
494 upcall_info->egress_tun_opts);
495 BUG_ON(err); 494 BUG_ON(err);
496 nla_nest_end(user_skb, nla); 495 nla_nest_end(user_skb, nla);
497 } 496 }
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 */
118struct dp_upcall_info { 118struct 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_netlink.c b/net/openvswitch/flow_netlink.c
index 80e1f09397c0..907d6fd28ede 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -764,7 +764,7 @@ static int __ip_tun_to_nlattr(struct sk_buff *skb,
764 if ((output->tun_flags & TUNNEL_OAM) && 764 if ((output->tun_flags & TUNNEL_OAM) &&
765 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM)) 765 nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_OAM))
766 return -EMSGSIZE; 766 return -EMSGSIZE;
767 if (tun_opts) { 767 if (swkey_tun_opts_len) {
768 if (output->tun_flags & TUNNEL_GENEVE_OPT && 768 if (output->tun_flags & TUNNEL_GENEVE_OPT &&
769 nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, 769 nla_put(skb, OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS,
770 swkey_tun_opts_len, tun_opts)) 770 swkey_tun_opts_len, tun_opts))
@@ -798,14 +798,13 @@ static int ip_tun_to_nlattr(struct sk_buff *skb,
798 return 0; 798 return 0;
799} 799}
800 800
801int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb, 801int ovs_nla_put_tunnel_info(struct sk_buff *skb,
802 const struct ip_tunnel_info *egress_tun_info, 802 struct ip_tunnel_info *tun_info)
803 const void *egress_tun_opts)
804{ 803{
805 return __ip_tun_to_nlattr(skb, &egress_tun_info->key, 804 return __ip_tun_to_nlattr(skb, &tun_info->key,
806 egress_tun_opts, 805 ip_tunnel_info_opts(tun_info),
807 egress_tun_info->options_len, 806 tun_info->options_len,
808 ip_tunnel_info_af(egress_tun_info)); 807 ip_tunnel_info_af(tun_info));
809} 808}
810 809
811static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, 810static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
@@ -866,7 +865,7 @@ static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match,
866 ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) { 865 ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) {
867 u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]); 866 u32 ct_state = nla_get_u32(a[OVS_KEY_ATTR_CT_STATE]);
868 867
869 if (!is_mask && !ovs_ct_state_supported(ct_state)) { 868 if (ct_state & ~CT_SUPPORTED_MASK) {
870 OVS_NLERR(log, "ct_state flags %08x unsupported", 869 OVS_NLERR(log, "ct_state flags %08x unsupported",
871 ct_state); 870 ct_state);
872 return -EINVAL; 871 return -EINVAL;
@@ -1149,6 +1148,9 @@ static void nlattr_set(struct nlattr *attr, u8 val,
1149 } else { 1148 } else {
1150 memset(nla_data(nla), val, nla_len(nla)); 1149 memset(nla_data(nla), val, nla_len(nla));
1151 } 1150 }
1151
1152 if (nla_type(nla) == OVS_KEY_ATTR_CT_STATE)
1153 *(u32 *)nla_data(nla) &= CT_SUPPORTED_MASK;
1152 } 1154 }
1153} 1155}
1154 1156
@@ -2432,11 +2434,7 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
2432 if (!start) 2434 if (!start)
2433 return -EMSGSIZE; 2435 return -EMSGSIZE;
2434 2436
2435 err = ip_tun_to_nlattr(skb, &tun_info->key, 2437 err = ovs_nla_put_tunnel_info(skb, tun_info);
2436 tun_info->options_len ?
2437 ip_tunnel_info_opts(tun_info) : NULL,
2438 tun_info->options_len,
2439 ip_tunnel_info_af(tun_info));
2440 if (err) 2438 if (err)
2441 return err; 2439 return err;
2442 nla_nest_end(skb, start); 2440 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);
55int ovs_nla_get_match(struct net *, struct sw_flow_match *, 55int 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);
58int ovs_nla_put_egress_tunnel_key(struct sk_buff *, 58
59 const struct ip_tunnel_info *, 59int ovs_nla_put_tunnel_info(struct sk_buff *skb,
60 const void *egress_tun_opts); 60 struct ip_tunnel_info *tun_info);
61 61
62bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log); 62bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log);
63int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, 63int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid,
diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c
index 7a568ca8da54..efb736bb6855 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
55static 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
67static struct vport *geneve_tnl_create(const struct vport_parms *parms) 55static 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 = dev_queue_xmit, 119 .send = dev_queue_xmit,
132 .owner = THIS_MODULE, 120 .owner = THIS_MODULE,
133 .get_egress_tun_info = geneve_get_egress_tun_info,
134}; 121};
135 122
136static int __init ovs_geneve_tnl_init(void) 123static int __init ovs_geneve_tnl_init(void)
diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c
index cdb758ab01cf..c3257d78d3d2 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
87static 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
94static struct vport_ops ovs_gre_vport_ops = { 87static 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 = dev_queue_xmit, 90 .send = dev_queue_xmit,
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 7f0a8bd08857..ec76398a792f 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
109static struct rtnl_link_stats64 *
110internal_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
109static const struct net_device_ops internal_dev_netdev_ops = { 141static 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
117static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { 150static 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
184error_free_netdev: 222error_unlock:
185 rtnl_unlock(); 223 rtnl_unlock();
224 free_percpu(vport->dev->tstats);
225error_free_netdev:
186 free_netdev(vport->dev); 226 free_netdev(vport->dev);
187error_free_vport: 227error_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 6f700710d413..1605691d9414 100644
--- a/net/openvswitch/vport-vxlan.c
+++ b/net/openvswitch/vport-vxlan.c
@@ -146,32 +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
149static 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 unsigned short family = ip_tunnel_info_af(upcall->egress_tun_info);
155 __be16 dst_port = vxlan_dev_dst_port(vxlan, family);
156 __be16 src_port;
157 int port_min;
158 int port_max;
159
160 inet_get_local_port_range(net, &port_min, &port_max);
161 src_port = udp_flow_src_port(net, skb, 0, 0, true);
162
163 return ovs_tunnel_get_egress_info(upcall, net,
164 skb, IPPROTO_UDP,
165 src_port, dst_port);
166}
167
168static struct vport_ops ovs_vxlan_netdev_vport_ops = { 149static struct vport_ops ovs_vxlan_netdev_vport_ops = {
169 .type = OVS_VPORT_TYPE_VXLAN, 150 .type = OVS_VPORT_TYPE_VXLAN,
170 .create = vxlan_create, 151 .create = vxlan_create,
171 .destroy = ovs_netdev_tunnel_destroy, 152 .destroy = ovs_netdev_tunnel_destroy,
172 .get_options = vxlan_get_options, 153 .get_options = vxlan_get_options,
173 .send = dev_queue_xmit, 154 .send = dev_queue_xmit,
174 .get_egress_tun_info = vxlan_get_egress_tun_info,
175}; 155};
176 156
177static int __init ovs_vxlan_tnl_init(void) 157static int __init ovs_vxlan_tnl_init(void)
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index ef19d0b77d13..0ac0fd004d7e 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -480,64 +480,6 @@ void ovs_vport_deferred_free(struct vport *vport)
480} 480}
481EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); 481EXPORT_SYMBOL_GPL(ovs_vport_deferred_free);
482 482
483int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall,
484 struct net *net,
485 struct sk_buff *skb,
486 u8 ipproto,
487 __be16 tp_src,
488 __be16 tp_dst)
489{
490 struct ip_tunnel_info *egress_tun_info = upcall->egress_tun_info;
491 const struct ip_tunnel_info *tun_info = skb_tunnel_info(skb);
492 const struct ip_tunnel_key *tun_key;
493 u32 skb_mark = skb->mark;
494 struct rtable *rt;
495 struct flowi4 fl;
496
497 if (unlikely(!tun_info))
498 return -EINVAL;
499 if (ip_tunnel_info_af(tun_info) != AF_INET)
500 return -EINVAL;
501
502 tun_key = &tun_info->key;
503
504 /* Route lookup to get srouce IP address.
505 * The process may need to be changed if the corresponding process
506 * in vports ops changed.
507 */
508 rt = ovs_tunnel_route_lookup(net, tun_key, skb_mark, &fl, ipproto);
509 if (IS_ERR(rt))
510 return PTR_ERR(rt);
511
512 ip_rt_put(rt);
513
514 /* Generate egress_tun_info based on tun_info,
515 * saddr, tp_src and tp_dst
516 */
517 ip_tunnel_key_init(&egress_tun_info->key,
518 fl.saddr, tun_key->u.ipv4.dst,
519 tun_key->tos,
520 tun_key->ttl,
521 tp_src, tp_dst,
522 tun_key->tun_id,
523 tun_key->tun_flags);
524 egress_tun_info->options_len = tun_info->options_len;
525 egress_tun_info->mode = tun_info->mode;
526 upcall->egress_tun_opts = ip_tunnel_info_opts(egress_tun_info);
527 return 0;
528}
529EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info);
530
531int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
532 struct dp_upcall_info *upcall)
533{
534 /* get_egress_tun_info() is only implemented on tunnel ports. */
535 if (unlikely(!vport->ops->get_egress_tun_info))
536 return -EINVAL;
537
538 return vport->ops->get_egress_tun_info(vport, skb, upcall);
539}
540
541static unsigned int packet_length(const struct sk_buff *skb) 483static unsigned int packet_length(const struct sk_buff *skb)
542{ 484{
543 unsigned int length = skb->len - ETH_HLEN; 485 unsigned int length = skb->len - ETH_HLEN;
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index 885607f28d56..bdfd82a7c064 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);
53int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); 52int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *);
54u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); 53u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *);
55 54
56int 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
63int 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 */
146struct vport_ops { 133struct 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 netdev_tx_t (*send) (struct sk_buff *skb); 143 netdev_tx_t (*send) (struct sk_buff *skb);
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};