From: "Julius R. Volz" <juliusv@google.com>
To: lvs-devel@vger.kernel.org, netdev@vger.kernel.org
Cc: horms@verge.net.au, davem@davemloft.net, vbusam@google.com,
"Julius R. Volz" <juliusv@google.com>
Subject: [PATCH 16/26] IPVS: Add IPv6 xmit forwarding functions.
Date: Wed, 11 Jun 2008 19:11:59 +0200 [thread overview]
Message-ID: <1213204329-10973-17-git-send-email-juliusv@google.com> (raw)
In-Reply-To: <1213204329-10973-1-git-send-email-juliusv@google.com>
Add IPv6 xmit functions where these are different from IPv4 versions. Add
an ip_vs_bind_xmit_v6() function that binds these functions to an IPv6
connection entry.
Signed-off-by: Julius R. Volz <juliusv@google.com>
3 files changed, 407 insertions(+), 0 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 2ab5d59..d04d5c6 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -1042,6 +1042,18 @@ extern int ip_vs_icmp_xmit
(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset);
extern void ip_vs_dst_reset(struct ip_vs_dest *dest);
+#ifdef CONFIG_IP_VS_IPV6
+extern int ip_vs_bypass_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_nat_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_tunnel_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_dr_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp);
+extern int ip_vs_icmp_xmit_v6
+(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset);
+#endif
/*
* This is a simple mechanism to ignore packets when
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c
index b3df938..1a4040d 100644
--- a/net/netfilter/ipvs/ip_vs_conn.c
+++ b/net/netfilter/ipvs/ip_vs_conn.c
@@ -374,6 +374,33 @@ static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp)
}
}
+#ifdef CONFIG_IP_VS_IPV6
+static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp)
+{
+ switch (IP_VS_FWD_METHOD(cp)) {
+ case IP_VS_CONN_F_MASQ:
+ cp->packet_xmit = ip_vs_nat_xmit_v6;
+ break;
+
+ case IP_VS_CONN_F_TUNNEL:
+ cp->packet_xmit = ip_vs_tunnel_xmit_v6;
+ break;
+
+ case IP_VS_CONN_F_DROUTE:
+ cp->packet_xmit = ip_vs_dr_xmit_v6;
+ break;
+
+ case IP_VS_CONN_F_LOCALNODE:
+ cp->packet_xmit = ip_vs_null_xmit;
+ break;
+
+ case IP_VS_CONN_F_BYPASS:
+ cp->packet_xmit = ip_vs_bypass_xmit_v6;
+ break;
+ }
+}
+#endif
+
static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
{
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 029d9ec..9d2c424 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -289,6 +289,68 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
return NF_STOLEN;
}
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+ struct ip_vs_protocol *pp)
+{
+ struct rt6_info *rt; /* Route to the other host */
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ int mtu;
+ struct flowi fl = {
+ .oif = 0,
+ .nl_u = {
+ .ip6_u = {
+ .daddr = iph->daddr,
+ .saddr = { .s6_addr32 = {0, 0, 0, 0} }, } },
+ };
+
+ EnterFunction(10);
+
+ if (!(rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl))) {
+ IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, "
+ "dest: " NIP6_FMT "\n", NIP6(iph->daddr));
+ goto tx_error_icmp;
+ }
+
+ /* MTU checking */
+ mtu = dst_mtu(&rt->u.dst);
+ if (skb->len > mtu) {
+ dst_release(&rt->u.dst);
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+ IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): frag needed\n");
+ goto tx_error;
+ }
+
+ /*
+ * Call ip_send_check because we are not sure it is called
+ * after ip_defrag. Is copy-on-write needed?
+ */
+ if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
+ dst_release(&rt->u.dst);
+ return NF_STOLEN;
+ }
+
+ /* drop old route */
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->local_df = 1;
+
+ IP_VS_XMIT(PF_INET6, skb, rt);
+
+ LeaveFunction(10);
+ return NF_STOLEN;
+
+ tx_error_icmp:
+ dst_link_failure(skb);
+ tx_error:
+ kfree_skb(skb);
+ LeaveFunction(10);
+ return NF_STOLEN;
+}
+#endif
/*
* NAT transmitter (only for outside-to-inside nat forwarding)
@@ -368,6 +430,80 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
goto tx_error;
}
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+ struct ip_vs_protocol *pp)
+{
+ struct rt6_info *rt; /* Route to the other host */
+ int mtu;
+
+ EnterFunction(10);
+
+ /* check if it is a connection of no-client-port */
+ if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
+ __be16 _pt, *p;
+ p = skb_header_pointer(skb, sizeof(struct ipv6hdr), sizeof(_pt), &_pt);
+ if (p == NULL)
+ goto tx_error;
+ ip_vs_conn_fill_cport(cp, *p);
+ IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
+ }
+
+ if (!(rt = __ip_vs_get_out_rt_v6(cp)))
+ goto tx_error_icmp;
+
+ /* MTU checking */
+ mtu = dst_mtu(&rt->u.dst);
+ if (skb->len > mtu) {
+ dst_release(&rt->u.dst);
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+ IP_VS_DBG_RL_PKT(0, pp, skb, 0, "ip_vs_nat_xmit_v6(): frag needed for");
+ goto tx_error;
+ }
+
+ /* copy-on-write the packet before mangling it */
+ if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
+ goto tx_error_put;
+
+ if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+ goto tx_error_put;
+
+ /* drop old route */
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+
+ /* mangle the packet */
+ if (pp->dnat_handler_v6 && !pp->dnat_handler_v6(skb, pp, cp))
+ goto tx_error;
+ ipv6_hdr(skb)->daddr = cp->daddr.v6;
+
+ IP_VS_DBG_PKT(10, pp, skb, 0, "After DNAT");
+
+ /* FIXME: when application helper enlarges the packet and the length
+ is larger than the MTU of outgoing device, there will be still
+ MTU problem. */
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->local_df = 1;
+
+ IP_VS_XMIT(PF_INET6, skb, rt);
+
+ LeaveFunction(10);
+ return NF_STOLEN;
+
+ tx_error_icmp:
+ dst_link_failure(skb);
+ tx_error:
+ LeaveFunction(10);
+ kfree_skb(skb);
+ return NF_STOLEN;
+ tx_error_put:
+ dst_release(&rt->u.dst);
+ goto tx_error;
+}
+#endif
+
/*
* IP Tunneling transmitter
@@ -499,6 +635,111 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
return NF_STOLEN;
}
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+ struct ip_vs_protocol *pp)
+{
+ struct rt6_info *rt; /* Route to the other host */
+ struct net_device *tdev; /* Device to other host */
+ struct ipv6hdr *old_iph = ipv6_hdr(skb);
+ sk_buff_data_t old_transport_header = skb->transport_header;
+ struct ipv6hdr *iph; /* Our new IP header */
+ unsigned int max_headroom; /* The extra header space needed */
+ int mtu;
+
+ EnterFunction(10);
+
+ if (skb->protocol != htons(ETH_P_IPV6)) {
+ IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): protocol error, "
+ "ETH_P_IPV6: %d, skb protocol: %d\n",
+ htons(ETH_P_IPV6), skb->protocol);
+ goto tx_error;
+ }
+
+ if (!(rt = __ip_vs_get_out_rt_v6(cp)))
+ goto tx_error_icmp;
+
+ tdev = rt->u.dst.dev;
+
+ mtu = dst_mtu(&rt->u.dst) - sizeof(struct ipv6hdr);
+ /* TODO IPv6: do we need this check in IPv6? */
+ if (mtu < 1280) {
+ dst_release(&rt->u.dst);
+ IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): mtu less than 1280\n");
+ goto tx_error;
+ }
+ if (skb->dst)
+ skb->dst->ops->update_pmtu(skb->dst, mtu);
+
+ if (mtu < ntohs(old_iph->payload_len) + sizeof(struct ipv6hdr)) {
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+ dst_release(&rt->u.dst);
+ IP_VS_DBG_RL("ip_vs_tunnel_xmit_v6(): frag needed\n");
+ goto tx_error;
+ }
+
+ /*
+ * Okay, now see if we can stuff it in the buffer as-is.
+ */
+ max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr);
+
+ if (skb_headroom(skb) < max_headroom
+ || skb_cloned(skb) || skb_shared(skb)) {
+ struct sk_buff *new_skb =
+ skb_realloc_headroom(skb, max_headroom);
+ if (!new_skb) {
+ dst_release(&rt->u.dst);
+ kfree_skb(skb);
+ IP_VS_ERR_RL("ip_vs_tunnel_xmit_v6(): no memory\n");
+ return NF_STOLEN;
+ }
+ kfree_skb(skb);
+ skb = new_skb;
+ old_iph = ipv6_hdr(skb);
+ }
+
+ skb->transport_header = old_transport_header;
+
+ skb_push(skb, sizeof(struct ipv6hdr));
+ skb_reset_network_header(skb);
+ memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+
+ /* drop old route */
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+
+ /*
+ * Push down and install the IPIP header.
+ */
+ iph = ipv6_hdr(skb);
+ iph->version = 6;
+ iph->nexthdr = IPPROTO_IPV6;
+ iph->payload_len = old_iph->payload_len + sizeof(old_iph);
+ iph->priority = old_iph->priority;
+ memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl));
+ iph->daddr = rt->rt6i_dst.addr;
+ iph->saddr = cp->vaddr.v6; /* rt->rt6i_src.addr; */
+ iph->hop_limit = old_iph->hop_limit;
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->local_df = 1;
+
+ ip6_local_out(skb);
+
+ LeaveFunction(10);
+
+ return NF_STOLEN;
+
+ tx_error_icmp:
+ dst_link_failure(skb);
+ tx_error:
+ kfree_skb(skb);
+ LeaveFunction(10);
+ return NF_STOLEN;
+}
+#endif
+
/*
* Direct Routing transmitter
@@ -556,6 +797,58 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
return NF_STOLEN;
}
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+ struct ip_vs_protocol *pp)
+{
+ struct rt6_info *rt; /* Route to the other host */
+ int mtu;
+
+ EnterFunction(10);
+
+ if (!(rt = __ip_vs_get_out_rt_v6(cp)))
+ goto tx_error_icmp;
+
+ /* MTU checking */
+ mtu = dst_mtu(&rt->u.dst);
+ if (skb->len > mtu) {
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+ dst_release(&rt->u.dst);
+ IP_VS_DBG_RL("ip_vs_dr_xmit_v6(): frag needed\n");
+ goto tx_error;
+ }
+
+ /*
+ * Call ip_send_check because we are not sure it is called
+ * after ip_defrag. Is copy-on-write needed?
+ */
+ if (unlikely((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)) {
+ dst_release(&rt->u.dst);
+ return NF_STOLEN;
+ }
+
+ /* drop old route */
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->local_df = 1;
+
+ IP_VS_XMIT(PF_INET6, skb, rt);
+
+ LeaveFunction(10);
+ return NF_STOLEN;
+
+ tx_error_icmp:
+ dst_link_failure(skb);
+ tx_error:
+ kfree_skb(skb);
+ LeaveFunction(10);
+ return NF_STOLEN;
+}
+#endif
+
/*
* ICMP packet transmitter
@@ -633,3 +926,78 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
ip_rt_put(rt);
goto tx_error;
}
+
+#ifdef CONFIG_IP_VS_IPV6
+int
+ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
+ struct ip_vs_protocol *pp, int offset)
+{
+ struct rt6_info *rt; /* Route to the other host */
+ int mtu;
+ int rc;
+
+ EnterFunction(10);
+
+ /* The ICMP packet for VS/TUN, VS/DR and LOCALNODE will be
+ forwarded directly here, because there is no need to
+ translate address/port back */
+ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) {
+ if (cp->packet_xmit)
+ rc = cp->packet_xmit(skb, cp, pp);
+ else
+ rc = NF_ACCEPT;
+ /* do not touch skb anymore */
+ atomic_inc(&cp->in_pkts);
+ goto out;
+ }
+
+ /*
+ * mangle and send the packet here (only for VS/NAT)
+ */
+
+ if (!(rt = __ip_vs_get_out_rt_v6(cp)))
+ goto tx_error_icmp;
+
+ /* MTU checking */
+ mtu = dst_mtu(&rt->u.dst);
+ if (skb->len > mtu) {
+ dst_release(&rt->u.dst);
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
+ IP_VS_DBG_RL("ip_vs_in_icmp(): frag needed\n");
+ goto tx_error;
+ }
+
+ /* copy-on-write the packet before mangling it */
+ if (!skb_make_writable(skb, offset))
+ goto tx_error_put;
+
+ if (skb_cow(skb, rt->u.dst.dev->hard_header_len))
+ goto tx_error_put;
+
+ /* drop the old route when skb is not shared */
+ dst_release(skb->dst);
+ skb->dst = &rt->u.dst;
+
+ ip_vs_nat_icmp_v6(skb, pp, cp, 0);
+
+ /* Another hack: avoid icmp_send in ip_fragment */
+ skb->local_df = 1;
+
+ IP_VS_XMIT(PF_INET6, skb, rt);
+
+ rc = NF_STOLEN;
+ goto out;
+
+ tx_error_icmp:
+ dst_link_failure(skb);
+ tx_error:
+ dev_kfree_skb(skb);
+ rc = NF_STOLEN;
+ out:
+ LeaveFunction(10);
+ return rc;
+ tx_error_put:
+ dst_release(&rt->u.dst);
+ goto tx_error;
+}
+#endif
--
1.5.3.6
next prev parent reply other threads:[~2008-06-11 17:11 UTC|newest]
Thread overview: 76+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-06-11 17:11 [PATCH 00/26] IPVS: Add first IPv6 support to IPVS Julius R. Volz
2008-06-11 17:11 ` [PATCH 01/26] IPVS: Add CONFIG_IP_VS_IPV6 option for IPv6 support Julius R. Volz
2008-06-11 17:11 ` [PATCH 02/26] IPVS: Change IPVS data structures to support IPv6 addresses Julius R. Volz
2008-06-11 17:12 ` Patrick McHardy
[not found] ` <f4845fc0806111041u2a9a197fseefe300ffbbda3c3@mail.gmail.com>
[not found] ` <485010E9.6000506@trash.net>
2008-06-11 18:08 ` Julius Volz
2008-06-12 1:54 ` Brian Haley
2008-06-12 9:47 ` Julius Volz
2008-06-11 17:11 ` [PATCH 03/26] IPVS: Use new address family fields in IPVS structs Julius R. Volz
2008-06-11 17:11 ` [PATCH 04/26] IPVS: Add address family specific debugging macros Julius R. Volz
2008-06-11 17:11 ` [PATCH 05/26] IPVS: Use new " Julius R. Volz
2008-06-11 17:14 ` Patrick McHardy
2008-06-11 17:11 ` [PATCH 06/26] IPVS: Add IPv6-specific function pointers to struct ip_vs_protocol Julius R. Volz
2008-06-11 17:11 ` [PATCH 07/26] IPVS: Add IPv6 handler functions to AH protocol handler Julius R. Volz
2008-06-11 17:11 ` [PATCH 08/26] IPVS: Add IPv6 handler functions to ESP " Julius R. Volz
2008-06-11 17:11 ` [PATCH 09/26] IPVS: Add IPv6 handler functions to TCP " Julius R. Volz
2008-06-11 17:11 ` [PATCH 10/26] IPVS: Add IPv6 handler functions to UDP " Julius R. Volz
2008-06-11 17:18 ` Patrick McHardy
2008-06-11 17:11 ` [PATCH 11/26] IPVS: Add supports_ipv6 flag to schedulers Julius R. Volz
2008-06-11 17:11 ` [PATCH 12/26] IPVS: Extend proto handler debug functions to handle IPv6 Julius R. Volz
2008-06-11 17:17 ` Patrick McHardy
2008-06-11 17:11 ` [PATCH 13/26] IPVS: Turn off FTP application helper for IPv6 Julius R. Volz
2008-06-11 17:11 ` [PATCH 14/26] IPVS: Extend xmit routing cache to support IPv6 Julius R. Volz
2008-06-11 17:11 ` [PATCH 15/26] IPVS: Modify IP_VS_XMIT() " Julius R. Volz
2008-06-11 17:11 ` Julius R. Volz [this message]
2008-06-12 1:55 ` [PATCH 16/26] IPVS: Add IPv6 xmit forwarding functions Brian Haley
2008-06-11 17:12 ` [PATCH 17/26] IPVS: Add connection hashing function for IPv6 entries Julius R. Volz
2008-06-11 17:12 ` [PATCH 18/26] IPVS: Add functions for getting/creating IPv6 connections Julius R. Volz
2008-06-12 1:55 ` Brian Haley
2008-06-11 17:12 ` [PATCH 19/26] IPVS: Add scheduling functions for " Julius R. Volz
2008-06-11 17:12 ` [PATCH 20/26] IPVS: Add IPv6 Netfilter hooks and add/modify support functions Julius R. Volz
2008-06-12 1:55 ` Brian Haley
2008-06-11 17:12 ` [PATCH 21/26] IPVS: Make proc/net files output IPv6 entries correctly Julius R. Volz
2008-06-11 17:12 ` [PATCH 22/26] IPVS: Add function to find out if IPv6 address is local Julius R. Volz
2008-06-11 17:12 ` [PATCH 23/26] IPVS: Add hash functions for IPv6 services and real servers Julius R. Volz
2008-06-11 17:12 ` [PATCH 24/26] IPVS: Add IPv6 support to userspace interface Julius R. Volz
2008-06-12 1:55 ` Brian Haley
2008-06-12 9:46 ` Julius Volz
2008-06-11 17:12 ` [PATCH 25/26] IPVS: Add support for IPv6 entry output in procfs files Julius R. Volz
2008-06-11 17:12 ` [PATCH 26/26] IPVS: Add some blame/credits for IPv6 version Julius R. Volz
2008-06-11 17:23 ` [PATCH 00/26] IPVS: Add first IPv6 support to IPVS Patrick McHardy
2008-06-11 18:23 ` Julius Volz
2008-06-11 18:42 ` Patrick McHardy
2008-06-11 19:05 ` Julius Volz
2008-06-11 19:10 ` Patrick McHardy
2008-06-11 19:29 ` Julius Volz
2008-06-11 19:31 ` Patrick McHardy
2008-06-11 19:53 ` Julius Volz
2008-06-11 20:14 ` Julius Volz
2008-06-11 20:55 ` Vince Busam
2008-06-11 21:30 ` Ben Greear
2008-06-11 22:26 ` Vince Busam
2008-06-12 1:45 ` Simon Horman
2008-06-12 13:31 ` Julius Volz
2008-06-12 13:38 ` Patrick McHardy
2008-06-12 15:34 ` Julius Volz
2008-06-12 15:41 ` Julius Volz
2008-06-12 15:46 ` Patrick McHardy
2008-06-12 19:33 ` Julius Volz
2008-06-13 6:26 ` Simon Horman
2008-06-13 14:17 ` Julius Volz
2008-06-13 15:14 ` Patrick McHardy
2008-06-16 0:14 ` Julius Volz
2008-06-16 11:47 ` Patrick McHardy
2008-06-16 12:13 ` Julius Volz
2008-06-16 23:19 ` Julius Volz
2008-06-17 11:52 ` Patrick McHardy
2008-06-17 17:18 ` Julius Volz
2008-06-17 20:08 ` Patrick McHardy
2008-06-17 22:47 ` Julius Volz
2008-06-18 8:57 ` Patrick McHardy
2008-06-18 14:17 ` Julius Volz
2008-06-18 14:19 ` Patrick McHardy
2008-06-18 14:27 ` Julius Volz
2008-06-18 14:30 ` Patrick McHardy
2008-06-18 14:36 ` Julius Volz
2008-06-30 12:01 ` Julius Volz
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=1213204329-10973-17-git-send-email-juliusv@google.com \
--to=juliusv@google.com \
--cc=davem@davemloft.net \
--cc=horms@verge.net.au \
--cc=lvs-devel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=vbusam@google.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;
as well as URLs for NNTP newsgroup(s).