hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
kernel/drivers/net/loopback.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * INET An implementation of the TCP/IP protocol suite for the LINUX
34 * operating system. INET is implemented using the BSD Socket
....@@ -22,11 +23,6 @@
2223 * interface.
2324 * Alexey Kuznetsov: Potential hang under some extreme
2425 * cases removed.
25
- *
26
- * This program is free software; you can redistribute it and/or
27
- * modify it under the terms of the GNU General Public License
28
- * as published by the Free Software Foundation; either version
29
- * 2 of the License, or (at your option) any later version.
3026 */
3127 #include <linux/kernel.h>
3228 #include <linux/jiffies.h>
....@@ -59,11 +55,12 @@
5955 #include <net/net_namespace.h>
6056 #include <linux/u64_stats_sync.h>
6157
62
-struct pcpu_lstats {
63
- u64 packets;
64
- u64 bytes;
65
- struct u64_stats_sync syncp;
66
-};
58
+/* blackhole_netdev - a device used for dsts that are marked expired!
59
+ * This is global device (instead of per-net-ns) since it's not needed
60
+ * to be per-ns and gets initialized at boot time.
61
+ */
62
+struct net_device *blackhole_netdev;
63
+EXPORT_SYMBOL(blackhole_netdev);
6764
6865 /* The higher levels take care of making this non-reentrant (it's
6966 * called with bh's disabled).
....@@ -71,7 +68,6 @@
7168 static netdev_tx_t loopback_xmit(struct sk_buff *skb,
7269 struct net_device *dev)
7370 {
74
- struct pcpu_lstats *lb_stats;
7571 int len;
7672
7773 skb_tx_timestamp(skb);
....@@ -88,26 +84,19 @@
8884
8985 skb->protocol = eth_type_trans(skb, dev);
9086
91
- /* it's OK to use per_cpu_ptr() because BHs are off */
92
- lb_stats = this_cpu_ptr(dev->lstats);
93
-
9487 len = skb->len;
95
- if (likely(netif_rx(skb) == NET_RX_SUCCESS)) {
96
- u64_stats_update_begin(&lb_stats->syncp);
97
- lb_stats->bytes += len;
98
- lb_stats->packets++;
99
- u64_stats_update_end(&lb_stats->syncp);
100
- }
88
+ if (likely(netif_rx(skb) == NET_RX_SUCCESS))
89
+ dev_lstats_add(dev, len);
10190
10291 return NETDEV_TX_OK;
10392 }
10493
105
-static void loopback_get_stats64(struct net_device *dev,
106
- struct rtnl_link_stats64 *stats)
94
+void dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes)
10795 {
108
- u64 bytes = 0;
109
- u64 packets = 0;
11096 int i;
97
+
98
+ *packets = 0;
99
+ *bytes = 0;
111100
112101 for_each_possible_cpu(i) {
113102 const struct pcpu_lstats *lb_stats;
....@@ -117,12 +106,22 @@
117106 lb_stats = per_cpu_ptr(dev->lstats, i);
118107 do {
119108 start = u64_stats_fetch_begin_irq(&lb_stats->syncp);
120
- tbytes = lb_stats->bytes;
121
- tpackets = lb_stats->packets;
109
+ tpackets = u64_stats_read(&lb_stats->packets);
110
+ tbytes = u64_stats_read(&lb_stats->bytes);
122111 } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start));
123
- bytes += tbytes;
124
- packets += tpackets;
112
+ *bytes += tbytes;
113
+ *packets += tpackets;
125114 }
115
+}
116
+EXPORT_SYMBOL(dev_lstats_read);
117
+
118
+static void loopback_get_stats64(struct net_device *dev,
119
+ struct rtnl_link_stats64 *stats)
120
+{
121
+ u64 packets, bytes;
122
+
123
+ dev_lstats_read(dev, &packets, &bytes);
124
+
126125 stats->rx_packets = packets;
127126 stats->tx_packets = packets;
128127 stats->rx_bytes = bytes;
....@@ -134,21 +133,9 @@
134133 return 1;
135134 }
136135
137
-static int loopback_get_ts_info(struct net_device *netdev,
138
- struct ethtool_ts_info *ts_info)
139
-{
140
- ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
141
- SOF_TIMESTAMPING_RX_SOFTWARE |
142
- SOF_TIMESTAMPING_SOFTWARE;
143
-
144
- ts_info->phc_index = -1;
145
-
146
- return 0;
147
-};
148
-
149136 static const struct ethtool_ops loopback_ethtool_ops = {
150137 .get_link = always_on,
151
- .get_ts_info = loopback_get_ts_info,
138
+ .get_ts_info = ethtool_op_get_ts_info,
152139 };
153140
154141 static int loopback_dev_init(struct net_device *dev)
....@@ -172,12 +159,14 @@
172159 .ndo_set_mac_address = eth_mac_addr,
173160 };
174161
175
-/* The loopback device is special. There is only one instance
176
- * per network namespace.
177
- */
178
-static void loopback_setup(struct net_device *dev)
162
+static void gen_lo_setup(struct net_device *dev,
163
+ unsigned int mtu,
164
+ const struct ethtool_ops *eth_ops,
165
+ const struct header_ops *hdr_ops,
166
+ const struct net_device_ops *dev_ops,
167
+ void (*dev_destructor)(struct net_device *dev))
179168 {
180
- dev->mtu = 64 * 1024;
169
+ dev->mtu = mtu;
181170 dev->hard_header_len = ETH_HLEN; /* 14 */
182171 dev->min_header_len = ETH_HLEN; /* 14 */
183172 dev->addr_len = ETH_ALEN; /* 6 */
....@@ -196,11 +185,20 @@
196185 | NETIF_F_NETNS_LOCAL
197186 | NETIF_F_VLAN_CHALLENGED
198187 | NETIF_F_LOOPBACK;
199
- dev->ethtool_ops = &loopback_ethtool_ops;
200
- dev->header_ops = &eth_header_ops;
201
- dev->netdev_ops = &loopback_ops;
188
+ dev->ethtool_ops = eth_ops;
189
+ dev->header_ops = hdr_ops;
190
+ dev->netdev_ops = dev_ops;
202191 dev->needs_free_netdev = true;
203
- dev->priv_destructor = loopback_dev_free;
192
+ dev->priv_destructor = dev_destructor;
193
+}
194
+
195
+/* The loopback device is special. There is only one instance
196
+ * per network namespace.
197
+ */
198
+static void loopback_setup(struct net_device *dev)
199
+{
200
+ gen_lo_setup(dev, (64 * 1024), &loopback_ethtool_ops, &eth_header_ops,
201
+ &loopback_ops, loopback_dev_free);
204202 }
205203
206204 /* Setup and register the loopback device. */
....@@ -210,7 +208,7 @@
210208 int err;
211209
212210 err = -ENOMEM;
213
- dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup);
211
+ dev = alloc_netdev(0, "lo", NET_NAME_PREDICTABLE, loopback_setup);
214212 if (!dev)
215213 goto out;
216214
....@@ -235,3 +233,45 @@
235233 struct pernet_operations __net_initdata loopback_net_ops = {
236234 .init = loopback_net_init,
237235 };
236
+
237
+/* blackhole netdevice */
238
+static netdev_tx_t blackhole_netdev_xmit(struct sk_buff *skb,
239
+ struct net_device *dev)
240
+{
241
+ kfree_skb(skb);
242
+ net_warn_ratelimited("%s(): Dropping skb.\n", __func__);
243
+ return NETDEV_TX_OK;
244
+}
245
+
246
+static const struct net_device_ops blackhole_netdev_ops = {
247
+ .ndo_start_xmit = blackhole_netdev_xmit,
248
+};
249
+
250
+/* This is a dst-dummy device used specifically for invalidated
251
+ * DSTs and unlike loopback, this is not per-ns.
252
+ */
253
+static void blackhole_netdev_setup(struct net_device *dev)
254
+{
255
+ gen_lo_setup(dev, ETH_MIN_MTU, NULL, NULL, &blackhole_netdev_ops, NULL);
256
+}
257
+
258
+/* Setup and register the blackhole_netdev. */
259
+static int __init blackhole_netdev_init(void)
260
+{
261
+ blackhole_netdev = alloc_netdev(0, "blackhole_dev", NET_NAME_UNKNOWN,
262
+ blackhole_netdev_setup);
263
+ if (!blackhole_netdev)
264
+ return -ENOMEM;
265
+
266
+ rtnl_lock();
267
+ dev_init_scheduler(blackhole_netdev);
268
+ dev_activate(blackhole_netdev);
269
+ rtnl_unlock();
270
+
271
+ blackhole_netdev->flags |= IFF_UP | IFF_RUNNING;
272
+ dev_net_set(blackhole_netdev, &init_net);
273
+
274
+ return 0;
275
+}
276
+
277
+device_initcall(blackhole_netdev_init);