diff options
| author | Tero Marttila <[email protected]> | 2016-06-19 21:30:00 +0300 | 
|---|---|---|
| committer | Tero Marttila <[email protected]> | 2016-06-19 21:30:00 +0300 | 
| commit | 3a9d9d6f612ef216cd5c34d303905208ecc18591 (patch) | |
| tree | 18a7d6baab297ccc003c0ed911c7e3e7666f5adf | |
| parent | 8d38f299ad81d752e68b2cdce62c9385d0a2cbdf (diff) | |
addrs: follow link state
| -rw-r--r-- | addr.go | 121 | 
1 files changed, 101 insertions, 20 deletions
@@ -5,53 +5,134 @@ import (  	"github.com/vishvananda/netlink"  	"fmt"  	"log" +	"io"  )  type AddrSet struct { +	linkAttrs	netlink.LinkAttrs +	linkChan	chan netlink.LinkUpdate +	addrChan	chan netlink.AddrUpdate +  	addrs	map[string]net.IP  } -func (as *AddrSet) ScanInterface(iface string, family Family) error { +func (addrs *AddrSet) String() string { +	return fmt.Sprintf("AddrSet iface=%v", addrs.linkAttrs.Name) +} + +func (addrs *AddrSet) testFlag(flag net.Flags) bool { +	return addrs.linkAttrs.Flags & flag != 0 +} + +func (addrs *AddrSet) Up() bool { +	return addrs.testFlag(net.FlagUp) +} + +func InterfaceAddrs(iface string, family Family) (*AddrSet, error) { +	var addrs AddrSet +  	link, err := netlink.LinkByName(iface)  	if err != nil { -		return fmt.Errorf("netlink.LinkByName %v: %v", iface, err) +		return nil, fmt.Errorf("netlink.LinkByName %v: %v", iface, err) +	} else { +		addrs.linkAttrs = *link.Attrs()  	} -	addrList, err := netlink.AddrList(link, int(family)) -	if err != nil { -		return fmt.Errorf("netlink.AddrList %v: %v", link, err) +	// list +	if addrList, err := netlink.AddrList(link, int(family)); err != nil { +		return nil, fmt.Errorf("netlink.AddrList %v: %v", link, err) +	} else { +		addrs.addrs = make(map[string]net.IP) + +		for _, addr := range addrList { +			addrs.updateAddr(addr, true) +		}  	} -	// set -	as.addrs = make(map[string]net.IP) +	// update +	addrs.linkChan = make(chan netlink.LinkUpdate) +	addrs.addrChan = make(chan netlink.AddrUpdate) + +	if err := netlink.LinkSubscribe(addrs.linkChan, nil); err != nil { +		return nil, fmt.Errorf("netlink.LinkSubscribe: %v", err) +	} -	for _, addr := range addrList { -		as.applyLinkAddr(link, addr) +	if err := netlink.AddrSubscribe(addrs.addrChan, nil); err != nil { +		return nil, fmt.Errorf("netlink.AddrSubscribe: %v", err)  	} -	return nil +	return &addrs, nil  } -func (as *AddrSet) applyLinkAddr(link netlink.Link, addr netlink.Addr) { -	linkUp := link.Attrs().Flags & net.FlagUp != 0 +func (addrs *AddrSet) Read() error { +	for { +		select { +		case linkUpdate, ok := <-addrs.linkChan: +			if !ok { +				return io.EOF +			} + +			linkAttrs := linkUpdate.Attrs() + +			if linkAttrs.Index != addrs.linkAttrs.Index { +				continue +			} + +			// update state +			addrs.updateLink(*linkAttrs) + +		case addrUpdate, ok := <-addrs.addrChan: +			if !ok { +				return io.EOF +			} +			if addrUpdate.LinkIndex != addrs.linkAttrs.Index { +				continue +			} + +			// XXX: scope and other filters? +			addrs.updateAddr(addrUpdate.Addr, addrUpdate.NewAddr) + +			return nil +		} +	} +} + +// Update state for address +func (addrs *AddrSet) updateAddr(addr netlink.Addr, up bool) {  	if addr.Scope >= int(netlink.SCOPE_LINK) {  		return  	} -	as.applyAddr(addr.IP, linkUp) -} +	ip := addr.IP -// Update state for address -func (as *AddrSet) applyAddr(ip net.IP, up bool) {  	if up { -		log.Printf("update: up %v", ip) +		log.Printf("%v: up %v", addrs, ip) -		as.addrs[ip.String()] = ip +		addrs.addrs[ip.String()] = ip  	} else { -		log.Printf("update: down %v", ip) +		log.Printf("%v: down %v", addrs, ip) + +		delete(addrs.addrs, ip.String()) +	} +} + +func (addrs *AddrSet) updateLink(linkAttrs netlink.LinkAttrs) { +	addrs.linkAttrs = linkAttrs + +	if !addrs.Up() { +		log.Printf("%v: down", addrs) +	} +} + +func (addrs *AddrSet) Each(visitFunc func(net.IP)) { +	if !addrs.Up() { +		// link down has no up addrs +		return +	} -		delete(as.addrs, ip.String()) +	for _, ip := range addrs.addrs { +		visitFunc(ip)  	}  }  | 
