18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 48c2ecf20Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 58c2ecf20Sopenharmony_ci * interface as the means of communication with the user level. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Pseudo-driver for the loopback interface. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Version: @(#)loopback.c 1.0.4b 08/16/93 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Authors: Ross Biro 128c2ecf20Sopenharmony_ci * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 138c2ecf20Sopenharmony_ci * Donald Becker, <becker@scyld.com> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Alan Cox : Fixed oddments for NET3.014 168c2ecf20Sopenharmony_ci * Alan Cox : Rejig for NET3.029 snap #3 178c2ecf20Sopenharmony_ci * Alan Cox : Fixed NET3.029 bugs and sped up 188c2ecf20Sopenharmony_ci * Larry McVoy : Tiny tweak to double performance 198c2ecf20Sopenharmony_ci * Alan Cox : Backed out LMV's tweak - the linux mm 208c2ecf20Sopenharmony_ci * can't take it... 218c2ecf20Sopenharmony_ci * Michael Griffith: Don't bother computing the checksums 228c2ecf20Sopenharmony_ci * on packets received on the loopback 238c2ecf20Sopenharmony_ci * interface. 248c2ecf20Sopenharmony_ci * Alexey Kuznetsov: Potential hang under some extreme 258c2ecf20Sopenharmony_ci * cases removed. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ci#include <linux/kernel.h> 288c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 298c2ecf20Sopenharmony_ci#include <linux/module.h> 308c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 318c2ecf20Sopenharmony_ci#include <linux/fs.h> 328c2ecf20Sopenharmony_ci#include <linux/types.h> 338c2ecf20Sopenharmony_ci#include <linux/string.h> 348c2ecf20Sopenharmony_ci#include <linux/socket.h> 358c2ecf20Sopenharmony_ci#include <linux/errno.h> 368c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 378c2ecf20Sopenharmony_ci#include <linux/in.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 408c2ecf20Sopenharmony_ci#include <linux/io.h> 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#include <linux/inet.h> 438c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 448c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 458c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 468c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 478c2ecf20Sopenharmony_ci#include <net/sock.h> 488c2ecf20Sopenharmony_ci#include <net/checksum.h> 498c2ecf20Sopenharmony_ci#include <linux/if_ether.h> /* For the statistics structure. */ 508c2ecf20Sopenharmony_ci#include <linux/if_arp.h> /* For ARPHRD_ETHER */ 518c2ecf20Sopenharmony_ci#include <linux/ip.h> 528c2ecf20Sopenharmony_ci#include <linux/tcp.h> 538c2ecf20Sopenharmony_ci#include <linux/percpu.h> 548c2ecf20Sopenharmony_ci#include <linux/net_tstamp.h> 558c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 568c2ecf20Sopenharmony_ci#include <linux/u64_stats_sync.h> 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* blackhole_netdev - a device used for dsts that are marked expired! 598c2ecf20Sopenharmony_ci * This is global device (instead of per-net-ns) since it's not needed 608c2ecf20Sopenharmony_ci * to be per-ns and gets initialized at boot time. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistruct net_device *blackhole_netdev; 638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(blackhole_netdev); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/* The higher levels take care of making this non-reentrant (it's 668c2ecf20Sopenharmony_ci * called with bh's disabled). 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_cistatic netdev_tx_t loopback_xmit(struct sk_buff *skb, 698c2ecf20Sopenharmony_ci struct net_device *dev) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int len; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* do not fool net_timestamp_check() with various clock bases */ 768c2ecf20Sopenharmony_ci skb->tstamp = 0; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci skb_orphan(skb); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* Before queueing this packet to netif_rx(), 818c2ecf20Sopenharmony_ci * make sure dst is refcounted. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci skb_dst_force(skb); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci len = skb->len; 888c2ecf20Sopenharmony_ci if (likely(netif_rx(skb) == NET_RX_SUCCESS)) 898c2ecf20Sopenharmony_ci dev_lstats_add(dev, len); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_civoid dev_lstats_read(struct net_device *dev, u64 *packets, u64 *bytes) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci int i; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci *packets = 0; 998c2ecf20Sopenharmony_ci *bytes = 0; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for_each_possible_cpu(i) { 1028c2ecf20Sopenharmony_ci const struct pcpu_lstats *lb_stats; 1038c2ecf20Sopenharmony_ci u64 tbytes, tpackets; 1048c2ecf20Sopenharmony_ci unsigned int start; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci lb_stats = per_cpu_ptr(dev->lstats, i); 1078c2ecf20Sopenharmony_ci do { 1088c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&lb_stats->syncp); 1098c2ecf20Sopenharmony_ci tpackets = u64_stats_read(&lb_stats->packets); 1108c2ecf20Sopenharmony_ci tbytes = u64_stats_read(&lb_stats->bytes); 1118c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start)); 1128c2ecf20Sopenharmony_ci *bytes += tbytes; 1138c2ecf20Sopenharmony_ci *packets += tpackets; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dev_lstats_read); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void loopback_get_stats64(struct net_device *dev, 1198c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *stats) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci u64 packets, bytes; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci dev_lstats_read(dev, &packets, &bytes); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci stats->rx_packets = packets; 1268c2ecf20Sopenharmony_ci stats->tx_packets = packets; 1278c2ecf20Sopenharmony_ci stats->rx_bytes = bytes; 1288c2ecf20Sopenharmony_ci stats->tx_bytes = bytes; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic u32 always_on(struct net_device *dev) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci return 1; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic const struct ethtool_ops loopback_ethtool_ops = { 1378c2ecf20Sopenharmony_ci .get_link = always_on, 1388c2ecf20Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int loopback_dev_init(struct net_device *dev) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); 1448c2ecf20Sopenharmony_ci if (!dev->lstats) 1458c2ecf20Sopenharmony_ci return -ENOMEM; 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void loopback_dev_free(struct net_device *dev) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci dev_net(dev)->loopback_dev = NULL; 1528c2ecf20Sopenharmony_ci free_percpu(dev->lstats); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic const struct net_device_ops loopback_ops = { 1568c2ecf20Sopenharmony_ci .ndo_init = loopback_dev_init, 1578c2ecf20Sopenharmony_ci .ndo_start_xmit = loopback_xmit, 1588c2ecf20Sopenharmony_ci .ndo_get_stats64 = loopback_get_stats64, 1598c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic void gen_lo_setup(struct net_device *dev, 1638c2ecf20Sopenharmony_ci unsigned int mtu, 1648c2ecf20Sopenharmony_ci const struct ethtool_ops *eth_ops, 1658c2ecf20Sopenharmony_ci const struct header_ops *hdr_ops, 1668c2ecf20Sopenharmony_ci const struct net_device_ops *dev_ops, 1678c2ecf20Sopenharmony_ci void (*dev_destructor)(struct net_device *dev)) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci dev->mtu = mtu; 1708c2ecf20Sopenharmony_ci dev->hard_header_len = ETH_HLEN; /* 14 */ 1718c2ecf20Sopenharmony_ci dev->min_header_len = ETH_HLEN; /* 14 */ 1728c2ecf20Sopenharmony_ci dev->addr_len = ETH_ALEN; /* 6 */ 1738c2ecf20Sopenharmony_ci dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ 1748c2ecf20Sopenharmony_ci dev->flags = IFF_LOOPBACK; 1758c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; 1768c2ecf20Sopenharmony_ci netif_keep_dst(dev); 1778c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_GSO_SOFTWARE; 1788c2ecf20Sopenharmony_ci dev->features = NETIF_F_SG | NETIF_F_FRAGLIST 1798c2ecf20Sopenharmony_ci | NETIF_F_GSO_SOFTWARE 1808c2ecf20Sopenharmony_ci | NETIF_F_HW_CSUM 1818c2ecf20Sopenharmony_ci | NETIF_F_RXCSUM 1828c2ecf20Sopenharmony_ci | NETIF_F_SCTP_CRC 1838c2ecf20Sopenharmony_ci | NETIF_F_HIGHDMA 1848c2ecf20Sopenharmony_ci | NETIF_F_LLTX 1858c2ecf20Sopenharmony_ci | NETIF_F_NETNS_LOCAL 1868c2ecf20Sopenharmony_ci | NETIF_F_VLAN_CHALLENGED 1878c2ecf20Sopenharmony_ci | NETIF_F_LOOPBACK; 1888c2ecf20Sopenharmony_ci dev->ethtool_ops = eth_ops; 1898c2ecf20Sopenharmony_ci dev->header_ops = hdr_ops; 1908c2ecf20Sopenharmony_ci dev->netdev_ops = dev_ops; 1918c2ecf20Sopenharmony_ci dev->needs_free_netdev = true; 1928c2ecf20Sopenharmony_ci dev->priv_destructor = dev_destructor; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* The loopback device is special. There is only one instance 1968c2ecf20Sopenharmony_ci * per network namespace. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_cistatic void loopback_setup(struct net_device *dev) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci gen_lo_setup(dev, (64 * 1024), &loopback_ethtool_ops, ð_header_ops, 2018c2ecf20Sopenharmony_ci &loopback_ops, loopback_dev_free); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* Setup and register the loopback device. */ 2058c2ecf20Sopenharmony_cistatic __net_init int loopback_net_init(struct net *net) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct net_device *dev; 2088c2ecf20Sopenharmony_ci int err; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci err = -ENOMEM; 2118c2ecf20Sopenharmony_ci dev = alloc_netdev(0, "lo", NET_NAME_PREDICTABLE, loopback_setup); 2128c2ecf20Sopenharmony_ci if (!dev) 2138c2ecf20Sopenharmony_ci goto out; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci dev_net_set(dev, net); 2168c2ecf20Sopenharmony_ci err = register_netdev(dev); 2178c2ecf20Sopenharmony_ci if (err) 2188c2ecf20Sopenharmony_ci goto out_free_netdev; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci BUG_ON(dev->ifindex != LOOPBACK_IFINDEX); 2218c2ecf20Sopenharmony_ci net->loopback_dev = dev; 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciout_free_netdev: 2258c2ecf20Sopenharmony_ci free_netdev(dev); 2268c2ecf20Sopenharmony_ciout: 2278c2ecf20Sopenharmony_ci if (net_eq(net, &init_net)) 2288c2ecf20Sopenharmony_ci panic("loopback: Failed to register netdevice: %d\n", err); 2298c2ecf20Sopenharmony_ci return err; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/* Registered in net/core/dev.c */ 2338c2ecf20Sopenharmony_cistruct pernet_operations __net_initdata loopback_net_ops = { 2348c2ecf20Sopenharmony_ci .init = loopback_net_init, 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* blackhole netdevice */ 2388c2ecf20Sopenharmony_cistatic netdev_tx_t blackhole_netdev_xmit(struct sk_buff *skb, 2398c2ecf20Sopenharmony_ci struct net_device *dev) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci kfree_skb(skb); 2428c2ecf20Sopenharmony_ci net_warn_ratelimited("%s(): Dropping skb.\n", __func__); 2438c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic const struct net_device_ops blackhole_netdev_ops = { 2478c2ecf20Sopenharmony_ci .ndo_start_xmit = blackhole_netdev_xmit, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci/* This is a dst-dummy device used specifically for invalidated 2518c2ecf20Sopenharmony_ci * DSTs and unlike loopback, this is not per-ns. 2528c2ecf20Sopenharmony_ci */ 2538c2ecf20Sopenharmony_cistatic void blackhole_netdev_setup(struct net_device *dev) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci gen_lo_setup(dev, ETH_MIN_MTU, NULL, NULL, &blackhole_netdev_ops, NULL); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci/* Setup and register the blackhole_netdev. */ 2598c2ecf20Sopenharmony_cistatic int __init blackhole_netdev_init(void) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci blackhole_netdev = alloc_netdev(0, "blackhole_dev", NET_NAME_UNKNOWN, 2628c2ecf20Sopenharmony_ci blackhole_netdev_setup); 2638c2ecf20Sopenharmony_ci if (!blackhole_netdev) 2648c2ecf20Sopenharmony_ci return -ENOMEM; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci rtnl_lock(); 2678c2ecf20Sopenharmony_ci dev_init_scheduler(blackhole_netdev); 2688c2ecf20Sopenharmony_ci dev_activate(blackhole_netdev); 2698c2ecf20Sopenharmony_ci rtnl_unlock(); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci blackhole_netdev->flags |= IFF_UP | IFF_RUNNING; 2728c2ecf20Sopenharmony_ci dev_net_set(blackhole_netdev, &init_net); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return 0; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cidevice_initcall(blackhole_netdev_init); 278