API Reference Manual  1.46.0
odp_l3fwd_lpm.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2016-2018 Linaro Limited
3  */
4 
7 #ifndef _GNU_SOURCE
8 #define _GNU_SOURCE
9 #endif
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 
14 #include <odp_api.h>
15 #include <odp/helper/odph_api.h>
16 
17 #include <odp_l3fwd_lpm.h>
18 
31 #define FIB_IP_WIDTH 32
32 #define FIB_FIRST_STRIDE 16
33 #define FIB_NEXT_STRIDE 4
34 #define FIB_NEXT_SIZE (1 << FIB_NEXT_STRIDE)
35 #define FIB_SUB_COUNT 16384
36 #define DEPTH_TO_MASK(depth) ((1 << (depth)) - 1)
37 
38 typedef struct fib_node_s {
39  union {
40  uint32_t next_hop;
41  struct fib_node_s *next; /* next level table */
42  };
43  uint8_t valid :1; /* 1, this node has a valid next hop */
44  uint8_t end :1; /* 0, next points to the extended table */
45  uint8_t depth :6; /* bit length of subnet mask */
46 } fib_node_t;
47 
48 typedef struct fib_sub_tbl_s {
49  fib_node_t *fib_nodes;
50  uint32_t fib_count;
51  uint32_t fib_idx;
52 } fib_sub_tbl_t;
53 
54 static fib_node_t fib_rt_tbl[1 << FIB_FIRST_STRIDE];
55 static fib_sub_tbl_t fib_lpm_cache;
56 
57 static inline fib_node_t *fib_alloc_sub(void)
58 {
59  fib_node_t *sub_tbl = NULL;
60  uint32_t i, nb_entry;
61 
62  /* extend to next level */
63  if (fib_lpm_cache.fib_idx < fib_lpm_cache.fib_count) {
64  nb_entry = (fib_lpm_cache.fib_idx + 1) * FIB_NEXT_SIZE;
65  sub_tbl = &fib_lpm_cache.fib_nodes[nb_entry];
66  fib_lpm_cache.fib_idx++;
67  for (i = 0; i < nb_entry; i++) {
68  sub_tbl[i].valid = 0;
69  sub_tbl[i].end = 1;
70  }
71  }
72 
73  return sub_tbl;
74 }
75 
76 static void fib_update_node(fib_node_t *fe, int port, int depth)
77 {
78  fib_node_t *p;
79  int i;
80 
81  if (fe->end) {
82  if (!fe->valid) {
83  fe->depth = depth;
84  fe->next_hop = port;
85  fe->valid = 1;
86  } else if (fe->depth <= depth) {
87  fe->next_hop = port;
88  fe->depth = depth;
89  }
90 
91  return;
92  }
93 
94  for (i = 0; i < FIB_NEXT_SIZE; i++) {
95  p = &fe->next[i];
96  if (p->end)
97  fib_update_node(p, port, depth);
98  }
99 }
100 
101 static void fib_insert_node(fib_node_t *fe, uint32_t ip, uint32_t next_hop,
102  int ip_width, int eat_bits, int depth)
103 {
104  int i;
105  uint32_t idx, port;
106  fib_node_t *p;
107 
108  if (fe->end) {
109  port = fe->next_hop;
110  p = fib_alloc_sub();
111  if (!p)
112  return;
113 
114  fe->next = p;
115  fe->end = 0;
116  if (fe->valid) {
117  for (i = 0; i < FIB_NEXT_SIZE; i++) {
118  p = &fe->next[i];
119  p->next_hop = port;
120  p->depth = fe->depth;
121  }
122  }
123  }
124  if (depth - eat_bits <= FIB_NEXT_STRIDE) {
125  ip_width -= depth - eat_bits;
126  idx = ip >> ip_width;
127  ip &= DEPTH_TO_MASK(ip_width);
128  p = &fe->next[idx];
129  fib_update_node(p, next_hop, depth);
130  } else {
131  ip_width -= FIB_NEXT_STRIDE;
132  idx = ip >> ip_width;
133  p = &fe->next[idx];
134  ip &= DEPTH_TO_MASK(ip_width);
135  eat_bits += FIB_NEXT_STRIDE;
136  fib_insert_node(p, ip, next_hop, ip_width, eat_bits, depth);
137  }
138 }
139 
140 void fib_tbl_init(void)
141 {
142  int i;
143  fib_node_t *fe;
144  uint32_t size;
145  odp_shm_t lpm_shm;
146 
147  for (i = 0; i < (1 << FIB_FIRST_STRIDE); i++) {
148  fe = &fib_rt_tbl[i];
149  fe->valid = 0;
150  fe->end = 1;
151  fe->depth = 0;
152  fe->next_hop = 0;
153  }
154 
155  size = FIB_NEXT_SIZE * FIB_SUB_COUNT;
156  /*Reserve memory for Routing hash table*/
157  lpm_shm = odp_shm_reserve("fib_lpm_sub", size, ODP_CACHE_LINE_SIZE, 0);
158  if (lpm_shm == ODP_SHM_INVALID) {
159  ODPH_ERR("Error: shared mem reserve failed.\n");
160  exit(EXIT_FAILURE);
161  }
162 
163  fe = odp_shm_addr(lpm_shm);
164  if (!fe) {
165  ODPH_ERR("Error: shared mem alloc failed for lpm cache.\n");
166  exit(-1);
167  }
168 
169  fib_lpm_cache.fib_nodes = fe;
170  fib_lpm_cache.fib_count = FIB_SUB_COUNT;
171  fib_lpm_cache.fib_idx = 0;
172 }
173 
174 void fib_tbl_insert(uint32_t ip, int port, int depth)
175 {
176  fib_node_t *fe, *p;
177  uint32_t idx;
178  int i, j;
179  int nb_bits;
180 
181  nb_bits = FIB_FIRST_STRIDE;
182  idx = ip >> (FIB_IP_WIDTH - nb_bits);
183  fe = &fib_rt_tbl[idx];
184  if (depth <= nb_bits) {
185  if (fe->end) {
186  fe->next_hop = port;
187  fe->depth = depth;
188  fe->valid = 1;
189  return;
190  }
191 
192  for (i = 0; i < FIB_NEXT_SIZE; i++) {
193  p = &fe->next[i];
194  if (p->end)
195  fib_update_node(p, port, depth);
196  else
197  for (j = 0; j < FIB_NEXT_SIZE; j++)
198  fib_update_node(&p->next[j], port,
199  depth);
200  }
201 
202  return;
203  }
204 
205  /* need to check sub table */
206  ip &= DEPTH_TO_MASK(FIB_IP_WIDTH - nb_bits);
207  fib_insert_node(fe, ip, port, FIB_IP_WIDTH - nb_bits, nb_bits, depth);
208 }
209 
210 int fib_tbl_lookup(uint32_t ip, int *port)
211 {
212  fib_node_t *fe;
213  uint32_t idx;
214  int nb_bits;
215 
216  nb_bits = FIB_IP_WIDTH - FIB_FIRST_STRIDE;
217  idx = ip >> nb_bits;
218  fe = &fib_rt_tbl[idx];
219 
220  ip &= DEPTH_TO_MASK(nb_bits);
221  while (!fe->end) {
222  nb_bits -= FIB_NEXT_STRIDE;
223  idx = ip >> nb_bits;
224  fe = &fe->next[idx];
225  ip &= DEPTH_TO_MASK(nb_bits);
226  }
227  *port = fe->next_hop;
228 
229  return fe->valid ? 0 : -1;
230 }
#define ODP_SHM_INVALID
Invalid shared memory block.
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
odp_shm_t odp_shm_reserve(const char *name, uint64_t size, uint64_t align, uint32_t flags)
Reserve a contiguous block of shared memory.
The OpenDataPlane API.