[Cake] [PATCH net-next v7 3/7] sch_cake: Add optional ACK filter

kbuild test robot lkp at intel.com
Thu May 3 04:26:44 EDT 2018


Hi Toke,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net-next/master]

url:    https://github.com/0day-ci/linux/commits/Toke-H-iland-J-rgensen/sched-Add-Common-Applications-Kept-Enhanced-cake-qdisc/20180503-073002


coccinelle warnings: (new ones prefixed by >>)

>> net/sched/sch_cake.c:1047:6-13: ERROR: PTR_ERR applied after initialization to constant on line 822

vim +1047 net/sched/sch_cake.c

   812	
   813	static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
   814					       struct cake_flow *flow)
   815	{
   816		bool thisconn_redundant_seen = false, thisconn_seen_last = false;
   817		bool aggressive = q->ack_filter == CAKE_ACK_AGGRESSIVE;
   818		bool otherconn_ack_seen = false;
   819		struct sk_buff *skb_check, *skb_check_prev;
   820		struct sk_buff *otherconn_checked_to = NULL;
   821		struct sk_buff *thisconn_checked_to = NULL;
   822		struct sk_buff *thisconn_ack = NULL;
   823		const struct ipv6hdr *ipv6h, *ipv6h_check;
   824		const struct tcphdr *tcph, *tcph_check;
   825		const struct iphdr *iph, *iph_check;
   826		const struct sk_buff *skb;
   827		struct ipv6hdr _iph, _iph_check;
   828		struct tcphdr _tcph_check;
   829		unsigned char _tcph[64]; /* need to hold maximum hdr size */
   830		int seglen;
   831	
   832		/* no other possible ACKs to filter */
   833		if (flow->head == flow->tail)
   834			return NULL;
   835	
   836		skb = flow->tail;
   837		tcph = cake_get_tcphdr(skb, _tcph, sizeof(_tcph));
   838		iph = cake_get_iphdr(skb, &_iph);
   839		if (!tcph)
   840			return NULL;
   841	
   842		/* the 'triggering' packet need only have the ACK flag set.
   843		 * also check that SYN is not set, as there won't be any previous ACKs.
   844		 */
   845		if ((tcp_flag_word(tcph) &
   846		     (TCP_FLAG_ACK | TCP_FLAG_SYN)) != TCP_FLAG_ACK)
   847			return NULL;
   848	
   849		/* the 'triggering' ACK is at the end of the queue,
   850		 * we have already returned if it is the only packet in the flow.
   851		 * stop before last packet in queue, don't compare trigger ACK to itself
   852		 * start where we finished last time if recorded in ->ackcheck
   853		 * otherwise start from the the head of the flow queue.
   854		 */
   855		skb_check_prev = flow->ackcheck;
   856		skb_check = flow->ackcheck ?: flow->head;
   857	
   858		while (skb_check->next) {
   859			bool pure_ack, thisconn;
   860	
   861			/* don't increment if at head of flow queue (_prev == NULL) */
   862			if (skb_check_prev) {
   863				skb_check_prev = skb_check;
   864				skb_check = skb_check->next;
   865				if (!skb_check->next)
   866					break;
   867			} else {
   868				skb_check_prev = ERR_PTR(-1);
   869			}
   870	
   871			iph_check = cake_get_iphdr(skb_check, &_iph_check);
   872			tcph_check = cake_get_tcphdr(skb_check, &_tcph_check,
   873						     sizeof(_tcph_check));
   874	
   875			if (!tcph_check || iph->version != iph_check->version)
   876				continue;
   877	
   878			if (iph->version == 4) {
   879				seglen = ntohs(iph_check->tot_len) -
   880					       (4 * iph_check->ihl);
   881	
   882				thisconn = (iph_check->saddr == iph->saddr &&
   883					    iph_check->daddr == iph->daddr);
   884			} else if (iph->version == 6) {
   885				ipv6h = (struct ipv6hdr *)iph;
   886				ipv6h_check = (struct ipv6hdr *)iph_check;
   887				seglen = ntohs(ipv6h_check->payload_len);
   888	
   889				thisconn = (!ipv6_addr_cmp(&ipv6h_check->saddr,
   890							   &ipv6h->saddr) &&
   891					    !ipv6_addr_cmp(&ipv6h_check->daddr,
   892							   &ipv6h->daddr));
   893			} else {
   894				WARN_ON(1);  /* shouldn't happen */
   895				continue;
   896			}
   897	
   898			/* stricter criteria apply to ACKs that we may filter
   899			 * 3 reserved flags must be unset to avoid future breakage
   900			 * ECE/CWR/NS can be safely ignored
   901			 * ACK must be set
   902			 * All other flags URG/PSH/RST/SYN/FIN must be unset
   903			 * 0x0FFF0000 = all TCP flags (confirm ACK=1, others zero)
   904			 * 0x01C00000 = NS/CWR/ECE (safe to ignore)
   905			 * 0x0E3F0000 = 0x0FFF0000 & ~0x01C00000
   906			 * must be 'pure' ACK, contain zero bytes of segment data
   907			 * options are ignored
   908			 */
   909			if ((tcp_flag_word(tcph_check) &
   910			     (TCP_FLAG_ACK | TCP_FLAG_SYN)) != TCP_FLAG_ACK)
   911				continue;
   912	
   913			else if (((tcp_flag_word(tcph_check) &
   914				   cpu_to_be32(0x0E3F0000)) != TCP_FLAG_ACK) ||
   915				 ((seglen - __tcp_hdrlen(tcph_check)) != 0))
   916				pure_ack = false;
   917	
   918			else
   919				pure_ack = true;
   920	
   921			/* if we find an ACK belonging to a different connection
   922			 * continue checking for other ACKs this round however
   923			 * restart checking from the other connection next time.
   924			 */
   925			if (thisconn &&	(tcph_check->source != tcph->source ||
   926					 tcph_check->dest != tcph->dest))
   927				thisconn = false;
   928	
   929			/* new ack sequence must be greater
   930			 */
   931			if (thisconn &&
   932			    ((int32_t)(ntohl(tcph_check->ack_seq) -
   933				       ntohl(tcph->ack_seq)) > 0))
   934				continue;
   935	
   936			/* DupACKs with an equal sequence number shouldn't be filtered,
   937			 * but we can filter if the triggering packet is a SACK
   938			 */
   939			if (thisconn &&
   940			    (ntohl(tcph_check->ack_seq) == ntohl(tcph->ack_seq))) {
   941				/* inspired by tcp_parse_options in tcp_input.c */
   942				bool sack = false;
   943				int length = __tcp_hdrlen(tcph) - sizeof(struct tcphdr);
   944				const u8 *ptr = (const u8 *)(tcph + 1);
   945	
   946				while (length > 0) {
   947					int opcode = *ptr++;
   948					int opsize;
   949	
   950					if (opcode == TCPOPT_EOL)
   951						break;
   952					if (opcode == TCPOPT_NOP) {
   953						length--;
   954						continue;
   955					}
   956					opsize = *ptr++;
   957					if (opsize < 2 || opsize > length)
   958						break;
   959					if (opcode == TCPOPT_SACK) {
   960						sack = true;
   961						break;
   962					}
   963					ptr += opsize - 2;
   964					length -= opsize;
   965				}
   966				if (!sack)
   967					continue;
   968			}
   969	
   970			/* somewhat complicated control flow for 'conservative'
   971			 * ACK filtering that aims to be more polite to slow-start and
   972			 * in the presence of packet loss.
   973			 * does not filter if there is one 'redundant' ACK in the queue.
   974			 * 'data' ACKs won't be filtered but do count as redundant ACKs.
   975			 */
   976			if (thisconn) {
   977				thisconn_seen_last = true;
   978				/* if aggressive and this is a data ack we can skip
   979				 * checking it next time.
   980				 */
   981				thisconn_checked_to = (aggressive && !pure_ack) ?
   982					skb_check : skb_check_prev;
   983				/* the first pure ack for this connection.
   984				 * record where it is, but only break if aggressive
   985				 * or already seen data ack from the same connection
   986				 */
   987				if (pure_ack && !thisconn_ack) {
   988					thisconn_ack = skb_check_prev;
   989					if (aggressive || thisconn_redundant_seen)
   990						break;
   991				/* data ack or subsequent pure ack */
   992				} else {
   993					thisconn_redundant_seen = true;
   994					/* this is the second ack for this connection
   995					 * break to filter the first pure ack
   996					 */
   997					if (thisconn_ack)
   998						break;
   999				}
  1000			/* track packets from non-matching tcp connections that will
  1001			 * need evaluation on the next run.
  1002			 * if there are packets from both the matching connection and
  1003			 * others that requre checking next run, track which was updated
  1004			 * last and return the older of the two to ensure full coverage.
  1005			 * if a non-matching pure ack has been seen, cannot skip any
  1006			 * further on the next run so don't update.
  1007			 */
  1008			} else if (!otherconn_ack_seen) {
  1009				thisconn_seen_last = false;
  1010				if (pure_ack) {
  1011					otherconn_ack_seen = true;
  1012					/* if aggressive we don't care about old data,
  1013					 * start from the pure ack.
  1014					 * otherwise if there is a previous data ack,
  1015					 * start checking from it next time.
  1016					 */
  1017					if (aggressive || !otherconn_checked_to)
  1018						otherconn_checked_to = skb_check_prev;
  1019				} else {
  1020					otherconn_checked_to = aggressive ?
  1021						skb_check : skb_check_prev;
  1022				}
  1023			}
  1024		}
  1025	
  1026		/* skb_check is reused at this point
  1027		 * it is the pure ACK to be filtered (if any)
  1028		 */
  1029		skb_check = NULL;
  1030	
  1031		/* next time start checking from the older/nearest to head of unfiltered
  1032		 * but important tcp packets from this connection and other connections.
  1033		 * if none seen, start after the last packet evaluated in the loop.
  1034		 */
  1035		if (thisconn_checked_to && otherconn_checked_to)
  1036			flow->ackcheck = thisconn_seen_last ?
  1037				otherconn_checked_to : thisconn_checked_to;
  1038		else if (thisconn_checked_to)
  1039			flow->ackcheck = thisconn_checked_to;
  1040		else if (otherconn_checked_to)
  1041			flow->ackcheck = otherconn_checked_to;
  1042		else
  1043			flow->ackcheck = skb_check_prev;
  1044	
  1045		/* if filtering, remove the pure ACK from the flow queue */
  1046		if (thisconn_ack && (aggressive || thisconn_redundant_seen)) {
> 1047			if (PTR_ERR(thisconn_ack) == -1) {
  1048				skb_check = flow->head;
  1049				flow->head = flow->head->next;
  1050			} else {
  1051				skb_check = thisconn_ack->next;
  1052				thisconn_ack->next = thisconn_ack->next->next;
  1053			}
  1054		}
  1055	
  1056		/* we just filtered that ack, fix up the list */
  1057		if (flow->ackcheck == skb_check)
  1058			flow->ackcheck = thisconn_ack;
  1059		/* check the entire flow queue next time */
  1060		if (PTR_ERR(flow->ackcheck) == -1)
  1061			flow->ackcheck = NULL;
  1062	
  1063		return skb_check;
  1064	}
  1065	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation


More information about the Cake mailing list