net/netfilter/nf_flow_table_ip.c

Source file repositories/reference/linux-study-clean/net/netfilter/nf_flow_table_ip.c

File Facts

System
Linux kernel
Corpus path
net/netfilter/nf_flow_table_ip.c
Extension
.c
Size
31077 bytes
Lines
1239
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: exported/initcall integration point
Status
integration 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

struct nf_flowtable_ctx {
	const struct net_device	*in;
	u32			offset;
	u32			hdrsize;
	struct {
		/* Tunnel IP header size */
		u32 hdr_size;
		/* IP tunnel protocol */
		u8 proto;
	} tun;
};

static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
				struct sk_buff *skb,
				struct flow_offload_tuple *tuple)
{
	__be16 inner_proto = skb->protocol;
	struct vlan_ethhdr *veth;
	struct pppoe_hdr *phdr;
	struct ipv6hdr *ip6h;
	struct iphdr *iph;
	u16 offset = 0;
	int i = 0;

	if (skb_vlan_tag_present(skb)) {
		tuple->encap[i].id = skb_vlan_tag_get(skb);
		tuple->encap[i].proto = skb->vlan_proto;
		i++;
	}
	switch (skb->protocol) {
	case htons(ETH_P_8021Q):
		veth = (struct vlan_ethhdr *)skb_mac_header(skb);
		tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
		tuple->encap[i].proto = skb->protocol;
		inner_proto = veth->h_vlan_encapsulated_proto;
		offset += VLAN_HLEN;
		break;
	case htons(ETH_P_PPP_SES):
		phdr = (struct pppoe_hdr *)skb_network_header(skb);
		tuple->encap[i].id = ntohs(phdr->sid);
		tuple->encap[i].proto = skb->protocol;
		inner_proto = *((__be16 *)(phdr + 1));
		offset += PPPOE_SES_HLEN;
		break;
	}

	switch (inner_proto) {
	case htons(ETH_P_IP):
		iph = (struct iphdr *)(skb_network_header(skb) + offset);
		if (ctx->tun.proto == IPPROTO_IPIP) {
			tuple->tun.dst_v4.s_addr = iph->daddr;
			tuple->tun.src_v4.s_addr = iph->saddr;
			tuple->tun.l3_proto = IPPROTO_IPIP;
		}
		break;
	case htons(ETH_P_IPV6):
		ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
		if (ctx->tun.proto == IPPROTO_IPV6) {
			tuple->tun.dst_v6 = ip6h->daddr;
			tuple->tun.src_v6 = ip6h->saddr;
			tuple->tun.l3_proto = IPPROTO_IPV6;
		}
		break;
	default:
		break;
	}
}

static int nf_flow_tuple_ip(struct nf_flowtable_ctx *ctx, struct sk_buff *skb,
			    struct flow_offload_tuple *tuple)
{
	struct flow_ports *ports;
	unsigned int thoff;
	struct iphdr *iph;
	u8 ipproto;

	if (!pskb_may_pull(skb, sizeof(*iph) + ctx->offset))
		return -1;

	iph = (struct iphdr *)(skb_network_header(skb) + ctx->offset);
	thoff = (iph->ihl * 4);

	if (ip_is_fragment(iph) ||
	    unlikely(ip_has_options(thoff)))
		return -1;

	thoff += ctx->offset;

	ipproto = iph->protocol;
	switch (ipproto) {

Annotation

Implementation Notes