Steffen Klassert says: ==================== pull request (net-next): ipsec-next 2017-08-21 1) Support RX checksum with IPsec crypto offload for esp4/esp6. From Ilan Tayari. 2) Fixup IPv6 checksums when doing IPsec crypto offload. From Yossi Kuperman. 3) Auto load the xfrom offload modules if a user installs a SA that requests IPsec offload. From Ilan Tayari. 4) Clear RX offload informations in xfrm_input to not confuse the TX path with stale offload informations. From Ilan Tayari. 5) Allow IPsec GSO for local sockets if the crypto operation will be offloaded. 6) Support setting of an output mark to the xfrm_state. This mark can be used to to do the tunnel route lookup. From Lorenzo Colitti. ====================
Unified · Split
| @@ -43,6 +43,8 @@ · 42 unmodified lines | ||
| 43 | 43 | MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap)) |
| 44 | 44 | #define MODULE_ALIAS_XFRM_TYPE(family, proto) \ |
| 45 | 45 | MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(proto)) |
| 46 | +#define MODULE_ALIAS_XFRM_OFFLOAD_TYPE(family, proto) \ | |
| 47 | + MODULE_ALIAS("xfrm-offload-" __stringify(family) "-" __stringify(proto)) | |
| 46 | 48 | |
| 47 | 49 | #ifdef CONFIG_XFRM_STATISTICS |
| 48 | 50 | #define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field) |
| @@ -163,6 +165,7 @@ struct xfrm_state { · 114 unmodified lines | ||
| 163 | 165 | int header_len; |
| 164 | 166 | int trailer_len; |
| 165 | 167 | u32 extra_flags; |
| 168 | + u32 output_mark; | |
| 166 | 169 | } props; |
| 167 | 170 | |
| 168 | 171 | struct xfrm_lifetime_cfg lft; |
| @@ -296,10 +299,12 @@ struct xfrm_policy_afinfo { · 127 unmodified lines | ||
| 296 | 299 | struct dst_entry *(*dst_lookup)(struct net *net, |
| 297 | 300 | int tos, int oif, |
| 298 | 301 | const xfrm_address_t *saddr, |
| 299 | − const xfrm_address_t *daddr); | |
| 302 | + const xfrm_address_t *daddr, | |
| 303 | + u32 mark); | |
| 300 | 304 | int (*get_saddr)(struct net *net, int oif, |
| 301 | 305 | xfrm_address_t *saddr, |
| 302 | − xfrm_address_t *daddr); | |
| 306 | + xfrm_address_t *daddr, | |
| 307 | + u32 mark); | |
| 303 | 308 | void (*decode_session)(struct sk_buff *skb, |
| 304 | 309 | struct flowi *fl, |
| 305 | 310 | int reverse); |
| @@ -1558,7 +1563,7 @@ void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si); · 1252 unmodified lines | ||
| 1558 | 1563 | u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq); |
| 1559 | 1564 | int xfrm_init_replay(struct xfrm_state *x); |
| 1560 | 1565 | int xfrm_state_mtu(struct xfrm_state *x, int mtu); |
| 1561 | −int __xfrm_init_state(struct xfrm_state *x, bool init_replay); | |
| 1566 | +int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload); | |
| 1562 | 1567 | int xfrm_init_state(struct xfrm_state *x); |
| 1563 | 1568 | int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); |
| 1564 | 1569 | int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type); |
| @@ -1638,7 +1643,7 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) · 73 unmodified lines | ||
| 1638 | 1643 | struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif, |
| 1639 | 1644 | const xfrm_address_t *saddr, |
| 1640 | 1645 | const xfrm_address_t *daddr, |
| 1641 | − int family); | |
| 1646 | + int family, u32 mark); | |
| 1642 | 1647 | |
| 1643 | 1648 | struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp); |
| 1644 | 1649 | |
| @@ -1856,6 +1861,20 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, · 211 unmodified lines | ||
| 1856 | 1861 | struct xfrm_user_offload *xuo); |
| 1857 | 1862 | bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x); |
| 1858 | 1863 | |
| 1864 | +static inline bool xfrm_dst_offload_ok(struct dst_entry *dst) | |
| 1865 | +{ | |
| 1866 | + struct xfrm_state *x = dst->xfrm; | |
| 1867 | + | |
| 1868 | + if (!x || !x->type_offload) | |
| 1869 | + return false; | |
| 1870 | + | |
| 1871 | + if (x->xso.offload_handle && (x->xso.dev == dst->path->dev) && | |
| 1872 | + !dst->child->xfrm) | |
| 1873 | + return true; | |
| 1874 | + | |
| 1875 | + return false; | |
| 1876 | +} | |
| 1877 | + | |
| 1859 | 1878 | static inline void xfrm_dev_state_delete(struct xfrm_state *x) |
| 1860 | 1879 | { |
| 1861 | 1880 | struct xfrm_state_offload *xso = &x->xso; |
| @@ -1898,6 +1917,11 @@ static inline bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x · 36 unmodified lines | ||
| 1898 | 1917 | { |
| 1899 | 1918 | return false; |
| 1900 | 1919 | } |
| 1920 | + | |
| 1921 | +static inline bool xfrm_dst_offload_ok(struct dst_entry *dst) | |
| 1922 | +{ | |
| 1923 | + return false; | |
| 1924 | +} | |
| 1901 | 1925 | #endif |
| 1902 | 1926 | |
| 1903 | 1927 | static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m) |
| @@ -304,6 +304,7 @@ enum xfrm_attr_type_t { · 303 unmodified lines | ||
| 304 | 304 | XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ |
| 305 | 305 | XFRMA_PAD, |
| 306 | 306 | XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */ |
| 307 | + XFRMA_OUTPUT_MARK, /* __u32 */ | |
| 307 | 308 | __XFRMA_MAX |
| 308 | 309 | |
| 309 | 310 | #define XFRMA_MAX (__XFRMA_MAX - 1) |
| @@ -1776,7 +1776,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) · 1775 unmodified lines | ||
| 1776 | 1776 | sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; |
| 1777 | 1777 | sk->sk_route_caps &= ~sk->sk_route_nocaps; |
| 1778 | 1778 | if (sk_can_gso(sk)) { |
| 1779 | − if (dst->header_len) { | |
| 1779 | + if (dst->header_len && !xfrm_dst_offload_ok(dst)) { | |
| 1780 | 1780 | sk->sk_route_caps &= ~NETIF_F_GSO_MASK; |
| 1781 | 1781 | } else { |
| 1782 | 1782 | sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; |
| @@ -510,7 +510,8 @@ int esp_input_done2(struct sk_buff *skb, int err) · 509 unmodified lines | ||
| 510 | 510 | int elen = skb->len - hlen; |
| 511 | 511 | int ihl; |
| 512 | 512 | u8 nexthdr[2]; |
| 513 | − int padlen; | |
| 513 | + int padlen, trimlen; | |
| 514 | + __wsum csumdiff; | |
| 514 | 515 | |
| 515 | 516 | if (!xo || (xo && !(xo->flags & CRYPTO_DONE))) |
| 516 | 517 | kfree(ESP_SKB_CB(skb)->tmp); |
| @@ -568,8 +569,15 @@ int esp_input_done2(struct sk_buff *skb, int err) · 51 unmodified lines | ||
| 568 | 569 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 569 | 570 | } |
| 570 | 571 | |
| 571 | − pskb_trim(skb, skb->len - alen - padlen - 2); | |
| 572 | − __skb_pull(skb, hlen); | |
| 572 | + trimlen = alen + padlen + 2; | |
| 573 | + if (skb->ip_summed == CHECKSUM_COMPLETE) { | |
| 574 | + csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0); | |
| 575 | + skb->csum = csum_block_sub(skb->csum, csumdiff, | |
| 576 | + skb->len - trimlen); | |
| 577 | + } | |
| 578 | + pskb_trim(skb, skb->len - trimlen); | |
| 579 | + | |
| 580 | + skb_pull_rcsum(skb, hlen); | |
| 573 | 581 | if (x->props.mode == XFRM_MODE_TUNNEL) |
| 574 | 582 | skb_reset_transport_header(skb); |
| 575 | 583 | else |
| @@ -182,11 +182,13 @@ out: · 181 unmodified lines | ||
| 182 | 182 | static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb) |
| 183 | 183 | { |
| 184 | 184 | struct crypto_aead *aead = x->data; |
| 185 | + struct xfrm_offload *xo = xfrm_offload(skb); | |
| 185 | 186 | |
| 186 | 187 | if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead))) |
| 187 | 188 | return -EINVAL; |
| 188 | 189 | |
| 189 | − skb->ip_summed = CHECKSUM_NONE; | |
| 190 | + if (!(xo->flags & CRYPTO_DONE)) | |
| 191 | + skb->ip_summed = CHECKSUM_NONE; | |
| 190 | 192 | |
| 191 | 193 | return esp_input_done2(skb, 0); |
| 192 | 194 | } |
| @@ -303,3 +305,4 @@ module_init(esp4_offload_init); · 110 unmodified lines | ||
| 303 | 305 | module_exit(esp4_offload_exit); |
| 304 | 306 | MODULE_LICENSE("GPL"); |
| 305 | 307 | MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>"); |
| 308 | +MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET, XFRM_PROTO_ESP); | |
| @@ -20,7 +20,8 @@ · 19 unmodified lines | ||
| 20 | 20 | static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, |
| 21 | 21 | int tos, int oif, |
| 22 | 22 | const xfrm_address_t *saddr, |
| 23 | − const xfrm_address_t *daddr) | |
| 23 | + const xfrm_address_t *daddr, | |
| 24 | + u32 mark) | |
| 24 | 25 | { |
| 25 | 26 | struct rtable *rt; |
| 26 | 27 | |
| @@ -28,6 +29,7 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, · 1 unmodified line | ||
| 28 | 29 | fl4->daddr = daddr->a4; |
| 29 | 30 | fl4->flowi4_tos = tos; |
| 30 | 31 | fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif); |
| 32 | + fl4->flowi4_mark = mark; | |
| 31 | 33 | if (saddr) |
| 32 | 34 | fl4->saddr = saddr->a4; |
| 33 | 35 | |
| @@ -42,20 +44,22 @@ static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, · 8 unmodified lines | ||
| 42 | 44 | |
| 43 | 45 | static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif, |
| 44 | 46 | const xfrm_address_t *saddr, |
| 45 | − const xfrm_address_t *daddr) | |
| 47 | + const xfrm_address_t *daddr, | |
| 48 | + u32 mark) | |
| 46 | 49 | { |
| 47 | 50 | struct flowi4 fl4; |
| 48 | 51 | |
| 49 | − return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr); | |
| 52 | + return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr, mark); | |
| 50 | 53 | } |
| 51 | 54 | |
| 52 | 55 | static int xfrm4_get_saddr(struct net *net, int oif, |
| 53 | − xfrm_address_t *saddr, xfrm_address_t *daddr) | |
| 56 | + xfrm_address_t *saddr, xfrm_address_t *daddr, | |
| 57 | + u32 mark) | |
| 54 | 58 | { |
| 55 | 59 | struct dst_entry *dst; |
| 56 | 60 | struct flowi4 fl4; |
| 57 | 61 | |
| 58 | − dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr); | |
| 62 | + dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark); | |
| 59 | 63 | if (IS_ERR(dst)) |
| 60 | 64 | return -EHOSTUNREACH; |
| 61 | 65 | |
| @@ -470,7 +470,8 @@ int esp6_input_done2(struct sk_buff *skb, int err) · 469 unmodified lines | ||
| 470 | 470 | int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead); |
| 471 | 471 | int elen = skb->len - hlen; |
| 472 | 472 | int hdr_len = skb_network_header_len(skb); |
| 473 | − int padlen; | |
| 473 | + int padlen, trimlen; | |
| 474 | + __wsum csumdiff; | |
| 474 | 475 | u8 nexthdr[2]; |
| 475 | 476 | |
| 476 | 477 | if (!xo || (xo && !(xo->flags & CRYPTO_DONE))) |
| @@ -492,8 +493,17 @@ int esp6_input_done2(struct sk_buff *skb, int err) · 15 unmodified lines | ||
| 492 | 493 | |
| 493 | 494 | /* ... check padding bits here. Silly. :-) */ |
| 494 | 495 | |
| 495 | − pskb_trim(skb, skb->len - alen - padlen - 2); | |
| 496 | − __skb_pull(skb, hlen); | |
| 496 | + trimlen = alen + padlen + 2; | |
| 497 | + if (skb->ip_summed == CHECKSUM_COMPLETE) { | |
| 498 | + skb_postpull_rcsum(skb, skb_network_header(skb), | |
| 499 | + skb_network_header_len(skb)); | |
| 500 | + csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0); | |
| 501 | + skb->csum = csum_block_sub(skb->csum, csumdiff, | |
| 502 | + skb->len - trimlen); | |
| 503 | + } | |
| 504 | + pskb_trim(skb, skb->len - trimlen); | |
| 505 | + | |
| 506 | + skb_pull_rcsum(skb, hlen); | |
| 497 | 507 | if (x->props.mode == XFRM_MODE_TUNNEL) |
| 498 | 508 | skb_reset_transport_header(skb); |
| 499 | 509 | else |
| @@ -209,11 +209,13 @@ out: · 208 unmodified lines | ||
| 209 | 209 | static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb) |
| 210 | 210 | { |
| 211 | 211 | struct crypto_aead *aead = x->data; |
| 212 | + struct xfrm_offload *xo = xfrm_offload(skb); | |
| 212 | 213 | |
| 213 | 214 | if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead))) |
| 214 | 215 | return -EINVAL; |
| 215 | 216 | |
| 216 | − skb->ip_summed = CHECKSUM_NONE; | |
| 217 | + if (!(xo->flags & CRYPTO_DONE)) | |
| 218 | + skb->ip_summed = CHECKSUM_NONE; | |
| 217 | 219 | |
| 218 | 220 | return esp6_input_done2(skb, 0); |
| 219 | 221 | } |
| @@ -332,3 +334,4 @@ module_init(esp6_offload_init); · 112 unmodified lines | ||
| 332 | 334 | module_exit(esp6_offload_exit); |
| 333 | 335 | MODULE_LICENSE("GPL"); |
| 334 | 336 | MODULE_AUTHOR("Steffen Klassert <steffen.klassert@secunet.com>"); |
| 337 | +MODULE_ALIAS_XFRM_OFFLOAD_TYPE(AF_INET6, XFRM_PROTO_ESP); | |
| @@ -34,6 +34,7 @@ EXPORT_SYMBOL(xfrm6_rcv_spi); · 33 unmodified lines | ||
| 34 | 34 | int xfrm6_transport_finish(struct sk_buff *skb, int async) |
| 35 | 35 | { |
| 36 | 36 | struct xfrm_offload *xo = xfrm_offload(skb); |
| 37 | + int nhlen = skb->data - skb_network_header(skb); | |
| 37 | 38 | |
| 38 | 39 | skb_network_header(skb)[IP6CB(skb)->nhoff] = |
| 39 | 40 | XFRM_MODE_SKB_CB(skb)->protocol; |
| @@ -43,8 +44,9 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) · 3 unmodified lines | ||
| 43 | 44 | return 1; |
| 44 | 45 | #endif |
| 45 | 46 | |
| 46 | − __skb_push(skb, skb->data - skb_network_header(skb)); | |
| 47 | + __skb_push(skb, nhlen); | |
| 47 | 48 | ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); |
| 49 | + skb_postpush_rcsum(skb, skb_network_header(skb), nhlen); | |
| 48 | 50 | |
| 49 | 51 | if (xo && (xo->flags & XFRM_GRO)) { |
| 50 | 52 | skb_mac_header_rebuild(skb); |
| @@ -27,7 +27,8 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, |
| 29 | 29 | const xfrm_address_t *saddr, |
| 30 | − const xfrm_address_t *daddr) | |
| 30 | + const xfrm_address_t *daddr, | |
| 31 | + u32 mark) | |
| 31 | 32 | { |
| 32 | 33 | struct flowi6 fl6; |
| 33 | 34 | struct dst_entry *dst; |
| @@ -36,6 +37,7 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, · 2 unmodified lines | ||
| 36 | 37 | memset(&fl6, 0, sizeof(fl6)); |
| 37 | 38 | fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif); |
| 38 | 39 | fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF; |
| 40 | + fl6.flowi6_mark = mark; | |
| 39 | 41 | memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr)); |
| 40 | 42 | if (saddr) |
| 41 | 43 | memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr)); |
| @@ -52,12 +54,13 @@ static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, · 10 unmodified lines | ||
| 52 | 54 | } |
| 53 | 55 | |
| 54 | 56 | static int xfrm6_get_saddr(struct net *net, int oif, |
| 55 | − xfrm_address_t *saddr, xfrm_address_t *daddr) | |
| 57 | + xfrm_address_t *saddr, xfrm_address_t *daddr, | |
| 58 | + u32 mark) | |
| 56 | 59 | { |
| 57 | 60 | struct dst_entry *dst; |
| 58 | 61 | struct net_device *dev; |
| 59 | 62 | |
| 60 | − dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr); | |
| 63 | + dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr, mark); | |
| 61 | 64 | if (IS_ERR(dst)) |
| 62 | 65 | return -EHOSTUNREACH; |
| 63 | 66 | |
| @@ -63,7 +63,7 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, · 62 unmodified lines | ||
| 63 | 63 | xfrm_address_t *daddr; |
| 64 | 64 | |
| 65 | 65 | if (!x->type_offload) |
| 66 | − return 0; | |
| 66 | + return -EINVAL; | |
| 67 | 67 | |
| 68 | 68 | /* We don't yet support UDP encapsulation, TFC padding and ESN. */ |
| 69 | 69 | if (x->encap || x->tfcpad || (x->props.flags & XFRM_STATE_ESN)) |
| @@ -79,7 +79,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x, · 9 unmodified lines | ||
| 79 | 79 | daddr = &x->props.saddr; |
| 80 | 80 | } |
| 81 | 81 | |
| 82 | − dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr, x->props.family); | |
| 82 | + dst = __xfrm_dst_lookup(net, 0, 0, saddr, daddr, | |
| 83 | + x->props.family, x->props.output_mark); | |
| 83 | 84 | if (IS_ERR(dst)) |
| 84 | 85 | return 0; |
| 85 | 86 | |
| @@ -424,6 +424,7 @@ resume: · 423 unmodified lines | ||
| 424 | 424 | nf_reset(skb); |
| 425 | 425 | |
| 426 | 426 | if (decaps) { |
| 427 | + skb->sp->olen = 0; | |
| 427 | 428 | skb_dst_drop(skb); |
| 428 | 429 | gro_cells_receive(&gro_cells, skb); |
| 429 | 430 | return 0; |
| @@ -434,6 +435,7 @@ resume: · 4 unmodified lines | ||
| 434 | 435 | |
| 435 | 436 | err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async); |
| 436 | 437 | if (xfrm_gro) { |
| 438 | + skb->sp->olen = 0; | |
| 437 | 439 | skb_dst_drop(skb); |
| 438 | 440 | gro_cells_receive(&gro_cells, skb); |
| 439 | 441 | return err; |
| @@ -66,6 +66,9 @@ static int xfrm_output_one(struct sk_buff *skb, int err) · 65 unmodified lines | ||
| 66 | 66 | goto error_nolock; |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | + if (x->props.output_mark) | |
| 70 | + skb->mark = x->props.output_mark; | |
| 71 | + | |
| 69 | 72 | err = x->outer_mode->output(x, skb); |
| 70 | 73 | if (err) { |
| 71 | 74 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); |
| @@ -122,7 +122,7 @@ static const struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short fa · 121 unmodified lines | ||
| 122 | 122 | struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif, |
| 123 | 123 | const xfrm_address_t *saddr, |
| 124 | 124 | const xfrm_address_t *daddr, |
| 125 | − int family) | |
| 125 | + int family, u32 mark) | |
| 126 | 126 | { |
| 127 | 127 | const struct xfrm_policy_afinfo *afinfo; |
| 128 | 128 | struct dst_entry *dst; |
| @@ -131,7 +131,7 @@ struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, int oif, · 2 unmodified lines | ||
| 131 | 131 | if (unlikely(afinfo == NULL)) |
| 132 | 132 | return ERR_PTR(-EAFNOSUPPORT); |
| 133 | 133 | |
| 134 | − dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr); | |
| 134 | + dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr, mark); | |
| 135 | 135 | |
| 136 | 136 | rcu_read_unlock(); |
| 137 | 137 | |
| @@ -143,7 +143,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, · 5 unmodified lines | ||
| 143 | 143 | int tos, int oif, |
| 144 | 144 | xfrm_address_t *prev_saddr, |
| 145 | 145 | xfrm_address_t *prev_daddr, |
| 146 | − int family) | |
| 146 | + int family, u32 mark) | |
| 147 | 147 | { |
| 148 | 148 | struct net *net = xs_net(x); |
| 149 | 149 | xfrm_address_t *saddr = &x->props.saddr; |
| @@ -159,7 +159,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, · 9 unmodified lines | ||
| 159 | 159 | daddr = x->coaddr; |
| 160 | 160 | } |
| 161 | 161 | |
| 162 | − dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family); | |
| 162 | + dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family, mark); | |
| 163 | 163 | |
| 164 | 164 | if (!IS_ERR(dst)) { |
| 165 | 165 | if (prev_saddr != saddr) |
| @@ -1340,14 +1340,14 @@ int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) · 1174 unmodified lines | ||
| 1340 | 1340 | |
| 1341 | 1341 | static int |
| 1342 | 1342 | xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local, |
| 1343 | − xfrm_address_t *remote, unsigned short family) | |
| 1343 | + xfrm_address_t *remote, unsigned short family, u32 mark) | |
| 1344 | 1344 | { |
| 1345 | 1345 | int err; |
| 1346 | 1346 | const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
| 1347 | 1347 | |
| 1348 | 1348 | if (unlikely(afinfo == NULL)) |
| 1349 | 1349 | return -EINVAL; |
| 1350 | − err = afinfo->get_saddr(net, oif, local, remote); | |
| 1350 | + err = afinfo->get_saddr(net, oif, local, remote, mark); | |
| 1351 | 1351 | rcu_read_unlock(); |
| 1352 | 1352 | return err; |
| 1353 | 1353 | } |
| @@ -1378,7 +1378,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl, · 24 unmodified lines | ||
| 1378 | 1378 | if (xfrm_addr_any(local, tmpl->encap_family)) { |
| 1379 | 1379 | error = xfrm_get_saddr(net, fl->flowi_oif, |
| 1380 | 1380 | &tmp, remote, |
| 1381 | − tmpl->encap_family); | |
| 1381 | + tmpl->encap_family, 0); | |
| 1382 | 1382 | if (error) |
| 1383 | 1383 | goto fail; |
| 1384 | 1384 | local = &tmp; |
| @@ -1598,7 +1598,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, · 213 unmodified lines | ||
| 1598 | 1598 | if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { |
| 1599 | 1599 | family = xfrm[i]->props.family; |
| 1600 | 1600 | dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif, |
| 1601 | − &saddr, &daddr, family); | |
| 1601 | + &saddr, &daddr, family, | |
| 1602 | + xfrm[i]->props.output_mark); | |
| 1602 | 1603 | err = PTR_ERR(dst); |
| 1603 | 1604 | if (IS_ERR(dst)) |
| 1604 | 1605 | goto put_states; |
| @@ -296,12 +296,14 @@ int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, · 295 unmodified lines | ||
| 296 | 296 | } |
| 297 | 297 | EXPORT_SYMBOL(xfrm_unregister_type_offload); |
| 298 | 298 | |
| 299 | −static const struct xfrm_type_offload *xfrm_get_type_offload(u8 proto, unsigned short family) | |
| 299 | +static const struct xfrm_type_offload * | |
| 300 | +xfrm_get_type_offload(u8 proto, unsigned short family, bool try_load) | |
| 300 | 301 | { |
| 301 | 302 | struct xfrm_state_afinfo *afinfo; |
| 302 | 303 | const struct xfrm_type_offload **typemap; |
| 303 | 304 | const struct xfrm_type_offload *type; |
| 304 | 305 | |
| 306 | +retry: | |
| 305 | 307 | afinfo = xfrm_state_get_afinfo(family); |
| 306 | 308 | if (unlikely(afinfo == NULL)) |
| 307 | 309 | return NULL; |
| @@ -311,6 +313,12 @@ static const struct xfrm_type_offload *xfrm_get_type_offload(u8 proto, unsigned · 3 unmodified lines | ||
| 311 | 313 | if ((type && !try_module_get(type->owner))) |
| 312 | 314 | type = NULL; |
| 313 | 315 | |
| 316 | + if (!type && try_load) { | |
| 317 | + request_module("xfrm-offload-%d-%d", family, proto); | |
| 318 | + try_load = 0; | |
| 319 | + goto retry; | |
| 320 | + } | |
| 321 | + | |
| 314 | 322 | rcu_read_unlock(); |
| 315 | 323 | return type; |
| 316 | 324 | } |
| @@ -2165,7 +2173,7 @@ int xfrm_state_mtu(struct xfrm_state *x, int mtu) · 1848 unmodified lines | ||
| 2165 | 2173 | return mtu - x->props.header_len; |
| 2166 | 2174 | } |
| 2167 | 2175 | |
| 2168 | −int __xfrm_init_state(struct xfrm_state *x, bool init_replay) | |
| 2176 | +int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload) | |
| 2169 | 2177 | { |
| 2170 | 2178 | struct xfrm_state_afinfo *afinfo; |
| 2171 | 2179 | struct xfrm_mode *inner_mode; |
| @@ -2230,7 +2238,7 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay) · 58 unmodified lines | ||
| 2230 | 2238 | if (x->type == NULL) |
| 2231 | 2239 | goto error; |
| 2232 | 2240 | |
| 2233 | − x->type_offload = xfrm_get_type_offload(x->id.proto, family); | |
| 2241 | + x->type_offload = xfrm_get_type_offload(x->id.proto, family, offload); | |
| 2234 | 2242 | |
| 2235 | 2243 | err = x->type->init_state(x); |
| 2236 | 2244 | if (err) |
| @@ -2258,7 +2266,7 @@ EXPORT_SYMBOL(__xfrm_init_state); · 21 unmodified lines | ||
| 2258 | 2266 | |
| 2259 | 2267 | int xfrm_init_state(struct xfrm_state *x) |
| 2260 | 2268 | { |
| 2261 | − return __xfrm_init_state(x, true); | |
| 2269 | + return __xfrm_init_state(x, true, false); | |
| 2262 | 2270 | } |
| 2263 | 2271 | |
| 2264 | 2272 | EXPORT_SYMBOL(xfrm_init_state); |
| @@ -584,7 +584,10 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, · 583 unmodified lines | ||
| 584 | 584 | |
| 585 | 585 | xfrm_mark_get(attrs, &x->mark); |
| 586 | 586 | |
| 587 | − err = __xfrm_init_state(x, false); | |
| 587 | + if (attrs[XFRMA_OUTPUT_MARK]) | |
| 588 | + x->props.output_mark = nla_get_u32(attrs[XFRMA_OUTPUT_MARK]); | |
| 589 | + | |
| 590 | + err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]); | |
| 588 | 591 | if (err) |
| 589 | 592 | goto error; |
| 590 | 593 | |
| @@ -899,6 +902,11 @@ static int copy_to_user_state_extra(struct xfrm_state *x, · 308 unmodified lines | ||
| 899 | 902 | goto out; |
| 900 | 903 | if (x->security) |
| 901 | 904 | ret = copy_sec_ctx(x->security, skb); |
| 905 | + if (x->props.output_mark) { | |
| 906 | + ret = nla_put_u32(skb, XFRMA_OUTPUT_MARK, x->props.output_mark); | |
| 907 | + if (ret) | |
| 908 | + goto out; | |
| 909 | + } | |
| 902 | 910 | out: |
| 903 | 911 | return ret; |
| 904 | 912 | } |
| @@ -2454,6 +2462,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { · 1549 unmodified lines | ||
| 2454 | 2462 | [XFRMA_PROTO] = { .type = NLA_U8 }, |
| 2455 | 2463 | [XFRMA_ADDRESS_FILTER] = { .len = sizeof(struct xfrm_address_filter) }, |
| 2456 | 2464 | [XFRMA_OFFLOAD_DEV] = { .len = sizeof(struct xfrm_user_offload) }, |
| 2465 | + [XFRMA_OUTPUT_MARK] = { .len = NLA_U32 }, | |
| 2457 | 2466 | }; |
| 2458 | 2467 | |
| 2459 | 2468 | static const struct nla_policy xfrma_spd_policy[XFRMA_SPD_MAX+1] = { |
| @@ -2673,6 +2682,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) · 213 unmodified lines | ||
| 2673 | 2682 | l += nla_total_size(sizeof(x->props.extra_flags)); |
| 2674 | 2683 | if (x->xso.dev) |
| 2675 | 2684 | l += nla_total_size(sizeof(x->xso)); |
| 2685 | + if (x->props.output_mark) | |
| 2686 | + l += nla_total_size(sizeof(x->props.output_mark)); | |
| 2676 | 2687 | |
| 2677 | 2688 | /* Must count x->lastused as it may become non-zero behind our back. */ |
| 2678 | 2689 | l += nla_total_size_64bit(sizeof(u64)); |