net/ipv4/ip_gre.c

Source file repositories/reference/linux-study-clean/net/ipv4/ip_gre.c

File Facts

System
Linux kernel
Corpus path
net/ipv4/ip_gre.c
Extension
.c
Size
49374 bytes
Lines
1871
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct net_device_ops ipgre_netdev_ops = {
	.ndo_init		= ipgre_tunnel_init,
	.ndo_uninit		= ip_tunnel_uninit,
#ifdef CONFIG_NET_IPGRE_BROADCAST
	.ndo_open		= ipgre_open,
	.ndo_stop		= ipgre_close,
#endif
	.ndo_start_xmit		= ipgre_xmit,
	.ndo_siocdevprivate	= ip_tunnel_siocdevprivate,
	.ndo_change_mtu		= ip_tunnel_change_mtu,
	.ndo_get_stats64	= dev_get_tstats64,
	.ndo_get_iflink		= ip_tunnel_get_iflink,
	.ndo_tunnel_ctl		= ipgre_tunnel_ctl,
};

#define GRE_FEATURES (NETIF_F_SG |		\
		      NETIF_F_FRAGLIST |	\
		      NETIF_F_HIGHDMA |		\
		      NETIF_F_HW_CSUM)

static void ipgre_tunnel_setup(struct net_device *dev)
{
	dev->netdev_ops		= &ipgre_netdev_ops;
	dev->type		= ARPHRD_IPGRE;
	ip_tunnel_setup(dev, ipgre_net_id);
}

static void __gre_tunnel_init(struct net_device *dev)
{
	struct ip_tunnel *tunnel;

	tunnel = netdev_priv(dev);
	tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags);
	tunnel->parms.iph.protocol = IPPROTO_GRE;

	tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen;
	dev->needed_headroom = tunnel->hlen + sizeof(tunnel->parms.iph);

	dev->features		|= GRE_FEATURES;
	dev->hw_features	|= GRE_FEATURES;

	/* TCP offload with GRE SEQ is not supported, nor can we support 2
	 * levels of outer headers requiring an update.
	 */
	if (test_bit(IP_TUNNEL_SEQ_BIT, tunnel->parms.o_flags))
		return;
	if (test_bit(IP_TUNNEL_CSUM_BIT, tunnel->parms.o_flags) &&
	    tunnel->encap.type != TUNNEL_ENCAP_NONE)
		return;

	dev->features |= NETIF_F_GSO_SOFTWARE;
	dev->hw_features |= NETIF_F_GSO_SOFTWARE;

	dev->lltx = true;
}

static int ipgre_tunnel_init(struct net_device *dev)
{
	struct ip_tunnel *tunnel = netdev_priv(dev);
	struct iphdr *iph = &tunnel->parms.iph;

	__gre_tunnel_init(dev);

	__dev_addr_set(dev, &iph->saddr, 4);
	memcpy(dev->broadcast, &iph->daddr, 4);

	dev->flags		= IFF_NOARP;
	netif_keep_dst(dev);
	dev->addr_len		= 4;

	if (iph->daddr && !tunnel->collect_md) {
#ifdef CONFIG_NET_IPGRE_BROADCAST
		if (ipv4_is_multicast(iph->daddr)) {
			if (!iph->saddr)
				return -EINVAL;
			dev->flags = IFF_BROADCAST;
			dev->header_ops = &ipgre_header_ops;
			dev->hard_header_len = tunnel->hlen + sizeof(*iph);
			dev->needed_headroom = 0;
		}
#endif
	} else if (!tunnel->collect_md) {
		dev->header_ops = &ipgre_header_ops;
		dev->hard_header_len = tunnel->hlen + sizeof(*iph);
		dev->needed_headroom = 0;
	}

	return ip_tunnel_init(dev);
}

Annotation

Implementation Notes