diff options
Diffstat (limited to 'net/openvswitch/vport-internal_dev.c')
-rw-r--r-- | net/openvswitch/vport-internal_dev.c | 46 |
1 files changed, 43 insertions, 3 deletions
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 | ||