Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */
2 : : #ifndef __NET_DST_METADATA_H
3 : : #define __NET_DST_METADATA_H 1
4 : :
5 : : #include <linux/skbuff.h>
6 : : #include <net/ip_tunnels.h>
7 : : #include <net/dst.h>
8 : :
9 : : enum metadata_type {
10 : : METADATA_IP_TUNNEL,
11 : : METADATA_HW_PORT_MUX,
12 : : };
13 : :
14 : : struct hw_port_info {
15 : : struct net_device *lower_dev;
16 : : u32 port_id;
17 : : };
18 : :
19 : : struct metadata_dst {
20 : : struct dst_entry dst;
21 : : enum metadata_type type;
22 : : union {
23 : : struct ip_tunnel_info tun_info;
24 : : struct hw_port_info port_info;
25 : : } u;
26 : : };
27 : :
28 : : static inline struct metadata_dst *skb_metadata_dst(const struct sk_buff *skb)
29 : : {
30 : : struct metadata_dst *md_dst = (struct metadata_dst *) skb_dst(skb);
31 : :
32 [ - + # # : 2638 : if (md_dst && md_dst->dst.flags & DST_METADATA)
# # # # ]
33 : : return md_dst;
34 : :
35 : : return NULL;
36 : : }
37 : :
38 : : static inline struct ip_tunnel_info *
39 : 2638 : skb_tunnel_info(const struct sk_buff *skb)
40 : : {
41 : : struct metadata_dst *md_dst = skb_metadata_dst(skb);
42 : : struct dst_entry *dst;
43 : :
44 [ - + # # ]: 2638 : if (md_dst && md_dst->type == METADATA_IP_TUNNEL)
45 : 0 : return &md_dst->u.tun_info;
46 : :
47 : : dst = skb_dst(skb);
48 [ - + # # ]: 2638 : if (dst && dst->lwtstate)
49 : 0 : return lwt_tun_info(dst->lwtstate);
50 : :
51 : : return NULL;
52 : : }
53 : :
54 : : static inline bool skb_valid_dst(const struct sk_buff *skb)
55 : : {
56 : : struct dst_entry *dst = skb_dst(skb);
57 : :
58 [ + + - + : 17914 : return dst && !(dst->flags & DST_METADATA);
+ + - + ]
59 : : }
60 : :
61 : 0 : static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
62 : : const struct sk_buff *skb_b)
63 : : {
64 : : const struct metadata_dst *a, *b;
65 : :
66 [ # # ]: 0 : if (!(skb_a->_skb_refdst | skb_b->_skb_refdst))
67 : : return 0;
68 : :
69 : : a = (const struct metadata_dst *) skb_dst(skb_a);
70 : : b = (const struct metadata_dst *) skb_dst(skb_b);
71 : :
72 [ # # # # ]: 0 : if (!a != !b || a->type != b->type)
73 : : return 1;
74 : :
75 [ # # # ]: 0 : switch (a->type) {
76 : : case METADATA_HW_PORT_MUX:
77 : 0 : return memcmp(&a->u.port_info, &b->u.port_info,
78 : : sizeof(a->u.port_info));
79 : : case METADATA_IP_TUNNEL:
80 : 0 : return memcmp(&a->u.tun_info, &b->u.tun_info,
81 : : sizeof(a->u.tun_info) +
82 : 0 : a->u.tun_info.options_len);
83 : : default:
84 : : return 1;
85 : : }
86 : : }
87 : :
88 : : void metadata_dst_free(struct metadata_dst *);
89 : : struct metadata_dst *metadata_dst_alloc(u8 optslen, enum metadata_type type,
90 : : gfp_t flags);
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);
94 : :
95 : : static inline struct metadata_dst *tun_rx_dst(int md_size)
96 : : {
97 : : struct metadata_dst *tun_dst;
98 : :
99 : : tun_dst = metadata_dst_alloc(md_size, METADATA_IP_TUNNEL, GFP_ATOMIC);
100 : : if (!tun_dst)
101 : : return NULL;
102 : :
103 : : tun_dst->u.tun_info.options_len = 0;
104 : : tun_dst->u.tun_info.mode = 0;
105 : : return tun_dst;
106 : : }
107 : :
108 : 0 : static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb)
109 : : {
110 : : struct metadata_dst *md_dst = skb_metadata_dst(skb);
111 : : int md_size;
112 : : struct metadata_dst *new_md;
113 : :
114 [ # # # # ]: 0 : if (!md_dst || md_dst->type != METADATA_IP_TUNNEL)
115 : : return ERR_PTR(-EINVAL);
116 : :
117 : 0 : md_size = md_dst->u.tun_info.options_len;
118 : 0 : new_md = metadata_dst_alloc(md_size, METADATA_IP_TUNNEL, GFP_ATOMIC);
119 [ # # ]: 0 : if (!new_md)
120 : : return ERR_PTR(-ENOMEM);
121 : :
122 : 0 : memcpy(&new_md->u.tun_info, &md_dst->u.tun_info,
123 : : sizeof(struct ip_tunnel_info) + md_size);
124 : 0 : skb_dst_drop(skb);
125 : 0 : dst_hold(&new_md->dst);
126 : : skb_dst_set(skb, &new_md->dst);
127 : 0 : return new_md;
128 : : }
129 : :
130 : : static inline struct ip_tunnel_info *skb_tunnel_info_unclone(struct sk_buff *skb)
131 : : {
132 : : struct metadata_dst *dst;
133 : :
134 : 0 : dst = tun_dst_unclone(skb);
135 [ # # ]: 0 : if (IS_ERR(dst))
136 : : return NULL;
137 : :
138 : 0 : return &dst->u.tun_info;
139 : : }
140 : :
141 : : static inline struct metadata_dst *__ip_tun_set_dst(__be32 saddr,
142 : : __be32 daddr,
143 : : __u8 tos, __u8 ttl,
144 : : __be16 tp_dst,
145 : : __be16 flags,
146 : : __be64 tunnel_id,
147 : : int md_size)
148 : : {
149 : : struct metadata_dst *tun_dst;
150 : :
151 : : tun_dst = tun_rx_dst(md_size);
152 : : if (!tun_dst)
153 : : return NULL;
154 : :
155 : : ip_tunnel_key_init(&tun_dst->u.tun_info.key,
156 : : saddr, daddr, tos, ttl,
157 : : 0, 0, tp_dst, tunnel_id, flags);
158 : : return tun_dst;
159 : : }
160 : :
161 : : static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb,
162 : : __be16 flags,
163 : : __be64 tunnel_id,
164 : : int md_size)
165 : : {
166 : : const struct iphdr *iph = ip_hdr(skb);
167 : :
168 : : return __ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl,
169 : : 0, flags, tunnel_id, md_size);
170 : : }
171 : :
172 : : static inline struct metadata_dst *__ipv6_tun_set_dst(const struct in6_addr *saddr,
173 : : const struct in6_addr *daddr,
174 : : __u8 tos, __u8 ttl,
175 : : __be16 tp_dst,
176 : : __be32 label,
177 : : __be16 flags,
178 : : __be64 tunnel_id,
179 : : int md_size)
180 : : {
181 : : struct metadata_dst *tun_dst;
182 : : struct ip_tunnel_info *info;
183 : :
184 : : tun_dst = tun_rx_dst(md_size);
185 : : if (!tun_dst)
186 : : return NULL;
187 : :
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;
194 : :
195 : : info->key.u.ipv6.src = *saddr;
196 : : info->key.u.ipv6.dst = *daddr;
197 : :
198 : : info->key.tos = tos;
199 : : info->key.ttl = ttl;
200 : : info->key.label = label;
201 : :
202 : : return tun_dst;
203 : : }
204 : :
205 : : static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb,
206 : : __be16 flags,
207 : : __be64 tunnel_id,
208 : : int md_size)
209 : : {
210 : : const struct ipv6hdr *ip6h = ipv6_hdr(skb);
211 : :
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,
215 : : md_size);
216 : : }
217 : : #endif /* __NET_DST_METADATA_H */
|