[Algorithm] CIDR set algorithm

Source: Internet
Author: User

Classless Inter-Domain Routing is short for classless Inter-Domain Routing. Is currently used to represent a route. Because some algorithms of the CIDR set are required for a product, such as intersection, union, and supplement operations of the set. The following shows the implementation code.

 

The first is the structure of CIDR:

    public sealed class CIDR : IXmlSerializable, IComparable<CIDR>    {        private byte[] bytes = null;        public IPAddress IPAddress { get; private set; }        public int Subnet { get; private set; }        public override bool Equals(object obj)        {            CIDR cidr = obj as CIDR;            if (cidr == null)                return false;            return this.Subnet == cidr.Subnet && this.IPAddress.Equals(cidr.IPAddress);        }        public override int GetHashCode()        {            return this.IPAddress.GetHashCode() ^ this.Subnet.GetHashCode();        }        public override string ToString()        {            return string.Format("{0}/{1}", IPAddress, Subnet);        }        public static CIDR Parse(string str)        {            CIDR cidr = new CIDR();            cidr.SetFromString(str);            return cidr;        }        private void SetFromString(string str)        {            int i = str.IndexOf('/');            this.IPAddress = IPAddress.Parse(str.Substring(0, i));            this.Subnet = int.Parse(str.Substring(i + 1));            this.bytes = this.IPAddress.GetAddressBytes();            int length = this.bytes.Length << 3;            if (this.Subnet < 0 || this.Subnet > length)                throw new ArgumentException("", "str");            // can optimize            for (i = this.Subnet + 1; i <= length; i++)            {                int bit = (bytes[(i - 1) >> 3] >> ((8 - i) & 7)) & 1;                if (bit != 0)                    throw new ArgumentException("", "str");            }        }        public bool IsIPv6        {            get { return this.IPAddress.AddressFamily == AddressFamily.InterNetworkV6; }        }        #region IXmlSerializable        XmlSchema IXmlSerializable.GetSchema()        {            return null;        }        void IXmlSerializable.ReadXml(XmlReader reader)        {            this.SetFromString(reader.ReadElementContentAsString());        }        void IXmlSerializable.WriteXml(XmlWriter writer)        {            writer.WriteString(this.ToString());        }        #endregion        #region CIDR Algorithm        public CIDR GetPaired()        {            if (this.Subnet == 0)                throw new NotSupportedException("Subnet=0");            CIDR cidr = new CIDR();            cidr.Subnet = this.Subnet;            cidr.bytes = new byte[this.bytes.Length];            this.bytes.CopyTo(cidr.bytes, 0);            int k = this.Subnet - 1;            int i = k >> 3;            int j = (7 - k) & 7;            cidr.bytes[i] = (byte)(cidr.bytes[i] ^ (1 << j));            cidr.IPAddress = new IPAddress(cidr.bytes);            return cidr;        }        public CIDR GetBiggerSubnet()        {            if (this.Subnet == 0)                throw new NotSupportedException("Subnet=0");            CIDR cidr = new CIDR();            cidr.Subnet = this.Subnet - 1;            cidr.bytes = new byte[this.bytes.Length];            this.bytes.CopyTo(cidr.bytes, 0);            int k = this.Subnet - 1;            int i = k >> 3;            int j = (7 - k) & 7;            cidr.bytes[i] = (byte)(cidr.bytes[i] & ~(1 << j));            cidr.IPAddress = new IPAddress(cidr.bytes);            return cidr;        }        public CIDR GetSmallerSubnet()        {            if (this.Subnet == this.bytes.Length << 3)                throw new NotSupportedException("Subnet=max");            CIDR cidr = new CIDR();            cidr.Subnet = this.Subnet + 1;            cidr.bytes = this.bytes;            cidr.IPAddress = this.IPAddress;            return cidr;        }        public bool ExistsIntersection(CIDR other)        {            if (other == null)                throw new ArgumentNullException("other");            if (this.IsIPv6 != other.IsIPv6)                throw new NotSupportedException("Different address family");            if (this.Subnet == 0 || other.Subnet == 0)                return true;            int min = Math.Min(this.Subnet, other.Subnet) - 1;            int length = min >> 3;            int k;            for (k = 0; k < length; k++)                if (this.bytes[k] != other.bytes[k])                    return false;            //int m = (0xff << (7 - min & 7)) & 0xff;            int m = (0xff80 >> (min & 7));            if (k < this.bytes.Length && (this.bytes[k] & m) != (other.bytes[k] & m))                return false;            return true;        }        public CIDR Intersect(CIDR other)        {            if (other == null)                throw new ArgumentNullException("other");            if (this.IsIPv6 != other.IsIPv6)                throw new NotSupportedException("Different address family");            if (this.ExistsIntersection(other))                if (this.Subnet > other.Subnet)                    return this;                else                    return other;            else                return null;        }        public CIDR[] Union(CIDR other)        {            if (other == null)                throw new ArgumentNullException("other");            if (this.IsIPv6 != other.IsIPv6)                throw new NotSupportedException("Different address family");            if (this.ExistsIntersection(other))                if (this.Subnet < other.Subnet)                    return new[] { this };                else                    return new[] { other };            else                if (this.Subnet == other.Subnet && this.Equals(other.GetPaired()))                    return new[] { this.GetBiggerSubnet() };                else                    return new[] { this, other };        }        #endregion        public int CompareTo(CIDR other)        {            if (other == null)                throw new ArgumentNullException("other");            if (this.IsIPv6 != other.IsIPv6)                if (this.IsIPv6)                    return 1;                else                    return -1;            else if (this.Subnet > other.Subnet)                return 1;            else if (this.Subnet < other.Subnet)                return -1;            else                for (int i = 0; i < this.bytes.Length; i++)                    if (this.bytes[i] > other.bytes[i])                        return 1;                    else if (this.bytes[i] < other.bytes[i])                        return -1;            return 0;        }    }

This class implements the serialization interface (ixmlserializable) and the comparable interface (icomparable <t> ). Convenient storage and other operations.

The next step is to operate the CIDR set. Because routegroup is called in the product, the name is not changed here:

    public class RouteGroup    {        public RouteGroup()        {            this.CIDRs = new HashSet<CIDR>();        }        [XmlAttribute]        public string GroupName { get; set; }        [XmlAttribute]        public Guid GroupID { get; set; }        public HashSet<CIDR> CIDRs { get; set; }        public static RouteGroup Create(string groupName)        {            return new RouteGroup { GroupName = groupName, GroupID = Guid.NewGuid() };        }        public void Union(CIDR cidr)        {            if (cidr == null)                throw new ArgumentNullException("cidr");            var list = this.CIDRs                .Where(s => s.IsIPv6 == cidr.IsIPv6 && s.ExistsIntersection(cidr))                .ToList();            if (list.Count == 0)            {                if (cidr.Subnet > 0 && this.CIDRs.Remove(cidr.GetPaired()))                    this.Union(cidr.GetBiggerSubnet());                else                    this.CIDRs.Add(cidr);            }            else            {                foreach (var item in list)                    this.CIDRs.Remove(item);                var max = list.Max();                if (max.Subnet < cidr.Subnet)                    this.CIDRs.Add(max);                else if (max.Subnet > cidr.Subnet)                    this.CIDRs.Add(cidr);            }        }        public void Subtract(CIDR cidr)        {            if (cidr == null)                throw new ArgumentNullException("cidr");            var list = this.CIDRs               .Where(s => s.IsIPv6 == cidr.IsIPv6 && s.ExistsIntersection(cidr))               .ToList();            if (list.Count > 0)            {                foreach (var item in list)                    this.CIDRs.Remove(item);                var min = list.Min();                CIDR other = cidr;                for (int i = cidr.Subnet; i > min.Subnet; i--)                {                    this.CIDRs.Add(other.GetPaired());                    other = other.GetBiggerSubnet();                }            }        }        public void Union(string cidr)        {            this.Union(CIDR.Parse(cidr));        }        public void Subtract(string cidr)        {            this.Subtract(CIDR.Parse(cidr));        }        public void Reverse()        {            var list = this.CIDRs.ToList();            this.CIDRs.Clear();            this.Union("0.0.0.0/0");            foreach (var item in list)                this.Subtract(item);        }        public void Sort()        {            var list = this.CIDRs.OrderBy(s => s).ToList();            this.CIDRs.Clear();            foreach (var item in list)            {                this.CIDRs.Add(item);            }        }        public void Rebuild()        {            var list = this.CIDRs.OrderBy(s => s).ToList();            this.CIDRs.Clear();            foreach (var item in list)            {                this.Union(item);            }        }    }

Sample Code:

   static void Main(string[] args)        {            var rg = RouteGroup.Create("test");            rg.Union("1.2.0.0/16");            rg.Union("1.3.0.0/16");            rg.Union("2.2.0.0/16");            rg.Union("3.2.0.0/16");            rg.Union("4.2.5.0/24");            rg.Union("5.2.8.0/21");            rg.Union("4.2.12.0/22");            rg.Sort();            foreach (var item in rg.CIDRs)                Console.WriteLine(item);            Console.WriteLine();            rg.Reverse();            rg.Sort();            foreach (var item in rg.CIDRs)                Console.WriteLine(item);            Console.WriteLine();            rg.Subtract("0.0.0.0/2");            rg.Sort();            foreach (var item in rg.CIDRs)                Console.WriteLine(item);            /*             * 1.2.0.0/15             * 2.2.0.0/16             * 3.2.0.0/16             * 5.2.8.0/21             * 4.2.12.0/22             * 4.2.5.0/24             *              * 128.0.0.0/1             * 64.0.0.0/2             * 32.0.0.0/3             * 16.0.0.0/4             * 8.0.0.0/5             * 6.0.0.0/7             * 0.0.0.0/8             * 1.128.0.0/9             * 2.128.0.0/9             * 3.128.0.0/9             * 4.128.0.0/9             * 5.128.0.0/9             * 1.64.0.0/10             * 2.64.0.0/10             * 3.64.0.0/10             * 4.64.0.0/10             * 5.64.0.0/10             * 1.32.0.0/11             * 2.32.0.0/11             * 3.32.0.0/11             * 4.32.0.0/11             * 5.32.0.0/11             * 1.16.0.0/12             * 2.16.0.0/12             * 3.16.0.0/12             * 4.16.0.0/12             * 5.16.0.0/12             * 1.8.0.0/13             * 2.8.0.0/13             * 3.8.0.0/13             * 4.8.0.0/13             * 5.8.0.0/13             * 1.4.0.0/14             * 2.4.0.0/14             * 3.4.0.0/14             * 4.4.0.0/14             * 5.4.0.0/14             * 1.0.0.0/15             * 2.0.0.0/15             * 3.0.0.0/15             * 4.0.0.0/15             * 5.0.0.0/15             * 2.3.0.0/16             * 3.3.0.0/16             * 4.3.0.0/16             * 5.3.0.0/16             * 4.2.128.0/17             * 5.2.128.0/17             * 4.2.64.0/18             * 5.2.64.0/18             * 4.2.32.0/19             * 5.2.32.0/19             * 4.2.16.0/20             * 5.2.16.0/20             * 5.2.0.0/21             * 4.2.0.0/22             * 4.2.8.0/22             * 4.2.6.0/23             * 4.2.4.0/24             *              * 128.0.0.0/1             * 64.0.0.0/2             * Press any key to continue . . .             */        }

Welcome to the discussion.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.