AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/07/07 23:53 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": [
    "GENEVE"
  ],
  "FocusSymbols": [
    "geneve_changelink",
    "geneve_configure",
    "geneve_fill_info",
    "geneve_config_alloc",
    "geneve_free_dev"
  ],
  "Reasoning": "The patch refactors the GENEVE driver to use RCU for its configuration (`struct geneve_config`), replacing the previous synchronous `geneve_quiesce`/`geneve_unquiesce` mechanism. This is a functional change affecting how configuration updates are handled concurrently with the data path. Fuzzing should focus on the netlink control path functions that allocate, update, and free the configuration.",
  "WorthFuzzing": true
}

1/1 2026/07/07 23:53 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 3a1d0941dbc90d639a922cad60215b93775b954e\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Tue Jul 7 23:53:29 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/drivers/net/geneve.c b/drivers/net/geneve.c\nindex 396e1a113cd49e..17bd3543d587a9 100644\n--- a/drivers/net/geneve.c\n+++ b/drivers/net/geneve.c\n@@ -82,6 +82,7 @@ struct geneve_config {\n \tu16\t\t\tport_min;\n \tu16\t\t\tport_max;\n \n+\tstruct rcu_head\t\trcu;\n \t/* Must be last --ends in a flexible-array member. */\n \tstruct ip_tunnel_info\tinfo;\n };\n@@ -100,7 +101,7 @@ struct geneve_dev {\n #endif\n \tstruct list_head   next;\t/* geneve's per namespace list */\n \tstruct gro_cells   gro_cells;\n-\tstruct geneve_config cfg;\n+\tstruct geneve_config __rcu *cfg;\n };\n \n struct geneve_sock {\n@@ -182,8 +183,10 @@ static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,\n \thash = geneve_net_vni_hash(vni);\n \tvni_list_head = \u0026gs-\u003evni_list[hash];\n \thlist_for_each_entry_rcu(node, vni_list_head, hlist) {\n-\t\tif (eq_tun_id_and_vni((u8 *)\u0026node-\u003egeneve-\u003ecfg.info.key.tun_id, vni) \u0026\u0026\n-\t\t    addr == node-\u003egeneve-\u003ecfg.info.key.u.ipv4.dst)\n+\t\tconst struct geneve_config *cfg = rcu_dereference(node-\u003egeneve-\u003ecfg);\n+\n+\t\tif (eq_tun_id_and_vni((u8 *)\u0026cfg-\u003einfo.key.tun_id, vni) \u0026\u0026\n+\t\t    addr == cfg-\u003einfo.key.u.ipv4.dst)\n \t\t\treturn node-\u003egeneve;\n \t}\n \treturn NULL;\n@@ -201,8 +204,10 @@ static struct geneve_dev *geneve6_lookup(struct geneve_sock *gs,\n \thash = geneve_net_vni_hash(vni);\n \tvni_list_head = \u0026gs-\u003evni_list[hash];\n \thlist_for_each_entry_rcu(node, vni_list_head, hlist) {\n-\t\tif (eq_tun_id_and_vni((u8 *)\u0026node-\u003egeneve-\u003ecfg.info.key.tun_id, vni) \u0026\u0026\n-\t\t    ipv6_addr_equal(\u0026addr6, \u0026node-\u003egeneve-\u003ecfg.info.key.u.ipv6.dst))\n+\t\tconst struct geneve_config *cfg = rcu_dereference(node-\u003egeneve-\u003ecfg);\n+\n+\t\tif (eq_tun_id_and_vni((u8 *)\u0026cfg-\u003einfo.key.tun_id, vni) \u0026\u0026\n+\t\t    ipv6_addr_equal(\u0026addr6, \u0026cfg-\u003einfo.key.u.ipv6.dst))\n \t\t\treturn node-\u003egeneve;\n \t}\n \treturn NULL;\n@@ -386,11 +391,6 @@ static int geneve_init(struct net_device *dev)\n \tif (err)\n \t\treturn err;\n \n-\terr = dst_cache_init(\u0026geneve-\u003ecfg.info.dst_cache, GFP_KERNEL);\n-\tif (err) {\n-\t\tgro_cells_destroy(\u0026geneve-\u003egro_cells);\n-\t\treturn err;\n-\t}\n \tnetdev_lockdep_set_classes(dev);\n \treturn 0;\n }\n@@ -399,7 +399,6 @@ static void geneve_uninit(struct net_device *dev)\n {\n \tstruct geneve_dev *geneve = netdev_priv(dev);\n \n-\tdst_cache_destroy(\u0026geneve-\u003ecfg.info.dst_cache);\n \tgro_cells_destroy(\u0026geneve-\u003egro_cells);\n }\n \n@@ -650,6 +649,7 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb,\n /* Callback from net/ipv4/udp.c to receive packets */\n static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)\n {\n+\tconst struct geneve_config *cfg;\n \tstruct genevehdr *geneveh;\n \tstruct geneve_dev *geneve;\n \tstruct geneve_sock *gs;\n@@ -675,8 +675,9 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)\n \n \tinner_proto = geneveh-\u003eproto_type;\n \n-\tif (unlikely((!geneve-\u003ecfg.inner_proto_inherit \u0026\u0026\n-\t\t      inner_proto != htons(ETH_P_TEB)))) {\n+\tcfg = rcu_dereference(geneve-\u003ecfg);\n+\tif (unlikely(!cfg || (!cfg-\u003einner_proto_inherit \u0026\u0026\n+\t\t\t      inner_proto != htons(ETH_P_TEB)))) {\n \t\tdev_dstats_rx_dropped(geneve-\u003edev);\n \t\tgoto drop;\n \t}\n@@ -762,9 +763,10 @@ static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)\n }\n \n static struct sock *geneve_create_sock(struct net *net,\n-\t\t\t\t       struct geneve_dev *geneve, bool ipv6)\n+\t\t\t\t       struct geneve_dev *geneve,\n+\t\t\t\t       const struct geneve_config *cfg, bool ipv6)\n {\n-\tstruct ip_tunnel_info *info = \u0026geneve-\u003ecfg.info;\n+\tconst struct ip_tunnel_info *info = \u0026cfg-\u003einfo;\n \tstruct udp_port_cfg udp_conf;\n \tstruct socket *sock;\n \tint err;\n@@ -775,7 +777,7 @@ static struct sock *geneve_create_sock(struct net *net,\n \tif (ipv6) {\n \t\tudp_conf.family = AF_INET6;\n \t\tudp_conf.ipv6_v6only = 1;\n-\t\tudp_conf.use_udp6_rx_checksums = geneve-\u003ecfg.use_udp6_rx_checksums;\n+\t\tudp_conf.use_udp6_rx_checksums = cfg-\u003euse_udp6_rx_checksums;\n \t\tudp_conf.local_ip6 = info-\u003ekey.u.ipv6.src;\n \t} else\n #endif\n@@ -991,7 +993,8 @@ static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,\n \n /* Create new listen socket if needed */\n static struct geneve_sock *geneve_socket_create(struct net *net,\n-\t\t\t\t\t\tstruct geneve_dev *geneve, bool ipv6)\n+\t\t\t\t\t\tstruct geneve_dev *geneve,\n+\t\t\t\t\t\tconst struct geneve_config *cfg, bool ipv6)\n {\n \tstruct geneve_net *gn = net_generic(net, geneve_net_id);\n \tstruct udp_tunnel_sock_cfg tunnel_cfg;\n@@ -1003,7 +1006,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net,\n \tif (!gs)\n \t\treturn ERR_PTR(-ENOMEM);\n \n-\tsk = geneve_create_sock(net, geneve, ipv6);\n+\tsk = geneve_create_sock(net, geneve, cfg, ipv6);\n \tif (IS_ERR(sk)) {\n \t\tkfree(gs);\n \t\treturn ERR_CAST(sk);\n@@ -1060,12 +1063,13 @@ static void geneve_sock_release(struct geneve_dev *geneve)\n }\n \n static struct geneve_sock *geneve_find_sock(struct net *net,\n-\t\t\t\t\t    struct geneve_dev *geneve, bool ipv6)\n+\t\t\t\t\t    struct geneve_dev *geneve,\n+\t\t\t\t\t    const struct geneve_config *cfg, bool ipv6)\n {\n \tstruct geneve_net *gn = net_generic(net, geneve_net_id);\n-\tstruct ip_tunnel_info *info = \u0026geneve-\u003ecfg.info;\n+\tconst struct ip_tunnel_info *info = \u0026cfg-\u003einfo;\n \tsa_family_t family = ipv6 ? AF_INET6 : AF_INET;\n-\tbool gro_hint = geneve-\u003ecfg.gro_hint;\n+\tbool gro_hint = cfg-\u003egro_hint;\n \t__be16 dst_port = info-\u003ekey.tp_dst;\n \tstruct geneve_sock *gs;\n \n@@ -1095,7 +1099,8 @@ static struct geneve_sock *geneve_find_sock(struct net *net,\n \treturn NULL;\n }\n \n-static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)\n+static int geneve_sock_add(struct geneve_dev *geneve,\n+\t\t\t   const struct geneve_config *cfg, bool ipv6)\n {\n \tstruct net *net = geneve-\u003enet;\n \tstruct geneve_dev_node *node;\n@@ -1103,19 +1108,19 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)\n \t__u8 vni[3];\n \t__u32 hash;\n \n-\tgs = geneve_find_sock(net, geneve, ipv6);\n+\tgs = geneve_find_sock(net, geneve, cfg, ipv6);\n \tif (gs) {\n \t\tgs-\u003erefcnt++;\n \t\tgoto out;\n \t}\n \n-\tgs = geneve_socket_create(net, geneve, ipv6);\n+\tgs = geneve_socket_create(net, geneve, cfg, ipv6);\n \tif (IS_ERR(gs))\n \t\treturn PTR_ERR(gs);\n \n out:\n-\tgs-\u003ecollect_md = geneve-\u003ecfg.collect_md;\n-\tgs-\u003egro_hint = geneve-\u003ecfg.gro_hint;\n+\tgs-\u003ecollect_md = cfg-\u003ecollect_md;\n+\tgs-\u003egro_hint = cfg-\u003egro_hint;\n #if IS_ENABLED(CONFIG_IPV6)\n \tif (ipv6) {\n \t\trcu_assign_pointer(geneve-\u003esock6, gs);\n@@ -1128,7 +1133,7 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)\n \t}\n \tnode-\u003egeneve = geneve;\n \n-\ttunnel_id_to_vni(geneve-\u003ecfg.info.key.tun_id, vni);\n+\ttunnel_id_to_vni(cfg-\u003einfo.key.tun_id, vni);\n \thash = geneve_net_vni_hash(vni);\n \thlist_add_head_rcu(\u0026node-\u003ehlist, \u0026gs-\u003evni_list[hash]);\n \treturn 0;\n@@ -1137,21 +1142,23 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)\n static int geneve_open(struct net_device *dev)\n {\n \tstruct geneve_dev *geneve = netdev_priv(dev);\n-\tbool dualstack = geneve-\u003ecfg.dualstack;\n-\tbool ipv4, ipv6;\n+\tconst struct geneve_config *cfg;\n+\tbool ipv4, ipv6, dualstack;\n \tint ret = 0;\n \n-\tipv6 = geneve-\u003ecfg.info.mode \u0026 IP_TUNNEL_INFO_IPV6 || dualstack;\n+\tcfg = rtnl_dereference(geneve-\u003ecfg);\n+\tdualstack = cfg-\u003edualstack;\n+\tipv6 = cfg-\u003einfo.mode \u0026 IP_TUNNEL_INFO_IPV6 || dualstack;\n \tipv4 = !ipv6 || dualstack;\n #if IS_ENABLED(CONFIG_IPV6)\n \tif (ipv6) {\n-\t\tret = geneve_sock_add(geneve, true);\n+\t\tret = geneve_sock_add(geneve, cfg, true);\n \t\tif (ret \u003c 0 \u0026\u0026 ret != -EAFNOSUPPORT)\n \t\t\tipv4 = false;\n \t}\n #endif\n \tif (ipv4)\n-\t\tret = geneve_sock_add(geneve, false);\n+\t\tret = geneve_sock_add(geneve, cfg, false);\n \tif (ret \u003c 0)\n \t\tgeneve_sock_release(geneve);\n \n@@ -1189,6 +1196,7 @@ static void geneve_build_header(struct genevehdr *geneveh,\n }\n \n static int geneve_build_gro_hint_opt(const struct geneve_dev *geneve,\n+\t\t\t\t     const struct geneve_config *cfg,\n \t\t\t\t     struct sk_buff *skb)\n {\n \tstruct geneve_skb_cb *cb = GENEVE_SKB_CB(skb);\n@@ -1201,7 +1209,7 @@ static int geneve_build_gro_hint_opt(const struct geneve_dev *geneve,\n \tcb-\u003egro_hint_len = 0;\n \n \t/* Try to add the GRO hint only in case of double encap. */\n-\tif (!geneve-\u003ecfg.gro_hint || !skb-\u003eencapsulation)\n+\tif (!cfg-\u003egro_hint || !skb-\u003eencapsulation)\n \t\treturn 0;\n \n \t/*\n@@ -1262,10 +1270,11 @@ static void geneve_put_gro_hint_opt(struct genevehdr *gnvh, int opt_size,\n \n static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,\n \t\t\t    const struct ip_tunnel_info *info,\n-\t\t\t    const struct geneve_dev *geneve, int ip_hdr_len)\n+\t\t\t    const struct geneve_dev *geneve,\n+\t\t\t    const struct geneve_config *cfg, int ip_hdr_len)\n {\n \tbool udp_sum = test_bit(IP_TUNNEL_CSUM_BIT, info-\u003ekey.tun_flags);\n-\tbool inner_proto_inherit = geneve-\u003ecfg.inner_proto_inherit;\n+\tbool inner_proto_inherit = cfg-\u003einner_proto_inherit;\n \tbool xnet = !net_eq(geneve-\u003enet, dev_net(geneve-\u003edev));\n \tstruct geneve_skb_cb *cb = GENEVE_SKB_CB(skb);\n \tstruct genevehdr *gnvh;\n@@ -1306,14 +1315,14 @@ static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,\n }\n \n static u8 geneve_get_dsfield(struct sk_buff *skb, struct net_device *dev,\n+\t\t\t     const struct geneve_config *cfg,\n \t\t\t     const struct ip_tunnel_info *info,\n \t\t\t     bool *use_cache)\n {\n-\tstruct geneve_dev *geneve = netdev_priv(dev);\n \tu8 dsfield;\n \n \tdsfield = info-\u003ekey.tos;\n-\tif (dsfield == 1 \u0026\u0026 !geneve-\u003ecfg.collect_md) {\n+\tif (cfg \u0026\u0026 dsfield == 1 \u0026\u0026 !cfg-\u003ecollect_md) {\n \t\tdsfield = ip_tunnel_get_dsfield(ip_hdr(skb), skb);\n \t\t*use_cache = false;\n \t}\n@@ -1323,6 +1332,7 @@ static u8 geneve_get_dsfield(struct sk_buff *skb, struct net_device *dev,\n \n static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n \t\t\t   struct geneve_dev *geneve,\n+\t\t\t   const struct geneve_config *cfg,\n \t\t\t   const struct ip_tunnel_info *info)\n {\n \tstruct geneve_sock *gs4 = rcu_dereference(geneve-\u003esock4);\n@@ -1335,35 +1345,35 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n \t__be16 sport;\n \tint err;\n \n-\tif (skb_vlan_inet_prepare(skb, geneve-\u003ecfg.inner_proto_inherit))\n+\tif (skb_vlan_inet_prepare(skb, cfg-\u003einner_proto_inherit))\n \t\treturn -EINVAL;\n \n \tif (!gs4)\n \t\treturn -EIO;\n \n \tuse_cache = ip_tunnel_dst_cache_usable(skb, info);\n-\ttos = geneve_get_dsfield(skb, dev, info, \u0026use_cache);\n+\ttos = geneve_get_dsfield(skb, dev, cfg, info, \u0026use_cache);\n \tsport = udp_flow_src_port(geneve-\u003enet, skb,\n-\t\t\t\t  geneve-\u003ecfg.port_min,\n-\t\t\t\t  geneve-\u003ecfg.port_max, true);\n+\t\t\t\t  cfg-\u003eport_min,\n+\t\t\t\t  cfg-\u003eport_max, true);\n \n \trt = udp_tunnel_dst_lookup(skb, dev, geneve-\u003enet, 0, \u0026saddr,\n \t\t\t\t   \u0026info-\u003ekey,\n-\t\t\t\t   sport, geneve-\u003ecfg.info.key.tp_dst, tos,\n+\t\t\t\t   sport, cfg-\u003einfo.key.tp_dst, tos,\n \t\t\t\t   use_cache ?\n \t\t\t\t   (struct dst_cache *)\u0026info-\u003edst_cache : NULL);\n \tif (IS_ERR(rt))\n \t\treturn PTR_ERR(rt);\n \n-\tif (geneve-\u003ecfg.info.key.u.ipv4.src \u0026\u0026\n-\t    saddr != geneve-\u003ecfg.info.key.u.ipv4.src) {\n+\tif (cfg-\u003einfo.key.u.ipv4.src \u0026\u0026\n+\t    saddr != cfg-\u003einfo.key.u.ipv4.src) {\n \t\tdst_release(\u0026rt-\u003edst);\n \t\treturn -EADDRNOTAVAIL;\n \t}\n \n \terr = skb_tunnel_check_pmtu(skb, \u0026rt-\u003edst,\n \t\t\t\t    GENEVE_IPV4_HLEN + info-\u003eoptions_len +\n-\t\t\t\t    geneve_build_gro_hint_opt(geneve, skb),\n+\t\t\t\t    geneve_build_gro_hint_opt(geneve, cfg, skb),\n \t\t\t\t    netif_is_any_bridge_port(dev));\n \tif (err \u003c 0) {\n \t\tdst_release(\u0026rt-\u003edst);\n@@ -1397,21 +1407,21 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n \t}\n \n \ttos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb);\n-\tif (geneve-\u003ecfg.collect_md) {\n+\tif (cfg-\u003ecollect_md) {\n \t\tttl = key-\u003ettl;\n \n \t\tdf = test_bit(IP_TUNNEL_DONT_FRAGMENT_BIT, key-\u003etun_flags) ?\n \t\t     htons(IP_DF) : 0;\n \t} else {\n-\t\tif (geneve-\u003ecfg.ttl_inherit)\n+\t\tif (cfg-\u003ettl_inherit)\n \t\t\tttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);\n \t\telse\n \t\t\tttl = key-\u003ettl;\n \t\tttl = ttl ? : ip4_dst_hoplimit(\u0026rt-\u003edst);\n \n-\t\tif (geneve-\u003ecfg.df == GENEVE_DF_SET) {\n+\t\tif (cfg-\u003edf == GENEVE_DF_SET) {\n \t\t\tdf = htons(IP_DF);\n-\t\t} else if (geneve-\u003ecfg.df == GENEVE_DF_INHERIT) {\n+\t\t} else if (cfg-\u003edf == GENEVE_DF_INHERIT) {\n \t\t\tstruct ethhdr *eth = skb_eth_hdr(skb);\n \n \t\t\tif (ntohs(eth-\u003eh_proto) == ETH_P_IPV6) {\n@@ -1425,13 +1435,13 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n \t\t}\n \t}\n \n-\terr = geneve_build_skb(\u0026rt-\u003edst, skb, info, geneve,\n+\terr = geneve_build_skb(\u0026rt-\u003edst, skb, info, geneve, cfg,\n \t\t\t       sizeof(struct iphdr));\n \tif (unlikely(err))\n \t\treturn err;\n \n \tudp_tunnel_xmit_skb(rt, gs4-\u003esk, skb, saddr, info-\u003ekey.u.ipv4.dst,\n-\t\t\t    tos, ttl, df, sport, geneve-\u003ecfg.info.key.tp_dst,\n+\t\t\t    tos, ttl, df, sport, cfg-\u003einfo.key.tp_dst,\n \t\t\t    !net_eq(geneve-\u003enet, dev_net(geneve-\u003edev)),\n \t\t\t    !test_bit(IP_TUNNEL_CSUM_BIT, info-\u003ekey.tun_flags),\n \t\t\t    0);\n@@ -1441,6 +1451,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n #if IS_ENABLED(CONFIG_IPV6)\n static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n \t\t\t    struct geneve_dev *geneve,\n+\t\t\t    const struct geneve_config *cfg,\n \t\t\t    const struct ip_tunnel_info *info)\n {\n \tstruct geneve_sock *gs6 = rcu_dereference(geneve-\u003esock6);\n@@ -1452,35 +1463,35 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n \t__be16 sport;\n \tint err;\n \n-\tif (skb_vlan_inet_prepare(skb, geneve-\u003ecfg.inner_proto_inherit))\n+\tif (skb_vlan_inet_prepare(skb, cfg-\u003einner_proto_inherit))\n \t\treturn -EINVAL;\n \n \tif (!gs6)\n \t\treturn -EIO;\n \n \tuse_cache = ip_tunnel_dst_cache_usable(skb, info);\n-\tprio = geneve_get_dsfield(skb, dev, info, \u0026use_cache);\n+\tprio = geneve_get_dsfield(skb, dev, cfg, info, \u0026use_cache);\n \tsport = udp_flow_src_port(geneve-\u003enet, skb,\n-\t\t\t\t  geneve-\u003ecfg.port_min,\n-\t\t\t\t  geneve-\u003ecfg.port_max, true);\n+\t\t\t\t  cfg-\u003eport_min,\n+\t\t\t\t  cfg-\u003eport_max, true);\n \n \tdst = udp_tunnel6_dst_lookup(skb, dev, geneve-\u003enet, gs6-\u003esk, 0,\n \t\t\t\t     \u0026saddr, key, sport,\n-\t\t\t\t     geneve-\u003ecfg.info.key.tp_dst, prio,\n+\t\t\t\t     cfg-\u003einfo.key.tp_dst, prio,\n \t\t\t\t     use_cache ?\n \t\t\t\t     (struct dst_cache *)\u0026info-\u003edst_cache : NULL);\n \tif (IS_ERR(dst))\n \t\treturn PTR_ERR(dst);\n \n-\tif (!ipv6_addr_any(\u0026geneve-\u003ecfg.info.key.u.ipv6.src) \u0026\u0026\n-\t    !ipv6_addr_equal(\u0026saddr, \u0026geneve-\u003ecfg.info.key.u.ipv6.src)) {\n+\tif (!ipv6_addr_any(\u0026cfg-\u003einfo.key.u.ipv6.src) \u0026\u0026\n+\t    !ipv6_addr_equal(\u0026saddr, \u0026cfg-\u003einfo.key.u.ipv6.src)) {\n \t\tdst_release(dst);\n \t\treturn -EADDRNOTAVAIL;\n \t}\n \n \terr = skb_tunnel_check_pmtu(skb, dst,\n \t\t\t\t    GENEVE_IPV6_HLEN + info-\u003eoptions_len +\n-\t\t\t\t    geneve_build_gro_hint_opt(geneve, skb),\n+\t\t\t\t    geneve_build_gro_hint_opt(geneve, cfg, skb),\n \t\t\t\t    netif_is_any_bridge_port(dev));\n \tif (err \u003c 0) {\n \t\tdst_release(dst);\n@@ -1513,22 +1524,22 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n \t}\n \n \tprio = ip_tunnel_ecn_encap(prio, ip_hdr(skb), skb);\n-\tif (geneve-\u003ecfg.collect_md) {\n+\tif (cfg-\u003ecollect_md) {\n \t\tttl = key-\u003ettl;\n \t} else {\n-\t\tif (geneve-\u003ecfg.ttl_inherit)\n+\t\tif (cfg-\u003ettl_inherit)\n \t\t\tttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);\n \t\telse\n \t\t\tttl = key-\u003ettl;\n \t\tttl = ttl ? : ip6_dst_hoplimit(dst);\n \t}\n-\terr = geneve_build_skb(dst, skb, info, geneve, sizeof(struct ipv6hdr));\n+\terr = geneve_build_skb(dst, skb, info, geneve, cfg, sizeof(struct ipv6hdr));\n \tif (unlikely(err))\n \t\treturn err;\n \n \tudp_tunnel6_xmit_skb(dst, gs6-\u003esk, skb, dev,\n \t\t\t     \u0026saddr, \u0026key-\u003eu.ipv6.dst, prio, ttl,\n-\t\t\t     info-\u003ekey.label, sport, geneve-\u003ecfg.info.key.tp_dst,\n+\t\t\t     info-\u003ekey.label, sport, cfg-\u003einfo.key.tp_dst,\n \t\t\t     !test_bit(IP_TUNNEL_CSUM_BIT,\n \t\t\t\t       info-\u003ekey.tun_flags),\n \t\t\t     0);\n@@ -1539,28 +1550,31 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,\n static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)\n {\n \tstruct geneve_dev *geneve = netdev_priv(dev);\n-\tstruct ip_tunnel_info *info = NULL;\n+\tconst struct ip_tunnel_info *info = NULL;\n+\tconst struct geneve_config *cfg;\n \tint err;\n \n-\tif (geneve-\u003ecfg.collect_md) {\n+\trcu_read_lock();\n+\tcfg = rcu_dereference(geneve-\u003ecfg);\n+\tif (cfg-\u003ecollect_md) {\n \t\tinfo = skb_tunnel_info(skb);\n \t\tif (unlikely(!info || !(info-\u003emode \u0026 IP_TUNNEL_INFO_TX))) {\n \t\t\tnetdev_dbg(dev, \"no tunnel metadata\\n\");\n \t\t\tdev_kfree_skb(skb);\n \t\t\tdev_dstats_tx_dropped(dev);\n+\t\t\trcu_read_unlock();\n \t\t\treturn NETDEV_TX_OK;\n \t\t}\n \t} else {\n-\t\tinfo = \u0026geneve-\u003ecfg.info;\n+\t\tinfo = \u0026cfg-\u003einfo;\n \t}\n \n-\trcu_read_lock();\n #if IS_ENABLED(CONFIG_IPV6)\n \tif (info-\u003emode \u0026 IP_TUNNEL_INFO_IPV6)\n-\t\terr = geneve6_xmit_skb(skb, dev, geneve, info);\n+\t\terr = geneve6_xmit_skb(skb, dev, geneve, cfg, info);\n \telse\n #endif\n-\t\terr = geneve_xmit_skb(skb, dev, geneve, info);\n+\t\terr = geneve_xmit_skb(skb, dev, geneve, cfg, info);\n \trcu_read_unlock();\n \n \tif (likely(!err))\n@@ -1593,8 +1607,13 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)\n {\n \tstruct ip_tunnel_info *info = skb_tunnel_info(skb);\n \tstruct geneve_dev *geneve = netdev_priv(dev);\n+\tconst struct geneve_config *cfg;\n \t__be16 sport;\n \n+\tcfg = rcu_dereference(geneve-\u003ecfg);\n+\tif (unlikely(!cfg))\n+\t\treturn -ENODEV;\n+\n \tif (ip_tunnel_info_af(info) == AF_INET) {\n \t\tstruct rtable *rt;\n \t\tstruct geneve_sock *gs4 = rcu_dereference(geneve-\u003esock4);\n@@ -1606,14 +1625,14 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)\n \t\t\treturn -EIO;\n \n \t\tuse_cache = ip_tunnel_dst_cache_usable(skb, info);\n-\t\ttos = geneve_get_dsfield(skb, dev, info, \u0026use_cache);\n+\t\ttos = geneve_get_dsfield(skb, dev, cfg, info, \u0026use_cache);\n \t\tsport = udp_flow_src_port(geneve-\u003enet, skb,\n-\t\t\t\t\t  geneve-\u003ecfg.port_min,\n-\t\t\t\t\t  geneve-\u003ecfg.port_max, true);\n+\t\t\t\t\t  cfg-\u003eport_min,\n+\t\t\t\t\t  cfg-\u003eport_max, true);\n \n \t\trt = udp_tunnel_dst_lookup(skb, dev, geneve-\u003enet, 0, \u0026saddr,\n \t\t\t\t\t   \u0026info-\u003ekey,\n-\t\t\t\t\t   sport, geneve-\u003ecfg.info.key.tp_dst,\n+\t\t\t\t\t   sport, cfg-\u003einfo.key.tp_dst,\n \t\t\t\t\t   tos,\n \t\t\t\t\t   use_cache ? \u0026info-\u003edst_cache : NULL);\n \t\tif (IS_ERR(rt))\n@@ -1633,14 +1652,14 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)\n \t\t\treturn -EIO;\n \n \t\tuse_cache = ip_tunnel_dst_cache_usable(skb, info);\n-\t\tprio = geneve_get_dsfield(skb, dev, info, \u0026use_cache);\n+\t\tprio = geneve_get_dsfield(skb, dev, cfg, info, \u0026use_cache);\n \t\tsport = udp_flow_src_port(geneve-\u003enet, skb,\n-\t\t\t\t\t  geneve-\u003ecfg.port_min,\n-\t\t\t\t\t  geneve-\u003ecfg.port_max, true);\n+\t\t\t\t\t  cfg-\u003eport_min,\n+\t\t\t\t\t  cfg-\u003eport_max, true);\n \n \t\tdst = udp_tunnel6_dst_lookup(skb, dev, geneve-\u003enet, gs6-\u003esk, 0,\n \t\t\t\t\t     \u0026saddr, \u0026info-\u003ekey, sport,\n-\t\t\t\t\t     geneve-\u003ecfg.info.key.tp_dst, prio,\n+\t\t\t\t\t     cfg-\u003einfo.key.tp_dst, prio,\n \t\t\t\t\t     use_cache ? \u0026info-\u003edst_cache : NULL);\n \t\tif (IS_ERR(dst))\n \t\t\treturn PTR_ERR(dst);\n@@ -1653,7 +1672,7 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)\n \t}\n \n \tinfo-\u003ekey.tp_src = sport;\n-\tinfo-\u003ekey.tp_dst = geneve-\u003ecfg.info.key.tp_dst;\n+\tinfo-\u003ekey.tp_dst = cfg-\u003einfo.key.tp_dst;\n \treturn 0;\n }\n \n@@ -1709,7 +1728,50 @@ static void geneve_offload_rx_ports(struct net_device *dev, bool push)\n \t}\n }\n \n+static struct geneve_config *geneve_config_alloc(const struct geneve_config *src)\n+{\n+\tstruct geneve_config *cfg;\n+\tint err;\n+\n+\tcfg = kmemdup(src, sizeof(*src), GFP_KERNEL);\n+\tif (!cfg)\n+\t\treturn ERR_PTR(-ENOMEM);\n+\n+\tcfg-\u003einfo.dst_cache.cache = NULL;\n+\terr = dst_cache_init(\u0026cfg-\u003einfo.dst_cache, GFP_KERNEL);\n+\tif (err) {\n+\t\tkfree(cfg);\n+\t\treturn ERR_PTR(err);\n+\t}\n+\n+\treturn cfg;\n+}\n+\n+static void geneve_config_free(struct geneve_config *cfg)\n+{\n+\tif (cfg) {\n+\t\tdst_cache_destroy(\u0026cfg-\u003einfo.dst_cache);\n+\t\tkfree(cfg);\n+\t}\n+}\n+\n+static void geneve_config_free_rcu(struct rcu_head *head)\n+{\n+\tstruct geneve_config *cfg = container_of(head, struct geneve_config, rcu);\n+\n+\tgeneve_config_free(cfg);\n+}\n+\n /* Initialize the device structure. */\n+static void geneve_free_dev(struct net_device *dev)\n+{\n+\tstruct geneve_dev *geneve = netdev_priv(dev);\n+\tstruct geneve_config *cfg = rcu_dereference_protected(geneve-\u003ecfg, 1);\n+\n+\tgeneve_config_free(cfg);\n+\tRCU_INIT_POINTER(geneve-\u003ecfg, NULL);\n+}\n+\n static void geneve_setup(struct net_device *dev)\n {\n \tether_setup(dev);\n@@ -1717,6 +1779,7 @@ static void geneve_setup(struct net_device *dev)\n \tdev-\u003enetdev_ops = \u0026geneve_netdev_ops;\n \tdev-\u003eethtool_ops = \u0026geneve_ethtool_ops;\n \tdev-\u003eneeds_free_netdev = true;\n+\tdev-\u003epriv_destructor = geneve_free_dev;\n \n \tSET_NETDEV_DEVTYPE(dev, \u0026geneve_type);\n \n@@ -1878,15 +1941,17 @@ static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,\n \t*tun_on_same_port = false;\n \t*tun_collect_md = false;\n \tlist_for_each_entry(geneve, \u0026gn-\u003egeneve_list, next) {\n-\t\tif (info-\u003ekey.tp_dst == geneve-\u003ecfg.info.key.tp_dst \u0026\u0026\n-\t\t    (cfg-\u003edualstack || geneve-\u003ecfg.dualstack ||\n-\t\t     geneve_saddr_conflict(info, \u0026geneve-\u003ecfg.info))) {\n-\t\t\t*tun_collect_md |= geneve-\u003ecfg.collect_md;\n+\t\tconst struct geneve_config *gcfg = rtnl_dereference(geneve-\u003ecfg);\n+\n+\t\tif (info-\u003ekey.tp_dst == gcfg-\u003einfo.key.tp_dst \u0026\u0026\n+\t\t    (cfg-\u003edualstack || gcfg-\u003edualstack ||\n+\t\t     geneve_saddr_conflict(info, \u0026gcfg-\u003einfo))) {\n+\t\t\t*tun_collect_md |= gcfg-\u003ecollect_md;\n \t\t\t*tun_on_same_port = true;\n \t\t}\n-\t\tif (info-\u003ekey.tun_id == geneve-\u003ecfg.info.key.tun_id \u0026\u0026\n-\t\t    info-\u003ekey.tp_dst == geneve-\u003ecfg.info.key.tp_dst \u0026\u0026\n-\t\t    !memcmp(\u0026info-\u003ekey.u, \u0026geneve-\u003ecfg.info.key.u, sizeof(info-\u003ekey.u)))\n+\t\tif (info-\u003ekey.tun_id == gcfg-\u003einfo.key.tun_id \u0026\u0026\n+\t\t    info-\u003ekey.tp_dst == gcfg-\u003einfo.key.tp_dst \u0026\u0026\n+\t\t    !memcmp(\u0026info-\u003ekey.u, \u0026gcfg-\u003einfo.key.u, sizeof(info-\u003ekey.u)))\n \t\t\tt = geneve;\n \t}\n \treturn t;\n@@ -1922,6 +1987,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,\n \tstruct geneve_dev *t, *geneve = netdev_priv(dev);\n \tconst struct ip_tunnel_info *info = \u0026cfg-\u003einfo;\n \tbool tun_collect_md, tun_on_same_port;\n+\tstruct geneve_config *new_cfg;\n \tint err, encap_len;\n \n \tif (cfg-\u003ecollect_md \u0026\u0026 !is_tnl_info_zero(info)) {\n@@ -1962,10 +2028,13 @@ static int geneve_configure(struct net *net, struct net_device *dev,\n \t\t}\n \t}\n \n-\tdst_cache_reset(\u0026geneve-\u003ecfg.info.dst_cache);\n-\tmemcpy(\u0026geneve-\u003ecfg, cfg, sizeof(*cfg));\n+\tnew_cfg = geneve_config_alloc(cfg);\n+\tif (IS_ERR(new_cfg))\n+\t\treturn PTR_ERR(new_cfg);\n+\n+\trcu_assign_pointer(geneve-\u003ecfg, new_cfg);\n \n-\tif (geneve-\u003ecfg.inner_proto_inherit) {\n+\tif (cfg-\u003einner_proto_inherit) {\n \t\tdev-\u003eheader_ops = NULL;\n \t\tdev-\u003etype = ARPHRD_NONE;\n \t\tdev-\u003ehard_header_len = 0;\n@@ -2323,81 +2392,45 @@ static int geneve_newlink(struct net_device *dev,\n \treturn 0;\n }\n \n-/* Quiesces the geneve device data path for both TX and RX.\n- *\n- * On transmit geneve checks for non-NULL geneve_sock before it proceeds.\n- * So, if we set that socket to NULL under RCU and wait for synchronize_net()\n- * to complete for the existing set of in-flight packets to be transmitted,\n- * then we would have quiesced the transmit data path. All the future packets\n- * will get dropped until we unquiesce the data path.\n- *\n- * On receive geneve dereference the geneve_sock stashed in the socket. So,\n- * if we set that to NULL under RCU and wait for synchronize_net() to\n- * complete, then we would have quiesced the receive data path.\n+/* Update the device configuration under RTNL.\n+ * We use RCU swap to update the configuration atomically, so the data path\n+ * (both TX and RX) can continue running without interruption or packet loss.\n  */\n-static void geneve_quiesce(struct geneve_dev *geneve, struct geneve_sock **gs4,\n-\t\t\t   struct geneve_sock **gs6)\n-{\n-\t*gs4 = rtnl_dereference(geneve-\u003esock4);\n-\trcu_assign_pointer(geneve-\u003esock4, NULL);\n-\tif (*gs4)\n-\t\trcu_assign_sk_user_data((*gs4)-\u003esk, NULL);\n-#if IS_ENABLED(CONFIG_IPV6)\n-\t*gs6 = rtnl_dereference(geneve-\u003esock6);\n-\trcu_assign_pointer(geneve-\u003esock6, NULL);\n-\tif (*gs6)\n-\t\trcu_assign_sk_user_data((*gs6)-\u003esk, NULL);\n-#else\n-\t*gs6 = NULL;\n-#endif\n-\tsynchronize_net();\n-}\n-\n-/* Resumes the geneve device data path for both TX and RX. */\n-static void geneve_unquiesce(struct geneve_dev *geneve, struct geneve_sock *gs4,\n-\t\t\t     struct geneve_sock __maybe_unused *gs6)\n-{\n-\trcu_assign_pointer(geneve-\u003esock4, gs4);\n-\tif (gs4)\n-\t\trcu_assign_sk_user_data(gs4-\u003esk, gs4);\n-#if IS_ENABLED(CONFIG_IPV6)\n-\trcu_assign_pointer(geneve-\u003esock6, gs6);\n-\tif (gs6)\n-\t\trcu_assign_sk_user_data(gs6-\u003esk, gs6);\n-#endif\n-}\n-\n static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],\n \t\t\t     struct nlattr *data[],\n \t\t\t     struct netlink_ext_ack *extack)\n {\n \tstruct geneve_dev *geneve = netdev_priv(dev);\n-\tstruct geneve_sock *gs4, *gs6;\n-\tstruct geneve_config cfg;\n+\tstruct geneve_config *old_cfg = rtnl_dereference(geneve-\u003ecfg);\n+\tstruct geneve_config *cfg;\n \tint err;\n \n \t/* If the geneve device is configured for metadata (or externally\n \t * controlled, for example, OVS), then nothing can be changed.\n \t */\n-\tif (geneve-\u003ecfg.collect_md)\n+\tif (old_cfg-\u003ecollect_md)\n \t\treturn -EOPNOTSUPP;\n \n \t/* Start with the existing info. */\n-\tmemcpy(\u0026cfg, \u0026geneve-\u003ecfg, sizeof(cfg));\n-\terr = geneve_nl2info(tb, data, extack, \u0026cfg, true);\n+\tcfg = geneve_config_alloc(old_cfg);\n+\tif (IS_ERR(cfg))\n+\t\treturn PTR_ERR(cfg);\n+\n+\terr = geneve_nl2info(tb, data, extack, cfg, true);\n \tif (err)\n-\t\treturn err;\n+\t\tgoto err_free_cfg;\n \n-\tif (!geneve_dst_addr_equal(\u0026geneve-\u003ecfg.info, \u0026cfg.info)) {\n-\t\tdst_cache_reset(\u0026cfg.info.dst_cache);\n-\t\tgeneve_link_config(dev, \u0026cfg.info, tb);\n-\t}\n+\tif (!geneve_dst_addr_equal(\u0026old_cfg-\u003einfo, \u0026cfg-\u003einfo))\n+\t\tgeneve_link_config(dev, \u0026cfg-\u003einfo, tb);\n \n-\tgeneve_quiesce(geneve, \u0026gs4, \u0026gs6);\n-\tmemcpy(\u0026geneve-\u003ecfg, \u0026cfg, sizeof(cfg));\n-\tgeneve_unquiesce(geneve, gs4, gs6);\n+\trcu_assign_pointer(geneve-\u003ecfg, cfg);\n \n+\tcall_rcu_hurry(\u0026old_cfg-\u003ercu, geneve_config_free_rcu);\n \treturn 0;\n+\n+err_free_cfg:\n+\tgeneve_config_free(cfg);\n+\treturn err;\n }\n \n static void geneve_dellink(struct net_device *dev, struct list_head *head)\n@@ -2431,16 +2464,27 @@ static size_t geneve_get_size(const struct net_device *dev)\n \n static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)\n {\n-\tstruct geneve_dev *geneve = netdev_priv(dev);\n-\tstruct ip_tunnel_info *info = \u0026geneve-\u003ecfg.info;\n-\tbool ttl_inherit = geneve-\u003ecfg.ttl_inherit;\n-\tbool metadata = geneve-\u003ecfg.collect_md;\n-\tstruct ifla_geneve_port_range ports = {\n-\t\t.low\t= htons(geneve-\u003ecfg.port_min),\n-\t\t.high\t= htons(geneve-\u003ecfg.port_max),\n-\t};\n+\tconst struct geneve_dev *geneve = netdev_priv(dev);\n+\tstruct ifla_geneve_port_range ports;\n+\tconst struct geneve_config *cfg;\n+\tconst struct ip_tunnel_info *info;\n+\tbool ttl_inherit, metadata;\n \t__u8 tmp_vni[3];\n \t__u32 vni;\n+\tint err = 0;\n+\n+\trcu_read_lock();\n+\tcfg = rcu_dereference(geneve-\u003ecfg);\n+\tif (!cfg) {\n+\t\terr = -ENODEV;\n+\t\tgoto out;\n+\t}\n+\n+\tinfo = \u0026cfg-\u003einfo;\n+\tttl_inherit = cfg-\u003ettl_inherit;\n+\tmetadata = cfg-\u003ecollect_md;\n+\tports.low = htons(cfg-\u003eport_min);\n+\tports.high = htons(cfg-\u003eport_max);\n \n \ttunnel_id_to_vni(info-\u003ekey.tun_id, tmp_vni);\n \tvni = (tmp_vni[0] \u003c\u003c 16) | (tmp_vni[1] \u003c\u003c 8) | tmp_vni[2];\n@@ -2468,17 +2512,17 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)\n #endif\n \t}\n \n-\tif (!geneve-\u003ecfg.dualstack) {\n+\tif (!cfg-\u003edualstack) {\n \t\tif (ip_tunnel_info_af(info) == AF_INET) {\n \t\t\tif ((info-\u003ekey.u.ipv4.src ||\n-\t\t\t     geneve-\u003ecfg.collect_md) \u0026\u0026\n+\t\t\t     metadata) \u0026\u0026\n \t\t\t    nla_put_in_addr(skb, IFLA_GENEVE_LOCAL,\n \t\t\t\t\t    info-\u003ekey.u.ipv4.src))\n \t\t\t\tgoto nla_put_failure;\n #if IS_ENABLED(CONFIG_IPV6)\n \t\t} else {\n \t\t\tif ((!ipv6_addr_any(\u0026info-\u003ekey.u.ipv6.src) ||\n-\t\t\t     geneve-\u003ecfg.collect_md) \u0026\u0026\n+\t\t\t     metadata) \u0026\u0026\n \t\t\t    nla_put_in6_addr(skb, IFLA_GENEVE_LOCAL6,\n \t\t\t\t\t     \u0026info-\u003ekey.u.ipv6.src))\n \t\t\t\tgoto nla_put_failure;\n@@ -2491,7 +2535,7 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)\n \t    nla_put_be32(skb, IFLA_GENEVE_LABEL, info-\u003ekey.label))\n \t\tgoto nla_put_failure;\n \n-\tif (nla_put_u8(skb, IFLA_GENEVE_DF, geneve-\u003ecfg.df))\n+\tif (nla_put_u8(skb, IFLA_GENEVE_DF, cfg-\u003edf))\n \t\tgoto nla_put_failure;\n \n \tif (nla_put_be16(skb, IFLA_GENEVE_PORT, info-\u003ekey.tp_dst))\n@@ -2502,28 +2546,31 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)\n \n #if IS_ENABLED(CONFIG_IPV6)\n \tif (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,\n-\t\t       !geneve-\u003ecfg.use_udp6_rx_checksums))\n+\t\t       !cfg-\u003euse_udp6_rx_checksums))\n \t\tgoto nla_put_failure;\n #endif\n \n \tif (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))\n \t\tgoto nla_put_failure;\n \n-\tif (geneve-\u003ecfg.inner_proto_inherit \u0026\u0026\n+\tif (cfg-\u003einner_proto_inherit \u0026\u0026\n \t    nla_put_flag(skb, IFLA_GENEVE_INNER_PROTO_INHERIT))\n \t\tgoto nla_put_failure;\n \n \tif (nla_put(skb, IFLA_GENEVE_PORT_RANGE, sizeof(ports), \u0026ports))\n \t\tgoto nla_put_failure;\n \n-\tif (geneve-\u003ecfg.gro_hint \u0026\u0026\n+\tif (cfg-\u003egro_hint \u0026\u0026\n \t    nla_put_flag(skb, IFLA_GENEVE_GRO_HINT))\n \t\tgoto nla_put_failure;\n \n-\treturn 0;\n+out:\n+\trcu_read_unlock();\n+\treturn err;\n \n nla_put_failure:\n-\treturn -EMSGSIZE;\n+\terr = -EMSGSIZE;\n+\tgoto out;\n }\n \n static struct rtnl_link_ops geneve_link_ops __read_mostly = {\n@@ -2671,6 +2718,7 @@ static void __exit geneve_cleanup_module(void)\n \trtnl_link_unregister(\u0026geneve_link_ops);\n \tunregister_netdevice_notifier(\u0026geneve_notifier_block);\n \tunregister_pernet_subsys(\u0026geneve_net_ops);\n+\trcu_barrier();\n }\n module_exit(geneve_cleanup_module);\n \n"
}

2/1 2026/07/07 23:53 agent patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
{
  "EnableConfigs": [
    "GENEVE"
  ],
  "FocusSymbols": [
    "geneve_changelink",
    "geneve_configure",
    "geneve_fill_info",
    "geneve_config_alloc",
    "geneve_free_dev"
  ],
  "Reasoning": "The patch refactors the GENEVE driver to use RCU for its configuration (`struct geneve_config`), replacing the previous synchronous `geneve_quiesce`/`geneve_unquiesce` mechanism. This is a functional change affecting how configuration updates are handled concurrently with the data path. Fuzzing should focus on the netlink control path functions that allocate, update, and free the configuration.",
  "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 3a1d0941dbc90d639a922cad60215b93775b954e
Author: syz-cluster <triage@syzkaller.com>
Date:   Tue Jul 7 23:53:29 2026 +0000

    syz-cluster: applied patch under review

diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 396e1a113cd49e..17bd3543d587a9 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -82,6 +82,7 @@ struct geneve_config {
 	u16			port_min;
 	u16			port_max;
 
+	struct rcu_head		rcu;
 	/* Must be last --ends in a flexible-array member. */
 	struct ip_tunnel_info	info;
 };
@@ -100,7 +101,7 @@ struct geneve_dev {
 #endif
 	struct list_head   next;	/* geneve's per namespace list */
 	struct gro_cells   gro_cells;
-	struct geneve_config cfg;
+	struct geneve_config __rcu *cfg;
 };
 
 struct geneve_sock {
@@ -182,8 +183,10 @@ static struct geneve_dev *geneve_lookup(struct geneve_sock *gs,
 	hash = geneve_net_vni_hash(vni);
 	vni_list_head = &gs->vni_list[hash];
 	hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
-		if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) &&
-		    addr == node->geneve->cfg.info.key.u.ipv4.dst)
+		const struct geneve_config *cfg = rcu_dereference(node->geneve->cfg);
+
+		if (eq_tun_id_and_vni((u8 *)&cfg->info.key.tun_id, vni) &&
+		    addr == cfg->info.key.u.ipv4.dst)
 			return node->geneve;
 	}
 	return NULL;
@@ -201,8 +204,10 @@ static struct geneve_dev *geneve6_lookup(struct geneve_sock *gs,
 	hash = geneve_net_vni_hash(vni);
 	vni_list_head = &gs->vni_list[hash];
 	hlist_for_each_entry_rcu(node, vni_list_head, hlist) {
-		if (eq_tun_id_and_vni((u8 *)&node->geneve->cfg.info.key.tun_id, vni) &&
-		    ipv6_addr_equal(&addr6, &node->geneve->cfg.info.key.u.ipv6.dst))
+		const struct geneve_config *cfg = rcu_dereference(node->geneve->cfg);
+
+		if (eq_tun_id_and_vni((u8 *)&cfg->info.key.tun_id, vni) &&
+		    ipv6_addr_equal(&addr6, &cfg->info.key.u.ipv6.dst))
 			return node->geneve;
 	}
 	return NULL;
@@ -386,11 +391,6 @@ static int geneve_init(struct net_device *dev)
 	if (err)
 		return err;
 
-	err = dst_cache_init(&geneve->cfg.info.dst_cache, GFP_KERNEL);
-	if (err) {
-		gro_cells_destroy(&geneve->gro_cells);
-		return err;
-	}
 	netdev_lockdep_set_classes(dev);
 	return 0;
 }
@@ -399,7 +399,6 @@ static void geneve_uninit(struct net_device *dev)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
 
-	dst_cache_destroy(&geneve->cfg.info.dst_cache);
 	gro_cells_destroy(&geneve->gro_cells);
 }
 
@@ -650,6 +649,7 @@ static int geneve_post_decap_hint(const struct sock *sk, struct sk_buff *skb,
 /* Callback from net/ipv4/udp.c to receive packets */
 static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
+	const struct geneve_config *cfg;
 	struct genevehdr *geneveh;
 	struct geneve_dev *geneve;
 	struct geneve_sock *gs;
@@ -675,8 +675,9 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 
 	inner_proto = geneveh->proto_type;
 
-	if (unlikely((!geneve->cfg.inner_proto_inherit &&
-		      inner_proto != htons(ETH_P_TEB)))) {
+	cfg = rcu_dereference(geneve->cfg);
+	if (unlikely(!cfg || (!cfg->inner_proto_inherit &&
+			      inner_proto != htons(ETH_P_TEB)))) {
 		dev_dstats_rx_dropped(geneve->dev);
 		goto drop;
 	}
@@ -762,9 +763,10 @@ static int geneve_udp_encap_err_lookup(struct sock *sk, struct sk_buff *skb)
 }
 
 static struct sock *geneve_create_sock(struct net *net,
-				       struct geneve_dev *geneve, bool ipv6)
+				       struct geneve_dev *geneve,
+				       const struct geneve_config *cfg, bool ipv6)
 {
-	struct ip_tunnel_info *info = &geneve->cfg.info;
+	const struct ip_tunnel_info *info = &cfg->info;
 	struct udp_port_cfg udp_conf;
 	struct socket *sock;
 	int err;
@@ -775,7 +777,7 @@ static struct sock *geneve_create_sock(struct net *net,
 	if (ipv6) {
 		udp_conf.family = AF_INET6;
 		udp_conf.ipv6_v6only = 1;
-		udp_conf.use_udp6_rx_checksums = geneve->cfg.use_udp6_rx_checksums;
+		udp_conf.use_udp6_rx_checksums = cfg->use_udp6_rx_checksums;
 		udp_conf.local_ip6 = info->key.u.ipv6.src;
 	} else
 #endif
@@ -991,7 +993,8 @@ static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb,
 
 /* Create new listen socket if needed */
 static struct geneve_sock *geneve_socket_create(struct net *net,
-						struct geneve_dev *geneve, bool ipv6)
+						struct geneve_dev *geneve,
+						const struct geneve_config *cfg, bool ipv6)
 {
 	struct geneve_net *gn = net_generic(net, geneve_net_id);
 	struct udp_tunnel_sock_cfg tunnel_cfg;
@@ -1003,7 +1006,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net,
 	if (!gs)
 		return ERR_PTR(-ENOMEM);
 
-	sk = geneve_create_sock(net, geneve, ipv6);
+	sk = geneve_create_sock(net, geneve, cfg, ipv6);
 	if (IS_ERR(sk)) {
 		kfree(gs);
 		return ERR_CAST(sk);
@@ -1060,12 +1063,13 @@ static void geneve_sock_release(struct geneve_dev *geneve)
 }
 
 static struct geneve_sock *geneve_find_sock(struct net *net,
-					    struct geneve_dev *geneve, bool ipv6)
+					    struct geneve_dev *geneve,
+					    const struct geneve_config *cfg, bool ipv6)
 {
 	struct geneve_net *gn = net_generic(net, geneve_net_id);
-	struct ip_tunnel_info *info = &geneve->cfg.info;
+	const struct ip_tunnel_info *info = &cfg->info;
 	sa_family_t family = ipv6 ? AF_INET6 : AF_INET;
-	bool gro_hint = geneve->cfg.gro_hint;
+	bool gro_hint = cfg->gro_hint;
 	__be16 dst_port = info->key.tp_dst;
 	struct geneve_sock *gs;
 
@@ -1095,7 +1099,8 @@ static struct geneve_sock *geneve_find_sock(struct net *net,
 	return NULL;
 }
 
-static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
+static int geneve_sock_add(struct geneve_dev *geneve,
+			   const struct geneve_config *cfg, bool ipv6)
 {
 	struct net *net = geneve->net;
 	struct geneve_dev_node *node;
@@ -1103,19 +1108,19 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
 	__u8 vni[3];
 	__u32 hash;
 
-	gs = geneve_find_sock(net, geneve, ipv6);
+	gs = geneve_find_sock(net, geneve, cfg, ipv6);
 	if (gs) {
 		gs->refcnt++;
 		goto out;
 	}
 
-	gs = geneve_socket_create(net, geneve, ipv6);
+	gs = geneve_socket_create(net, geneve, cfg, ipv6);
 	if (IS_ERR(gs))
 		return PTR_ERR(gs);
 
 out:
-	gs->collect_md = geneve->cfg.collect_md;
-	gs->gro_hint = geneve->cfg.gro_hint;
+	gs->collect_md = cfg->collect_md;
+	gs->gro_hint = cfg->gro_hint;
 #if IS_ENABLED(CONFIG_IPV6)
 	if (ipv6) {
 		rcu_assign_pointer(geneve->sock6, gs);
@@ -1128,7 +1133,7 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
 	}
 	node->geneve = geneve;
 
-	tunnel_id_to_vni(geneve->cfg.info.key.tun_id, vni);
+	tunnel_id_to_vni(cfg->info.key.tun_id, vni);
 	hash = geneve_net_vni_hash(vni);
 	hlist_add_head_rcu(&node->hlist, &gs->vni_list[hash]);
 	return 0;
@@ -1137,21 +1142,23 @@ static int geneve_sock_add(struct geneve_dev *geneve, bool ipv6)
 static int geneve_open(struct net_device *dev)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
-	bool dualstack = geneve->cfg.dualstack;
-	bool ipv4, ipv6;
+	const struct geneve_config *cfg;
+	bool ipv4, ipv6, dualstack;
 	int ret = 0;
 
-	ipv6 = geneve->cfg.info.mode & IP_TUNNEL_INFO_IPV6 || dualstack;
+	cfg = rtnl_dereference(geneve->cfg);
+	dualstack = cfg->dualstack;
+	ipv6 = cfg->info.mode & IP_TUNNEL_INFO_IPV6 || dualstack;
 	ipv4 = !ipv6 || dualstack;
 #if IS_ENABLED(CONFIG_IPV6)
 	if (ipv6) {
-		ret = geneve_sock_add(geneve, true);
+		ret = geneve_sock_add(geneve, cfg, true);
 		if (ret < 0 && ret != -EAFNOSUPPORT)
 			ipv4 = false;
 	}
 #endif
 	if (ipv4)
-		ret = geneve_sock_add(geneve, false);
+		ret = geneve_sock_add(geneve, cfg, false);
 	if (ret < 0)
 		geneve_sock_release(geneve);
 
@@ -1189,6 +1196,7 @@ static void geneve_build_header(struct genevehdr *geneveh,
 }
 
 static int geneve_build_gro_hint_opt(const struct geneve_dev *geneve,
+				     const struct geneve_config *cfg,
 				     struct sk_buff *skb)
 {
 	struct geneve_skb_cb *cb = GENEVE_SKB_CB(skb);
@@ -1201,7 +1209,7 @@ static int geneve_build_gro_hint_opt(const struct geneve_dev *geneve,
 	cb->gro_hint_len = 0;
 
 	/* Try to add the GRO hint only in case of double encap. */
-	if (!geneve->cfg.gro_hint || !skb->encapsulation)
+	if (!cfg->gro_hint || !skb->encapsulation)
 		return 0;
 
 	/*
@@ -1262,10 +1270,11 @@ static void geneve_put_gro_hint_opt(struct genevehdr *gnvh, int opt_size,
 
 static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
 			    const struct ip_tunnel_info *info,
-			    const struct geneve_dev *geneve, int ip_hdr_len)
+			    const struct geneve_dev *geneve,
+			    const struct geneve_config *cfg, int ip_hdr_len)
 {
 	bool udp_sum = test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags);
-	bool inner_proto_inherit = geneve->cfg.inner_proto_inherit;
+	bool inner_proto_inherit = cfg->inner_proto_inherit;
 	bool xnet = !net_eq(geneve->net, dev_net(geneve->dev));
 	struct geneve_skb_cb *cb = GENEVE_SKB_CB(skb);
 	struct genevehdr *gnvh;
@@ -1306,14 +1315,14 @@ static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
 }
 
 static u8 geneve_get_dsfield(struct sk_buff *skb, struct net_device *dev,
+			     const struct geneve_config *cfg,
 			     const struct ip_tunnel_info *info,
 			     bool *use_cache)
 {
-	struct geneve_dev *geneve = netdev_priv(dev);
 	u8 dsfield;
 
 	dsfield = info->key.tos;
-	if (dsfield == 1 && !geneve->cfg.collect_md) {
+	if (cfg && dsfield == 1 && !cfg->collect_md) {
 		dsfield = ip_tunnel_get_dsfield(ip_hdr(skb), skb);
 		*use_cache = false;
 	}
@@ -1323,6 +1332,7 @@ static u8 geneve_get_dsfield(struct sk_buff *skb, struct net_device *dev,
 
 static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 			   struct geneve_dev *geneve,
+			   const struct geneve_config *cfg,
 			   const struct ip_tunnel_info *info)
 {
 	struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
@@ -1335,35 +1345,35 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	__be16 sport;
 	int err;
 
-	if (skb_vlan_inet_prepare(skb, geneve->cfg.inner_proto_inherit))
+	if (skb_vlan_inet_prepare(skb, cfg->inner_proto_inherit))
 		return -EINVAL;
 
 	if (!gs4)
 		return -EIO;
 
 	use_cache = ip_tunnel_dst_cache_usable(skb, info);
-	tos = geneve_get_dsfield(skb, dev, info, &use_cache);
+	tos = geneve_get_dsfield(skb, dev, cfg, info, &use_cache);
 	sport = udp_flow_src_port(geneve->net, skb,
-				  geneve->cfg.port_min,
-				  geneve->cfg.port_max, true);
+				  cfg->port_min,
+				  cfg->port_max, true);
 
 	rt = udp_tunnel_dst_lookup(skb, dev, geneve->net, 0, &saddr,
 				   &info->key,
-				   sport, geneve->cfg.info.key.tp_dst, tos,
+				   sport, cfg->info.key.tp_dst, tos,
 				   use_cache ?
 				   (struct dst_cache *)&info->dst_cache : NULL);
 	if (IS_ERR(rt))
 		return PTR_ERR(rt);
 
-	if (geneve->cfg.info.key.u.ipv4.src &&
-	    saddr != geneve->cfg.info.key.u.ipv4.src) {
+	if (cfg->info.key.u.ipv4.src &&
+	    saddr != cfg->info.key.u.ipv4.src) {
 		dst_release(&rt->dst);
 		return -EADDRNOTAVAIL;
 	}
 
 	err = skb_tunnel_check_pmtu(skb, &rt->dst,
 				    GENEVE_IPV4_HLEN + info->options_len +
-				    geneve_build_gro_hint_opt(geneve, skb),
+				    geneve_build_gro_hint_opt(geneve, cfg, skb),
 				    netif_is_any_bridge_port(dev));
 	if (err < 0) {
 		dst_release(&rt->dst);
@@ -1397,21 +1407,21 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	}
 
 	tos = ip_tunnel_ecn_encap(tos, ip_hdr(skb), skb);
-	if (geneve->cfg.collect_md) {
+	if (cfg->collect_md) {
 		ttl = key->ttl;
 
 		df = test_bit(IP_TUNNEL_DONT_FRAGMENT_BIT, key->tun_flags) ?
 		     htons(IP_DF) : 0;
 	} else {
-		if (geneve->cfg.ttl_inherit)
+		if (cfg->ttl_inherit)
 			ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
 		else
 			ttl = key->ttl;
 		ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
 
-		if (geneve->cfg.df == GENEVE_DF_SET) {
+		if (cfg->df == GENEVE_DF_SET) {
 			df = htons(IP_DF);
-		} else if (geneve->cfg.df == GENEVE_DF_INHERIT) {
+		} else if (cfg->df == GENEVE_DF_INHERIT) {
 			struct ethhdr *eth = skb_eth_hdr(skb);
 
 			if (ntohs(eth->h_proto) == ETH_P_IPV6) {
@@ -1425,13 +1435,13 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 		}
 	}
 
-	err = geneve_build_skb(&rt->dst, skb, info, geneve,
+	err = geneve_build_skb(&rt->dst, skb, info, geneve, cfg,
 			       sizeof(struct iphdr));
 	if (unlikely(err))
 		return err;
 
 	udp_tunnel_xmit_skb(rt, gs4->sk, skb, saddr, info->key.u.ipv4.dst,
-			    tos, ttl, df, sport, geneve->cfg.info.key.tp_dst,
+			    tos, ttl, df, sport, cfg->info.key.tp_dst,
 			    !net_eq(geneve->net, dev_net(geneve->dev)),
 			    !test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags),
 			    0);
@@ -1441,6 +1451,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 #if IS_ENABLED(CONFIG_IPV6)
 static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 			    struct geneve_dev *geneve,
+			    const struct geneve_config *cfg,
 			    const struct ip_tunnel_info *info)
 {
 	struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
@@ -1452,35 +1463,35 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	__be16 sport;
 	int err;
 
-	if (skb_vlan_inet_prepare(skb, geneve->cfg.inner_proto_inherit))
+	if (skb_vlan_inet_prepare(skb, cfg->inner_proto_inherit))
 		return -EINVAL;
 
 	if (!gs6)
 		return -EIO;
 
 	use_cache = ip_tunnel_dst_cache_usable(skb, info);
-	prio = geneve_get_dsfield(skb, dev, info, &use_cache);
+	prio = geneve_get_dsfield(skb, dev, cfg, info, &use_cache);
 	sport = udp_flow_src_port(geneve->net, skb,
-				  geneve->cfg.port_min,
-				  geneve->cfg.port_max, true);
+				  cfg->port_min,
+				  cfg->port_max, true);
 
 	dst = udp_tunnel6_dst_lookup(skb, dev, geneve->net, gs6->sk, 0,
 				     &saddr, key, sport,
-				     geneve->cfg.info.key.tp_dst, prio,
+				     cfg->info.key.tp_dst, prio,
 				     use_cache ?
 				     (struct dst_cache *)&info->dst_cache : NULL);
 	if (IS_ERR(dst))
 		return PTR_ERR(dst);
 
-	if (!ipv6_addr_any(&geneve->cfg.info.key.u.ipv6.src) &&
-	    !ipv6_addr_equal(&saddr, &geneve->cfg.info.key.u.ipv6.src)) {
+	if (!ipv6_addr_any(&cfg->info.key.u.ipv6.src) &&
+	    !ipv6_addr_equal(&saddr, &cfg->info.key.u.ipv6.src)) {
 		dst_release(dst);
 		return -EADDRNOTAVAIL;
 	}
 
 	err = skb_tunnel_check_pmtu(skb, dst,
 				    GENEVE_IPV6_HLEN + info->options_len +
-				    geneve_build_gro_hint_opt(geneve, skb),
+				    geneve_build_gro_hint_opt(geneve, cfg, skb),
 				    netif_is_any_bridge_port(dev));
 	if (err < 0) {
 		dst_release(dst);
@@ -1513,22 +1524,22 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	}
 
 	prio = ip_tunnel_ecn_encap(prio, ip_hdr(skb), skb);
-	if (geneve->cfg.collect_md) {
+	if (cfg->collect_md) {
 		ttl = key->ttl;
 	} else {
-		if (geneve->cfg.ttl_inherit)
+		if (cfg->ttl_inherit)
 			ttl = ip_tunnel_get_ttl(ip_hdr(skb), skb);
 		else
 			ttl = key->ttl;
 		ttl = ttl ? : ip6_dst_hoplimit(dst);
 	}
-	err = geneve_build_skb(dst, skb, info, geneve, sizeof(struct ipv6hdr));
+	err = geneve_build_skb(dst, skb, info, geneve, cfg, sizeof(struct ipv6hdr));
 	if (unlikely(err))
 		return err;
 
 	udp_tunnel6_xmit_skb(dst, gs6->sk, skb, dev,
 			     &saddr, &key->u.ipv6.dst, prio, ttl,
-			     info->key.label, sport, geneve->cfg.info.key.tp_dst,
+			     info->key.label, sport, cfg->info.key.tp_dst,
 			     !test_bit(IP_TUNNEL_CSUM_BIT,
 				       info->key.tun_flags),
 			     0);
@@ -1539,28 +1550,31 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
-	struct ip_tunnel_info *info = NULL;
+	const struct ip_tunnel_info *info = NULL;
+	const struct geneve_config *cfg;
 	int err;
 
-	if (geneve->cfg.collect_md) {
+	rcu_read_lock();
+	cfg = rcu_dereference(geneve->cfg);
+	if (cfg->collect_md) {
 		info = skb_tunnel_info(skb);
 		if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) {
 			netdev_dbg(dev, "no tunnel metadata\n");
 			dev_kfree_skb(skb);
 			dev_dstats_tx_dropped(dev);
+			rcu_read_unlock();
 			return NETDEV_TX_OK;
 		}
 	} else {
-		info = &geneve->cfg.info;
+		info = &cfg->info;
 	}
 
-	rcu_read_lock();
 #if IS_ENABLED(CONFIG_IPV6)
 	if (info->mode & IP_TUNNEL_INFO_IPV6)
-		err = geneve6_xmit_skb(skb, dev, geneve, info);
+		err = geneve6_xmit_skb(skb, dev, geneve, cfg, info);
 	else
 #endif
-		err = geneve_xmit_skb(skb, dev, geneve, info);
+		err = geneve_xmit_skb(skb, dev, geneve, cfg, info);
 	rcu_read_unlock();
 
 	if (likely(!err))
@@ -1593,8 +1607,13 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 {
 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
 	struct geneve_dev *geneve = netdev_priv(dev);
+	const struct geneve_config *cfg;
 	__be16 sport;
 
+	cfg = rcu_dereference(geneve->cfg);
+	if (unlikely(!cfg))
+		return -ENODEV;
+
 	if (ip_tunnel_info_af(info) == AF_INET) {
 		struct rtable *rt;
 		struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
@@ -1606,14 +1625,14 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 			return -EIO;
 
 		use_cache = ip_tunnel_dst_cache_usable(skb, info);
-		tos = geneve_get_dsfield(skb, dev, info, &use_cache);
+		tos = geneve_get_dsfield(skb, dev, cfg, info, &use_cache);
 		sport = udp_flow_src_port(geneve->net, skb,
-					  geneve->cfg.port_min,
-					  geneve->cfg.port_max, true);
+					  cfg->port_min,
+					  cfg->port_max, true);
 
 		rt = udp_tunnel_dst_lookup(skb, dev, geneve->net, 0, &saddr,
 					   &info->key,
-					   sport, geneve->cfg.info.key.tp_dst,
+					   sport, cfg->info.key.tp_dst,
 					   tos,
 					   use_cache ? &info->dst_cache : NULL);
 		if (IS_ERR(rt))
@@ -1633,14 +1652,14 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 			return -EIO;
 
 		use_cache = ip_tunnel_dst_cache_usable(skb, info);
-		prio = geneve_get_dsfield(skb, dev, info, &use_cache);
+		prio = geneve_get_dsfield(skb, dev, cfg, info, &use_cache);
 		sport = udp_flow_src_port(geneve->net, skb,
-					  geneve->cfg.port_min,
-					  geneve->cfg.port_max, true);
+					  cfg->port_min,
+					  cfg->port_max, true);
 
 		dst = udp_tunnel6_dst_lookup(skb, dev, geneve->net, gs6->sk, 0,
 					     &saddr, &info->key, sport,
-					     geneve->cfg.info.key.tp_dst, prio,
+					     cfg->info.key.tp_dst, prio,
 					     use_cache ? &info->dst_cache : NULL);
 		if (IS_ERR(dst))
 			return PTR_ERR(dst);
@@ -1653,7 +1672,7 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 	}
 
 	info->key.tp_src = sport;
-	info->key.tp_dst = geneve->cfg.info.key.tp_dst;
+	info->key.tp_dst = cfg->info.key.tp_dst;
 	return 0;
 }
 
@@ -1709,7 +1728,50 @@ static void geneve_offload_rx_ports(struct net_device *dev, bool push)
 	}
 }
 
+static struct geneve_config *geneve_config_alloc(const struct geneve_config *src)
+{
+	struct geneve_config *cfg;
+	int err;
+
+	cfg = kmemdup(src, sizeof(*src), GFP_KERNEL);
+	if (!cfg)
+		return ERR_PTR(-ENOMEM);
+
+	cfg->info.dst_cache.cache = NULL;
+	err = dst_cache_init(&cfg->info.dst_cache, GFP_KERNEL);
+	if (err) {
+		kfree(cfg);
+		return ERR_PTR(err);
+	}
+
+	return cfg;
+}
+
+static void geneve_config_free(struct geneve_config *cfg)
+{
+	if (cfg) {
+		dst_cache_destroy(&cfg->info.dst_cache);
+		kfree(cfg);
+	}
+}
+
+static void geneve_config_free_rcu(struct rcu_head *head)
+{
+	struct geneve_config *cfg = container_of(head, struct geneve_config, rcu);
+
+	geneve_config_free(cfg);
+}
+
 /* Initialize the device structure. */
+static void geneve_free_dev(struct net_device *dev)
+{
+	struct geneve_dev *geneve = netdev_priv(dev);
+	struct geneve_config *cfg = rcu_dereference_protected(geneve->cfg, 1);
+
+	geneve_config_free(cfg);
+	RCU_INIT_POINTER(geneve->cfg, NULL);
+}
+
 static void geneve_setup(struct net_device *dev)
 {
 	ether_setup(dev);
@@ -1717,6 +1779,7 @@ static void geneve_setup(struct net_device *dev)
 	dev->netdev_ops = &geneve_netdev_ops;
 	dev->ethtool_ops = &geneve_ethtool_ops;
 	dev->needs_free_netdev = true;
+	dev->priv_destructor = geneve_free_dev;
 
 	SET_NETDEV_DEVTYPE(dev, &geneve_type);
 
@@ -1878,15 +1941,17 @@ static struct geneve_dev *geneve_find_dev(struct geneve_net *gn,
 	*tun_on_same_port = false;
 	*tun_collect_md = false;
 	list_for_each_entry(geneve, &gn->geneve_list, next) {
-		if (info->key.tp_dst == geneve->cfg.info.key.tp_dst &&
-		    (cfg->dualstack || geneve->cfg.dualstack ||
-		     geneve_saddr_conflict(info, &geneve->cfg.info))) {
-			*tun_collect_md |= geneve->cfg.collect_md;
+		const struct geneve_config *gcfg = rtnl_dereference(geneve->cfg);
+
+		if (info->key.tp_dst == gcfg->info.key.tp_dst &&
+		    (cfg->dualstack || gcfg->dualstack ||
+		     geneve_saddr_conflict(info, &gcfg->info))) {
+			*tun_collect_md |= gcfg->collect_md;
 			*tun_on_same_port = true;
 		}
-		if (info->key.tun_id == geneve->cfg.info.key.tun_id &&
-		    info->key.tp_dst == geneve->cfg.info.key.tp_dst &&
-		    !memcmp(&info->key.u, &geneve->cfg.info.key.u, sizeof(info->key.u)))
+		if (info->key.tun_id == gcfg->info.key.tun_id &&
+		    info->key.tp_dst == gcfg->info.key.tp_dst &&
+		    !memcmp(&info->key.u, &gcfg->info.key.u, sizeof(info->key.u)))
 			t = geneve;
 	}
 	return t;
@@ -1922,6 +1987,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
 	struct geneve_dev *t, *geneve = netdev_priv(dev);
 	const struct ip_tunnel_info *info = &cfg->info;
 	bool tun_collect_md, tun_on_same_port;
+	struct geneve_config *new_cfg;
 	int err, encap_len;
 
 	if (cfg->collect_md && !is_tnl_info_zero(info)) {
@@ -1962,10 +2028,13 @@ static int geneve_configure(struct net *net, struct net_device *dev,
 		}
 	}
 
-	dst_cache_reset(&geneve->cfg.info.dst_cache);
-	memcpy(&geneve->cfg, cfg, sizeof(*cfg));
+	new_cfg = geneve_config_alloc(cfg);
+	if (IS_ERR(new_cfg))
+		return PTR_ERR(new_cfg);
+
+	rcu_assign_pointer(geneve->cfg, new_cfg);
 
-	if (geneve->cfg.inner_proto_inherit) {
+	if (cfg->inner_proto_inherit) {
 		dev->header_ops = NULL;
 		dev->type = ARPHRD_NONE;
 		dev->hard_header_len = 0;
@@ -2323,81 +2392,45 @@ static int geneve_newlink(struct net_device *dev,
 	return 0;
 }
 
-/* Quiesces the geneve device data path for both TX and RX.
- *
- * On transmit geneve checks for non-NULL geneve_sock before it proceeds.
- * So, if we set that socket to NULL under RCU and wait for synchronize_net()
- * to complete for the existing set of in-flight packets to be transmitted,
- * then we would have quiesced the transmit data path. All the future packets
- * will get dropped until we unquiesce the data path.
- *
- * On receive geneve dereference the geneve_sock stashed in the socket. So,
- * if we set that to NULL under RCU and wait for synchronize_net() to
- * complete, then we would have quiesced the receive data path.
+/* Update the device configuration under RTNL.
+ * We use RCU swap to update the configuration atomically, so the data path
+ * (both TX and RX) can continue running without interruption or packet loss.
  */
-static void geneve_quiesce(struct geneve_dev *geneve, struct geneve_sock **gs4,
-			   struct geneve_sock **gs6)
-{
-	*gs4 = rtnl_dereference(geneve->sock4);
-	rcu_assign_pointer(geneve->sock4, NULL);
-	if (*gs4)
-		rcu_assign_sk_user_data((*gs4)->sk, NULL);
-#if IS_ENABLED(CONFIG_IPV6)
-	*gs6 = rtnl_dereference(geneve->sock6);
-	rcu_assign_pointer(geneve->sock6, NULL);
-	if (*gs6)
-		rcu_assign_sk_user_data((*gs6)->sk, NULL);
-#else
-	*gs6 = NULL;
-#endif
-	synchronize_net();
-}
-
-/* Resumes the geneve device data path for both TX and RX. */
-static void geneve_unquiesce(struct geneve_dev *geneve, struct geneve_sock *gs4,
-			     struct geneve_sock __maybe_unused *gs6)
-{
-	rcu_assign_pointer(geneve->sock4, gs4);
-	if (gs4)
-		rcu_assign_sk_user_data(gs4->sk, gs4);
-#if IS_ENABLED(CONFIG_IPV6)
-	rcu_assign_pointer(geneve->sock6, gs6);
-	if (gs6)
-		rcu_assign_sk_user_data(gs6->sk, gs6);
-#endif
-}
-
 static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],
 			     struct nlattr *data[],
 			     struct netlink_ext_ack *extack)
 {
 	struct geneve_dev *geneve = netdev_priv(dev);
-	struct geneve_sock *gs4, *gs6;
-	struct geneve_config cfg;
+	struct geneve_config *old_cfg = rtnl_dereference(geneve->cfg);
+	struct geneve_config *cfg;
 	int err;
 
 	/* If the geneve device is configured for metadata (or externally
 	 * controlled, for example, OVS), then nothing can be changed.
 	 */
-	if (geneve->cfg.collect_md)
+	if (old_cfg->collect_md)
 		return -EOPNOTSUPP;
 
 	/* Start with the existing info. */
-	memcpy(&cfg, &geneve->cfg, sizeof(cfg));
-	err = geneve_nl2info(tb, data, extack, &cfg, true);
+	cfg = geneve_config_alloc(old_cfg);
+	if (IS_ERR(cfg))
+		return PTR_ERR(cfg);
+
+	err = geneve_nl2info(tb, data, extack, cfg, true);
 	if (err)
-		return err;
+		goto err_free_cfg;
 
-	if (!geneve_dst_addr_equal(&geneve->cfg.info, &cfg.info)) {
-		dst_cache_reset(&cfg.info.dst_cache);
-		geneve_link_config(dev, &cfg.info, tb);
-	}
+	if (!geneve_dst_addr_equal(&old_cfg->info, &cfg->info))
+		geneve_link_config(dev, &cfg->info, tb);
 
-	geneve_quiesce(geneve, &gs4, &gs6);
-	memcpy(&geneve->cfg, &cfg, sizeof(cfg));
-	geneve_unquiesce(geneve, gs4, gs6);
+	rcu_assign_pointer(geneve->cfg, cfg);
 
+	call_rcu_hurry(&old_cfg->rcu, geneve_config_free_rcu);
 	return 0;
+
+err_free_cfg:
+	geneve_config_free(cfg);
+	return err;
 }
 
 static void geneve_dellink(struct net_device *dev, struct list_head *head)
@@ -2431,16 +2464,27 @@ static size_t geneve_get_size(const struct net_device *dev)
 
 static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
 {
-	struct geneve_dev *geneve = netdev_priv(dev);
-	struct ip_tunnel_info *info = &geneve->cfg.info;
-	bool ttl_inherit = geneve->cfg.ttl_inherit;
-	bool metadata = geneve->cfg.collect_md;
-	struct ifla_geneve_port_range ports = {
-		.low	= htons(geneve->cfg.port_min),
-		.high	= htons(geneve->cfg.port_max),
-	};
+	const struct geneve_dev *geneve = netdev_priv(dev);
+	struct ifla_geneve_port_range ports;
+	const struct geneve_config *cfg;
+	const struct ip_tunnel_info *info;
+	bool ttl_inherit, metadata;
 	__u8 tmp_vni[3];
 	__u32 vni;
+	int err = 0;
+
+	rcu_read_lock();
+	cfg = rcu_dereference(geneve->cfg);
+	if (!cfg) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	info = &cfg->info;
+	ttl_inherit = cfg->ttl_inherit;
+	metadata = cfg->collect_md;
+	ports.low = htons(cfg->port_min);
+	ports.high = htons(cfg->port_max);
 
 	tunnel_id_to_vni(info->key.tun_id, tmp_vni);
 	vni = (tmp_vni[0] << 16) | (tmp_vni[1] << 8) | tmp_vni[2];
@@ -2468,17 +2512,17 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
 #endif
 	}
 
-	if (!geneve->cfg.dualstack) {
+	if (!cfg->dualstack) {
 		if (ip_tunnel_info_af(info) == AF_INET) {
 			if ((info->key.u.ipv4.src ||
-			     geneve->cfg.collect_md) &&
+			     metadata) &&
 			    nla_put_in_addr(skb, IFLA_GENEVE_LOCAL,
 					    info->key.u.ipv4.src))
 				goto nla_put_failure;
 #if IS_ENABLED(CONFIG_IPV6)
 		} else {
 			if ((!ipv6_addr_any(&info->key.u.ipv6.src) ||
-			     geneve->cfg.collect_md) &&
+			     metadata) &&
 			    nla_put_in6_addr(skb, IFLA_GENEVE_LOCAL6,
 					     &info->key.u.ipv6.src))
 				goto nla_put_failure;
@@ -2491,7 +2535,7 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
 	    nla_put_be32(skb, IFLA_GENEVE_LABEL, info->key.label))
 		goto nla_put_failure;
 
-	if (nla_put_u8(skb, IFLA_GENEVE_DF, geneve->cfg.df))
+	if (nla_put_u8(skb, IFLA_GENEVE_DF, cfg->df))
 		goto nla_put_failure;
 
 	if (nla_put_be16(skb, IFLA_GENEVE_PORT, info->key.tp_dst))
@@ -2502,28 +2546,31 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)
 
 #if IS_ENABLED(CONFIG_IPV6)
 	if (nla_put_u8(skb, IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
-		       !geneve->cfg.use_udp6_rx_checksums))
+		       !cfg->use_udp6_rx_checksums))
 		goto nla_put_failure;
 #endif
 
 	if (nla_put_u8(skb, IFLA_GENEVE_TTL_INHERIT, ttl_inherit))
 		goto nla_put_failure;
 
-	if (geneve->cfg.inner_proto_inherit &&
+	if (cfg->inner_proto_inherit &&
 	    nla_put_flag(skb, IFLA_GENEVE_INNER_PROTO_INHERIT))
 		goto nla_put_failure;
 
 	if (nla_put(skb, IFLA_GENEVE_PORT_RANGE, sizeof(ports), &ports))
 		goto nla_put_failure;
 
-	if (geneve->cfg.gro_hint &&
+	if (cfg->gro_hint &&
 	    nla_put_flag(skb, IFLA_GENEVE_GRO_HINT))
 		goto nla_put_failure;
 
-	return 0;
+out:
+	rcu_read_unlock();
+	return err;
 
 nla_put_failure:
-	return -EMSGSIZE;
+	err = -EMSGSIZE;
+	goto out;
 }
 
 static struct rtnl_link_ops geneve_link_ops __read_mostly = {
@@ -2671,6 +2718,7 @@ static void __exit geneve_cleanup_module(void)
 	rtnl_link_unregister(&geneve_link_ops);
 	unregister_netdevice_notifier(&geneve_notifier_block);
 	unregister_pernet_subsys(&geneve_net_ops);
+	rcu_barrier();
 }
 module_exit(geneve_cleanup_module);
 

3/2 2026/07/07 23:53 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 14083
							output: 18
							thoughts: 621
						

Thoughts:
**Analyzing the GENEVE Configuration Patch for Fuzzing**

Okay, so I've got this patch affecting `drivers/net/geneve.c`, and it's a significant functional change. They're switching how `geneve_config` is accessed, moving from a direct `struct` to an `__rcu *` pointer within the `geneve_dev` structure. This immediately flags as something that *needs* fuzzing. It's designed to fix RCU dereferencing issues, essentially replacing the old synchronous `geneve_quiesce` and `geneve_unquiesce` mechanisms with RCU-based atomic configuration updates. That's a solid win for concurrency, but a potential landmine if the RCU usage isn't perfect.

Let's drill down and figure out the best focus points for fuzzing. I've got a list of the modified symbols: `geneve_lookup`, `geneve6_lookup`, `geneve_udp_encap_recv`, `geneve_create_sock`, all the way down to `geneve_fill_info`. My initial thought is to avoid the hot path functions like `geneve_xmit`, `geneve_xmit_skb`, and so on. They're important, but their sheer volume of execution might drown out subtle concurrency bugs. The same goes for receive processing like `geneve_udp_encap_recv` which will be complex with the encap and decapsulation.

Instead, I'll prioritize the configuration and control path functions. My target list is:

*   `geneve_changelink`
*   `geneve_configure`
*   `geneve_newlink` (even though it's minimally touched, it calls `geneve_configure`, so it's relevant)
*   `geneve_fill_info`
*   The newly introduced functions, like `geneve_config_alloc`, `geneve_config_free`, and `geneve_free_dev` are also high value since they implement the new configuration management.

I also need to double-check the Kconfig options for GENEVE. I need to make sure I'm targeting the correct configuration options, either in `drivers/net/Kconfig` or maybe within `drivers/net/geneve.c` itself. This will inform the initial fuzz harness setup.



4/2 2026/07/07 23:53 tool grepper
0m Args:
{
  "Expression": "config GENEVE"
}

Results:
{
  "Output": "drivers/net/Kconfig=230=config VXLAN\n--\ndrivers/net/Kconfig-244-\ndrivers/net/Kconfig:245:config GENEVE\ndrivers/net/Kconfig-246-\ttristate \"Generic Network Virtualization Encapsulation\"\n"
}

5/2 2026/07/07 23:53 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 15317
							output: 19
							thoughts: 76
						

Thoughts:
Okay, here's my take on those thoughts, framed as my own mental processing:

**Examining the GENEVE Configuration**

Alright, so `GENEVE` is the key configuration point here, that much is clear. But I need to be thorough. Are there *any* other configurations we need to consider? Let's see... Ah, yes, `CONFIG_IPV6` is also being referenced in the code, so that's something to keep in mind, although `CONFIG_GENEVE` appears to be the primary one. Now, to really understand the implications of this configuration, I need to dig deeper into the codebase and analyze its application.

Let's focus on `geneve_changelink` and `geneve_configure`. Are these the right functions to zero in on to understand how the configuration actually gets put into effect? They seem like strong candidates, given the names. My gut says they'll be critical focus symbols. I'll start with those and see where they lead.



6/2 2026/07/07 23:53 tool grepper
0m Args:
{
  "Expression": "geneve_changelink"
}

Results:
{
  "Output": "drivers/net/geneve.c=2363=static int geneve_newlink(struct net_device *dev,\n--\ndrivers/net/geneve.c-2398- */\ndrivers/net/geneve.c:2399:static int geneve_changelink(struct net_device *dev, struct nlattr *tb[],\ndrivers/net/geneve.c-2400-\t\t\t     struct nlattr *data[],\n--\ndrivers/net/geneve.c=2576=static struct rtnl_link_ops geneve_link_ops __read_mostly = {\n--\ndrivers/net/geneve.c-2583-\t.newlink\t= geneve_newlink,\ndrivers/net/geneve.c:2584:\t.changelink\t= geneve_changelink,\ndrivers/net/geneve.c-2585-\t.dellink\t= geneve_dellink,\n"
}

7/2 2026/07/07 23:53 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 15865
							output: 18
							thoughts: 23
						

Thoughts:
Okay, here's my take on those thoughts, framed as an expert's internal monologue:

**Focusing on Geneve Configuration**

Right, `geneve_changelink` and `geneve_configure`. Those are definitely the key areas to concentrate on. Thinking about the configuration procedures, specifically those functions, that is where the intricacies of Geneve implementation will undoubtedly lie. `geneve_changelink` is critical for ensuring the proper handling of link state changes – vital for reliable operation. And `geneve_configure`… well, that's the heart of the matter, isn't it? That's where all the setup logic lives; any architectural weaknesses or performance bottlenecks will become readily apparent there. I need to make a mental note to scrutinize their interaction.



8/2 2026/07/07 23:53 tool grepper
0m Args:
{
  "Expression": "geneve_configure"
}

Results:
{
  "Output": "drivers/net/geneve.c=1973=static bool geneve_dst_addr_equal(struct ip_tunnel_info *a,\n--\ndrivers/net/geneve.c-1981-\ndrivers/net/geneve.c:1982:static int geneve_configure(struct net *net, struct net_device *dev,\ndrivers/net/geneve.c-1983-\t\t\t    struct netlink_ext_ack *extack,\n--\ndrivers/net/geneve.c=2363=static int geneve_newlink(struct net_device *dev,\n--\ndrivers/net/geneve.c-2385-\ndrivers/net/geneve.c:2386:\terr = geneve_configure(link_net, dev, extack, \u0026cfg);\ndrivers/net/geneve.c-2387-\tif (err)\n--\ndrivers/net/geneve.c=2590=struct net_device *geneve_dev_create_fb(struct net *net, const char *name,\n--\ndrivers/net/geneve.c-2613-\tinit_tnl_info(\u0026cfg.info, dst_port);\ndrivers/net/geneve.c:2614:\terr = geneve_configure(net, dev, NULL, \u0026cfg);\ndrivers/net/geneve.c-2615-\tif (err) {\n"
}

9/2 2026/07/07 23:54 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16426
							output: 20
							thoughts: 25
						

Thoughts:
Okay, here's my interpretation of those thoughts, framed as my own:

**Initial Assessment of Focus Symbols in Geneve Configuration**

Right, thinking about this `geneve_configure` is a solid, clean symbol to start with. It immediately suggests the core function: setting up and managing the Geneve configuration. It’s concise and conveys the appropriate level of abstraction. Moving on to `geneve_fill_info` feels like a natural progression. It dovetails perfectly as a companion; the implication being the act of *populating* or *completing* the necessary details for that configuration. This is good; the symbols work in tandem to create a clear progression from configuration to instantiation. It helps to delineate the functional areas clearly.



10/2 2026/07/07 23:54 tool grepper
0m Args:
{
  "Expression": "geneve_fill_info"
}

Results:
{
  "Output": "drivers/net/geneve.c=2444=static size_t geneve_get_size(const struct net_device *dev)\n--\ndrivers/net/geneve.c-2464-\ndrivers/net/geneve.c:2465:static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev)\ndrivers/net/geneve.c-2466-{\n--\ndrivers/net/geneve.c=2576=static struct rtnl_link_ops geneve_link_ops __read_mostly = {\n--\ndrivers/net/geneve.c-2586-\t.get_size\t= geneve_get_size,\ndrivers/net/geneve.c:2587:\t.fill_info\t= geneve_fill_info,\ndrivers/net/geneve.c-2588-};\n"
}

11/2 2026/07/07 23:54 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 16856
							output: 162
							thoughts: 224
						

Thoughts:
**Refactoring the GENEVE Driver's Configuration Handling**

Okay, so this patch is a significant shift in how the GENEVE driver manages its configuration data, specifically the `struct geneve_config`. It looks like they're ditching the old synchronous `geneve_quiesce`/`geneve_unquiesce` method, which is good. That `synchronize_net()` call was probably a performance bottleneck, and the RCU-based pointer swap they're using should be a big improvement, allowing lockless access in the data path.

Functionally, this means the control path is undergoing a transformation. The core change is the introduction of RCU for managing that `struct geneve_config`. So, I need to focus my fuzzing efforts on the netlink control path functions. Specifically, I'm thinking about those functions that deal with allocating, updating, and freeing the configuration. I should probably pay extra attention to `geneve_changelink`, `geneve_configure`, `geneve_fill_info`, `geneve_config_alloc`, and `geneve_free_dev` -- those seem like the key areas affected by this RCU implementation. This will be critical for concurrent access and configuration changes.

The `GENEVE` config seems to be the trigger, so keep an eye out for that being enabled. Given this RCU implementation, there might be some interesting race conditions to exploit during configuration changes.



12/2 2026/07/07 23:54 tool set-results
0m Args:
{
  "EnableConfigs": [
    "GENEVE"
  ],
  "FocusSymbols": [
    "geneve_changelink",
    "geneve_configure",
    "geneve_fill_info",
    "geneve_config_alloc",
    "geneve_free_dev"
  ],
  "Reasoning": "The patch refactors the GENEVE driver to use RCU for its configuration (`struct geneve_config`), replacing the previous synchronous `geneve_quiesce`/`geneve_unquiesce` mechanism. This is a functional change affecting how configuration updates are handled concurrently with the data path. Fuzzing should focus on the netlink control path functions that allocate, update, and free the configuration.",
  "WorthFuzzing": true
}

Results:
{
  "EnableConfigs": [
    "GENEVE"
  ],
  "FocusSymbols": [
    "geneve_changelink",
    "geneve_configure",
    "geneve_fill_info",
    "geneve_config_alloc",
    "geneve_free_dev"
  ],
  "Reasoning": "The patch refactors the GENEVE driver to use RCU for its configuration (`struct geneve_config`), replacing the previous synchronous `geneve_quiesce`/`geneve_unquiesce` mechanism. This is a functional change affecting how configuration updates are handled concurrently with the data path. Fuzzing should focus on the netlink control path functions that allocate, update, and free the configuration.",
  "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)