From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ig0-f195.google.com (mail-ig0-f195.google.com [209.85.213.195]) by dpdk.org (Postfix) with ESMTP id A190358D3 for ; Sat, 23 Aug 2014 16:53:01 +0200 (CEST) Received: by mail-ig0-f195.google.com with SMTP id uq10so297863igb.10 for ; Sat, 23 Aug 2014 07:56:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=l7WD8/aTS0qW6F3wsttFrEX9VzEfkCseNo/WnfIondE=; b=kfFj8/YgIDnPnSO8rY9qduhgOEbnJgemCVw8/fnT2yDBPPdO53HxNJdiS3hU2jbw8/ 7iAEJkOIwqlHS8qbdUbXiRXQYVQMn4AvEl9MXPIDJGn782VMFkiqSkxTSvf6hHL1VJeT t1+3FqXbNx9Ja974PImET39Qkcg8y8ZvQFGkoWIn8zZCRA3kpL+QuNMBfOHtZdSWL7dJ Tt7XtO7N3esvUYQvlaurRR54wGdyzIvPiSuNjYdrTvEvmYlqYvb+/NKgmmylzcPc8Mcj TO4TNJD7tcc9xiUfCuzDiWfhqcO7BDqU7eTn+sRNzZ9JdKFikGmlEd5GPDAqpKSHHjYT oygg== MIME-Version: 1.0 X-Received: by 10.43.154.145 with SMTP id le17mr15422839icc.20.1408805807129; Sat, 23 Aug 2014 07:56:47 -0700 (PDT) Received: by 10.64.159.6 with HTTP; Sat, 23 Aug 2014 07:56:47 -0700 (PDT) Date: Sat, 23 Aug 2014 10:56:47 -0400 Message-ID: From: daniel chapiesky To: dev@dpdk.org Content-Type: text/plain; charset=UTF-8 X-Content-Filtered-By: Mailman/MimeDel 2.1.15 Subject: [dpdk-dev] rte_table: fails on 32 bit platforms X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 23 Aug 2014 14:53:02 -0000 Hello, I found a problem with the Packet Framework's rte_table library. The rte_table library, when compiled against a 32-bit target, becomes non-functional. This is because certain code in the various table implementations assumes 64-bit (or 8 byte) pointers. For example, the following code: if ((check_params_create_lru(p) != 0) || ((sizeof(struct rte_table_hash) % CACHE_LINE_SIZE) != 0) || ((sizeof(struct rte_bucket_4_8) % CACHE_LINE_SIZE) != 0) ) { return NULL; } when combined with the structure: struct rte_bucket_4_8 { /* Cache line 0 */ uint64_t signature; uint64_t lru_list; struct rte_bucket_4_8 *next; uint64_t next_valid; uint64_t key[4]; /* Cache line 1 */ uint8_t data[0]; }; will compile just fine, but the compiler optimizer will happily do constant propagation, note the math does not line up, and performs dead code removal, thus removing everything below this point without a word. I was able to do a quick fix by adding a uint32_t pad variable, but that is a hack. In rte_table_acl.c we find the following assertion: RTE_BUILD_BUG_ON(((sizeof(struct rte_table_acl) % CACHE_LINE_SIZE) != 0)); This appears to be a better way to perform this kind of check, rather than embedding it in an "if" statement. While I have a git patch which fixes this problem, I would prefer that the experts take a look at this problem and figure out if it can be more elegantly fixed. Sincerely, Daniel Chapiesky AllSource Below is listed some of the files and offending bits of code: -------------------------------- In rte_table_hash_key8.c we find: struct rte_bucket_4_8 { /* Cache line 0 */ uint64_t signature; uint64_t lru_list; struct rte_bucket_4_8 *next; uint64_t next_valid; uint64_t key[4]; /* Cache line 1 */ uint8_t data[0]; }; and the questionable checks: /* Check input parameters */ if ((check_params_create_lru(p) != 0) || ((sizeof(struct rte_table_hash) % CACHE_LINE_SIZE) != 0) || ((sizeof(struct rte_bucket_4_8) % CACHE_LINE_SIZE) != 0) ) { return NULL; } This was fixed by me using 4 bytes for padding: struct rte_bucket_4_8 { /* Cache line 0 */ uint64_t signature; uint64_t lru_list; struct rte_bucket_4_8 *next; uint32_t pad0; // <<< TOTAL HACK uint64_t next_valid; uint64_t key[4]; /* Cache line 1 */ uint8_t data[0]; }; ------------------------------- The same code structure was found in these files as well: rte_table_hash_key16.c rte_table_hash_key32.c rte_table_hash_lru.c ------------------------------- Interestingly in rte_table_hash_ext.c we find: struct bucket { union { uintptr_t next; uint64_t lru_list; }; uint16_t sig[KEYS_PER_BUCKET]; uint32_t key_pos[KEYS_PER_BUCKET]; }; and the questionable checks: /* Check input parameters */ if ((check_params_create(p) != 0) || (!rte_is_power_of_2(entry_size)) || ((sizeof(struct rte_table_hash) % CACHE_LINE_SIZE) != 0) || (sizeof(struct bucket) != (CACHE_LINE_SIZE / 2))) return NULL; The union in struct bucket saves us from 32 bit pointers mucking up the math.