diff options
Diffstat (limited to 'net/l2tp')
-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 | ||