ipam

package module
v1.8.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 25, 2022 License: MIT Imports: 15 Imported by: 0

README

go-ipam

Actions GoDoc Go Report Card codecov License

go-ipam is a module to handle IP address management. It can operate on networks, prefixes and IPs.

IP

Most obvious this library is all about IP management. The main purpose is to acquire and release an IP, or a bunch of IP's from prefixes.

Prefix

A prefix is a network with IP and mask, typically in the form of 192.168.0.0/24. To be able to manage IPs you have to create a prefix first.

Example usage:


package main

import (
    "fmt"
    goipam "github.com/metal-stack/go-ipam"
)

func main() {
    // create a ipamer with in memory storage
    ipam := goipam.New()

    prefix, err := ipam.NewPrefix("192.168.0.0/24")
    if err != nil {
        panic(err)
    }

    ip, err := ipam.AcquireIP(prefix.Cidr)
    if err != nil {
        panic(err)
    }
    fmt.Printf("got IP: %s\n", ip.IP)

    prefix, err = ipam.ReleaseIP(ip)
    if err != nil {
        panic(err)
    }
    fmt.Printf("IP: %s released.\n", ip.IP)

    // Now a IPv6 Super Prefix with Child Prefixes
    prefix, err = ipam.NewPrefix("2001:aabb::/48")
    if err != nil {
        panic(err)
    }
    cp1, err := ipam.AcquireChildPrefix(prefix.Cidr, 64)
    if err != nil {
        panic(err)
    }
    fmt.Printf("got Prefix: %s\n", cp1)
    cp2, err := ipam.AcquireChildPrefix(prefix.Cidr, 72)
    if err != nil {
        panic(err)
    }
    fmt.Printf("got Prefix: %s\n", cp2)
    ip21, err := ipam.AcquireIP(cp2.Cidr)
    if err != nil {
        panic(err)
    }
    fmt.Printf("got IP: %s\n", ip21.IP)
}

Supported Databases

Postgres CockroachDB Redis KeyDB Memory
Production ready Y Y Y Y N
geo redundant setup possible N Y N Y N
AcquireIP/sec ~100/s ~60/s ~1400/s ~1400/s >200.000/s
AcquireChildPrefix/sec ~40/s ~35/s ~1000/s ~1000/s >100.000/s

Test were run on a Intel(R) Core(TM) i5-6600 CPU @ 3.30GHz

Performance

BenchmarkNewPrefix/Memory-4               464994        2675 ns/op     1728 B/op     27 allocs/op
BenchmarkNewPrefix/Postgres-4                126    11775448 ns/op     6259 B/op    144 allocs/op
BenchmarkNewPrefix/Cockroach-4               100    25558820 ns/op     6250 B/op    144 allocs/op
BenchmarkNewPrefix/Redis-4                  3854      308122 ns/op     3930 B/op     78 allocs/op
BenchmarkNewPrefix/KeyDB-4                  3907      307655 ns/op     3930 B/op     78 allocs/op
BenchmarkAcquireIP/Memory-4               229524        4508 ns/op     2680 B/op     56 allocs/op
BenchmarkAcquireIP/Postgres-4                 98    14918027 ns/op    10684 B/op    263 allocs/op
BenchmarkAcquireIP/Cockroach-4                51    19688920 ns/op    10728 B/op    264 allocs/op
BenchmarkAcquireIP/Redis-4                  1734      695545 ns/op    12113 B/op    268 allocs/op
BenchmarkAcquireIP/KeyDB-4                  1476      751854 ns/op    12110 B/op    268 allocs/op
BenchmarkAcquireChildPrefix/Memory-4      128704        8453 ns/op     5201 B/op     94 allocs/op
BenchmarkAcquireChildPrefix/Postgres-4        70    21220704 ns/op    15663 B/op    378 allocs/op
BenchmarkAcquireChildPrefix/Cockroach-4       32    37638608 ns/op    15774 B/op    381 allocs/op
BenchmarkAcquireChildPrefix/Redis-4         1280      925054 ns/op    16016 B/op    349 allocs/op
BenchmarkAcquireChildPrefix/KeyDB-4         1143      953056 ns/op    16018 B/op    349 allocs/op
BenchmarkPrefixOverlapping-4             4306106       274.4 ns/op        0 B/op      0 allocs/op

Testing individual Backends

It is possible to test a individual backend only to speed up development roundtrip.

backend can be one of Memory, Postgres, Cockroach and Redis.

BACKEND=backend make test

Documentation

Overview

Package ipam is a ip address management library for ip's and prefixes (networks).

It uses either memory or postgresql database to store the ip's and prefixes. You can also bring you own Storage implementation as you need.

Example usage:

import (
	"fmt"
	goipam "github.com/metal-stack/go-ipam"
)

func main() {
	// create a ipamer with in memory storage
	ipam := goipam.New()

	prefix, err := ipam.NewPrefix("192.168.0.0/24")
	if err != nil {
		panic(err)
	}

	ip, err := ipam.AcquireIP(prefix)
	if err != nil {
		panic(err)
	}
	fmt.Printf("got IP: %s", ip.IP)

	err = ipam.ReleaseIP(ip)
	if err != nil {
		panic(err)
	}
	fmt.Printf("IP: %s released.", ip.IP)
}

Index

Constants

View Source
const (
	// SSLModeAllow I don't care about security
	// but I will pay the overhead of encryption if the server insists on it
	SSLModeAllow = SSLMode("allow")
	// SSLModeDisable I don't care about security
	// and I don't want to pay the overhead of encryption.
	SSLModeDisable = SSLMode("disable")
	// SSLModePrefer I don't care about encryption
	// but I wish to pay the overhead of encryption if the server supports it.
	SSLModePrefer = SSLMode("prefer")
	// SSLModeRequire I want my data to be encrypted and I accept the overhead.
	// I trust that the network will make sure I always connect to the server I want.
	SSLModeRequire = SSLMode("require")
	// SSLModeVerifyCA I want my data encrypted and I accept the overhead.
	// I want to be sure that I connect to a server that I trust.
	SSLModeVerifyCA = SSLMode("verify-ca")
	// SSLModeVerifyFull I want my data encrypted and I accept the overhead.
	// I want to be sure that I connect to a server I trust, and that it's the one I specify.
	SSLModeVerifyFull = SSLMode("verify-full")
)

Variables

View Source
var (
	// ErrNotFound is returned if prefix or cidr was not found
	ErrNotFound NotFoundError
	// ErrNoIPAvailable is returned if no IP is available anymore
	ErrNoIPAvailable NoIPAvailableError
	// ErrAlreadyAllocated is returned if the requested address is not available
	ErrAlreadyAllocated AlreadyAllocatedError
	// ErrOptimisticLockError is returned if insert or update conflicts with the existing data
	ErrOptimisticLockError OptimisticLockError
)

Functions

This section is empty.

Types

type AlreadyAllocatedError

type AlreadyAllocatedError struct {
}

AlreadyAllocatedError is raised if the given address is already in use

func (AlreadyAllocatedError) Error

func (o AlreadyAllocatedError) Error() string

type IP

type IP struct {
	IP           netaddr.IP
	ParentPrefix string
}

IP is a single ipaddress.

type Ipamer

type Ipamer interface {
	// NewPrefix create a new Prefix from a string notation.
	NewPrefix(cidr string) (*Prefix, error)
	// DeletePrefix delete a Prefix from a string notation.
	// If the Prefix is not found an NotFoundError is returned.
	DeletePrefix(cidr string) (*Prefix, error)
	// AcquireChildPrefix will return a Prefix with a smaller length from the given Prefix.
	AcquireChildPrefix(parentCidr string, length uint8) (*Prefix, error)
	// AcquireSpecificChildPrefix will return a Prefix with a smaller length from the given Prefix.
	AcquireSpecificChildPrefix(parentCidr, childCidr string) (*Prefix, error)
	// ReleaseChildPrefix will mark this child Prefix as available again.
	ReleaseChildPrefix(child *Prefix) error
	// PrefixFrom will return a known Prefix.
	PrefixFrom(cidr string) *Prefix
	// AcquireSpecificIP will acquire given IP and mark this IP as used, if already in use, return nil.
	// If specificIP is empty, the next free IP is returned.
	// If there is no free IP an NoIPAvailableError is returned.
	AcquireSpecificIP(prefixCidr, specificIP string) (*IP, error)
	// AcquireIP will return the next unused IP from this Prefix.
	AcquireIP(prefixCidr string) (*IP, error)
	// ReleaseIP will release the given IP for later usage and returns the updated Prefix.
	// If the IP is not found an NotFoundError is returned.
	ReleaseIP(ip *IP) (*Prefix, error)
	// ReleaseIPFromPrefix will release the given IP for later usage.
	// If the Prefix or the IP is not found an NotFoundError is returned.
	ReleaseIPFromPrefix(prefixCidr, ip string) error
	// PrefixesOverlapping will check if one ore more prefix of newPrefixes is overlapping
	// with one of existingPrefixes
	PrefixesOverlapping(existingPrefixes []string, newPrefixes []string) error
	// ReadAllPrefixCidrs retrieves all existing Prefix CIDRs from the underlying storage
	ReadAllPrefixCidrs() ([]string, error)
}

Ipamer can be used to do IPAM stuff.

func New

func New() Ipamer

New returns a Ipamer with in memory storage for networks, prefixes and ips.

func NewWithStorage

func NewWithStorage(storage Storage) Ipamer

NewWithStorage allows you to create a Ipamer instance with your Storage implementation. The Storage interface must be implemented.

type NoIPAvailableError

type NoIPAvailableError struct {
}

NoIPAvailableError indicates that the acquire-operation could not be executed because the specified prefix has no free IP anymore.

func (NoIPAvailableError) Error

func (o NoIPAvailableError) Error() string

type NotFoundError

type NotFoundError struct {
}

NotFoundError is raised if the given Prefix or Cidr was not found

func (NotFoundError) Error

func (o NotFoundError) Error() string

type OptimisticLockError

type OptimisticLockError struct {
}

OptimisticLockError indicates that the operation could not be executed because the dataset to update has changed in the meantime. clients can decide to read the current dataset and retry the operation.

func (OptimisticLockError) Error

func (o OptimisticLockError) Error() string

type Prefix

type Prefix struct {
	Cidr       string // The Cidr of this prefix
	ParentCidr string // if this prefix is a child this is a pointer back
	// contains filtered or unexported fields
}

Prefix is a expression of a ip with length and forms a classless network.

func (*Prefix) GobDecode

func (p *Prefix) GobDecode(buf []byte) error

GobDecode implements GobDecode for Prefix

func (*Prefix) GobEncode

func (p *Prefix) GobEncode() ([]byte, error)

GobEncode implements GobEncode for Prefix

func (*Prefix) Network

func (p *Prefix) Network() (net.IP, error)

Network return the net.IP part of the Prefix

func (*Prefix) String

func (p *Prefix) String() string

func (*Prefix) Usage

func (p *Prefix) Usage() Usage

Usage report Prefix usage.

type SSLMode

type SSLMode string

SSLMode specifies how to configure ssl encryption to the database

func (SSLMode) String

func (s SSLMode) String() string

type Storage

type Storage interface {
	CreatePrefix(prefix Prefix) (Prefix, error)
	ReadPrefix(prefix string) (Prefix, error)
	ReadAllPrefixes() ([]Prefix, error)
	ReadAllPrefixCidrs() ([]string, error)
	UpdatePrefix(prefix Prefix) (Prefix, error)
	DeletePrefix(prefix Prefix) (Prefix, error)
}

Storage is a interface to store ipam objects.

func NewMemory

func NewMemory() Storage

NewMemory create a memory storage for ipam

func NewPostgresStorage

func NewPostgresStorage(host, port, user, password, dbname string, sslmode SSLMode) (Storage, error)

NewPostgresStorage creates a new Storage which uses postgres.

func NewRedis

func NewRedis(ip, port string) Storage

NewRedis create a redis storage for ipam

func NewRedisWithOptions

func NewRedisWithOptions(options *redigo.Options) Storage

type Usage

type Usage struct {
	// AvailableIPs the number of available IPs if this is not a parent prefix
	// No more than 2^31 available IPs are reported
	AvailableIPs uint64
	// AcquiredIPs the number of acquire IPs if this is not a parent prefix
	AcquiredIPs uint64
	// AvailableSmallestPrefixes is the count of available Prefixes with 2 countable Bits
	// No more than 2^31 available Prefixes are reported
	AvailableSmallestPrefixes uint64
	// AvailablePrefixes is a list of prefixes which are available
	AvailablePrefixes []string
	// AcquiredPrefixes the number of acquired prefixes if this is a parent prefix
	AcquiredPrefixes uint64
}

Usage of ips and child Prefixes of a Prefix

func (*Usage) String

func (u *Usage) String() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL