Blame view
drivers/net/veth.c
9.52 KB
e314dbdc1 [NET]: Virtual et... |
1 2 3 4 5 6 7 8 9 |
/* * drivers/net/veth.c * * Copyright (C) 2007 OpenVZ http://openvz.org, SWsoft Inc * * Author: Pavel Emelianov <xemul@openvz.org> * Ethtool interface from: Eric W. Biederman <ebiederm@xmission.com> * */ |
e314dbdc1 [NET]: Virtual et... |
10 |
#include <linux/netdevice.h> |
5a0e3ad6a include cleanup: ... |
11 |
#include <linux/slab.h> |
e314dbdc1 [NET]: Virtual et... |
12 13 |
#include <linux/ethtool.h> #include <linux/etherdevice.h> |
cf05c700c veth: fix 64bit s... |
14 |
#include <linux/u64_stats_sync.h> |
e314dbdc1 [NET]: Virtual et... |
15 16 17 |
#include <net/dst.h> #include <net/xfrm.h> |
ecef969e5 [VETH]: move veth... |
18 |
#include <linux/veth.h> |
9d9779e72 drivers/net: Add ... |
19 |
#include <linux/module.h> |
e314dbdc1 [NET]: Virtual et... |
20 21 22 |
#define DRV_NAME "veth" #define DRV_VERSION "1.0" |
38d408152 veth: Allow setti... |
23 24 |
#define MIN_MTU 68 /* Min L3 MTU */ #define MAX_MTU 65535 /* Max L3 MTU (arbitrary) */ |
38d408152 veth: Allow setti... |
25 |
|
e314dbdc1 [NET]: Virtual et... |
26 |
struct veth_net_stats { |
cf05c700c veth: fix 64bit s... |
27 |
u64 rx_packets; |
cf05c700c veth: fix 64bit s... |
28 |
u64 rx_bytes; |
8ce120f11 net: better pcpu ... |
29 |
u64 tx_packets; |
cf05c700c veth: fix 64bit s... |
30 31 |
u64 tx_bytes; u64 rx_dropped; |
cf05c700c veth: fix 64bit s... |
32 |
struct u64_stats_sync syncp; |
e314dbdc1 [NET]: Virtual et... |
33 34 35 36 |
}; struct veth_priv { struct net_device *peer; |
47d742752 percpu: add __per... |
37 |
struct veth_net_stats __percpu *stats; |
e314dbdc1 [NET]: Virtual et... |
38 |
}; |
e314dbdc1 [NET]: Virtual et... |
39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
/* * ethtool interface */ static struct { const char string[ETH_GSTRING_LEN]; } ethtool_stats_keys[] = { { "peer_ifindex" }, }; static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = 0; cmd->advertising = 0; |
707394972 ethtool: cosmetic... |
53 |
ethtool_cmd_speed_set(cmd, SPEED_10000); |
e314dbdc1 [NET]: Virtual et... |
54 55 56 57 58 59 60 61 62 63 64 65 |
cmd->duplex = DUPLEX_FULL; cmd->port = PORT_TP; cmd->phy_address = 0; cmd->transceiver = XCVR_INTERNAL; cmd->autoneg = AUTONEG_DISABLE; cmd->maxtxpkt = 0; cmd->maxrxpkt = 0; return 0; } static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { |
33a5ba144 net: sweep-up som... |
66 67 |
strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); |
e314dbdc1 [NET]: Virtual et... |
68 69 70 71 72 73 74 75 76 77 |
} static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf) { switch(stringset) { case ETH_SS_STATS: memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); break; } } |
b9f2c0440 [netdrvr] Stop us... |
78 |
static int veth_get_sset_count(struct net_device *dev, int sset) |
e314dbdc1 [NET]: Virtual et... |
79 |
{ |
b9f2c0440 [netdrvr] Stop us... |
80 81 82 83 84 85 |
switch (sset) { case ETH_SS_STATS: return ARRAY_SIZE(ethtool_stats_keys); default: return -EOPNOTSUPP; } |
e314dbdc1 [NET]: Virtual et... |
86 87 88 89 90 91 92 93 94 95 |
} static void veth_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { struct veth_priv *priv; priv = netdev_priv(dev); data[0] = priv->peer->ifindex; } |
0fc0b732e netdev: drivers s... |
96 |
static const struct ethtool_ops veth_ethtool_ops = { |
e314dbdc1 [NET]: Virtual et... |
97 98 99 |
.get_settings = veth_get_settings, .get_drvinfo = veth_get_drvinfo, .get_link = ethtool_op_get_link, |
e314dbdc1 [NET]: Virtual et... |
100 |
.get_strings = veth_get_strings, |
b9f2c0440 [netdrvr] Stop us... |
101 |
.get_sset_count = veth_get_sset_count, |
e314dbdc1 [NET]: Virtual et... |
102 103 104 105 106 107 |
.get_ethtool_stats = veth_get_ethtool_stats, }; /* * xmit */ |
424efe9ca netdev: convert p... |
108 |
static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) |
e314dbdc1 [NET]: Virtual et... |
109 110 111 |
{ struct net_device *rcv = NULL; struct veth_priv *priv, *rcv_priv; |
38d408152 veth: Allow setti... |
112 |
struct veth_net_stats *stats, *rcv_stats; |
e7dcaa475 this_cpu: Elimina... |
113 |
int length; |
e314dbdc1 [NET]: Virtual et... |
114 |
|
e314dbdc1 [NET]: Virtual et... |
115 116 117 |
priv = netdev_priv(dev); rcv = priv->peer; rcv_priv = netdev_priv(rcv); |
e7dcaa475 this_cpu: Elimina... |
118 119 |
stats = this_cpu_ptr(priv->stats); rcv_stats = this_cpu_ptr(rcv_priv->stats); |
e314dbdc1 [NET]: Virtual et... |
120 |
|
0b7967503 net/veth: Fix pac... |
121 122 |
/* don't change ip_summed == CHECKSUM_PARTIAL, as that will cause bad checksum on forwarded packets */ |
a2c725fa3 veth: convert to ... |
123 124 125 |
if (skb->ip_summed == CHECKSUM_NONE && rcv->features & NETIF_F_RXCSUM) skb->ip_summed = CHECKSUM_UNNECESSARY; |
e314dbdc1 [NET]: Virtual et... |
126 |
|
675071a2e veth: Fix the byt... |
127 |
length = skb->len; |
445409602 veth: move loopba... |
128 129 |
if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS) goto rx_drop; |
e314dbdc1 [NET]: Virtual et... |
130 |
|
cf05c700c veth: fix 64bit s... |
131 |
u64_stats_update_begin(&stats->syncp); |
e314dbdc1 [NET]: Virtual et... |
132 133 |
stats->tx_bytes += length; stats->tx_packets++; |
cf05c700c veth: fix 64bit s... |
134 |
u64_stats_update_end(&stats->syncp); |
e314dbdc1 [NET]: Virtual et... |
135 |
|
cf05c700c veth: fix 64bit s... |
136 |
u64_stats_update_begin(&rcv_stats->syncp); |
38d408152 veth: Allow setti... |
137 138 |
rcv_stats->rx_bytes += length; rcv_stats->rx_packets++; |
cf05c700c veth: fix 64bit s... |
139 |
u64_stats_update_end(&rcv_stats->syncp); |
e314dbdc1 [NET]: Virtual et... |
140 |
|
6ed106549 net: use NETDEV_T... |
141 |
return NETDEV_TX_OK; |
e314dbdc1 [NET]: Virtual et... |
142 |
|
38d408152 veth: Allow setti... |
143 |
rx_drop: |
cf05c700c veth: fix 64bit s... |
144 |
u64_stats_update_begin(&rcv_stats->syncp); |
38d408152 veth: Allow setti... |
145 |
rcv_stats->rx_dropped++; |
cf05c700c veth: fix 64bit s... |
146 |
u64_stats_update_end(&rcv_stats->syncp); |
6ed106549 net: use NETDEV_T... |
147 |
return NETDEV_TX_OK; |
e314dbdc1 [NET]: Virtual et... |
148 149 150 151 152 |
} /* * general routines */ |
6311cc44a veth: convert to ... |
153 154 |
static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *tot) |
e314dbdc1 [NET]: Virtual et... |
155 |
{ |
cf05c700c veth: fix 64bit s... |
156 |
struct veth_priv *priv = netdev_priv(dev); |
11687a109 Revert "veth: pre... |
157 |
int cpu; |
e314dbdc1 [NET]: Virtual et... |
158 |
|
2b1c8b0f9 veth: Fix veth_ge... |
159 |
for_each_possible_cpu(cpu) { |
cf05c700c veth: fix 64bit s... |
160 161 |
struct veth_net_stats *stats = per_cpu_ptr(priv->stats, cpu); u64 rx_packets, rx_bytes, rx_dropped; |
81b16ba2f veth: Kill unused... |
162 |
u64 tx_packets, tx_bytes; |
cf05c700c veth: fix 64bit s... |
163 164 165 166 167 168 169 170 171 |
unsigned int start; do { start = u64_stats_fetch_begin_bh(&stats->syncp); rx_packets = stats->rx_packets; tx_packets = stats->tx_packets; rx_bytes = stats->rx_bytes; tx_bytes = stats->tx_bytes; rx_dropped = stats->rx_dropped; |
cf05c700c veth: fix 64bit s... |
172 173 174 175 176 177 |
} while (u64_stats_fetch_retry_bh(&stats->syncp, start)); tot->rx_packets += rx_packets; tot->tx_packets += tx_packets; tot->rx_bytes += rx_bytes; tot->tx_bytes += tx_bytes; tot->rx_dropped += rx_dropped; |
11687a109 Revert "veth: pre... |
178 |
} |
6311cc44a veth: convert to ... |
179 180 |
return tot; |
e314dbdc1 [NET]: Virtual et... |
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
} static int veth_open(struct net_device *dev) { struct veth_priv *priv; priv = netdev_priv(dev); if (priv->peer == NULL) return -ENOTCONN; if (priv->peer->flags & IFF_UP) { netif_carrier_on(dev); netif_carrier_on(priv->peer); } return 0; } |
2cf48a10a veth: Fix carrier... |
197 198 199 200 201 202 203 204 205 |
static int veth_close(struct net_device *dev) { struct veth_priv *priv = netdev_priv(dev); netif_carrier_off(dev); netif_carrier_off(priv->peer); return 0; } |
38d408152 veth: Allow setti... |
206 207 |
static int is_valid_veth_mtu(int new_mtu) { |
807540baa drivers/net: retu... |
208 |
return new_mtu >= MIN_MTU && new_mtu <= MAX_MTU; |
38d408152 veth: Allow setti... |
209 210 211 212 213 214 215 216 217 |
} static int veth_change_mtu(struct net_device *dev, int new_mtu) { if (!is_valid_veth_mtu(new_mtu)) return -EINVAL; dev->mtu = new_mtu; return 0; } |
e314dbdc1 [NET]: Virtual et... |
218 219 |
static int veth_dev_init(struct net_device *dev) { |
47d742752 percpu: add __per... |
220 |
struct veth_net_stats __percpu *stats; |
e314dbdc1 [NET]: Virtual et... |
221 222 223 224 225 226 227 228 229 230 |
struct veth_priv *priv; stats = alloc_percpu(struct veth_net_stats); if (stats == NULL) return -ENOMEM; priv = netdev_priv(dev); priv->stats = stats; return 0; } |
11687a109 Revert "veth: pre... |
231 232 233 234 235 236 237 238 |
static void veth_dev_free(struct net_device *dev) { struct veth_priv *priv; priv = netdev_priv(dev); free_percpu(priv->stats); free_netdev(dev); } |
4456e7bdf veth: convert to ... |
239 |
static const struct net_device_ops veth_netdev_ops = { |
ee9236231 veth : add the se... |
240 241 |
.ndo_init = veth_dev_init, .ndo_open = veth_open, |
2cf48a10a veth: Fix carrier... |
242 |
.ndo_stop = veth_close, |
ee9236231 veth : add the se... |
243 |
.ndo_start_xmit = veth_xmit, |
38d408152 veth: Allow setti... |
244 |
.ndo_change_mtu = veth_change_mtu, |
6311cc44a veth: convert to ... |
245 |
.ndo_get_stats64 = veth_get_stats64, |
ee9236231 veth : add the se... |
246 |
.ndo_set_mac_address = eth_mac_addr, |
4456e7bdf veth: convert to ... |
247 |
}; |
e314dbdc1 [NET]: Virtual et... |
248 249 250 |
static void veth_setup(struct net_device *dev) { ether_setup(dev); |
550fd08c2 net: Audit driver... |
251 |
dev->priv_flags &= ~IFF_TX_SKB_SHARING; |
4456e7bdf veth: convert to ... |
252 |
dev->netdev_ops = &veth_netdev_ops; |
e314dbdc1 [NET]: Virtual et... |
253 254 |
dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; |
11687a109 Revert "veth: pre... |
255 |
dev->destructor = veth_dev_free; |
a2c725fa3 veth: convert to ... |
256 |
|
34324dc2b net: remove NETIF... |
257 |
dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_RXCSUM; |
e314dbdc1 [NET]: Virtual et... |
258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
} /* * netlink interface */ static int veth_validate(struct nlattr *tb[], struct nlattr *data[]) { if (tb[IFLA_ADDRESS]) { if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) return -EINVAL; if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) return -EADDRNOTAVAIL; } |
38d408152 veth: Allow setti... |
272 273 274 275 |
if (tb[IFLA_MTU]) { if (!is_valid_veth_mtu(nla_get_u32(tb[IFLA_MTU]))) return -EINVAL; } |
e314dbdc1 [NET]: Virtual et... |
276 277 278 279 |
return 0; } static struct rtnl_link_ops veth_link_ops; |
81adee47d net: Support spec... |
280 |
static int veth_newlink(struct net *src_net, struct net_device *dev, |
e314dbdc1 [NET]: Virtual et... |
281 282 283 284 285 286 287 |
struct nlattr *tb[], struct nlattr *data[]) { int err; struct net_device *peer; struct veth_priv *priv; char ifname[IFNAMSIZ]; struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; |
3729d5021 rtnetlink: suppor... |
288 |
struct ifinfomsg *ifmp; |
81adee47d net: Support spec... |
289 |
struct net *net; |
e314dbdc1 [NET]: Virtual et... |
290 291 292 |
/* * create and register peer first |
e314dbdc1 [NET]: Virtual et... |
293 |
*/ |
e314dbdc1 [NET]: Virtual et... |
294 295 296 297 |
if (data != NULL && data[VETH_INFO_PEER] != NULL) { struct nlattr *nla_peer; nla_peer = data[VETH_INFO_PEER]; |
3729d5021 rtnetlink: suppor... |
298 |
ifmp = nla_data(nla_peer); |
e314dbdc1 [NET]: Virtual et... |
299 300 301 302 303 304 305 306 307 308 309 310 |
err = nla_parse(peer_tb, IFLA_MAX, nla_data(nla_peer) + sizeof(struct ifinfomsg), nla_len(nla_peer) - sizeof(struct ifinfomsg), ifla_policy); if (err < 0) return err; err = veth_validate(peer_tb, NULL); if (err < 0) return err; tbp = peer_tb; |
3729d5021 rtnetlink: suppor... |
311 312 |
} else { ifmp = NULL; |
e314dbdc1 [NET]: Virtual et... |
313 |
tbp = tb; |
3729d5021 rtnetlink: suppor... |
314 |
} |
e314dbdc1 [NET]: Virtual et... |
315 316 317 318 319 |
if (tbp[IFLA_IFNAME]) nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); else snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); |
81adee47d net: Support spec... |
320 321 322 323 324 325 326 |
net = rtnl_link_get_net(src_net, tbp); if (IS_ERR(net)) return PTR_ERR(net); peer = rtnl_create_link(src_net, net, ifname, &veth_link_ops, tbp); if (IS_ERR(peer)) { put_net(net); |
e314dbdc1 [NET]: Virtual et... |
327 |
return PTR_ERR(peer); |
81adee47d net: Support spec... |
328 |
} |
e314dbdc1 [NET]: Virtual et... |
329 330 331 332 333 |
if (tbp[IFLA_ADDRESS] == NULL) random_ether_addr(peer->dev_addr); err = register_netdevice(peer); |
81adee47d net: Support spec... |
334 335 |
put_net(net); net = NULL; |
e314dbdc1 [NET]: Virtual et... |
336 337 338 339 |
if (err < 0) goto err_register_peer; netif_carrier_off(peer); |
3729d5021 rtnetlink: suppor... |
340 341 342 |
err = rtnl_configure_link(peer, ifmp); if (err < 0) goto err_configure_peer; |
e314dbdc1 [NET]: Virtual et... |
343 344 345 346 347 348 349 350 351 |
/* * register dev last * * note, that since we've registered new device the dev's name * should be re-allocated */ if (tb[IFLA_ADDRESS] == NULL) random_ether_addr(dev->dev_addr); |
6c8c44462 Revert: veth: rem... |
352 353 354 355 356 357 358 359 360 361 |
if (tb[IFLA_IFNAME]) nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ); else snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); if (strchr(dev->name, '%')) { err = dev_alloc_name(dev, dev->name); if (err < 0) goto err_alloc_name; } |
e314dbdc1 [NET]: Virtual et... |
362 363 364 365 366 367 368 369 370 371 372 |
err = register_netdevice(dev); if (err < 0) goto err_register_dev; netif_carrier_off(dev); /* * tie the deviced together */ priv = netdev_priv(dev); |
e314dbdc1 [NET]: Virtual et... |
373 |
priv->peer = peer; |
e314dbdc1 [NET]: Virtual et... |
374 375 |
priv = netdev_priv(peer); |
e314dbdc1 [NET]: Virtual et... |
376 |
priv->peer = dev; |
e314dbdc1 [NET]: Virtual et... |
377 378 379 380 |
return 0; err_register_dev: /* nothing to do */ |
6c8c44462 Revert: veth: rem... |
381 |
err_alloc_name: |
3729d5021 rtnetlink: suppor... |
382 |
err_configure_peer: |
e314dbdc1 [NET]: Virtual et... |
383 384 385 386 387 388 389 |
unregister_netdevice(peer); return err; err_register_peer: free_netdev(peer); return err; } |
23289a37e net: add a list_h... |
390 |
static void veth_dellink(struct net_device *dev, struct list_head *head) |
e314dbdc1 [NET]: Virtual et... |
391 392 393 394 395 396 |
{ struct veth_priv *priv; struct net_device *peer; priv = netdev_priv(dev); peer = priv->peer; |
24540535d veth: Fix veth_de... |
397 398 |
unregister_netdevice_queue(dev, head); unregister_netdevice_queue(peer, head); |
e314dbdc1 [NET]: Virtual et... |
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
} static const struct nla_policy veth_policy[VETH_INFO_MAX + 1]; static struct rtnl_link_ops veth_link_ops = { .kind = DRV_NAME, .priv_size = sizeof(struct veth_priv), .setup = veth_setup, .validate = veth_validate, .newlink = veth_newlink, .dellink = veth_dellink, .policy = veth_policy, .maxtype = VETH_INFO_MAX, }; /* * init/fini */ static __init int veth_init(void) { return rtnl_link_register(&veth_link_ops); } static __exit void veth_exit(void) { |
68365458a [NET]: rtnl_link:... |
425 |
rtnl_link_unregister(&veth_link_ops); |
e314dbdc1 [NET]: Virtual et... |
426 427 428 429 430 431 432 433 |
} module_init(veth_init); module_exit(veth_exit); MODULE_DESCRIPTION("Virtual Ethernet Tunnel"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS_RTNL_LINK(DRV_NAME); |