This repository has been archived by the owner on May 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
homa_impl.h
2886 lines (2516 loc) · 89.5 KB
/
homa_impl.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* Copyright (c) 2019-2022 Stanford University
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* Copyright (c) 2022-2024, Tianyi Gao, University of Edinburgh
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* This file contains definitions that are shared across the files
* that implement Homa for Linux.
*/
#ifndef _HOMA_IMPL_H
#define _HOMA_IMPL_H
#pragma GCC diagnostic ignored "-Wpointer-sign"
#pragma GCC diagnostic ignored "-Wunused-variable"
#include <linux/bug.h>
#ifdef __UNIT_TEST__
#undef WARN
#define WARN(condition, format...)
#undef WARN_ON
#define WARN_ON(condition) ({ \
int __ret_warn_on = !!(condition); \
unlikely(__ret_warn_on); \
})
#undef WARN_ON_ONCE
#define WARN_ON_ONCE(condition) WARN_ON(condition)
#endif
#include <linux/audit.h>
#include <linux/icmp.h>
#include <linux/if_vlan.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/completion.h>
#include <linux/proc_fs.h>
#include <linux/sched/signal.h>
#include <linux/skbuff.h>
#include <linux/version.h>
#include <linux/socket.h>
#include <net/icmp.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <net/inet_common.h>
#include <net/gro.h>
#pragma GCC diagnostic warning "-Wpointer-sign"
#pragma GCC diagnostic warning "-Wunused-variable"
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0)
typedef unsigned int __poll_t;
#endif
#ifdef __UNIT_TEST__
#define spin_unlock mock_spin_unlock
extern void mock_spin_unlock(spinlock_t *lock);
#define get_cycles mock_get_cycles
extern cycles_t mock_get_cycles(void);
#define signal_pending(xxx) mock_signal_pending
extern int mock_signal_pending;
#define rcu_read_lock mock_rcu_read_lock
extern void mock_rcu_read_lock(void);
#define rcu_read_unlock mock_rcu_read_unlock
extern void mock_rcu_read_unlock(void);
#undef current
#define current current_task
#define kthread_complete_and_exit(comp, code)
#define kmalloc mock_kmalloc
extern void *mock_kmalloc(size_t size, gfp_t flags);
#endif
#include "homa.h"
#include "timetrace.h"
/* Forward declarations. */
struct homa_sock;
struct homa_rpc;
struct homa;
struct homa_peer;
struct homa_lcache;
/* Declarations used in this file, so they can't be made at the end. */
extern void homa_grantable_lock_slow(struct homa *homa);
extern void homa_peer_lock_slow(struct homa_peer *peer);
extern void homa_rpc_lock_slow(struct homa_rpc *rpc);
extern void homa_sock_lock_slow(struct homa_sock *hsk);
extern void homa_throttle_lock_slow(struct homa *homa);
/**
* enum homa_packet_type - Defines the possible types of Homa packets.
*
* See the xxx_header structs below for more information about each type.
*/
enum homa_packet_type {
DATA = 20,
GRANT = 21,
RESEND = 22,
UNKNOWN = 23,
BUSY = 24,
CUTOFFS = 25,
FREEZE = 26,
NEED_ACK = 27,
ACK = 28,
BOGUS = 29, /* Used only in unit tests. */
/* If you add a new type here, you must also do the following:
* 1. Change BOGUS so it is the highest opcode
* 2. Add support for the new opcode in homa_print_packet,
* homa_print_packet_short, homa_symbol_for_type, and mock_skb_new.
* 3. Add the header length to header_lengths in homa_plumbing.c.
*/
};
/** define HOMA_IPV4_HEADER_LENGTH - Size of IP header (V4). */
#define HOMA_IPV4_HEADER_LENGTH 20
/**
* define HOMA_SKB_EXTRA - How many bytes of additional space to allow at the
* beginning of each sk_buff, before the IP header. This includes room for a
* VLAN header and also includes some extra space, "just to be safe" (not
* really sure if this is needed).
*/
#define HOMA_SKB_EXTRA 40
/** define HOMA_VLAN_HEADER - Number of bytes in an Ethernet VLAN header. */
#define HOMA_VLAN_HEADER 20
/**
* define HOMA_ETH_OVERHEAD - Number of bytes per Ethernet packet for CRC,
* preamble, and inter-packet gap.
*/
#define HOMA_ETH_OVERHEAD 24
/**
* define HOMA_MIN_PKT_LENGTH - Every Homa packet must be padded to at least
* this length to meet Ethernet frame size limitations. This number includes
* Homa headers and data, but not IP or Ethernet headers.
*/
#define HOMA_MIN_PKT_LENGTH 26
/**
* define HOMA_MAX_HEADER - Number of bytes in the largest Homa header.
*/
#define HOMA_MAX_HEADER 90
/**
* define ETHERNET_MAX_PAYLOAD - A maximum length of an Ethernet packet,
* excluding preamble, frame delimeter, VLAN header, CRC, and interpacket gap;
* i.e. all of this space is available for Homa.
*/
#define ETHERNET_MAX_PAYLOAD 1500
/**
* define HOMA_MAX_PRIORITIES - The maximum number of priority levels that
* Homa can use (the actual number can be restricted to less than this at
* runtime). Changing this value will affect packet formats.
*/
#define HOMA_MAX_PRIORITIES 8
#define sizeof32(type) ((int) (sizeof(type)))
/** define CACHE_LINE_SIZE - The number of bytes in a cache line. */
#define CACHE_LINE_SIZE 64
/**
* define NUM_PEER_UNACKED_IDS - The number of ids for unacked RPCs that
* can be stored in a struct homa_peer.
*/
#define NUM_PEER_UNACKED_IDS 5
/**
* struct common_header - Wire format for the first bytes in every Homa
* packet. This must partially match the format of a TCP header so that
* Homa can piggyback on TCP segmentation offload (and possibly other
* features, such as RSS).
*/
struct common_header {
/**
* @sport: Port on source machine from which packet was sent.
* Must be in the same position as in a TCP header.
*/
__be16 sport;
/**
* @dport: Port on destination that is to receive packet. Must be
* in the same position as in a TCP header.
*/
__be16 dport;
/**
* @unused1: corresponds to the sequence number field in TCP headers;
* must not be used by Homa, in case it gets incremented during TCP
* offload.
*/
__be32 unused1;
__be32 unused2;
/**
* @doff: High order 4 bits holds the number of 4-byte chunks in a
* data_header (low-order bits unused). Used only for DATA packets;
* must be in the same position as the data offset in a TCP header.
*/
__u8 doff;
/** @type: One of the values of &enum packet_type. */
__u8 type;
__u16 unused3;
/**
* @checksum: not used by Homa, but must occupy the same bytes as
* the checksum in a TCP header (TSO may modify this?).*/
__be16 checksum;
__u16 unused4;
/**
* @sender_id: the identifier of this RPC as used on the sender (i.e.,
* if the low-order bit is set, then the sender is the server for
* this RPC).
*/
__be64 sender_id;
} __attribute__((packed));
/**
* struct homa_ack - Identifies an RPC that can be safely deleted by its
* server. After sending the response for an RPC, the server must retain its
* state for the RPC until it knows that the client has successfully
* received the entire response. An ack indicates this. Clients will
* piggyback acks on future data packets, but if a client doesn't send
* any data to the server, the server will eventually request an ack
* explicitly with a NEED_ACK packet, in which case the client will
* return an explicit ACK.
*/
struct homa_ack {
/**
* @id: The client's identifier for the RPC. 0 means this ack
* is invalid.
*/
__be64 client_id;
/** @client_port: The client-side port for the RPC. */
__be16 client_port;
/** @server_port: The server-side port for the RPC. */
__be16 server_port;
} __attribute__((packed));
/**
* struct data_segment - Wire format for a chunk of data that is part of
* a DATA packet. A single sk_buff can hold multiple data_segments in order
* to enable send and receive offload (the idea is to carry many network
* packets of info in a single traversal of the Linux networking stack).
* A DATA sk_buff contains a data_header followed by any number of
* data_segments.
*/
struct data_segment {
/**
* @offset: Offset within message of the first byte of data in
* this segment. Segments within an sk_buff are not guaranteed
* to be in order.
*/
__be32 offset;
/** @segment_length: Number of bytes of data in this segment. */
__be32 segment_length;
/** @ack: If the @client_id field is nonzero, provides info about
* an RPC that the recipient can now safely free.
*/
struct homa_ack ack;
/** @data: the payload of this segment. */
char data[0];
} __attribute__((packed));
/* struct data_header - Overall header format for a DATA sk_buff, which
* contains this header followed by any number of data_segments.
*/
struct data_header {
struct common_header common;
/** @message_length: Total #bytes in the *message* */
__be32 message_length;
/**
* @incoming: The receiver can expect the sender to send all of the
* bytes in the message up to at least this offset (exclusive),
* even without additional grants. This includes unscheduled
* bytes, granted bytes, plus any additional bytes the sender
* transmits unilaterally (e.g., to send batches, such as with GSO).
*/
__be32 incoming;
/**
* @cutoff_version: The cutoff_version from the most recent
* CUTOFFS packet that the source of this packet has received
* from the destination of this packet, or 0 if the source hasn't
* yet received a CUTOFFS packet.
*/
__be16 cutoff_version;
/**
* @retransmit: 1 means this packet was sent in response to a RESEND
* (it has already been sent previously).
*/
__u8 retransmit;
__u8 pad;
/** @seg: First of possibly many segments */
struct data_segment seg;
} __attribute__((packed));
_Static_assert(sizeof(struct data_header) <= HOMA_MAX_HEADER,
"data_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
_Static_assert(sizeof(struct data_header) >= HOMA_MIN_PKT_LENGTH,
"data_header too small: Homa doesn't currently have code"
"to pad data packets");
_Static_assert(((sizeof(struct data_header) - sizeof(struct data_segment))
& 0x3) == 0,
" data_header length not a multiple of 4 bytes (required "
"for TCP/TSO compatibility");
/**
* struct grant_header - Wire format for GRANT packets, which are sent by
* the receiver back to the sender to indicate that the sender may transmit
* additional bytes in the message.
*/
struct grant_header {
/** @common: Fields common to all packet types. */
struct common_header common;
/**
* @offset: Byte offset within the message.
*
* The sender should now transmit all data up to (but not including)
* this offset ASAP, if it hasn't already.
*/
__be32 offset;
/**
* @priority: The sender should use this priority level for all future
* MESSAGE_FRAG packets for this message, until a GRANT is received
* with higher offset. Larger numbers indicate higher priorities.
*/
__u8 priority;
} __attribute__((packed));
_Static_assert(sizeof(struct grant_header) <= HOMA_MAX_HEADER,
"grant_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
/**
* struct resend_header - Wire format for RESEND packets.
*
* A RESEND is sent by the receiver when it believes that message data may
* have been lost in transmission (or if it is concerned that the sender may
* have crashed). The receiver should resend the specified portion of the
* message, even if it already sent it previously.
*/
struct resend_header {
/** @common: Fields common to all packet types. */
struct common_header common;
/**
* @offset: Offset within the message of the first byte of data that
* should be retransmitted.
*/
__be32 offset;
/**
* @length: Number of bytes of data to retransmit; this could specify
* a range longer than the total message size. Zero is a special case
* used by servers; in this case, there is no need to actually resend
* anything; the purpose of this packet is to trigger an UNKNOWN
* response if the client no longer cares about this RPC.
*/
__be32 length;
/**
* @priority: Packet priority to use.
*
* The sender should transmit all the requested data using this
* priority.
*/
__u8 priority;
} __attribute__((packed));
_Static_assert(sizeof(struct resend_header) <= HOMA_MAX_HEADER,
"resend_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
/**
* struct unknown_header - Wire format for UNKNOWN packets.
*
* An UNKNOWN packet is sent by either server or client when it receives a
* packet for an RPC that is unknown to it. When a client receives an
* UNKNOWN packet it will typically restart the RPC from the beginning;
* when a server receives an UNKNOWN packet it will typically discard its
* state for the RPC.
*/
struct unknown_header {
/** @common: Fields common to all packet types. */
struct common_header common;
} __attribute__((packed));
_Static_assert(sizeof(struct unknown_header) <= HOMA_MAX_HEADER,
"unknown_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
/**
* struct busy_header - Wire format for BUSY packets.
*
* These packets tell the recipient that the sender is still alive (even if
* it isn't sending data expected by the recipient).
*/
struct busy_header {
/** @common: Fields common to all packet types. */
struct common_header common;
} __attribute__((packed));
_Static_assert(sizeof(struct busy_header) <= HOMA_MAX_HEADER,
"busy_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
/**
* struct cutoffs_header - Wire format for CUTOFFS packets.
*
* These packets tell the recipient how to assign priorities to
* unscheduled packets.
*/
struct cutoffs_header {
/** @common: Fields common to all packet types. */
struct common_header common;
/**
* @unsched_cutoffs: priorities to use for unscheduled packets
* sent to the sender of this packet. See documentation for
* @homa.unsched_cutoffs for the meanings of these values.
*/
__be32 unsched_cutoffs[HOMA_MAX_PRIORITIES];
/**
* @cutoff_version: unique identifier associated with @unsched_cutoffs.
* Must be included in future DATA packets sent to the sender of
* this packet.
*/
__be16 cutoff_version;
} __attribute__((packed));
_Static_assert(sizeof(struct cutoffs_header) <= HOMA_MAX_HEADER,
"cutoffs_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
/**
* struct freeze_header - Wire format for FREEZE packets.
*
* These packets tell the recipient to freeze its timetrace; used
* for debugging.
*/
struct freeze_header {
/** @common: Fields common to all packet types. */
struct common_header common;
} __attribute__((packed));
_Static_assert(sizeof(struct freeze_header) <= HOMA_MAX_HEADER,
"freeze_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
/**
* struct need_ack_header - Wire format for NEED_ACK packets.
*
* These packets ask the recipient (a client) to return an ACK message if
* the packet's RPC is no longer active.
*/
struct need_ack_header {
/** @common: Fields common to all packet types. */
struct common_header common;
} __attribute__((packed));
_Static_assert(sizeof(struct need_ack_header) <= HOMA_MAX_HEADER,
"need_ack_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
/**
* struct ack_header - Wire format for ACK packets.
*
* These packets are sent from a client to a server to indicate that
* a set of RPCs is no longer active on the client, so the server can
* free any state it may have for them.
*/
struct ack_header {
/** @common: Fields common to all packet types. */
struct common_header common;
/** @num_acks: number of (leading) elements in @acks that are valid. */
__be16 num_acks;
struct homa_ack acks[NUM_PEER_UNACKED_IDS];
} __attribute__((packed));
_Static_assert(sizeof(struct ack_header) <= HOMA_MAX_HEADER,
"ack_header too large for HOMA_MAX_HEADER; must "
"adjust HOMA_MAX_HEADER");
/**
* struct homa_message_out - Describes a message (either request or response)
* for which this machine is the sender.
*/
struct homa_message_out {
/** @length: Total bytes in message (excluding headers). A value
* less than 0 means this structure is uninitialized and therefore
* not in use.*/
int length;
/**
* @packets: singly-linked list of all packets in message, linked
* using homa_next_skb. The list is in order of offset in the message
* (offset 0 first); each sk_buff can potentially contain multiple
* data_segments, which will be split into separate packets by GSO.
*/
struct sk_buff *packets;
/**
* @num_skbs: Total number of buffers in @packets. Will be 0 if
* @length is less than 0.
*/
int num_skbs;
/**
* @next_packet: Pointer within @request of the next packet to transmit.
*
* All packets before this one have already been sent. NULL means
* entire message has been sent.
*/
struct sk_buff *next_packet;
/**
* @unscheduled: Initial bytes of message that we'll send
* without waiting for grants. May be larger than @length;
*/
int unscheduled;
/**
* @granted: Total number of bytes we are currently permitted to
* send, including unscheduled bytes; must wait for grants before
* sending bytes at or beyond this position. Never larger than
* @length.
*/
int granted;
/** @priority: Priority level to use for future scheduled packets. */
__u8 sched_priority;
/**
* @init_cycles: Time in get_cycles units when this structure was
* initialized. Used to find the oldest outgoing message.
*/
__u64 init_cycles;
};
/**
* struct homa_message_in - Holds the state of a message received by
* this machine; used for both requests and responses.
*/
struct homa_message_in {
/**
* @total_length: Size of the entire message, in bytes. A value
* less than 0 means this structure is uninitialized and therefore
* not in use.
*/
int total_length;
/**
* @packets: DATA packets received for this message so far. The list
* is sorted in order of offset (head is lowest offset), but
* packets can be received out of order, so there may be times
* when there are holes in the list. Packets in this list contain
* exactly one data_segment.
*/
struct sk_buff_head packets;
/**
* @num_skbs: Total number of buffers in @packets. Will be 0 if
* @total_length is less than 0.
*/
int num_skbs;
/**
* @bytes_remaining: Amount of data for this message that has
* not yet been received; will determine the message's priority.
*/
int bytes_remaining;
/**
* @incoming: Total # of bytes of the message that the sender will
* transmit without additional grants. Never larger than @total_length.
* Note: this may not be modified without holding @homa->grantable_lock.
*/
int incoming;
/**
* @extra_incoming: zero unless this message is not on the grantable
* list; in that case it contains the number of bytes in this message
* that are incoming (i.e. either unscheduled or granted). Used to
* update homa->extra_incoming once the message has been fully
* received.
*/
int extra_incoming;
/** @priority: Priority level to include in future GRANTS. */
int priority;
/**
* @scheduled: True means some of the bytes of this message
* must be scheduled with grants.
*/
bool scheduled;
/**
* @possibly_in_grant_queue: True means this RPC may be linked
* into peer->grantable_rpcs. Zero means it can't possibly be in
* the list, so no need to check (which means acquiring a global
* lock) when cleaning up the RPC.
*/
bool possibly_in_grant_queue;
/**
* The offset within the message of the next byte to be copied
* out of the message to a user buffer.
*/
int xfer_offset;
/**
* The next buffer in @packets to consider when copying data out of
* the message to a user buffer (all skbs before this one have
* already been copied). NULL means we haven't yet transferred
* any data.
*/
struct sk_buff *xfer_skb;
/**
* @birth: get_cycles time when this RPC was added to the grantable
* list. Invalid if RPC isn't in the grantable list.
*/
__u64 birth;
};
/**
* struct homa_interest - Contains various information used while waiting
* for incoming messages (indicates what kinds of messages a particular
* thread is interested in receiving).
*/
struct homa_interest {
/**
* @thread: Thread that would like to receive a message. Will get
* woken up when a suitable message becomes available.
*/
struct task_struct *thread;
/**
* @rpc: If non-null, it identifies the RPC given by @id and
* @peer_addr, and that RPC is locked. Only set by
* homa_register_interests. This is a shortcut so
* homa_wait_for_message doesn't need to relock the RPC.
*/
struct homa_rpc *ready_rpc;
/**
* @id: Id of the RPC that was found, or zero if none. This variable
* is used for synchronization, and must be set after the variables
* below it. This variable and the others below are used later to
* look up and lock the RPC. It isn't always safe to pass the RPC
* itself: the locking rules create a window where the RPC could be
* deleted.
*/
atomic_long_t id;
/**
* @peer_addr: IP address of the peer for the matching RPC. Valid
* only if @id is nonzero.
*/
__be32 peer_addr;
/**
* @peer_port: Port of the peer for the matching RPC. Valid
* only if @id is nonzero.
*/
__u16 peer_port;
/**
* @reg_rpc: RPC whose @interest field points here, or
* NULL if none.
*/
struct homa_rpc *reg_rpc;
/**
* @request_links: For linking this object into
* &homa_sock.request_interests. The interest must not be linked
* on either this list or @response_links if @id is nonzero.
*/
struct list_head request_links;
/**
* @response_links: For linking this object into
* &homa_sock.request_interests.
*/
struct list_head response_links;
};
/**
* homa_interest_init() - Fill in default values for all of the fields
* of a struct homa_interest. Intended for testing.
* @interest: Struct to initialize.
*/
static void inline homa_interest_init(struct homa_interest *interest)
{
interest->thread = current;
interest->ready_rpc = NULL;
atomic_long_set(&interest->id, 0);
interest->reg_rpc = NULL;
interest->request_links.next = LIST_POISON1;
interest->response_links.next = LIST_POISON1;
}
/**
* struct homa_rpc - One of these structures exists for each active
* RPC. The same structure is used to manage both outgoing RPCs on
* clients and incoming RPCs on servers.
*/
struct homa_rpc {
/** @hsk: Socket that owns the RPC. */
struct homa_sock *hsk;
/** @lock: Used to synchronize modifications to this structure;
* points to the lock in hsk->client_rpc_buckets or
* hsk->server_rpc_buckets.
*/
struct spinlock *lock;
/**
* @state: The current state of this RPC:
*
* @RPC_OUTGOING: The RPC is waiting for @msgout to be transmitted
* to the peer.
* @RPC_INCOMING: The RPC is waiting for data @msgin to be received
* from the peer; at least one packet has already
* been received.
* @RPC_READY: @msgin is now complete; the next step is for
* the message to be read from the socket by the
* application.
* @RPC_IN_SERVICE: Used only for server RPCs: the request message
* has been read from the socket, but the response
* message has not yet been presented to the kernel.
* @RPC_DEAD: RPC has been deleted and is waiting to be
* reaped. In some cases, information in the RPC
* structure may be accessed in this state.
*
* Client RPCs pass through states in the following order:
* RPC_OUTGOING, RPC_INCOMING, RPC_READY, RPC_DEAD.
*
* Server RPCs pass through states in the following order:
* RPC_INCOMING, RPC_READY, RPC_IN_SERVICE, RPC_OUTGOING, RPC_DEAD.
*/
enum {
RPC_OUTGOING = 5,
RPC_INCOMING = 6,
RPC_READY = 7,
RPC_IN_SERVICE = 8,
RPC_DEAD = 9
} state;
/**
* @dont_reap: True means data is still being copied out of the
* RPC to a receiver, so it isn't safe to reap it yet.
*/
bool dont_reap;
/**
* @grants_in_progress: Count of active grant sends for this RPC;
* it's not safe to reap the RPC unless this value is zero.
* This variable is needed so that grantable_lock can be released
* while sending grants, to reduce contention.
*/
atomic_t grants_in_progress;
/**
* @peer: Information about the other machine (the server, if
* this is a client RPC, or the client, if this is a server RPC).
*/
struct homa_peer *peer;
/** @dport: Port number on @peer that will handle packets. */
__u16 dport;
/**
* @id: Unique identifier for the RPC among all those issued
* from its port. The low-order bit indicates whether we are
* server (1) or client (0) for this RPC.
*/
__u64 id;
/**
* @error: Only used on clients. If nonzero, then the RPC has
* failed and the value is a negative errno that describes the
* problem.
*/
int error;
/**
* @msgin: Information about the message we receive for this RPC
* (for server RPCs this is the request, for client RPCs this is the
* response).
*/
struct homa_message_in msgin;
/**
* @msgout: Information about the message we send for this RPC
* (for client RPCs this is the request, for server RPCs this is the
* response).
*/
struct homa_message_out msgout;
/**
* @hash_links: Used to link this object into a hash bucket for
* either @hsk->client_rpc_buckets (for a client RPC), or
* @hsk->server_rpc_buckets (for a server RPC).
*/
struct hlist_node hash_links;
/**
* @active_links: For linking this object into @hsk->active_rpcs.
* The next field will be LIST_POISON1 if this RPC hasn't yet been
* linked into @hsk->active_rpcs. Access with RCU.
*/
struct list_head active_links;
/** @dead_links: For linking this object into @hsk->dead_rpcs. */
struct list_head dead_links;
/**
* @interest: Describes a thread that wants to be notified when
* msgin is complete, or NULL if none.
*/
struct homa_interest *interest;
/**
* @ready_links: Used to link this object into
* &homa_sock.ready_requests or &homa_sock.ready_responses.
*/
struct list_head ready_links;
/**
* @grantable_links: Used to link this RPC into peer->grantable_rpcs.
* If this RPC isn't in peer->grantable_rpcs, this is an empty
* list pointing to itself.
*/
struct list_head grantable_links;
/**
* @throttled_links: Used to link this RPC into homa->throttled_rpcs.
* If this RPC isn't in homa->throttled_rpcs, this is an empty
* list pointing to itself.
*/
struct list_head throttled_links;
/**
* @silent_ticks: Number of times homa_timer has been invoked
* since the last time a packet indicating progress was received
* for this RPC, so we don't need to send a resend for a while.
*/
int silent_ticks;
/**
* @resend_timer_ticks: Value of homa->timer_ticks the last time
* we sent a RESEND for this RPC.
*/
__u32 resend_timer_ticks;
/**
* @done_timer_ticks: The value of homa->timer_ticks the first
* time we noticed that this (server) RPC is done (all response
* packets have been transmitted), so we're ready for an ack.
* Zero means we haven't reached that point yet.
*/
__u32 done_timer_ticks;
/**
* @magic: when the RPC is alive, this holds a distinct value that
* is unlikely to occur naturally. The value is cleared when the
* RPC is reaped, so we can detect accidental use of an RPC after
* it has been reaped.
*/
#define HOMA_RPC_MAGIC 0xdeadbeef
int magic;
/**
* @start_cycles: time (from get_cycles()) when this RPC was created.
* Used (sometimes) for testing.
*/
uint64_t start_cycles;
struct homals_context *homals_ctx;
};
/**
* homa_rpc_lock() - Acquire the lock for an RPC.
* @rpc: RPC to lock. Note: this function is only safe under
* limited conditions. The caller must ensure that the RPC
* cannot be reaped before the lock is acquired. It cannot
* do that by acquiring the socket lock, since that violates
* lock ordering constraints. One approach is to increment
* rpc->hsk->reap_disable. Don't use this function unless you
* are very sure what you are doing! See sync.txt for more
* info on locking.
*/
inline static void homa_rpc_lock(struct homa_rpc *rpc) {
if (!spin_trylock_bh(rpc->lock))
homa_rpc_lock_slow(rpc);
}
/**
* homa_rpc_unlock() - Release the lock for an RPC.
* @rpc: RPC to unlock.
*/
inline static void homa_rpc_unlock(struct homa_rpc *rpc) {
spin_unlock_bh(rpc->lock);
}
/**
* homa_rpc_validate() - Check to see if an RPC has been reaped (which
* would mean it is no longer valid); if so, crash the kernel with a stack
* trace.
* @rpc: RPC to validate.
*/
inline static void homa_rpc_validate(struct homa_rpc *rpc) {
if (rpc->magic == HOMA_RPC_MAGIC)
return;
printk(KERN_ERR "Accessing reaped Homa RPC!\n");
BUG();
}
/**
* define HOMA_SOCKTAB_BUCKETS - Number of hash buckets in a homa_socktab.
* Must be a power of 2.
*/
#define HOMA_SOCKTAB_BUCKETS 1024
/**
* struct homa_socktab - A hash table that maps from port numbers (either
* client or server) to homa_sock objects.
*
* This table is managed exclusively by homa_socktab.c, using RCU to
* minimize synchronization during lookups.
*/
struct homa_socktab {
/**
* @mutex: Controls all modifications to this object; not needed
* for socket lookups (RCU is used instead). Also used to
* synchronize port allocation.
*/
struct mutex write_lock;
/**
* @buckets: Heads of chains for hash table buckets. Chains
* consist of homa_socktab_link objects.
*/
struct hlist_head buckets[HOMA_SOCKTAB_BUCKETS];
};
/**
* struct homa_socktab_links - Used to link homa_socks into the hash chains