2017-02-11 03:15:53 +03:00
|
|
|
// Copyright 2017 Microsoft. All rights reserved.
|
|
|
|
// MIT License
|
|
|
|
|
2016-02-10 23:23:26 +03:00
|
|
|
package network
|
2015-12-02 00:58:59 +03:00
|
|
|
|
|
|
|
import (
|
2016-09-22 01:39:25 +03:00
|
|
|
"fmt"
|
|
|
|
"net"
|
2018-07-06 21:45:47 +03:00
|
|
|
"strconv"
|
2018-02-22 22:22:47 +03:00
|
|
|
"strings"
|
2016-09-22 01:39:25 +03:00
|
|
|
|
2020-04-16 08:30:48 +03:00
|
|
|
"github.com/Azure/azure-container-networking/iptables"
|
2016-10-07 00:40:29 +03:00
|
|
|
"github.com/Azure/azure-container-networking/log"
|
|
|
|
"github.com/Azure/azure-container-networking/netlink"
|
2020-04-16 08:30:48 +03:00
|
|
|
"github.com/Azure/azure-container-networking/network/epcommon"
|
2019-05-01 02:27:48 +03:00
|
|
|
"github.com/Azure/azure-container-networking/platform"
|
2016-09-22 01:39:25 +03:00
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// Prefix for bridge names.
|
2016-11-22 23:19:54 +03:00
|
|
|
bridgePrefix = "azure"
|
2017-03-07 03:24:20 +03:00
|
|
|
// Virtual MAC address used by Azure VNET.
|
2019-05-01 02:27:48 +03:00
|
|
|
virtualMacAddress = "12:34:56:78:9a:bc"
|
|
|
|
versionID = "VERSION_ID"
|
|
|
|
distroID = "ID"
|
|
|
|
ubuntuStr = "ubuntu"
|
|
|
|
dnsServersStr = "DNS Servers"
|
2019-05-03 01:51:40 +03:00
|
|
|
dnsDomainStr = "DNS Domain"
|
2019-05-01 02:27:48 +03:00
|
|
|
ubuntuVersion17 = 17
|
|
|
|
defaultDnsServerIP = "168.63.129.16"
|
|
|
|
systemdResolvConfFile = "/run/systemd/resolve/resolv.conf"
|
|
|
|
SnatBridgeIPKey = "snatBridgeIP"
|
|
|
|
LocalIPKey = "localIP"
|
|
|
|
InfraVnetIPKey = "infraVnetIP"
|
|
|
|
OptVethName = "vethname"
|
|
|
|
)
|
2018-08-19 00:50:49 +03:00
|
|
|
|
2019-05-01 02:27:48 +03:00
|
|
|
const (
|
|
|
|
lineDelimiter = "\n"
|
|
|
|
colonDelimiter = ":"
|
|
|
|
dotDelimiter = "."
|
2015-12-02 00:58:59 +03:00
|
|
|
)
|
|
|
|
|
2017-02-11 03:15:53 +03:00
|
|
|
// Linux implementation of route.
|
|
|
|
type route netlink.Route
|
2016-11-22 23:31:48 +03:00
|
|
|
|
2017-02-11 03:15:53 +03:00
|
|
|
// NewNetworkImpl creates a new container network.
|
|
|
|
func (nm *networkManager) newNetworkImpl(nwInfo *NetworkInfo, extIf *externalInterface) (*network, error) {
|
2017-03-02 03:59:37 +03:00
|
|
|
// Connect the external interface.
|
2018-07-06 21:45:47 +03:00
|
|
|
var vlanid int
|
|
|
|
opt, _ := nwInfo.Options[genericData].(map[string]interface{})
|
|
|
|
log.Printf("opt %+v options %+v", opt, nwInfo.Options)
|
|
|
|
|
2017-03-03 04:52:43 +03:00
|
|
|
switch nwInfo.Mode {
|
2017-03-07 03:24:20 +03:00
|
|
|
case opModeTunnel:
|
|
|
|
fallthrough
|
|
|
|
case opModeBridge:
|
2018-07-06 21:45:47 +03:00
|
|
|
log.Printf("create bridge")
|
|
|
|
if err := nm.connectExternalInterface(extIf, nwInfo); err != nil {
|
2017-02-11 03:15:53 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
2018-07-06 21:45:47 +03:00
|
|
|
|
|
|
|
if opt != nil && opt[VlanIDKey] != nil {
|
|
|
|
vlanid, _ = strconv.Atoi(opt[VlanIDKey].(string))
|
|
|
|
}
|
2019-07-17 03:09:34 +03:00
|
|
|
|
2019-01-05 03:19:36 +03:00
|
|
|
case opModeTransparent:
|
|
|
|
break
|
2017-03-02 03:59:37 +03:00
|
|
|
default:
|
2017-03-07 03:24:20 +03:00
|
|
|
return nil, errNetworkModeInvalid
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
|
|
|
|
2017-02-11 03:15:53 +03:00
|
|
|
// Create the network object.
|
|
|
|
nw := &network{
|
2018-07-06 21:45:47 +03:00
|
|
|
Id: nwInfo.Id,
|
|
|
|
Mode: nwInfo.Mode,
|
|
|
|
Endpoints: make(map[string]*endpoint),
|
|
|
|
extIf: extIf,
|
|
|
|
VlanId: vlanid,
|
2018-08-19 00:50:49 +03:00
|
|
|
DNS: nwInfo.DNS,
|
2018-07-06 21:45:47 +03:00
|
|
|
EnableSnatOnHost: nwInfo.EnableSnatOnHost,
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
|
|
|
|
2017-02-11 03:15:53 +03:00
|
|
|
return nw, nil
|
2016-06-03 05:02:07 +03:00
|
|
|
}
|
|
|
|
|
2017-02-11 03:15:53 +03:00
|
|
|
// DeleteNetworkImpl deletes an existing container network.
|
|
|
|
func (nm *networkManager) deleteNetworkImpl(nw *network) error {
|
2018-07-06 21:45:47 +03:00
|
|
|
var networkClient NetworkClient
|
|
|
|
|
|
|
|
if nw.VlanId != 0 {
|
2019-07-17 03:09:34 +03:00
|
|
|
networkClient = NewOVSClient(nw.extIf.BridgeName, nw.extIf.Name)
|
2018-07-06 21:45:47 +03:00
|
|
|
} else {
|
2020-04-16 08:30:48 +03:00
|
|
|
networkClient = NewLinuxBridgeClient(nw.extIf.BridgeName, nw.extIf.Name, NetworkInfo{})
|
2018-07-06 21:45:47 +03:00
|
|
|
}
|
|
|
|
|
2017-02-11 03:15:53 +03:00
|
|
|
// Disconnect the interface if this was the last network using it.
|
2017-02-28 12:27:20 +03:00
|
|
|
if len(nw.extIf.Networks) == 1 {
|
2018-07-06 21:45:47 +03:00
|
|
|
nm.disconnectExternalInterface(nw.extIf, networkClient)
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
2016-06-03 05:02:07 +03:00
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-03-02 03:59:37 +03:00
|
|
|
// SaveIPConfig saves the IP configuration of an interface.
|
|
|
|
func (nm *networkManager) saveIPConfig(hostIf *net.Interface, extIf *externalInterface) error {
|
2017-03-03 04:52:43 +03:00
|
|
|
// Save the default routes on the interface.
|
|
|
|
routes, err := netlink.GetIpRoute(&netlink.Route{Dst: &net.IPNet{}, LinkIndex: hostIf.Index})
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[net] Failed to query routes: %v.", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, r := range routes {
|
|
|
|
if r.Dst == nil {
|
|
|
|
if r.Family == unix.AF_INET {
|
|
|
|
extIf.IPv4Gateway = r.Gw
|
|
|
|
} else if r.Family == unix.AF_INET6 {
|
|
|
|
extIf.IPv6Gateway = r.Gw
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extIf.Routes = append(extIf.Routes, (*route)(r))
|
|
|
|
}
|
|
|
|
|
2017-03-02 03:59:37 +03:00
|
|
|
// Save global unicast IP addresses on the interface.
|
|
|
|
addrs, err := hostIf.Addrs()
|
|
|
|
for _, addr := range addrs {
|
|
|
|
ipAddr, ipNet, err := net.ParseCIDR(addr.String())
|
|
|
|
ipNet.IP = ipAddr
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if !ipAddr.IsGlobalUnicast() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
extIf.IPAddresses = append(extIf.IPAddresses, ipNet)
|
|
|
|
|
|
|
|
log.Printf("[net] Deleting IP address %v from interface %v.", ipNet, hostIf.Name)
|
|
|
|
|
|
|
|
err = netlink.DeleteIpAddress(hostIf.Name, ipAddr, ipNet)
|
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("[net] Saved interface IP configuration %+v.", extIf)
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-05-01 02:27:48 +03:00
|
|
|
func getMajorVersion(version string) (int, error) {
|
|
|
|
versionSplit := strings.Split(version, dotDelimiter)
|
|
|
|
if len(versionSplit) > 0 {
|
|
|
|
retrieved_version, err := strconv.Atoi(versionSplit[0])
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return retrieved_version, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0, fmt.Errorf("[net] Error getting major version")
|
|
|
|
}
|
|
|
|
|
|
|
|
func isGreaterOrEqaulUbuntuVersion(versionToMatch int) bool {
|
|
|
|
osInfo, err := platform.GetOSDetails()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[net] Unable to get OS Details: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("[net] OSInfo: %+v", osInfo)
|
|
|
|
|
|
|
|
version := osInfo[versionID]
|
|
|
|
distro := osInfo[distroID]
|
|
|
|
|
|
|
|
if strings.EqualFold(distro, ubuntuStr) {
|
|
|
|
version = strings.Trim(version, "\"")
|
|
|
|
retrieved_version, err := getMajorVersion(version)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[net] Not setting dns. Unable to retrieve major version: %v", err)
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if retrieved_version >= versionToMatch {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-05-03 01:51:40 +03:00
|
|
|
func readDnsInfo(ifName string) (DNSInfo, error) {
|
|
|
|
var dnsInfo DNSInfo
|
|
|
|
|
2019-05-01 02:27:48 +03:00
|
|
|
cmd := fmt.Sprintf("systemd-resolve --status %s", ifName)
|
|
|
|
out, err := platform.ExecuteCommand(cmd)
|
|
|
|
if err != nil {
|
2019-05-03 01:51:40 +03:00
|
|
|
return dnsInfo, err
|
2019-05-01 02:27:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("[net] console output for above cmd: %s", out)
|
|
|
|
|
|
|
|
lineArr := strings.Split(out, lineDelimiter)
|
|
|
|
if len(lineArr) <= 0 {
|
2019-05-03 01:51:40 +03:00
|
|
|
return dnsInfo, fmt.Errorf("[net] Console output doesn't have any lines")
|
2019-05-01 02:27:48 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, line := range lineArr {
|
|
|
|
if strings.Contains(line, dnsServersStr) {
|
|
|
|
dnsServerSplit := strings.Split(line, colonDelimiter)
|
|
|
|
if len(dnsServerSplit) > 1 {
|
2019-05-03 01:51:40 +03:00
|
|
|
dnsServerSplit[1] = strings.TrimSpace(dnsServerSplit[1])
|
|
|
|
dnsInfo.Servers = append(dnsInfo.Servers, dnsServerSplit[1])
|
|
|
|
}
|
|
|
|
} else if strings.Contains(line, dnsDomainStr) {
|
|
|
|
dnsDomainSplit := strings.Split(line, colonDelimiter)
|
|
|
|
if len(dnsDomainSplit) > 1 {
|
|
|
|
dnsInfo.Suffix = strings.TrimSpace(dnsDomainSplit[1])
|
2019-05-01 02:27:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-03 01:51:40 +03:00
|
|
|
return dnsInfo, nil
|
2019-05-01 02:27:48 +03:00
|
|
|
}
|
|
|
|
|
2019-05-03 01:51:40 +03:00
|
|
|
func saveDnsConfig(extIf *externalInterface) error {
|
|
|
|
dnsInfo, err := readDnsInfo(extIf.Name)
|
|
|
|
if err != nil || len(dnsInfo.Servers) == 0 || dnsInfo.Suffix == "" {
|
|
|
|
log.Printf("[net] Failed to read dns info %+v from interface %v: %v", dnsInfo, extIf.Name, err)
|
|
|
|
return err
|
2019-05-01 02:27:48 +03:00
|
|
|
}
|
|
|
|
|
2019-05-03 01:51:40 +03:00
|
|
|
extIf.DNSInfo = dnsInfo
|
|
|
|
log.Printf("[net] Saved DNS Info %v from %v", extIf.DNSInfo, extIf.Name)
|
|
|
|
|
|
|
|
return nil
|
2019-05-01 02:27:48 +03:00
|
|
|
}
|
|
|
|
|
2017-03-02 03:59:37 +03:00
|
|
|
// ApplyIPConfig applies a previously saved IP configuration to an interface.
|
|
|
|
func (nm *networkManager) applyIPConfig(extIf *externalInterface, targetIf *net.Interface) error {
|
|
|
|
// Add IP addresses.
|
|
|
|
for _, addr := range extIf.IPAddresses {
|
2017-03-03 04:52:43 +03:00
|
|
|
log.Printf("[net] Adding IP address %v to interface %v.", addr, targetIf.Name)
|
2017-03-02 03:59:37 +03:00
|
|
|
|
2017-03-03 04:52:43 +03:00
|
|
|
err := netlink.AddIpAddress(targetIf.Name, addr.IP, addr)
|
2018-02-22 22:22:47 +03:00
|
|
|
if err != nil && !strings.Contains(strings.ToLower(err.Error()), "file exists") {
|
2017-03-02 03:59:37 +03:00
|
|
|
log.Printf("[net] Failed to add IP address %v: %v.", addr, err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add IP routes.
|
|
|
|
for _, route := range extIf.Routes {
|
|
|
|
route.LinkIndex = targetIf.Index
|
|
|
|
|
|
|
|
log.Printf("[net] Adding IP route %+v.", route)
|
|
|
|
|
|
|
|
err := netlink.AddIpRoute((*netlink.Route)(route))
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[net] Failed to add IP route %v: %v.", route, err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-05-01 02:27:48 +03:00
|
|
|
func applyDnsConfig(extIf *externalInterface, ifName string) error {
|
2019-09-21 02:15:08 +03:00
|
|
|
var err error
|
|
|
|
|
|
|
|
if extIf != nil && len(extIf.DNSInfo.Servers) > 0 {
|
|
|
|
cmd := fmt.Sprintf("systemd-resolve --interface=%s --set-dns=%s", ifName, extIf.DNSInfo.Servers[0])
|
|
|
|
_, err = platform.ExecuteCommand(cmd)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd = fmt.Sprintf("systemd-resolve --interface=%s --set-domain=%s", ifName, extIf.DNSInfo.Suffix)
|
|
|
|
_, err = platform.ExecuteCommand(cmd)
|
2019-05-03 01:51:40 +03:00
|
|
|
}
|
|
|
|
|
2019-05-01 02:27:48 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
// ConnectExternalInterface connects the given host interface to a bridge.
|
2017-03-07 03:24:20 +03:00
|
|
|
func (nm *networkManager) connectExternalInterface(extIf *externalInterface, nwInfo *NetworkInfo) error {
|
2020-04-16 08:30:48 +03:00
|
|
|
var (
|
|
|
|
err error
|
|
|
|
networkClient NetworkClient
|
|
|
|
)
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
log.Printf("[net] Connecting interface %v.", extIf.Name)
|
2017-08-17 00:13:46 +03:00
|
|
|
defer func() { log.Printf("[net] Connecting interface %v completed with err:%v.", extIf.Name, err) }()
|
2016-09-22 01:39:25 +03:00
|
|
|
|
2017-03-02 03:59:37 +03:00
|
|
|
// Check whether this interface is already connected.
|
|
|
|
if extIf.BridgeName != "" {
|
|
|
|
log.Printf("[net] Interface is already connected to bridge %v.", extIf.BridgeName)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
// Find the external interface.
|
|
|
|
hostIf, err := net.InterfaceByName(extIf.Name)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2016-06-03 05:02:07 +03:00
|
|
|
}
|
|
|
|
|
2016-11-22 23:31:48 +03:00
|
|
|
// If a bridge name is not specified, generate one based on the external interface index.
|
2017-03-07 03:24:20 +03:00
|
|
|
bridgeName := nwInfo.BridgeName
|
2016-11-22 23:31:48 +03:00
|
|
|
if bridgeName == "" {
|
|
|
|
bridgeName = fmt.Sprintf("%s%d", bridgePrefix, hostIf.Index)
|
|
|
|
}
|
2016-11-22 23:19:54 +03:00
|
|
|
|
2018-07-06 21:45:47 +03:00
|
|
|
opt, _ := nwInfo.Options[genericData].(map[string]interface{})
|
|
|
|
if opt != nil && opt[VlanIDKey] != nil {
|
2019-07-17 03:09:34 +03:00
|
|
|
networkClient = NewOVSClient(bridgeName, extIf.Name)
|
2018-07-06 21:45:47 +03:00
|
|
|
} else {
|
2020-04-16 08:30:48 +03:00
|
|
|
networkClient = NewLinuxBridgeClient(bridgeName, extIf.Name, *nwInfo)
|
2018-07-06 21:45:47 +03:00
|
|
|
}
|
|
|
|
|
2016-11-22 23:19:54 +03:00
|
|
|
// Check if the bridge already exists.
|
2016-09-22 01:39:25 +03:00
|
|
|
bridge, err := net.InterfaceByName(bridgeName)
|
|
|
|
if err != nil {
|
2016-11-22 23:19:54 +03:00
|
|
|
// Create the bridge.
|
2020-04-16 08:30:48 +03:00
|
|
|
if err = networkClient.CreateBridge(); err != nil {
|
2018-07-06 21:45:47 +03:00
|
|
|
log.Printf("Error while creating bridge %+v", err)
|
2016-09-22 01:39:25 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
bridge, err = net.InterfaceByName(bridgeName)
|
|
|
|
if err != nil {
|
2017-08-17 00:13:46 +03:00
|
|
|
return err
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
2016-11-22 23:19:54 +03:00
|
|
|
} else {
|
|
|
|
// Use the existing bridge.
|
|
|
|
log.Printf("[net] Found existing bridge %v.", bridgeName)
|
2016-06-03 05:02:07 +03:00
|
|
|
}
|
|
|
|
|
2020-04-16 08:30:48 +03:00
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[net] cleanup network")
|
|
|
|
nm.disconnectExternalInterface(extIf, networkClient)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2017-03-02 03:59:37 +03:00
|
|
|
// Save host IP configuration.
|
|
|
|
err = nm.saveIPConfig(hostIf, extIf)
|
2016-09-22 01:39:25 +03:00
|
|
|
if err != nil {
|
2017-03-02 03:59:37 +03:00
|
|
|
log.Printf("[net] Failed to save IP configuration for interface %v: %v.", hostIf.Name, err)
|
2016-06-03 05:02:07 +03:00
|
|
|
}
|
|
|
|
|
2019-05-01 02:27:48 +03:00
|
|
|
isGreaterOrEqualUbuntu17 := isGreaterOrEqaulUbuntuVersion(ubuntuVersion17)
|
|
|
|
if isGreaterOrEqualUbuntu17 {
|
|
|
|
log.Printf("[net] Saving dns config from %v", extIf.Name)
|
2020-04-16 08:30:48 +03:00
|
|
|
if err = saveDnsConfig(extIf); err != nil {
|
2019-05-03 01:51:40 +03:00
|
|
|
log.Printf("[net] Failed to save dns config: %v", err)
|
|
|
|
return err
|
|
|
|
}
|
2019-05-01 02:27:48 +03:00
|
|
|
}
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
// External interface down.
|
2016-11-22 23:19:54 +03:00
|
|
|
log.Printf("[net] Setting link %v state down.", hostIf.Name)
|
2016-09-22 01:39:25 +03:00
|
|
|
err = netlink.SetLinkState(hostIf.Name, false)
|
|
|
|
if err != nil {
|
2017-08-17 00:13:46 +03:00
|
|
|
return err
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
2016-06-03 05:02:07 +03:00
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
// Connect the external interface to the bridge.
|
2016-11-22 23:19:54 +03:00
|
|
|
log.Printf("[net] Setting link %v master %v.", hostIf.Name, bridgeName)
|
2020-04-16 08:30:48 +03:00
|
|
|
if err = networkClient.SetBridgeMasterToHostInterface(); err != nil {
|
2017-08-17 00:13:46 +03:00
|
|
|
return err
|
2016-06-03 05:02:07 +03:00
|
|
|
}
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
// External interface up.
|
2016-11-22 23:19:54 +03:00
|
|
|
log.Printf("[net] Setting link %v state up.", hostIf.Name)
|
2016-09-22 01:39:25 +03:00
|
|
|
err = netlink.SetLinkState(hostIf.Name, true)
|
2016-06-03 05:02:07 +03:00
|
|
|
if err != nil {
|
2017-08-17 00:13:46 +03:00
|
|
|
return err
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
|
|
|
|
2018-07-06 21:45:47 +03:00
|
|
|
// Bridge up.
|
|
|
|
log.Printf("[net] Setting link %v state up.", bridgeName)
|
|
|
|
err = netlink.SetLinkState(bridgeName, true)
|
2017-03-31 16:45:28 +03:00
|
|
|
if err != nil {
|
2017-08-17 00:13:46 +03:00
|
|
|
return err
|
2017-03-31 16:45:28 +03:00
|
|
|
}
|
|
|
|
|
2018-07-06 21:45:47 +03:00
|
|
|
// Add the bridge rules.
|
|
|
|
err = networkClient.AddL2Rules(extIf)
|
2016-09-22 01:39:25 +03:00
|
|
|
if err != nil {
|
2017-08-17 00:13:46 +03:00
|
|
|
return err
|
2016-09-22 01:39:25 +03:00
|
|
|
}
|
|
|
|
|
2018-07-06 21:45:47 +03:00
|
|
|
// External interface hairpin on.
|
2020-01-17 01:27:25 +03:00
|
|
|
if !nwInfo.DisableHairpinOnHostInterface {
|
|
|
|
log.Printf("[net] Setting link %v hairpin on.", hostIf.Name)
|
2020-04-16 08:30:48 +03:00
|
|
|
if err = networkClient.SetHairpinOnHostInterface(true); err != nil {
|
2020-01-17 01:27:25 +03:00
|
|
|
return err
|
|
|
|
}
|
2018-07-06 21:45:47 +03:00
|
|
|
}
|
|
|
|
|
2017-03-02 03:59:37 +03:00
|
|
|
// Apply IP configuration to the bridge for host traffic.
|
|
|
|
err = nm.applyIPConfig(extIf, bridge)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("[net] Failed to apply interface IP configuration: %v.", err)
|
2019-05-01 02:27:48 +03:00
|
|
|
return err
|
2016-06-03 05:02:07 +03:00
|
|
|
}
|
|
|
|
|
2019-05-01 02:27:48 +03:00
|
|
|
if isGreaterOrEqualUbuntu17 {
|
|
|
|
log.Printf("[net] Applying dns config on %v", bridgeName)
|
|
|
|
|
2020-04-16 08:30:48 +03:00
|
|
|
if err = applyDnsConfig(extIf, bridgeName); err != nil {
|
2019-05-01 02:27:48 +03:00
|
|
|
log.Printf("[net] Failed to apply DNS configuration: %v.", err)
|
|
|
|
return err
|
|
|
|
}
|
2016-09-22 01:39:25 +03:00
|
|
|
|
2019-05-03 01:51:40 +03:00
|
|
|
log.Printf("[net] Applied dns config %v on %v", extIf.DNSInfo, bridgeName)
|
2019-05-01 02:27:48 +03:00
|
|
|
}
|
|
|
|
|
2020-09-30 00:43:19 +03:00
|
|
|
err = networkClient.AddRoutes(nwInfo, bridgeName)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-04-16 08:30:48 +03:00
|
|
|
if nwInfo.IPV6Mode == IPV6Nat {
|
|
|
|
// adds pod cidr gateway ip to bridge
|
|
|
|
if err = addIpv6NatGateway(nwInfo); err != nil {
|
|
|
|
log.Errorf("[net] Adding IPv6 Nat Gateway failed:%v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = addIpv6SnatRule(extIf, nwInfo); err != nil {
|
|
|
|
log.Errorf("[net] Adding IPv6 Snat Rule failed:%v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// unmark packet if set by kube-proxy to skip kube-postrouting rule and processed
|
|
|
|
// by cni snat rule
|
|
|
|
if err = iptables.InsertIptableRule(iptables.V6, iptables.Mangle, iptables.Postrouting, "", "MARK --set-mark 0x0"); err != nil {
|
|
|
|
log.Errorf("[net] Adding Iptable mangle rule failed:%v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-01 02:27:48 +03:00
|
|
|
extIf.BridgeName = bridgeName
|
2016-09-22 01:39:25 +03:00
|
|
|
log.Printf("[net] Connected interface %v to bridge %v.", extIf.Name, extIf.BridgeName)
|
2016-06-03 05:02:07 +03:00
|
|
|
|
|
|
|
return nil
|
2015-12-02 00:58:59 +03:00
|
|
|
}
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
// DisconnectExternalInterface disconnects a host interface from its bridge.
|
2018-07-06 21:45:47 +03:00
|
|
|
func (nm *networkManager) disconnectExternalInterface(extIf *externalInterface, networkClient NetworkClient) {
|
2016-09-22 01:39:25 +03:00
|
|
|
log.Printf("[net] Disconnecting interface %v.", extIf.Name)
|
|
|
|
|
2018-07-06 21:45:47 +03:00
|
|
|
log.Printf("[net] Deleting bridge rules")
|
2017-03-07 03:24:20 +03:00
|
|
|
// Delete bridge rules set on the external interface.
|
2018-07-06 21:45:47 +03:00
|
|
|
networkClient.DeleteL2Rules(extIf)
|
2016-09-22 01:39:25 +03:00
|
|
|
|
2018-07-06 21:45:47 +03:00
|
|
|
log.Printf("[net] Deleting bridge")
|
|
|
|
// Delete Bridge
|
|
|
|
networkClient.DeleteBridge()
|
2016-06-03 05:02:07 +03:00
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
extIf.BridgeName = ""
|
2018-07-06 21:45:47 +03:00
|
|
|
log.Printf("Restoring ipconfig with primary interface %v", extIf.Name)
|
2016-06-03 05:02:07 +03:00
|
|
|
|
2017-03-02 03:59:37 +03:00
|
|
|
// Restore IP configuration.
|
|
|
|
hostIf, _ := net.InterfaceByName(extIf.Name)
|
2018-07-06 21:45:47 +03:00
|
|
|
err := nm.applyIPConfig(extIf, hostIf)
|
2017-03-02 03:59:37 +03:00
|
|
|
if err != nil {
|
|
|
|
log.Printf("[net] Failed to apply IP configuration: %v.", err)
|
2016-06-03 05:02:07 +03:00
|
|
|
}
|
|
|
|
|
2016-09-22 01:39:25 +03:00
|
|
|
extIf.IPAddresses = nil
|
|
|
|
extIf.Routes = nil
|
|
|
|
|
|
|
|
log.Printf("[net] Disconnected interface %v.", extIf.Name)
|
2018-07-06 21:45:47 +03:00
|
|
|
}
|
2016-06-03 05:02:07 +03:00
|
|
|
|
2020-04-16 08:30:48 +03:00
|
|
|
// Add ipv6 nat gateway IP on bridge
|
|
|
|
func addIpv6NatGateway(nwInfo *NetworkInfo) error {
|
|
|
|
log.Printf("[net] Adding ipv6 nat gateway on azure bridge")
|
|
|
|
for _, subnetInfo := range nwInfo.Subnets {
|
|
|
|
if subnetInfo.Family == platform.AfINET6 {
|
|
|
|
ipAddr := []net.IPNet{{
|
|
|
|
IP: subnetInfo.Gateway,
|
|
|
|
Mask: subnetInfo.Prefix.Mask,
|
|
|
|
}}
|
|
|
|
return epcommon.AssignIPToInterface(nwInfo.BridgeName, ipAddr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// snat ipv6 traffic to secondary ipv6 ip before leaving VM
|
|
|
|
func addIpv6SnatRule(extIf *externalInterface, nwInfo *NetworkInfo) error {
|
|
|
|
log.Printf("[net] Adding ipv6 snat rule")
|
|
|
|
for _, ipAddr := range extIf.IPAddresses {
|
|
|
|
if ipAddr.IP.To4() == nil {
|
|
|
|
if err := epcommon.AddSnatRule("", ipAddr.IP); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-06 21:45:47 +03:00
|
|
|
func getNetworkInfoImpl(nwInfo *NetworkInfo, nw *network) {
|
|
|
|
if nw.VlanId != 0 {
|
|
|
|
vlanMap := make(map[string]interface{})
|
|
|
|
vlanMap[VlanIDKey] = strconv.Itoa(nw.VlanId)
|
|
|
|
nwInfo.Options[genericData] = vlanMap
|
|
|
|
}
|
2016-06-03 05:02:07 +03:00
|
|
|
}
|
2018-08-19 00:50:49 +03:00
|
|
|
|
|
|
|
func AddStaticRoute(ip string, interfaceName string) error {
|
|
|
|
log.Printf("[ovs] Adding %v static route", ip)
|
|
|
|
var routes []RouteInfo
|
|
|
|
_, ipNet, _ := net.ParseCIDR(ip)
|
|
|
|
gwIP := net.ParseIP("0.0.0.0")
|
|
|
|
route := RouteInfo{Dst: *ipNet, Gw: gwIP}
|
|
|
|
routes = append(routes, route)
|
|
|
|
if err := addRoutes(interfaceName, routes); err != nil {
|
|
|
|
if err != nil && !strings.Contains(strings.ToLower(err.Error()), "file exists") {
|
|
|
|
log.Printf("addroutes failed with error %v", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|