Skip to content
Snippets Groups Projects
prefix.go 1.97 KiB
Newer Older
Oliver Herms's avatar
Oliver Herms committed
package net

import (
	"fmt"
	"math"
	"net"
	"strconv"
	"strings"

	"github.com/taktv6/tflow2/convert"
)

// Prefix represents an IPv4 prefix
type Prefix struct {
	addr   uint32
	pfxlen uint8
}

// NewPfx creates a new Prefix
func NewPfx(addr uint32, pfxlen uint8) Prefix {
	return Prefix{
Oliver Herms's avatar
Oliver Herms committed
		addr:   addr,
		pfxlen: pfxlen,
	}
}

// StrToAddr converts an IP address string to it's uint32 representation
func StrToAddr(x string) (uint32, error) {
	parts := strings.Split(x, ".")
	if len(parts) != 4 {
		return 0, fmt.Errorf("Invalid format")
	}

	ret := uint32(0)
	for i := 0; i < 4; i++ {
		y, err := strconv.Atoi(parts[i])
		if err != nil {
			return 0, fmt.Errorf("Unable to convert %q to int: %v", parts[i], err)
		}

		if y > 255 {
			return 0, fmt.Errorf("%d is too big for a uint8", y)
		}

		ret += uint32(math.Pow(256, float64(3-i))) * uint32(y)
	}

	return ret, nil
}

// Addr returns the address of the prefix
func (pfx Prefix) Addr() uint32 {
Oliver Herms's avatar
Oliver Herms committed
	return pfx.addr
}

// Pfxlen returns the length of the prefix
func (pfx Prefix) Pfxlen() uint8 {
Oliver Herms's avatar
Oliver Herms committed
	return pfx.pfxlen
}

// String returns a string representation of pfx
func (pfx Prefix) String() string {
Oliver Herms's avatar
Oliver Herms committed
	return fmt.Sprintf("%s/%d", net.IP(convert.Uint32Byte(pfx.addr)), pfx.pfxlen)
}

// Contains checks if x is a subnet of or equal to pfx
func (pfx Prefix) Contains(x Prefix) bool {
Oliver Herms's avatar
Oliver Herms committed
	if x.pfxlen <= pfx.pfxlen {
		return false
	}

	mask := (uint32(1) << (32 - pfx.pfxlen))
	return (pfx.addr & mask) == (x.addr & mask)
}

// Equal checks if pfx and x are equal
func (pfx Prefix) Equal(x Prefix) bool {
	return pfx == x
Oliver Herms's avatar
Oliver Herms committed
}

// GetSupernet gets the next common supernet of pfx and x
func (pfx Prefix) GetSupernet(x Prefix) Prefix {
Oliver Herms's avatar
Oliver Herms committed
	maxPfxLen := min(pfx.pfxlen, x.pfxlen) - 1
	a := pfx.addr >> (32 - maxPfxLen)
	b := x.addr >> (32 - maxPfxLen)

	for i := 0; a != b; i++ {
		a = a >> 1
		b = b >> 1
		maxPfxLen--
	}

Oliver Herms's avatar
Oliver Herms committed
		addr:   a << (32 - maxPfxLen),
		pfxlen: maxPfxLen,
	}
}

func min(a uint8, b uint8) uint8 {
	if a < b {
		return a
	}
	return b
}