Exposed NetworkManager interface and made it more generic to support CNI

This commit is contained in:
Onur Filiz 2016-11-22 12:31:48 -08:00
Родитель a632028510
Коммит 0bf716e607
4 изменённых файлов: 145 добавлений и 37 удалений

Просмотреть файл

@ -33,28 +33,36 @@ type endpoint struct {
IPv6Gateway net.IP
}
// EndpointInfo contains read-only information about an endpoint.
type EndpointInfo struct {
Id string
IfName string
IPv4Address string
NetNsPath string
}
// NewEndpoint creates a new endpoint in the network.
func (nw *network) newEndpoint(endpointId string, ipAddress string) (*endpoint, error) {
func (nw *network) newEndpoint(epInfo *EndpointInfo) (*endpoint, error) {
var containerIf *net.Interface
var ep *endpoint
var err error
if nw.Endpoints[endpointId] != nil {
if nw.Endpoints[epInfo.Id] != nil {
return nil, errEndpointExists
}
// Parse IP address.
ipAddr, ipNet, err := net.ParseCIDR(ipAddress)
ipAddr, ipNet, err := net.ParseCIDR(epInfo.IPv4Address)
ipNet.IP = ipAddr
if err != nil {
return nil, err
}
log.Printf("[net] Creating endpoint %v in network %v.", endpointId, nw.Id)
log.Printf("[net] Creating endpoint %v in network %v.", epInfo.Id, nw.Id)
// Create a veth pair.
hostIfName := fmt.Sprintf("%s%s", hostInterfacePrefix, endpointId[:7])
contIfName := fmt.Sprintf("%s%s-2", hostInterfacePrefix, endpointId[:7])
hostIfName := fmt.Sprintf("%s%s", hostInterfacePrefix, epInfo.Id[:7])
contIfName := fmt.Sprintf("%s%s-2", hostInterfacePrefix, epInfo.Id[:7])
log.Printf("[net] Creating veth pair %v %v.", hostIfName, contIfName)
err = netlink.AddVethPair(contIfName, hostIfName)
@ -97,6 +105,31 @@ func (nw *network) newEndpoint(endpointId string, ipAddress string) (*endpoint,
goto cleanup
}
// If a name for the container interface is specified...
if epInfo.IfName != "" {
// Interface needs to be down before renaming.
log.Printf("[net] Setting link %v state down.", contIfName)
err = netlink.SetLinkState(contIfName, false)
if err != nil {
goto cleanup
}
// Rename the container interface.
log.Printf("[net] Setting link %v name %v.", contIfName, epInfo.IfName)
err = netlink.SetLinkName(contIfName, epInfo.IfName)
if err != nil {
goto cleanup
}
contIfName = epInfo.IfName
// Bring the interface back up.
log.Printf("[net] Setting link %v state up.", contIfName)
err = netlink.SetLinkState(contIfName, true)
if err != nil {
goto cleanup
}
}
// Assign IP address to container network interface.
log.Printf("[net] Adding IP address %v to link %v.", ipAddr, contIfName)
err = netlink.AddIpAddress(contIfName, ipAddr, ipNet)
@ -106,7 +139,7 @@ func (nw *network) newEndpoint(endpointId string, ipAddress string) (*endpoint,
// Create the endpoint object.
ep = &endpoint{
Id: endpointId,
Id: epInfo.Id,
SrcName: contIfName,
DstPrefix: containerInterfacePrefix,
MacAddress: containerIf.HardwareAddr,
@ -116,7 +149,7 @@ func (nw *network) newEndpoint(endpointId string, ipAddress string) (*endpoint,
IPv6Gateway: nw.extIf.IPv6Gateway,
}
nw.Endpoints[endpointId] = ep
nw.Endpoints[epInfo.Id] = ep
log.Printf("[net] Created endpoint %+v.", ep)

Просмотреть файл

@ -24,12 +24,25 @@ type networkManager struct {
}
// NetworkManager API.
type NetApi interface {
type NetworkManager interface {
Initialize(config *common.PluginConfig) error
Uninitialize()
AddExternalInterface(ifName string, subnet string) error
CreateNetwork(nwInfo *NetworkInfo) error
DeleteNetwork(networkId string) error
GetNetworkInfo(networkId string) (*NetworkInfo, error)
CreateEndpoint(networkId string, epInfo *EndpointInfo) error
DeleteEndpoint(networkId string, endpointId string) error
GetEndpointInfo(networkId string, endpointId string) (*EndpointInfo, error)
AttachEndpoint(networkId string, endpointId string, sandboxKey string) (*endpoint, error)
DetachEndpoint(networkId string, endpointId string) error
}
// Creates a new network manager.
func newNetworkManager() (*networkManager, error) {
func NewNetworkManager() (NetworkManager, error) {
nm := &networkManager{
ExternalInterfaces: make(map[string]*externalInterface),
}
@ -122,11 +135,11 @@ func (nm *networkManager) AddExternalInterface(ifName string, subnet string) err
}
// CreateNetwork creates a new container network.
func (nm *networkManager) CreateNetwork(networkId string, options map[string]interface{}, ipv4Data, ipv6Data []ipamData) error {
func (nm *networkManager) CreateNetwork(nwInfo *NetworkInfo) error {
nm.Lock()
defer nm.Unlock()
_, err := nm.newNetwork(networkId, options, ipv4Data, ipv6Data)
_, err := nm.newNetwork(nwInfo)
if err != nil {
return err
}
@ -157,8 +170,26 @@ func (nm *networkManager) DeleteNetwork(networkId string) error {
return nil
}
// GetNetworkInfo returns information about the given network.
func (nm *networkManager) GetNetworkInfo(networkId string) (*NetworkInfo, error) {
nm.Lock()
defer nm.Unlock()
nw, err := nm.getNetwork(networkId)
if err != nil {
return nil, err
}
nwInfo := &NetworkInfo{
Id: networkId,
Subnets: []string{nw.extIf.Subnets[0]},
}
return nwInfo, nil
}
// CreateEndpoint creates a new container endpoint.
func (nm *networkManager) CreateEndpoint(networkId string, endpointId string, ipAddress string) error {
func (nm *networkManager) CreateEndpoint(networkId string, epInfo *EndpointInfo) error {
nm.Lock()
defer nm.Unlock()
@ -167,7 +198,7 @@ func (nm *networkManager) CreateEndpoint(networkId string, endpointId string, ip
return err
}
_, err = nw.newEndpoint(endpointId, ipAddress)
_, err = nw.newEndpoint(epInfo)
if err != nil {
return err
}
@ -203,6 +234,29 @@ func (nm *networkManager) DeleteEndpoint(networkId string, endpointId string) er
return nil
}
// GetEndpointInfo returns information about the given endpoint.
func (nm *networkManager) GetEndpointInfo(networkId string, endpointId string) (*EndpointInfo, error) {
nm.Lock()
defer nm.Unlock()
nw, err := nm.getNetwork(networkId)
if err != nil {
return nil, err
}
ep, err := nw.getEndpoint(endpointId)
if err != nil {
return nil, err
}
epInfo := &EndpointInfo{
Id: endpointId,
IPv4Address: ep.IPv4Address.String(),
}
return epInfo, nil
}
// AttachEndpoint attaches an endpoint to a sandbox.
func (nm *networkManager) AttachEndpoint(networkId string, endpointId string, sandboxKey string) (*endpoint, error) {
nm.Lock()

Просмотреть файл

@ -38,6 +38,14 @@ type network struct {
extIf *externalInterface
}
// NetworkInfo contains read-only information about a container network.
type NetworkInfo struct {
Id string
Subnets []string
BridgeName string
Options map[string]interface{}
}
type options map[string]interface{}
// NewExternalInterface adds a host interface to the list of available external interfaces.
@ -93,7 +101,7 @@ func (nm *networkManager) findExternalInterfaceBySubnet(subnet string) *external
}
// ConnectExternalInterface connects the given host interface to a bridge.
func (nm *networkManager) connectExternalInterface(extIf *externalInterface) error {
func (nm *networkManager) connectExternalInterface(extIf *externalInterface, bridgeName string) error {
var addrs []net.Addr
log.Printf("[net] Connecting interface %v.", extIf.Name)
@ -104,7 +112,10 @@ func (nm *networkManager) connectExternalInterface(extIf *externalInterface) err
return err
}
bridgeName := fmt.Sprintf("%s%d", bridgePrefix, hostIf.Index)
// If a bridge name is not specified, generate one based on the external interface index.
if bridgeName == "" {
bridgeName = fmt.Sprintf("%s%d", bridgePrefix, hostIf.Index)
}
// Check if the bridge already exists.
bridge, err := net.InterfaceByName(bridgeName)
@ -287,32 +298,23 @@ func (nm *networkManager) disconnectExternalInterface(extIf *externalInterface)
}
// NewNetwork creates a new container network.
func (nm *networkManager) newNetwork(networkId string, options map[string]interface{}, ipv4Data, ipv6Data []ipamData) (*network, error) {
// Assume single pool per address family.
var ipv4Pool, ipv6Pool string
if len(ipv4Data) > 0 {
ipv4Pool = ipv4Data[0].Pool
}
func (nm *networkManager) newNetwork(nwInfo *NetworkInfo) (*network, error) {
if len(ipv6Data) > 0 {
ipv6Pool = ipv6Data[0].Pool
}
log.Printf("[net] Creating network %v for subnet %v %v.", networkId, ipv4Pool, ipv6Pool)
log.Printf("[net] Creating network %+v.", nwInfo)
// Find the external interface for this subnet.
extIf := nm.findExternalInterfaceBySubnet(ipv4Pool)
extIf := nm.findExternalInterfaceBySubnet(nwInfo.Subnets[0])
if extIf == nil {
return nil, fmt.Errorf("Pool not found")
}
if extIf.Networks[networkId] != nil {
if extIf.Networks[nwInfo.Id] != nil {
return nil, errNetworkExists
}
// Connect the external interface if not already connected.
if extIf.BridgeName == "" {
err := nm.connectExternalInterface(extIf)
err := nm.connectExternalInterface(extIf, nwInfo.BridgeName)
if err != nil {
return nil, err
}
@ -320,14 +322,14 @@ func (nm *networkManager) newNetwork(networkId string, options map[string]interf
// Create the network object.
nw := &network{
Id: networkId,
Id: nwInfo.Id,
Endpoints: make(map[string]*endpoint),
extIf: extIf,
}
extIf.Networks[networkId] = nw
extIf.Networks[nwInfo.Id] = nw
log.Printf("[net] Created network %v on interface %v.", networkId, extIf.Name)
log.Printf("[net] Created network %v on interface %v.", nwInfo.Id, extIf.Name)
return nw, nil
}

Просмотреть файл

@ -22,7 +22,7 @@ const (
type netPlugin struct {
*common.Plugin
scope string
nm *networkManager
nm NetworkManager
}
type NetPlugin interface {
@ -38,7 +38,7 @@ func NewPlugin(config *common.PluginConfig) (NetPlugin, error) {
}
// Setup network manager.
nm, err := newNetworkManager()
nm, err := NewNetworkManager()
if err != nil {
return nil, err
}
@ -120,7 +120,21 @@ func (plugin *netPlugin) createNetwork(w http.ResponseWriter, r *http.Request) {
}
// Process request.
err = plugin.nm.CreateNetwork(req.NetworkID, req.Options, req.IPv4Data, req.IPv6Data)
nwInfo := NetworkInfo{
Id: req.NetworkID,
Options: req.Options,
}
// Assume single pool per address family.
if len(req.IPv4Data) > 0 {
nwInfo.Subnets = append(nwInfo.Subnets, req.IPv4Data[0].Pool)
}
if len(req.IPv6Data) > 0 {
nwInfo.Subnets = append(nwInfo.Subnets, req.IPv6Data[0].Pool)
}
err = plugin.nm.CreateNetwork(&nwInfo)
if err != nil {
plugin.SendErrorResponse(w, err)
return
@ -175,7 +189,12 @@ func (plugin *netPlugin) createEndpoint(w http.ResponseWriter, r *http.Request)
ipv4Address = req.Interface.Address
}
err = plugin.nm.CreateEndpoint(req.NetworkID, req.EndpointID, ipv4Address)
epInfo := EndpointInfo{
Id: req.EndpointID,
IPv4Address: ipv4Address,
}
err = plugin.nm.CreateEndpoint(req.NetworkID, &epInfo)
if err != nil {
plugin.SendErrorResponse(w, err)
return