haproxy-lb/pkg/vip/vip.go
2021-11-07 13:30:22 +01:00

127 lines
2.1 KiB
Go

package vip
import (
"errors"
"net"
"sync"
"github.com/vishvananda/netlink"
)
var ErrNoDefaultInterface = errors.New("no default interface found")
func DefaultInterface() (iface string, err error) {
routes, err := netlink.RouteGet(net.IPv4bcast)
if err != nil {
return
}
if len(routes) >= 1 {
link, err := netlink.LinkByIndex(routes[0].LinkIndex)
if err != nil {
return "", err
}
return link.Attrs().Name, nil
}
err = ErrNoDefaultInterface
return
}
type Network struct {
mu sync.Mutex
m map[string]struct{}
iface string
label string
link netlink.Link
}
func NewNetwork(iface string) (n *Network, err error) {
return NewNetworkWithLabel(iface, "")
}
func NewNetworkWithLabel(iface, label string) (n *Network, err error) {
if iface == "" {
iface, err = DefaultInterface()
if err != nil {
return
}
}
link, err := netlink.LinkByName(iface)
if err != nil {
return
}
n = &Network{
m: make(map[string]struct{}),
iface: iface,
label: label,
link: link,
}
return
}
func (n *Network) Interface() string {
return n.iface
}
func (n *Network) HasIP(a *netlink.Addr) bool {
addrs, err := netlink.AddrList(n.link, 0)
if err != nil {
return false
}
for _, addr := range addrs {
if addr.Equal(*a) {
return true
}
}
return false
}
func (n *Network) AddIP(cidr string) error {
n.mu.Lock()
defer n.mu.Unlock()
addr, err := netlink.ParseAddr(cidr)
if err != nil {
return err
}
if n.HasIP(addr) {
return nil
}
if n.label != "" {
addr.Label = n.iface + ":" + n.label
}
err = netlink.AddrReplace(n.link, addr)
if err != nil {
return err
}
n.m[cidr] = struct{}{}
return ARPSendGratuitous(cidr, n.iface)
}
func (n *Network) DeleteIP(cidr string) error {
n.mu.Lock()
defer n.mu.Unlock()
addr, err := netlink.ParseAddr(cidr)
if err != nil {
return err
}
if !n.HasIP(addr) {
return nil
}
err = netlink.AddrDel(n.link, addr)
if err != nil {
return err
}
delete(n.m, cidr)
return nil
}
func (n *Network) GetIPs() (cidrs []string) {
n.mu.Lock()
defer n.mu.Unlock()
cidrs = make([]string, len(n.m))
c := 0
for k := range n.m {
cidrs[c] = k
c++
}
return
}