162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci========================= 462306a36Sopenharmony_ciStream Parser (strparser) 562306a36Sopenharmony_ci========================= 662306a36Sopenharmony_ci 762306a36Sopenharmony_ciIntroduction 862306a36Sopenharmony_ci============ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ciThe stream parser (strparser) is a utility that parses messages of an 1162306a36Sopenharmony_ciapplication layer protocol running over a data stream. The stream 1262306a36Sopenharmony_ciparser works in conjunction with an upper layer in the kernel to provide 1362306a36Sopenharmony_cikernel support for application layer messages. For instance, Kernel 1462306a36Sopenharmony_ciConnection Multiplexor (KCM) uses the Stream Parser to parse messages 1562306a36Sopenharmony_ciusing a BPF program. 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciThe strparser works in one of two modes: receive callback or general 1862306a36Sopenharmony_cimode. 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciIn receive callback mode, the strparser is called from the data_ready 2162306a36Sopenharmony_cicallback of a TCP socket. Messages are parsed and delivered as they are 2262306a36Sopenharmony_cireceived on the socket. 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ciIn general mode, a sequence of skbs are fed to strparser from an 2562306a36Sopenharmony_cioutside source. Message are parsed and delivered as the sequence is 2662306a36Sopenharmony_ciprocessed. This modes allows strparser to be applied to arbitrary 2762306a36Sopenharmony_cistreams of data. 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ciInterface 3062306a36Sopenharmony_ci========= 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciThe API includes a context structure, a set of callbacks, utility 3362306a36Sopenharmony_cifunctions, and a data_ready function for receive callback mode. The 3462306a36Sopenharmony_cicallbacks include a parse_msg function that is called to perform 3562306a36Sopenharmony_ciparsing (e.g. BPF parsing in case of KCM), and a rcv_msg function 3662306a36Sopenharmony_cithat is called when a full message has been completed. 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciFunctions 3962306a36Sopenharmony_ci========= 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci :: 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci strp_init(struct strparser *strp, struct sock *sk, 4462306a36Sopenharmony_ci const struct strp_callbacks *cb) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci Called to initialize a stream parser. strp is a struct of type 4762306a36Sopenharmony_ci strparser that is allocated by the upper layer. sk is the TCP 4862306a36Sopenharmony_ci socket associated with the stream parser for use with receive 4962306a36Sopenharmony_ci callback mode; in general mode this is set to NULL. Callbacks 5062306a36Sopenharmony_ci are called by the stream parser (the callbacks are listed below). 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci :: 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci void strp_pause(struct strparser *strp) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci Temporarily pause a stream parser. Message parsing is suspended 5762306a36Sopenharmony_ci and no new messages are delivered to the upper layer. 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci :: 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci void strp_unpause(struct strparser *strp) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci Unpause a paused stream parser. 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci :: 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci void strp_stop(struct strparser *strp); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci strp_stop is called to completely stop stream parser operations. 7062306a36Sopenharmony_ci This is called internally when the stream parser encounters an 7162306a36Sopenharmony_ci error, and it is called from the upper layer to stop parsing 7262306a36Sopenharmony_ci operations. 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci :: 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci void strp_done(struct strparser *strp); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci strp_done is called to release any resources held by the stream 7962306a36Sopenharmony_ci parser instance. This must be called after the stream processor 8062306a36Sopenharmony_ci has been stopped. 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci :: 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci int strp_process(struct strparser *strp, struct sk_buff *orig_skb, 8562306a36Sopenharmony_ci unsigned int orig_offset, size_t orig_len, 8662306a36Sopenharmony_ci size_t max_msg_size, long timeo) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci strp_process is called in general mode for a stream parser to 8962306a36Sopenharmony_ci parse an sk_buff. The number of bytes processed or a negative 9062306a36Sopenharmony_ci error number is returned. Note that strp_process does not 9162306a36Sopenharmony_ci consume the sk_buff. max_msg_size is maximum size the stream 9262306a36Sopenharmony_ci parser will parse. timeo is timeout for completing a message. 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci :: 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci void strp_data_ready(struct strparser *strp); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci The upper layer calls strp_tcp_data_ready when data is ready on 9962306a36Sopenharmony_ci the lower socket for strparser to process. This should be called 10062306a36Sopenharmony_ci from a data_ready callback that is set on the socket. Note that 10162306a36Sopenharmony_ci maximum messages size is the limit of the receive socket 10262306a36Sopenharmony_ci buffer and message timeout is the receive timeout for the socket. 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci :: 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci void strp_check_rcv(struct strparser *strp); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci strp_check_rcv is called to check for new messages on the socket. 10962306a36Sopenharmony_ci This is normally called at initialization of a stream parser 11062306a36Sopenharmony_ci instance or after strp_unpause. 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciCallbacks 11362306a36Sopenharmony_ci========= 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciThere are six callbacks: 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci :: 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci int (*parse_msg)(struct strparser *strp, struct sk_buff *skb); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci parse_msg is called to determine the length of the next message 12262306a36Sopenharmony_ci in the stream. The upper layer must implement this function. It 12362306a36Sopenharmony_ci should parse the sk_buff as containing the headers for the 12462306a36Sopenharmony_ci next application layer message in the stream. 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci The skb->cb in the input skb is a struct strp_msg. Only 12762306a36Sopenharmony_ci the offset field is relevant in parse_msg and gives the offset 12862306a36Sopenharmony_ci where the message starts in the skb. 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci The return values of this function are: 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ========= =========================================================== 13362306a36Sopenharmony_ci >0 indicates length of successfully parsed message 13462306a36Sopenharmony_ci 0 indicates more data must be received to parse the message 13562306a36Sopenharmony_ci -ESTRPIPE current message should not be processed by the 13662306a36Sopenharmony_ci kernel, return control of the socket to userspace which 13762306a36Sopenharmony_ci can proceed to read the messages itself 13862306a36Sopenharmony_ci other < 0 Error in parsing, give control back to userspace 13962306a36Sopenharmony_ci assuming that synchronization is lost and the stream 14062306a36Sopenharmony_ci is unrecoverable (application expected to close TCP socket) 14162306a36Sopenharmony_ci ========= =========================================================== 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci In the case that an error is returned (return value is less than 14462306a36Sopenharmony_ci zero) and the parser is in receive callback mode, then it will set 14562306a36Sopenharmony_ci the error on TCP socket and wake it up. If parse_msg returned 14662306a36Sopenharmony_ci -ESTRPIPE and the stream parser had previously read some bytes for 14762306a36Sopenharmony_ci the current message, then the error set on the attached socket is 14862306a36Sopenharmony_ci ENODATA since the stream is unrecoverable in that case. 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci :: 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci void (*lock)(struct strparser *strp) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci The lock callback is called to lock the strp structure when 15562306a36Sopenharmony_ci the strparser is performing an asynchronous operation (such as 15662306a36Sopenharmony_ci processing a timeout). In receive callback mode the default 15762306a36Sopenharmony_ci function is to lock_sock for the associated socket. In general 15862306a36Sopenharmony_ci mode the callback must be set appropriately. 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci :: 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci void (*unlock)(struct strparser *strp) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci The unlock callback is called to release the lock obtained 16562306a36Sopenharmony_ci by the lock callback. In receive callback mode the default 16662306a36Sopenharmony_ci function is release_sock for the associated socket. In general 16762306a36Sopenharmony_ci mode the callback must be set appropriately. 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci :: 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci rcv_msg is called when a full message has been received and 17462306a36Sopenharmony_ci is queued. The callee must consume the sk_buff; it can 17562306a36Sopenharmony_ci call strp_pause to prevent any further messages from being 17662306a36Sopenharmony_ci received in rcv_msg (see strp_pause above). This callback 17762306a36Sopenharmony_ci must be set. 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci The skb->cb in the input skb is a struct strp_msg. This 18062306a36Sopenharmony_ci struct contains two fields: offset and full_len. Offset is 18162306a36Sopenharmony_ci where the message starts in the skb, and full_len is the 18262306a36Sopenharmony_ci the length of the message. skb->len - offset may be greater 18362306a36Sopenharmony_ci then full_len since strparser does not trim the skb. 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci :: 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci int (*read_sock_done)(struct strparser *strp, int err); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci read_sock_done is called when the stream parser is done reading 19062306a36Sopenharmony_ci the TCP socket in receive callback mode. The stream parser may 19162306a36Sopenharmony_ci read multiple messages in a loop and this function allows cleanup 19262306a36Sopenharmony_ci to occur when exiting the loop. If the callback is not set (NULL 19362306a36Sopenharmony_ci in strp_init) a default function is used. 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci :: 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci void (*abort_parser)(struct strparser *strp, int err); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci This function is called when stream parser encounters an error 20062306a36Sopenharmony_ci in parsing. The default function stops the stream parser and 20162306a36Sopenharmony_ci sets the error in the socket if the parser is in receive callback 20262306a36Sopenharmony_ci mode. The default function can be changed by setting the callback 20362306a36Sopenharmony_ci to non-NULL in strp_init. 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ciStatistics 20662306a36Sopenharmony_ci========== 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ciVarious counters are kept for each stream parser instance. These are in 20962306a36Sopenharmony_cithe strp_stats structure. strp_aggr_stats is a convenience structure for 21062306a36Sopenharmony_ciaccumulating statistics for multiple stream parser instances. 21162306a36Sopenharmony_cisave_strp_stats and aggregate_strp_stats are helper functions to save 21262306a36Sopenharmony_ciand aggregate statistics. 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ciMessage assembly limits 21562306a36Sopenharmony_ci======================= 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ciThe stream parser provide mechanisms to limit the resources consumed by 21862306a36Sopenharmony_cimessage assembly. 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciA timer is set when assembly starts for a new message. In receive 22162306a36Sopenharmony_cicallback mode the message timeout is taken from rcvtime for the 22262306a36Sopenharmony_ciassociated TCP socket. In general mode, the timeout is passed as an 22362306a36Sopenharmony_ciargument in strp_process. If the timer fires before assembly completes 22462306a36Sopenharmony_cithe stream parser is aborted and the ETIMEDOUT error is set on the TCP 22562306a36Sopenharmony_cisocket if in receive callback mode. 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ciIn receive callback mode, message length is limited to the receive 22862306a36Sopenharmony_cibuffer size of the associated TCP socket. If the length returned by 22962306a36Sopenharmony_ciparse_msg is greater than the socket buffer size then the stream parser 23062306a36Sopenharmony_ciis aborted with EMSGSIZE error set on the TCP socket. Note that this 23162306a36Sopenharmony_cimakes the maximum size of receive skbuffs for a socket with a stream 23262306a36Sopenharmony_ciparser to be 2*sk_rcvbuf of the TCP socket. 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ciIn general mode the message length limit is passed in as an argument 23562306a36Sopenharmony_cito strp_process. 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciAuthor 23862306a36Sopenharmony_ci====== 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ciTom Herbert (tom@quantonium.net) 241