mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 01:03:32 +00:00
ipsec-next-2024-03-06
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEH7ZpcWbFyOOp6OJbrB3Eaf9PW7cFAmXoQdQACgkQrB3Eaf9P W7dnTQ//RnTEaOPgTsHzhSwVOfWhsWkHx2xqUAlPNY8W2jrzxGgAIknPzobivvRJ U2bYPXDocDHUJAHIELUlu+lzATEz8baBN5zK5a+pPx5hXJlf5UI95linNZ5rEIiV RoxLpicnJqtWn1oMZ8d7Y0CknsLR/f4ruiVApzoifk1JaXC/zX8FcqqKsSPwVlqA GKy4+f71rNrIE9fbBAqDpmt6RuyRp/5yXPHLBoZlEXfYrYU1JOG8b/HLtGMD0SzV yHbDcgRPtbkWgAwNO/zxSDKa+PZr7NbVgakDzyHK+TltpU+6cOsajCaSXHWwsTBB +AebDschYY1H49oQe4bwLbNdGY+4lFvXxtk02sa8eM5a104MWxxTEB1QGAEri6gQ biAh3xTTbDpls26qkm97iZ6LlDE6pVIzF744buOYedvR8gjjoLt1z1PId05wMYGB A/4P6WkM8I1CZL++ODVfT8qR2N6lwFAQ6AM/eqHLvc6QpZ5Hm3lQAdLz1tK6QlCP MIV9uuNz8dFPrX1QifmLGojjdedB+4ASglxffOaoqRpHnMgHgzWTOux8tSFpuJGu mIYO/Dv5sHMdH8Jm+xXX1549bRzR+KGuqjXPxOSiO1jbOb5VC5ZDd3LVWb7fpDid K4eaU4Bo4R3eiCo1Bapt/1jKV1YFuyBKqTvObCDslVuN3Fu9d7I= =e4aa -----END PGP SIGNATURE----- Merge tag 'ipsec-next-2024-03-06' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next Steffen Klassert says: ==================== 1) Introduce forwarding of ICMP Error messages. That is specified in RFC 4301 but was never implemented. From Antony Antony. 2) Use KMEM_CACHE instead of kmem_cache_create in xfrm6_tunnel_init() and xfrm_policy_init(). From Kunwu Chan. 3) Do not allocate stats in the xfrm interface driver, this can be done on net core now. From Breno Leitao. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
3dbf6d67f2
@ -355,10 +355,7 @@ static int __init xfrm6_tunnel_init(void)
|
||||
{
|
||||
int rv;
|
||||
|
||||
xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
|
||||
sizeof(struct xfrm6_tunnel_spi),
|
||||
0, SLAB_HWCACHE_ALIGN,
|
||||
NULL);
|
||||
xfrm6_tunnel_spi_kmem = KMEM_CACHE(xfrm6_tunnel_spi, SLAB_HWCACHE_ALIGN);
|
||||
if (!xfrm6_tunnel_spi_kmem)
|
||||
return -ENOMEM;
|
||||
rv = register_pernet_subsys(&xfrm6_tunnel_net_ops);
|
||||
|
@ -240,7 +240,6 @@ static void xfrmi_dev_free(struct net_device *dev)
|
||||
struct xfrm_if *xi = netdev_priv(dev);
|
||||
|
||||
gro_cells_destroy(&xi->gro_cells);
|
||||
free_percpu(dev->tstats);
|
||||
}
|
||||
|
||||
static int xfrmi_create(struct net_device *dev)
|
||||
@ -749,6 +748,7 @@ static void xfrmi_dev_setup(struct net_device *dev)
|
||||
dev->flags = IFF_NOARP;
|
||||
dev->needs_free_netdev = true;
|
||||
dev->priv_destructor = xfrmi_dev_free;
|
||||
dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS;
|
||||
netif_keep_dst(dev);
|
||||
|
||||
eth_broadcast_addr(dev->broadcast);
|
||||
@ -765,15 +765,9 @@ static int xfrmi_dev_init(struct net_device *dev)
|
||||
struct net_device *phydev = __dev_get_by_index(xi->net, xi->p.link);
|
||||
int err;
|
||||
|
||||
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
|
||||
if (!dev->tstats)
|
||||
return -ENOMEM;
|
||||
|
||||
err = gro_cells_init(&xi->gro_cells, dev);
|
||||
if (err) {
|
||||
free_percpu(dev->tstats);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
dev->features |= NETIF_F_LLTX;
|
||||
dev->features |= XFRMI_FEATURES;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <linux/audit.h>
|
||||
#include <linux/rhashtable.h>
|
||||
#include <linux/if_tunnel.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <net/dst.h>
|
||||
#include <net/flow.h>
|
||||
#include <net/inet_ecn.h>
|
||||
@ -3505,6 +3506,128 @@ static inline int secpath_has_nontransport(const struct sec_path *sp, int k, int
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool icmp_err_packet(const struct flowi *fl, unsigned short family)
|
||||
{
|
||||
const struct flowi4 *fl4 = &fl->u.ip4;
|
||||
|
||||
if (family == AF_INET &&
|
||||
fl4->flowi4_proto == IPPROTO_ICMP &&
|
||||
(fl4->fl4_icmp_type == ICMP_DEST_UNREACH ||
|
||||
fl4->fl4_icmp_type == ICMP_TIME_EXCEEDED))
|
||||
return true;
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
if (family == AF_INET6) {
|
||||
const struct flowi6 *fl6 = &fl->u.ip6;
|
||||
|
||||
if (fl6->flowi6_proto == IPPROTO_ICMPV6 &&
|
||||
(fl6->fl6_icmp_type == ICMPV6_DEST_UNREACH ||
|
||||
fl6->fl6_icmp_type == ICMPV6_PKT_TOOBIG ||
|
||||
fl6->fl6_icmp_type == ICMPV6_TIME_EXCEED))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool xfrm_icmp_flow_decode(struct sk_buff *skb, unsigned short family,
|
||||
const struct flowi *fl, struct flowi *fl1)
|
||||
{
|
||||
bool ret = true;
|
||||
struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
|
||||
int hl = family == AF_INET ? (sizeof(struct iphdr) + sizeof(struct icmphdr)) :
|
||||
(sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr));
|
||||
|
||||
if (!newskb)
|
||||
return true;
|
||||
|
||||
if (!pskb_pull(newskb, hl))
|
||||
goto out;
|
||||
|
||||
skb_reset_network_header(newskb);
|
||||
|
||||
if (xfrm_decode_session_reverse(dev_net(skb->dev), newskb, fl1, family) < 0)
|
||||
goto out;
|
||||
|
||||
fl1->flowi_oif = fl->flowi_oif;
|
||||
fl1->flowi_mark = fl->flowi_mark;
|
||||
fl1->flowi_tos = fl->flowi_tos;
|
||||
nf_nat_decode_session(newskb, fl1, family);
|
||||
ret = false;
|
||||
|
||||
out:
|
||||
consume_skb(newskb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool xfrm_selector_inner_icmp_match(struct sk_buff *skb, unsigned short family,
|
||||
const struct xfrm_selector *sel,
|
||||
const struct flowi *fl)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (icmp_err_packet(fl, family)) {
|
||||
struct flowi fl1;
|
||||
|
||||
if (xfrm_icmp_flow_decode(skb, family, fl, &fl1))
|
||||
return ret;
|
||||
|
||||
ret = xfrm_selector_match(sel, &fl1, family);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline struct
|
||||
xfrm_policy *xfrm_in_fwd_icmp(struct sk_buff *skb,
|
||||
const struct flowi *fl, unsigned short family,
|
||||
u32 if_id)
|
||||
{
|
||||
struct xfrm_policy *pol = NULL;
|
||||
|
||||
if (icmp_err_packet(fl, family)) {
|
||||
struct flowi fl1;
|
||||
struct net *net = dev_net(skb->dev);
|
||||
|
||||
if (xfrm_icmp_flow_decode(skb, family, fl, &fl1))
|
||||
return pol;
|
||||
|
||||
pol = xfrm_policy_lookup(net, &fl1, family, XFRM_POLICY_FWD, if_id);
|
||||
}
|
||||
|
||||
return pol;
|
||||
}
|
||||
|
||||
static inline struct
|
||||
dst_entry *xfrm_out_fwd_icmp(struct sk_buff *skb, struct flowi *fl,
|
||||
unsigned short family, struct dst_entry *dst)
|
||||
{
|
||||
if (icmp_err_packet(fl, family)) {
|
||||
struct net *net = dev_net(skb->dev);
|
||||
struct dst_entry *dst2;
|
||||
struct flowi fl1;
|
||||
|
||||
if (xfrm_icmp_flow_decode(skb, family, fl, &fl1))
|
||||
return dst;
|
||||
|
||||
dst_hold(dst);
|
||||
|
||||
dst2 = xfrm_lookup(net, dst, &fl1, NULL, (XFRM_LOOKUP_QUEUE | XFRM_LOOKUP_ICMP));
|
||||
|
||||
if (IS_ERR(dst2))
|
||||
return dst;
|
||||
|
||||
if (dst2->xfrm) {
|
||||
dst_release(dst);
|
||||
dst = dst2;
|
||||
} else {
|
||||
dst_release(dst2);
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
|
||||
unsigned short family)
|
||||
{
|
||||
@ -3551,9 +3674,17 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
|
||||
|
||||
for (i = sp->len - 1; i >= 0; i--) {
|
||||
struct xfrm_state *x = sp->xvec[i];
|
||||
int ret = 0;
|
||||
|
||||
if (!xfrm_selector_match(&x->sel, &fl, family)) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
|
||||
return 0;
|
||||
ret = 1;
|
||||
if (x->props.flags & XFRM_STATE_ICMP &&
|
||||
xfrm_selector_inner_icmp_match(skb, family, &x->sel, &fl))
|
||||
ret = 0;
|
||||
if (ret) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3576,6 +3707,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pol && dir == XFRM_POLICY_FWD)
|
||||
pol = xfrm_in_fwd_icmp(skb, &fl, family, if_id);
|
||||
|
||||
if (!pol) {
|
||||
if (net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK) {
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS);
|
||||
@ -3709,6 +3843,10 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
|
||||
res = 0;
|
||||
dst = NULL;
|
||||
}
|
||||
|
||||
if (dst && !dst->xfrm)
|
||||
dst = xfrm_out_fwd_icmp(skb, &fl, family, dst);
|
||||
|
||||
skb_dst_set(skb, dst);
|
||||
return res;
|
||||
}
|
||||
@ -4027,10 +4165,7 @@ static int __net_init xfrm_policy_init(struct net *net)
|
||||
int dir, err;
|
||||
|
||||
if (net_eq(net, &init_net)) {
|
||||
xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
|
||||
sizeof(struct xfrm_dst),
|
||||
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
|
||||
NULL);
|
||||
xfrm_dst_cache = KMEM_CACHE(xfrm_dst, SLAB_HWCACHE_ALIGN | SLAB_PANIC);
|
||||
err = rhashtable_init(&xfrm_policy_inexact_table,
|
||||
&xfrm_pol_inexact_params);
|
||||
BUG_ON(err);
|
||||
|
Loading…
Reference in New Issue
Block a user