2017-02-11 03:15:53 +03:00
|
|
|
// Copyright 2017 Microsoft. All rights reserved.
|
|
|
|
// MIT License
|
|
|
|
|
|
|
|
// +build linux
|
2016-09-22 01:39:25 +03:00
|
|
|
|
|
|
|
package network
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
|
2016-10-07 00:40:29 +03:00
|
|
|
"github.com/Azure/azure-container-networking/ebtables"
|
|
|
|
"github.com/Azure/azure-container-networking/log"
|
|
|
|
"github.com/Azure/azure-container-networking/netlink"
|
2016-09-22 01:39:25 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Prefix for host virtual network interface names.
|
|
|
|
hostInterfacePrefix = "veth"
|
|
|
|
|
|
|
|
// Prefix for container network interface names.
|
|
|
|
containerInterfacePrefix = "eth"
|
|
|
|
)
|
|
|
|
|
2017-02-11 03:15:53 +03:00
|
|
|
// newEndpointImpl creates a new endpoint in the network.
|
|
|
|
func (nw *network) newEndpointImpl(epInfo *EndpointInfo) (*endpoint, error) {
|
2016-09-22 01:39:25 +03:00
|
|
|
var containerIf *net.Interface
|
2016-11-23 02:28:57 +03:00
|
|
|
var ns *Namespace
|
2016-09-22 01:39:25 +03:00
|
|
|
var ep *endpoint
|
|
|
|
var err error
|
|
|
|
|
|
|
|
// Create a veth pair.
|
2016-11-22 23:31:48 +03:00
|
|
|
hostIfName := fmt.Sprintf("%s%s", hostInterfacePrefix, epInfo.Id[:7])
|
|
|
|
contIfName := fmt.Sprintf("%s%s-2", hostInterfacePrefix, epInfo.Id[:7])
|
2016-09-22 01:39:25 +03:00
|
|
|
|
2016-11-22 23:19:54 +03:00
|
|
|
log.Printf("[net] Creating veth pair %v %v.", hostIfName, contIfName)
|
2017-02-28 12:27:20 +03:00
|
|
|
|
|
|
|
link := netlink.VEthLink{
|
|
|
|
LinkInfo: netlink.LinkInfo{
|
|
|
|
Type: netlink.LINK_TYPE_VETH,
|
|
|
|
Name: contIfName,
|
|
|
|
},
|
|
|
|
PeerName: hostIfName,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = netlink.AddLink(&link)
|
2016-09-22 01:39:25 +03:00
|
|
|
if err != nil {
|
2016-11-23 02:28:57 +03:00
|
|
|
log.Printf("[net] Failed to create veth pair, err:%v.", err)
|
2016-09-22 01:39:25 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-11-22 23:19:54 +03:00
|
|
|
//
|
|
|
|
// Host network interface setup.
|
|
|
|
//
|
2016-09-22 01:39:25 +03:00
|
|
|
|
|
|
|
// Host interface up.
|
2016-11-22 23:19:54 +03:00
|
|
|
log.Printf("[net] Setting link %v state up.", hostIfName)
|
2016-09-22 01:39:25 +03:00
|
|
|
err = netlink.SetLinkState(hostIfName, true)
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect host interface to the bridge.
|
2016-11-22 23:19:54 +03:00
|
|
|
log.Printf("[net] Setting link %v master %v.", hostIfName, nw.extIf.BridgeName)
|
2016-09-22 01:39:25 +03:00
|
|
|
err = netlink.SetLinkMaster(hostIfName, nw.extIf.BridgeName)
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
|
|
|
|
2016-11-22 23:19:54 +03:00
|
|
|
//
|
|
|
|
// Container network interface setup.
|
|
|
|
//
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
// Query container network interface info.
|
|
|
|
containerIf, err = net.InterfaceByName(contIfName)
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup MAC address translation rules for container interface.
|
2016-11-22 23:19:54 +03:00
|
|
|
log.Printf("[net] Setting up MAC address translation rules for endpoint %v.", contIfName)
|
2016-12-13 03:03:10 +03:00
|
|
|
for _, ipAddr := range epInfo.IPAddresses {
|
2017-03-07 03:24:20 +03:00
|
|
|
err = ebtables.SetDnatForIPAddress(nw.extIf.Name, ipAddr.IP, containerIf.HardwareAddr, ebtables.Append)
|
2016-12-13 03:03:10 +03:00
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
|
|
|
|
2016-11-23 02:28:57 +03:00
|
|
|
// If a network namespace for the container interface is specified...
|
|
|
|
if epInfo.NetNsPath != "" {
|
|
|
|
// Open the network namespace.
|
|
|
|
log.Printf("[net] Opening netns %v.", epInfo.NetNsPath)
|
|
|
|
ns, err = OpenNamespace(epInfo.NetNsPath)
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
|
|
|
defer ns.Close()
|
|
|
|
|
|
|
|
// Move the container interface to container's network namespace.
|
|
|
|
log.Printf("[net] Setting link %v netns %v.", contIfName, epInfo.NetNsPath)
|
|
|
|
err = netlink.SetLinkNetNs(contIfName, ns.GetFd())
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
|
|
|
|
|
|
|
// Enter the container network namespace.
|
|
|
|
log.Printf("[net] Entering netns %v.", epInfo.NetNsPath)
|
|
|
|
err = ns.Enter()
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-22 23:31:48 +03:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-22 23:19:54 +03:00
|
|
|
// Assign IP address to container network interface.
|
2016-12-13 03:03:10 +03:00
|
|
|
for _, ipAddr := range epInfo.IPAddresses {
|
|
|
|
log.Printf("[net] Adding IP address %v to link %v.", ipAddr.String(), contIfName)
|
|
|
|
err = netlink.AddIpAddress(contIfName, ipAddr.IP, &ipAddr)
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add IP routes to container network interface.
|
|
|
|
for _, route := range epInfo.Routes {
|
|
|
|
log.Printf("[net] Adding IP route %+v to link %v.", route, contIfName)
|
|
|
|
|
|
|
|
nlRoute := &netlink.Route{
|
|
|
|
Family: netlink.GetIpAddressFamily(route.Gw),
|
|
|
|
Dst: &route.Dst,
|
|
|
|
Gw: route.Gw,
|
|
|
|
LinkIndex: containerIf.Index,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = netlink.AddIpRoute(nlRoute)
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
2016-11-22 23:19:54 +03:00
|
|
|
}
|
|
|
|
|
2016-11-23 02:28:57 +03:00
|
|
|
// If inside the container network namespace...
|
|
|
|
if ns != nil {
|
|
|
|
// Return to host network namespace.
|
|
|
|
log.Printf("[net] Exiting netns %v.", epInfo.NetNsPath)
|
|
|
|
err = ns.Exit()
|
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
// Create the endpoint object.
|
|
|
|
ep = &endpoint{
|
2016-11-22 23:31:48 +03:00
|
|
|
Id: epInfo.Id,
|
2016-12-08 02:56:19 +03:00
|
|
|
IfName: contIfName,
|
|
|
|
HostIfName: hostIfName,
|
2016-09-22 01:39:25 +03:00
|
|
|
MacAddress: containerIf.HardwareAddr,
|
2016-12-13 03:03:10 +03:00
|
|
|
IPAddresses: epInfo.IPAddresses,
|
|
|
|
Gateways: []net.IP{nw.extIf.IPv4Gateway},
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return ep, nil
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
// Roll back the changes for the endpoint.
|
|
|
|
netlink.DeleteLink(contIfName)
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-02-11 03:15:53 +03:00
|
|
|
// deleteEndpointImpl deletes an existing endpoint from the network.
|
|
|
|
func (nw *network) deleteEndpointImpl(ep *endpoint) error {
|
2016-12-08 02:56:19 +03:00
|
|
|
// Delete the veth pair by deleting one of the peer interfaces.
|
|
|
|
// Deleting the host interface is more convenient since it does not require
|
|
|
|
// entering the container netns and hence works both for CNI and CNM.
|
|
|
|
log.Printf("[net] Deleting veth pair %v %v.", ep.HostIfName, ep.IfName)
|
2017-02-11 03:15:53 +03:00
|
|
|
err := netlink.DeleteLink(ep.HostIfName)
|
2016-12-08 02:56:19 +03:00
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
2016-09-22 01:39:25 +03:00
|
|
|
|
2016-12-08 02:56:19 +03:00
|
|
|
// Delete MAC address translation rule.
|
2017-02-11 03:15:53 +03:00
|
|
|
log.Printf("[net] Deleting MAC address translation rules for endpoint %v.", ep.Id)
|
2016-12-13 03:03:10 +03:00
|
|
|
for _, ipAddr := range ep.IPAddresses {
|
2017-03-07 03:24:20 +03:00
|
|
|
err = ebtables.SetDnatForIPAddress(nw.extIf.Name, ipAddr.IP, ep.MacAddress, ebtables.Delete)
|
2016-12-13 03:03:10 +03:00
|
|
|
if err != nil {
|
|
|
|
goto cleanup
|
|
|
|
}
|
2016-12-08 02:56:19 +03:00
|
|
|
}
|
2016-09-22 01:39:25 +03:00
|
|
|
|
2016-12-08 02:56:19 +03:00
|
|
|
cleanup:
|
|
|
|
return err
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
2017-05-17 23:36:57 +03:00
|
|
|
|
|
|
|
// getInfoImpl returns information about the endpoint.
|
|
|
|
func (ep *endpoint) getInfoImpl(epInfo *EndpointInfo) {
|
|
|
|
}
|