1

Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net

Merge in late fixes to prepare for the 6.11 net-next PR.

Conflicts:
  93c3a96c30 ("net: pse-pd: Do not return EOPNOSUPP if config is null")
  4cddb0f15e ("net: ethtool: pse-pd: Fix possible null-deref")
  30d7b67277 ("net: ethtool: Add new power limit get and set features")
https://lore.kernel.org/20240715123204.623520bb@canb.auug.org.au/

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-07-15 13:05:05 -07:00
commit 51b35d4f9d
22 changed files with 311 additions and 68 deletions

View File

@ -973,6 +973,7 @@ restart:
/* rtnl_lock already held /* rtnl_lock already held
* we might sleep in __netpoll_cleanup() * we might sleep in __netpoll_cleanup()
*/ */
nt->enabled = false;
spin_unlock_irqrestore(&target_list_lock, flags); spin_unlock_irqrestore(&target_list_lock, flags);
__netpoll_cleanup(&nt->np); __netpoll_cleanup(&nt->np);
@ -980,7 +981,6 @@ restart:
spin_lock_irqsave(&target_list_lock, flags); spin_lock_irqsave(&target_list_lock, flags);
netdev_put(nt->np.dev, &nt->np.dev_tracker); netdev_put(nt->np.dev, &nt->np.dev_tracker);
nt->np.dev = NULL; nt->np.dev = NULL;
nt->enabled = false;
stopped = true; stopped = true;
netconsole_target_put(nt); netconsole_target_put(nt);
goto restart; goto restart;

View File

@ -832,13 +832,13 @@ int pse_ethtool_set_config(struct pse_control *psec,
{ {
int err = 0; int err = 0;
if (pse_has_c33(psec)) { if (pse_has_c33(psec) && config->c33_admin_control) {
err = pse_ethtool_c33_set_config(psec, config); err = pse_ethtool_c33_set_config(psec, config);
if (err) if (err)
return err; return err;
} }
if (pse_has_podl(psec)) if (pse_has_podl(psec) && config->podl_admin_control)
err = pse_ethtool_podl_set_config(psec, config); err = pse_ethtool_podl_set_config(psec, config);
return err; return err;

View File

@ -127,18 +127,26 @@ void rt6_age_exceptions(struct fib6_info *f6i, struct fib6_gc_args *gc_args,
static inline int ip6_route_get_saddr(struct net *net, struct fib6_info *f6i, static inline int ip6_route_get_saddr(struct net *net, struct fib6_info *f6i,
const struct in6_addr *daddr, const struct in6_addr *daddr,
unsigned int prefs, unsigned int prefs, int l3mdev_index,
struct in6_addr *saddr) struct in6_addr *saddr)
{ {
struct net_device *l3mdev;
struct net_device *dev;
bool same_vrf;
int err = 0; int err = 0;
if (f6i && f6i->fib6_prefsrc.plen) { rcu_read_lock();
*saddr = f6i->fib6_prefsrc.addr;
} else {
struct net_device *dev = f6i ? fib6_info_nh_dev(f6i) : NULL;
err = ipv6_dev_get_saddr(net, dev, daddr, prefs, saddr); l3mdev = dev_get_by_index_rcu(net, l3mdev_index);
} if (!f6i || !f6i->fib6_prefsrc.plen || l3mdev)
dev = f6i ? fib6_info_nh_dev(f6i) : NULL;
same_vrf = !l3mdev || l3mdev_master_dev_rcu(dev) == l3mdev;
if (f6i && f6i->fib6_prefsrc.plen && same_vrf)
*saddr = f6i->fib6_prefsrc.addr;
else
err = ipv6_dev_get_saddr(net, same_vrf ? dev : l3mdev, daddr, prefs, saddr);
rcu_read_unlock();
return err; return err;
} }

View File

@ -178,7 +178,10 @@ struct xfrm_state {
struct hlist_node gclist; struct hlist_node gclist;
struct hlist_node bydst; struct hlist_node bydst;
}; };
union {
struct hlist_node dev_gclist;
struct hlist_node bysrc; struct hlist_node bysrc;
};
struct hlist_node byspi; struct hlist_node byspi;
struct hlist_node byseq; struct hlist_node byseq;
@ -1592,7 +1595,7 @@ void xfrm_state_update_stats(struct net *net);
static inline void xfrm_dev_state_update_stats(struct xfrm_state *x) static inline void xfrm_dev_state_update_stats(struct xfrm_state *x)
{ {
struct xfrm_dev_offload *xdo = &x->xso; struct xfrm_dev_offload *xdo = &x->xso;
struct net_device *dev = xdo->dev; struct net_device *dev = READ_ONCE(xdo->dev);
if (dev && dev->xfrmdev_ops && if (dev && dev->xfrmdev_ops &&
dev->xfrmdev_ops->xdo_dev_state_update_stats) dev->xfrmdev_ops->xdo_dev_state_update_stats)
@ -1950,13 +1953,16 @@ int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
struct xfrm_user_offload *xuo, u8 dir, struct xfrm_user_offload *xuo, u8 dir,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x); bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
void xfrm_dev_state_delete(struct xfrm_state *x);
void xfrm_dev_state_free(struct xfrm_state *x);
static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x) static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
{ {
struct xfrm_dev_offload *xso = &x->xso; struct xfrm_dev_offload *xso = &x->xso;
struct net_device *dev = READ_ONCE(xso->dev);
if (xso->dev && xso->dev->xfrmdev_ops->xdo_dev_state_advance_esn) if (dev && dev->xfrmdev_ops->xdo_dev_state_advance_esn)
xso->dev->xfrmdev_ops->xdo_dev_state_advance_esn(x); dev->xfrmdev_ops->xdo_dev_state_advance_esn(x);
} }
static inline bool xfrm_dst_offload_ok(struct dst_entry *dst) static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
@ -1977,28 +1983,6 @@ static inline bool xfrm_dst_offload_ok(struct dst_entry *dst)
return false; return false;
} }
static inline void xfrm_dev_state_delete(struct xfrm_state *x)
{
struct xfrm_dev_offload *xso = &x->xso;
if (xso->dev)
xso->dev->xfrmdev_ops->xdo_dev_state_delete(x);
}
static inline void xfrm_dev_state_free(struct xfrm_state *x)
{
struct xfrm_dev_offload *xso = &x->xso;
struct net_device *dev = xso->dev;
if (dev && dev->xfrmdev_ops) {
if (dev->xfrmdev_ops->xdo_dev_state_free)
dev->xfrmdev_ops->xdo_dev_state_free(x);
xso->dev = NULL;
xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
netdev_put(dev, &xso->dev_tracker);
}
}
static inline void xfrm_dev_policy_delete(struct xfrm_policy *x) static inline void xfrm_dev_policy_delete(struct xfrm_policy *x)
{ {
struct xfrm_dev_offload *xdo = &x->xdo; struct xfrm_dev_offload *xdo = &x->xdo;

View File

@ -25,8 +25,8 @@ static inline int should_deliver(const struct net_bridge_port *p,
vg = nbp_vlan_group_rcu(p); vg = nbp_vlan_group_rcu(p);
return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) && return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
p->state == BR_STATE_FORWARDING && br_allowed_egress(vg, skb) && (br_mst_is_enabled(p->br) || p->state == BR_STATE_FORWARDING) &&
nbp_switchdev_allowed_egress(p, skb) && br_allowed_egress(vg, skb) && nbp_switchdev_allowed_egress(p, skb) &&
!br_skb_isolated(p, skb); !br_skb_isolated(p, skb);
} }

View File

@ -127,10 +127,8 @@ void xdp_unreg_mem_model(struct xdp_mem_info *mem)
return; return;
if (type == MEM_TYPE_PAGE_POOL) { if (type == MEM_TYPE_PAGE_POOL) {
rcu_read_lock(); xa = rhashtable_lookup_fast(mem_id_ht, &id, mem_id_rht_params);
xa = rhashtable_lookup(mem_id_ht, &id, mem_id_rht_params);
page_pool_destroy(xa->page_pool); page_pool_destroy(xa->page_pool);
rcu_read_unlock();
} }
} }
EXPORT_SYMBOL_GPL(xdp_unreg_mem_model); EXPORT_SYMBOL_GPL(xdp_unreg_mem_model);

View File

@ -277,17 +277,21 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL]) { tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL]) {
struct pse_control_config config = {}; struct pse_control_config config = {};
if (pse_has_podl(phydev->psec)) if (tb[ETHTOOL_A_PODL_PSE_ADMIN_CONTROL])
config.podl_admin_control = nla_get_u32(tb[ETHTOOL_A_PODL_PSE_ADMIN_CONTROL]); config.podl_admin_control = nla_get_u32(tb[ETHTOOL_A_PODL_PSE_ADMIN_CONTROL]);
if (pse_has_c33(phydev->psec)) if (tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL])
config.c33_admin_control = nla_get_u32(tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL]); config.c33_admin_control = nla_get_u32(tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL]);
/* pse_ethtool_set_config() will do nothing if the config
* is zero
*/
ret = pse_ethtool_set_config(phydev->psec, info->extack, ret = pse_ethtool_set_config(phydev->psec, info->extack,
&config); &config);
if (ret) if (ret)
return ret; return ret;
} }
/* Return errno or zero - PSE has no notification */
return ret; return ret;
} }

View File

@ -239,8 +239,7 @@ static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
#else #else
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb) static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
{ {
kfree_skb(skb); WARN_ON(1);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
#endif #endif

View File

@ -56,6 +56,13 @@ static struct sk_buff *esp4_gro_receive(struct list_head *head,
x = xfrm_state_lookup(dev_net(skb->dev), skb->mark, x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
(xfrm_address_t *)&ip_hdr(skb)->daddr, (xfrm_address_t *)&ip_hdr(skb)->daddr,
spi, IPPROTO_ESP, AF_INET); spi, IPPROTO_ESP, AF_INET);
if (unlikely(x && x->dir && x->dir != XFRM_SA_DIR_IN)) {
/* non-offload path will record the error and audit log */
xfrm_state_put(x);
x = NULL;
}
if (!x) if (!x)
goto out_reset; goto out_reset;

View File

@ -2269,6 +2269,15 @@ void fib_select_path(struct net *net, struct fib_result *res,
fib_select_default(fl4, res); fib_select_default(fl4, res);
check_saddr: check_saddr:
if (!fl4->saddr) if (!fl4->saddr) {
struct net_device *l3mdev;
l3mdev = dev_get_by_index_rcu(net, fl4->flowi4_l3mdev);
if (!l3mdev ||
l3mdev_master_dev_rcu(FIB_RES_DEV(*res)) == l3mdev)
fl4->saddr = fib_result_prefsrc(net, res); fl4->saddr = fib_result_prefsrc(net, res);
else
fl4->saddr = inet_select_addr(l3mdev, 0, RT_SCOPE_LINK);
}
} }

View File

@ -1873,7 +1873,8 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
master, &dst, master, &dst,
scores, hiscore_idx); scores, hiscore_idx);
if (scores[hiscore_idx].ifa) if (scores[hiscore_idx].ifa &&
scores[hiscore_idx].scopedist >= 0)
goto out; goto out;
} }

View File

@ -256,8 +256,7 @@ static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
#else #else
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb) static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
{ {
kfree_skb(skb); WARN_ON(1);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
#endif #endif

View File

@ -83,6 +83,13 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head,
x = xfrm_state_lookup(dev_net(skb->dev), skb->mark, x = xfrm_state_lookup(dev_net(skb->dev), skb->mark,
(xfrm_address_t *)&ipv6_hdr(skb)->daddr, (xfrm_address_t *)&ipv6_hdr(skb)->daddr,
spi, IPPROTO_ESP, AF_INET6); spi, IPPROTO_ESP, AF_INET6);
if (unlikely(x && x->dir && x->dir != XFRM_SA_DIR_IN)) {
/* non-offload path will record the error and audit log */
xfrm_state_put(x);
x = NULL;
}
if (!x) if (!x)
goto out_reset; goto out_reset;

View File

@ -1124,6 +1124,7 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
from = rt ? rcu_dereference(rt->from) : NULL; from = rt ? rcu_dereference(rt->from) : NULL;
err = ip6_route_get_saddr(net, from, &fl6->daddr, err = ip6_route_get_saddr(net, from, &fl6->daddr,
sk ? READ_ONCE(inet6_sk(sk)->srcprefs) : 0, sk ? READ_ONCE(inet6_sk(sk)->srcprefs) : 0,
fl6->flowi6_l3mdev,
&fl6->saddr); &fl6->saddr);
rcu_read_unlock(); rcu_read_unlock();

View File

@ -5687,7 +5687,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
goto nla_put_failure; goto nla_put_failure;
} else if (dest) { } else if (dest) {
struct in6_addr saddr_buf; struct in6_addr saddr_buf;
if (ip6_route_get_saddr(net, rt, dest, 0, &saddr_buf) == 0 && if (ip6_route_get_saddr(net, rt, dest, 0, 0, &saddr_buf) == 0 &&
nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf)) nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf))
goto nla_put_failure; goto nla_put_failure;
} }

View File

@ -538,6 +538,61 @@ static void *packet_current_frame(struct packet_sock *po,
return packet_lookup_frame(po, rb, rb->head, status); return packet_lookup_frame(po, rb, rb->head, status);
} }
static u16 vlan_get_tci(struct sk_buff *skb, struct net_device *dev)
{
u8 *skb_orig_data = skb->data;
int skb_orig_len = skb->len;
struct vlan_hdr vhdr, *vh;
unsigned int header_len;
if (!dev)
return 0;
/* In the SOCK_DGRAM scenario, skb data starts at the network
* protocol, which is after the VLAN headers. The outer VLAN
* header is at the hard_header_len offset in non-variable
* length link layer headers. If it's a VLAN device, the
* min_header_len should be used to exclude the VLAN header
* size.
*/
if (dev->min_header_len == dev->hard_header_len)
header_len = dev->hard_header_len;
else if (is_vlan_dev(dev))
header_len = dev->min_header_len;
else
return 0;
skb_push(skb, skb->data - skb_mac_header(skb));
vh = skb_header_pointer(skb, header_len, sizeof(vhdr), &vhdr);
if (skb_orig_data != skb->data) {
skb->data = skb_orig_data;
skb->len = skb_orig_len;
}
if (unlikely(!vh))
return 0;
return ntohs(vh->h_vlan_TCI);
}
static __be16 vlan_get_protocol_dgram(struct sk_buff *skb)
{
__be16 proto = skb->protocol;
if (unlikely(eth_type_vlan(proto))) {
u8 *skb_orig_data = skb->data;
int skb_orig_len = skb->len;
skb_push(skb, skb->data - skb_mac_header(skb));
proto = __vlan_get_protocol(skb, proto, NULL);
if (skb_orig_data != skb->data) {
skb->data = skb_orig_data;
skb->len = skb_orig_len;
}
}
return proto;
}
static void prb_del_retire_blk_timer(struct tpacket_kbdq_core *pkc) static void prb_del_retire_blk_timer(struct tpacket_kbdq_core *pkc)
{ {
del_timer_sync(&pkc->retire_blk_timer); del_timer_sync(&pkc->retire_blk_timer);
@ -1007,10 +1062,16 @@ static void prb_clear_rxhash(struct tpacket_kbdq_core *pkc,
static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc, static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc,
struct tpacket3_hdr *ppd) struct tpacket3_hdr *ppd)
{ {
struct packet_sock *po = container_of(pkc, struct packet_sock, rx_ring.prb_bdqc);
if (skb_vlan_tag_present(pkc->skb)) { if (skb_vlan_tag_present(pkc->skb)) {
ppd->hv1.tp_vlan_tci = skb_vlan_tag_get(pkc->skb); ppd->hv1.tp_vlan_tci = skb_vlan_tag_get(pkc->skb);
ppd->hv1.tp_vlan_tpid = ntohs(pkc->skb->vlan_proto); ppd->hv1.tp_vlan_tpid = ntohs(pkc->skb->vlan_proto);
ppd->tp_status = TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID; ppd->tp_status = TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else if (unlikely(po->sk.sk_type == SOCK_DGRAM && eth_type_vlan(pkc->skb->protocol))) {
ppd->hv1.tp_vlan_tci = vlan_get_tci(pkc->skb, pkc->skb->dev);
ppd->hv1.tp_vlan_tpid = ntohs(pkc->skb->protocol);
ppd->tp_status = TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else { } else {
ppd->hv1.tp_vlan_tci = 0; ppd->hv1.tp_vlan_tci = 0;
ppd->hv1.tp_vlan_tpid = 0; ppd->hv1.tp_vlan_tpid = 0;
@ -2427,6 +2488,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h2->tp_vlan_tci = skb_vlan_tag_get(skb); h.h2->tp_vlan_tci = skb_vlan_tag_get(skb);
h.h2->tp_vlan_tpid = ntohs(skb->vlan_proto); h.h2->tp_vlan_tpid = ntohs(skb->vlan_proto);
status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID; status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else if (unlikely(sk->sk_type == SOCK_DGRAM && eth_type_vlan(skb->protocol))) {
h.h2->tp_vlan_tci = vlan_get_tci(skb, skb->dev);
h.h2->tp_vlan_tpid = ntohs(skb->protocol);
status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else { } else {
h.h2->tp_vlan_tci = 0; h.h2->tp_vlan_tci = 0;
h.h2->tp_vlan_tpid = 0; h.h2->tp_vlan_tpid = 0;
@ -2456,7 +2521,8 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
sll->sll_halen = dev_parse_header(skb, sll->sll_addr); sll->sll_halen = dev_parse_header(skb, sll->sll_addr);
sll->sll_family = AF_PACKET; sll->sll_family = AF_PACKET;
sll->sll_hatype = dev->type; sll->sll_hatype = dev->type;
sll->sll_protocol = skb->protocol; sll->sll_protocol = (sk->sk_type == SOCK_DGRAM) ?
vlan_get_protocol_dgram(skb) : skb->protocol;
sll->sll_pkttype = skb->pkt_type; sll->sll_pkttype = skb->pkt_type;
if (unlikely(packet_sock_flag(po, PACKET_SOCK_ORIGDEV))) if (unlikely(packet_sock_flag(po, PACKET_SOCK_ORIGDEV)))
sll->sll_ifindex = orig_dev->ifindex; sll->sll_ifindex = orig_dev->ifindex;
@ -3481,7 +3547,8 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
/* Original length was stored in sockaddr_ll fields */ /* Original length was stored in sockaddr_ll fields */
origlen = PACKET_SKB_CB(skb)->sa.origlen; origlen = PACKET_SKB_CB(skb)->sa.origlen;
sll->sll_family = AF_PACKET; sll->sll_family = AF_PACKET;
sll->sll_protocol = skb->protocol; sll->sll_protocol = (sock->type == SOCK_DGRAM) ?
vlan_get_protocol_dgram(skb) : skb->protocol;
} }
sock_recv_cmsgs(msg, sk, skb); sock_recv_cmsgs(msg, sk, skb);
@ -3538,6 +3605,21 @@ static int packet_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
aux.tp_vlan_tci = skb_vlan_tag_get(skb); aux.tp_vlan_tci = skb_vlan_tag_get(skb);
aux.tp_vlan_tpid = ntohs(skb->vlan_proto); aux.tp_vlan_tpid = ntohs(skb->vlan_proto);
aux.tp_status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID; aux.tp_status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else if (unlikely(sock->type == SOCK_DGRAM && eth_type_vlan(skb->protocol))) {
struct sockaddr_ll *sll = &PACKET_SKB_CB(skb)->sa.ll;
struct net_device *dev;
rcu_read_lock();
dev = dev_get_by_index_rcu(sock_net(sk), sll->sll_ifindex);
if (dev) {
aux.tp_vlan_tci = vlan_get_tci(skb, dev);
aux.tp_vlan_tpid = ntohs(skb->protocol);
aux.tp_status |= TP_STATUS_VLAN_VALID | TP_STATUS_VLAN_TPID_VALID;
} else {
aux.tp_vlan_tci = 0;
aux.tp_vlan_tpid = 0;
}
rcu_read_unlock();
} else { } else {
aux.tp_vlan_tci = 0; aux.tp_vlan_tci = 0;
aux.tp_vlan_tpid = 0; aux.tp_vlan_tpid = 0;

View File

@ -475,11 +475,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
encap_type == UDP_ENCAP_ESPINUDP))) { encap_type == UDP_ENCAP_ESPINUDP))) {
x = xfrm_input_state(skb); x = xfrm_input_state(skb);
if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
goto drop;
}
if (unlikely(x->km.state != XFRM_STATE_VALID)) { if (unlikely(x->km.state != XFRM_STATE_VALID)) {
if (x->km.state == XFRM_STATE_ACQ) if (x->km.state == XFRM_STATE_ACQ)
XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR); XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
@ -586,8 +581,11 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
} }
if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) { if (unlikely(x->dir && x->dir != XFRM_SA_DIR_IN)) {
secpath_reset(skb);
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR); XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
xfrm_audit_state_notfound(skb, family, spi, seq);
xfrm_state_put(x); xfrm_state_put(x);
x = NULL;
goto drop; goto drop;
} }

View File

@ -452,6 +452,8 @@ EXPORT_SYMBOL(xfrm_policy_destroy);
static void xfrm_policy_kill(struct xfrm_policy *policy) static void xfrm_policy_kill(struct xfrm_policy *policy)
{ {
xfrm_dev_policy_delete(policy);
write_lock_bh(&policy->lock); write_lock_bh(&policy->lock);
policy->walk.dead = 1; policy->walk.dead = 1;
write_unlock_bh(&policy->lock); write_unlock_bh(&policy->lock);
@ -1850,7 +1852,6 @@ again:
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_dev_policy_delete(pol);
cnt++; cnt++;
xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_audit_policy_delete(pol, 1, task_valid);
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
@ -1891,7 +1892,6 @@ again:
__xfrm_policy_unlink(pol, dir); __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
xfrm_dev_policy_delete(pol);
cnt++; cnt++;
xfrm_audit_policy_delete(pol, 1, task_valid); xfrm_audit_policy_delete(pol, 1, task_valid);
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
@ -2342,7 +2342,6 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
pol = __xfrm_policy_unlink(pol, dir); pol = __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (pol) { if (pol) {
xfrm_dev_policy_delete(pol);
xfrm_policy_kill(pol); xfrm_policy_kill(pol);
return 0; return 0;
} }

View File

@ -49,6 +49,7 @@ static struct kmem_cache *xfrm_state_cache __ro_after_init;
static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task); static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task);
static HLIST_HEAD(xfrm_state_gc_list); static HLIST_HEAD(xfrm_state_gc_list);
static HLIST_HEAD(xfrm_state_dev_gc_list);
static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x) static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x)
{ {
@ -214,6 +215,7 @@ static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO]; static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO];
static DEFINE_SPINLOCK(xfrm_state_gc_lock); static DEFINE_SPINLOCK(xfrm_state_gc_lock);
static DEFINE_SPINLOCK(xfrm_state_dev_gc_lock);
int __xfrm_state_delete(struct xfrm_state *x); int __xfrm_state_delete(struct xfrm_state *x);
@ -683,6 +685,41 @@ struct xfrm_state *xfrm_state_alloc(struct net *net)
} }
EXPORT_SYMBOL(xfrm_state_alloc); EXPORT_SYMBOL(xfrm_state_alloc);
#ifdef CONFIG_XFRM_OFFLOAD
void xfrm_dev_state_delete(struct xfrm_state *x)
{
struct xfrm_dev_offload *xso = &x->xso;
struct net_device *dev = READ_ONCE(xso->dev);
if (dev) {
dev->xfrmdev_ops->xdo_dev_state_delete(x);
spin_lock_bh(&xfrm_state_dev_gc_lock);
hlist_add_head(&x->dev_gclist, &xfrm_state_dev_gc_list);
spin_unlock_bh(&xfrm_state_dev_gc_lock);
}
}
EXPORT_SYMBOL_GPL(xfrm_dev_state_delete);
void xfrm_dev_state_free(struct xfrm_state *x)
{
struct xfrm_dev_offload *xso = &x->xso;
struct net_device *dev = READ_ONCE(xso->dev);
if (dev && dev->xfrmdev_ops) {
spin_lock_bh(&xfrm_state_dev_gc_lock);
if (!hlist_unhashed(&x->dev_gclist))
hlist_del(&x->dev_gclist);
spin_unlock_bh(&xfrm_state_dev_gc_lock);
if (dev->xfrmdev_ops->xdo_dev_state_free)
dev->xfrmdev_ops->xdo_dev_state_free(x);
WRITE_ONCE(xso->dev, NULL);
xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
netdev_put(dev, &xso->dev_tracker);
}
}
#endif
void __xfrm_state_destroy(struct xfrm_state *x, bool sync) void __xfrm_state_destroy(struct xfrm_state *x, bool sync)
{ {
WARN_ON(x->km.state != XFRM_STATE_DEAD); WARN_ON(x->km.state != XFRM_STATE_DEAD);
@ -849,6 +886,9 @@ EXPORT_SYMBOL(xfrm_state_flush);
int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid) int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid)
{ {
struct xfrm_state *x;
struct hlist_node *tmp;
struct xfrm_dev_offload *xso;
int i, err = 0, cnt = 0; int i, err = 0, cnt = 0;
spin_lock_bh(&net->xfrm.xfrm_state_lock); spin_lock_bh(&net->xfrm.xfrm_state_lock);
@ -858,8 +898,6 @@ int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_vali
err = -ESRCH; err = -ESRCH;
for (i = 0; i <= net->xfrm.state_hmask; i++) { for (i = 0; i <= net->xfrm.state_hmask; i++) {
struct xfrm_state *x;
struct xfrm_dev_offload *xso;
restart: restart:
hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
xso = &x->xso; xso = &x->xso;
@ -869,6 +907,8 @@ restart:
spin_unlock_bh(&net->xfrm.xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
err = xfrm_state_delete(x); err = xfrm_state_delete(x);
xfrm_dev_state_free(x);
xfrm_audit_state_delete(x, err ? 0 : 1, xfrm_audit_state_delete(x, err ? 0 : 1,
task_valid); task_valid);
xfrm_state_put(x); xfrm_state_put(x);
@ -885,6 +925,24 @@ restart:
out: out:
spin_unlock_bh(&net->xfrm.xfrm_state_lock); spin_unlock_bh(&net->xfrm.xfrm_state_lock);
spin_lock_bh(&xfrm_state_dev_gc_lock);
restart_gc:
hlist_for_each_entry_safe(x, tmp, &xfrm_state_dev_gc_list, dev_gclist) {
xso = &x->xso;
if (xso->dev == dev) {
spin_unlock_bh(&xfrm_state_dev_gc_lock);
xfrm_dev_state_free(x);
spin_lock_bh(&xfrm_state_dev_gc_lock);
goto restart_gc;
}
}
spin_unlock_bh(&xfrm_state_dev_gc_lock);
xfrm_flush_gc();
return err; return err;
} }
EXPORT_SYMBOL(xfrm_dev_state_flush); EXPORT_SYMBOL(xfrm_dev_state_flush);
@ -1274,8 +1332,7 @@ found:
xso->dev = xdo->dev; xso->dev = xdo->dev;
xso->real_dev = xdo->real_dev; xso->real_dev = xdo->real_dev;
xso->flags = XFRM_DEV_OFFLOAD_FLAG_ACQ; xso->flags = XFRM_DEV_OFFLOAD_FLAG_ACQ;
netdev_tracker_alloc(xso->dev, &xso->dev_tracker, netdev_hold(xso->dev, &xso->dev_tracker, GFP_ATOMIC);
GFP_ATOMIC);
error = xso->dev->xfrmdev_ops->xdo_dev_state_add(x, NULL); error = xso->dev->xfrmdev_ops->xdo_dev_state_add(x, NULL);
if (error) { if (error) {
xso->dir = 0; xso->dir = 0;

View File

@ -2466,7 +2466,6 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
NETLINK_CB(skb).portid); NETLINK_CB(skb).portid);
} }
} else { } else {
xfrm_dev_policy_delete(xp);
xfrm_audit_policy_delete(xp, err ? 0 : 1, true); xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
if (err != 0) if (err != 0)

View File

@ -122,6 +122,8 @@ devlink_reload()
still_pending=$(devlink resource show "$DEVLINK_DEV" | \ still_pending=$(devlink resource show "$DEVLINK_DEV" | \
grep -c "size_new") grep -c "size_new")
check_err $still_pending "Failed reload - There are still unset sizes" check_err $still_pending "Failed reload - There are still unset sizes"
udevadm settle
} }
declare -A DEVLINK_ORIG declare -A DEVLINK_ORIG

View File

@ -59,6 +59,7 @@
# while it is forwarded between different vrfs. # while it is forwarded between different vrfs.
source lib.sh source lib.sh
PATH=$PWD:$PWD/tools/testing/selftests/net:$PATH
VERBOSE=0 VERBOSE=0
PAUSE_ON_FAIL=no PAUSE_ON_FAIL=no
DEFAULT_TTYPE=sym DEFAULT_TTYPE=sym
@ -533,6 +534,86 @@ ipv6_ping_frag_asym()
ipv6_ping_frag asym ipv6_ping_frag asym
} }
ipv4_ping_local()
{
log_section "IPv4 (sym route): VRF ICMP local error route lookup ping"
setup_sym
check_connectivity || return
run_cmd ip netns exec $r1 ip vrf exec blue ping -c1 -w1 ${H2_N2_IP}
log_test $? 0 "VRF ICMP local IPv4"
}
ipv4_tcp_local()
{
log_section "IPv4 (sym route): VRF tcp local connection"
setup_sym
check_connectivity || return
run_cmd nettest -s -O "$h2" -l ${H2_N2_IP} -I eth0 -3 eth0 &
sleep 1
run_cmd nettest -N "$r1" -d blue -r ${H2_N2_IP}
log_test $? 0 "VRF tcp local connection IPv4"
}
ipv4_udp_local()
{
log_section "IPv4 (sym route): VRF udp local connection"
setup_sym
check_connectivity || return
run_cmd nettest -s -D -O "$h2" -l ${H2_N2_IP} -I eth0 -3 eth0 &
sleep 1
run_cmd nettest -D -N "$r1" -d blue -r ${H2_N2_IP}
log_test $? 0 "VRF udp local connection IPv4"
}
ipv6_ping_local()
{
log_section "IPv6 (sym route): VRF ICMP local error route lookup ping"
setup_sym
check_connectivity6 || return
run_cmd ip netns exec $r1 ip vrf exec blue ${ping6} -c1 -w1 ${H2_N2_IP6}
log_test $? 0 "VRF ICMP local IPv6"
}
ipv6_tcp_local()
{
log_section "IPv6 (sym route): VRF tcp local connection"
setup_sym
check_connectivity6 || return
run_cmd nettest -s -6 -O "$h2" -l ${H2_N2_IP6} -I eth0 -3 eth0 &
sleep 1
run_cmd nettest -6 -N "$r1" -d blue -r ${H2_N2_IP6}
log_test $? 0 "VRF tcp local connection IPv6"
}
ipv6_udp_local()
{
log_section "IPv6 (sym route): VRF udp local connection"
setup_sym
check_connectivity6 || return
run_cmd nettest -s -6 -D -O "$h2" -l ${H2_N2_IP6} -I eth0 -3 eth0 &
sleep 1
run_cmd nettest -6 -D -N "$r1" -d blue -r ${H2_N2_IP6}
log_test $? 0 "VRF udp local connection IPv6"
}
################################################################################ ################################################################################
# usage # usage
@ -555,8 +636,10 @@ EOF
# Some systems don't have a ping6 binary anymore # Some systems don't have a ping6 binary anymore
command -v ping6 > /dev/null 2>&1 && ping6=$(command -v ping6) || ping6=$(command -v ping) command -v ping6 > /dev/null 2>&1 && ping6=$(command -v ping6) || ping6=$(command -v ping)
TESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_ttl_asym ipv4_traceroute_asym" TESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_local ipv4_tcp_local
TESTS_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_ttl_asym ipv6_traceroute_asym" ipv4_udp_local ipv4_ping_ttl_asym ipv4_traceroute_asym"
TESTS_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_local ipv6_tcp_local ipv6_udp_local
ipv6_ping_ttl_asym ipv6_traceroute_asym"
ret=0 ret=0
nsuccess=0 nsuccess=0
@ -594,12 +677,18 @@ do
ipv4_traceroute|traceroute) ipv4_traceroute;;& ipv4_traceroute|traceroute) ipv4_traceroute;;&
ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;& ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;&
ipv4_ping_frag|ping) ipv4_ping_frag;;& ipv4_ping_frag|ping) ipv4_ping_frag;;&
ipv4_ping_local|ping) ipv4_ping_local;;&
ipv4_tcp_local) ipv4_tcp_local;;&
ipv4_udp_local) ipv4_udp_local;;&
ipv6_ping_ttl|ping) ipv6_ping_ttl;;& ipv6_ping_ttl|ping) ipv6_ping_ttl;;&
ipv6_ping_ttl_asym|ping) ipv6_ping_ttl_asym;;& ipv6_ping_ttl_asym|ping) ipv6_ping_ttl_asym;;&
ipv6_traceroute|traceroute) ipv6_traceroute;;& ipv6_traceroute|traceroute) ipv6_traceroute;;&
ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;& ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;&
ipv6_ping_frag|ping) ipv6_ping_frag;;& ipv6_ping_frag|ping) ipv6_ping_frag;;&
ipv6_ping_local|ping) ipv6_ping_local;;&
ipv6_tcp_local) ipv6_tcp_local;;&
ipv6_udp_local) ipv6_udp_local;;&
# setup namespaces and config, but do not run any tests # setup namespaces and config, but do not run any tests
setup_sym|setup) setup_sym; exit 0;; setup_sym|setup) setup_sym; exit 0;;