mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
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:
commit
51b35d4f9d
@ -973,6 +973,7 @@ restart:
|
||||
/* rtnl_lock already held
|
||||
* we might sleep in __netpoll_cleanup()
|
||||
*/
|
||||
nt->enabled = false;
|
||||
spin_unlock_irqrestore(&target_list_lock, flags);
|
||||
|
||||
__netpoll_cleanup(&nt->np);
|
||||
@ -980,7 +981,6 @@ restart:
|
||||
spin_lock_irqsave(&target_list_lock, flags);
|
||||
netdev_put(nt->np.dev, &nt->np.dev_tracker);
|
||||
nt->np.dev = NULL;
|
||||
nt->enabled = false;
|
||||
stopped = true;
|
||||
netconsole_target_put(nt);
|
||||
goto restart;
|
||||
|
@ -832,13 +832,13 @@ int pse_ethtool_set_config(struct pse_control *psec,
|
||||
{
|
||||
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);
|
||||
if (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);
|
||||
|
||||
return err;
|
||||
|
@ -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,
|
||||
const struct in6_addr *daddr,
|
||||
unsigned int prefs,
|
||||
unsigned int prefs, int l3mdev_index,
|
||||
struct in6_addr *saddr)
|
||||
{
|
||||
struct net_device *l3mdev;
|
||||
struct net_device *dev;
|
||||
bool same_vrf;
|
||||
int err = 0;
|
||||
|
||||
if (f6i && f6i->fib6_prefsrc.plen) {
|
||||
*saddr = f6i->fib6_prefsrc.addr;
|
||||
} else {
|
||||
struct net_device *dev = f6i ? fib6_info_nh_dev(f6i) : NULL;
|
||||
rcu_read_lock();
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -178,7 +178,10 @@ struct xfrm_state {
|
||||
struct hlist_node gclist;
|
||||
struct hlist_node bydst;
|
||||
};
|
||||
struct hlist_node bysrc;
|
||||
union {
|
||||
struct hlist_node dev_gclist;
|
||||
struct hlist_node bysrc;
|
||||
};
|
||||
struct hlist_node byspi;
|
||||
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)
|
||||
{
|
||||
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 &&
|
||||
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 netlink_ext_ack *extack);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
xso->dev->xfrmdev_ops->xdo_dev_state_advance_esn(x);
|
||||
if (dev && dev->xfrmdev_ops->xdo_dev_state_advance_esn)
|
||||
dev->xfrmdev_ops->xdo_dev_state_advance_esn(x);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct xfrm_dev_offload *xdo = &x->xdo;
|
||||
|
@ -25,8 +25,8 @@ static inline int should_deliver(const struct net_bridge_port *p,
|
||||
|
||||
vg = nbp_vlan_group_rcu(p);
|
||||
return ((p->flags & BR_HAIRPIN_MODE) || skb->dev != p->dev) &&
|
||||
p->state == BR_STATE_FORWARDING && br_allowed_egress(vg, skb) &&
|
||||
nbp_switchdev_allowed_egress(p, skb) &&
|
||||
(br_mst_is_enabled(p->br) || p->state == BR_STATE_FORWARDING) &&
|
||||
br_allowed_egress(vg, skb) && nbp_switchdev_allowed_egress(p, skb) &&
|
||||
!br_skb_isolated(p, skb);
|
||||
}
|
||||
|
||||
|
@ -127,10 +127,8 @@ void xdp_unreg_mem_model(struct xdp_mem_info *mem)
|
||||
return;
|
||||
|
||||
if (type == MEM_TYPE_PAGE_POOL) {
|
||||
rcu_read_lock();
|
||||
xa = rhashtable_lookup(mem_id_ht, &id, mem_id_rht_params);
|
||||
xa = rhashtable_lookup_fast(mem_id_ht, &id, mem_id_rht_params);
|
||||
page_pool_destroy(xa->page_pool);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdp_unreg_mem_model);
|
||||
|
@ -277,17 +277,21 @@ ethnl_set_pse(struct ethnl_req_info *req_info, struct genl_info *info)
|
||||
tb[ETHTOOL_A_C33_PSE_ADMIN_CONTROL]) {
|
||||
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]);
|
||||
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]);
|
||||
|
||||
/* pse_ethtool_set_config() will do nothing if the config
|
||||
* is zero
|
||||
*/
|
||||
ret = pse_ethtool_set_config(phydev->psec, info->extack,
|
||||
&config);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return errno or zero - PSE has no notification */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -239,8 +239,7 @@ static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
|
||||
#else
|
||||
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
|
||||
WARN_ON(1);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
@ -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,
|
||||
(xfrm_address_t *)&ip_hdr(skb)->daddr,
|
||||
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)
|
||||
goto out_reset;
|
||||
|
||||
|
@ -2269,6 +2269,15 @@ void fib_select_path(struct net *net, struct fib_result *res,
|
||||
fib_select_default(fl4, res);
|
||||
|
||||
check_saddr:
|
||||
if (!fl4->saddr)
|
||||
fl4->saddr = fib_result_prefsrc(net, res);
|
||||
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);
|
||||
else
|
||||
fl4->saddr = inet_select_addr(l3mdev, 0, RT_SCOPE_LINK);
|
||||
}
|
||||
}
|
||||
|
@ -1873,7 +1873,8 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev,
|
||||
master, &dst,
|
||||
scores, hiscore_idx);
|
||||
|
||||
if (scores[hiscore_idx].ifa)
|
||||
if (scores[hiscore_idx].ifa &&
|
||||
scores[hiscore_idx].scopedist >= 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -256,8 +256,7 @@ static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
|
||||
#else
|
||||
static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
|
||||
{
|
||||
kfree_skb(skb);
|
||||
|
||||
WARN_ON(1);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
@ -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,
|
||||
(xfrm_address_t *)&ipv6_hdr(skb)->daddr,
|
||||
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)
|
||||
goto out_reset;
|
||||
|
||||
|
@ -1124,6 +1124,7 @@ static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk,
|
||||
from = rt ? rcu_dereference(rt->from) : NULL;
|
||||
err = ip6_route_get_saddr(net, from, &fl6->daddr,
|
||||
sk ? READ_ONCE(inet6_sk(sk)->srcprefs) : 0,
|
||||
fl6->flowi6_l3mdev,
|
||||
&fl6->saddr);
|
||||
rcu_read_unlock();
|
||||
|
||||
|
@ -5687,7 +5687,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
|
||||
goto nla_put_failure;
|
||||
} else if (dest) {
|
||||
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))
|
||||
goto nla_put_failure;
|
||||
}
|
||||
|
@ -538,6 +538,61 @@ static void *packet_current_frame(struct packet_sock *po,
|
||||
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)
|
||||
{
|
||||
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,
|
||||
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)) {
|
||||
ppd->hv1.tp_vlan_tci = skb_vlan_tag_get(pkc->skb);
|
||||
ppd->hv1.tp_vlan_tpid = ntohs(pkc->skb->vlan_proto);
|
||||
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 {
|
||||
ppd->hv1.tp_vlan_tci = 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_tpid = ntohs(skb->vlan_proto);
|
||||
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 {
|
||||
h.h2->tp_vlan_tci = 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_family = AF_PACKET;
|
||||
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;
|
||||
if (unlikely(packet_sock_flag(po, PACKET_SOCK_ORIGDEV)))
|
||||
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 */
|
||||
origlen = PACKET_SKB_CB(skb)->sa.origlen;
|
||||
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);
|
||||
@ -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_tpid = ntohs(skb->vlan_proto);
|
||||
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 {
|
||||
aux.tp_vlan_tci = 0;
|
||||
aux.tp_vlan_tpid = 0;
|
||||
|
@ -475,11 +475,6 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
|
||||
encap_type == UDP_ENCAP_ESPINUDP))) {
|
||||
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 (x->km.state == XFRM_STATE_ACQ)
|
||||
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)) {
|
||||
secpath_reset(skb);
|
||||
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEDIRERROR);
|
||||
xfrm_audit_state_notfound(skb, family, spi, seq);
|
||||
xfrm_state_put(x);
|
||||
x = NULL;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
|
@ -452,6 +452,8 @@ EXPORT_SYMBOL(xfrm_policy_destroy);
|
||||
|
||||
static void xfrm_policy_kill(struct xfrm_policy *policy)
|
||||
{
|
||||
xfrm_dev_policy_delete(policy);
|
||||
|
||||
write_lock_bh(&policy->lock);
|
||||
policy->walk.dead = 1;
|
||||
write_unlock_bh(&policy->lock);
|
||||
@ -1850,7 +1852,6 @@ again:
|
||||
|
||||
__xfrm_policy_unlink(pol, dir);
|
||||
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
|
||||
xfrm_dev_policy_delete(pol);
|
||||
cnt++;
|
||||
xfrm_audit_policy_delete(pol, 1, task_valid);
|
||||
xfrm_policy_kill(pol);
|
||||
@ -1891,7 +1892,6 @@ again:
|
||||
|
||||
__xfrm_policy_unlink(pol, dir);
|
||||
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
|
||||
xfrm_dev_policy_delete(pol);
|
||||
cnt++;
|
||||
xfrm_audit_policy_delete(pol, 1, task_valid);
|
||||
xfrm_policy_kill(pol);
|
||||
@ -2342,7 +2342,6 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
|
||||
pol = __xfrm_policy_unlink(pol, dir);
|
||||
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
|
||||
if (pol) {
|
||||
xfrm_dev_policy_delete(pol);
|
||||
xfrm_policy_kill(pol);
|
||||
return 0;
|
||||
}
|
||||
|
@ -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 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)
|
||||
{
|
||||
@ -214,6 +215,7 @@ static DEFINE_SPINLOCK(xfrm_state_afinfo_lock);
|
||||
static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO];
|
||||
|
||||
static DEFINE_SPINLOCK(xfrm_state_gc_lock);
|
||||
static DEFINE_SPINLOCK(xfrm_state_dev_gc_lock);
|
||||
|
||||
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);
|
||||
|
||||
#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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
struct xfrm_state *x;
|
||||
struct hlist_node *tmp;
|
||||
struct xfrm_dev_offload *xso;
|
||||
int i, err = 0, cnt = 0;
|
||||
|
||||
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;
|
||||
for (i = 0; i <= net->xfrm.state_hmask; i++) {
|
||||
struct xfrm_state *x;
|
||||
struct xfrm_dev_offload *xso;
|
||||
restart:
|
||||
hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) {
|
||||
xso = &x->xso;
|
||||
@ -869,6 +907,8 @@ restart:
|
||||
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
|
||||
|
||||
err = xfrm_state_delete(x);
|
||||
xfrm_dev_state_free(x);
|
||||
|
||||
xfrm_audit_state_delete(x, err ? 0 : 1,
|
||||
task_valid);
|
||||
xfrm_state_put(x);
|
||||
@ -885,6 +925,24 @@ restart:
|
||||
|
||||
out:
|
||||
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;
|
||||
}
|
||||
EXPORT_SYMBOL(xfrm_dev_state_flush);
|
||||
@ -1274,8 +1332,7 @@ found:
|
||||
xso->dev = xdo->dev;
|
||||
xso->real_dev = xdo->real_dev;
|
||||
xso->flags = XFRM_DEV_OFFLOAD_FLAG_ACQ;
|
||||
netdev_tracker_alloc(xso->dev, &xso->dev_tracker,
|
||||
GFP_ATOMIC);
|
||||
netdev_hold(xso->dev, &xso->dev_tracker, GFP_ATOMIC);
|
||||
error = xso->dev->xfrmdev_ops->xdo_dev_state_add(x, NULL);
|
||||
if (error) {
|
||||
xso->dir = 0;
|
||||
|
@ -2466,7 +2466,6 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
|
||||
NETLINK_CB(skb).portid);
|
||||
}
|
||||
} else {
|
||||
xfrm_dev_policy_delete(xp);
|
||||
xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
|
||||
|
||||
if (err != 0)
|
||||
|
@ -122,6 +122,8 @@ devlink_reload()
|
||||
still_pending=$(devlink resource show "$DEVLINK_DEV" | \
|
||||
grep -c "size_new")
|
||||
check_err $still_pending "Failed reload - There are still unset sizes"
|
||||
|
||||
udevadm settle
|
||||
}
|
||||
|
||||
declare -A DEVLINK_ORIG
|
||||
|
@ -59,6 +59,7 @@
|
||||
# while it is forwarded between different vrfs.
|
||||
|
||||
source lib.sh
|
||||
PATH=$PWD:$PWD/tools/testing/selftests/net:$PATH
|
||||
VERBOSE=0
|
||||
PAUSE_ON_FAIL=no
|
||||
DEFAULT_TTYPE=sym
|
||||
@ -533,6 +534,86 @@ 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
|
||||
|
||||
@ -555,8 +636,10 @@ EOF
|
||||
# Some systems don't have a ping6 binary anymore
|
||||
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_IPV6="ipv6_ping_ttl ipv6_traceroute ipv6_ping_ttl_asym ipv6_traceroute_asym"
|
||||
TESTS_IPV4="ipv4_ping_ttl ipv4_traceroute ipv4_ping_frag ipv4_ping_local ipv4_tcp_local
|
||||
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
|
||||
nsuccess=0
|
||||
@ -594,12 +677,18 @@ do
|
||||
ipv4_traceroute|traceroute) ipv4_traceroute;;&
|
||||
ipv4_traceroute_asym|traceroute) ipv4_traceroute_asym;;&
|
||||
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_asym|ping) ipv6_ping_ttl_asym;;&
|
||||
ipv6_traceroute|traceroute) ipv6_traceroute;;&
|
||||
ipv6_traceroute_asym|traceroute) ipv6_traceroute_asym;;&
|
||||
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_sym|setup) setup_sym; exit 0;;
|
||||
|
Loading…
Reference in New Issue
Block a user