xref: /openbmc/linux/include/net/dst_metadata.h (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2f38a9eb1SThomas Graf #ifndef __NET_DST_METADATA_H
3f38a9eb1SThomas Graf #define __NET_DST_METADATA_H 1
4f38a9eb1SThomas Graf 
5f38a9eb1SThomas Graf #include <linux/skbuff.h>
6f38a9eb1SThomas Graf #include <net/ip_tunnels.h>
70a28bfd4SLior Nahmanson #include <net/macsec.h>
8f38a9eb1SThomas Graf #include <net/dst.h>
9f38a9eb1SThomas Graf 
103fcece12SJakub Kicinski enum metadata_type {
113fcece12SJakub Kicinski 	METADATA_IP_TUNNEL,
123fcece12SJakub Kicinski 	METADATA_HW_PORT_MUX,
130a28bfd4SLior Nahmanson 	METADATA_MACSEC,
145182a5d4SEyal Birger 	METADATA_XFRM,
153fcece12SJakub Kicinski };
163fcece12SJakub Kicinski 
173fcece12SJakub Kicinski struct hw_port_info {
183fcece12SJakub Kicinski 	struct net_device *lower_dev;
193fcece12SJakub Kicinski 	u32 port_id;
203fcece12SJakub Kicinski };
213fcece12SJakub Kicinski 
220a28bfd4SLior Nahmanson struct macsec_info {
230a28bfd4SLior Nahmanson 	sci_t sci;
240a28bfd4SLior Nahmanson };
250a28bfd4SLior Nahmanson 
265182a5d4SEyal Birger struct xfrm_md_info {
275182a5d4SEyal Birger 	u32 if_id;
285182a5d4SEyal Birger 	int link;
29*94151f5aSEyal Birger 	struct dst_entry *dst_orig;
305182a5d4SEyal Birger };
315182a5d4SEyal Birger 
32f38a9eb1SThomas Graf struct metadata_dst {
33f38a9eb1SThomas Graf 	struct dst_entry		dst;
343fcece12SJakub Kicinski 	enum metadata_type		type;
35ee122c79SThomas Graf 	union {
36ee122c79SThomas Graf 		struct ip_tunnel_info	tun_info;
373fcece12SJakub Kicinski 		struct hw_port_info	port_info;
380a28bfd4SLior Nahmanson 		struct macsec_info	macsec_info;
395182a5d4SEyal Birger 		struct xfrm_md_info	xfrm_info;
40ee122c79SThomas Graf 	} u;
41f38a9eb1SThomas Graf };
42f38a9eb1SThomas Graf 
skb_metadata_dst(const struct sk_buff * skb)4332f16369SSimon Horman static inline struct metadata_dst *skb_metadata_dst(const struct sk_buff *skb)
44f38a9eb1SThomas Graf {
45f38a9eb1SThomas Graf 	struct metadata_dst *md_dst = (struct metadata_dst *) skb_dst(skb);
46f38a9eb1SThomas Graf 
47f38a9eb1SThomas Graf 	if (md_dst && md_dst->dst.flags & DST_METADATA)
48f38a9eb1SThomas Graf 		return md_dst;
49f38a9eb1SThomas Graf 
50f38a9eb1SThomas Graf 	return NULL;
51f38a9eb1SThomas Graf }
52f38a9eb1SThomas Graf 
5332f16369SSimon Horman static inline struct ip_tunnel_info *
skb_tunnel_info(const struct sk_buff * skb)5432f16369SSimon Horman skb_tunnel_info(const struct sk_buff *skb)
55ee122c79SThomas Graf {
56ee122c79SThomas Graf 	struct metadata_dst *md_dst = skb_metadata_dst(skb);
5761adedf3SJiri Benc 	struct dst_entry *dst;
58ee122c79SThomas Graf 
593fcece12SJakub Kicinski 	if (md_dst && md_dst->type == METADATA_IP_TUNNEL)
60ee122c79SThomas Graf 		return &md_dst->u.tun_info;
61ee122c79SThomas Graf 
6261adedf3SJiri Benc 	dst = skb_dst(skb);
6367a9c943STaehee Yoo 	if (dst && dst->lwtstate &&
6467a9c943STaehee Yoo 	    (dst->lwtstate->type == LWTUNNEL_ENCAP_IP ||
6567a9c943STaehee Yoo 	     dst->lwtstate->type == LWTUNNEL_ENCAP_IP6))
6661adedf3SJiri Benc 		return lwt_tun_info(dst->lwtstate);
673093fbe7SThomas Graf 
68ee122c79SThomas Graf 	return NULL;
69ee122c79SThomas Graf }
70ee122c79SThomas Graf 
lwt_xfrm_info(struct lwtunnel_state * lwt)712c2493b9SEyal Birger static inline struct xfrm_md_info *lwt_xfrm_info(struct lwtunnel_state *lwt)
722c2493b9SEyal Birger {
732c2493b9SEyal Birger 	return (struct xfrm_md_info *)lwt->data;
742c2493b9SEyal Birger }
752c2493b9SEyal Birger 
skb_xfrm_md_info(const struct sk_buff * skb)765182a5d4SEyal Birger static inline struct xfrm_md_info *skb_xfrm_md_info(const struct sk_buff *skb)
775182a5d4SEyal Birger {
785182a5d4SEyal Birger 	struct metadata_dst *md_dst = skb_metadata_dst(skb);
792c2493b9SEyal Birger 	struct dst_entry *dst;
805182a5d4SEyal Birger 
815182a5d4SEyal Birger 	if (md_dst && md_dst->type == METADATA_XFRM)
825182a5d4SEyal Birger 		return &md_dst->u.xfrm_info;
835182a5d4SEyal Birger 
842c2493b9SEyal Birger 	dst = skb_dst(skb);
852c2493b9SEyal Birger 	if (dst && dst->lwtstate &&
862c2493b9SEyal Birger 	    dst->lwtstate->type == LWTUNNEL_ENCAP_XFRM)
872c2493b9SEyal Birger 		return lwt_xfrm_info(dst->lwtstate);
882c2493b9SEyal Birger 
895182a5d4SEyal Birger 	return NULL;
905182a5d4SEyal Birger }
915182a5d4SEyal Birger 
skb_valid_dst(const struct sk_buff * skb)92f38a9eb1SThomas Graf static inline bool skb_valid_dst(const struct sk_buff *skb)
93f38a9eb1SThomas Graf {
94f38a9eb1SThomas Graf 	struct dst_entry *dst = skb_dst(skb);
95f38a9eb1SThomas Graf 
96f38a9eb1SThomas Graf 	return dst && !(dst->flags & DST_METADATA);
97f38a9eb1SThomas Graf }
98f38a9eb1SThomas Graf 
skb_metadata_dst_cmp(const struct sk_buff * skb_a,const struct sk_buff * skb_b)99ce87fc6cSJesse Gross static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
100ce87fc6cSJesse Gross 				       const struct sk_buff *skb_b)
101ce87fc6cSJesse Gross {
102ce87fc6cSJesse Gross 	const struct metadata_dst *a, *b;
103ce87fc6cSJesse Gross 
104ce87fc6cSJesse Gross 	if (!(skb_a->_skb_refdst | skb_b->_skb_refdst))
105ce87fc6cSJesse Gross 		return 0;
106ce87fc6cSJesse Gross 
107ce87fc6cSJesse Gross 	a = (const struct metadata_dst *) skb_dst(skb_a);
108ce87fc6cSJesse Gross 	b = (const struct metadata_dst *) skb_dst(skb_b);
109ce87fc6cSJesse Gross 
1103fcece12SJakub Kicinski 	if (!a != !b || a->type != b->type)
111ce87fc6cSJesse Gross 		return 1;
112ce87fc6cSJesse Gross 
1133fcece12SJakub Kicinski 	switch (a->type) {
1143fcece12SJakub Kicinski 	case METADATA_HW_PORT_MUX:
1153fcece12SJakub Kicinski 		return memcmp(&a->u.port_info, &b->u.port_info,
1163fcece12SJakub Kicinski 			      sizeof(a->u.port_info));
1173fcece12SJakub Kicinski 	case METADATA_IP_TUNNEL:
118ce87fc6cSJesse Gross 		return memcmp(&a->u.tun_info, &b->u.tun_info,
1193fcece12SJakub Kicinski 			      sizeof(a->u.tun_info) +
1203fcece12SJakub Kicinski 					 a->u.tun_info.options_len);
1210a28bfd4SLior Nahmanson 	case METADATA_MACSEC:
1220a28bfd4SLior Nahmanson 		return memcmp(&a->u.macsec_info, &b->u.macsec_info,
1230a28bfd4SLior Nahmanson 			      sizeof(a->u.macsec_info));
1245182a5d4SEyal Birger 	case METADATA_XFRM:
1255182a5d4SEyal Birger 		return memcmp(&a->u.xfrm_info, &b->u.xfrm_info,
1265182a5d4SEyal Birger 			      sizeof(a->u.xfrm_info));
1273fcece12SJakub Kicinski 	default:
1283fcece12SJakub Kicinski 		return 1;
1293fcece12SJakub Kicinski 	}
130ce87fc6cSJesse Gross }
131ce87fc6cSJesse Gross 
132d71785ffSPaolo Abeni void metadata_dst_free(struct metadata_dst *);
1333fcece12SJakub Kicinski struct metadata_dst *metadata_dst_alloc(u8 optslen, enum metadata_type type,
1343fcece12SJakub Kicinski 					gfp_t flags);
135d66f2b91SJakub Kicinski void metadata_dst_free_percpu(struct metadata_dst __percpu *md_dst);
1363fcece12SJakub Kicinski struct metadata_dst __percpu *
1373fcece12SJakub Kicinski metadata_dst_alloc_percpu(u8 optslen, enum metadata_type type, gfp_t flags);
138f38a9eb1SThomas Graf 
tun_rx_dst(int md_size)1394c222798SPravin B Shelar static inline struct metadata_dst *tun_rx_dst(int md_size)
140c29a70d2SPravin B Shelar {
141c29a70d2SPravin B Shelar 	struct metadata_dst *tun_dst;
142c29a70d2SPravin B Shelar 
1433fcece12SJakub Kicinski 	tun_dst = metadata_dst_alloc(md_size, METADATA_IP_TUNNEL, GFP_ATOMIC);
144c29a70d2SPravin B Shelar 	if (!tun_dst)
145c29a70d2SPravin B Shelar 		return NULL;
146c29a70d2SPravin B Shelar 
1474c222798SPravin B Shelar 	tun_dst->u.tun_info.options_len = 0;
1484c222798SPravin B Shelar 	tun_dst->u.tun_info.mode = 0;
149c29a70d2SPravin B Shelar 	return tun_dst;
150c29a70d2SPravin B Shelar }
151c29a70d2SPravin B Shelar 
tun_dst_unclone(struct sk_buff * skb)152fc4099f1SPravin B Shelar static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb)
153fc4099f1SPravin B Shelar {
154fc4099f1SPravin B Shelar 	struct metadata_dst *md_dst = skb_metadata_dst(skb);
155f63ce5b6STobias Klauser 	int md_size;
156fc4099f1SPravin B Shelar 	struct metadata_dst *new_md;
157fc4099f1SPravin B Shelar 
1583fcece12SJakub Kicinski 	if (!md_dst || md_dst->type != METADATA_IP_TUNNEL)
159fc4099f1SPravin B Shelar 		return ERR_PTR(-EINVAL);
160fc4099f1SPravin B Shelar 
161f63ce5b6STobias Klauser 	md_size = md_dst->u.tun_info.options_len;
1623fcece12SJakub Kicinski 	new_md = metadata_dst_alloc(md_size, METADATA_IP_TUNNEL, GFP_ATOMIC);
163fc4099f1SPravin B Shelar 	if (!new_md)
164fc4099f1SPravin B Shelar 		return ERR_PTR(-ENOMEM);
165fc4099f1SPravin B Shelar 
166fc4099f1SPravin B Shelar 	memcpy(&new_md->u.tun_info, &md_dst->u.tun_info,
167fc4099f1SPravin B Shelar 	       sizeof(struct ip_tunnel_info) + md_size);
168cfc56f85SAntoine Tenart #ifdef CONFIG_DST_CACHE
169cfc56f85SAntoine Tenart 	/* Unclone the dst cache if there is one */
170cfc56f85SAntoine Tenart 	if (new_md->u.tun_info.dst_cache.cache) {
171cfc56f85SAntoine Tenart 		int ret;
172cfc56f85SAntoine Tenart 
173cfc56f85SAntoine Tenart 		ret = dst_cache_init(&new_md->u.tun_info.dst_cache, GFP_ATOMIC);
174cfc56f85SAntoine Tenart 		if (ret) {
175cfc56f85SAntoine Tenart 			metadata_dst_free(new_md);
176cfc56f85SAntoine Tenart 			return ERR_PTR(ret);
177cfc56f85SAntoine Tenart 		}
178cfc56f85SAntoine Tenart 	}
179cfc56f85SAntoine Tenart #endif
180cfc56f85SAntoine Tenart 
181fc4099f1SPravin B Shelar 	skb_dst_drop(skb);
182fc4099f1SPravin B Shelar 	skb_dst_set(skb, &new_md->dst);
183fc4099f1SPravin B Shelar 	return new_md;
184fc4099f1SPravin B Shelar }
185fc4099f1SPravin B Shelar 
skb_tunnel_info_unclone(struct sk_buff * skb)186fc4099f1SPravin B Shelar static inline struct ip_tunnel_info *skb_tunnel_info_unclone(struct sk_buff *skb)
187fc4099f1SPravin B Shelar {
188fc4099f1SPravin B Shelar 	struct metadata_dst *dst;
189fc4099f1SPravin B Shelar 
190fc4099f1SPravin B Shelar 	dst = tun_dst_unclone(skb);
191fc4099f1SPravin B Shelar 	if (IS_ERR(dst))
192fc4099f1SPravin B Shelar 		return NULL;
193fc4099f1SPravin B Shelar 
194fc4099f1SPravin B Shelar 	return &dst->u.tun_info;
195fc4099f1SPravin B Shelar }
196fc4099f1SPravin B Shelar 
__ip_tun_set_dst(__be32 saddr,__be32 daddr,__u8 tos,__u8 ttl,__be16 tp_dst,__be16 flags,__be64 tunnel_id,int md_size)1972ff378b7SAmir Vadai static inline struct metadata_dst *__ip_tun_set_dst(__be32 saddr,
1982ff378b7SAmir Vadai 						    __be32 daddr,
1992ff378b7SAmir Vadai 						    __u8 tos, __u8 ttl,
20024ba898dSHadar Hen Zion 						    __be16 tp_dst,
201c29a70d2SPravin B Shelar 						    __be16 flags,
202c29a70d2SPravin B Shelar 						    __be64 tunnel_id,
203c29a70d2SPravin B Shelar 						    int md_size)
204c29a70d2SPravin B Shelar {
205c29a70d2SPravin B Shelar 	struct metadata_dst *tun_dst;
206c29a70d2SPravin B Shelar 
2074c222798SPravin B Shelar 	tun_dst = tun_rx_dst(md_size);
208c29a70d2SPravin B Shelar 	if (!tun_dst)
209c29a70d2SPravin B Shelar 		return NULL;
210c29a70d2SPravin B Shelar 
2114c222798SPravin B Shelar 	ip_tunnel_key_init(&tun_dst->u.tun_info.key,
2122ff378b7SAmir Vadai 			   saddr, daddr, tos, ttl,
21324ba898dSHadar Hen Zion 			   0, 0, tp_dst, tunnel_id, flags);
214c29a70d2SPravin B Shelar 	return tun_dst;
215c29a70d2SPravin B Shelar }
216c29a70d2SPravin B Shelar 
ip_tun_rx_dst(struct sk_buff * skb,__be16 flags,__be64 tunnel_id,int md_size)2172ff378b7SAmir Vadai static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb,
218c29a70d2SPravin B Shelar 						 __be16 flags,
219c29a70d2SPravin B Shelar 						 __be64 tunnel_id,
220c29a70d2SPravin B Shelar 						 int md_size)
221c29a70d2SPravin B Shelar {
2222ff378b7SAmir Vadai 	const struct iphdr *iph = ip_hdr(skb);
2232ff378b7SAmir Vadai 
2242ff378b7SAmir Vadai 	return __ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl,
22524ba898dSHadar Hen Zion 				0, flags, tunnel_id, md_size);
2262ff378b7SAmir Vadai }
2272ff378b7SAmir Vadai 
__ipv6_tun_set_dst(const struct in6_addr * saddr,const struct in6_addr * daddr,__u8 tos,__u8 ttl,__be16 tp_dst,__be32 label,__be16 flags,__be64 tunnel_id,int md_size)2282ff378b7SAmir Vadai static inline struct metadata_dst *__ipv6_tun_set_dst(const struct in6_addr *saddr,
2292ff378b7SAmir Vadai 						      const struct in6_addr *daddr,
2302ff378b7SAmir Vadai 						      __u8 tos, __u8 ttl,
23124ba898dSHadar Hen Zion 						      __be16 tp_dst,
2322ff378b7SAmir Vadai 						      __be32 label,
2332ff378b7SAmir Vadai 						      __be16 flags,
2342ff378b7SAmir Vadai 						      __be64 tunnel_id,
2352ff378b7SAmir Vadai 						      int md_size)
2362ff378b7SAmir Vadai {
237c29a70d2SPravin B Shelar 	struct metadata_dst *tun_dst;
238c29a70d2SPravin B Shelar 	struct ip_tunnel_info *info;
239c29a70d2SPravin B Shelar 
2404c222798SPravin B Shelar 	tun_dst = tun_rx_dst(md_size);
241c29a70d2SPravin B Shelar 	if (!tun_dst)
242c29a70d2SPravin B Shelar 		return NULL;
243c29a70d2SPravin B Shelar 
244c29a70d2SPravin B Shelar 	info = &tun_dst->u.tun_info;
2454c222798SPravin B Shelar 	info->mode = IP_TUNNEL_INFO_IPV6;
2464c222798SPravin B Shelar 	info->key.tun_flags = flags;
2474c222798SPravin B Shelar 	info->key.tun_id = tunnel_id;
2484c222798SPravin B Shelar 	info->key.tp_src = 0;
24924ba898dSHadar Hen Zion 	info->key.tp_dst = tp_dst;
2504c222798SPravin B Shelar 
2512ff378b7SAmir Vadai 	info->key.u.ipv6.src = *saddr;
2522ff378b7SAmir Vadai 	info->key.u.ipv6.dst = *daddr;
25313461144SDaniel Borkmann 
2542ff378b7SAmir Vadai 	info->key.tos = tos;
2552ff378b7SAmir Vadai 	info->key.ttl = ttl;
2562ff378b7SAmir Vadai 	info->key.label = label;
25713461144SDaniel Borkmann 
258c29a70d2SPravin B Shelar 	return tun_dst;
259c29a70d2SPravin B Shelar }
260c29a70d2SPravin B Shelar 
ipv6_tun_rx_dst(struct sk_buff * skb,__be16 flags,__be64 tunnel_id,int md_size)2612ff378b7SAmir Vadai static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb,
2622ff378b7SAmir Vadai 						   __be16 flags,
2632ff378b7SAmir Vadai 						   __be64 tunnel_id,
2642ff378b7SAmir Vadai 						   int md_size)
2652ff378b7SAmir Vadai {
2662ff378b7SAmir Vadai 	const struct ipv6hdr *ip6h = ipv6_hdr(skb);
2672ff378b7SAmir Vadai 
2682ff378b7SAmir Vadai 	return __ipv6_tun_set_dst(&ip6h->saddr, &ip6h->daddr,
2692ff378b7SAmir Vadai 				  ipv6_get_dsfield(ip6h), ip6h->hop_limit,
27024ba898dSHadar Hen Zion 				  0, ip6_flowlabel(ip6h), flags, tunnel_id,
2712ff378b7SAmir Vadai 				  md_size);
2722ff378b7SAmir Vadai }
273f38a9eb1SThomas Graf #endif /* __NET_DST_METADATA_H */
274