Skip to content

Commit 0f1becc

Browse files
committed
modified: homa_impl.h
modified: homa_offload.c modified: homa_offload.h modified: homa_outgoing.c modified: homa_plumbing.c modified: homa_qdisc.c modified: homa_sock.c modified: homa_wire.h modified: util/cp_node.cc modified: util/homa_test.cc modified: util/server.cc
1 parent 690e7d5 commit 0f1becc

11 files changed

Lines changed: 722 additions & 23 deletions

‎homa_impl.h‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,13 @@ struct homa {
358358
*/
359359
int hijack_tcp;
360360

361+
/**
362+
* @hijack_udp: Non-zero means encapsulate outgoing Homa packets
363+
* as UDP packets (i.e. use UDP as the IP protocol). Set externally
364+
* via sysctl.
365+
*/
366+
int hijack_udp;
367+
361368
/**
362369
* @max_gro_skbs: Maximum number of socket buffers that can be
363370
* aggregated by the GRO mechanism. Set externally via sysctl.
@@ -665,7 +672,9 @@ static inline bool is_homa_pkt(struct sk_buff *skb)
665672
ip_hdr(skb)->protocol;
666673
return (protocol == IPPROTO_HOMA ||
667674
(protocol == IPPROTO_TCP &&
668-
tcp_hdr(skb)->urg_ptr == htons(HOMA_TCP_URGENT)));
675+
tcp_hdr(skb)->urg_ptr == htons(HOMA_TCP_URGENT)) ||
676+
(protocol == IPPROTO_UDP &&
677+
tcp_hdr(skb)->urg_ptr == htons(HOMA_UDP_URGENT)));
669678
return protocol == IPPROTO_HOMA;
670679
}
671680
#endif /* See strip.py */

‎homa_offload.c‎

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ static const struct net_offload *tcp6_net_offload;
3737
*/
3838
static struct net_offload hook_tcp_net_offload;
3939
static struct net_offload hook_tcp6_net_offload;
40+
41+
/* Pointers to UDP's net_offload structures. NULL means homa_gro_hook_udp
42+
* hasn't been called yet.
43+
*/
44+
static const struct net_offload *udp_net_offload;
45+
static const struct net_offload *udp6_net_offload;
46+
47+
/*
48+
* Identical to *udp_net_offload except that the gro_receive function
49+
* has been replaced.
50+
*/
51+
static struct net_offload hook_udp_net_offload;
52+
static struct net_offload hook_udp6_net_offload;
4053
#endif /* See strip.py */
4154

4255
/**
@@ -167,6 +180,82 @@ struct sk_buff *homa_tcp_gro_receive(struct list_head *held_list,
167180
return homa_gro_receive(held_list, skb);
168181
}
169182

183+
/**
184+
* homa_gro_hook_udp() - Arranges for UDP gro_receive calls to be
185+
* mediated by this file, so that Homa-over-UDP packets can be retrieved
186+
* and funneled through Homa.
187+
*/
188+
void homa_gro_hook_udp(void)
189+
{
190+
if (udp_net_offload)
191+
return;
192+
193+
pr_notice("Homa setting up UDP hijacking\n");
194+
rcu_read_lock();
195+
udp_net_offload = rcu_dereference(inet_offloads[IPPROTO_UDP]);
196+
hook_udp_net_offload = *udp_net_offload;
197+
hook_udp_net_offload.callbacks.gro_receive = homa_udp_gro_receive;
198+
inet_offloads[IPPROTO_UDP] = (struct net_offload __rcu *)
199+
&hook_udp_net_offload;
200+
201+
udp6_net_offload = rcu_dereference(inet6_offloads[IPPROTO_UDP]);
202+
hook_udp6_net_offload = *udp6_net_offload;
203+
hook_udp6_net_offload.callbacks.gro_receive = homa_udp_gro_receive;
204+
inet6_offloads[IPPROTO_UDP] = (struct net_offload __rcu *)
205+
&hook_udp6_net_offload;
206+
rcu_read_unlock();
207+
}
208+
209+
/**
210+
* homa_gro_unhook_udp() - Reverses the effects of a previous call to
211+
* homa_gro_hook_udp, so that UDP packets are now passed directly to
212+
* UDP's gro_receive function without mediation.
213+
*/
214+
void homa_gro_unhook_udp(void)
215+
{
216+
if (!udp_net_offload)
217+
return;
218+
pr_notice("Homa cancelling UDP hijacking\n");
219+
inet_offloads[IPPROTO_UDP] = (struct net_offload __rcu *)
220+
udp_net_offload;
221+
udp_net_offload = NULL;
222+
inet6_offloads[IPPROTO_UDP] = (struct net_offload __rcu *)
223+
udp6_net_offload;
224+
udp6_net_offload = NULL;
225+
}
226+
227+
/**
228+
* homa_udp_gro_receive() - Invoked instead of UDP's normal gro_receive
229+
* function when hooking is enabled. Identifies Homa-over-UDP packets and
230+
* passes them to Homa; sends real UDP packets to UDP's gro_receive function.
231+
* @held_list: Pointer to header for list of packets that are being
232+
* held for possible GRO merging.
233+
* @skb: The newly arrived packet.
234+
*/
235+
struct sk_buff *homa_udp_gro_receive(struct list_head *held_list,
236+
struct sk_buff *skb)
237+
{
238+
struct homa_common_hdr *h = (struct homa_common_hdr *)
239+
skb_transport_header(skb);
240+
241+
if (h->flags != HOMA_UDP_FLAGS ||
242+
ntohs(h->urgent) != HOMA_UDP_URGENT)
243+
return udp_net_offload->callbacks.gro_receive(held_list, skb);
244+
245+
/* Change the packet's IP protocol to Homa so that it will get
246+
* dispatched directly to Homa in the future.
247+
*/
248+
if (skb_is_ipv6(skb)) {
249+
ipv6_hdr(skb)->nexthdr = IPPROTO_HOMA;
250+
} else {
251+
ip_hdr(skb)->check = ~csum16_add(csum16_sub(~ip_hdr(skb)->check,
252+
htons(ip_hdr(skb)->protocol)),
253+
htons(IPPROTO_HOMA));
254+
ip_hdr(skb)->protocol = IPPROTO_HOMA;
255+
}
256+
return homa_gro_receive(held_list, skb);
257+
}
258+
170259
/**
171260
* homa_set_softirq_cpu() - Arrange for SoftIRQ processing of a packet to
172261
* occur on a specific core (creates a socket flow table entry for the core,

‎homa_offload.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ void homa_gro_gen3(struct homa *homa, struct sk_buff *skb);
7878
#ifndef __STRIP__ /* See strip.py */
7979
void homa_gro_hook_tcp(void);
8080
void homa_gro_unhook_tcp(void);
81+
void homa_gro_hook_udp(void);
82+
void homa_gro_unhook_udp(void);
8183
#endif /* See strip.py */
8284
struct sk_buff *homa_gro_receive(struct list_head *gro_list,
8385
struct sk_buff *skb);
@@ -90,6 +92,8 @@ void homa_set_softirq_cpu(struct sk_buff *skb, int cpu);
9092
#ifndef __STRIP__ /* See strip.py */
9193
struct sk_buff *homa_tcp_gro_receive(struct list_head *held_list,
9294
struct sk_buff *skb);
95+
struct sk_buff *homa_udp_gro_receive(struct list_head *held_list,
96+
struct sk_buff *skb);
9397
#endif /* See strip.py */
9498

9599
#endif /* _HOMA_OFFLOAD_H */

‎homa_outgoing.c‎

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "homa_wire.h"
1111

1212
#ifndef __STRIP__ /* See strip.py */
13+
#include <net/udp.h>
1314
#include "homa_pacer.h"
1415
#include "homa_qdisc.h"
1516
#include "homa_skb.h"
@@ -49,6 +50,45 @@ static inline void homa_set_hijack(struct sk_buff *skb, struct homa_peer *peer,
4950
h->checksum = ~tcp_v4_check(skb->len, peer->flow.u.ip4.saddr,
5051
peer->flow.u.ip4.daddr, 0);
5152
}
53+
54+
/**
55+
* homa_set_udp_hijack() - Set fields in an outgoing Homa packet that are
56+
* needed for UDP hijacking to work properly. Similar to homa_set_hijack()
57+
* but uses IPPROTO_UDP for checksumming and writes a UDP length/checksum
58+
* overlay at bytes 4-7 of the transport header.
59+
* @skb: Packet buffer in which to set fields.
60+
* @peer: Peer that contains source and destination addresses for the packet.
61+
* @ipv6: True means the packet is going to be sent via IPv6; false means
62+
* IPv4.
63+
*/
64+
static inline void homa_set_udp_hijack(struct sk_buff *skb,
65+
struct homa_peer *peer, bool ipv6)
66+
{
67+
struct homa_common_hdr *h;
68+
__be16 *udp_len_csum;
69+
70+
h = (struct homa_common_hdr *)skb_transport_header(skb);
71+
h->flags = HOMA_UDP_FLAGS;
72+
h->urgent = htons(HOMA_UDP_URGENT);
73+
74+
/* Write UDP length and checksum at bytes 4-7 of transport header. */
75+
udp_len_csum = (__be16 *)(skb_transport_header(skb) + 4);
76+
udp_len_csum[0] = htons(skb->len); /* UDP length */
77+
udp_len_csum[1] = 0; /* UDP checksum (0 = none) */
78+
79+
/* Arrange for proper UDP checksumming. */
80+
skb->ip_summed = CHECKSUM_PARTIAL;
81+
skb->csum_start = skb_transport_header(skb) - skb->head;
82+
skb->csum_offset = offsetof(struct homa_common_hdr, checksum);
83+
if (ipv6)
84+
h->checksum = ~csum_ipv6_magic(&peer->flow.u.ip6.saddr,
85+
&peer->flow.u.ip6.daddr,
86+
skb->len, IPPROTO_UDP, 0);
87+
else
88+
h->checksum = ~udp_v4_check(skb->len,
89+
peer->flow.u.ip4.saddr,
90+
peer->flow.u.ip4.daddr, 0);
91+
}
5292
#endif /* See strip.py */
5393

5494
/**
@@ -204,7 +244,10 @@ struct sk_buff *homa_tx_data_pkt_alloc(struct homa_rpc *rpc,
204244
IF_NO_STRIP(h->cutoff_version = rpc->peer->cutoff_version);
205245
h->retransmit = 0;
206246
#ifndef __STRIP__ /* See strip.py */
207-
h->seg.offset = htonl(-1);
247+
if (hsk->sock.sk_protocol == IPPROTO_UDP)
248+
h->seg.offset = htonl(offset);
249+
else
250+
h->seg.offset = htonl(-1);
208251
#else /* See strip.py */
209252
h->seg.offset = htonl(offset);
210253
#endif /* See strip.py */
@@ -219,7 +262,8 @@ struct sk_buff *homa_tx_data_pkt_alloc(struct homa_rpc *rpc,
219262
homa_info->rpc = rpc;
220263

221264
#ifndef __STRIP__ /* See strip.py */
222-
if (segs > 1 && hsk->sock.sk_protocol != IPPROTO_TCP) {
265+
if (segs > 1 && hsk->sock.sk_protocol != IPPROTO_TCP
266+
&& hsk->sock.sk_protocol != IPPROTO_UDP) {
223267
#else /* See strip.py */
224268
if (segs > 1) {
225269
#endif /* See strip.py */
@@ -322,10 +366,13 @@ int homa_message_out_fill(struct homa_rpc *rpc, struct iov_iter *iter, int xmit)
322366
* if no hijacking).
323367
*/
324368
if (rpc->hsk->sock.sk_protocol == IPPROTO_TCP) {
325-
/* Hijacking */
369+
/* TCP Hijacking */
326370
segs_per_gso = gso_size - rpc->hsk->ip_header_length
327371
- sizeof(struct homa_data_hdr);
328372
do_div(segs_per_gso, max_seg_data);
373+
} else if (rpc->hsk->sock.sk_protocol == IPPROTO_UDP) {
374+
/* UDP Hijacking: one segment per GSO */
375+
segs_per_gso = 1;
329376
} else {
330377
/* No hijacking */
331378
segs_per_gso = gso_size - rpc->hsk->ip_header_length -
@@ -509,12 +556,18 @@ int __homa_xmit_control(void *contents, size_t length, struct homa_peer *peer,
509556
homa_set_doff(skb, length);
510557
#ifndef __STRIP__ /* See strip.py */
511558
if (hsk->inet.sk.sk_family == AF_INET6) {
512-
homa_set_hijack(skb, peer, true);
559+
if (hsk->sock.sk_protocol == IPPROTO_UDP)
560+
homa_set_udp_hijack(skb, peer, true);
561+
else
562+
homa_set_hijack(skb, peer, true);
513563
result = ip6_xmit(&hsk->inet.sk, skb, &peer->flow.u.ip6, 0,
514564
NULL, hsk->homa->priority_map[priority] << 5,
515565
0);
516566
} else {
517-
homa_set_hijack(skb, peer, false);
567+
if (hsk->sock.sk_protocol == IPPROTO_UDP)
568+
homa_set_udp_hijack(skb, peer, false);
569+
else
570+
homa_set_hijack(skb, peer, false);
518571

519572
/* This will find its way to the DSCP field in the IPv4 hdr. */
520573
hsk->inet.tos = hsk->homa->priority_map[priority] << 5;
@@ -721,7 +774,10 @@ void __homa_xmit_data(struct sk_buff *skb, struct homa_rpc *rpc)
721774
tt_addr(rpc->peer->addr), rpc->id,
722775
homa_get_skb_info(skb)->offset);
723776
#ifndef __STRIP__ /* See strip.py */
724-
homa_set_hijack(skb, rpc->peer, true);
777+
if (rpc->hsk->sock.sk_protocol == IPPROTO_UDP)
778+
homa_set_udp_hijack(skb, rpc->peer, true);
779+
else
780+
homa_set_hijack(skb, rpc->peer, true);
725781
err = ip6_xmit(&rpc->hsk->inet.sk, skb, &rpc->peer->flow.u.ip6,
726782
0, NULL,
727783
rpc->hsk->homa->priority_map[priority] << 5, 0);
@@ -736,7 +792,10 @@ void __homa_xmit_data(struct sk_buff *skb, struct homa_rpc *rpc)
736792
homa_get_skb_info(skb)->offset);
737793

738794
#ifndef __STRIP__ /* See strip.py */
739-
homa_set_hijack(skb, rpc->peer, false);
795+
if (rpc->hsk->sock.sk_protocol == IPPROTO_UDP)
796+
homa_set_udp_hijack(skb, rpc->peer, false);
797+
else
798+
homa_set_hijack(skb, rpc->peer, false);
740799
rpc->hsk->inet.tos =
741800
rpc->hsk->homa->priority_map[priority] << 5;
742801
err = ip_queue_xmit(&rpc->hsk->inet.sk, skb, &rpc->peer->flow);

‎homa_plumbing.c‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,13 @@ static struct ctl_table homa_ctl_table[] = {
257257
.mode = 0644,
258258
.proc_handler = homa_dointvec
259259
},
260+
{
261+
.procname = "hijack_udp",
262+
.data = OFFSET(hijack_udp),
263+
.maxlen = sizeof(int),
264+
.mode = 0644,
265+
.proc_handler = homa_dointvec
266+
},
260267
{
261268
.procname = "link_mbps",
262269
.data = OFFSET(link_mbps),
@@ -642,6 +649,7 @@ int __init homa_load(void)
642649

643650
#ifndef __STRIP__ /* See strip.py */
644651
homa_gro_hook_tcp();
652+
homa_gro_hook_udp();
645653
#endif /* See strip.py */
646654
#ifndef __UPSTREAM__ /* See strip.py */
647655
tt_set_temp(homa->temp);
@@ -695,6 +703,7 @@ void __exit homa_unload(void)
695703

696704
#ifndef __STRIP__ /* See strip.py */
697705
homa_gro_unhook_tcp();
706+
homa_gro_unhook_udp();
698707
#endif /* See strip.py */
699708
if (timer_kthread) {
700709
timer_thread_exit = 1;

‎homa_qdisc.c‎

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -557,15 +557,17 @@ bool homa_qdisc_can_bypass(struct sk_buff *skb, struct homa_qdisc *q)
557557
bool result;
558558
int element;
559559

560-
/* Collect information from skb. If it isn't a TCP packet then
560+
/* Collect information from skb. If it isn't a TCP or UDP packet then
561561
* reordering constraints are unknown so deny reordering.
562562
*/
563563
if (skb->protocol == htons(ETH_P_IP)) {
564-
if (ip_hdr(skb)->protocol != IPPROTO_TCP)
564+
if (ip_hdr(skb)->protocol != IPPROTO_TCP
565+
&& ip_hdr(skb)->protocol != IPPROTO_UDP)
565566
return false;
566567
daddr = ip_hdr(skb)->daddr;
567568
} else if (skb->protocol == htons(ETH_P_IPV6)) {
568-
if (ipv6_hdr(skb)->nexthdr != IPPROTO_TCP)
569+
if (ipv6_hdr(skb)->nexthdr != IPPROTO_TCP
570+
&& ipv6_hdr(skb)->nexthdr != IPPROTO_UDP)
569571
return false;
570572
daddr = ipv6_hdr(skb)->daddr.in6_u.u6_addr32[0] ^
571573
ipv6_hdr(skb)->daddr.in6_u.u6_addr32[1] ^
@@ -591,11 +593,13 @@ bool homa_qdisc_can_bypass(struct sk_buff *skb, struct homa_qdisc *q)
591593
skb_queue_walk(&q->deferred_tcp, skb2) {
592594
element++;
593595
if (skb2->protocol == htons(ETH_P_IP)) {
594-
if (ip_hdr(skb2)->protocol != IPPROTO_TCP)
596+
if (ip_hdr(skb2)->protocol != IPPROTO_TCP
597+
&& ip_hdr(skb2)->protocol != IPPROTO_UDP)
595598
continue;
596599
daddr2 = ip_hdr(skb2)->daddr;
597600
} else if (skb2->protocol == htons(ETH_P_IPV6)) {
598-
if (ipv6_hdr(skb2)->nexthdr != IPPROTO_TCP)
601+
if (ipv6_hdr(skb2)->nexthdr != IPPROTO_TCP
602+
&& ipv6_hdr(skb2)->nexthdr != IPPROTO_UDP)
599603
continue;
600604
daddr2 = ipv6_hdr(skb2)->daddr.in6_u.u6_addr32[0] ^
601605
ipv6_hdr(skb2)->daddr.in6_u.u6_addr32[1] ^
@@ -757,8 +761,9 @@ int homa_qdisc_xmit_deferred_tcp(struct homa_qdisc_dev *qdev)
757761

758762
pkt_len = qdisc_pkt_len(skb);
759763
homa_qdisc_update_link_idle(qdev, pkt_len, -1);
760-
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
761-
tt_record_tcp("homa_qdisc_pacer requeued TCP packet from "
764+
if (ip_hdr(skb)->protocol == IPPROTO_TCP
765+
|| ip_hdr(skb)->protocol == IPPROTO_UDP)
766+
tt_record_tcp("homa_qdisc_pacer requeued TCP/UDP packet from "
762767
"0x%x to 0x%x, data bytes %d, seq/ack %u",
763768
skb, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
764769
homa_qdisc_schedule_skb(skb, q->qdisc);

‎homa_sock.c‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ int homa_sock_init(struct homa_sock *hsk)
164164
#ifndef __STRIP__ /* See strip.py */
165165
if (homa->hijack_tcp)
166166
hsk->sock.sk_protocol = IPPROTO_TCP;
167+
else if (homa->hijack_udp)
168+
hsk->sock.sk_protocol = IPPROTO_UDP;
167169
#endif /* See strip.py */
168170

169171
/* Do things requiring memory allocation before locking the socket,

0 commit comments

Comments
 (0)