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