使用 RtmAddRouteToDest 添加和更新路由

函数 RtmAddRouteToDest 用于添加新路由和更新目标的现有路由。 以下过程说明了这两种情况。 下面的示例代码演示如何实现第一个过程。

若要添加路由,客户端应执行以下步骤

  1. 如果客户端已缓存下一跃点句柄,请转到步骤 4。

  2. 创建 RTM_NEXTHOP_INFO 结构并填充相应的信息。

  3. 通过调用 RtmAddNextHop 将下一跃点添加到路由表。 路由表管理器返回下一跃点的句柄。 如果已存在下一跃点,则路由表不会添加下一跃点;而是返回下一跃点的句柄。

  4. 创建 RTM_ROUTE_INFO 结构,并使用相应的信息填充该结构,包括路由表管理器返回的下一跃点句柄。

  5. 通过调用 RtmAddRouteToDest 将路由添加到路由表。 路由表管理器将新路由与路由表中已有的路由进行比较。 如果满足以下所有条件,则两个路由相等:

    • 正在将路由添加到同一目标。
    • 路由由RTM_ROUTE_INFO结构的 Owner 成员指定的同一客户端添加。
    • 路由由RTM_ROUTE_INFO结构的邻居成员指定的同一邻居播发。

    如果路由存在,路由表管理器会将句柄返回到现有路由。 否则,路由表管理器将添加路由,并将句柄返回到新路由。

    客户端可以将 Change_Flags 参数设置为 RTM_ROUTE_CHANGE_NEW,以指示路由表管理器在目标上添加新路由,即使存在具有相同所有者和邻居字段的另一个路由也是如此。

    客户端可以将 Change_Flags 参数设置为 RTM_ROUTE_CHANGE_FIRST以告知路由表管理器更新客户端拥有的目标上的第一个路由。 如果存在此类路由,则可以执行此更新,即使邻居字段不匹配也是如此。 此标志由每个目标维护单个路由的客户端使用。

若要更新路由,客户端应执行以下步骤

  1. 使用路由的句柄调用 RtmGetRouteInfo 。 句柄以前由客户端缓存,或者由路由表管理器从返回路由句柄(如 RtmGetRouteInfo)的调用中返回。
  2. 对路由表管理器返回的 RTM_ROUTE_INFO 结构进行更改。
  3. 使用路由的句柄和更改的 RTM_ROUTE_INFO 结构调用 RtmAddRouteToDest

以下示例代码演示如何使用路由表管理器作为中介将路由添加到目标。

// Add a route to a destination given by (addr, masklen)
// using a next hop reachable with an interface

RTM_NEXTHOP_INFO NextHopInfo;

// First, create and add a next hop to the caller's
// next-hop tree (if it does not already exist)

ZeroMemory(&NextHopInfo, sizeof(RTM_NEXTHOP_INFO);

RTM_IPV4_MAKE_NET_ADDRESS(&NextHopInfo.NextHopAddress,
                          nexthop, // Address of the next hop
                          32);

NextHopInfo.InterfaceIndex = interface;

NextHopHandle = NULL;

Status = RtmAddNextHop(RtmRegHandle,
                       &NextHopInfo,
                       &NextHopHandle,
                       &ChangeFlags);

if (Status == NO_ERROR)
{
    // Created a new next hop or found an old one

        // Fill in the route information for the route
    
    ZeroMemory(&RouteInfo, sizeof(RTM_ROUTE_INFO);

    // Fill in the destination network's address and mask values
    RTM_IPV4_MAKE_NET_ADDRESS(&NetAddress, addr, masklen);

    // Assume 'neighbour learnt from' is the first next hop
    RouteInfo.Neighbour = NextHopHandle;

    // Set metric for route; Preference set internally
    RouteInfo.PrefInfo.Metric = metric;

    // Adding a route to both the unicast and multicast views
    RouteInfo.BelongsToViews = RTM_VIEW_MASK_UCAST|RTM_VIEW_MASK_MCAST;

    RouteInfo.NextHopsList.NumNextHops = 1;
    RouteInfo.NextHopsList.NextHops[0] = NextHopHandle;

    // If you want to add a new route, regardless of
    // whether a similar route already exists, use the following 
    //     ChangeFlags = RTM_ROUTE_CHANGE_NEW;

    ChangeFlags = 0;

    Status = RtmAddRouteToDest(RtmRegHandle,
                               &RouteHandle,     // Can be NULL if you do not need handle
                               &NetAddress,
                               &RouteInfo,
                               1000,             // Time out route after 1000 ms
                               RouteListHandle1, // Also add the route to this list
                               0,
                               NULL,
                               &ChangeFlags);

    if (Status == NO_ERROR)
    {
        if (ChangeFlags & RTM_ROUTE_CHANGE_NEW)
        {
        ; // A new route has been created
        }
        else
        {
        ; // An existing route is updated
        }

        if (ChangeFlags & RTM_ROUTE_CHANGE_BEST)
        {
        ; // Best route information has changed
        }

        // Release the route handle if you do not need it
        RtmReleaseRoutes(RtmRegHandle, 1, &RouteHandle);
    }

    // Also release the next hop since it is no longer needed 
    RtmReleaseNextHops(RtmRegHandle, 1, &NextHopHandle);
}