1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef __NET_DST_METADATA_H
3 #define __NET_DST_METADATA_H 1
5 #include <linux/skbuff.h>
6 #include <net/ip_tunnels.h>
15 struct net_device
*lower_dev
;
21 enum metadata_type type
;
23 struct ip_tunnel_info tun_info
;
24 struct hw_port_info port_info
;
28 static inline struct metadata_dst
*skb_metadata_dst(const struct sk_buff
*skb
)
30 struct metadata_dst
*md_dst
= (struct metadata_dst
*) skb_dst(skb
);
32 if (md_dst
&& md_dst
->dst
.flags
& DST_METADATA
)
38 static inline struct ip_tunnel_info
*
39 skb_tunnel_info(const struct sk_buff
*skb
)
41 struct metadata_dst
*md_dst
= skb_metadata_dst(skb
);
42 struct dst_entry
*dst
;
44 if (md_dst
&& md_dst
->type
== METADATA_IP_TUNNEL
)
45 return &md_dst
->u
.tun_info
;
48 if (dst
&& dst
->lwtstate
)
49 return lwt_tun_info(dst
->lwtstate
);
54 static inline bool skb_valid_dst(const struct sk_buff
*skb
)
56 struct dst_entry
*dst
= skb_dst(skb
);
58 return dst
&& !(dst
->flags
& DST_METADATA
);
61 static inline int skb_metadata_dst_cmp(const struct sk_buff
*skb_a
,
62 const struct sk_buff
*skb_b
)
64 const struct metadata_dst
*a
, *b
;
66 if (!(skb_a
->_skb_refdst
| skb_b
->_skb_refdst
))
69 a
= (const struct metadata_dst
*) skb_dst(skb_a
);
70 b
= (const struct metadata_dst
*) skb_dst(skb_b
);
72 if (!a
!= !b
|| a
->type
!= b
->type
)
76 case METADATA_HW_PORT_MUX
:
77 return memcmp(&a
->u
.port_info
, &b
->u
.port_info
,
78 sizeof(a
->u
.port_info
));
79 case METADATA_IP_TUNNEL
:
80 return memcmp(&a
->u
.tun_info
, &b
->u
.tun_info
,
81 sizeof(a
->u
.tun_info
) +
82 a
->u
.tun_info
.options_len
);
88 void metadata_dst_free(struct metadata_dst
*);
89 struct metadata_dst
*metadata_dst_alloc(u8 optslen
, enum metadata_type type
,
91 void metadata_dst_free_percpu(struct metadata_dst __percpu
*md_dst
);
92 struct metadata_dst __percpu
*
93 metadata_dst_alloc_percpu(u8 optslen
, enum metadata_type type
, gfp_t flags
);
95 static inline struct metadata_dst
*tun_rx_dst(int md_size
)
97 struct metadata_dst
*tun_dst
;
99 tun_dst
= metadata_dst_alloc(md_size
, METADATA_IP_TUNNEL
, GFP_ATOMIC
);
103 tun_dst
->u
.tun_info
.options_len
= 0;
104 tun_dst
->u
.tun_info
.mode
= 0;
108 static inline struct metadata_dst
*tun_dst_unclone(struct sk_buff
*skb
)
110 struct metadata_dst
*md_dst
= skb_metadata_dst(skb
);
112 struct metadata_dst
*new_md
;
114 if (!md_dst
|| md_dst
->type
!= METADATA_IP_TUNNEL
)
115 return ERR_PTR(-EINVAL
);
117 md_size
= md_dst
->u
.tun_info
.options_len
;
118 new_md
= metadata_dst_alloc(md_size
, METADATA_IP_TUNNEL
, GFP_ATOMIC
);
120 return ERR_PTR(-ENOMEM
);
122 memcpy(&new_md
->u
.tun_info
, &md_dst
->u
.tun_info
,
123 sizeof(struct ip_tunnel_info
) + md_size
);
125 dst_hold(&new_md
->dst
);
126 skb_dst_set(skb
, &new_md
->dst
);
130 static inline struct ip_tunnel_info
*skb_tunnel_info_unclone(struct sk_buff
*skb
)
132 struct metadata_dst
*dst
;
134 dst
= tun_dst_unclone(skb
);
138 return &dst
->u
.tun_info
;
141 static inline struct metadata_dst
*__ip_tun_set_dst(__be32 saddr
,
149 struct metadata_dst
*tun_dst
;
151 tun_dst
= tun_rx_dst(md_size
);
155 ip_tunnel_key_init(&tun_dst
->u
.tun_info
.key
,
156 saddr
, daddr
, tos
, ttl
,
157 0, 0, tp_dst
, tunnel_id
, flags
);
161 static inline struct metadata_dst
*ip_tun_rx_dst(struct sk_buff
*skb
,
166 const struct iphdr
*iph
= ip_hdr(skb
);
168 return __ip_tun_set_dst(iph
->saddr
, iph
->daddr
, iph
->tos
, iph
->ttl
,
169 0, flags
, tunnel_id
, md_size
);
172 static inline struct metadata_dst
*__ipv6_tun_set_dst(const struct in6_addr
*saddr
,
173 const struct in6_addr
*daddr
,
181 struct metadata_dst
*tun_dst
;
182 struct ip_tunnel_info
*info
;
184 tun_dst
= tun_rx_dst(md_size
);
188 info
= &tun_dst
->u
.tun_info
;
189 info
->mode
= IP_TUNNEL_INFO_IPV6
;
190 info
->key
.tun_flags
= flags
;
191 info
->key
.tun_id
= tunnel_id
;
192 info
->key
.tp_src
= 0;
193 info
->key
.tp_dst
= tp_dst
;
195 info
->key
.u
.ipv6
.src
= *saddr
;
196 info
->key
.u
.ipv6
.dst
= *daddr
;
200 info
->key
.label
= label
;
205 static inline struct metadata_dst
*ipv6_tun_rx_dst(struct sk_buff
*skb
,
210 const struct ipv6hdr
*ip6h
= ipv6_hdr(skb
);
212 return __ipv6_tun_set_dst(&ip6h
->saddr
, &ip6h
->daddr
,
213 ipv6_get_dsfield(ip6h
), ip6h
->hop_limit
,
214 0, ip6_flowlabel(ip6h
), flags
, tunnel_id
,
217 #endif /* __NET_DST_METADATA_H */