This repository has been archived by the owner on Jun 20, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 677
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move NetDev utils from common/ to net/
- Loading branch information
Showing
7 changed files
with
172 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package net | ||
|
||
import ( | ||
"fmt" | ||
"net" | ||
"os" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/vishvananda/netlink" | ||
"github.com/vishvananda/netns" | ||
) | ||
|
||
var netdevRegExp = regexp.MustCompile(`^([^ ]+?) ([^ ]+?) \[([^]]*)\]$`) | ||
|
||
type Dev struct { | ||
Name string | ||
MAC net.HardwareAddr | ||
CIDRs []*net.IPNet | ||
} | ||
|
||
func (d Dev) String() string { | ||
return fmt.Sprintf("%s %s %s", d.Name, d.MAC, d.CIDRs) | ||
} | ||
|
||
func ParseNetDev(netdev string) (Dev, error) { | ||
match := netdevRegExp.FindStringSubmatch(netdev) | ||
if match == nil { | ||
return Dev{}, fmt.Errorf("invalid netdev: %s", netdev) | ||
} | ||
|
||
iface := match[1] | ||
mac, err := net.ParseMAC(match[2]) | ||
if err != nil { | ||
return Dev{}, fmt.Errorf("cannot parse mac %s: %s", match[2], err) | ||
} | ||
|
||
var cidrs []*net.IPNet | ||
for _, cidr := range strings.Split(match[3], " ") { | ||
if cidr != "" { | ||
ip, ipnet, err := net.ParseCIDR(cidr) | ||
if err != nil { | ||
return Dev{}, fmt.Errorf("cannot parse cidr %s: %s", cidr, err) | ||
} | ||
ipnet.IP = ip | ||
cidrs = append(cidrs, ipnet) | ||
} | ||
} | ||
|
||
return Dev{Name: iface, MAC: mac, CIDRs: cidrs}, nil | ||
} | ||
|
||
func LinkToNetDev(link netlink.Link) (Dev, error) { | ||
addrs, err := netlink.AddrList(link, netlink.FAMILY_V4) | ||
if err != nil { | ||
return Dev{}, err | ||
} | ||
|
||
netDev := Dev{Name: link.Attrs().Name, MAC: link.Attrs().HardwareAddr} | ||
for _, addr := range addrs { | ||
netDev.CIDRs = append(netDev.CIDRs, addr.IPNet) | ||
} | ||
return netDev, nil | ||
} | ||
|
||
// ConnectedToBridgeVethPeerIds returns peer indexes of veth links connected to | ||
// the given bridge. The peer index is used to query from a container netns | ||
// whether the container is connected to the bridge. | ||
func ConnectedToBridgeVethPeerIds(bridgeName string) ([]int, error) { | ||
var ids []int | ||
|
||
br, err := netlink.LinkByName(bridgeName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
links, err := netlink.LinkList() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for _, link := range links { | ||
if _, isveth := link.(*netlink.Veth); isveth && link.Attrs().MasterIndex == br.Attrs().Index { | ||
peerID := link.Attrs().ParentIndex | ||
if peerID == 0 { | ||
// perhaps running on an older kernel where ParentIndex doesn't work. | ||
// as fall-back, assume the peers are consecutive | ||
peerID = link.Attrs().Index - 1 | ||
} | ||
ids = append(ids, peerID) | ||
} | ||
} | ||
|
||
return ids, nil | ||
} | ||
|
||
// Lookup the weave interface of a container | ||
func GetWeaveNetDevs(processID int) ([]Dev, error) { | ||
peerIDs, err := ConnectedToBridgeVethPeerIds("weave") | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return GetNetDevsByVethPeerIds(processID, peerIDs) | ||
} | ||
|
||
func GetNetDevsByVethPeerIds(processID int, peerIDs []int) ([]Dev, error) { | ||
// Bail out if this container is running in the root namespace | ||
netnsRoot, err := netns.GetFromPid(1) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to open root namespace: %s", err) | ||
} | ||
defer netnsRoot.Close() | ||
netnsContainer, err := netns.GetFromPid(processID) | ||
if err != nil { | ||
// Unable to find a namespace for this process - just return nothing | ||
if os.IsNotExist(err) { | ||
return nil, nil | ||
} | ||
return nil, fmt.Errorf("unable to open process %d namespace: %s", processID, err) | ||
} | ||
defer netnsContainer.Close() | ||
if netnsRoot.Equal(netnsContainer) { | ||
return nil, nil | ||
} | ||
|
||
var netdevs []Dev | ||
|
||
peersStr := make([]string, len(peerIDs)) | ||
for i, id := range peerIDs { | ||
peersStr[i] = strconv.Itoa(id) | ||
} | ||
netdevsStr, err := WithNetNSByPid(processID, "list-netdevs", strings.Join(peersStr, ",")) | ||
if err != nil { | ||
return nil, fmt.Errorf("list-netdevs failed: %s", err) | ||
} | ||
for _, netdevStr := range strings.Split(netdevsStr, "\n") { | ||
if netdevStr != "" { | ||
netdev, err := ParseNetDev(netdevStr) | ||
if err != nil { | ||
return nil, fmt.Errorf("cannot parse netdev %s: %s", netdevStr, err) | ||
} | ||
netdevs = append(netdevs, netdev) | ||
} | ||
} | ||
|
||
return netdevs, nil | ||
} | ||
|
||
// Get the weave bridge interface. | ||
// NB: Should be called from the root network namespace. | ||
func GetBridgeNetDev(bridgeName string) (Dev, error) { | ||
link, err := netlink.LinkByName(bridgeName) | ||
if err != nil { | ||
return Dev{}, err | ||
} | ||
|
||
return LinkToNetDev(link) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.