Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfrm: Remove xfrmi interface ID from flowi

In order to remove performance impact of having the extra u32 in every
single flowi, this change removes the flowi_xfrm struct, prefering to
take the if_id as a method parameter where needed.

In the inbound direction, if_id is only needed during the
__xfrm_check_policy() function, and the if_id can be determined at that
point based on the skb. As such, xfrmi_decode_session() is only called
with the skb in __xfrm_check_policy().

In the outbound direction, the only place where if_id is needed is the
xfrm_lookup() call in xfrmi_xmit2(). With this change, the if_id is
directly passed into the xfrm_lookup_with_ifid() call. All existing
callers can still call xfrm_lookup(), which uses a default if_id of 0.

This change does not change any behavior of XFRMIs except for improving
overall system performance via flowi size reduction.

This change has been tested against the Android Kernel Networking Tests:

https://android.googlesource.com/kernel/tests/+/master/net/test

Signed-off-by: Benedict Wong <benedictwong@google.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>

authored by

Benedict Wong and committed by
Steffen Klassert
bc56b334 fcb662de

+83 -47
+14
include/net/dst.h
··· 475 475 return dst_orig; 476 476 } 477 477 478 + static inline struct dst_entry * 479 + xfrm_lookup_with_ifid(struct net *net, struct dst_entry *dst_orig, 480 + const struct flowi *fl, const struct sock *sk, 481 + int flags, u32 if_id) 482 + { 483 + return dst_orig; 484 + } 485 + 478 486 static inline struct dst_entry *xfrm_lookup_route(struct net *net, 479 487 struct dst_entry *dst_orig, 480 488 const struct flowi *fl, ··· 501 493 struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, 502 494 const struct flowi *fl, const struct sock *sk, 503 495 int flags); 496 + 497 + struct dst_entry *xfrm_lookup_with_ifid(struct net *net, 498 + struct dst_entry *dst_orig, 499 + const struct flowi *fl, 500 + const struct sock *sk, int flags, 501 + u32 if_id); 504 502 505 503 struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig, 506 504 const struct flowi *fl, const struct sock *sk,
-9
include/net/flow.h
··· 26 26 __be64 tun_id; 27 27 }; 28 28 29 - struct flowi_xfrm { 30 - __u32 if_id; 31 - }; 32 - 33 29 struct flowi_common { 34 30 int flowic_oif; 35 31 int flowic_iif; ··· 39 43 #define FLOWI_FLAG_SKIP_NH_OIF 0x04 40 44 __u32 flowic_secid; 41 45 struct flowi_tunnel flowic_tun_key; 42 - struct flowi_xfrm xfrm; 43 46 kuid_t flowic_uid; 44 47 }; 45 48 ··· 78 83 #define flowi4_secid __fl_common.flowic_secid 79 84 #define flowi4_tun_key __fl_common.flowic_tun_key 80 85 #define flowi4_uid __fl_common.flowic_uid 81 - #define flowi4_xfrm __fl_common.xfrm 82 86 83 87 /* (saddr,daddr) must be grouped, same order as in IP header */ 84 88 __be32 saddr; ··· 109 115 fl4->flowi4_flags = flags; 110 116 fl4->flowi4_secid = 0; 111 117 fl4->flowi4_tun_key.tun_id = 0; 112 - fl4->flowi4_xfrm.if_id = 0; 113 118 fl4->flowi4_uid = uid; 114 119 fl4->daddr = daddr; 115 120 fl4->saddr = saddr; ··· 138 145 #define flowi6_secid __fl_common.flowic_secid 139 146 #define flowi6_tun_key __fl_common.flowic_tun_key 140 147 #define flowi6_uid __fl_common.flowic_uid 141 - #define flowi6_xfrm __fl_common.xfrm 142 148 struct in6_addr daddr; 143 149 struct in6_addr saddr; 144 150 /* Note: flowi6_tos is encoded in flowlabel, too. */ ··· 185 193 #define flowi_secid u.__fl_common.flowic_secid 186 194 #define flowi_tun_key u.__fl_common.flowic_tun_key 187 195 #define flowi_uid u.__fl_common.flowic_uid 188 - #define flowi_xfrm u.__fl_common.xfrm 189 196 } __attribute__((__aligned__(BITS_PER_LONG/8))); 190 197 191 198 static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4)
+1 -1
include/net/xfrm.h
··· 1557 1557 const struct flowi *fl, 1558 1558 struct xfrm_tmpl *tmpl, 1559 1559 struct xfrm_policy *pol, int *err, 1560 - unsigned short family); 1560 + unsigned short family, u32 if_id); 1561 1561 struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id, 1562 1562 xfrm_address_t *daddr, 1563 1563 xfrm_address_t *saddr,
+1 -3
net/xfrm/xfrm_interface.c
··· 307 307 if (!dst) 308 308 goto tx_err_link_failure; 309 309 310 - fl->flowi_xfrm.if_id = xi->p.if_id; 311 - 312 310 dst_hold(dst); 313 - dst = xfrm_lookup(xi->net, dst, fl, NULL, 0); 311 + dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, xi->p.if_id); 314 312 if (IS_ERR(dst)) { 315 313 err = PTR_ERR(dst); 316 314 dst = NULL;
+66 -32
net/xfrm/xfrm_policy.c
··· 1068 1068 */ 1069 1069 static int xfrm_policy_match(const struct xfrm_policy *pol, 1070 1070 const struct flowi *fl, 1071 - u8 type, u16 family, int dir) 1071 + u8 type, u16 family, int dir, u32 if_id) 1072 1072 { 1073 1073 const struct xfrm_selector *sel = &pol->selector; 1074 1074 int ret = -ESRCH; 1075 1075 bool match; 1076 1076 1077 1077 if (pol->family != family || 1078 - pol->if_id != fl->flowi_xfrm.if_id || 1078 + pol->if_id != if_id || 1079 1079 (fl->flowi_mark & pol->mark.m) != pol->mark.v || 1080 1080 pol->type != type) 1081 1081 return ret; ··· 1090 1090 1091 1091 static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, 1092 1092 const struct flowi *fl, 1093 - u16 family, u8 dir) 1093 + u16 family, u8 dir, 1094 + u32 if_id) 1094 1095 { 1095 1096 int err; 1096 1097 struct xfrm_policy *pol, *ret; ··· 1115 1114 priority = ~0U; 1116 1115 ret = NULL; 1117 1116 hlist_for_each_entry_rcu(pol, chain, bydst) { 1118 - err = xfrm_policy_match(pol, fl, type, family, dir); 1117 + err = xfrm_policy_match(pol, fl, type, family, dir, if_id); 1119 1118 if (err) { 1120 1119 if (err == -ESRCH) 1121 1120 continue; ··· 1134 1133 if ((pol->priority >= priority) && ret) 1135 1134 break; 1136 1135 1137 - err = xfrm_policy_match(pol, fl, type, family, dir); 1136 + err = xfrm_policy_match(pol, fl, type, family, dir, if_id); 1138 1137 if (err) { 1139 1138 if (err == -ESRCH) 1140 1139 continue; ··· 1159 1158 return ret; 1160 1159 } 1161 1160 1162 - static struct xfrm_policy * 1163 - xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir) 1161 + static struct xfrm_policy *xfrm_policy_lookup(struct net *net, 1162 + const struct flowi *fl, 1163 + u16 family, u8 dir, u32 if_id) 1164 1164 { 1165 1165 #ifdef CONFIG_XFRM_SUB_POLICY 1166 1166 struct xfrm_policy *pol; 1167 1167 1168 - pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir); 1168 + pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, 1169 + dir, if_id); 1169 1170 if (pol != NULL) 1170 1171 return pol; 1171 1172 #endif 1172 - return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir); 1173 + return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, 1174 + dir, if_id); 1173 1175 } 1174 1176 1175 1177 static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir, 1176 - const struct flowi *fl, u16 family) 1178 + const struct flowi *fl, 1179 + u16 family, u32 if_id) 1177 1180 { 1178 1181 struct xfrm_policy *pol; 1179 1182 ··· 1196 1191 match = xfrm_selector_match(&pol->selector, fl, family); 1197 1192 if (match) { 1198 1193 if ((sk->sk_mark & pol->mark.m) != pol->mark.v || 1199 - pol->if_id != fl->flowi_xfrm.if_id) { 1194 + pol->if_id != if_id) { 1200 1195 pol = NULL; 1201 1196 goto out; 1202 1197 } ··· 1410 1405 } 1411 1406 } 1412 1407 1413 - x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); 1408 + x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, 1409 + family, policy->if_id); 1414 1410 1415 1411 if (x && x->km.state == XFRM_STATE_VALID) { 1416 1412 xfrm[nx++] = x; ··· 1714 1708 pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]), 1715 1709 XFRM_POLICY_TYPE_MAIN, 1716 1710 fl, family, 1717 - XFRM_POLICY_OUT); 1711 + XFRM_POLICY_OUT, 1712 + pols[0]->if_id); 1718 1713 if (pols[1]) { 1719 1714 if (IS_ERR(pols[1])) { 1720 1715 xfrm_pols_put(pols, *num_pols); ··· 1949 1942 goto out; 1950 1943 } 1951 1944 1952 - static struct xfrm_dst * 1953 - xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, struct xfrm_flo *xflo) 1945 + static struct xfrm_dst *xfrm_bundle_lookup(struct net *net, 1946 + const struct flowi *fl, 1947 + u16 family, u8 dir, 1948 + struct xfrm_flo *xflo, u32 if_id) 1954 1949 { 1955 1950 struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; 1956 1951 int num_pols = 0, num_xfrms = 0, err; ··· 1961 1952 /* Resolve policies to use if we couldn't get them from 1962 1953 * previous cache entry */ 1963 1954 num_pols = 1; 1964 - pols[0] = xfrm_policy_lookup(net, fl, family, dir); 1955 + pols[0] = xfrm_policy_lookup(net, fl, family, dir, if_id); 1965 1956 err = xfrm_expand_policies(fl, family, pols, 1966 1957 &num_pols, &num_xfrms); 1967 1958 if (err < 0) ··· 2029 2020 return ret; 2030 2021 } 2031 2022 2032 - /* Main function: finds/creates a bundle for given flow. 2023 + /* Finds/creates a bundle for given flow and if_id 2033 2024 * 2034 2025 * At the moment we eat a raw IP route. Mostly to speed up lookups 2035 2026 * on interfaces with disabled IPsec. 2027 + * 2028 + * xfrm_lookup uses an if_id of 0 by default, and is provided for 2029 + * compatibility 2036 2030 */ 2037 - struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, 2038 - const struct flowi *fl, 2039 - const struct sock *sk, int flags) 2031 + struct dst_entry *xfrm_lookup_with_ifid(struct net *net, 2032 + struct dst_entry *dst_orig, 2033 + const struct flowi *fl, 2034 + const struct sock *sk, 2035 + int flags, u32 if_id) 2040 2036 { 2041 2037 struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; 2042 2038 struct xfrm_dst *xdst; ··· 2057 2043 sk = sk_const_to_full_sk(sk); 2058 2044 if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { 2059 2045 num_pols = 1; 2060 - pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family); 2046 + pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family, 2047 + if_id); 2061 2048 err = xfrm_expand_policies(fl, family, pols, 2062 2049 &num_pols, &num_xfrms); 2063 2050 if (err < 0) ··· 2102 2087 !net->xfrm.policy_count[XFRM_POLICY_OUT]) 2103 2088 goto nopol; 2104 2089 2105 - xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo); 2090 + xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo, if_id); 2106 2091 if (xdst == NULL) 2107 2092 goto nopol; 2108 2093 if (IS_ERR(xdst)) { ··· 2182 2167 dst_release(dst_orig); 2183 2168 xfrm_pols_put(pols, drop_pols); 2184 2169 return ERR_PTR(err); 2170 + } 2171 + EXPORT_SYMBOL(xfrm_lookup_with_ifid); 2172 + 2173 + /* Main function: finds/creates a bundle for given flow. 2174 + * 2175 + * At the moment we eat a raw IP route. Mostly to speed up lookups 2176 + * on interfaces with disabled IPsec. 2177 + */ 2178 + struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, 2179 + const struct flowi *fl, const struct sock *sk, 2180 + int flags) 2181 + { 2182 + return xfrm_lookup_with_ifid(net, dst_orig, fl, sk, flags, 0); 2185 2183 } 2186 2184 EXPORT_SYMBOL(xfrm_lookup); 2187 2185 ··· 2285 2257 unsigned int family, int reverse) 2286 2258 { 2287 2259 const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); 2288 - const struct xfrm_if_cb *ifcb = xfrm_if_get_cb(); 2289 - struct xfrm_if *xi; 2290 2260 int err; 2291 2261 2292 2262 if (unlikely(afinfo == NULL)) 2293 2263 return -EAFNOSUPPORT; 2294 2264 2295 2265 afinfo->decode_session(skb, fl, reverse); 2296 - if (ifcb) { 2297 - xi = ifcb->decode_session(skb); 2298 - if (xi) 2299 - fl->flowi_xfrm.if_id = xi->p.if_id; 2300 - } 2301 2266 2302 2267 err = security_xfrm_decode_session(skb, &fl->flowi_secid); 2303 2268 rcu_read_unlock(); ··· 2322 2301 int reverse; 2323 2302 struct flowi fl; 2324 2303 int xerr_idx = -1; 2304 + const struct xfrm_if_cb *ifcb; 2305 + struct xfrm_if *xi; 2306 + u32 if_id = 0; 2307 + 2308 + rcu_read_lock(); 2309 + ifcb = xfrm_if_get_cb(); 2310 + 2311 + if (ifcb) { 2312 + xi = ifcb->decode_session(skb); 2313 + if (xi) 2314 + if_id = xi->p.if_id; 2315 + } 2316 + rcu_read_unlock(); 2325 2317 2326 2318 reverse = dir & ~XFRM_POLICY_MASK; 2327 2319 dir &= XFRM_POLICY_MASK; ··· 2362 2328 pol = NULL; 2363 2329 sk = sk_to_full_sk(sk); 2364 2330 if (sk && sk->sk_policy[dir]) { 2365 - pol = xfrm_sk_policy_lookup(sk, dir, &fl, family); 2331 + pol = xfrm_sk_policy_lookup(sk, dir, &fl, family, if_id); 2366 2332 if (IS_ERR(pol)) { 2367 2333 XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); 2368 2334 return 0; ··· 2370 2336 } 2371 2337 2372 2338 if (!pol) 2373 - pol = xfrm_policy_lookup(net, &fl, family, dir); 2339 + pol = xfrm_policy_lookup(net, &fl, family, dir, if_id); 2374 2340 2375 2341 if (IS_ERR(pol)) { 2376 2342 XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); ··· 2394 2360 if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { 2395 2361 pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, 2396 2362 &fl, family, 2397 - XFRM_POLICY_IN); 2363 + XFRM_POLICY_IN, if_id); 2398 2364 if (pols[1]) { 2399 2365 if (IS_ERR(pols[1])) { 2400 2366 XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
+1 -2
net/xfrm/xfrm_state.c
··· 930 930 xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, 931 931 const struct flowi *fl, struct xfrm_tmpl *tmpl, 932 932 struct xfrm_policy *pol, int *err, 933 - unsigned short family) 933 + unsigned short family, u32 if_id) 934 934 { 935 935 static xfrm_address_t saddr_wildcard = { }; 936 936 struct net *net = xp_net(pol); ··· 940 940 int error = 0; 941 941 struct xfrm_state *best = NULL; 942 942 u32 mark = pol->mark.v & pol->mark.m; 943 - u32 if_id = fl->flowi_xfrm.if_id; 944 943 unsigned short encap_family = tmpl->encap_family; 945 944 unsigned int sequence; 946 945 struct km_event c;