net/ipv4/ipmr.c

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

File Facts

System
Linux kernel
Corpus path
net/ipv4/ipmr.c
Extension
.c
Size
84331 bytes
Lines
3406
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 reg_vif_netdev_ops = {
	.ndo_start_xmit	= reg_vif_xmit,
	.ndo_get_iflink = reg_vif_get_iflink,
};

static void reg_vif_setup(struct net_device *dev)
{
	dev->type		= ARPHRD_PIMREG;
	dev->mtu		= ETH_DATA_LEN - sizeof(struct iphdr) - 8;
	dev->flags		= IFF_NOARP;
	dev->netdev_ops		= &reg_vif_netdev_ops;
	dev->needs_free_netdev	= true;
	dev->netns_immutable	= true;
}

static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
{
	struct net_device *dev;
	char name[IFNAMSIZ];

	if (mrt->id == RT_TABLE_DEFAULT)
		sprintf(name, "pimreg");
	else
		sprintf(name, "pimreg%u", mrt->id);

	dev = alloc_netdev(0, name, NET_NAME_UNKNOWN, reg_vif_setup);

	if (!dev)
		return NULL;

	dev_net_set(dev, net);

	if (register_netdevice(dev)) {
		free_netdev(dev);
		return NULL;
	}

	if (!ipmr_init_vif_indev(dev))
		goto failure;
	if (dev_open(dev, NULL))
		goto failure;

	dev_hold(dev);

	return dev;

failure:
	unregister_netdevice(dev);
	return NULL;
}

/* called with rcu_read_lock() */
static int __pim_rcv(struct mr_table *mrt, struct sk_buff *skb,
		     unsigned int pimlen)
{
	struct net_device *reg_dev = NULL;
	struct iphdr *encap;
	int vif_num;

	encap = (struct iphdr *)(skb_transport_header(skb) + pimlen);
	/* Check that:
	 * a. packet is really sent to a multicast group
	 * b. packet is not a NULL-REGISTER
	 * c. packet is not truncated
	 */
	if (!ipv4_is_multicast(encap->daddr) ||
	    encap->tot_len == 0 ||
	    ntohs(encap->tot_len) + pimlen > skb->len)
		return 1;

	/* Pairs with WRITE_ONCE() in vif_add()/vid_delete() */
	vif_num = READ_ONCE(mrt->mroute_reg_vif_num);
	if (vif_num >= 0)
		reg_dev = vif_dev_read(&mrt->vif_table[vif_num]);
	if (!reg_dev)
		return 1;

	skb->mac_header = skb->network_header;
	skb_pull(skb, (u8 *)encap - skb->data);
	skb_reset_network_header(skb);
	skb->protocol = htons(ETH_P_IP);
	skb->ip_summed = CHECKSUM_NONE;

	skb_tunnel_rx(skb, reg_dev, dev_net(reg_dev));

	netif_rx(skb);

	return NET_RX_SUCCESS;
}
#else

Annotation

Implementation Notes