]>
git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Route.c
bed4fde0589aedb6de5ee90b35efbd9f3abc0ff0
3 Copyright (c) 2005 - 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
26 Allocate a route entry then initialize it with the Dest/Netmaks
29 @param Dest The destination network
30 @param Netmask The destination network mask
31 @param GateWay The nexthop address
33 @return NULL if failed to allocate memeory, otherwise the newly created
44 IP4_ROUTE_ENTRY
*RtEntry
;
46 RtEntry
= AllocatePool (sizeof (IP4_ROUTE_ENTRY
));
48 if (RtEntry
== NULL
) {
52 InitializeListHead (&RtEntry
->Link
);
56 RtEntry
->Netmask
= Netmask
;
57 RtEntry
->NextHop
= GateWay
;
65 Free the route table entry. It is reference counted.
67 @param RtEntry The route entry to free.
74 IN IP4_ROUTE_ENTRY
*RtEntry
77 ASSERT (RtEntry
->RefCnt
> 0);
79 if (--RtEntry
->RefCnt
== 0) {
80 gBS
->FreePool (RtEntry
);
86 Allocate and initialize a IP4 route cache entry.
88 @param Dst The destination address
89 @param Src The source address
90 @param GateWay The next hop address
91 @param Tag The tag from the caller. This marks all the cache
92 entries spawned from one route table entry.
94 @return NULL if failed to allocate memory for the cache, other point
95 @return to the created route cache entry.
98 IP4_ROUTE_CACHE_ENTRY
*
99 Ip4CreateRouteCacheEntry (
106 IP4_ROUTE_CACHE_ENTRY
*RtCacheEntry
;
108 RtCacheEntry
= AllocatePool (sizeof (IP4_ROUTE_CACHE_ENTRY
));
110 if (RtCacheEntry
== NULL
) {
114 InitializeListHead (&RtCacheEntry
->Link
);
116 RtCacheEntry
->RefCnt
= 1;
117 RtCacheEntry
->Dest
= Dst
;
118 RtCacheEntry
->Src
= Src
;
119 RtCacheEntry
->NextHop
= GateWay
;
120 RtCacheEntry
->Tag
= Tag
;
127 Free the route cache entry. It is reference counted.
129 @param RtCacheEntry The route cache entry to free.
135 Ip4FreeRouteCacheEntry (
136 IN IP4_ROUTE_CACHE_ENTRY
*RtCacheEntry
139 ASSERT (RtCacheEntry
->RefCnt
> 0);
141 if (--RtCacheEntry
->RefCnt
== 0) {
142 gBS
->FreePool (RtCacheEntry
);
148 Initialize an empty route cache table.
150 @param RtCache The rotue cache table to initialize.
157 IN IP4_ROUTE_CACHE
*RtCache
162 for (Index
= 0; Index
< IP4_ROUTE_CACHE_HASH
; Index
++) {
163 InitializeListHead (&(RtCache
->CacheBucket
[Index
]));
169 Clean up a route cache, that is free all the route cache
170 entries enqueued in the cache.
172 @param RtCache The route cache table to clean up
179 IN IP4_ROUTE_CACHE
*RtCache
184 IP4_ROUTE_CACHE_ENTRY
*RtCacheEntry
;
187 for (Index
= 0; Index
< IP4_ROUTE_CACHE_HASH
; Index
++) {
188 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &(RtCache
->CacheBucket
[Index
])) {
189 RtCacheEntry
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_CACHE_ENTRY
, Link
);
191 RemoveEntryList (Entry
);
192 Ip4FreeRouteCacheEntry (RtCacheEntry
);
200 Create an empty route table, includes its internal route cache
204 @return NULL if failed to allocate memory for the route table, otherwise
205 @return the point to newly created route table.
209 Ip4CreateRouteTable (
213 IP4_ROUTE_TABLE
*RtTable
;
216 RtTable
= AllocatePool (sizeof (IP4_ROUTE_TABLE
));
218 if (RtTable
== NULL
) {
223 RtTable
->TotalNum
= 0;
225 for (Index
= 0; Index
< IP4_MASK_NUM
; Index
++) {
226 InitializeListHead (&(RtTable
->RouteArea
[Index
]));
229 RtTable
->Next
= NULL
;
231 Ip4InitRouteCache (&RtTable
->Cache
);
237 Free the route table and its associated route cache. Route
238 table is reference counted.
240 @param RtTable The route table to free.
247 IN IP4_ROUTE_TABLE
*RtTable
252 IP4_ROUTE_ENTRY
*RtEntry
;
255 ASSERT (RtTable
->RefCnt
> 0);
257 if (--RtTable
->RefCnt
> 0) {
262 // Free all the route table entry and its route cache.
264 for (Index
= 0; Index
< IP4_MASK_NUM
; Index
++) {
265 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &(RtTable
->RouteArea
[Index
])) {
266 RtEntry
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_ENTRY
, Link
);
268 RemoveEntryList (Entry
);
269 Ip4FreeRouteEntry (RtEntry
);
273 Ip4CleanRouteCache (&RtTable
->Cache
);
275 gBS
->FreePool (RtTable
);
281 Remove all the cache entries bearing the Tag. When a route cache
282 entry is created, it is tagged with the address of route entry
283 from which it is spawned. When a route entry is deleted, the cache
284 entries spawned from it are also deleted.
286 @param RtCache Route cache to remove the entries from
287 @param Tag The Tag of the entries to remove
294 IN IP4_ROUTE_CACHE
*RtCache
,
300 IP4_ROUTE_CACHE_ENTRY
*RtCacheEntry
;
303 for (Index
= 0; Index
< IP4_ROUTE_CACHE_HASH
; Index
++) {
304 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &RtCache
->CacheBucket
[Index
]) {
306 RtCacheEntry
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_CACHE_ENTRY
, Link
);
308 if (RtCacheEntry
->Tag
== Tag
) {
309 RemoveEntryList (Entry
);
310 Ip4FreeRouteCacheEntry (RtCacheEntry
);
318 Add a route entry to the route table. All the IP4_ADDRs are in
321 @param RtTable Route table to add route to
322 @param Dest The destination of the network
323 @param Netmask The netmask of the destination
324 @param Gateway The next hop address
326 @retval EFI_ACCESS_DENIED The same route already exists
327 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the entry
328 @retval EFI_SUCCESS The route is added successfully.
333 IN IP4_ROUTE_TABLE
*RtTable
,
341 IP4_ROUTE_ENTRY
*RtEntry
;
344 // All the route entries with the same netmask length are
345 // linke to the same route area
347 Head
= &(RtTable
->RouteArea
[NetGetMaskLength (Netmask
)]);
350 // First check whether the route exists
352 NET_LIST_FOR_EACH (Entry
, Head
) {
353 RtEntry
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_ENTRY
, Link
);
355 if (IP4_NET_EQUAL (RtEntry
->Dest
, Dest
, Netmask
) && (RtEntry
->NextHop
== Gateway
)) {
356 return EFI_ACCESS_DENIED
;
361 // Create a route entry and insert it to the route area.
363 RtEntry
= Ip4CreateRouteEntry (Dest
, Netmask
, Gateway
);
365 if (RtEntry
== NULL
) {
366 return EFI_OUT_OF_RESOURCES
;
369 if (Gateway
== IP4_ALLZERO_ADDRESS
) {
370 RtEntry
->Flag
= IP4_DIRECT_ROUTE
;
373 InsertHeadList (Head
, &RtEntry
->Link
);
381 Remove a route entry and all the route caches spawn from it.
383 @param RtTable The route table to remove the route from
384 @param Dest The destination network
385 @param Netmask The netmask of the Dest
386 @param Gateway The next hop address
388 @retval EFI_SUCCESS The route entry is successfully removed
389 @retval EFI_NOT_FOUND There is no route entry in the table with that
395 IN IP4_ROUTE_TABLE
*RtTable
,
404 IP4_ROUTE_ENTRY
*RtEntry
;
406 Head
= &(RtTable
->RouteArea
[NetGetMaskLength (Netmask
)]);
408 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
409 RtEntry
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_ENTRY
, Link
);
411 if (IP4_NET_EQUAL (RtEntry
->Dest
, Dest
, Netmask
) && (RtEntry
->NextHop
== Gateway
)) {
412 Ip4PurgeRouteCache (&RtTable
->Cache
, (UINTN
) RtEntry
);
413 RemoveEntryList (Entry
);
414 Ip4FreeRouteEntry (RtEntry
);
421 return EFI_NOT_FOUND
;
426 Find a route cache with the dst and src. This is used by ICMP
427 redirect messasge process. All kinds of redirect is treated as
428 host redirect according to RFC1122. So, only route cache entries
429 are modified according to the ICMP redirect message.
431 @param RtTable The route table to search the cache for
432 @param Dest The destination address
433 @param Src The source address
435 @return NULL if no route entry to the (Dest, Src). Otherwise the point
436 @return to the correct route cache entry.
439 IP4_ROUTE_CACHE_ENTRY
*
441 IN IP4_ROUTE_TABLE
*RtTable
,
447 IP4_ROUTE_CACHE_ENTRY
*RtCacheEntry
;
450 Index
= IP4_ROUTE_CACHE_HASH (Dest
, Src
);
452 NET_LIST_FOR_EACH (Entry
, &RtTable
->Cache
.CacheBucket
[Index
]) {
453 RtCacheEntry
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_CACHE_ENTRY
, Link
);
455 if ((RtCacheEntry
->Dest
== Dest
) && (RtCacheEntry
->Src
== Src
)) {
456 NET_GET_REF (RtCacheEntry
);
466 Search the route table for a most specific match to the Dst. It searches
467 from the longest route area (mask length == 32) to the shortest route area (
468 default routes). In each route area, it will first search the instance's
469 route table, then the default route table. This is required by the following
471 1. IP search the route table for a most specific match
472 2. The local route entries have precedence over the default route entry.
474 @param RtTable The route table to search from
475 @param Dst The destionation address to search
477 @return NULL if no route matches the Dst, otherwise the point to the
478 @return most specific route to the Dst.
483 IN IP4_ROUTE_TABLE
*RtTable
,
488 IP4_ROUTE_ENTRY
*RtEntry
;
489 IP4_ROUTE_TABLE
*Table
;
494 for (Index
= IP4_MASK_NUM
- 1; Index
>= 0; Index
--) {
495 for (Table
= RtTable
; Table
!= NULL
; Table
= Table
->Next
) {
496 NET_LIST_FOR_EACH (Entry
, &Table
->RouteArea
[Index
]) {
497 RtEntry
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_ENTRY
, Link
);
499 if (IP4_NET_EQUAL (RtEntry
->Dest
, Dst
, RtEntry
->Netmask
)) {
500 NET_GET_REF (RtEntry
);
513 Search the route table to route the packet. Return/creat a route
514 cache if there is a route to the destination.
516 @param RtTable The route table to search from
517 @param Dest The destination address to search for
518 @param Src The source address to search for
520 @return NULL if failed to route packet, otherwise a route cache
521 @return entry that can be used to route packet.
524 IP4_ROUTE_CACHE_ENTRY
*
526 IN IP4_ROUTE_TABLE
*RtTable
,
534 IP4_ROUTE_CACHE_ENTRY
*RtCacheEntry
;
535 IP4_ROUTE_CACHE_ENTRY
*Cache
;
536 IP4_ROUTE_ENTRY
*RtEntry
;
540 ASSERT (RtTable
!= NULL
);
542 Head
= &RtTable
->Cache
.CacheBucket
[IP4_ROUTE_CACHE_HASH (Dest
, Src
)];
543 RtCacheEntry
= Ip4FindRouteCache (RtTable
, Dest
, Src
);
546 // If found, promote the cache entry to the head of the hash bucket. LRU
548 if (RtCacheEntry
!= NULL
) {
549 RemoveEntryList (&RtCacheEntry
->Link
);
550 InsertHeadList (Head
, &RtCacheEntry
->Link
);
555 // Search the route table for the most specific route
557 RtEntry
= Ip4FindRouteEntry (RtTable
, Dest
);
559 if (RtEntry
== NULL
) {
564 // Found a route to the Dest, if it is a direct route, the packet
565 // will be send directly to the destination, such as for connected
566 // network. Otherwise, it is an indirect route, the packet will be
567 // send the next hop router.
569 if ((RtEntry
->Flag
& IP4_DIRECT_ROUTE
) != 0) {
572 NextHop
= RtEntry
->NextHop
;
575 Ip4FreeRouteEntry (RtEntry
);
578 // Create a route cache entry, and tag it as spawned from this route entry
580 RtCacheEntry
= Ip4CreateRouteCacheEntry (Dest
, Src
, NextHop
, (UINTN
) RtEntry
);
582 if (RtCacheEntry
== NULL
) {
586 InsertHeadList (Head
, &RtCacheEntry
->Link
);
587 NET_GET_REF (RtCacheEntry
);
590 // Each bucket of route cache can contain at most 64 entries.
591 // Remove the entries at the tail of the bucket. These entries
592 // are likely to be used least.
595 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, Head
) {
596 if (++Count
< IP4_ROUTE_CACHE_MAX
) {
600 Cache
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_CACHE_ENTRY
, Link
);
602 RemoveEntryList (Entry
);
603 Ip4FreeRouteCacheEntry (Cache
);
611 Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of
612 GetModeData. The EFI_IP4_ROUTE_TABLE is clumsy to use in the
613 internal operation of the IP4 driver.
615 @param IpInstance The IP4 child that requests the route table.
617 @retval EFI_SUCCESS The route table is successfully build
618 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the rotue table.
622 Ip4BuildEfiRouteTable (
623 IN IP4_PROTOCOL
*IpInstance
627 IP4_ROUTE_TABLE
*RtTable
;
628 IP4_ROUTE_ENTRY
*RtEntry
;
629 EFI_IP4_ROUTE_TABLE
*Table
;
633 RtTable
= IpInstance
->RouteTable
;
635 if (IpInstance
->EfiRouteTable
!= NULL
) {
636 gBS
->FreePool (IpInstance
->EfiRouteTable
);
638 IpInstance
->EfiRouteTable
= NULL
;
639 IpInstance
->EfiRouteCount
= 0;
642 Count
= RtTable
->TotalNum
;
644 if (RtTable
->Next
!= NULL
) {
645 Count
+= RtTable
->Next
->TotalNum
;
652 Table
= AllocatePool (sizeof (EFI_IP4_ROUTE_TABLE
) * Count
);
655 return EFI_OUT_OF_RESOURCES
;
659 // Copy the route entry to EFI route table. Keep the order of
660 // route entry copied from most specific to default route. That
661 // is, interlevel the route entry from the instance's route area
662 // and those from the default route table's route area.
666 for (Index
= IP4_MASK_NUM
- 1; Index
>= 0; Index
--) {
667 for (RtTable
= IpInstance
->RouteTable
; RtTable
!= NULL
; RtTable
= RtTable
->Next
) {
668 NET_LIST_FOR_EACH (Entry
, &(RtTable
->RouteArea
[Index
])) {
669 RtEntry
= NET_LIST_USER_STRUCT (Entry
, IP4_ROUTE_ENTRY
, Link
);
671 EFI_IP4 (Table
[Count
].SubnetAddress
) = HTONL (RtEntry
->Dest
& RtEntry
->Netmask
);
672 EFI_IP4 (Table
[Count
].SubnetMask
) = HTONL (RtEntry
->Netmask
);
673 EFI_IP4 (Table
[Count
].GatewayAddress
) = HTONL (RtEntry
->NextHop
);
680 IpInstance
->EfiRouteTable
= Table
;
681 IpInstance
->EfiRouteCount
= Count
;