/////////////////////////////////////////////////////////////////////////////// // // 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); } } } }