AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/06/29 19:50 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "IP_MULTIPLE_TABLES",
    "IPV6_MULTIPLE_TABLES"
  ],
  "FocusSymbols": [
    "fib_newrule",
    "fib_delrule",
    "fib_new_table",
    "fib_rules_event",
    "fib4_rule_configure",
    "fib4_rule_delete",
    "fib6_rule_configure",
    "fib6_rule_delete"
  ],
  "Reasoning": "The patch modifies the locking mechanism for FIB rules and tables, replacing RTNL with finer-grained mutexes and spinlocks (ops-\u003elock and fib_table_hash_lock). This is a functional change to core networking logic that can be reached via netlink messages (e.g., RTM_NEWRULE, RTM_DELRULE) and netdev events. Fuzzing should focus on the control path functions that were modified to use the new locks.",
  "WorthFuzzing": true
}

1/1 2026/06/29 19:50 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit c86518c61cc4c7dc4daffd7cc09a20db99052150\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Mon Jun 29 19:50:06 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/include/net/fib_rules.h b/include/net/fib_rules.h\nindex 7dee0ae616e322..c6b94790fa81ee 100644\n--- a/include/net/fib_rules.h\n+++ b/include/net/fib_rules.h\n@@ -82,7 +82,7 @@ struct fib_rules_ops {\n \t\t\t\t\t     struct fib_rule_hdr *,\n \t\t\t\t\t     struct nlattr **,\n \t\t\t\t\t     struct netlink_ext_ack *);\n-\tint\t\t\t(*delete)(struct fib_rule *);\n+\tvoid\t\t\t(*delete)(struct fib_rule *);\n \tint\t\t\t(*compare)(struct fib_rule *,\n \t\t\t\t\t   struct fib_rule_hdr *,\n \t\t\t\t\t   struct nlattr **);\n@@ -93,11 +93,13 @@ struct fib_rules_ops {\n \t/* Called after modifications to the rules set, must flush\n \t * the route cache if one exists. */\n \tvoid\t\t\t(*flush_cache)(struct fib_rules_ops *ops);\n+\tbool\t\t\t(*need_rtnl)(struct net *net);\n \n \tint\t\t\tnlgroup;\n \tstruct list_head\trules_list;\n \tstruct module\t\t*owner;\n \tstruct net\t\t*fro_net;\n+\tstruct mutex\t\tlock;\n \tstruct rcu_head\t\trcu;\n };\n \ndiff --git a/include/net/ip_fib.h b/include/net/ip_fib.h\nindex c63a3c4967ae61..0a35355fb0f335 100644\n--- a/include/net/ip_fib.h\n+++ b/include/net/ip_fib.h\n@@ -302,7 +302,8 @@ static inline struct fib_table *fib_get_table(struct net *net, u32 id)\n \t\t\u0026net-\u003eipv4.fib_table_hash[TABLE_LOCAL_INDEX] :\n \t\t\u0026net-\u003eipv4.fib_table_hash[TABLE_MAIN_INDEX];\n \n-\ttb_hlist = rcu_dereference_rtnl(hlist_first_rcu(ptr));\n+\t/* Only fib4_rules_init() adds fib_table. */\n+\ttb_hlist = rcu_dereference_protected(hlist_first_rcu(ptr), true);\n \n \treturn hlist_entry(tb_hlist, struct fib_table, tb_hlist);\n }\ndiff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h\nindex 6e27c56514df57..59506320558a99 100644\n--- a/include/net/netns/ipv4.h\n+++ b/include/net/netns/ipv4.h\n@@ -127,6 +127,7 @@ struct netns_ipv4 {\n \tatomic_t\t\tfib_num_tclassid_users;\n #endif\n \tstruct hlist_head\t*fib_table_hash;\n+\tspinlock_t\t\tfib_table_hash_lock;\n \tstruct sock\t\t*fibnl;\n \tstruct hlist_head\t*fib_info_hash;\n \tunsigned int\t\tfib_info_hash_bits;\ndiff --git a/net/core/fib_rules.c b/net/core/fib_rules.c\nindex cf374c20873258..22e5e5e1a9c44f 100644\n--- a/net/core/fib_rules.c\n+++ b/net/core/fib_rules.c\n@@ -51,7 +51,6 @@ bool fib_rule_matchall(const struct fib_rule *rule)\n \t\treturn false;\n \treturn true;\n }\n-EXPORT_SYMBOL_GPL(fib_rule_matchall);\n \n int fib_default_rule_add(struct fib_rules_ops *ops,\n \t\t\t u32 pref, u32 table)\n@@ -78,7 +77,6 @@ int fib_default_rule_add(struct fib_rules_ops *ops,\n \tlist_add_tail(\u0026r-\u003elist, \u0026ops-\u003erules_list);\n \treturn 0;\n }\n-EXPORT_SYMBOL(fib_default_rule_add);\n \n static u32 fib_default_rule_pref(struct fib_rules_ops *ops)\n {\n@@ -172,6 +170,7 @@ fib_rules_register(const struct fib_rules_ops *tmpl, struct net *net)\n \t\treturn ERR_PTR(-ENOMEM);\n \n \tINIT_LIST_HEAD(\u0026ops-\u003erules_list);\n+\tmutex_init(\u0026ops-\u003elock);\n \tops-\u003efro_net = net;\n \n \terr = __fib_rules_register(ops);\n@@ -182,7 +181,6 @@ fib_rules_register(const struct fib_rules_ops *tmpl, struct net *net)\n \n \treturn ops;\n }\n-EXPORT_SYMBOL_GPL(fib_rules_register);\n \n static void fib_rules_cleanup_ops(struct fib_rules_ops *ops)\n {\n@@ -207,7 +205,6 @@ void fib_rules_unregister(struct fib_rules_ops *ops)\n \tfib_rules_cleanup_ops(ops);\n \tkfree_rcu(ops, rcu);\n }\n-EXPORT_SYMBOL_GPL(fib_rules_unregister);\n \n static int uid_range_set(struct fib_kuid_range *range)\n {\n@@ -363,7 +360,6 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,\n \n \treturn err;\n }\n-EXPORT_SYMBOL_GPL(fib_rules_lookup);\n \n static int call_fib_rule_notifier(struct notifier_block *nb,\n \t\t\t\t  enum fib_event_type event_type,\n@@ -391,7 +387,7 @@ static int call_fib_rule_notifiers(struct net *net,\n \t\t.rule = rule,\n \t};\n \n-\tASSERT_RTNL_NET(net);\n+\tlockdep_assert_held(\u0026ops-\u003elock);\n \n \t/* Paired with READ_ONCE() in fib_rules_seq() */\n \tWRITE_ONCE(ops-\u003efib_rules_seq, ops-\u003efib_rules_seq + 1);\n@@ -423,7 +419,6 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,\n \n \treturn err;\n }\n-EXPORT_SYMBOL_GPL(fib_rules_dump);\n \n unsigned int fib_rules_seq_read(const struct net *net, int family)\n {\n@@ -439,7 +434,6 @@ unsigned int fib_rules_seq_read(const struct net *net, int family)\n \n \treturn fib_rules_seq;\n }\n-EXPORT_SYMBOL_GPL(fib_rules_seq_read);\n \n static struct fib_rule *rule_find(struct fib_rules_ops *ops,\n \t\t\t\t  struct fib_rule_hdr *frh,\n@@ -740,10 +734,10 @@ static int fib_nl2rule(struct net *net, struct nlmsghdr *nlh,\n \treturn err;\n }\n \n-static int fib_nl2rule_rtnl(struct fib_rule *nlrule,\n-\t\t\t    struct fib_rules_ops *ops,\n-\t\t\t    struct nlattr *tb[],\n-\t\t\t    struct netlink_ext_ack *extack)\n+static int fib_nl2rule_locked(struct fib_rule *nlrule,\n+\t\t\t      struct fib_rules_ops *ops,\n+\t\t\t      struct nlattr *tb[],\n+\t\t\t      struct netlink_ext_ack *extack)\n {\n \tif (!tb[FRA_PRIORITY])\n \t\tnlrule-\u003epref = fib_default_rule_pref(ops);\n@@ -754,12 +748,14 @@ static int fib_nl2rule_rtnl(struct fib_rule *nlrule,\n \t\treturn -EINVAL;\n \t}\n \n+\trcu_read_lock();\n+\n \tif (tb[FRA_IIFNAME]) {\n \t\tstruct net_device *dev;\n \n-\t\tdev = __dev_get_by_name(nlrule-\u003efr_net, nlrule-\u003eiifname);\n+\t\tdev = dev_get_by_name_rcu(nlrule-\u003efr_net, nlrule-\u003eiifname);\n \t\tif (dev) {\n-\t\t\tnlrule-\u003eiifindex = dev-\u003eifindex;\n+\t\t\tnlrule-\u003eiifindex = READ_ONCE(dev-\u003eifindex);\n \t\t\tnlrule-\u003eiif_is_l3_master = netif_is_l3_master(dev);\n \t\t}\n \t}\n@@ -767,13 +763,15 @@ static int fib_nl2rule_rtnl(struct fib_rule *nlrule,\n \tif (tb[FRA_OIFNAME]) {\n \t\tstruct net_device *dev;\n \n-\t\tdev = __dev_get_by_name(nlrule-\u003efr_net, nlrule-\u003eoifname);\n+\t\tdev = dev_get_by_name_rcu(nlrule-\u003efr_net, nlrule-\u003eoifname);\n \t\tif (dev) {\n-\t\t\tnlrule-\u003eoifindex = dev-\u003eifindex;\n+\t\t\tnlrule-\u003eoifindex = READ_ONCE(dev-\u003eifindex);\n \t\t\tnlrule-\u003eoif_is_l3_master = netif_is_l3_master(dev);\n \t\t}\n \t}\n \n+\trcu_read_unlock();\n+\n \treturn 0;\n }\n \n@@ -883,6 +881,7 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \tstruct nlattr *tb[FRA_MAX + 1];\n \tbool user_priority = false;\n \tstruct fib_rule_hdr *frh;\n+\tbool unlock_rtnl = false;\n \n \tfrh = nlmsg_payload(nlh, sizeof(*frh));\n \tif (!frh) {\n@@ -908,10 +907,13 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \tif (err)\n \t\tgoto errout;\n \n-\tif (!rtnl_held)\n+\tif (!rtnl_held \u0026\u0026 ops-\u003eneed_rtnl \u0026\u0026 ops-\u003eneed_rtnl(net)) {\n+\t\tunlock_rtnl = true;\n \t\trtnl_net_lock(net);\n+\t}\n+\tmutex_lock(\u0026ops-\u003elock);\n \n-\terr = fib_nl2rule_rtnl(rule, ops, tb, extack);\n+\terr = fib_nl2rule_locked(rule, ops, tb, extack);\n \tif (err)\n \t\tgoto errout_free;\n \n@@ -959,7 +961,7 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \t\tlist_for_each_entry(r, \u0026ops-\u003erules_list, list) {\n \t\t\tif (r-\u003eaction == FR_ACT_GOTO \u0026\u0026\n \t\t\t    r-\u003etarget == rule-\u003epref \u0026\u0026\n-\t\t\t    rtnl_dereference(r-\u003ectarget) == NULL) {\n+\t\t\t    !rcu_access_pointer(r-\u003ectarget)) {\n \t\t\t\trcu_assign_pointer(r-\u003ectarget, rule);\n \t\t\t\tif (--ops-\u003eunresolved_rules == 0)\n \t\t\t\t\tbreak;\n@@ -978,7 +980,8 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \n \tfib_rule_get(rule);\n \n-\tif (!rtnl_held)\n+\tmutex_unlock(\u0026ops-\u003elock);\n+\tif (unlock_rtnl)\n \t\trtnl_net_unlock(net);\n \n \tnotify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid);\n@@ -988,7 +991,8 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \treturn 0;\n \n errout_free:\n-\tif (!rtnl_held)\n+\tmutex_unlock(\u0026ops-\u003elock);\n+\tif (unlock_rtnl)\n \t\trtnl_net_unlock(net);\n \tkfree(rule);\n errout:\n@@ -1037,10 +1041,9 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \tif (err)\n \t\tgoto errout;\n \n-\tif (!rtnl_held)\n-\t\trtnl_net_lock(net);\n+\tmutex_lock(\u0026ops-\u003elock);\n \n-\terr = fib_nl2rule_rtnl(nlrule, ops, tb, extack);\n+\terr = fib_nl2rule_locked(nlrule, ops, tb, extack);\n \tif (err)\n \t\tgoto errout_free;\n \n@@ -1055,11 +1058,8 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \t\tgoto errout_free;\n \t}\n \n-\tif (ops-\u003edelete) {\n-\t\terr = ops-\u003edelete(rule);\n-\t\tif (err)\n-\t\t\tgoto errout_free;\n-\t}\n+\tif (ops-\u003edelete)\n+\t\tops-\u003edelete(rule);\n \n \tif (rule-\u003etun_id)\n \t\tip_tunnel_unneed_metadata();\n@@ -1068,7 +1068,7 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \n \tif (rule-\u003eaction == FR_ACT_GOTO) {\n \t\tops-\u003enr_goto_rules--;\n-\t\tif (rtnl_dereference(rule-\u003ectarget) == NULL)\n+\t\tif (!rcu_access_pointer(rule-\u003ectarget))\n \t\t\tops-\u003eunresolved_rules--;\n \t}\n \n@@ -1086,7 +1086,7 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \t\tif (\u0026n-\u003elist == \u0026ops-\u003erules_list || n-\u003epref != rule-\u003epref)\n \t\t\tn = NULL;\n \t\tlist_for_each_entry(r, \u0026ops-\u003erules_list, list) {\n-\t\t\tif (rtnl_dereference(r-\u003ectarget) != rule)\n+\t\t\tif (rcu_access_pointer(r-\u003ectarget) != rule)\n \t\t\t\tcontinue;\n \t\t\trcu_assign_pointer(r-\u003ectarget, n);\n \t\t\tif (!n)\n@@ -1096,8 +1096,7 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \n \tcall_fib_rule_notifiers(net, FIB_EVENT_RULE_DEL, rule, ops, NULL);\n \n-\tif (!rtnl_held)\n-\t\trtnl_net_unlock(net);\n+\tmutex_unlock(\u0026ops-\u003elock);\n \n \tnotify_rule_change(RTM_DELRULE, rule, ops, nlh, NETLINK_CB(skb).portid);\n \tfib_rule_put(rule);\n@@ -1107,8 +1106,7 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,\n \treturn 0;\n \n errout_free:\n-\tif (!rtnl_held)\n-\t\trtnl_net_unlock(net);\n+\tmutex_unlock(\u0026ops-\u003elock);\n \tkfree(nlrule);\n errout:\n \trules_ops_put(ops);\n@@ -1402,24 +1400,30 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,\n \tstruct net *net = dev_net(dev);\n \tstruct fib_rules_ops *ops;\n \n-\tASSERT_RTNL();\n-\n \tswitch (event) {\n \tcase NETDEV_REGISTER:\n-\t\tlist_for_each_entry(ops, \u0026net-\u003erules_ops, list)\n+\t\tlist_for_each_entry(ops, \u0026net-\u003erules_ops, list) {\n+\t\t\tmutex_lock(\u0026ops-\u003elock);\n \t\t\tattach_rules(\u0026ops-\u003erules_list, dev);\n+\t\t\tmutex_unlock(\u0026ops-\u003elock);\n+\t\t}\n \t\tbreak;\n \n \tcase NETDEV_CHANGENAME:\n \t\tlist_for_each_entry(ops, \u0026net-\u003erules_ops, list) {\n+\t\t\tmutex_lock(\u0026ops-\u003elock);\n \t\t\tdetach_rules(\u0026ops-\u003erules_list, dev);\n \t\t\tattach_rules(\u0026ops-\u003erules_list, dev);\n+\t\t\tmutex_unlock(\u0026ops-\u003elock);\n \t\t}\n \t\tbreak;\n \n \tcase NETDEV_UNREGISTER:\n-\t\tlist_for_each_entry(ops, \u0026net-\u003erules_ops, list)\n+\t\tlist_for_each_entry(ops, \u0026net-\u003erules_ops, list) {\n+\t\t\tmutex_lock(\u0026ops-\u003elock);\n \t\t\tdetach_rules(\u0026ops-\u003erules_list, dev);\n+\t\t\tmutex_unlock(\u0026ops-\u003elock);\n+\t\t}\n \t\tbreak;\n \t}\n \ndiff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c\nindex 42212970d73540..54eb72695093da 100644\n--- a/net/ipv4/fib_frontend.c\n+++ b/net/ipv4/fib_frontend.c\n@@ -76,7 +76,7 @@ static int __net_init fib4_rules_init(struct net *net)\n \n struct fib_table *fib_new_table(struct net *net, u32 id)\n {\n-\tstruct fib_table *tb, *alias = NULL;\n+\tstruct fib_table *tb, *new_tb, *alias = NULL;\n \tunsigned int h;\n \n \tif (id == 0)\n@@ -85,14 +85,27 @@ struct fib_table *fib_new_table(struct net *net, u32 id)\n \tif (tb)\n \t\treturn tb;\n \n+\tif (!check_net(net))\n+\t\treturn NULL;\n+\n \tif (id == RT_TABLE_LOCAL \u0026\u0026 !net-\u003eipv4.fib_has_custom_rules)\n \t\talias = fib_new_table(net, RT_TABLE_MAIN);\n \n-\tif (check_net(net))\n-\t\ttb = fib_trie_table(id, alias);\n-\tif (!tb)\n+\tnew_tb = fib_trie_table(id, alias);\n+\tif (!new_tb)\n \t\treturn NULL;\n \n+\tspin_lock(\u0026net-\u003eipv4.fib_table_hash_lock);\n+\n+\ttb = fib_get_table(net, id);\n+\tif (tb) {\n+\t\tspin_unlock(\u0026net-\u003eipv4.fib_table_hash_lock);\n+\t\tfib_free_table(new_tb);\n+\t\treturn tb;\n+\t}\n+\n+\ttb = new_tb;\n+\n \tswitch (id) {\n \tcase RT_TABLE_MAIN:\n \t\trcu_assign_pointer(net-\u003eipv4.fib_main, tb);\n@@ -106,28 +119,35 @@ struct fib_table *fib_new_table(struct net *net, u32 id)\n \n \th = id \u0026 (FIB_TABLE_HASHSZ - 1);\n \thlist_add_head_rcu(\u0026tb-\u003etb_hlist, \u0026net-\u003eipv4.fib_table_hash[h]);\n+\n+\tspin_unlock(\u0026net-\u003eipv4.fib_table_hash_lock);\n+\n \treturn tb;\n }\n EXPORT_SYMBOL_GPL(fib_new_table);\n \n-/* caller must hold either rtnl or rcu read lock */\n struct fib_table *fib_get_table(struct net *net, u32 id)\n {\n-\tstruct fib_table *tb;\n+\tstruct fib_table *tb = NULL;\n \tstruct hlist_head *head;\n \tunsigned int h;\n \n \tif (id == 0)\n \t\tid = RT_TABLE_MAIN;\n \th = id \u0026 (FIB_TABLE_HASHSZ - 1);\n-\n \thead = \u0026net-\u003eipv4.fib_table_hash[h];\n-\thlist_for_each_entry_rcu(tb, head, tb_hlist,\n-\t\t\t\t lockdep_rtnl_is_held()) {\n+\n+\t/* fib_table is not destroyed until ip_fib_net_exit()\n+\t * except for the merged main/local table.\n+\t * fib_unmerge() is called under RTNL, so other readers\n+\t * under RTNL (e.g. fib_flush(), fib_info_notify_update())\n+\t * can safely traverse the list with rcu_dereference_raw().\n+\t */\n+\thlist_for_each_entry_rcu(tb, head, tb_hlist, true)\n \t\tif (tb-\u003etb_id == id)\n-\t\t\treturn tb;\n-\t}\n-\treturn NULL;\n+\t\t\tbreak;\n+\n+\treturn tb;\n }\n #endif /* CONFIG_IP_MULTIPLE_TABLES */\n \n@@ -190,10 +210,9 @@ void fib_flush(struct net *net)\n \n \tfor (h = 0; h \u003c FIB_TABLE_HASHSZ; h++) {\n \t\tstruct hlist_head *head = \u0026net-\u003eipv4.fib_table_hash[h];\n-\t\tstruct hlist_node *tmp;\n \t\tstruct fib_table *tb;\n \n-\t\thlist_for_each_entry_safe(tb, tmp, head, tb_hlist)\n+\t\thlist_for_each_entry_rcu(tb, head, tb_hlist, true)\n \t\t\tflushed += fib_table_flush(net, tb, false);\n \t}\n \n@@ -1565,6 +1584,7 @@ static int __net_init ip_fib_net_init(struct net *net)\n \tnet-\u003eipv4.sysctl_fib_multipath_hash_fields =\n \t\tFIB_MULTIPATH_HASH_FIELD_DEFAULT_MASK;\n #endif\n+\tspin_lock_init(\u0026net-\u003eipv4.fib_table_hash_lock);\n \n \t/* Avoid false sharing : Use at least a full cache line */\n \tsize = max_t(size_t, size, L1_CACHE_BYTES);\ndiff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c\nindex e068a5bace73f2..4edb0dca7be8a1 100644\n--- a/net/ipv4/fib_rules.c\n+++ b/net/ipv4/fib_rules.c\n@@ -301,10 +301,12 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,\n \t    fib4_nl2rule_dscp_mask(tb[FRA_DSCP_MASK], rule4, extack) \u003c 0)\n \t\tgoto errout;\n \n-\t/* split local/main if they are not already split */\n-\terr = fib_unmerge(net);\n-\tif (err)\n-\t\tgoto errout;\n+\tif (!net-\u003eipv4.fib_has_custom_rules) {\n+\t\t/* split local/main if they are not already split */\n+\t\terr = fib_unmerge(net);\n+\t\tif (err)\n+\t\t\tgoto errout;\n+\t}\n \n \tif (rule-\u003etable == RT_TABLE_UNSPEC \u0026\u0026 !rule-\u003el3mdev) {\n \t\tif (rule-\u003eaction == FR_ACT_TO_TBL) {\n@@ -349,7 +351,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,\n \treturn err;\n }\n \n-static int fib4_rule_delete(struct fib_rule *rule)\n+static void fib4_rule_delete(struct fib_rule *rule)\n {\n \tstruct net *net = rule-\u003efr_net;\n \n@@ -361,8 +363,6 @@ static int fib4_rule_delete(struct fib_rule *rule)\n \tif (net-\u003eipv4.fib_rules_require_fldissect \u0026\u0026\n \t    fib_rule_requires_fldissect(rule))\n \t\tnet-\u003eipv4.fib_rules_require_fldissect--;\n-\n-\treturn 0;\n }\n \n static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,\n@@ -460,6 +460,11 @@ static void fib4_rule_flush_cache(struct fib_rules_ops *ops)\n \trt_cache_flush(ops-\u003efro_net);\n }\n \n+static bool fib4_rule_need_rtnl(struct net *net)\n+{\n+\treturn !net-\u003eipv4.fib_has_custom_rules;\n+}\n+\n static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {\n \t.family\t\t= AF_INET,\n \t.rule_size\t= sizeof(struct fib4_rule),\n@@ -473,6 +478,7 @@ static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {\n \t.fill\t\t= fib4_rule_fill,\n \t.nlmsg_payload\t= fib4_rule_nlmsg_payload,\n \t.flush_cache\t= fib4_rule_flush_cache,\n+\t.need_rtnl\t= fib4_rule_need_rtnl,\n \t.nlgroup\t= RTNLGRP_IPV4_RULE,\n \t.owner\t\t= THIS_MODULE,\n };\ndiff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c\nindex e11dc86ceda0be..d1d342d7148e82 100644\n--- a/net/ipv4/fib_trie.c\n+++ b/net/ipv4/fib_trie.c\n@@ -2137,8 +2137,7 @@ void fib_info_notify_update(struct net *net, struct nl_info *info)\n \t\tstruct hlist_head *head = \u0026net-\u003eipv4.fib_table_hash[h];\n \t\tstruct fib_table *tb;\n \n-\t\thlist_for_each_entry_rcu(tb, head, tb_hlist,\n-\t\t\t\t\t lockdep_rtnl_is_held())\n+\t\thlist_for_each_entry_rcu(tb, head, tb_hlist, true)\n \t\t\t__fib_info_notify_update(net, tb, info);\n \t}\n }\ndiff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c\nindex e1b2b4fa6e1890..04dab9329d0cf5 100644\n--- a/net/ipv6/fib6_rules.c\n+++ b/net/ipv6/fib6_rules.c\n@@ -480,15 +480,13 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,\n \treturn err;\n }\n \n-static int fib6_rule_delete(struct fib_rule *rule)\n+static void fib6_rule_delete(struct fib_rule *rule)\n {\n \tstruct net *net = rule-\u003efr_net;\n \n \tif (net-\u003eipv6.fib6_rules_require_fldissect \u0026\u0026\n \t    fib_rule_requires_fldissect(rule))\n \t\tnet-\u003eipv6.fib6_rules_require_fldissect--;\n-\n-\treturn 0;\n }\n \n static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,\n@@ -637,21 +635,14 @@ static int __net_init fib6_rules_net_init(struct net *net)\n \tgoto out;\n }\n \n-static void __net_exit fib6_rules_net_exit_batch(struct list_head *net_list)\n+static void __net_exit fib6_rules_net_exit(struct net *net)\n {\n-\tstruct net *net;\n-\n-\trtnl_lock();\n-\tlist_for_each_entry(net, net_list, exit_list) {\n-\t\tfib_rules_unregister(net-\u003eipv6.fib6_rules_ops);\n-\t\tcond_resched();\n-\t}\n-\trtnl_unlock();\n+\tfib_rules_unregister(net-\u003eipv6.fib6_rules_ops);\n }\n \n static struct pernet_operations fib6_rules_net_ops = {\n \t.init = fib6_rules_net_init,\n-\t.exit_batch = fib6_rules_net_exit_batch,\n+\t.exit = fib6_rules_net_exit,\n };\n \n int __init fib6_rules_init(void)\n"
}

2/1 2026/06/29 19:50 agent patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "IP_MULTIPLE_TABLES",
    "IPV6_MULTIPLE_TABLES"
  ],
  "FocusSymbols": [
    "fib_newrule",
    "fib_delrule",
    "fib_new_table",
    "fib_rules_event",
    "fib4_rule_configure",
    "fib4_rule_delete",
    "fib6_rule_configure",
    "fib6_rule_delete"
  ],
  "Reasoning": "The patch modifies the locking mechanism for FIB rules and tables, replacing RTNL with finer-grained mutexes and spinlocks (ops-\u003elock and fib_table_hash_lock). This is a functional change to core networking logic that can be reached via netlink messages (e.g., RTM_NEWRULE, RTM_DELRULE) and netdev events. Fuzzing should focus on the control path functions that were modified to use the new locks.",
  "WorthFuzzing": true
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Do not list too generic configs (we already have them enabled). Only list those that
   specifically cover the modified code. List them in the EnableConfigs output array,
   and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit c86518c61cc4c7dc4daffd7cc09a20db99052150
Author: syz-cluster <triage@syzkaller.com>
Date:   Mon Jun 29 19:50:06 2026 +0000

    syz-cluster: applied patch under review

diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index 7dee0ae616e322..c6b94790fa81ee 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -82,7 +82,7 @@ struct fib_rules_ops {
 					     struct fib_rule_hdr *,
 					     struct nlattr **,
 					     struct netlink_ext_ack *);
-	int			(*delete)(struct fib_rule *);
+	void			(*delete)(struct fib_rule *);
 	int			(*compare)(struct fib_rule *,
 					   struct fib_rule_hdr *,
 					   struct nlattr **);
@@ -93,11 +93,13 @@ struct fib_rules_ops {
 	/* Called after modifications to the rules set, must flush
 	 * the route cache if one exists. */
 	void			(*flush_cache)(struct fib_rules_ops *ops);
+	bool			(*need_rtnl)(struct net *net);
 
 	int			nlgroup;
 	struct list_head	rules_list;
 	struct module		*owner;
 	struct net		*fro_net;
+	struct mutex		lock;
 	struct rcu_head		rcu;
 };
 
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index c63a3c4967ae61..0a35355fb0f335 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -302,7 +302,8 @@ static inline struct fib_table *fib_get_table(struct net *net, u32 id)
 		&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] :
 		&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX];
 
-	tb_hlist = rcu_dereference_rtnl(hlist_first_rcu(ptr));
+	/* Only fib4_rules_init() adds fib_table. */
+	tb_hlist = rcu_dereference_protected(hlist_first_rcu(ptr), true);
 
 	return hlist_entry(tb_hlist, struct fib_table, tb_hlist);
 }
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 6e27c56514df57..59506320558a99 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -127,6 +127,7 @@ struct netns_ipv4 {
 	atomic_t		fib_num_tclassid_users;
 #endif
 	struct hlist_head	*fib_table_hash;
+	spinlock_t		fib_table_hash_lock;
 	struct sock		*fibnl;
 	struct hlist_head	*fib_info_hash;
 	unsigned int		fib_info_hash_bits;
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index cf374c20873258..22e5e5e1a9c44f 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -51,7 +51,6 @@ bool fib_rule_matchall(const struct fib_rule *rule)
 		return false;
 	return true;
 }
-EXPORT_SYMBOL_GPL(fib_rule_matchall);
 
 int fib_default_rule_add(struct fib_rules_ops *ops,
 			 u32 pref, u32 table)
@@ -78,7 +77,6 @@ int fib_default_rule_add(struct fib_rules_ops *ops,
 	list_add_tail(&r->list, &ops->rules_list);
 	return 0;
 }
-EXPORT_SYMBOL(fib_default_rule_add);
 
 static u32 fib_default_rule_pref(struct fib_rules_ops *ops)
 {
@@ -172,6 +170,7 @@ fib_rules_register(const struct fib_rules_ops *tmpl, struct net *net)
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&ops->rules_list);
+	mutex_init(&ops->lock);
 	ops->fro_net = net;
 
 	err = __fib_rules_register(ops);
@@ -182,7 +181,6 @@ fib_rules_register(const struct fib_rules_ops *tmpl, struct net *net)
 
 	return ops;
 }
-EXPORT_SYMBOL_GPL(fib_rules_register);
 
 static void fib_rules_cleanup_ops(struct fib_rules_ops *ops)
 {
@@ -207,7 +205,6 @@ void fib_rules_unregister(struct fib_rules_ops *ops)
 	fib_rules_cleanup_ops(ops);
 	kfree_rcu(ops, rcu);
 }
-EXPORT_SYMBOL_GPL(fib_rules_unregister);
 
 static int uid_range_set(struct fib_kuid_range *range)
 {
@@ -363,7 +360,6 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
 
 	return err;
 }
-EXPORT_SYMBOL_GPL(fib_rules_lookup);
 
 static int call_fib_rule_notifier(struct notifier_block *nb,
 				  enum fib_event_type event_type,
@@ -391,7 +387,7 @@ static int call_fib_rule_notifiers(struct net *net,
 		.rule = rule,
 	};
 
-	ASSERT_RTNL_NET(net);
+	lockdep_assert_held(&ops->lock);
 
 	/* Paired with READ_ONCE() in fib_rules_seq() */
 	WRITE_ONCE(ops->fib_rules_seq, ops->fib_rules_seq + 1);
@@ -423,7 +419,6 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,
 
 	return err;
 }
-EXPORT_SYMBOL_GPL(fib_rules_dump);
 
 unsigned int fib_rules_seq_read(const struct net *net, int family)
 {
@@ -439,7 +434,6 @@ unsigned int fib_rules_seq_read(const struct net *net, int family)
 
 	return fib_rules_seq;
 }
-EXPORT_SYMBOL_GPL(fib_rules_seq_read);
 
 static struct fib_rule *rule_find(struct fib_rules_ops *ops,
 				  struct fib_rule_hdr *frh,
@@ -740,10 +734,10 @@ static int fib_nl2rule(struct net *net, struct nlmsghdr *nlh,
 	return err;
 }
 
-static int fib_nl2rule_rtnl(struct fib_rule *nlrule,
-			    struct fib_rules_ops *ops,
-			    struct nlattr *tb[],
-			    struct netlink_ext_ack *extack)
+static int fib_nl2rule_locked(struct fib_rule *nlrule,
+			      struct fib_rules_ops *ops,
+			      struct nlattr *tb[],
+			      struct netlink_ext_ack *extack)
 {
 	if (!tb[FRA_PRIORITY])
 		nlrule->pref = fib_default_rule_pref(ops);
@@ -754,12 +748,14 @@ static int fib_nl2rule_rtnl(struct fib_rule *nlrule,
 		return -EINVAL;
 	}
 
+	rcu_read_lock();
+
 	if (tb[FRA_IIFNAME]) {
 		struct net_device *dev;
 
-		dev = __dev_get_by_name(nlrule->fr_net, nlrule->iifname);
+		dev = dev_get_by_name_rcu(nlrule->fr_net, nlrule->iifname);
 		if (dev) {
-			nlrule->iifindex = dev->ifindex;
+			nlrule->iifindex = READ_ONCE(dev->ifindex);
 			nlrule->iif_is_l3_master = netif_is_l3_master(dev);
 		}
 	}
@@ -767,13 +763,15 @@ static int fib_nl2rule_rtnl(struct fib_rule *nlrule,
 	if (tb[FRA_OIFNAME]) {
 		struct net_device *dev;
 
-		dev = __dev_get_by_name(nlrule->fr_net, nlrule->oifname);
+		dev = dev_get_by_name_rcu(nlrule->fr_net, nlrule->oifname);
 		if (dev) {
-			nlrule->oifindex = dev->ifindex;
+			nlrule->oifindex = READ_ONCE(dev->ifindex);
 			nlrule->oif_is_l3_master = netif_is_l3_master(dev);
 		}
 	}
 
+	rcu_read_unlock();
+
 	return 0;
 }
 
@@ -883,6 +881,7 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 	struct nlattr *tb[FRA_MAX + 1];
 	bool user_priority = false;
 	struct fib_rule_hdr *frh;
+	bool unlock_rtnl = false;
 
 	frh = nlmsg_payload(nlh, sizeof(*frh));
 	if (!frh) {
@@ -908,10 +907,13 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 	if (err)
 		goto errout;
 
-	if (!rtnl_held)
+	if (!rtnl_held && ops->need_rtnl && ops->need_rtnl(net)) {
+		unlock_rtnl = true;
 		rtnl_net_lock(net);
+	}
+	mutex_lock(&ops->lock);
 
-	err = fib_nl2rule_rtnl(rule, ops, tb, extack);
+	err = fib_nl2rule_locked(rule, ops, tb, extack);
 	if (err)
 		goto errout_free;
 
@@ -959,7 +961,7 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 		list_for_each_entry(r, &ops->rules_list, list) {
 			if (r->action == FR_ACT_GOTO &&
 			    r->target == rule->pref &&
-			    rtnl_dereference(r->ctarget) == NULL) {
+			    !rcu_access_pointer(r->ctarget)) {
 				rcu_assign_pointer(r->ctarget, rule);
 				if (--ops->unresolved_rules == 0)
 					break;
@@ -978,7 +980,8 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	fib_rule_get(rule);
 
-	if (!rtnl_held)
+	mutex_unlock(&ops->lock);
+	if (unlock_rtnl)
 		rtnl_net_unlock(net);
 
 	notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
@@ -988,7 +991,8 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 	return 0;
 
 errout_free:
-	if (!rtnl_held)
+	mutex_unlock(&ops->lock);
+	if (unlock_rtnl)
 		rtnl_net_unlock(net);
 	kfree(rule);
 errout:
@@ -1037,10 +1041,9 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 	if (err)
 		goto errout;
 
-	if (!rtnl_held)
-		rtnl_net_lock(net);
+	mutex_lock(&ops->lock);
 
-	err = fib_nl2rule_rtnl(nlrule, ops, tb, extack);
+	err = fib_nl2rule_locked(nlrule, ops, tb, extack);
 	if (err)
 		goto errout_free;
 
@@ -1055,11 +1058,8 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 		goto errout_free;
 	}
 
-	if (ops->delete) {
-		err = ops->delete(rule);
-		if (err)
-			goto errout_free;
-	}
+	if (ops->delete)
+		ops->delete(rule);
 
 	if (rule->tun_id)
 		ip_tunnel_unneed_metadata();
@@ -1068,7 +1068,7 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	if (rule->action == FR_ACT_GOTO) {
 		ops->nr_goto_rules--;
-		if (rtnl_dereference(rule->ctarget) == NULL)
+		if (!rcu_access_pointer(rule->ctarget))
 			ops->unresolved_rules--;
 	}
 
@@ -1086,7 +1086,7 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 		if (&n->list == &ops->rules_list || n->pref != rule->pref)
 			n = NULL;
 		list_for_each_entry(r, &ops->rules_list, list) {
-			if (rtnl_dereference(r->ctarget) != rule)
+			if (rcu_access_pointer(r->ctarget) != rule)
 				continue;
 			rcu_assign_pointer(r->ctarget, n);
 			if (!n)
@@ -1096,8 +1096,7 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	call_fib_rule_notifiers(net, FIB_EVENT_RULE_DEL, rule, ops, NULL);
 
-	if (!rtnl_held)
-		rtnl_net_unlock(net);
+	mutex_unlock(&ops->lock);
 
 	notify_rule_change(RTM_DELRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
 	fib_rule_put(rule);
@@ -1107,8 +1106,7 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
 	return 0;
 
 errout_free:
-	if (!rtnl_held)
-		rtnl_net_unlock(net);
+	mutex_unlock(&ops->lock);
 	kfree(nlrule);
 errout:
 	rules_ops_put(ops);
@@ -1402,24 +1400,30 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event,
 	struct net *net = dev_net(dev);
 	struct fib_rules_ops *ops;
 
-	ASSERT_RTNL();
-
 	switch (event) {
 	case NETDEV_REGISTER:
-		list_for_each_entry(ops, &net->rules_ops, list)
+		list_for_each_entry(ops, &net->rules_ops, list) {
+			mutex_lock(&ops->lock);
 			attach_rules(&ops->rules_list, dev);
+			mutex_unlock(&ops->lock);
+		}
 		break;
 
 	case NETDEV_CHANGENAME:
 		list_for_each_entry(ops, &net->rules_ops, list) {
+			mutex_lock(&ops->lock);
 			detach_rules(&ops->rules_list, dev);
 			attach_rules(&ops->rules_list, dev);
+			mutex_unlock(&ops->lock);
 		}
 		break;
 
 	case NETDEV_UNREGISTER:
-		list_for_each_entry(ops, &net->rules_ops, list)
+		list_for_each_entry(ops, &net->rules_ops, list) {
+			mutex_lock(&ops->lock);
 			detach_rules(&ops->rules_list, dev);
+			mutex_unlock(&ops->lock);
+		}
 		break;
 	}
 
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 42212970d73540..54eb72695093da 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -76,7 +76,7 @@ static int __net_init fib4_rules_init(struct net *net)
 
 struct fib_table *fib_new_table(struct net *net, u32 id)
 {
-	struct fib_table *tb, *alias = NULL;
+	struct fib_table *tb, *new_tb, *alias = NULL;
 	unsigned int h;
 
 	if (id == 0)
@@ -85,14 +85,27 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
 	if (tb)
 		return tb;
 
+	if (!check_net(net))
+		return NULL;
+
 	if (id == RT_TABLE_LOCAL && !net->ipv4.fib_has_custom_rules)
 		alias = fib_new_table(net, RT_TABLE_MAIN);
 
-	if (check_net(net))
-		tb = fib_trie_table(id, alias);
-	if (!tb)
+	new_tb = fib_trie_table(id, alias);
+	if (!new_tb)
 		return NULL;
 
+	spin_lock(&net->ipv4.fib_table_hash_lock);
+
+	tb = fib_get_table(net, id);
+	if (tb) {
+		spin_unlock(&net->ipv4.fib_table_hash_lock);
+		fib_free_table(new_tb);
+		return tb;
+	}
+
+	tb = new_tb;
+
 	switch (id) {
 	case RT_TABLE_MAIN:
 		rcu_assign_pointer(net->ipv4.fib_main, tb);
@@ -106,28 +119,35 @@ struct fib_table *fib_new_table(struct net *net, u32 id)
 
 	h = id & (FIB_TABLE_HASHSZ - 1);
 	hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]);
+
+	spin_unlock(&net->ipv4.fib_table_hash_lock);
+
 	return tb;
 }
 EXPORT_SYMBOL_GPL(fib_new_table);
 
-/* caller must hold either rtnl or rcu read lock */
 struct fib_table *fib_get_table(struct net *net, u32 id)
 {
-	struct fib_table *tb;
+	struct fib_table *tb = NULL;
 	struct hlist_head *head;
 	unsigned int h;
 
 	if (id == 0)
 		id = RT_TABLE_MAIN;
 	h = id & (FIB_TABLE_HASHSZ - 1);
-
 	head = &net->ipv4.fib_table_hash[h];
-	hlist_for_each_entry_rcu(tb, head, tb_hlist,
-				 lockdep_rtnl_is_held()) {
+
+	/* fib_table is not destroyed until ip_fib_net_exit()
+	 * except for the merged main/local table.
+	 * fib_unmerge() is called under RTNL, so other readers
+	 * under RTNL (e.g. fib_flush(), fib_info_notify_update())
+	 * can safely traverse the list with rcu_dereference_raw().
+	 */
+	hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
 		if (tb->tb_id == id)
-			return tb;
-	}
-	return NULL;
+			break;
+
+	return tb;
 }
 #endif /* CONFIG_IP_MULTIPLE_TABLES */
 
@@ -190,10 +210,9 @@ void fib_flush(struct net *net)
 
 	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {
 		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
-		struct hlist_node *tmp;
 		struct fib_table *tb;
 
-		hlist_for_each_entry_safe(tb, tmp, head, tb_hlist)
+		hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
 			flushed += fib_table_flush(net, tb, false);
 	}
 
@@ -1565,6 +1584,7 @@ static int __net_init ip_fib_net_init(struct net *net)
 	net->ipv4.sysctl_fib_multipath_hash_fields =
 		FIB_MULTIPATH_HASH_FIELD_DEFAULT_MASK;
 #endif
+	spin_lock_init(&net->ipv4.fib_table_hash_lock);
 
 	/* Avoid false sharing : Use at least a full cache line */
 	size = max_t(size_t, size, L1_CACHE_BYTES);
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index e068a5bace73f2..4edb0dca7be8a1 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -301,10 +301,12 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
 	    fib4_nl2rule_dscp_mask(tb[FRA_DSCP_MASK], rule4, extack) < 0)
 		goto errout;
 
-	/* split local/main if they are not already split */
-	err = fib_unmerge(net);
-	if (err)
-		goto errout;
+	if (!net->ipv4.fib_has_custom_rules) {
+		/* split local/main if they are not already split */
+		err = fib_unmerge(net);
+		if (err)
+			goto errout;
+	}
 
 	if (rule->table == RT_TABLE_UNSPEC && !rule->l3mdev) {
 		if (rule->action == FR_ACT_TO_TBL) {
@@ -349,7 +351,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
 	return err;
 }
 
-static int fib4_rule_delete(struct fib_rule *rule)
+static void fib4_rule_delete(struct fib_rule *rule)
 {
 	struct net *net = rule->fr_net;
 
@@ -361,8 +363,6 @@ static int fib4_rule_delete(struct fib_rule *rule)
 	if (net->ipv4.fib_rules_require_fldissect &&
 	    fib_rule_requires_fldissect(rule))
 		net->ipv4.fib_rules_require_fldissect--;
-
-	return 0;
 }
 
 static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
@@ -460,6 +460,11 @@ static void fib4_rule_flush_cache(struct fib_rules_ops *ops)
 	rt_cache_flush(ops->fro_net);
 }
 
+static bool fib4_rule_need_rtnl(struct net *net)
+{
+	return !net->ipv4.fib_has_custom_rules;
+}
+
 static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {
 	.family		= AF_INET,
 	.rule_size	= sizeof(struct fib4_rule),
@@ -473,6 +478,7 @@ static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {
 	.fill		= fib4_rule_fill,
 	.nlmsg_payload	= fib4_rule_nlmsg_payload,
 	.flush_cache	= fib4_rule_flush_cache,
+	.need_rtnl	= fib4_rule_need_rtnl,
 	.nlgroup	= RTNLGRP_IPV4_RULE,
 	.owner		= THIS_MODULE,
 };
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index e11dc86ceda0be..d1d342d7148e82 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -2137,8 +2137,7 @@ void fib_info_notify_update(struct net *net, struct nl_info *info)
 		struct hlist_head *head = &net->ipv4.fib_table_hash[h];
 		struct fib_table *tb;
 
-		hlist_for_each_entry_rcu(tb, head, tb_hlist,
-					 lockdep_rtnl_is_held())
+		hlist_for_each_entry_rcu(tb, head, tb_hlist, true)
 			__fib_info_notify_update(net, tb, info);
 	}
 }
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index e1b2b4fa6e1890..04dab9329d0cf5 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -480,15 +480,13 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
 	return err;
 }
 
-static int fib6_rule_delete(struct fib_rule *rule)
+static void fib6_rule_delete(struct fib_rule *rule)
 {
 	struct net *net = rule->fr_net;
 
 	if (net->ipv6.fib6_rules_require_fldissect &&
 	    fib_rule_requires_fldissect(rule))
 		net->ipv6.fib6_rules_require_fldissect--;
-
-	return 0;
 }
 
 static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
@@ -637,21 +635,14 @@ static int __net_init fib6_rules_net_init(struct net *net)
 	goto out;
 }
 
-static void __net_exit fib6_rules_net_exit_batch(struct list_head *net_list)
+static void __net_exit fib6_rules_net_exit(struct net *net)
 {
-	struct net *net;
-
-	rtnl_lock();
-	list_for_each_entry(net, net_list, exit_list) {
-		fib_rules_unregister(net->ipv6.fib6_rules_ops);
-		cond_resched();
-	}
-	rtnl_unlock();
+	fib_rules_unregister(net->ipv6.fib6_rules_ops);
 }
 
 static struct pernet_operations fib6_rules_net_ops = {
 	.init = fib6_rules_net_init,
-	.exit_batch = fib6_rules_net_exit_batch,
+	.exit = fib6_rules_net_exit,
 };
 
 int __init fib6_rules_init(void)

3/2 2026/06/29 19:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 9108
							output: 23
							thoughts: 496
						

Thoughts:
**Analyzing a Networking Subsystem Patch**

Okay, so I'm looking at this patch for the networking subsystem, specifically the part dealing with `fib_rules` and `fib_table` logic. It's a significant refactor, as I can see it's making some fundamental changes to how these tables are managed. The first thing that jumps out is the alteration of `fib_rules_ops->delete` to return `void` instead of `int`. That's a subtle but potentially impactful change to the error handling model.

The real meat of this seems to be the locking strategy. Instead of relying solely on `rtnl_lock()`, the patch introduces a `mutex` lock within `fib_rules_ops` to protect `fib_rules_list`. It also throws in a `need_rtnl` flag to `fib_rules_ops` which warrants further investigation to understand its purpose. This fine-grained locking approach is interesting. We're moving away from the more coarse-grained RTNL lock, indicating a potential performance optimization or maybe a move towards more concurrent access.

I see that `fib_newrule` and `fib_delrule` are being updated to use the new `ops->lock` instead of `rtnl_lock()`, which makes sense. Similarly, `fib_new_table` is now using a `fib_table_hash_lock` spinlock, which I assume is for protecting the hash table's integrity during table creation. `fib_get_table` is using either `rcu_dereference_protected` or `hlist_for_each_entry_rcu` with `true`, which is definitely important, and I need to understand the exact context for this usage, verifying its use case with the other locks in this patch. The `fib_rules_event` function seems to be gaining a lock to protect attaching and detaching rules; likely critical for a multithreaded environment. And the `fib6_rules_net_exit_batch` is being refactored to `fib6_rules_net_exit` with the removal of `rtnl_lock()`, which definitely changes the execution flow of the IPv6 FIB rules management.

From a functional standpoint, this patch is a core networking change, and the introduction of lockless or finer-grained locking definitely alters the execution flow, especially in a virtualized environment. Because of this, it's definitely worth fuzzing. I need to focus my attention on specific functions: `fib_newrule`, `fib_delrule`, `fib_new_table`, `fib_get_table`, `fib_rules_event`, and the IPv4 and IPv6 rule configuration and deletion functions (`fib4_rule_configure`, `fib4_rule_delete`, `fib6_rule_configure`, `fib6_rule_delete`).

Finally, I need to check the configurations. The `CONFIG_IP_MULTIPLE_TABLES` and `CONFIG_IPV6_MULTIPLE_TABLES` are going to be key, especially for understanding the impact of changes in `fib_new_table` and `fib_get_table`, and also the `fib6_rules_net` functions. I need to verify that those configurations are properly enabled.



4/2 2026/06/29 19:50 tool grepper
0m Args:
{
  "Expression": "CONFIG_IP_MULTIPLE_TABLES"
}

Results:
{
  "Output": "arch/arm/configs/aspeed_g5_defconfig=53=CONFIG_IP_ADVANCED_ROUTER=y\narch/arm/configs/aspeed_g5_defconfig:54:CONFIG_IP_MULTIPLE_TABLES=y\narch/arm/configs/aspeed_g5_defconfig-55-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/arm/configs/ixp4xx_defconfig=24=CONFIG_IP_ADVANCED_ROUTER=y\narch/arm/configs/ixp4xx_defconfig:25:CONFIG_IP_MULTIPLE_TABLES=y\narch/arm/configs/ixp4xx_defconfig-26-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/arm/configs/keystone_defconfig=50=CONFIG_IP_ADVANCED_ROUTER=y\narch/arm/configs/keystone_defconfig:51:CONFIG_IP_MULTIPLE_TABLES=y\narch/arm/configs/keystone_defconfig-52-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/arm/configs/qcom_defconfig=38=CONFIG_IP_ADVANCED_ROUTER=y\narch/arm/configs/qcom_defconfig:39:CONFIG_IP_MULTIPLE_TABLES=y\narch/arm/configs/qcom_defconfig-40-CONFIG_IP_ROUTE_VERBOSE=y\n--\narch/loongarch/configs/loongson32_defconfig=119=CONFIG_IP_ADVANCED_ROUTER=y\narch/loongarch/configs/loongson32_defconfig:120:CONFIG_IP_MULTIPLE_TABLES=y\narch/loongarch/configs/loongson32_defconfig-121-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/loongarch/configs/loongson64_defconfig=135=CONFIG_IP_ADVANCED_ROUTER=y\narch/loongarch/configs/loongson64_defconfig:136:CONFIG_IP_MULTIPLE_TABLES=y\narch/loongarch/configs/loongson64_defconfig-137-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/bcm47xx_defconfig=17=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/bcm47xx_defconfig:18:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/bcm47xx_defconfig-19-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/cavium_octeon_defconfig=32=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/cavium_octeon_defconfig:33:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/cavium_octeon_defconfig-34-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/gpr_defconfig=24=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/gpr_defconfig:25:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/gpr_defconfig-26-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/lemote2f_defconfig=36=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/lemote2f_defconfig:37:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/lemote2f_defconfig-38-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/loongson2k_defconfig=45=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/loongson2k_defconfig:46:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/loongson2k_defconfig-47-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/loongson3_defconfig=57=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/loongson3_defconfig:58:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/loongson3_defconfig-59-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/malta_defconfig=29=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/malta_defconfig:30:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/malta_defconfig-31-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/malta_kvm_defconfig=33=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/malta_kvm_defconfig:34:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/malta_kvm_defconfig-35-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/malta_qemu_32r6_defconfig=28=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/malta_qemu_32r6_defconfig:29:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/malta_qemu_32r6_defconfig-30-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/maltaaprp_defconfig=30=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/maltaaprp_defconfig:31:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/maltaaprp_defconfig-32-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/maltasmvp_defconfig=31=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/maltasmvp_defconfig:32:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/maltasmvp_defconfig-33-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/maltasmvp_eva_defconfig=32=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/maltasmvp_eva_defconfig:33:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/maltasmvp_eva_defconfig-34-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/maltaup_defconfig=29=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/maltaup_defconfig:30:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/maltaup_defconfig-31-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/maltaup_xpa_defconfig=32=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/maltaup_xpa_defconfig:33:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/maltaup_xpa_defconfig-34-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/mtx1_defconfig=47=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/mtx1_defconfig:48:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/mtx1_defconfig-49-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/qi_lb60_defconfig=25=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/qi_lb60_defconfig:26:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/qi_lb60_defconfig-27-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/rb532_defconfig=30=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/rb532_defconfig:31:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/rb532_defconfig-32-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/rs90_defconfig=47=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/rs90_defconfig:48:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/rs90_defconfig-49-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/rt305x_defconfig=31=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/rt305x_defconfig:32:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/rt305x_defconfig-33-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/mips/configs/xway_defconfig=33=CONFIG_IP_ADVANCED_ROUTER=y\narch/mips/configs/xway_defconfig:34:CONFIG_IP_MULTIPLE_TABLES=y\narch/mips/configs/xway_defconfig-35-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/powerpc/configs/85xx/ge_imp3a_defconfig=46=CONFIG_IP_ADVANCED_ROUTER=y\narch/powerpc/configs/85xx/ge_imp3a_defconfig:47:CONFIG_IP_MULTIPLE_TABLES=y\narch/powerpc/configs/85xx/ge_imp3a_defconfig-48-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/powerpc/configs/85xx/xes_mpc85xx_defconfig=42=CONFIG_IP_ADVANCED_ROUTER=y\narch/powerpc/configs/85xx/xes_mpc85xx_defconfig:43:CONFIG_IP_MULTIPLE_TABLES=y\narch/powerpc/configs/85xx/xes_mpc85xx_defconfig-44-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/powerpc/configs/fsl-emb-nonhw.config=60=CONFIG_IP_MULTICAST=y\narch/powerpc/configs/fsl-emb-nonhw.config:61:CONFIG_IP_MULTIPLE_TABLES=y\narch/powerpc/configs/fsl-emb-nonhw.config-62-CONFIG_IP_PIMSM_V1=y\n--\narch/powerpc/configs/ppc6xx_defconfig=86=CONFIG_IP_ADVANCED_ROUTER=y\narch/powerpc/configs/ppc6xx_defconfig:87:CONFIG_IP_MULTIPLE_TABLES=y\narch/powerpc/configs/ppc6xx_defconfig-88-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/s390/configs/debug_defconfig=138=CONFIG_IP_ADVANCED_ROUTER=y\narch/s390/configs/debug_defconfig:139:CONFIG_IP_MULTIPLE_TABLES=y\narch/s390/configs/debug_defconfig-140-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/s390/configs/defconfig=129=CONFIG_IP_ADVANCED_ROUTER=y\narch/s390/configs/defconfig:130:CONFIG_IP_MULTIPLE_TABLES=y\narch/s390/configs/defconfig-131-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/sh/configs/se7712_defconfig=32=CONFIG_IP_ADVANCED_ROUTER=y\narch/sh/configs/se7712_defconfig:33:CONFIG_IP_MULTIPLE_TABLES=y\narch/sh/configs/se7712_defconfig-34-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/sh/configs/se7721_defconfig=32=CONFIG_IP_ADVANCED_ROUTER=y\narch/sh/configs/se7721_defconfig:33:CONFIG_IP_MULTIPLE_TABLES=y\narch/sh/configs/se7721_defconfig-34-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/sh/configs/sh2007_defconfig=33=CONFIG_IP_ADVANCED_ROUTER=y\narch/sh/configs/sh2007_defconfig:34:CONFIG_IP_MULTIPLE_TABLES=y\narch/sh/configs/sh2007_defconfig-35-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/sh/configs/titan_defconfig=32=CONFIG_IP_ADVANCED_ROUTER=y\narch/sh/configs/titan_defconfig:33:CONFIG_IP_MULTIPLE_TABLES=y\narch/sh/configs/titan_defconfig-34-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/x86/configs/i386_defconfig=66=CONFIG_IP_ADVANCED_ROUTER=y\narch/x86/configs/i386_defconfig:67:CONFIG_IP_MULTIPLE_TABLES=y\narch/x86/configs/i386_defconfig-68-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/x86/configs/x86_64_defconfig=67=CONFIG_IP_ADVANCED_ROUTER=y\narch/x86/configs/x86_64_defconfig:68:CONFIG_IP_MULTIPLE_TABLES=y\narch/x86/configs/x86_64_defconfig-69-CONFIG_IP_ROUTE_MULTIPATH=y\n--\narch/xtensa/configs/common_defconfig=16=CONFIG_IP_ADVANCED_ROUTER=y\narch/xtensa/configs/common_defconfig:17:CONFIG_IP_MULTIPLE_TABLES=y\narch/xtensa/configs/common_defconfig-18-CONFIG_IP_ROUTE_MULTIPATH=y\n--\ninclude/net/ip_fib.h=166=void __net_exit fib4_semantics_exit(struct net *net);\ninclude/net/ip_fib.h-167-\ninclude/net/ip_fib.h:168:#ifdef CONFIG_IP_MULTIPLE_TABLES\ninclude/net/ip_fib.h-169-struct fib_rule;\n--\ninclude/net/ip_fib.h=187=struct fib_result_nl {\n--\ninclude/net/ip_fib.h-201-\ninclude/net/ip_fib.h:202:#ifdef CONFIG_IP_MULTIPLE_TABLES\ninclude/net/ip_fib.h-203-#define FIB_TABLE_HASHSZ 256\n--\ninclude/net/ip_fib.h=289=void fib_free_table(struct fib_table *tb);\ninclude/net/ip_fib.h-290-\ninclude/net/ip_fib.h:291:#ifndef CONFIG_IP_MULTIPLE_TABLES\ninclude/net/ip_fib.h-292-\n--\ninclude/net/ip_fib.h=357=static inline bool fib4_rules_early_flow_dissect(struct net *net,\n--\ninclude/net/ip_fib.h-363-}\ninclude/net/ip_fib.h:364:#else /* CONFIG_IP_MULTIPLE_TABLES */\ninclude/net/ip_fib.h-365-int __net_init fib4_rules_init(struct net *net);\n--\ninclude/net/ip_fib.h=417=static inline bool fib4_rules_early_flow_dissect(struct net *net,\n--\ninclude/net/ip_fib.h-437-\ninclude/net/ip_fib.h:438:#endif /* CONFIG_IP_MULTIPLE_TABLES */\ninclude/net/ip_fib.h-439-\n--\ninclude/net/ip_fib.h=598=static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)\n--\ninclude/net/ip_fib.h-601-\tstruct fib_nh_common *nhc = res-\u003enhc;\ninclude/net/ip_fib.h:602:#ifdef CONFIG_IP_MULTIPLE_TABLES\ninclude/net/ip_fib.h-603-\tu32 rtag;\n--\ninclude/net/ip_fib.h-613-\ninclude/net/ip_fib.h:614:#ifdef CONFIG_IP_MULTIPLE_TABLES\ninclude/net/ip_fib.h-615-\trtag = res-\u003etclassid;\n--\ninclude/net/netns/ipv4.h=55=struct netns_ipv4 {\n--\ninclude/net/netns/ipv4.h-116-\tstruct mutex\t\tra_mutex;\ninclude/net/netns/ipv4.h:117:#ifdef CONFIG_IP_MULTIPLE_TABLES\ninclude/net/netns/ipv4.h-118-\tstruct fib_rules_ops\t*rules_ops;\n--\nnet/core/fib_rules.c-20-#if defined(CONFIG_IPV6) \u0026\u0026 defined(CONFIG_IPV6_MULTIPLE_TABLES)\nnet/core/fib_rules.c:21:#ifdef CONFIG_IP_MULTIPLE_TABLES\nnet/core/fib_rules.c-22-#define INDIRECT_CALL_MT(f, f2, f1, ...) \\\n--\nnet/core/fib_rules.c-26-#endif\nnet/core/fib_rules.c:27:#elif defined(CONFIG_IP_MULTIPLE_TABLES)\nnet/core/fib_rules.c-28-#define INDIRECT_CALL_MT(f, f2, f1, ...) INDIRECT_CALL_1(f, f1, __VA_ARGS__)\n--\nnet/ipv4/Makefile=21=obj-$(CONFIG_PROC_FS) += proc.o\nnet/ipv4/Makefile:22:obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o\nnet/ipv4/Makefile-23-obj-$(CONFIG_IP_MROUTE) += ipmr.o\n--\nnet/ipv4/fib_frontend.c-50-\nnet/ipv4/fib_frontend.c:51:#ifndef CONFIG_IP_MULTIPLE_TABLES\nnet/ipv4/fib_frontend.c-52-\n--\nnet/ipv4/fib_frontend.c=129=struct fib_table *fib_get_table(struct net *net, u32 id)\n--\nnet/ipv4/fib_frontend.c-151-}\nnet/ipv4/fib_frontend.c:152:#endif /* CONFIG_IP_MULTIPLE_TABLES */\nnet/ipv4/fib_frontend.c-153-\nnet/ipv4/fib_frontend.c=154=static void fib_replace_table(struct net *net, struct fib_table *old,\n--\nnet/ipv4/fib_frontend.c-156-{\nnet/ipv4/fib_frontend.c:157:#ifdef CONFIG_IP_MULTIPLE_TABLES\nnet/ipv4/fib_frontend.c-158-\tswitch (new-\u003etb_id) {\n--\nnet/ipv4/fib_frontend.c=1610=static void ip_fib_net_exit(struct net *net)\n--\nnet/ipv4/fib_frontend.c-1614-\tASSERT_RTNL_NET(net);\nnet/ipv4/fib_frontend.c:1615:#ifdef CONFIG_IP_MULTIPLE_TABLES\nnet/ipv4/fib_frontend.c-1616-\tRCU_INIT_POINTER(net-\u003eipv4.fib_main, NULL);\n--\nnet/ipv4/fib_frontend.c=1637=static int __net_init fib_net_init(struct net *net)\n--\nnet/ipv4/fib_frontend.c-1670-\nnet/ipv4/fib_frontend.c:1671:#ifdef CONFIG_IP_MULTIPLE_TABLES\nnet/ipv4/fib_frontend.c-1672-\tfib4_rules_exit(net);\n--\nnet/ipv4/fib_frontend.c=1691=static void __net_exit fib_net_exit(struct net *net)\nnet/ipv4/fib_frontend.c-1692-{\nnet/ipv4/fib_frontend.c:1693:#ifdef CONFIG_IP_MULTIPLE_TABLES\nnet/ipv4/fib_frontend.c-1694-\tfib4_rules_exit(net);\n--\nnet/ipv4/route.c=1584=static void rt_set_nexthop(struct rtable *rt, __be32 daddr,\n--\nnet/ipv4/route.c-1635-#ifdef CONFIG_IP_ROUTE_CLASSID\nnet/ipv4/route.c:1636:#ifdef CONFIG_IP_MULTIPLE_TABLES\nnet/ipv4/route.c-1637-\tset_class_tag(rt, res-\u003etclassid);\n--\ntools/testing/selftests/bpf/config.aarch64=72=CONFIG_IP_MULTICAST=y\ntools/testing/selftests/bpf/config.aarch64:73:CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/bpf/config.aarch64-74-CONFIG_IPV6_SEG6_LWTUNNEL=y\n--\ntools/testing/selftests/bpf/config.ppc64el=40=CONFIG_IP_MULTICAST=y\ntools/testing/selftests/bpf/config.ppc64el:41:CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/bpf/config.ppc64el-42-CONFIG_IPV6_SEG6_LWTUNNEL=y\n--\ntools/testing/selftests/bpf/config.riscv64=35=CONFIG_IP_MULTICAST=y\ntools/testing/selftests/bpf/config.riscv64:36:CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/bpf/config.riscv64-37-CONFIG_JUMP_LABEL=y\n--\ntools/testing/selftests/bpf/config.s390x=57=CONFIG_IP_MULTICAST=y\ntools/testing/selftests/bpf/config.s390x:58:CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/bpf/config.s390x-59-CONFIG_IPV6_SEG6_LWTUNNEL=y\n--\ntools/testing/selftests/bpf/config.x86_64=108=CONFIG_IP_MULTICAST=y\ntools/testing/selftests/bpf/config.x86_64:109:CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/bpf/config.x86_64-110-CONFIG_IP_PIMSM_V1=y\n--\ntools/testing/selftests/hid/config.common=95=CONFIG_IP_MULTICAST=y\ntools/testing/selftests/hid/config.common:96:CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/hid/config.common-97-CONFIG_IP_NF_FILTER=y\n--\ntools/testing/selftests/net/mptcp/config=5=CONFIG_IP_ADVANCED_ROUTER=y\ntools/testing/selftests/net/mptcp/config:6:CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/net/mptcp/config-7-CONFIG_IP_NF_FILTER=m\n--\ntools/testing/selftests/wireguard/qemu/kernel.config=31=CONFIG_IP_ADVANCED_ROUTER=y\ntools/testing/selftests/wireguard/qemu/kernel.config:32:CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/wireguard/qemu/kernel.config-33-CONFIG_IPV6_MULTIPLE_TABLES=y\n"
}

5/2 2026/06/29 19:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16484
							output: 24
							thoughts: 16
						

Thoughts:
Okay, let's dive into this. Here's my thought process on this, as if I'm directly experiencing it:

**Examining `CONFIG_IPV6_MULTIPLE_TABLES`**

Alright, time to focus. I'm taking a look at this configuration option, `CONFIG_IPV6_MULTIPLE_TABLES`. Immediately, I'm thinking about the implications for routing. Specifically, I'm already envisioning the routing table infrastructure and how enabling this option changes things within the IPv6 context. Is this about policy routing? Traffic management? The ability to segregate traffic based on different source or destination address prefixes? I'm picturing the kernel data structures – the route tables, the FIB (Forwarding Information Base) lookups, the interface configurations. I'm wondering if this is a recent addition, or a long-standing feature that's finally getting some more attention. What are the common use cases where multiple IPv6 routing tables become essential? Are we talking about virtualized environments, network namespaces, or perhaps sophisticated traffic engineering scenarios? I need to quickly scan the related documentation to refresh my memory on any dependencies or caveats. Are there any other configuration options that are tied to this one, impacting its functionality? And what is the performance impact? This could significantly affect the overall packet forwarding rate. Okay, time to see if the source code comments give me any more insight.



6/2 2026/06/29 19:50 tool grepper
0m Args:
{
  "Expression": "CONFIG_IPV6_MULTIPLE_TABLES"
}

Results:
{
  "Output": "arch/arm/configs/aspeed_g4_defconfig=50=CONFIG_IPV6_OPTIMISTIC_DAD=y\narch/arm/configs/aspeed_g4_defconfig-51-# CONFIG_IPV6_SIT is not set\narch/arm/configs/aspeed_g4_defconfig:52:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/arm/configs/aspeed_g4_defconfig-53-CONFIG_NETFILTER=y\n--\narch/arm/configs/aspeed_g5_defconfig=61=CONFIG_IPV6_OPTIMISTIC_DAD=y\narch/arm/configs/aspeed_g5_defconfig-62-# CONFIG_IPV6_SIT is not set\narch/arm/configs/aspeed_g5_defconfig:63:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/arm/configs/aspeed_g5_defconfig-64-CONFIG_NETFILTER=y\n--\narch/arm/configs/keystone_defconfig=68=CONFIG_IPV6_SIT=m\narch/arm/configs/keystone_defconfig:69:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/arm/configs/keystone_defconfig-70-CONFIG_IPV6_SUBTREES=y\n--\narch/arm/configs/multi_v7_defconfig=150=CONFIG_IPV6_TUNNEL=m\narch/arm/configs/multi_v7_defconfig:151:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/arm/configs/multi_v7_defconfig-152-CONFIG_NET_DSA=m\n--\narch/arm/configs/tegra_defconfig=52=CONFIG_IPV6_TUNNEL=y\narch/arm/configs/tegra_defconfig:53:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/arm/configs/tegra_defconfig-54-CONFIG_CAN=y\n--\narch/loongarch/configs/loongson32_defconfig=158=CONFIG_INET6_IPCOMP=m\narch/loongarch/configs/loongson32_defconfig:159:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/loongarch/configs/loongson32_defconfig-160-CONFIG_IPV6_MROUTE=y\n--\narch/loongarch/configs/loongson64_defconfig=174=CONFIG_INET6_IPCOMP=m\narch/loongarch/configs/loongson64_defconfig:175:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/loongarch/configs/loongson64_defconfig-176-CONFIG_IPV6_MROUTE=y\n--\narch/mips/configs/bcm47xx_defconfig=23=CONFIG_TCP_CONG_ADVANCED=y\narch/mips/configs/bcm47xx_defconfig:24:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/bcm47xx_defconfig-25-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/bigsur_defconfig=60=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/bigsur_defconfig:61:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/bigsur_defconfig-62-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/db1xxx_defconfig=63=CONFIG_IPV6_GRE=y\narch/mips/configs/db1xxx_defconfig:64:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/db1xxx_defconfig-65-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/decstation_64_defconfig=45=CONFIG_IPV6_MIP6=m\narch/mips/configs/decstation_64_defconfig:46:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/decstation_64_defconfig-47-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/decstation_defconfig=41=CONFIG_IPV6_MIP6=m\narch/mips/configs/decstation_defconfig:42:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/decstation_defconfig-43-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/decstation_r4k_defconfig=40=CONFIG_IPV6_MIP6=m\narch/mips/configs/decstation_r4k_defconfig:41:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/decstation_r4k_defconfig-42-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/ip22_defconfig=46=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/ip22_defconfig:47:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/ip22_defconfig-48-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/ip27_defconfig=45=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/ip27_defconfig:46:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/ip27_defconfig-47-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/ip30_defconfig=45=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/ip30_defconfig:46:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/ip30_defconfig-47-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/lemote2f_defconfig=50=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/lemote2f_defconfig:51:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/lemote2f_defconfig-52-CONFIG_IPV6_SUBTREES=y\n--\narch/mips/configs/rm200_defconfig=38=CONFIG_IPV6_TUNNEL=m\narch/mips/configs/rm200_defconfig:39:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/mips/configs/rm200_defconfig-40-CONFIG_IPV6_SUBTREES=y\n--\narch/powerpc/configs/ppc6xx_defconfig=115=CONFIG_IPV6_TUNNEL=m\narch/powerpc/configs/ppc6xx_defconfig:116:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/powerpc/configs/ppc6xx_defconfig-117-CONFIG_IPV6_SUBTREES=y\n--\narch/s390/configs/debug_defconfig=173=CONFIG_IPV6_GRE=m\narch/s390/configs/debug_defconfig:174:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/s390/configs/debug_defconfig-175-CONFIG_IPV6_SUBTREES=y\n--\narch/s390/configs/defconfig=164=CONFIG_IPV6_GRE=m\narch/s390/configs/defconfig:165:CONFIG_IPV6_MULTIPLE_TABLES=y\narch/s390/configs/defconfig-166-CONFIG_IPV6_SUBTREES=y\n--\ninclude/net/ip6_fib.h-24-\ninclude/net/ip6_fib.h:25:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\ninclude/net/ip6_fib.h-26-#define FIB6_TABLE_HASHSZ 256\n--\ninclude/net/ip6_fib.h=391=struct fib6_table {\n--\ninclude/net/ip6_fib.h-408-\ninclude/net/ip6_fib.h:409:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\ninclude/net/ip6_fib.h-410-#define FIB6_TABLE_MIN\t\t1\n--\ninclude/net/ip6_fib.h=660=static inline struct rt6_info *pol_lookup_func(pol_lookup_t lookup,\n--\ninclude/net/ip6_fib.h-674-\ninclude/net/ip6_fib.h:675:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\ninclude/net/ip6_fib.h-676-static inline bool fib6_has_custom_rules(const struct net *net)\n--\ninclude/net/netns/ipv6.h=66=struct netns_ipv6 {\n--\ninclude/net/netns/ipv6.h-87-\tunsigned char\t\tflowlabel_has_excl;\ninclude/net/netns/ipv6.h:88:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\ninclude/net/netns/ipv6.h-89-\tbool\t\t\tfib6_has_custom_rules;\n--\nnet/core/fib_rules.c-19-\nnet/core/fib_rules.c:20:#if defined(CONFIG_IPV6) \u0026\u0026 defined(CONFIG_IPV6_MULTIPLE_TABLES)\nnet/core/fib_rules.c-21-#ifdef CONFIG_IP_MULTIPLE_TABLES\n--\nnet/ipv6/Makefile=20=ipv6-$(CONFIG_NETFILTER) += netfilter.o\nnet/ipv6/Makefile:21:ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o\nnet/ipv6/Makefile-22-ipv6-$(CONFIG_PROC_FS) += proc.o\n--\nnet/ipv6/ip6_fib.c=213=static void fib6_link_table(struct net *net, struct fib6_table *tb)\n--\nnet/ipv6/ip6_fib.c-230-\nnet/ipv6/ip6_fib.c:231:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/ip6_fib.c-232-\n--\nnet/ipv6/ip6_fib.c=2462=static int __net_init fib6_net_init(struct net *net)\n--\nnet/ipv6/ip6_fib.c-2504-\nnet/ipv6/ip6_fib.c:2505:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/ip6_fib.c-2506-\tnet-\u003eipv6.fib6_local_tbl = kzalloc_obj(*net-\u003eipv6.fib6_local_tbl);\n--\nnet/ipv6/ip6_fib.c-2520-\nnet/ipv6/ip6_fib.c:2521:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/ip6_fib.c-2522-out_fib6_main_tbl:\n--\nnet/ipv6/route.c=293=static const struct rt6_info ip6_null_entry_template = {\n--\nnet/ipv6/route.c-304-\nnet/ipv6/route.c:305:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/route.c-306-\n--\nnet/ipv6/route.c=6482=static int ip6_route_dev_notify(struct notifier_block *this,\n--\nnet/ipv6/route.c-6494-\t\tnet-\u003eipv6.ip6_null_entry-\u003ert6i_idev = in6_dev_get(dev);\nnet/ipv6/route.c:6495:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/route.c-6496-\t\tnet-\u003eipv6.ip6_prohibit_entry-\u003edst.dev = dev;\n--\nnet/ipv6/route.c-6506-\t\tin6_dev_put_clear(\u0026net-\u003eipv6.ip6_null_entry-\u003ert6i_idev);\nnet/ipv6/route.c:6507:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/route.c-6508-\t\tin6_dev_put_clear(\u0026net-\u003eipv6.ip6_prohibit_entry-\u003ert6i_idev);\n--\nnet/ipv6/route.c=6676=static int __net_init ip6_route_net_init(struct net *net)\n--\nnet/ipv6/route.c-6701-\nnet/ipv6/route.c:6702:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/route.c-6703-\tnet-\u003eipv6.fib6_has_custom_rules = false;\n--\nnet/ipv6/route.c-6743-\nnet/ipv6/route.c:6744:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/route.c-6745-out_ip6_prohibit_entry:\n--\nnet/ipv6/route.c=6758=static void __net_exit ip6_route_net_exit(struct net *net)\n--\nnet/ipv6/route.c-6761-\tkfree(net-\u003eipv6.ip6_null_entry);\nnet/ipv6/route.c:6762:#ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/route.c-6763-\tkfree(net-\u003eipv6.ip6_prohibit_entry);\n--\nnet/ipv6/route.c=6834=void __init ip6_route_init_special_entries(void)\n--\nnet/ipv6/route.c-6841-\tinit_net.ipv6.ip6_null_entry-\u003ert6i_idev = in6_dev_get(init_net.loopback_dev);\nnet/ipv6/route.c:6842:  #ifdef CONFIG_IPV6_MULTIPLE_TABLES\nnet/ipv6/route.c-6843-\tinit_net.ipv6.ip6_prohibit_entry-\u003edst.dev = init_net.loopback_dev;\n--\ntools/testing/selftests/drivers/net/virtio_net/config=3=CONFIG_IPV6=y\ntools/testing/selftests/drivers/net/virtio_net/config:4:CONFIG_IPV6_MULTIPLE_TABLES=y\ntools/testing/selftests/drivers/net/virtio_net/config-5-CONFIG_NET_L3_MASTER_DEV=y\n--\ntools/testing/selftests/net/config=44=CONFIG_IPV6_MROUTE=y\ntools/testing/selftests/net/config:45:CONFIG_IPV6_MULTIPLE_TABLES=y\ntools/testing/selftests/net/config-46-CONFIG_IPV6_ROUTE_INFO=y\n--\ntools/testing/selftests/net/forwarding/config=14=CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y\ntools/testing/selftests/net/forwarding/config:15:CONFIG_IPV6_MULTIPLE_TABLES=y\ntools/testing/selftests/net/forwarding/config-16-CONFIG_IPV6_PIMSM_V2=y\n--\ntools/testing/selftests/net/mptcp/config=10=CONFIG_IPV6=y\ntools/testing/selftests/net/mptcp/config:11:CONFIG_IPV6_MULTIPLE_TABLES=y\ntools/testing/selftests/net/mptcp/config-12-CONFIG_KALLSYMS=y\n--\ntools/testing/selftests/net/netfilter/config=35=CONFIG_IPV6=y\ntools/testing/selftests/net/netfilter/config:36:CONFIG_IPV6_MULTIPLE_TABLES=y\ntools/testing/selftests/net/netfilter/config-37-CONFIG_IPV6_TUNNEL=m\n--\ntools/testing/selftests/net/tcp_ao/config=1=CONFIG_IPV6=y\ntools/testing/selftests/net/tcp_ao/config:2:CONFIG_IPV6_MULTIPLE_TABLES=y\ntools/testing/selftests/net/tcp_ao/config-3-CONFIG_NET_L3_MASTER_DEV=y\n--\ntools/testing/selftests/wireguard/qemu/kernel.config=32=CONFIG_IP_MULTIPLE_TABLES=y\ntools/testing/selftests/wireguard/qemu/kernel.config:33:CONFIG_IPV6_MULTIPLE_TABLES=y\ntools/testing/selftests/wireguard/qemu/kernel.config-34-CONFIG_TTY=y\n"
}

7/2 2026/06/29 19:50 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 21065
							output: 212
							thoughts: 704
						

Thoughts:
**Fuzzing Target Selection for FIB Rule and Table Locking**

Okay, so I'm thinking about how to best fuzz this patch. The configs that are relevant here are `IP_MULTIPLE_TABLES` and `IPV6_MULTIPLE_TABLES`, so we're good there. The core change is to the locking mechanisms for FIB rules and tables, moving from the RTNL to more fine-grained locking with mutexes and spinlocks. This is definitely a significant functional change, potentially affecting anything that interacts with routing rules and tables.

I need to focus on the control path functions. These are the ones where the locking changes are directly implemented. I initially thought to include `fib_get_table`, but hold on. Let me just double check whether it is called in hot paths, since that would make it more difficult to fuzz effectively. Ah, yes, it's called by the core lookup functions like `fib_lookup` and `ip_route_input_noref`. Not ideal. Let's exclude that for now.

So, the focus symbols should be: `fib_newrule`, `fib_delrule`, `fib_new_table`, `fib_rules_event`, `fib4_rule_configure`, `fib4_rule_delete`, `fib6_rule_configure`, and `fib6_rule_delete`.

Now, let's verify where those are implemented. `fib_newrule` and `fib_delrule` live in `net/core/fib_rules.c`. `fib_new_table` is in `net/ipv4/fib_frontend.c`. And `fib_rules_event` is also in `net/core/fib_rules.c`.

Okay, just to be absolutely sure, `IP_MULTIPLE_TABLES` and `IPV6_MULTIPLE_TABLES` are the correct configs, right? Yep, confirmed.

The reasoning is pretty clear now: the patch modifies the locking, so we want to hit the new locking code directly. The primary way to trigger this is through netlink messages like `RTM_NEWRULE` and `RTM_DELRULE` or through netdev events. These trigger the control path functions, so those are what we want to fuzz.

Now, let's just make sure we haven't missed anything. I should check whether `fib4_rule_delete` and `fib6_rule_delete` are static. Yes, they are in the respective files `net/ipv4/fib_rules.c` and `net/ipv6/fib6_rules.c`. Let's also double check `fib_newrule` and `fib_delrule`. Yep, exported or just global. And `fib_new_table` is also exported. Finally, `fib_rules_event` is also static.

Alright, looks like we have a solid target list: the control path functions impacted by the locking changes. Let's call `set-results`.



8/2 2026/06/29 19:50 tool set-results
0m Args:
{
  "EnableConfigs": [
    "IP_MULTIPLE_TABLES",
    "IPV6_MULTIPLE_TABLES"
  ],
  "FocusSymbols": [
    "fib_newrule",
    "fib_delrule",
    "fib_new_table",
    "fib_rules_event",
    "fib4_rule_configure",
    "fib4_rule_delete",
    "fib6_rule_configure",
    "fib6_rule_delete"
  ],
  "Reasoning": "The patch modifies the locking mechanism for FIB rules and tables, replacing RTNL with finer-grained mutexes and spinlocks (ops-\u003elock and fib_table_hash_lock). This is a functional change to core networking logic that can be reached via netlink messages (e.g., RTM_NEWRULE, RTM_DELRULE) and netdev events. Fuzzing should focus on the control path functions that were modified to use the new locks.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "IP_MULTIPLE_TABLES",
    "IPV6_MULTIPLE_TABLES"
  ],
  "FocusSymbols": [
    "fib_newrule",
    "fib_delrule",
    "fib_new_table",
    "fib_rules_event",
    "fib4_rule_configure",
    "fib4_rule_delete",
    "fib6_rule_configure",
    "fib6_rule_delete"
  ],
  "Reasoning": "The patch modifies the locking mechanism for FIB rules and tables, replacing RTNL with finer-grained mutexes and spinlocks (ops-\u003elock and fib_table_hash_lock). This is a functional change to core networking logic that can be reached via netlink messages (e.g., RTM_NEWRULE, RTM_DELRULE) and netdev events. Fuzzing should focus on the control path functions that were modified to use the new locks.",
  "WorthFuzzing": true
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)