net/ipv6/seg6_iptunnel.c

Source file repositories/reference/linux-study-clean/net/ipv6/seg6_iptunnel.c

File Facts

System
Linux kernel
Corpus path
net/ipv6/seg6_iptunnel.c
Extension
.c
Size
21161 bytes
Lines
852
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 seg6_lwt {
	struct dst_cache cache_input;
	struct dst_cache cache_output;
	struct in6_addr tunsrc;
	struct seg6_iptunnel_encap tuninfo[];
};

static inline struct seg6_lwt *seg6_lwt_lwtunnel(struct lwtunnel_state *lwt)
{
	return (struct seg6_lwt *)lwt->data;
}

static inline struct seg6_iptunnel_encap *
seg6_encap_lwtunnel(struct lwtunnel_state *lwt)
{
	return seg6_lwt_lwtunnel(lwt)->tuninfo;
}

static const struct nla_policy seg6_iptunnel_policy[SEG6_IPTUNNEL_MAX + 1] = {
	[SEG6_IPTUNNEL_SRH]	= { .type = NLA_BINARY },
	[SEG6_IPTUNNEL_SRC]	= NLA_POLICY_EXACT_LEN(sizeof(struct in6_addr)),
};

static int nla_put_srh(struct sk_buff *skb, int attrtype,
		       struct seg6_iptunnel_encap *tuninfo)
{
	struct seg6_iptunnel_encap *data;
	struct nlattr *nla;
	int len;

	len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);

	nla = nla_reserve(skb, attrtype, len);
	if (!nla)
		return -EMSGSIZE;

	data = nla_data(nla);
	memcpy(data, tuninfo, len);

	return 0;
}

static void set_tun_src(struct net *net, struct net_device *dev,
			struct in6_addr *daddr, struct in6_addr *saddr,
			struct in6_addr *route_tunsrc)
{
	struct seg6_pernet_data *sdata = seg6_pernet(net);
	struct in6_addr *tun_src;

	/* Priority order to select tunnel source address:
	 *  1. per route source address (if configured)
	 *  2. per network namespace source address (if configured)
	 *  3. dynamic resolution
	 */
	if (route_tunsrc && !ipv6_addr_any(route_tunsrc)) {
		memcpy(saddr, route_tunsrc, sizeof(struct in6_addr));
	} else {
		rcu_read_lock();
		tun_src = rcu_dereference(sdata->tun_src);

		if (!ipv6_addr_any(tun_src)) {
			memcpy(saddr, tun_src, sizeof(struct in6_addr));
		} else {
			ipv6_dev_get_saddr(net, dev, daddr,
					   IPV6_PREFER_SRC_PUBLIC, saddr);
		}

		rcu_read_unlock();
	}
}

/* Compute flowlabel for outer IPv6 header */
static __be32 seg6_make_flowlabel(struct net *net, struct sk_buff *skb,
				  struct ipv6hdr *inner_hdr)
{
	int do_flowlabel = net->ipv6.sysctl.seg6_flowlabel;
	__be32 flowlabel = 0;
	u32 hash;

	if (do_flowlabel > 0) {
		hash = skb_get_hash(skb);
		hash = rol32(hash, 16);
		flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK;
	} else if (!do_flowlabel && skb->protocol == htons(ETH_P_IPV6)) {
		flowlabel = ip6_flowlabel(inner_hdr);
	}
	return flowlabel;
}

static int __seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,

Annotation

Implementation Notes