]>
Commit | Line | Data |
---|---|---|
ba94a1bb WD |
1 | /** |
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 */ | |
48 | IX_ETH_DB_PUBLIC HashTable dbHashtable; | |
49 | IX_ETH_DB_PUBLIC MatchFunction matchFunctions[IX_ETH_DB_MAX_KEY_INDEX + 1]; | |
50 | IX_ETH_DB_PUBLIC BOOL ixEthDBPortUpdateRequired[IX_ETH_DB_MAX_RECORD_TYPE_INDEX + 1]; | |
51 | IX_ETH_DB_PUBLIC UINT32 ixEthDBKeyType[IX_ETH_DB_MAX_RECORD_TYPE_INDEX + 1]; | |
52 | ||
53 | /* private initialization flag */ | |
472d5460 | 54 | IX_ETH_DB_PRIVATE BOOL ethDBInitializationComplete = false; |
ba94a1bb WD |
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 | */ | |
83 | IX_ETH_DB_PUBLIC | |
84 | IxEthDBStatus 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 | ||
472d5460 | 127 | ethDBInitializationComplete = true; |
ba94a1bb WD |
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 | */ | |
154 | IX_ETH_DB_PUBLIC | |
155 | IxEthDBStatus 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 | ||
472d5460 | 182 | ixEthDBPortInfo[portIndex].initialized = false; |
ba94a1bb WD |
183 | } |
184 | ||
185 | /* shutdown event processor */ | |
186 | ixEthDBStopLearningFunction(); | |
187 | ||
188 | /* deallocate NPE update zones */ | |
189 | ixEthDBNPEUpdateAreasUnload(); | |
190 | ||
472d5460 | 191 | ethDBInitializationComplete = false; |
ba94a1bb WD |
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 | */ | |
219 | IX_ETH_DB_PUBLIC | |
220 | IxEthDBStatus 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 | */ | |
318 | IX_ETH_DB_PUBLIC | |
319 | IxEthDBStatus 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 | */ | |
355 | IX_ETH_DB_PUBLIC | |
356 | UINT32 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 | */ | |
377 | IX_ETH_DB_PUBLIC | |
378 | IxEthDBStatus 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 | */ | |
424 | IX_ETH_DB_PUBLIC | |
425 | IxEthDBStatus 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 | } |