///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections;
using System.Net.IP;
using Drivers.Net;
namespace NetStack.Runtime
{
public class RouteEntry : IComparable
{
public const uint InterfaceRouteTag = 0x80000000;
public const uint InterfaceMetric = 0;
public const uint DirectlyConnectedMetric = 1;
public const uint DefaultRouteMetric = 20;
private IPv4Network network;
private IPv4 gateway;
private IPv4 ifaddr;
private uint metric;
private uint tag;
public RouteEntry(IPv4Network network,
IPv4 gateway,
IPv4 ifaddr,
uint metric,
uint tag)
{
this.network = network;
this.gateway = gateway;
this.ifaddr = ifaddr;
this.metric = metric;
this.tag = tag;
}
public RouteEntry(IPv4Network network,
IPv4 gateway,
IPv4 ifaddr)
: this (network, gateway, ifaddr, DefaultRouteMetric, 0)
{
}
public RouteEntry(IPv4 host,
IPv4 gateway,
IPv4 ifaddr,
uint metric,
uint tag)
{
this.network = new IPv4Network(host, IPv4.BitCount);
this.gateway = gateway;
this.ifaddr = ifaddr;
this.metric = metric;
this.tag = tag;
}
public RouteEntry(IPv4 host,
IPv4 gateway,
IPv4 ifaddr)
: this (host, gateway, ifaddr, DefaultRouteMetric, 0)
{
}
public IPv4Network Network { get { return network; } }
public IPv4 Gateway { get { return gateway; } }
public IPv4 InterfaceAddress { get { return ifaddr; } }
public uint Metric { get { return metric; } }
public uint Tag { get { return tag; } }
public override string! ToString()
{
if (network.MaskLength == IPv4.BitCount)
{
return String.Format("Host {0,-17} Gateway {1,-14} " +
"Interface {2,-14} Metric {3,-3} " +
"Tag {4:x8}",
network.LowerBound, gateway,
ifaddr, metric, tag);
}
else
{
return String.Format("Network {0,-17} Gateway {1,-14} " +
"Interface {2,-14} Metric {3,-3} " +
"Tag {4:x8}",
network, gateway, ifaddr, metric, tag);
}
}
public int CompareTo(object o)
{
RouteEntry other = o as RouteEntry;
if (other == null)
throw new ArgumentException();
//
// Metric - Cheapest route wins
//
if (this.metric < other.metric)
{
return -1;
}
else if (this.metric > other.metric)
{
return +1;
}
//
// Specificity - Most specific wins
//
if (network.IsLessSpecificThan(other.network))
{
return +1;
}
else if (network.IsMoreSpecificThan(other.network))
{
return -1;
}
//
// Numeric value of network - lowest value wins
//
IPv4 ourAddress = network.LowerBound;
IPv4 otherAddress = other.network.LowerBound;
if (ourAddress < otherAddress)
{
return -1;
}
if (ourAddress == otherAddress)
{
return 0;
}
return +1;
}
} // RouteEntry
///
/// A placeholder implementation of a routing table.
/// RoutingTables are great areas for optimization and
/// there's a ton of ways to perform fast lookups. The
/// current implementation uses a linear search to find the
/// best route and should be replaced if there are going to
/// be have more than a handful of routes.
///
/// Also note the current implementation allows routes to be
/// added without being fully resolvable. Finding the interface
/// for a route may take multiple lookups.
///
///
public class RoutingTable
{
private SortedList! routes; // synchronized
public RoutingTable()
{
routes = SortedList.Synchronized(new SortedList());
base();
}
public int Count
{
get { return routes.Count; }
}
public bool AddRoute(RouteEntry! e)
{
try
{
routes.Add(e, e);
return true;
}
catch (ArgumentException)
{
return false;
}
}
public bool DeleteRoute(RouteEntry e)
{
lock (routes.SyncRoot)
{
int oldCount = routes.Count;
routes.Remove(e);
return oldCount > routes.Count;
}
}
///
/// Get route for destination address.
///
public RouteEntry Lookup(IPv4 destination)
{
foreach (RouteEntry! e in routes.Values)
{
if (e.Network.Contains(destination))
{
return e;
}
}
return null;
}
///
/// Get route for destination network.
///
public RouteEntry Lookup(IPv4Network destination)
{
foreach (RouteEntry! e in routes.Values)
{
if (e.Network.Contains(destination))
{
return e;
}
}
return null;
}
///
/// Get Enumerator for RouteEntry instances in Routing table.
///
public IEnumerator GetEnumerator()
{
return routes.Values.GetEnumerator();
}
///
/// Get route for specific destination.
///
/// Specific route if it is present,
/// null otherwise.
public RouteEntry LookupSpecific(IPv4 destination)
{
return LookupSpecific(new IPv4Network(destination, IPv4.BitCount));
}
///
/// Get route for specific destination network.
///
/// Specific route if it is present,
/// null otherwise.
public RouteEntry LookupSpecific(IPv4Network destination)
{
foreach (RouteEntry! e in routes.Values)
{
if (e.Network == destination)
{
return e;
}
}
return null;
}
///
/// Delete all routes that have specified interface address.
///
public void DeleteInterfaceRoutes(IPv4 interfaceAddress)
{
ArrayList deadRoutes = new ArrayList();
lock (routes)
{
foreach (RouteEntry! e in routes.Values)
{
if (e.InterfaceAddress == interfaceAddress)
{
deadRoutes.Add(e);
}
}
}
foreach (RouteEntry e in deadRoutes)
{
deadRoutes.Remove(e);
}
}
}
}