API Reference Manual 1.51.0
Loading...
Searching...
No Matches
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
38typedef 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
48typedef 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
54static fib_node_t fib_rt_tbl[1 << FIB_FIRST_STRIDE];
55static fib_sub_tbl_t fib_lpm_cache;
56
57static 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
76static 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
101static 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
140void 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
174void 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
210int 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}
void * odp_shm_addr(odp_shm_t shm)
Shared memory block address.
#define ODP_SHM_INVALID
Invalid shared memory block.
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.