LCOV - code coverage report
Current view: top level - plugins/map - lpm.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 91 93 97.8 %
Date: 2023-07-05 22:20:52 Functions: 10 10 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2018 Cisco and/or its affiliates.
       3             :  * Licensed under the Apache License, Version 2.0 (the "License");
       4             :  * you may not use this file except in compliance with the License.
       5             :  * You may obtain a copy of the License at:
       6             :  *
       7             :  *     http://www.apache.org/licenses/LICENSE-2.0
       8             :  *
       9             :  * Unless required by applicable law or agreed to in writing, software
      10             :  * distributed under the License is distributed on an "AS IS" BASIS,
      11             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             :  * See the License for the specific language governing permissions and
      13             :  * limitations under the License.
      14             :  */
      15             : 
      16             : #include "lpm.h"
      17             : #include <vnet/ip/ip4_packet.h>
      18             : #include <vnet/ip/ip6_packet.h>
      19             : #include <arpa/inet.h>
      20             : #include <vnet/ip/format.h>
      21             : 
      22             : static uint32_t
      23        8329 : masked_address32 (uint32_t addr, uint8_t len)
      24             : {
      25        8329 :   u32 a = ntohl(addr);
      26        8329 :   return htonl(len == 32 ? a : a & ~(~0u >> len));
      27             : }
      28             : static uint64_t
      29       16502 : masked_address64 (uint64_t addr, uint8_t len)
      30             : {
      31       16502 :   return len == 64 ? addr : addr & ~(~0ull >> len);
      32             : }
      33             : 
      34             : static void
      35        4120 : lpm_32_add (lpm_t *lpm, void *addr_v, u8 pfxlen,
      36             :             u32 value)
      37             : {
      38             :   uword * hash, * result;
      39             :   u32 key;
      40        4120 :   ip4_address_t *addr = addr_v;
      41        4120 :   key = masked_address32(addr->data_u32, pfxlen);
      42        4120 :   hash = lpm->hash[pfxlen];
      43        4120 :   result = hash_get (hash, key);
      44        4120 :   if (result) /* Entry exists */
      45          20 :     clib_warning("%U/%d already exists in table for domain %d",
      46             :                  format_ip4_address, addr, pfxlen, result[0]);
      47             : 
      48             :   /*
      49             :    * adding a new entry
      50             :    */
      51        4120 :   if (hash == NULL) {
      52           4 :     hash = hash_create (32 /* elts */, sizeof (uword));
      53           4 :     hash_set_flags (hash, HASH_FLAG_NO_AUTO_SHRINK);
      54             :   }
      55        4120 :   hash = hash_set(hash, key, value);
      56        4120 :   lpm->hash[pfxlen] = hash;
      57        4120 : }
      58             : 
      59             : static void
      60        4097 : lpm_32_delete (lpm_t *lpm, void *addr_v, u8 pfxlen)
      61             : {
      62             :   uword * hash, * result;
      63             :   u32 key;
      64        4097 :   ip4_address_t *addr = addr_v;
      65        4097 :   key = masked_address32(addr->data_u32, pfxlen);
      66        4097 :   hash = lpm->hash[pfxlen];
      67        4097 :   result = hash_get (hash, key);
      68        4097 :   if (result)
      69        4097 :     hash_unset(hash, key);
      70        4097 :   lpm->hash[pfxlen] = hash;
      71        4097 : }
      72             : 
      73             : static u32
      74          59 : lpm_32_lookup (lpm_t *lpm, void *addr_v, u8 pfxlen)
      75             : {
      76             :   uword * hash, * result;
      77             :   i32 mask_len;
      78             :   u32 key;
      79          59 :   ip4_address_t *addr = addr_v;
      80         938 :   for (mask_len = pfxlen; mask_len >= 0; mask_len--) {
      81         931 :     hash = lpm->hash[mask_len];
      82         931 :     if (hash) {
      83         112 :       key = masked_address32(addr->data_u32, mask_len);
      84         112 :       result = hash_get (hash, key);
      85         112 :       if (result != NULL) {
      86          52 :         return (result[0]);
      87             :       }
      88             :     }
      89             :   }
      90           7 :   return (~0);
      91             : }
      92             : 
      93             : static int
      94          34 : lpm_128_lookup_core (lpm_t *lpm, ip6_address_t *addr, u8 pfxlen, u32 *value)
      95             : {
      96             :   BVT(clib_bihash_kv) kv, v;
      97             :   int rv;
      98          34 :   kv.key[0] = masked_address64(addr->as_u64[0], pfxlen > 64 ? 64 : pfxlen);
      99          34 :   kv.key[1] = masked_address64(addr->as_u64[1], pfxlen > 64 ? pfxlen - 64 : 0);
     100          34 :   kv.key[2] = pfxlen;
     101          34 :   rv = BV(clib_bihash_search_inline_2)(&lpm->bihash, &kv, &v);
     102          34 :   if (rv != 0)
     103          12 :     return -1;
     104          22 :   *value = v.value;
     105          22 :   return 0;
     106             : }
     107             : 
     108             : static u32
     109          23 : lpm_128_lookup (lpm_t *lpm, void *addr_v, u8 pfxlen)
     110             : {
     111          23 :   ip6_address_t *addr = addr_v;
     112          23 :   int i = 0, rv;
     113             :   u32 value;
     114          35 :   clib_bitmap_foreach (i, lpm->prefix_lengths_bitmap)
     115             :      {
     116          34 :       rv = lpm_128_lookup_core(lpm, addr, i, &value);
     117          34 :       if (rv == 0)
     118          22 :         return value;
     119             :     }
     120           1 :   return ~0;
     121             : }
     122             : 
     123             : static void
     124        4120 : lpm_128_add (lpm_t *lpm, void *addr_v, u8 pfxlen, u32 value)
     125             : {
     126             :   BVT(clib_bihash_kv) kv;
     127        4120 :   ip6_address_t *addr = addr_v;
     128             : 
     129        4120 :   kv.key[0] = masked_address64(addr->as_u64[0], pfxlen > 64 ? 64 : pfxlen);
     130        4120 :   kv.key[1] = masked_address64(addr->as_u64[1], pfxlen > 64 ? pfxlen - 64 : 0);
     131        4120 :   kv.key[2] = pfxlen;
     132        4120 :   kv.value = value;
     133        4120 :   BV(clib_bihash_add_del)(&lpm->bihash, &kv, 1);
     134        4120 :   lpm->prefix_length_refcount[pfxlen]++;
     135        4120 :   lpm->prefix_lengths_bitmap = clib_bitmap_set (lpm->prefix_lengths_bitmap, 128 - pfxlen, 1);
     136        4120 : }
     137             : 
     138             : static void
     139        4097 : lpm_128_delete (lpm_t *lpm, void *addr_v, u8 pfxlen)
     140             : {
     141        4097 :   ip6_address_t *addr = addr_v;
     142             :   BVT(clib_bihash_kv) kv;
     143        4097 :   kv.key[0] = masked_address64(addr->as_u64[0], pfxlen > 64 ? 64 : pfxlen);
     144        4097 :   kv.key[1] = masked_address64(addr->as_u64[1], pfxlen > 64 ? pfxlen - 64 : 0);
     145        4097 :   kv.key[2] = pfxlen;
     146        4097 :   BV(clib_bihash_add_del)(&lpm->bihash, &kv, 0);
     147             : 
     148             :   /* refcount accounting */
     149        4097 :   ASSERT (lpm->prefix_length_refcount[pfxlen] > 0);
     150        4097 :   if (--lpm->prefix_length_refcount[pfxlen] == 0) {
     151           2 :     lpm->prefix_lengths_bitmap = clib_bitmap_set (lpm->prefix_lengths_bitmap, 
     152           2 :                                                   128 - pfxlen, 0);
     153             :   }
     154        4097 : }
     155             : 
     156             : lpm_t *
     157        1677 : lpm_table_init (enum lpm_type_e lpm_type)
     158             : {
     159        1677 :   lpm_t * lpm = clib_mem_alloc(sizeof(*lpm));
     160        1677 :   memset(lpm, 0, sizeof(*lpm));
     161             : 
     162        1677 :   switch (lpm_type) {
     163         559 :   case LPM_TYPE_KEY32:
     164         559 :     lpm->add = lpm_32_add;
     165         559 :     lpm->delete = lpm_32_delete;
     166         559 :     lpm->lookup = lpm_32_lookup;
     167         559 :     break;
     168        1118 :   case LPM_TYPE_KEY128:
     169        1118 :     lpm->add = lpm_128_add;
     170        1118 :     lpm->delete = lpm_128_delete;
     171        1118 :     lpm->lookup = lpm_128_lookup;
     172             :     /* Make bihash sizes configurable */
     173        1118 :     BV (clib_bihash_init) (&(lpm->bihash),
     174             :                            "LPM 128", 64*1024, 32<<20);
     175             : 
     176        1118 :     break;
     177           0 :   default:
     178           0 :     ASSERT(0);
     179             :   }
     180        1677 :   return lpm;
     181             : }

Generated by: LCOV version 1.14