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

Reply via email to