summaryrefslogtreecommitdiff
path: root/drivers/rmnet/perf/rmnet_perf_tcp_opt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rmnet/perf/rmnet_perf_tcp_opt.c')
-rw-r--r--drivers/rmnet/perf/rmnet_perf_tcp_opt.c182
1 files changed, 74 insertions, 108 deletions
diff --git a/drivers/rmnet/perf/rmnet_perf_tcp_opt.c b/drivers/rmnet/perf/rmnet_perf_tcp_opt.c
index 5dc2224..7c73aa1 100644
--- a/drivers/rmnet/perf/rmnet_perf_tcp_opt.c
+++ b/drivers/rmnet/perf/rmnet_perf_tcp_opt.c
@@ -27,7 +27,7 @@
#include "rmnet_perf_config.h"
/* Max number of bytes we allow tcp_opt to aggregate per flow */
-unsigned int rmnet_perf_tcp_opt_flush_limit __read_mostly = 65536;
+unsigned int rmnet_perf_tcp_opt_flush_limit __read_mostly = 65000;
module_param(rmnet_perf_tcp_opt_flush_limit, uint, 0644);
MODULE_PARM_DESC(rmnet_perf_tcp_opt_flush_limit,
"Max flush limiit for tcp_opt");
@@ -67,7 +67,7 @@ MODULE_PARM_DESC(rmnet_perf_tcp_opt_pkt_seq, "incoming pkt seq");
static bool
rmnet_perf_tcp_opt_tcp_flag_flush(struct rmnet_perf_pkt_info *pkt_info)
{
- struct tcphdr *tp = pkt_info->trns_hdr.tp;
+ struct tcphdr *tp = pkt_info->trans_hdr.tp;
if ((pkt_info->payload_len == 0 && tp->ack) || tp->cwr || tp->syn ||
tp->fin || tp->rst || tp->urg || tp->psh)
@@ -77,7 +77,6 @@ rmnet_perf_tcp_opt_tcp_flag_flush(struct rmnet_perf_pkt_info *pkt_info)
}
/* rmnet_perf_tcp_opt_pkt_can_be_merged() - Check if packet can be merged
- * @skb: Source socket buffer containing current MAP frames
* @flow_node: flow node meta data for checking condition
* @pkt_info: characteristics of the current packet
*
@@ -89,56 +88,44 @@ rmnet_perf_tcp_opt_tcp_flag_flush(struct rmnet_perf_pkt_info *pkt_info)
* - false if not
**/
static enum rmnet_perf_tcp_opt_merge_check_rc
-rmnet_perf_tcp_opt_pkt_can_be_merged(struct sk_buff *skb,
+rmnet_perf_tcp_opt_pkt_can_be_merged(
struct rmnet_perf_opt_flow_node *flow_node,
struct rmnet_perf_pkt_info *pkt_info)
{
- struct iphdr *ip4h;
- struct ipv6hdr *ip6h;
- u16 payload_len = pkt_info->payload_len;
- struct tcphdr *tp = pkt_info->trns_hdr.tp;
-
- /* cast iph to right ip header struct for ip_version */
- switch (pkt_info->ip_proto) {
- case 0x04:
- ip4h = pkt_info->iphdr.v4hdr;
- if (((__force u32)flow_node->next_seq ^
- (__force u32) ntohl(tp->seq))) {
- rmnet_perf_tcp_opt_fn_seq = flow_node->next_seq;
- rmnet_perf_tcp_opt_pkt_seq = ntohl(tp->seq);
- rmnet_perf_tcp_opt_flush_reason_cnt[
- RMNET_PERF_TCP_OPT_OUT_OF_ORDER_SEQ]++;
- return RMNET_PERF_TCP_OPT_FLUSH_ALL;
- }
- break;
- case 0x06:
- ip6h = (struct ipv6hdr *) pkt_info->iphdr.v6hdr;
- if (((__force u32)flow_node->next_seq ^
- (__force u32) ntohl(tp->seq))) {
- rmnet_perf_tcp_opt_fn_seq = flow_node->next_seq;
- rmnet_perf_tcp_opt_pkt_seq = ntohl(tp->seq);
- rmnet_perf_tcp_opt_flush_reason_cnt[
- RMNET_PERF_TCP_OPT_OUT_OF_ORDER_SEQ]++;
- return RMNET_PERF_TCP_OPT_FLUSH_ALL;
- }
- break;
- default:
- pr_err("Unsupported ip version %d", pkt_info->ip_proto);
+ struct tcphdr *tp = pkt_info->trans_hdr.tp;
+ u32 tcp_seq = ntohl(tp->seq);
+ u16 gso_len;
+
+ /* Use any previous GRO information, if present */
+ if (pkt_info->frag_desc && pkt_info->frag_desc->gso_size)
+ gso_len = pkt_info->frag_desc->gso_size;
+ else
+ gso_len = pkt_info->payload_len;
+
+ /* Use stamped TCP SEQ number if we have it */
+ if (pkt_info->frag_desc && pkt_info->frag_desc->tcp_seq_set)
+ tcp_seq = ntohl(pkt_info->frag_desc->tcp_seq);
+
+ /* 1. check ordering */
+ if (flow_node->next_seq ^ tcp_seq) {
+ rmnet_perf_tcp_opt_fn_seq = flow_node->next_seq;
+ rmnet_perf_tcp_opt_pkt_seq = ntohl(tp->seq);
rmnet_perf_tcp_opt_flush_reason_cnt[
- RMNET_PERF_TCP_OPT_PACKET_CORRUPT_ERROR]++;
- return RMNET_PERF_TCP_OPT_FLUSH_SOME;
+ RMNET_PERF_TCP_OPT_OUT_OF_ORDER_SEQ]++;
+ return RMNET_PERF_TCP_OPT_FLUSH_ALL;
}
/* 2. check if size overflow */
- if ((payload_len + flow_node->len >= rmnet_perf_tcp_opt_flush_limit)) {
+ if (pkt_info->payload_len + flow_node->len >=
+ rmnet_perf_tcp_opt_flush_limit) {
rmnet_perf_tcp_opt_flush_reason_cnt[
RMNET_PERF_TCP_OPT_64K_LIMIT]++;
return RMNET_PERF_TCP_OPT_FLUSH_SOME;
- } else if ((flow_node->num_pkts_held >= 50)) {
+ } else if (flow_node->num_pkts_held >= 50) {
rmnet_perf_tcp_opt_flush_reason_cnt[
RMNET_PERF_TCP_OPT_NO_SPACE_IN_NODE]++;
return RMNET_PERF_TCP_OPT_FLUSH_SOME;
- } else if (flow_node->gso_len != payload_len) {
+ } else if (flow_node->gso_len != gso_len) {
rmnet_perf_tcp_opt_flush_reason_cnt[
RMNET_PERF_TCP_OPT_LENGTH_MISMATCH]++;
return RMNET_PERF_TCP_OPT_FLUSH_SOME;
@@ -146,57 +133,42 @@ rmnet_perf_tcp_opt_pkt_can_be_merged(struct sk_buff *skb,
return RMNET_PERF_TCP_OPT_MERGE_SUCCESS;
}
-/* rmnet_perf_tcp_opt_check_timestamp() -Check timestamp of incoming packet
- * @skb: incoming packet to check
- * @tp: pointer to tcp header of incoming packet
- *
- * If the tcp segment has extended headers then parse them to check to see
- * if timestamps are included. If so, return the value
+/* rmnet_perf_tcp_opt_cmp_options() - Compare the TCP options of the packets
+ * in a given flow node with an incoming packet in the flow
+ * @flow_node: The flow node representing the current flow
+ * @pkt_info: The characteristics of the incoming packet
*
* Return:
- * - timestamp: if a timestamp is valid
- * - 0: if there is no timestamp extended header
+ * - true: The TCP headers have differing option fields
+ * - false: The TCP headers have the same options
**/
-static u32 rmnet_perf_tcp_opt_check_timestamp(struct sk_buff *skb,
- struct tcphdr *tp,
- struct net_device *dev)
+static bool
+rmnet_perf_tcp_opt_cmp_options(struct rmnet_perf_opt_flow_node *flow_node,
+ struct rmnet_perf_pkt_info *pkt_info)
{
- int length = tp->doff * 4 - sizeof(*tp);
- unsigned char *ptr = (unsigned char *)(tp + 1);
-
- while (length > 0) {
- int code = *ptr++;
- int size = *ptr++;
-
- /* Partial or malformed options */
- if (size < 2 || size > length)
- return 0;
-
- switch (code) {
- case TCPOPT_EOL:
- /* No more options */
- return 0;
- case TCPOPT_NOP:
- /* Empty option */
- length--;
- continue;
- case TCPOPT_TIMESTAMP:
- if (size == TCPOLEN_TIMESTAMP &&
- dev_net(dev)->ipv4.sysctl_tcp_timestamps)
- return get_unaligned_be32(ptr);
- }
+ struct tcphdr *flow_header;
+ struct tcphdr *new_header;
+ u32 optlen, i;
+
+ flow_header = (struct tcphdr *)
+ (flow_node->pkt_list[0].header_start +
+ flow_node->ip_len);
+ new_header = pkt_info->trans_hdr.tp;
+ optlen = flow_header->doff * 4;
+ if (new_header->doff * 4 != optlen)
+ return true;
- ptr += size - 2;
- length -= size;
+ /* Compare the bytes of the options */
+ for (i = sizeof(*flow_header); i < optlen; i += 4) {
+ if (*(u32 *)((u8 *)flow_header + i) ^
+ *(u32 *)((u8 *)new_header + i))
+ return true;
}
- /* No timestamp in the options */
- return 0;
+ return false;
}
/* rmnet_perf_tcp_opt_ingress() - Core business logic of tcp_opt
- * @perf: allows access to our required global structures
- * @skb: the incoming ip packet
* @pkt_info: characteristics of the current packet
* @flush: IP flag mismatch detected
*
@@ -208,24 +180,24 @@ static u32 rmnet_perf_tcp_opt_check_timestamp(struct sk_buff *skb,
* Return:
* - void
**/
-void rmnet_perf_tcp_opt_ingress(struct rmnet_perf *perf, struct sk_buff *skb,
- struct rmnet_perf_opt_flow_node *flow_node,
+void rmnet_perf_tcp_opt_ingress(struct rmnet_perf_opt_flow_node *flow_node,
struct rmnet_perf_pkt_info *pkt_info,
bool flush)
{
- bool timestamp_mismatch;
+ struct napi_struct *napi;
+ bool option_mismatch;
enum rmnet_perf_tcp_opt_merge_check_rc rc;
- struct napi_struct *napi = NULL;
+ u16 pkt_len;
+
+ pkt_len = pkt_info->ip_len + pkt_info->trans_len +
+ pkt_info->payload_len;
if (flush || rmnet_perf_tcp_opt_tcp_flag_flush(pkt_info)) {
rmnet_perf_opt_update_flow(flow_node, pkt_info);
- rmnet_perf_opt_flush_single_flow_node(perf, flow_node);
+ rmnet_perf_opt_flush_single_flow_node(flow_node);
napi = get_current_napi_context();
napi_gro_flush(napi, false);
- rmnet_perf_core_flush_curr_pkt(perf, skb, pkt_info,
- pkt_info->header_len +
- pkt_info->payload_len, true,
- false);
+ rmnet_perf_core_flush_curr_pkt(pkt_info, pkt_len, true, false);
napi_gro_flush(napi, false);
rmnet_perf_tcp_opt_flush_reason_cnt[
RMNET_PERF_TCP_OPT_TCP_FLUSH_FORCE]++;
@@ -236,33 +208,27 @@ void rmnet_perf_tcp_opt_ingress(struct rmnet_perf *perf, struct sk_buff *skb,
* We know at this point that it's a normal packet in the flow
*/
if (!flow_node->num_pkts_held) {
- rmnet_perf_opt_insert_pkt_in_flow(skb, flow_node, pkt_info);
+ rmnet_perf_opt_insert_pkt_in_flow(flow_node, pkt_info);
return;
}
- pkt_info->curr_timestamp =
- rmnet_perf_tcp_opt_check_timestamp(skb,
- pkt_info->trns_hdr.tp,
- perf->core_meta->dev);
- timestamp_mismatch = flow_node->timestamp != pkt_info->curr_timestamp;
+ option_mismatch = rmnet_perf_tcp_opt_cmp_options(flow_node, pkt_info);
- rc = rmnet_perf_tcp_opt_pkt_can_be_merged(skb, flow_node, pkt_info);
+ rc = rmnet_perf_tcp_opt_pkt_can_be_merged(flow_node, pkt_info);
if (rc == RMNET_PERF_TCP_OPT_FLUSH_ALL) {
- rmnet_perf_opt_flush_single_flow_node(perf, flow_node);
- rmnet_perf_core_flush_curr_pkt(perf, skb, pkt_info,
- pkt_info->header_len +
- pkt_info->payload_len, false,
+ rmnet_perf_opt_flush_single_flow_node(flow_node);
+ rmnet_perf_core_flush_curr_pkt(pkt_info, pkt_len, false,
false);
} else if (rc == RMNET_PERF_TCP_OPT_FLUSH_SOME) {
- rmnet_perf_opt_flush_single_flow_node(perf, flow_node);
- rmnet_perf_opt_insert_pkt_in_flow(skb, flow_node, pkt_info);
- } else if (timestamp_mismatch) {
- rmnet_perf_opt_flush_single_flow_node(perf, flow_node);
- rmnet_perf_opt_insert_pkt_in_flow(skb, flow_node, pkt_info);
+ rmnet_perf_opt_flush_single_flow_node(flow_node);
+ rmnet_perf_opt_insert_pkt_in_flow(flow_node, pkt_info);
+ } else if (option_mismatch) {
+ rmnet_perf_opt_flush_single_flow_node(flow_node);
+ rmnet_perf_opt_insert_pkt_in_flow(flow_node, pkt_info);
rmnet_perf_tcp_opt_flush_reason_cnt[
- RMNET_PERF_TCP_OPT_TIMESTAMP_MISMATCH]++;
+ RMNET_PERF_TCP_OPT_OPTION_MISMATCH]++;
} else if (rc == RMNET_PERF_TCP_OPT_MERGE_SUCCESS) {
pkt_info->first_packet = false;
- rmnet_perf_opt_insert_pkt_in_flow(skb, flow_node, pkt_info);
+ rmnet_perf_opt_insert_pkt_in_flow(flow_node, pkt_info);
}
}