From: Fernando Fernandez Mancera <fmancera@suse.de>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, dsahern@kernel.org, horms@kernel.org,
idosch@nvidia.com,
"Fernando Fernandez Mancera" <fmancera@suse.de>,
"Alexei Starovoitov" <ast@kernel.org>,
"Daniel Borkmann" <daniel@iogearbox.net>,
"Jesper Dangaard Brouer" <hawk@kernel.org>,
"John Fastabend" <john.fastabend@gmail.com>,
"Stanislav Fomichev" <sdf@fomichev.me>,
"Kuniyuki Iwashima" <kuniyu@google.com>,
"Pavel Begunkov" <asml.silence@gmail.com>,
"Dragos Tatulea" <dtatulea@nvidia.com>,
"Eric Biggers" <ebiggers@kernel.org>,
"Ard Biesheuvel" <ardb@kernel.org>,
"Florian Westphal" <fw@strlen.de>,
"Chia-Yu Chang" <chia-yu.chang@nokia-bell-labs.com>,
"Ilpo Järvinen" <ij@kernel.org>,
"Yung Chih Su" <yuuchihsu@gmail.com>,
"Wyatt Feng" <bronzed_45_vested@icloud.com>,
linux-kernel@vger.kernel.org, bpf@vger.kernel.org
Subject: [PATCH 09/13 RFC net-next] net: fib: split common nexthop logic to fib_core.c
Date: Sun, 12 Jul 2026 03:39:07 +0200 [thread overview]
Message-ID: <20260712013941.4570-10-fmancera@suse.de> (raw)
In-Reply-To: <20260712013941.4570-1-fmancera@suse.de>
To enable compiling INET subsystem without IPv4, shared FIB and nexthop
logic must be accessible to IPv6 when IPv4 routing stack is omitted.
This patch creates fib_core.c and move all the functions for common
nexthop initialization and release from fib_semantics.c to fib_core.c.
Note that fib_core.c is under net/core.
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
---
include/net/ip_fib.h | 43 +++++++++++
include/net/route.h | 6 ++
net/core/Makefile | 2 +-
net/core/fib_core.c | 146 +++++++++++++++++++++++++++++++++++++
net/ipv4/Makefile | 2 +
net/ipv4/fib_semantics.c | 142 ------------------------------------
net/ipv4/netlink.c | 2 +
net/ipv4/nexthop.c | 2 +-
net/ipv4/sysctl_net_ipv4.c | 2 +
net/ipv6/ip6_fib.c | 2 +
10 files changed, 205 insertions(+), 144 deletions(-)
create mode 100644 net/core/fib_core.c
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 0a35355fb0f3..0c56d8690e00 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -250,7 +250,13 @@ int call_fib4_notifiers(struct net *net, enum fib_event_type event_type,
int __net_init fib4_notifier_init(struct net *net);
void __net_exit fib4_notifier_exit(struct net *net);
+#if IS_ENABLED(CONFIG_IPV4)
void fib_info_notify_update(struct net *net, struct nl_info *info);
+#else
+static inline void fib_info_notify_update(struct net *net, struct nl_info *info)
+{
+}
+#endif
int fib_notify(struct net *net, struct notifier_block *nb,
struct netlink_ext_ack *extack);
@@ -578,10 +584,23 @@ void fib_select_multipath(struct fib_result *res, int hash,
void fib_select_path(struct net *net, struct fib_result *res,
struct flowi4 *fl4, const struct sk_buff *skb);
+#if IS_ENABLED(CONFIG_IPV4)
int fib_nh_init(struct net *net, struct fib_nh *fib_nh,
struct fib_config *cfg, int nh_weight,
struct netlink_ext_ack *extack);
void fib_nh_release(struct net *net, struct fib_nh *fib_nh);
+#else
+static inline int fib_nh_init(struct net *net, struct fib_nh *fib_nh,
+ struct fib_config *cfg, int gfp,
+ struct netlink_ext_ack *extack)
+{
+ return -EAFNOSUPPORT;
+}
+
+static inline void fib_nh_release(struct net *net, struct fib_nh *fib_nh)
+{
+}
+#endif
int fib_nh_common_init(struct net *net, struct fib_nh_common *nhc,
struct nlattr *fc_encap, u16 fc_encap_type,
void *cfg, gfp_t gfp_flags,
@@ -620,7 +639,13 @@ static inline void fib_combine_itag(u32 *itag, const struct fib_result *res)
#endif
}
+#if IS_ENABLED(CONFIG_IPV4)
void fib_flush(struct net *net);
+#else
+static inline void fib_flush(struct net *net)
+{
+}
+#endif
void free_fib_info(struct fib_info *fi);
static inline void fib_info_hold(struct fib_info *fi)
@@ -658,8 +683,26 @@ int ip_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
struct fib_dump_filter *filter,
struct netlink_callback *cb);
+#if IS_ENABLED(CONFIG_IPV4)
int fib_nexthop_info(struct sk_buff *skb, const struct fib_nh_common *nh,
u8 rt_family, unsigned char *flags, bool skip_oif);
int fib_add_nexthop(struct sk_buff *skb, const struct fib_nh_common *nh,
int nh_weight, u8 rt_family, u32 nh_tclassid);
+#else
+static inline int fib_nexthop_info(struct sk_buff *skb,
+ const struct fib_nh_common *nh,
+ u8 rt_family, unsigned char *flags,
+ bool skip_oif)
+{
+ return 0;
+}
+
+static inline int fib_add_nexthop(struct sk_buff *skb,
+ const struct fib_nh_common *nh,
+ int nh_weight, u8 rt_family,
+ u32 nh_tclassid)
+{
+ return 0;
+}
+#endif
#endif /* _NET_FIB_H */
diff --git a/include/net/route.h b/include/net/route.h
index 08adb14224a9..29944be291f8 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -128,7 +128,13 @@ extern struct ip_rt_acct __percpu *ip_rt_acct;
struct in_device;
int ip_rt_init(void);
+#if IS_ENABLED(CONFIG_IPV4)
void rt_cache_flush(struct net *net);
+#else
+static inline void rt_cache_flush(struct net *net)
+{
+}
+#endif
void rt_flush_dev(struct net_device *dev);
static inline void inet_sk_init_flowi4(const struct inet_sock *inet,
diff --git a/net/core/Makefile b/net/core/Makefile
index b3fdcb4e355f..63ebcdc6b9f1 100644
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
obj-y += dev.o dev_api.o dev_addr_lists.o dst.o netevent.o \
neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
- fib_notifier.o xdp.o flow_offload.o gro.o \
+ fib_notifier.o fib_core.o xdp.o flow_offload.o gro.o \
netdev-genl.o netdev-genl-gen.o netdev_work.o gso.o
obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o
diff --git a/net/core/fib_core.c b/net/core/fib_core.c
new file mode 100644
index 000000000000..93894b5847e9
--- /dev/null
+++ b/net/core/fib_core.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/types.h>
+#include <net/lwtunnel.h>
+#include <net/route.h>
+
+static void rt_fibinfo_free(struct rtable __rcu **rtp)
+{
+ struct rtable *rt = rcu_dereference_protected(*rtp, 1);
+
+ if (!rt)
+ return;
+
+ /* Not even needed : RCU_INIT_POINTER(*rtp, NULL);
+ * because we waited an RCU grace period before calling
+ * free_fib_info_rcu()
+ */
+
+ dst_dev_put(&rt->dst);
+ dst_release_immediate(&rt->dst);
+}
+
+static void free_nh_exceptions(struct fib_nh_common *nhc)
+{
+ struct fnhe_hash_bucket *hash;
+ int i;
+
+ hash = rcu_dereference_protected(nhc->nhc_exceptions, 1);
+ if (!hash)
+ return;
+ for (i = 0; i < FNHE_HASH_SIZE; i++) {
+ struct fib_nh_exception *fnhe;
+
+ fnhe = rcu_dereference_protected(hash[i].chain, 1);
+ while (fnhe) {
+ struct fib_nh_exception *next;
+
+ next = rcu_dereference_protected(fnhe->fnhe_next, 1);
+
+ rt_fibinfo_free(&fnhe->fnhe_rth_input);
+ rt_fibinfo_free(&fnhe->fnhe_rth_output);
+
+ kfree(fnhe);
+
+ fnhe = next;
+ }
+ }
+ kfree(hash);
+}
+
+static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
+{
+ int cpu;
+
+ if (!rtp)
+ return;
+
+ for_each_possible_cpu(cpu) {
+ struct rtable *rt;
+
+ rt = rcu_dereference_protected(*per_cpu_ptr(rtp, cpu), 1);
+ if (rt) {
+ dst_dev_put(&rt->dst);
+ dst_release_immediate(&rt->dst);
+ }
+ }
+ free_percpu(rtp);
+}
+
+void fib_nh_common_release(struct fib_nh_common *nhc)
+{
+ netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker);
+ lwtstate_put(nhc->nhc_lwtstate);
+ rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
+ rt_fibinfo_free(&nhc->nhc_rth_input);
+ free_nh_exceptions(nhc);
+}
+
+int fib_nh_common_init(struct net *net, struct fib_nh_common *nhc,
+ struct nlattr *encap, u16 encap_type,
+ void *cfg, gfp_t gfp_flags,
+ struct netlink_ext_ack *extack)
+{
+ int err;
+
+ nhc->nhc_pcpu_rth_output = alloc_percpu_gfp(struct rtable __rcu *,
+ gfp_flags);
+ if (!nhc->nhc_pcpu_rth_output)
+ return -ENOMEM;
+
+ if (encap) {
+ struct lwtunnel_state *lwtstate;
+
+ err = lwtunnel_build_state(net, encap_type, encap,
+ nhc->nhc_family, cfg, &lwtstate,
+ extack);
+ if (err)
+ goto lwt_failure;
+
+ nhc->nhc_lwtstate = lwtstate_get(lwtstate);
+ }
+
+ return 0;
+
+lwt_failure:
+ rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
+ nhc->nhc_pcpu_rth_output = NULL;
+ return err;
+}
+
+/* Update the PMTU of exceptions when:
+ * - the new MTU of the first hop becomes smaller than the PMTU
+ * - the old MTU was the same as the PMTU, and it limited discovery of
+ * larger MTUs on the path. With that limit raised, we can now
+ * discover larger MTUs
+ * A special case is locked exceptions, for which the PMTU is smaller
+ * than the minimal accepted PMTU:
+ * - if the new MTU is greater than the PMTU, don't make any change
+ * - otherwise, unlock and set PMTU
+ */
+void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
+{
+ struct fnhe_hash_bucket *bucket;
+ int i;
+
+ bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1);
+ if (!bucket)
+ return;
+
+ for (i = 0; i < FNHE_HASH_SIZE; i++) {
+ struct fib_nh_exception *fnhe;
+
+ for (fnhe = rcu_dereference_protected(bucket[i].chain, 1);
+ fnhe;
+ fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) {
+ if (fnhe->fnhe_mtu_locked) {
+ if (new <= fnhe->fnhe_pmtu) {
+ fnhe->fnhe_pmtu = new;
+ fnhe->fnhe_mtu_locked = false;
+ }
+ } else if (new < fnhe->fnhe_pmtu ||
+ orig == fnhe->fnhe_pmtu) {
+ fnhe->fnhe_pmtu = new;
+ }
+ }
+ }
+}
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 83c25f52eb58..b540d549f25a 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -19,7 +19,9 @@ obj-$(CONFIG_IPV4) += route.o ip_input.o ip_fragment.o ip_forward.o ip_options.o
obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o
obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
obj-$(CONFIG_PROC_FS) += proc.o
+ifeq ($(CONFIG_IPV4),y)
obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
+endif
obj-$(CONFIG_IP_MROUTE) += ipmr.o
obj-$(CONFIG_IP_MROUTE_COMMON) += ipmr_base.o
obj-$(CONFIG_NET_IPIP) += ipip.o
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 4f3c0740dde9..6ed252e9559e 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -136,78 +136,6 @@ const struct fib_prop fib_props[RTN_MAX + 1] = {
},
};
-static void rt_fibinfo_free(struct rtable __rcu **rtp)
-{
- struct rtable *rt = rcu_dereference_protected(*rtp, 1);
-
- if (!rt)
- return;
-
- /* Not even needed : RCU_INIT_POINTER(*rtp, NULL);
- * because we waited an RCU grace period before calling
- * free_fib_info_rcu()
- */
-
- dst_dev_put(&rt->dst);
- dst_release_immediate(&rt->dst);
-}
-
-static void free_nh_exceptions(struct fib_nh_common *nhc)
-{
- struct fnhe_hash_bucket *hash;
- int i;
-
- hash = rcu_dereference_protected(nhc->nhc_exceptions, 1);
- if (!hash)
- return;
- for (i = 0; i < FNHE_HASH_SIZE; i++) {
- struct fib_nh_exception *fnhe;
-
- fnhe = rcu_dereference_protected(hash[i].chain, 1);
- while (fnhe) {
- struct fib_nh_exception *next;
-
- next = rcu_dereference_protected(fnhe->fnhe_next, 1);
-
- rt_fibinfo_free(&fnhe->fnhe_rth_input);
- rt_fibinfo_free(&fnhe->fnhe_rth_output);
-
- kfree(fnhe);
-
- fnhe = next;
- }
- }
- kfree(hash);
-}
-
-static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
-{
- int cpu;
-
- if (!rtp)
- return;
-
- for_each_possible_cpu(cpu) {
- struct rtable *rt;
-
- rt = rcu_dereference_protected(*per_cpu_ptr(rtp, cpu), 1);
- if (rt) {
- dst_dev_put(&rt->dst);
- dst_release_immediate(&rt->dst);
- }
- }
- free_percpu(rtp);
-}
-
-void fib_nh_common_release(struct fib_nh_common *nhc)
-{
- netdev_put(nhc->nhc_dev, &nhc->nhc_dev_tracker);
- lwtstate_put(nhc->nhc_lwtstate);
- rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
- rt_fibinfo_free(&nhc->nhc_rth_input);
- free_nh_exceptions(nhc);
-}
-
void fib_nh_release(struct net *net, struct fib_nh *fib_nh)
{
#ifdef CONFIG_IP_ROUTE_CLASSID
@@ -607,38 +535,6 @@ static int fib_detect_death(struct fib_info *fi, int order,
return 1;
}
-int fib_nh_common_init(struct net *net, struct fib_nh_common *nhc,
- struct nlattr *encap, u16 encap_type,
- void *cfg, gfp_t gfp_flags,
- struct netlink_ext_ack *extack)
-{
- int err;
-
- nhc->nhc_pcpu_rth_output = alloc_percpu_gfp(struct rtable __rcu *,
- gfp_flags);
- if (!nhc->nhc_pcpu_rth_output)
- return -ENOMEM;
-
- if (encap) {
- struct lwtunnel_state *lwtstate;
-
- err = lwtunnel_build_state(net, encap_type, encap,
- nhc->nhc_family, cfg, &lwtstate,
- extack);
- if (err)
- goto lwt_failure;
-
- nhc->nhc_lwtstate = lwtstate_get(lwtstate);
- }
-
- return 0;
-
-lwt_failure:
- rt_fibinfo_free_cpus(nhc->nhc_pcpu_rth_output);
- nhc->nhc_pcpu_rth_output = NULL;
- return err;
-}
-
int fib_nh_init(struct net *net, struct fib_nh *nh,
struct fib_config *cfg, int nh_weight,
struct netlink_ext_ack *extack)
@@ -1864,44 +1760,6 @@ static int call_fib_nh_notifiers(struct fib_nh *nh,
return NOTIFY_DONE;
}
-/* Update the PMTU of exceptions when:
- * - the new MTU of the first hop becomes smaller than the PMTU
- * - the old MTU was the same as the PMTU, and it limited discovery of
- * larger MTUs on the path. With that limit raised, we can now
- * discover larger MTUs
- * A special case is locked exceptions, for which the PMTU is smaller
- * than the minimal accepted PMTU:
- * - if the new MTU is greater than the PMTU, don't make any change
- * - otherwise, unlock and set PMTU
- */
-void fib_nhc_update_mtu(struct fib_nh_common *nhc, u32 new, u32 orig)
-{
- struct fnhe_hash_bucket *bucket;
- int i;
-
- bucket = rcu_dereference_protected(nhc->nhc_exceptions, 1);
- if (!bucket)
- return;
-
- for (i = 0; i < FNHE_HASH_SIZE; i++) {
- struct fib_nh_exception *fnhe;
-
- for (fnhe = rcu_dereference_protected(bucket[i].chain, 1);
- fnhe;
- fnhe = rcu_dereference_protected(fnhe->fnhe_next, 1)) {
- if (fnhe->fnhe_mtu_locked) {
- if (new <= fnhe->fnhe_pmtu) {
- fnhe->fnhe_pmtu = new;
- fnhe->fnhe_mtu_locked = false;
- }
- } else if (new < fnhe->fnhe_pmtu ||
- orig == fnhe->fnhe_pmtu) {
- fnhe->fnhe_pmtu = new;
- }
- }
- }
-}
-
void fib_sync_mtu(struct net_device *dev, u32 orig_mtu)
{
struct hlist_head *head = fib_nh_head(dev);
diff --git a/net/ipv4/netlink.c b/net/ipv4/netlink.c
index b920e1bdcf58..57d4dca16d3e 100644
--- a/net/ipv4/netlink.c
+++ b/net/ipv4/netlink.c
@@ -16,10 +16,12 @@ int rtm_getroute_parse_ip_proto(struct nlattr *attr, u8 *ip_proto, u8 family,
case IPPROTO_TCP:
case IPPROTO_UDP:
return 0;
+#if IS_ENABLED(CONFIG_IPV4)
case IPPROTO_ICMP:
if (family != AF_INET)
break;
return 0;
+#endif
#if IS_ENABLED(CONFIG_IPV6)
case IPPROTO_ICMPV6:
if (family != AF_INET6)
diff --git a/net/ipv4/nexthop.c b/net/ipv4/nexthop.c
index 6205bd57aa85..b113a31f6150 100644
--- a/net/ipv4/nexthop.c
+++ b/net/ipv4/nexthop.c
@@ -1414,7 +1414,7 @@ static bool nexthop_is_good_nh(const struct nexthop *nh)
switch (nhi->family) {
case AF_INET:
- return ipv4_good_nh(&nhi->fib_nh);
+ return IS_ENABLED(CONFIG_IPV4) && ipv4_good_nh(&nhi->fib_nh);
case AF_INET6:
return IS_ENABLED(CONFIG_IPV6) && ipv6_good_nh(&nhi->fib6_nh);
}
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index ca1180dba1de..9c343c9566b7 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -613,6 +613,7 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
},
+#if IS_ENABLED(CONFIG_IPV4)
{
.procname = "fib_sync_mem",
.data = &sysctl_fib_sync_mem,
@@ -622,6 +623,7 @@ static struct ctl_table ipv4_table[] = {
.extra1 = &sysctl_fib_sync_mem_min,
.extra2 = &sysctl_fib_sync_mem_max,
},
+#endif
};
static struct ctl_table ipv4_net_table[] = {
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index a130cdfaebfb..8b5f855c8dcb 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -645,9 +645,11 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
rcu_read_lock();
if (cb->strict_check) {
+#if IS_ENABLED(CONFIG_IPV4)
err = ip_valid_fib_dump_req(net, nlh, &arg.filter, cb);
if (err < 0)
goto unlock;
+#endif
} else if (nlmsg_len(nlh) >= sizeof(struct rtmsg)) {
struct rtmsg *rtm = nlmsg_data(nlh);
--
2.54.0
prev parent reply other threads:[~2026-07-12 1:41 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20260712013941.4570-1-fmancera@suse.de>
2026-07-12 1:39 ` [PATCH 02/13 RFC net-next] net: core: add IPv4 fallback stubs and guards for CONFIG_IPV4=n Fernando Fernandez Mancera
2026-07-12 1:39 ` [PATCH 04/13 RFC net-next] net: tcp: move protocol agnostic TCP functions out of tcp_ipv4.c Fernando Fernandez Mancera
2026-07-12 1:39 ` [PATCH 06/13 RFC net-next] net: udp: split IPv4 specific logic into udp_ipv4.c Fernando Fernandez Mancera
2026-07-12 1:39 ` [PATCH 08/13 RFC net-next] net: ping: split IPv4 specific logic into ping_ipv4.c Fernando Fernandez Mancera
2026-07-12 1:39 ` Fernando Fernandez Mancera [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260712013941.4570-10-fmancera@suse.de \
--to=fmancera@suse.de \
--cc=ardb@kernel.org \
--cc=asml.silence@gmail.com \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=bronzed_45_vested@icloud.com \
--cc=chia-yu.chang@nokia-bell-labs.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=dtatulea@nvidia.com \
--cc=ebiggers@kernel.org \
--cc=edumazet@google.com \
--cc=fw@strlen.de \
--cc=hawk@kernel.org \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=ij@kernel.org \
--cc=john.fastabend@gmail.com \
--cc=kuba@kernel.org \
--cc=kuniyu@google.com \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sdf@fomichev.me \
--cc=yuuchihsu@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox