Skip to content

Commit b541e7b

Browse files
l0rdg3xplappermaul
authored andcommitted
realtek: l3: drop the route hash table
The rhltable keyed on the gateway had two lookups. In otto_l3_nexthop_update() it only let a gateway that no route has leave early; for one that some route has, the function walked routes_list right after. otto_l3_fib_del_v4() looked the route up by gateway, though otto_l3_route_find() had already found it by table and destination a few lines earlier. Both run on the single-threaded queue that already walks the list without a lock, and the tables are small, so the list serves both. The table goes, with its init, destroy, insert and remove, and the insert failure path; the comments and log lines that spoke of it are reworded. The handling stays the same: a neighbour update still returns -ENOENT for a gateway that no route has, and a delete still tears the route of that destination down only if it is via that gateway. Of the two errors for a route not found on delete, by gateway and by destination, the second one remains. Tested on a Hasivo S1100W-8XGT-SE (RTL9303), before and after: a route via a host forwards, traps once the host's neighbour entry is deleted and forwards again once it is resolved, and its delete leaves no row. The bench rounds on trap rows and on source-specific IPv6 routes pass 46 of 46 and 20 of 20, as before. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net> Link: openwrt/openwrt#25643 Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
1 parent 62ac036 commit b541e7b

2 files changed

Lines changed: 25 additions & 80 deletions

File tree

  • target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx

‎target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c‎

Lines changed: 24 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
#include <linux/iopoll.h>
6767
#include <linux/notifier.h>
6868
#include <linux/of.h>
69-
#include <linux/rhashtable.h>
7069
#include <linux/seq_file.h>
7170
#include <net/arp.h>
7271
#include <net/fib_notifier.h>
@@ -114,12 +113,6 @@
114113
#define MAX_ROUTER_MACS 64
115114
#define L3_EGRESS_DMACS 2048
116115

117-
static const struct rhashtable_params otto_l3_route_ht_params = {
118-
.key_len = sizeof(struct in6_addr),
119-
.key_offset = offsetof(struct otto_l3_route, gw_ip),
120-
.head_offset = offsetof(struct otto_l3_route, linkage),
121-
};
122-
123116
struct otto_l3_net_event_work {
124117
struct work_struct work;
125118
struct otto_l3_ctrl *ctrl;
@@ -1440,29 +1433,18 @@ static int otto_l3_nexthop_update(struct otto_l3_ctrl *ctrl, u8 type, int ifinde
14401433
const struct in6_addr *gw, u64 mac, bool valid)
14411434
{
14421435
struct otto_l3_route *r;
1443-
bool known;
1444-
1445-
/* The lookup runs in the section the rhashtable asks for and ends
1446-
* there: on a kernel without preemptible RCU that section is
1447-
* preempt_disable(), and every table op below it sleeps on a mutex.
1448-
* Only whether the gateway is known leaves that section, so no
1449-
* rhashtable pointer outlives it. The routes it would have walked are
1450-
* the ones on the driver's own list with that gateway, and the work
1451-
* queue that runs this is single threaded, which is what lets the rest
1452-
* of the driver walk that list with no lock.
1453-
*/
1454-
rcu_read_lock();
1455-
known = rhltable_lookup(&ctrl->routes, gw, otto_l3_route_ht_params);
1456-
rcu_read_unlock();
1457-
if (!known)
1458-
return -ENOENT;
1436+
bool known = false;
14591437

14601438
list_for_each_entry(r, &ctrl->routes_list, list) {
1439+
if (!ipv6_addr_equal(&r->gw_ip, gw))
1440+
continue;
1441+
1442+
known = true;
1443+
14611444
/* An IPv4 gateway written v4-mapped is a valid IPv6 one, so
1462-
* the key alone does not say whose route this is.
1445+
* the address alone does not say whose route this is.
14631446
*/
1464-
if (r->attr.type != type || r->gw_ifindex != ifindex ||
1465-
!ipv6_addr_equal(&r->gw_ip, gw))
1447+
if (r->attr.type != type || r->gw_ifindex != ifindex)
14661448
continue;
14671449

14681450
if (valid)
@@ -1471,17 +1453,20 @@ static int otto_l3_nexthop_update(struct otto_l3_ctrl *ctrl, u8 type, int ifinde
14711453
otto_l3_route_trap_hw(ctrl, r);
14721454
}
14731455

1456+
if (!known)
1457+
return -ENOENT;
1458+
14741459
/* An address of one family can be written as an address of the other,
14751460
* so a neighbour of the wrong family reaches this far without having
14761461
* placed anything, and has nothing to report.
14771462
*/
14781463
if (type != ROUTE_TYPE_IP6UC)
14791464
return 0;
14801465

1481-
/* Reporting the offload allocates and can send a netlink message, so it
1482-
* waits until the lookup above is over. It takes no lock of its own,
1483-
* so unlike the FIB work this path needs no rtnl. The FIB notifier is
1484-
* registered on init_net, which is where every route here comes from.
1466+
/* Reporting the offload allocates and can send a netlink message. It
1467+
* takes no lock of its own, so unlike the FIB work this path needs no
1468+
* rtnl. The FIB notifier is registered on init_net, which is where
1469+
* every route here comes from.
14851470
*/
14861471
list_for_each_entry(r, &ctrl->routes_list, list) {
14871472
bool trap;
@@ -1575,9 +1560,6 @@ static bool otto_l3_route_is_at(struct otto_l3_ctrl *ctrl, int id, struct otto_l
15751560
return false;
15761561
}
15771562

1578-
/* The routes are hashed on the gateway, which is the field a replace
1579-
* changes, so a lookup by destination needs a list of its own.
1580-
*/
15811563
static struct otto_l3_route *otto_l3_route_find(struct otto_l3_ctrl *ctrl, u32 tb_id, u8 type,
15821564
u32 dst_ip, const struct in6_addr *dst_ip6,
15831565
int prefix_len)
@@ -1616,9 +1598,6 @@ static void otto_l3_route_free(struct otto_l3_ctrl *ctrl, struct otto_l3_route *
16161598
{
16171599
struct otto_l3_route_src *s, *tmp;
16181600

1619-
if (rhltable_remove(&ctrl->routes, &r->linkage, otto_l3_route_ht_params))
1620-
dev_warn(ctrl->dev, "Could not remove route\n");
1621-
16221601
list_for_each_entry_safe(s, tmp, &r->srcs, list)
16231602
kfree(s);
16241603

@@ -1729,7 +1708,7 @@ static struct otto_l3_route *otto_l3_route_alloc(struct otto_l3_ctrl *ctrl,
17291708
unsigned long *use_bm = host ? ctrl->host_route_use_bm : ctrl->route_use_bm;
17301709
int size = host ? MAX_HOST_ROUTES : MAX_ROUTES;
17311710
struct otto_l3_route *r;
1732-
int idx, err;
1711+
int idx;
17331712

17341713
mutex_lock(ctrl->lock);
17351714

@@ -1759,14 +1738,6 @@ static struct otto_l3_route *otto_l3_route_alloc(struct otto_l3_ctrl *ctrl,
17591738
r->is_host_route = host;
17601739
INIT_LIST_HEAD(&r->srcs);
17611740

1762-
err = rhltable_insert(&ctrl->routes, &r->linkage, otto_l3_route_ht_params);
1763-
if (err) {
1764-
dev_err(ctrl->dev, "Could not insert new rule\n");
1765-
mutex_unlock(ctrl->lock);
1766-
kfree(r);
1767-
return NULL;
1768-
}
1769-
17701741
list_add_tail(&r->list, &ctrl->routes_list);
17711742
set_bit(idx, use_bm);
17721743

@@ -1983,9 +1954,9 @@ static int otto_l3_fib_add_v4(struct otto_l3_ctrl *ctrl, struct fib_entry_notifi
19831954
ROUTE_HOST : ROUTE_PREFIX);
19841955

19851956
if (route)
1986-
dev_info(ctrl->dev, "route hashtable extended for gw %pI4\n", &nh->fib_nh_gw4);
1957+
dev_info(ctrl->dev, "route allocated for gw %pI4\n", &nh->fib_nh_gw4);
19871958
else {
1988-
dev_err(ctrl->dev, "could not extend route hashtable for gw %pI4\n",
1959+
dev_err(ctrl->dev, "could not allocate a route for gw %pI4\n",
19891960
&nh->fib_nh_gw4);
19901961
return -ENOSPC;
19911962
}
@@ -2062,9 +2033,7 @@ static int otto_l3_fib_add_v4(struct otto_l3_ctrl *ctrl, struct fib_entry_notifi
20622033

20632034
static int otto_l3_fib_del_v4(struct otto_l3_ctrl *ctrl, struct fib_entry_notifier_info *info)
20642035
{
2065-
struct rhlist_head *tmp, *list;
20662036
struct otto_l3_route *route;
2067-
bool found = false;
20682037
struct in6_addr gw;
20692038
struct fib_nh *nh;
20702039

@@ -2085,7 +2054,7 @@ static int otto_l3_fib_del_v4(struct otto_l3_ctrl *ctrl, struct fib_entry_notifi
20852054
if (otto_l3_fib_check_v4(ctrl, info, FIB_EVENT_ENTRY_DEL))
20862055
return 0;
20872056

2088-
/* The entry that traps for a route left out is keyed on no gateway,
2057+
/* The entry that traps for a route left out carries no gateway,
20892058
* whatever gateway the route itself names
20902059
*/
20912060
route = otto_l3_route_find(ctrl, info->tb_id, ROUTE_TYPE_IP4UC, info->dst, NULL,
@@ -2098,29 +2067,13 @@ static int otto_l3_fib_del_v4(struct otto_l3_ctrl *ctrl, struct fib_entry_notifi
20982067

20992068
ipv6_addr_set_v4mapped(nh->fib_nh_gw4, &gw);
21002069

2101-
rcu_read_lock();
2102-
list = rhltable_lookup(&ctrl->routes, &gw, otto_l3_route_ht_params);
2103-
if (!list) {
2104-
rcu_read_unlock();
2105-
dev_err(ctrl->dev, "no such gateway: %pI4\n", &nh->fib_nh_gw4);
2106-
return -ENOENT;
2107-
}
2108-
rhl_for_each_entry_rcu(route, tmp, list, linkage) {
2109-
if (route->attr.type == ROUTE_TYPE_IP4UC &&
2110-
route->dst_ip == info->dst && route->prefix_len == info->dst_len) {
2111-
dev_info(ctrl->dev, "found a route with id %d, nh-id %d\n",
2112-
route->id, route->nh.id);
2113-
found = true;
2114-
break;
2115-
}
2116-
}
2117-
rcu_read_unlock();
2118-
2119-
if (!found) {
2070+
if (!route || !ipv6_addr_equal(&route->gw_ip, &gw)) {
21202071
dev_err(ctrl->dev, "no route %pI4/%d via %pI4\n",
21212072
&info->dst, info->dst_len, &nh->fib_nh_gw4);
21222073
return -ENOENT;
21232074
}
2075+
dev_info(ctrl->dev, "found a route with id %d, nh-id %d\n",
2076+
route->id, route->nh.id);
21242077

21252078
otto_l3_route_teardown(ctrl, route);
21262079

@@ -2477,7 +2430,7 @@ static int otto_l3_fib_add_v6(struct otto_l3_ctrl *ctrl, struct fib6_entry_notif
24772430

24782431
route = otto_l3_route_alloc(ctrl, gw, ROUTE_PREFIX);
24792432
if (!route) {
2480-
dev_err(ctrl->dev, "could not extend route hashtable for gw %pI6c\n", gw);
2433+
dev_err(ctrl->dev, "could not allocate a route for gw %pI6c\n", gw);
24812434
goto out_failed;
24822435
}
24832436

@@ -3670,14 +3623,12 @@ void otto_l3_remove(struct rtl838x_switch_priv *priv)
36703623
flush_workqueue(priv->wq);
36713624

36723625
/* Nothing takes a route out now, and a FIB entry one still names would
3673-
* be kept alive by it. Destroying the hash table also waits for the
3674-
* resize work it runs on its own.
3626+
* be kept alive by it.
36753627
*/
36763628
rtnl_lock();
36773629
list_for_each_entry_safe(r, tmp, &ctrl->routes_list, list)
36783630
otto_l3_route_free(ctrl, r);
36793631
rtnl_unlock();
3680-
rhltable_destroy(&ctrl->routes);
36813632
}
36823633

36833634
struct otto_l3_flush_work {
@@ -3781,11 +3732,7 @@ int otto_l3_probe(struct device *dev, struct rtl838x_switch_priv *priv)
37813732
return dev_err_probe(dev, err, "device specific L3 setup failed\n");
37823733
}
37833734

3784-
/* Initialize hash table for L3 routing */
37853735
INIT_LIST_HEAD(&ctrl->routes_list);
3786-
err = rhltable_init(&ctrl->routes, &otto_l3_route_ht_params);
3787-
if (err)
3788-
return dev_err_probe(dev, err, "could not set up the route hash table\n");
37893736

37903737
/* Before the notifiers, so no destination is dropped in the window
37913738
* where the tables are live and the routes have not arrived yet.

‎target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.h‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,7 @@ struct otto_l3_route {
9292
unsigned int members; /* FIB entries a trap row stands for */
9393
struct list_head srcs; /* source-specific routes a trap row stands for */
9494
bool srcs_incomplete; /* a source could not be tracked */
95-
struct rhlist_head linkage;
96-
struct list_head list; /* all routes, for lookups by destination */
95+
struct list_head list; /* all routes, for every lookup */
9796
u32 tb_id; /* routing table the route came from */
9897
u16 switch_mac_id; /* Index into switch's own MACs, RTL839X only */
9998
struct otto_l3_nexthop nh;
@@ -135,7 +134,6 @@ struct otto_l3_ctrl {
135134
struct delayed_work resync_work;
136135
unsigned int resync_delay;
137136
bool resync_wanted;
138-
struct rhltable routes;
139137
struct list_head routes_list;
140138
unsigned long route_use_bm[MAX_ROUTES / 32];
141139
unsigned long host_route_use_bm[MAX_HOST_ROUTES / 32];

0 commit comments

Comments
 (0)