Skip to content

Commit

Permalink
reuse local-redirect CIDR to select public IP (to listen on)
Browse files Browse the repository at this point in the history
* at node's startup, if its `config.HostNet.Hostname` is empty:
  - list local unicast IPs;
  - if there's more than one: use local-redirect CIDR to make the selection.
* in effect, reuse local-redirect CIDR for the second purpose
* with refactoring and comments inline

Signed-off-by: Alex Aizman <[email protected]>
  • Loading branch information
alex-aizman committed Aug 8, 2024
1 parent 268cfd1 commit 8defcb3
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 28 deletions.
17 changes: 7 additions & 10 deletions ais/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,6 @@ var _ cos.Runner = (*proxy)(nil)

func (*proxy) Name() string { return apc.Proxy } // as cos.Runner

func (p *proxy) initClusterCIDR() {
if nodeCIDR := os.Getenv("AIS_CLUSTER_CIDR"); nodeCIDR != "" {
_, network, err := net.ParseCIDR(nodeCIDR)
p.si.LocalNet = network
cos.AssertNoErr(err)
nlog.Infof("local network: %+v", *network)
}
}

func (p *proxy) init(config *cmn.Config) {
p.initSnode(config)

Expand All @@ -103,7 +94,13 @@ func (p *proxy) init(config *cmn.Config) {

cos.InitShortID(p.si.Digest())

p.initClusterCIDR()
if network, err := localRedirectCIDR(); err != nil {
cos.ExitLog(err) // FATAL
} else {
p.si.LocalNet = network
nlog.Infoln("using local redirect CIDR:", network.String())
}

daemon.rg.add(p)

ps := &stats.Prunner{}
Expand Down
91 changes: 77 additions & 14 deletions ais/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"strings"

"github.com/NVIDIA/aistore/api/apc"
"github.com/NVIDIA/aistore/api/env"
"github.com/NVIDIA/aistore/cmn"
"github.com/NVIDIA/aistore/cmn/cos"
"github.com/NVIDIA/aistore/cmn/k8s"
Expand All @@ -33,6 +34,8 @@ const (
accessNetAll = accessNetPublic | accessNetIntraData | accessNetIntraControl
)

const fmtErrParseIP = "failed to parse local unicast IP address: %s"

// Network access of handlers (Public, IntraControl, & IntraData)
type (
netAccess int
Expand All @@ -51,6 +54,16 @@ type (

func (na netAccess) isSet(flag netAccess) bool { return na&flag == flag }

func (addr *localIPv4Info) String() string {
return fmt.Sprintf("unicast IP: %s (MTU %d)", addr.ipv4, addr.mtu)
}

func (addr *localIPv4Info) warn() {
if addr.mtu <= 1500 {
nlog.Warningln("Warning: small MTU")
}
}

//
// IPV4
//
Expand Down Expand Up @@ -171,32 +184,82 @@ func _selectHost(locIPs []*localIPv4Info, hostnames []string) (string, error) {
}

// _localIP takes a list of local IPv4s and returns the best fit for a daemon to listen on it
func _localIP(addrList []*localIPv4Info) (ip net.IP, err error) {
if len(addrList) == 0 {
return nil, errors.New("no addresses to choose from")
func _localIP(addrList []*localIPv4Info) (ip net.IP, _ error) {
l := len(addrList)
if l == 0 {
return nil, errors.New("no unicast addresses to choose from")
}
if len(addrList) == 1 {
nlog.Infof("Found only one IPv4: %s, MTU %d", addrList[0].ipv4, addrList[0].mtu)
if addrList[0].mtu <= 1500 {
nlog.Warningf("IPv4 %s MTU size is small: %d\n", addrList[0].ipv4, addrList[0].mtu)
}
if l == 1 {
if ip = net.ParseIP(addrList[0].ipv4); ip == nil {
return nil, fmt.Errorf("failed to parse IP address: %s", addrList[0].ipv4)
return nil, fmt.Errorf(fmtErrParseIP, addrList[0].ipv4)
}
nlog.Infoln("Found a single", addrList[0].String())
addrList[0].warn()
return ip, nil
}
if cmn.Rom.FastV(4, cos.SmoduleAIS) {
nlog.Infof("%d IPv4s:", len(addrList))
for _, addr := range addrList {
nlog.Infof(" %#v\n", *addr)

// always log when multi-choice
nlog.Infoln(l, "local unicast IPs:")
for _, addr := range addrList {
nlog.Infoln(" ", addr.String())
}

// NOTE:
// reusing local-redirect CIDR ("AIS_CLUSTER_CIDR") for the second and separate purpose -
// to select public IP (to listen on) from the `addrList` of local unicast IP interfaces

var (
selected = -1
parsed net.IP
network, err = localRedirectCIDR()
)
if err != nil {
return nil, err
}
if network == nil {
goto warn
}
for j := range l {
if ip = net.ParseIP(addrList[j].ipv4); ip == nil {
return nil, fmt.Errorf(fmtErrParseIP, addrList[0].ipv4)
}
if network.Contains(ip) {
if selected >= 0 {
return nil, fmt.Errorf("CIDR network %s contains multiple local unicast IPs: %s and %s",
network, addrList[selected].ipv4, addrList[j].ipv4)
}
selected, parsed = j, ip
}
}
if selected < 0 {
nlog.Warningln("CIDR network", network.String(), "does not contain any local unicast IPs")
goto warn
}
nlog.Infoln("CIDR network", network.String(), "contains a single local unicast IP:", addrList[selected].ipv4)
addrList[selected].warn()
return parsed, nil

warn:
if ip = net.ParseIP(addrList[0].ipv4); ip == nil {
return nil, fmt.Errorf("failed to parse IP address: %s", addrList[0].ipv4)
return nil, fmt.Errorf(fmtErrParseIP, addrList[0].ipv4)
}
nlog.Warningln("given multiple choice, selecting the first", addrList[0].String())
addrList[0].warn()
return ip, nil
}

func localRedirectCIDR() (*net.IPNet, error) {
cidr := os.Getenv(env.AIS.LocalRedirectCIDR)
if cidr == "" {
return nil, nil
}
_, network, err := net.ParseCIDR(cidr)
if err != nil {
return nil, fmt.Errorf("invalid '%s=%s': %v", env.AIS.LocalRedirectCIDR, cidr, err)
}
return network, nil
}

func multihome(configuredIPv4s string) (pub string, extra []string) {
if i := strings.IndexByte(configuredIPv4s, cmn.HostnameListSepa[0]); i <= 0 {
cos.ExitAssertLog(i < 0, "invalid format:", configuredIPv4s)
Expand Down
19 changes: 15 additions & 4 deletions api/env/ais.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,36 @@
*/
package env

// See also:
// NOTE not included:
// - "AIS_READ_HEADER_TIMEOUT"
// - "AIS_DAEMON_ID"
// - "AIS_CLUSTER_CIDR", "AIS_HOST_IP", "AIS_HOST_PORT"
// - "AIS_TARGET_URL"
// - "AIS_HOST_IP", "AIS_HOST_PORT" - local playground (target only)
// - "AIS_TARGET_URL" - ETL
//
// See also:
// - docs/environment-vars.md

var (
AIS = struct {
// endpoint: client | primary startup
Endpoint string
PrimaryEP string
UseHTTPS string

// networking: local redirect
LocalRedirectCIDR string

// https
UseHTTPS string
// TLS: client side
Certificate string
CertKey string
ClientCA string
SkipVerifyCrt string

// tests, CI
NumTarget string
NumProxy string

// K8s
K8sPod string
K8sNode string
Expand All @@ -35,6 +43,9 @@ var (
Endpoint: "AIS_ENDPOINT",
PrimaryEP: "AIS_PRIMARY_EP",

// differentiate local (same CIDR) clients for faster HTTP redirect
LocalRedirectCIDR: "AIS_CLUSTER_CIDR",

// false: HTTP transport, with all the TLS config (below) ignored
// true: HTTPS/TLS
UseHTTPS: "AIS_USE_HTTPS", // cluster config: "net.http.use_https"
Expand Down

0 comments on commit 8defcb3

Please sign in to comment.