LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dp-core - vr_btable.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 85 116 73.3 %
Date: 2026-11-09 02:10:49 Functions: 4 6 66.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * vr_btable.c -- Big tables. With (kernel)malloc, there is a limitation of
       3             :  * how much contiguous memory we will get (4M). So, for allocations more than
       4             :  * 4M, we need a way to manage the requests, and that's where big tables come
       5             :  * in. Basically, a two level table.
       6             :  *
       7             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       8             :  * Copyright Contributors to the OpenSDN project
       9             :  */
      10             : #include <vr_os.h>
      11             : #include <vrouter.h>
      12             : #include "vr_btable.h"
      13             : 
      14             : /*
      15             :  * The aim of btable is to workaround kernel's limitation of 4M allocation
      16             :  * size by allocating multiple chunks of 4M for a huge allocation.
      17             :  *
      18             :  * In the linux world, while vmalloc can provide a huge chunk of memory,
      19             :  * kmalloc is preferred to vmalloc for the following reasons
      20             :  *
      21             :  * - lesser TLB misses
      22             :  * - vmalloc is restricted in 32 bit systems
      23             :  * - potential pagefaults
      24             :  *
      25             :  * Also, in 2.6, there are problems with mmap-ing k(mz)alloced memory (for
      26             :  * flow table). So, a page based allocation is what btable will follow.
      27             :  *
      28             :  * The basic oprations supported are alloc, free, and get. get is defined in
      29             :  * the header file as an inline function for performance reasons.
      30             :  */
      31             : 
      32             : /*
      33             :  * the discontiguous chunks of memory are seen as partitions, and hence the
      34             :  * nomenclature
      35             :  */
      36             : struct vr_btable_partition *
      37           0 : vr_btable_get_partition(struct vr_btable *table, unsigned int partition)
      38             : {
      39           0 :     if (partition >= table->vb_partitions)
      40           0 :         return NULL;
      41             : 
      42           0 :     return &table->vb_table_info[partition];
      43             : }
      44             : 
      45             : /*
      46             :  * given an offset into the total memory managed by the btable (i.e memory
      47             :  * across all partitions), return the corresponding virtual address
      48             :  */
      49             : void *
      50           0 : vr_btable_get_address(struct vr_btable *table, unsigned int offset)
      51             : {
      52             :     unsigned int i;
      53             :     struct vr_btable_partition *partition;
      54             : 
      55           0 :     for (i = 0; i < table->vb_partitions; i++) {
      56           0 :         partition = vr_btable_get_partition(table, i);
      57           0 :         if (!partition)
      58           0 :             break;
      59             : 
      60           0 :         if (offset >= partition->vb_offset &&
      61           0 :                 offset < partition->vb_offset + partition->vb_mem_size)
      62           0 :             return (char *)table->vb_mem[i] + (offset - partition->vb_offset);
      63             :     }
      64             : 
      65           0 :     return NULL;
      66             : }
      67             : 
      68             : void
      69         789 : vr_btable_free(struct vr_btable *table)
      70             : {
      71             :     unsigned int i;
      72             : 
      73         789 :     if (!table)
      74           0 :         return;
      75             : 
      76         789 :     if (!(table->vb_flags & VB_FLAG_MEMORY_ATTACHED) &&
      77         577 :             (table->vb_mem)) {
      78        1154 :         for (i = 0; i < table->vb_partitions; i++) {
      79         577 :             if (table->vb_mem[i]) {
      80         577 :                 vr_page_free(table->vb_mem[i],
      81         577 :                         table->vb_table_info[i].vb_mem_size);
      82             :             }
      83             :         }
      84             :     }
      85             : 
      86         789 :     vr_free(table, VR_BTABLE_OBJECT);
      87             : 
      88         789 :     return;
      89             : }
      90             : 
      91             : static void
      92         915 : vr_btable_fill_pow2_fields(struct vr_btable *table) {
      93         915 :     unsigned int number = table->vb_alloc_limit;
      94             : 
      95         915 :     if (!(table->vb_alloc_limit & (table->vb_alloc_limit - 1))) {
      96       18978 :         while (number >>= 1)
      97       18169 :             table->vb_alloc_limit_log++;
      98         809 :         table->vb_alloc_limit_mask = table->vb_alloc_limit - 1;
      99             :     } else {
     100         106 :         table->vb_alloc_limit_log = 0;
     101         106 :         table->vb_alloc_limit_mask = 0;
     102             :     }
     103         915 : }
     104             : 
     105             : struct vr_btable *
     106         703 : vr_btable_alloc(unsigned int num_entries, unsigned int entry_size)
     107             : {
     108         703 :     unsigned int i = 0, num_parts, remainder;
     109             :     unsigned int total_parts, alloc_size;
     110             :     uint64_t total_mem;
     111             :     struct vr_btable *table;
     112         703 :     unsigned int offset = 0;
     113             : 
     114         703 :     total_mem = num_entries * entry_size;
     115             : 
     116         703 :     num_parts = total_mem / VR_SINGLE_ALLOC_LIMIT;
     117         703 :     remainder = total_mem % VR_SINGLE_ALLOC_LIMIT;
     118             : 
     119         703 :     total_parts = num_parts;
     120             :     /*
     121             :      * anything left over that is not a multiple of VR_SINGLE_ALLOC_LIMIT
     122             :      * gets accomodated in the remainder, and hence an extra partition has
     123             :      * to be given
     124             :      */
     125         703 :     if (remainder)
     126         650 :         total_parts++;
     127             : 
     128         703 :     if (num_parts) {
     129             :         /*
     130             :          * the entry size has to be a factor of VR_SINGLE_ALLOC limit.
     131             :          * otherwise, we might access memory beyond the allocated chunk
     132             :          * while accessing the last entry
     133             :          */
     134          53 :         if (VR_SINGLE_ALLOC_LIMIT % entry_size)
     135           0 :             return NULL;
     136             :     }
     137             : 
     138         703 :     if (!total_parts)
     139           0 :         return NULL;
     140             : 
     141         703 :     alloc_size = sizeof(*table) + (total_parts * (sizeof(void *))) +
     142             :         (total_parts * sizeof(struct vr_btable_partition));
     143             : 
     144         703 :     table = vr_zalloc(alloc_size, VR_BTABLE_OBJECT);
     145         703 :     if (!table)
     146           0 :         return NULL;
     147             : 
     148         703 :     table->vb_alloc_limit = VR_SINGLE_ALLOC_LIMIT;
     149         703 :     table->vb_mem = (void **)(table + 1);
     150         703 :     table->vb_table_info =
     151         703 :         (struct vr_btable_partition *)((unsigned char *)table->vb_mem +
     152         703 :                 (total_parts * sizeof(void *)));
     153             : 
     154         703 :     if (num_parts) {
     155         106 :         for (i = 0; i < num_parts; i++) {
     156          53 :             table->vb_mem[i] = vr_page_alloc(VR_SINGLE_ALLOC_LIMIT);
     157          53 :             if (!table->vb_mem[i])
     158           0 :                 goto exit_alloc;
     159          53 :             table->vb_table_info[i].vb_mem_size = VR_SINGLE_ALLOC_LIMIT;
     160          53 :             table->vb_table_info[i].vb_offset = offset;
     161          53 :             offset += table->vb_table_info[i].vb_mem_size;
     162          53 :             table->vb_partitions++;
     163             :         }
     164             :     }
     165             : 
     166         703 :     if (remainder) {
     167         650 :         table->vb_mem[i] = vr_page_alloc(remainder);
     168         650 :         if (!table->vb_mem[i])
     169           0 :             goto exit_alloc;
     170         650 :         table->vb_table_info[i].vb_mem_size = remainder;
     171         650 :         table->vb_table_info[i].vb_offset = offset;
     172         650 :         table->vb_partitions++;
     173             :     }
     174             : 
     175         703 :     table->vb_entries = num_entries;
     176         703 :     table->vb_esize = entry_size;
     177             : 
     178         703 :     vr_btable_fill_pow2_fields(table);
     179             : 
     180         703 :     return table;
     181             : 
     182           0 : exit_alloc:
     183           0 :     vr_btable_free(table);
     184           0 :     return NULL;
     185             : }
     186             : 
     187             : struct vr_btable *
     188         212 : vr_btable_attach(struct iovec *iov, unsigned int iov_len,
     189             :         unsigned short esize)
     190             : {
     191             :     unsigned int i, alloc_size;
     192         212 :     unsigned int offset = 0, total_size = 0;
     193             :     struct vr_btable *table;
     194             : 
     195         212 :     if (!iov || !iov_len)
     196           0 :         return NULL;
     197             : 
     198         212 :     if (iov[0].iov_len % esize)
     199           0 :         return NULL;
     200             : 
     201         212 :     alloc_size = sizeof(struct vr_btable);
     202         212 :     alloc_size += (sizeof(void *) * iov_len);
     203         212 :     alloc_size += (sizeof(struct vr_btable_partition) * iov_len);
     204             : 
     205             : 
     206         212 :     table = (struct vr_btable *)vr_zalloc(alloc_size, VR_BTABLE_OBJECT);
     207         212 :     if (!table)
     208           0 :         return NULL;
     209             : 
     210         212 :     table->vb_esize = esize;
     211         212 :     table->vb_partitions = iov_len;
     212         212 :     table->vb_alloc_limit = iov->iov_len;
     213         212 :     table->vb_mem = (void **)(table + 1);
     214         212 :     table->vb_table_info =
     215         212 :         (struct vr_btable_partition *)((unsigned char *)table->vb_mem +
     216         212 :                 (iov_len * sizeof(void *)));
     217             : 
     218         424 :     for (i = 0; i < iov_len; i++) {
     219         212 :         table->vb_mem[i] = iov[i].iov_base;
     220         212 :         if ((iov[i].iov_len != table->vb_alloc_limit) &&
     221           0 :                 (i != (iov_len - 1)))
     222           0 :             goto error;
     223             : 
     224         212 :         table->vb_table_info[i].vb_mem_size = iov[i].iov_len;
     225         212 :         table->vb_table_info[i].vb_offset = offset;
     226             : 
     227         212 :         offset += iov[i].iov_len;
     228         212 :         total_size += iov[i].iov_len;
     229             :     }
     230             : 
     231         212 :     if (total_size % esize)
     232           0 :         goto error;
     233             : 
     234         212 :     table->vb_entries = (total_size / esize);
     235         212 :     table->vb_flags |= VB_FLAG_MEMORY_ATTACHED;
     236             : 
     237         212 :     vr_btable_fill_pow2_fields(table);
     238             : 
     239         212 :     return table;
     240             : 
     241           0 : error:
     242           0 :     vr_btable_free(table);
     243           0 :     return NULL;
     244             : }
     245             : 

Generated by: LCOV version 1.14