blob: 25b7cbb8b8040d19d62bf91f0a456d1cdf4d8b72 [file] [log] [blame]
Wolfgang Denk4646d2a2006-05-30 15:56:48 +02001/**
2 * @file IxEthDBDBCore.c
3 *
4 * @brief Database support functions
5 *
6 * @par
7 * IXP400 SW Release version 2.0
8 *
9 * -- Copyright Notice --
10 *
11 * @par
12 * Copyright 2001-2005, Intel Corporation.
13 * All rights reserved.
14 *
15 * @par
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. Neither the name of the Intel Corporation nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * @par
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
30 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
40 *
41 * @par
42 * -- End of Copyright Notice --
43 */
44
45#include "IxEthDB_p.h"
46
47/* list of database hashtables */
48IX_ETH_DB_PUBLIC HashTable dbHashtable;
49IX_ETH_DB_PUBLIC MatchFunction matchFunctions[IX_ETH_DB_MAX_KEY_INDEX + 1];
50IX_ETH_DB_PUBLIC BOOL ixEthDBPortUpdateRequired[IX_ETH_DB_MAX_RECORD_TYPE_INDEX + 1];
51IX_ETH_DB_PUBLIC UINT32 ixEthDBKeyType[IX_ETH_DB_MAX_RECORD_TYPE_INDEX + 1];
52
53/* private initialization flag */
54IX_ETH_DB_PRIVATE BOOL ethDBInitializationComplete = FALSE;
55
56/**
57 * @brief initializes EthDB
58 *
59 * This function must be called to initialize the component.
60 *
61 * It does the following things:
62 * - checks the port definition structure
63 * - scans the capabilities of the NPE images and sets the
64 * capabilities of the ports accordingly
65 * - initializes the memory pools internally used in EthDB
66 * for storing database records and handling data
67 * - registers automatic update handlers for add and remove
68 * operations
69 * - registers hashing match functions, depending on key sets
70 * - initializes the main database hashtable
71 * - allocates contiguous memory zones to be used for NPE
72 * updates
73 * - registers the serialize methods used to convert data
74 * into NPE-readable format
75 * - starts the event processor
76 *
77 * Note that this function is documented in the public
78 * component header file, IxEthDB.h.
79 *
80 * @return IX_ETH_DB_SUCCESS or an appropriate error if the
81 * component failed to initialize correctly
82 */
83IX_ETH_DB_PUBLIC
84IxEthDBStatus ixEthDBInit(void)
85{
86 IxEthDBStatus result;
87
88 if (ethDBInitializationComplete)
89 {
90 /* redundant */
91 return IX_ETH_DB_SUCCESS;
92 }
93
94 /* trap an invalid port definition structure */
95 IX_ETH_DB_PORTS_ASSERTION;
96
97 /* memory management */
98 ixEthDBInitMemoryPools();
99
100 /* register hashing search methods */
101 ixEthDBMatchMethodsRegister(matchFunctions);
102
103 /* register type-based automatic port updates */
104 ixEthDBUpdateTypeRegister(ixEthDBPortUpdateRequired);
105
106 /* register record to key type mappings */
107 ixEthDBKeyTypeRegister(ixEthDBKeyType);
108
109 /* hash table */
110 ixEthDBInitHash(&dbHashtable, NUM_BUCKETS, ixEthDBEntryXORHash, matchFunctions, (FreeFunction) ixEthDBFreeMacDescriptor);
111
112 /* NPE update zones */
113 ixEthDBNPEUpdateAreasInit();
114
115 /* register record serialization methods */
116 ixEthDBRecordSerializeMethodsRegister();
117
118 /* start the event processor */
119 result = ixEthDBEventProcessorInit();
120
121 /* scan NPE features */
122 if (result == IX_ETH_DB_SUCCESS)
123 {
124 ixEthDBFeatureCapabilityScan();
125 }
126
127 ethDBInitializationComplete = TRUE;
128
129 return result;
130}
131
132/**
133 * @brief prepares EthDB for unloading
134 *
135 * This function must be called before removing the
136 * EthDB component from memory (e.g. doing rmmod in
137 * Linux) if the component is to be re-initialized again
138 * without rebooting the platform.
139 *
140 * All the EthDB ports must be disabled before this
141 * function is to be called. Failure to disable all
142 * the ports will return the IX_ETH_DB_BUSY error.
143 *
144 * This function will destroy mutexes, deallocate
145 * memory and stop the event processor.
146 *
147 * Note that this function is fully documented in the
148 * main component header file, IxEthDB.h.
149 *
150 * @return IX_ETH_DB_SUCCESS if de-initialization
151 * completed successfully or an appropriate error
152 * message otherwise
153 */
154IX_ETH_DB_PUBLIC
155IxEthDBStatus ixEthDBUnload(void)
156{
157 IxEthDBPortId portIndex;
158
159 if (!ethDBInitializationComplete)
160 {
161 /* redundant */
162 return IX_ETH_DB_SUCCESS;
163 }
164
165 /* check if any ports are enabled */
166 for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
167 {
168 if (ixEthDBPortInfo[portIndex].enabled)
169 {
170 return IX_ETH_DB_BUSY;
171 }
172 }
173
174 /* free port resources */
175 for (portIndex = 0 ; portIndex < IX_ETH_DB_NUMBER_OF_PORTS ; portIndex++)
176 {
177 if (ixEthDBPortDefinitions[portIndex].type == IX_ETH_NPE)
178 {
179 ixOsalMutexDestroy(&ixEthDBPortInfo[portIndex].npeAckLock);
180 }
181
182 ixEthDBPortInfo[portIndex].initialized = FALSE;
183 }
184
185 /* shutdown event processor */
186 ixEthDBStopLearningFunction();
187
188 /* deallocate NPE update zones */
189 ixEthDBNPEUpdateAreasUnload();
190
191 ethDBInitializationComplete = FALSE;
192
193 return IX_ETH_DB_SUCCESS;
194}
195
196/**
197 * @brief adds a new entry to the Ethernet database
198 *
199 * @param newRecordTemplate address of the record template to use
200 * @param updateTrigger port map containing the update triggers
201 * resulting from this update operation
202 *
203 * Creates a new database entry, populates it with the data
204 * copied from the given template and adds the record to the
205 * database hash table.
206 * It also checks whether the new record type is registered to trigger
207 * automatic updates; if it is, the update trigger will contain the
208 * port on which the record insertion was performed, as well as the
209 * old port in case the addition was a record migration (from one port
210 * to the other). The caller can use the updateTrigger to trigger
211 * automatic updates on the ports changed as a result of this addition.
212 *
213 * @retval IX_ETH_DB_SUCCESS addition successful
214 * @retval IX_ETH_DB_NOMEM insertion failed, no memory left in the mac descriptor memory pool
215 * @retval IX_ETH_DB_BUSY database busy, cannot insert due to locking
216 *
217 * @internal
218 */
219IX_ETH_DB_PUBLIC
220IxEthDBStatus ixEthDBAdd(MacDescriptor *newRecordTemplate, IxEthDBPortMap updateTrigger)
221{
222 IxEthDBStatus result;
223 MacDescriptor *newDescriptor;
224 IxEthDBPortId originalPortID;
225 HashNode *node = NULL;
226
227 BUSY_RETRY(ixEthDBSearchHashEntry(&dbHashtable, ixEthDBKeyType[newRecordTemplate->type], newRecordTemplate, &node));
228
229 TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
230
231 if (node == NULL)
232 {
233 /* not found, create a new one */
234 newDescriptor = ixEthDBAllocMacDescriptor();
235
236 if (newDescriptor == NULL)
237 {
238 return IX_ETH_DB_NOMEM; /* no memory */
239 }
240
241 /* old port does not exist, avoid unnecessary updates */
242 originalPortID = newRecordTemplate->portID;
243 }
244 else
245 {
246 /* a node with the same key exists, will update node */
247 newDescriptor = (MacDescriptor *) node->data;
248
249 /* save original port id */
250 originalPortID = newDescriptor->portID;
251 }
252
253 /* copy/update fields into new record */
254 memcpy(newDescriptor->macAddress, newRecordTemplate->macAddress, sizeof (IxEthDBMacAddr));
255 memcpy(&newDescriptor->recordData, &newRecordTemplate->recordData, sizeof (IxEthDBRecordData));
256
257 newDescriptor->type = newRecordTemplate->type;
258 newDescriptor->portID = newRecordTemplate->portID;
259 newDescriptor->user = newRecordTemplate->user;
260
261 if (node == NULL)
262 {
263 /* new record, insert into hashtable */
264 BUSY_RETRY_WITH_RESULT(ixEthDBAddHashEntry(&dbHashtable, newDescriptor), result);
265
266 if (result != IX_ETH_DB_SUCCESS)
267 {
268 ixEthDBFreeMacDescriptor(newDescriptor);
269
270 return result; /* insertion failed */
271 }
272 }
273
274 if (node != NULL)
275 {
276 /* release access */
277 ixEthDBReleaseHashNode(node);
278 }
279
280 /* trigger add/remove update if required by type */
281 if (updateTrigger != NULL &&
282 ixEthDBPortUpdateRequired[newRecordTemplate->type])
283 {
284 /* add new port to update list */
285 JOIN_PORT_TO_MAP(updateTrigger, newRecordTemplate->portID);
286
287 /* check if record has moved, we'll need to update the old port as well */
288 if (originalPortID != newDescriptor->portID)
289 {
290 JOIN_PORT_TO_MAP(updateTrigger, originalPortID);
291 }
292 }
293
294 return IX_ETH_DB_SUCCESS;
295}
296
297/**
298 * @brief remove a record from the Ethernet database
299 *
300 * @param templateRecord template record used to determine
301 * what record is to be removed
302 * @param updateTrigger port map containing the update triggers
303 * resulting from this update operation
304 *
305 * This function will examine the template record it receives
306 * and attempts to delete a record of the same type and containing
307 * the same keys as the template record. If deletion is successful
308 * and the record type is registered for automatic port updates the
309 * port will also be set in the updateTrigger port map, so that the
310 * client can perform an update of the port.
311 *
312 * @retval IX_ETH_DB_SUCCESS removal was successful
313 * @retval IX_ETH_DB_NO_SUCH_ADDR the record with the given MAC address was not found
314 * @retval IX_ETH_DB_BUSY database busy, cannot remove due to locking
315 *
316 * @internal
317 */
318IX_ETH_DB_PUBLIC
319IxEthDBStatus ixEthDBRemove(MacDescriptor *templateRecord, IxEthDBPortMap updateTrigger)
320{
321 IxEthDBStatus result;
322
323 TEST_FIXTURE_INCREMENT_DB_CORE_ACCESS_COUNTER;
324
325 BUSY_RETRY_WITH_RESULT(ixEthDBRemoveHashEntry(&dbHashtable, ixEthDBKeyType[templateRecord->type], templateRecord), result);
326
327 if (result != IX_ETH_DB_SUCCESS)
328 {
329 return IX_ETH_DB_NO_SUCH_ADDR; /* not found */
330 }
331
332 /* trigger add/remove update if required by type */
333 if (updateTrigger != NULL
334 &&ixEthDBPortUpdateRequired[templateRecord->type])
335 {
336 /* add new port to update list */
337 JOIN_PORT_TO_MAP(updateTrigger, templateRecord->portID);
338 }
339
340 return IX_ETH_DB_SUCCESS;
341}
342
343/**
344 * @brief register record key types
345 *
346 * This function registers the appropriate key types,
347 * depending on record types.
348 *
349 * All filtering records use the MAC address as the key.
350 * WiFi and Firewall records use a compound key consisting
351 * in both the MAC address and the port ID.
352 *
353 * @return the number of registered record types
354 */
355IX_ETH_DB_PUBLIC
356UINT32 ixEthDBKeyTypeRegister(UINT32 *keyType)
357{
358 /* safety */
359 memset(keyType, 0, sizeof (keyType));
360
361 /* register all known record types */
362 keyType[IX_ETH_DB_FILTERING_RECORD] = IX_ETH_DB_MAC_KEY;
363 keyType[IX_ETH_DB_FILTERING_VLAN_RECORD] = IX_ETH_DB_MAC_KEY;
364 keyType[IX_ETH_DB_ALL_FILTERING_RECORDS] = IX_ETH_DB_MAC_KEY;
365 keyType[IX_ETH_DB_WIFI_RECORD] = IX_ETH_DB_MAC_PORT_KEY;
366 keyType[IX_ETH_DB_FIREWALL_RECORD] = IX_ETH_DB_MAC_PORT_KEY;
367
368 return 5;
369}
370
371/**
372 * @brief Sets a user-defined field into a database record
373 *
374 * Note that this function is fully documented in the main component
375 * header file.
376 */
377IX_ETH_DB_PUBLIC
378IxEthDBStatus ixEthDBUserFieldSet(IxEthDBRecordType recordType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, IxEthDBVlanId vlanID, void *field)
379{
380 HashNode *result = NULL;
381
382 if (macAddr == NULL)
383 {
384 return IX_ETH_DB_INVALID_ARG;
385 }
386
387 if (recordType == IX_ETH_DB_FILTERING_RECORD)
388 {
389 result = ixEthDBSearch(macAddr, recordType);
390 }
391 else if (recordType == IX_ETH_DB_FILTERING_VLAN_RECORD)
392 {
393 result = ixEthDBVlanSearch(macAddr, vlanID, recordType);
394 }
395 else if (recordType == IX_ETH_DB_WIFI_RECORD || recordType == IX_ETH_DB_FIREWALL_RECORD)
396 {
397 IX_ETH_DB_CHECK_PORT_EXISTS(portID);
398
399 result = ixEthDBPortSearch(macAddr, portID, recordType);
400 }
401 else
402 {
403 return IX_ETH_DB_INVALID_ARG;
404 }
405
406 if (result == NULL)
407 {
408 return IX_ETH_DB_NO_SUCH_ADDR;
409 }
410
411 ((MacDescriptor *) result->data)->user = field;
412
413 ixEthDBReleaseHashNode(result);
414
415 return IX_ETH_DB_SUCCESS;
416}
417
418/**
419 * @brief Retrieves a user-defined field from a database record
420 *
421 * Note that this function is fully documented in the main component
422 * header file.
423 */
424IX_ETH_DB_PUBLIC
425IxEthDBStatus ixEthDBUserFieldGet(IxEthDBRecordType recordType, IxEthDBMacAddr *macAddr, IxEthDBPortId portID, IxEthDBVlanId vlanID, void **field)
426{
427 HashNode *result = NULL;
428
429 if (macAddr == NULL || field == NULL)
430 {
431 return IX_ETH_DB_INVALID_ARG;
432 }
433
434 if (recordType == IX_ETH_DB_FILTERING_RECORD)
435 {
436 result = ixEthDBSearch(macAddr, recordType);
437 }
438 else if (recordType == IX_ETH_DB_FILTERING_VLAN_RECORD)
439 {
440 result = ixEthDBVlanSearch(macAddr, vlanID, recordType);
441 }
442 else if (recordType == IX_ETH_DB_WIFI_RECORD || recordType == IX_ETH_DB_FIREWALL_RECORD)
443 {
444 IX_ETH_DB_CHECK_PORT_EXISTS(portID);
445
446 result = ixEthDBPortSearch(macAddr, portID, recordType);
447 }
448 else
449 {
450 return IX_ETH_DB_INVALID_ARG;
451 }
452
453 if (result == NULL)
454 {
455 return IX_ETH_DB_NO_SUCH_ADDR;
456 }
457
458 *field = ((MacDescriptor *) result->data)->user;
459
460 ixEthDBReleaseHashNode(result);
461
462 return IX_ETH_DB_SUCCESS;
463}