From 72ddcb672423ce3c77087fef96703429a3ef8edd Mon Sep 17 00:00:00 2001 From: John Ousterhout Date: Fri, 23 Dec 2022 11:32:45 -0800 Subject: [PATCH] Implemented HOMA_GRO_SHORT_BYPASS policy --- homa_impl.h | 21 +++++++++++++--- homa_offload.c | 4 ++- test/unit_homa_offload.c | 53 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/homa_impl.h b/homa_impl.h index ce7fc4bb..88bae083 100644 --- a/homa_impl.h +++ b/homa_impl.h @@ -1874,8 +1874,22 @@ struct homa { /* Bits that can be specified for gro_policy. These were created for * testing, in order to evaluate various possible policies; you almost * certainly should not use any value other than HOMA_GRO_NORMAL. - * If you want to know what the bits mean, read the code of - * homa_offload.c. + * HOMA_GRO_BYPASS: Pass all incoming packets directly to + * homa_softirq during GRO; this bypasses + * the SoftIRQ dispatching mechanism as well + * as the network and IP stack layers. + * HOMA_GRO_SAME_CORE If isolated packets arrive (not part of + * a batch) use the GRO core for SoftIRQ also. + * HOMA_GRO_IDLE Use old mechanism for selecting an idle + * core for SoftIRQ (deprecated). + * HOMA_GRO_NEXT Always use the next core in circular + * order for SoftIRQ (deprecated). + * HOMA_GRO_IDLE_NEW Use the new mechanism for selecting an + * idle core for SoftIRQ. + * HOMA_GRO_FAST_GRANTS Pass all grant I can see immediately to + * homa_softirq during GRO. + * HOMA_GRO_SHORT_BYPASS Pass all short packets directly to + * homa_softirq during GR). */ #define HOMA_GRO_BYPASS 1 #define HOMA_GRO_SAME_CORE 2 @@ -1883,8 +1897,9 @@ struct homa { #define HOMA_GRO_NEXT 8 #define HOMA_GRO_IDLE_NEW 16 #define HOMA_GRO_FAST_GRANTS 32 + #define HOMA_GRO_SHORT_BYPASS 64 #define HOMA_GRO_NORMAL (HOMA_GRO_SAME_CORE|HOMA_GRO_IDLE_NEW \ - |HOMA_GRO_FAST_GRANTS) + |HOMA_GRO_SHORT_BYPASS) /* * @gro_busy_usecs: try not to schedule SoftIRQ processing on a core diff --git a/homa_offload.c b/homa_offload.c index 09a17b09..32b1a8da 100644 --- a/homa_offload.c +++ b/homa_offload.c @@ -184,7 +184,9 @@ struct sk_buff *homa_gro_receive(struct list_head *held_list, core->last_active = get_cycles(); - if (homa->gro_policy & HOMA_GRO_BYPASS) { + if ((homa->gro_policy & HOMA_GRO_BYPASS) + || ((homa->gro_policy & HOMA_GRO_SHORT_BYPASS) + && (skb->len < 1400))) { homa_softirq(skb); /* This return value indicates that we have freed skb. */ diff --git a/test/unit_homa_offload.c b/test/unit_homa_offload.c index ad082dca..65c321ac 100644 --- a/test/unit_homa_offload.c +++ b/test/unit_homa_offload.c @@ -57,8 +57,7 @@ FIXTURE_SETUP(homa_offload) } self->napi.gro_bitmask = 0; - self->skb = mock_skb_new(&self->ip, &self->header.common, 1400, - self->header.seg.offset); + self->skb = mock_skb_new(&self->ip, &self->header.common, 1400, 2000); NAPI_GRO_CB(self->skb)->same_flow = 0; NAPI_GRO_CB(self->skb)->last = self->skb; NAPI_GRO_CB(self->skb)->count = 1; @@ -87,6 +86,7 @@ FIXTURE_TEARDOWN(homa_offload) unit_teardown(); } + TEST_F(homa_offload, homa_gro_receive__fast_grant_optimization) { struct in6_addr client_ip = unit_get_in_addr("196.168.0.1"); @@ -124,6 +124,55 @@ TEST_F(homa_offload, homa_gro_receive__fast_grant_optimization) EXPECT_STREQ("", unit_log_get()); kfree_skb(skb); } +TEST_F(homa_offload, homa_gro_receive__HOMA_GRO_SHORT_BYPASS) +{ + struct in6_addr client_ip = unit_get_in_addr("196.168.0.1"); + struct in6_addr server_ip = unit_get_in_addr("1.2.3.4"); + int client_port = 40000; + int server_port = 99; + __u64 client_id = 1234; + __u64 server_id = 1235; + struct data_header h = {.common = { + .sport = htons(40000), .dport = htons(server_port), + .type = DATA, + .sender_id = cpu_to_be64(client_id)}, + .message_length = htonl(10000), + .incoming = htonl(10000), .cutoff_version = 0, + .retransmit = 0, + .seg = {.offset = htonl(2000), + .segment_length = htonl(1400), + .ack = {0, 0, 0}}}; + struct sk_buff *skb, *skb2, *skb3; + + struct homa_rpc *srpc = unit_server_rpc(&self->hsk, UNIT_RCVD_ONE_PKT, + &client_ip, &server_ip, client_port, server_id, 10000, + 200); + ASSERT_NE(NULL, srpc); + unit_log_clear(); + + /* First attempt: HOMA_GRO_SHORT_BYPASS not enabled. */ + skb = mock_skb_new(&self->ip, &h.common, 1400, 2000); + struct sk_buff *result = homa_gro_receive(&self->empty_list, skb); + EXPECT_EQ(0, -PTR_ERR(result)); + EXPECT_EQ(8600, srpc->msgin.bytes_remaining); + + /* Second attempt: HOMA_GRO_SHORT_BYPASS enabled but packet too long. */ + self->homa.gro_policy |= HOMA_GRO_SHORT_BYPASS; + skb2 = mock_skb_new(&self->ip, &h.common, 1400, 3000); + result = homa_gro_receive(&self->empty_list, skb2); + EXPECT_EQ(0, -PTR_ERR(result)); + EXPECT_EQ(8600, srpc->msgin.bytes_remaining); + + /* Third attempt: bypass should happen. */ + h.seg.segment_length = htonl(100); + skb3 = mock_skb_new(&self->ip, &h.common, 100, 4000); + result = homa_gro_receive(&self->empty_list, skb3); + EXPECT_EQ(EINPROGRESS, -PTR_ERR(result)); + EXPECT_EQ(8500, srpc->msgin.bytes_remaining); + + kfree_skb(skb); + kfree_skb(skb2); +} TEST_F(homa_offload, homa_gro_receive__no_held_skb) { struct sk_buff *skb;