drivers/net/vrf.c

Source file repositories/reference/linux-study-clean/drivers/net/vrf.c

File Facts

System
Linux kernel
Corpus path
drivers/net/vrf.c
Extension
.c
Size
45640 bytes
Lines
1970
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct net_device_ops vrf_netdev_ops = {
	.ndo_init		= vrf_dev_init,
	.ndo_uninit		= vrf_dev_uninit,
	.ndo_start_xmit		= vrf_xmit,
	.ndo_set_mac_address	= eth_mac_addr,
	.ndo_add_slave		= vrf_add_slave,
	.ndo_del_slave		= vrf_del_slave,
};

static u32 vrf_fib_table(const struct net_device *dev)
{
	struct net_vrf *vrf = netdev_priv(dev);

	return vrf->tb_id;
}

static int vrf_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
	kfree_skb(skb);
	return 0;
}

static struct sk_buff *vrf_rcv_nfhook(u8 pf, unsigned int hook,
				      struct sk_buff *skb,
				      struct net_device *dev)
{
	struct net *net = dev_net(dev);

	if (nf_hook(pf, hook, net, NULL, skb, dev, NULL, vrf_rcv_finish) != 1)
		skb = NULL;    /* kfree_skb(skb) handled by nf code */

	return skb;
}

static int vrf_prepare_mac_header(struct sk_buff *skb,
				  struct net_device *vrf_dev, u16 proto)
{
	struct ethhdr *eth;
	int err;

	/* in general, we do not know if there is enough space in the head of
	 * the packet for hosting the mac header.
	 */
	err = skb_cow_head(skb, LL_RESERVED_SPACE(vrf_dev));
	if (unlikely(err))
		/* no space in the skb head */
		return -ENOBUFS;

	__skb_push(skb, ETH_HLEN);
	eth = (struct ethhdr *)skb->data;

	skb_reset_mac_header(skb);
	skb_reset_mac_len(skb);

	/* we set the ethernet destination and the source addresses to the
	 * address of the VRF device.
	 */
	ether_addr_copy(eth->h_dest, vrf_dev->dev_addr);
	ether_addr_copy(eth->h_source, vrf_dev->dev_addr);
	eth->h_proto = htons(proto);

	/* the destination address of the Ethernet frame corresponds to the
	 * address set on the VRF interface; therefore, the packet is intended
	 * to be processed locally.
	 */
	skb->protocol = eth->h_proto;
	skb->pkt_type = PACKET_HOST;

	skb_postpush_rcsum(skb, skb->data, ETH_HLEN);

	skb_pull_inline(skb, ETH_HLEN);

	return 0;
}

/* prepare and add the mac header to the packet if it was not set previously.
 * In this way, packet sniffers such as tcpdump can parse the packet correctly.
 * If the mac header was already set, the original mac header is left
 * untouched and the function returns immediately.
 */
static int vrf_add_mac_header_if_unset(struct sk_buff *skb,
				       struct net_device *vrf_dev,
				       u16 proto, struct net_device *orig_dev)
{
	if (skb_mac_header_was_set(skb) && dev_has_header(orig_dev))
		return 0;

	return vrf_prepare_mac_header(skb, vrf_dev, proto);
}

Annotation

Implementation Notes