diff options
| -rw-r--r-- | net/l2tp/l2tp_eth.c | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c index c3738f49646a..47b259fccd27 100644 --- a/net/l2tp/l2tp_eth.c +++ b/net/l2tp/l2tp_eth.c | |||
| @@ -42,6 +42,11 @@ struct l2tp_eth { | |||
| 42 | struct sock *tunnel_sock; | 42 | struct sock *tunnel_sock; |
| 43 | struct l2tp_session *session; | 43 | struct l2tp_session *session; |
| 44 | struct list_head list; | 44 | struct list_head list; |
| 45 | atomic_long_t tx_bytes; | ||
| 46 | atomic_long_t tx_packets; | ||
| 47 | atomic_long_t rx_bytes; | ||
| 48 | atomic_long_t rx_packets; | ||
| 49 | atomic_long_t rx_errors; | ||
| 45 | }; | 50 | }; |
| 46 | 51 | ||
| 47 | /* via l2tp_session_priv() */ | 52 | /* via l2tp_session_priv() */ |
| @@ -88,24 +93,40 @@ static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 88 | struct l2tp_eth *priv = netdev_priv(dev); | 93 | struct l2tp_eth *priv = netdev_priv(dev); |
| 89 | struct l2tp_session *session = priv->session; | 94 | struct l2tp_session *session = priv->session; |
| 90 | 95 | ||
| 91 | dev->stats.tx_bytes += skb->len; | 96 | atomic_long_add(skb->len, &priv->tx_bytes); |
| 92 | dev->stats.tx_packets++; | 97 | atomic_long_inc(&priv->tx_packets); |
| 93 | 98 | ||
| 94 | l2tp_xmit_skb(session, skb, session->hdr_len); | 99 | l2tp_xmit_skb(session, skb, session->hdr_len); |
| 95 | 100 | ||
| 96 | return NETDEV_TX_OK; | 101 | return NETDEV_TX_OK; |
| 97 | } | 102 | } |
| 98 | 103 | ||
| 104 | static struct rtnl_link_stats64 *l2tp_eth_get_stats64(struct net_device *dev, | ||
| 105 | struct rtnl_link_stats64 *stats) | ||
| 106 | { | ||
| 107 | struct l2tp_eth *priv = netdev_priv(dev); | ||
| 108 | |||
| 109 | stats->tx_bytes = atomic_long_read(&priv->tx_bytes); | ||
| 110 | stats->tx_packets = atomic_long_read(&priv->tx_packets); | ||
| 111 | stats->rx_bytes = atomic_long_read(&priv->rx_bytes); | ||
| 112 | stats->rx_packets = atomic_long_read(&priv->rx_packets); | ||
| 113 | stats->rx_errors = atomic_long_read(&priv->rx_errors); | ||
| 114 | return stats; | ||
| 115 | } | ||
| 116 | |||
| 117 | |||
| 99 | static struct net_device_ops l2tp_eth_netdev_ops = { | 118 | static struct net_device_ops l2tp_eth_netdev_ops = { |
| 100 | .ndo_init = l2tp_eth_dev_init, | 119 | .ndo_init = l2tp_eth_dev_init, |
| 101 | .ndo_uninit = l2tp_eth_dev_uninit, | 120 | .ndo_uninit = l2tp_eth_dev_uninit, |
| 102 | .ndo_start_xmit = l2tp_eth_dev_xmit, | 121 | .ndo_start_xmit = l2tp_eth_dev_xmit, |
| 122 | .ndo_get_stats64 = l2tp_eth_get_stats64, | ||
| 103 | }; | 123 | }; |
| 104 | 124 | ||
| 105 | static void l2tp_eth_dev_setup(struct net_device *dev) | 125 | static void l2tp_eth_dev_setup(struct net_device *dev) |
| 106 | { | 126 | { |
| 107 | ether_setup(dev); | 127 | ether_setup(dev); |
| 108 | dev->priv_flags &= ~IFF_TX_SKB_SHARING; | 128 | dev->priv_flags &= ~IFF_TX_SKB_SHARING; |
| 129 | dev->features |= NETIF_F_LLTX; | ||
| 109 | dev->netdev_ops = &l2tp_eth_netdev_ops; | 130 | dev->netdev_ops = &l2tp_eth_netdev_ops; |
| 110 | dev->destructor = free_netdev; | 131 | dev->destructor = free_netdev; |
| 111 | } | 132 | } |
| @@ -114,17 +135,17 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, | |||
| 114 | { | 135 | { |
| 115 | struct l2tp_eth_sess *spriv = l2tp_session_priv(session); | 136 | struct l2tp_eth_sess *spriv = l2tp_session_priv(session); |
| 116 | struct net_device *dev = spriv->dev; | 137 | struct net_device *dev = spriv->dev; |
| 138 | struct l2tp_eth *priv = netdev_priv(dev); | ||
| 117 | 139 | ||
| 118 | if (session->debug & L2TP_MSG_DATA) { | 140 | if (session->debug & L2TP_MSG_DATA) { |
| 119 | unsigned int length; | 141 | unsigned int length; |
| 120 | u8 *ptr = skb->data; | ||
| 121 | 142 | ||
| 122 | length = min(32u, skb->len); | 143 | length = min(32u, skb->len); |
| 123 | if (!pskb_may_pull(skb, length)) | 144 | if (!pskb_may_pull(skb, length)) |
| 124 | goto error; | 145 | goto error; |
| 125 | 146 | ||
| 126 | pr_debug("%s: eth recv\n", session->name); | 147 | pr_debug("%s: eth recv\n", session->name); |
| 127 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, ptr, length); | 148 | print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, skb->data, length); |
| 128 | } | 149 | } |
| 129 | 150 | ||
| 130 | if (!pskb_may_pull(skb, sizeof(ETH_HLEN))) | 151 | if (!pskb_may_pull(skb, sizeof(ETH_HLEN))) |
| @@ -139,15 +160,15 @@ static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, | |||
| 139 | nf_reset(skb); | 160 | nf_reset(skb); |
| 140 | 161 | ||
| 141 | if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) { | 162 | if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) { |
| 142 | dev->stats.rx_packets++; | 163 | atomic_long_inc(&priv->rx_packets); |
| 143 | dev->stats.rx_bytes += data_len; | 164 | atomic_long_add(data_len, &priv->rx_bytes); |
| 144 | } else | 165 | } else { |
| 145 | dev->stats.rx_errors++; | 166 | atomic_long_inc(&priv->rx_errors); |
| 146 | 167 | } | |
| 147 | return; | 168 | return; |
| 148 | 169 | ||
| 149 | error: | 170 | error: |
| 150 | dev->stats.rx_errors++; | 171 | atomic_long_inc(&priv->rx_errors); |
| 151 | kfree_skb(skb); | 172 | kfree_skb(skb); |
| 152 | } | 173 | } |
| 153 | 174 | ||
