Skip to content

Commit 1a20e57

Browse files
committed
Merge: ipv6: stable backport for 9.7 phase 2
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6641 JIRA: https://issues.redhat.com/browse/RHEL-84573 Omitted-fix: 3ed61b8 ("selftests: net: test for lwtunnel dst ref loops") Omitted-fix: 0e7633d ("net: ipv6: fix dst ref loop in ila lwtunnel") Omitted-fix: 3ed61b8 ("selftests: net: test for lwtunnel dst ref loops") Signed-off-by: Hangbin Liu <haliu@redhat.com> Approved-by: Antoine Tenart <atenart@redhat.com> Approved-by: Ivan Vecera <ivecera@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Augusto Caringi <acaringi@redhat.com>
2 parents 912e5f3 + 350bfd4 commit 1a20e57

File tree

7 files changed

+60
-44
lines changed

7 files changed

+60
-44
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum_mr.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,10 +1003,10 @@ static void mlxsw_sp_mr_route_stats_update(struct mlxsw_sp *mlxsw_sp,
10031003
mr->mr_ops->route_stats(mlxsw_sp, mr_route->route_priv, &packets,
10041004
&bytes);
10051005

1006-
if (mr_route->mfc->mfc_un.res.pkt != packets)
1007-
mr_route->mfc->mfc_un.res.lastuse = jiffies;
1008-
mr_route->mfc->mfc_un.res.pkt = packets;
1009-
mr_route->mfc->mfc_un.res.bytes = bytes;
1006+
if (atomic_long_read(&mr_route->mfc->mfc_un.res.pkt) != packets)
1007+
WRITE_ONCE(mr_route->mfc->mfc_un.res.lastuse, jiffies);
1008+
atomic_long_set(&mr_route->mfc->mfc_un.res.pkt, packets);
1009+
atomic_long_set(&mr_route->mfc->mfc_un.res.bytes, bytes);
10101010
}
10111011

10121012
static void mlxsw_sp_mr_stats_update(struct work_struct *work)

include/linux/mroute_base.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ struct mr_mfc {
143143
unsigned long last_assert;
144144
int minvif;
145145
int maxvif;
146-
unsigned long bytes;
147-
unsigned long pkt;
148-
unsigned long wrong_if;
146+
atomic_long_t bytes;
147+
atomic_long_t pkt;
148+
atomic_long_t wrong_if;
149149
unsigned long lastuse;
150150
unsigned char ttls[MAXVIFS];
151151
refcount_t refcount;

net/ipv4/ipmr.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,7 @@ static void ipmr_update_thresholds(struct mr_table *mrt, struct mr_mfc *cache,
802802
cache->mfc_un.res.maxvif = vifi + 1;
803803
}
804804
}
805-
cache->mfc_un.res.lastuse = jiffies;
805+
WRITE_ONCE(cache->mfc_un.res.lastuse, jiffies);
806806
}
807807

808808
static int vif_add(struct net *net, struct mr_table *mrt,
@@ -1646,9 +1646,9 @@ int ipmr_ioctl(struct sock *sk, int cmd, void *arg)
16461646
rcu_read_lock();
16471647
c = ipmr_cache_find(mrt, sr->src.s_addr, sr->grp.s_addr);
16481648
if (c) {
1649-
sr->pktcnt = c->_c.mfc_un.res.pkt;
1650-
sr->bytecnt = c->_c.mfc_un.res.bytes;
1651-
sr->wrong_if = c->_c.mfc_un.res.wrong_if;
1649+
sr->pktcnt = atomic_long_read(&c->_c.mfc_un.res.pkt);
1650+
sr->bytecnt = atomic_long_read(&c->_c.mfc_un.res.bytes);
1651+
sr->wrong_if = atomic_long_read(&c->_c.mfc_un.res.wrong_if);
16521652
rcu_read_unlock();
16531653
return 0;
16541654
}
@@ -1718,9 +1718,9 @@ int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
17181718
rcu_read_lock();
17191719
c = ipmr_cache_find(mrt, sr.src.s_addr, sr.grp.s_addr);
17201720
if (c) {
1721-
sr.pktcnt = c->_c.mfc_un.res.pkt;
1722-
sr.bytecnt = c->_c.mfc_un.res.bytes;
1723-
sr.wrong_if = c->_c.mfc_un.res.wrong_if;
1721+
sr.pktcnt = atomic_long_read(&c->_c.mfc_un.res.pkt);
1722+
sr.bytecnt = atomic_long_read(&c->_c.mfc_un.res.bytes);
1723+
sr.wrong_if = atomic_long_read(&c->_c.mfc_un.res.wrong_if);
17241724
rcu_read_unlock();
17251725

17261726
if (copy_to_user(arg, &sr, sizeof(sr)))
@@ -1949,9 +1949,9 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
19491949
int vif, ct;
19501950

19511951
vif = c->_c.mfc_parent;
1952-
c->_c.mfc_un.res.pkt++;
1953-
c->_c.mfc_un.res.bytes += skb->len;
1954-
c->_c.mfc_un.res.lastuse = jiffies;
1952+
atomic_long_inc(&c->_c.mfc_un.res.pkt);
1953+
atomic_long_add(skb->len, &c->_c.mfc_un.res.bytes);
1954+
WRITE_ONCE(c->_c.mfc_un.res.lastuse, jiffies);
19551955

19561956
if (c->mfc_origin == htonl(INADDR_ANY) && true_vifi >= 0) {
19571957
struct mfc_cache *cache_proxy;
@@ -1982,7 +1982,7 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
19821982
goto dont_forward;
19831983
}
19841984

1985-
c->_c.mfc_un.res.wrong_if++;
1985+
atomic_long_inc(&c->_c.mfc_un.res.wrong_if);
19861986

19871987
if (true_vifi >= 0 && mrt->mroute_do_assert &&
19881988
/* pimsm uses asserts, when switching from RPT to SPT,
@@ -2994,9 +2994,9 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
29942994

29952995
if (it->cache != &mrt->mfc_unres_queue) {
29962996
seq_printf(seq, " %8lu %8lu %8lu",
2997-
mfc->_c.mfc_un.res.pkt,
2998-
mfc->_c.mfc_un.res.bytes,
2999-
mfc->_c.mfc_un.res.wrong_if);
2997+
atomic_long_read(&mfc->_c.mfc_un.res.pkt),
2998+
atomic_long_read(&mfc->_c.mfc_un.res.bytes),
2999+
atomic_long_read(&mfc->_c.mfc_un.res.wrong_if));
30003000
for (n = mfc->_c.mfc_un.res.minvif;
30013001
n < mfc->_c.mfc_un.res.maxvif; n++) {
30023002
if (VIF_EXISTS(mrt, n) &&

net/ipv4/ipmr_base.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,9 @@ int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
255255
lastuse = READ_ONCE(c->mfc_un.res.lastuse);
256256
lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
257257

258-
mfcs.mfcs_packets = c->mfc_un.res.pkt;
259-
mfcs.mfcs_bytes = c->mfc_un.res.bytes;
260-
mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
258+
mfcs.mfcs_packets = atomic_long_read(&c->mfc_un.res.pkt);
259+
mfcs.mfcs_bytes = atomic_long_read(&c->mfc_un.res.bytes);
260+
mfcs.mfcs_wrong_if = atomic_long_read(&c->mfc_un.res.wrong_if);
261261
if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
262262
nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
263263
RTA_PAD))

net/ipv6/ip6mr.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -488,9 +488,9 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
488488

489489
if (it->cache != &mrt->mfc_unres_queue) {
490490
seq_printf(seq, " %8lu %8lu %8lu",
491-
mfc->_c.mfc_un.res.pkt,
492-
mfc->_c.mfc_un.res.bytes,
493-
mfc->_c.mfc_un.res.wrong_if);
491+
atomic_long_read(&mfc->_c.mfc_un.res.pkt),
492+
atomic_long_read(&mfc->_c.mfc_un.res.bytes),
493+
atomic_long_read(&mfc->_c.mfc_un.res.wrong_if));
494494
for (n = mfc->_c.mfc_un.res.minvif;
495495
n < mfc->_c.mfc_un.res.maxvif; n++) {
496496
if (VIF_EXISTS(mrt, n) &&
@@ -855,7 +855,7 @@ static void ip6mr_update_thresholds(struct mr_table *mrt,
855855
cache->mfc_un.res.maxvif = vifi + 1;
856856
}
857857
}
858-
cache->mfc_un.res.lastuse = jiffies;
858+
WRITE_ONCE(cache->mfc_un.res.lastuse, jiffies);
859859
}
860860

861861
static int mif6_add(struct net *net, struct mr_table *mrt,
@@ -1903,9 +1903,9 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void *arg)
19031903
c = ip6mr_cache_find(mrt, &sr->src.sin6_addr,
19041904
&sr->grp.sin6_addr);
19051905
if (c) {
1906-
sr->pktcnt = c->_c.mfc_un.res.pkt;
1907-
sr->bytecnt = c->_c.mfc_un.res.bytes;
1908-
sr->wrong_if = c->_c.mfc_un.res.wrong_if;
1906+
sr->pktcnt = atomic_long_read(&c->_c.mfc_un.res.pkt);
1907+
sr->bytecnt = atomic_long_read(&c->_c.mfc_un.res.bytes);
1908+
sr->wrong_if = atomic_long_read(&c->_c.mfc_un.res.wrong_if);
19091909
rcu_read_unlock();
19101910
return 0;
19111911
}
@@ -1975,9 +1975,9 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
19751975
rcu_read_lock();
19761976
c = ip6mr_cache_find(mrt, &sr.src.sin6_addr, &sr.grp.sin6_addr);
19771977
if (c) {
1978-
sr.pktcnt = c->_c.mfc_un.res.pkt;
1979-
sr.bytecnt = c->_c.mfc_un.res.bytes;
1980-
sr.wrong_if = c->_c.mfc_un.res.wrong_if;
1978+
sr.pktcnt = atomic_long_read(&c->_c.mfc_un.res.pkt);
1979+
sr.bytecnt = atomic_long_read(&c->_c.mfc_un.res.bytes);
1980+
sr.wrong_if = atomic_long_read(&c->_c.mfc_un.res.wrong_if);
19811981
rcu_read_unlock();
19821982

19831983
if (copy_to_user(arg, &sr, sizeof(sr)))
@@ -2097,9 +2097,9 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
20972097
int true_vifi = ip6mr_find_vif(mrt, dev);
20982098

20992099
vif = c->_c.mfc_parent;
2100-
c->_c.mfc_un.res.pkt++;
2101-
c->_c.mfc_un.res.bytes += skb->len;
2102-
c->_c.mfc_un.res.lastuse = jiffies;
2100+
atomic_long_inc(&c->_c.mfc_un.res.pkt);
2101+
atomic_long_add(skb->len, &c->_c.mfc_un.res.bytes);
2102+
WRITE_ONCE(c->_c.mfc_un.res.lastuse, jiffies);
21032103

21042104
if (ipv6_addr_any(&c->mf6c_origin) && true_vifi >= 0) {
21052105
struct mfc6_cache *cache_proxy;
@@ -2121,7 +2121,7 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
21212121
* Wrong interface: drop packet and (maybe) send PIM assert.
21222122
*/
21232123
if (mrt->vif_table[vif].dev != dev) {
2124-
c->_c.mfc_un.res.wrong_if++;
2124+
atomic_long_inc(&c->_c.mfc_un.res.wrong_if);
21252125

21262126
if (true_vifi >= 0 && mrt->mroute_do_assert &&
21272127
/* pimsm uses asserts, when switching from RPT to SPT,

net/ipv6/route.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3655,7 +3655,8 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
36553655
in6_dev_put(idev);
36563656

36573657
if (err) {
3658-
lwtstate_put(fib6_nh->fib_nh_lws);
3658+
fib_nh_common_release(&fib6_nh->nh_common);
3659+
fib6_nh->nh_common.nhc_pcpu_rth_output = NULL;
36593660
fib6_nh->fib_nh_lws = NULL;
36603661
netdev_put(dev, dev_tracker);
36613662
}
@@ -3831,10 +3832,12 @@ static struct fib6_info *ip6_route_info_create(struct fib6_config *cfg,
38313832
if (nh) {
38323833
if (rt->fib6_src.plen) {
38333834
NL_SET_ERR_MSG(extack, "Nexthops can not be used with source routing");
3835+
err = -EINVAL;
38343836
goto out_free;
38353837
}
38363838
if (!nexthop_get(nh)) {
38373839
NL_SET_ERR_MSG(extack, "Nexthop has been deleted");
3840+
err = -ENOENT;
38383841
goto out_free;
38393842
}
38403843
rt->nh = nh;

net/ipv6/seg6_iptunnel.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -455,22 +455,32 @@ static int seg6_input_core(struct net *net, struct sock *sk,
455455
{
456456
struct dst_entry *orig_dst = skb_dst(skb);
457457
struct dst_entry *dst = NULL;
458+
struct lwtunnel_state *lwtst;
458459
struct seg6_lwt *slwt;
459460
int err;
460461

461462
err = seg6_do_srh(skb);
462463
if (unlikely(err))
463464
goto drop;
464465

465-
slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
466+
/* We cannot dereference "orig_dst" once ip6_route_input() or
467+
* skb_dst_drop() is called. However, in order to detect a dst loop, we
468+
* need the address of its lwtstate. So, save the address of lwtstate
469+
* now and use it later as a comparison.
470+
*/
471+
lwtst = orig_dst->lwtstate;
472+
473+
slwt = seg6_lwt_lwtunnel(lwtst);
466474

467475
local_bh_disable();
468476
dst = dst_cache_get(&slwt->cache);
469477

470478
if (!dst) {
471479
ip6_route_input(skb);
472480
dst = skb_dst(skb);
473-
if (!dst->error) {
481+
482+
/* cache only if we don't create a dst reference loop */
483+
if (!dst->error && lwtst != dst->lwtstate) {
474484
dst_cache_set_ip6(&slwt->cache, dst,
475485
&ipv6_hdr(skb)->saddr);
476486
}
@@ -556,9 +566,12 @@ static int seg6_output_core(struct net *net, struct sock *sk,
556566
goto drop;
557567
}
558568

559-
local_bh_disable();
560-
dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
561-
local_bh_enable();
569+
/* cache only if we don't create a dst reference loop */
570+
if (orig_dst->lwtstate != dst->lwtstate) {
571+
local_bh_disable();
572+
dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
573+
local_bh_enable();
574+
}
562575
}
563576

564577
skb_dst_drop(skb);

0 commit comments

Comments
 (0)