From 09a853257fa9ffaa46970c66f86beda06c5ba4ba Mon Sep 17 00:00:00 2001 From: m1093782566 Date: Sun, 16 Jul 2017 13:35:55 +0800 Subject: [PATCH] wrapper ipvs API as util --- pkg/util/BUILD | 1 + pkg/util/ipvs/BUILD | 71 +++ pkg/util/ipvs/ipvs.go | 92 ++++ pkg/util/ipvs/ipvs_linux.go | 302 ++++++++++++ pkg/util/ipvs/ipvs_linux_test.go | 448 ++++++++++++++++++ pkg/util/ipvs/ipvs_test.go | 265 +++++++++++ pkg/util/ipvs/ipvs_unsupported.go | 79 +++ pkg/util/ipvs/testing/BUILD | 28 ++ pkg/util/ipvs/testing/fake.go | 168 +++++++ vendor/BUILD | 2 + vendor/github.com/vishvananda/netlink/BUILD | 75 +++ .../github.com/vishvananda/netlink/nl/BUILD | 47 ++ vendor/github.com/vishvananda/netns/BUILD | 9 +- 13 files changed, 1585 insertions(+), 2 deletions(-) create mode 100644 pkg/util/ipvs/BUILD create mode 100644 pkg/util/ipvs/ipvs.go create mode 100644 pkg/util/ipvs/ipvs_linux.go create mode 100644 pkg/util/ipvs/ipvs_linux_test.go create mode 100644 pkg/util/ipvs/ipvs_test.go create mode 100644 pkg/util/ipvs/ipvs_unsupported.go create mode 100644 pkg/util/ipvs/testing/BUILD create mode 100644 pkg/util/ipvs/testing/fake.go create mode 100644 vendor/github.com/vishvananda/netlink/BUILD create mode 100644 vendor/github.com/vishvananda/netlink/nl/BUILD diff --git a/pkg/util/BUILD b/pkg/util/BUILD index d8a7be64ef3ba..acda102060276 100644 --- a/pkg/util/BUILD +++ b/pkg/util/BUILD @@ -27,6 +27,7 @@ filegroup( "//pkg/util/io:all-srcs", "//pkg/util/ipconfig:all-srcs", "//pkg/util/iptables:all-srcs", + "//pkg/util/ipvs:all-srcs", "//pkg/util/keymutex:all-srcs", "//pkg/util/labels:all-srcs", "//pkg/util/limitwriter:all-srcs", diff --git a/pkg/util/ipvs/BUILD b/pkg/util/ipvs/BUILD new file mode 100644 index 0000000000000..2a565b7d3bac7 --- /dev/null +++ b/pkg/util/ipvs/BUILD @@ -0,0 +1,71 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_test( + name = "go_default_test", + srcs = [ + "ipvs_test.go", + ] + select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "ipvs_linux_test.go", + ], + "//conditions:default": [], + }), + library = ":go_default_library", + tags = ["automanaged"], + deps = select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "//vendor/github.com/docker/libnetwork/ipvs:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//vendor/k8s.io/utils/exec:go_default_library", + "//vendor/k8s.io/utils/exec/testing:go_default_library", + ], + "//conditions:default": [], + }), +) + +go_library( + name = "go_default_library", + srcs = [ + "ipvs.go", + "ipvs_unsupported.go", + ] + select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "ipvs_linux.go", + ], + "//conditions:default": [], + }), + tags = ["automanaged"], + deps = [ + "//vendor/k8s.io/utils/exec:go_default_library", + ] + select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "//vendor/github.com/docker/libnetwork/ipvs:go_default_library", + "//vendor/github.com/golang/glog:go_default_library", + ], + "//conditions:default": [], + }), +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//pkg/util/ipvs/testing:all-srcs", + ], + tags = ["automanaged"], +) diff --git a/pkg/util/ipvs/ipvs.go b/pkg/util/ipvs/ipvs.go new file mode 100644 index 0000000000000..74917b9b7bf22 --- /dev/null +++ b/pkg/util/ipvs/ipvs.go @@ -0,0 +1,92 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ipvs + +import ( + "net" + "strconv" +) + +// Interface is an injectable interface for running ipvs commands. Implementations must be goroutine-safe. +type Interface interface { + // Flush clears all virtual servers in system. return occurred error immediately. + Flush() error + // EnsureVirtualServerAddressBind checks if virtual server's address is bound to dummy interface and, if not, binds it. If the address is already bound, return true. + EnsureVirtualServerAddressBind(serv *VirtualServer, dev string) (exist bool, err error) + // UnbindVirtualServerAddress checks if virtual server's address is bound to dummy interface and, if so, unbinds it. + UnbindVirtualServerAddress(serv *VirtualServer, dev string) error + // AddVirtualServer creates the specified virtual server. + AddVirtualServer(*VirtualServer) error + // UpdateVirtualServer updates an already existing virtual server. If the virtual server does not exist, return error. + UpdateVirtualServer(*VirtualServer) error + // DeleteVirtualServer deletes the specified virtual server. If the virtual server does not exist, return error. + DeleteVirtualServer(*VirtualServer) error + // Given a partial virtual server, GetVirtualServer will return the specified virtual server information in the system. + GetVirtualServer(*VirtualServer) (*VirtualServer, error) + // GetVirtualServers lists all virtual servers in the system. + GetVirtualServers() ([]*VirtualServer, error) + // AddRealServer creates the specified real server for the specified virtual server. + AddRealServer(*VirtualServer, *RealServer) error + // GetRealServers returns all real servers for the specified virtual server. + GetRealServers(*VirtualServer) ([]*RealServer, error) + // DeleteRealServer deletes the specified real server from the specified virtual server. + DeleteRealServer(*VirtualServer, *RealServer) error +} + +// VirtualServer is an user-oriented definition of an IPVS virtual server in its entirety. +type VirtualServer struct { + Address net.IP + Protocol string + Port uint16 + Scheduler string + Flags ServiceFlags + Timeout uint32 +} + +// ServiceFlags is used to specify session affinity, ip hash etc. +type ServiceFlags uint32 + +const ( + // FlagPersistent specify IPVS service session affinity + FlagPersistent = 0x1 +) + +// Equal check the equality of virtual server. +// We don't use struct == since it doesn't work because of slice. +func (svc *VirtualServer) Equal(other *VirtualServer) bool { + return svc.Address.Equal(other.Address) && + svc.Protocol == other.Protocol && + svc.Port == other.Port && + svc.Scheduler == other.Scheduler && + svc.Flags == other.Flags && + svc.Timeout == other.Timeout +} + +func (svc *VirtualServer) String() string { + return net.JoinHostPort(svc.Address.String(), strconv.Itoa(int(svc.Port))) + "/" + svc.Protocol +} + +// RealServer is an user-oriented definition of an IPVS real server in its entirety. +type RealServer struct { + Address net.IP + Port uint16 + Weight int +} + +func (dest *RealServer) String() string { + return net.JoinHostPort(dest.Address.String(), strconv.Itoa(int(dest.Port))) +} diff --git a/pkg/util/ipvs/ipvs_linux.go b/pkg/util/ipvs/ipvs_linux.go new file mode 100644 index 0000000000000..be50ad515c586 --- /dev/null +++ b/pkg/util/ipvs/ipvs_linux.go @@ -0,0 +1,302 @@ +// +build linux + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ipvs + +import ( + "errors" + "fmt" + "net" + "strings" + "syscall" + + "github.com/docker/libnetwork/ipvs" + "github.com/golang/glog" + utilexec "k8s.io/utils/exec" +) + +const cmdIP = "ip" + +// runner implements Interface. +type runner struct { + exec utilexec.Interface + ipvsHandle *ipvs.Handle +} + +// New returns a new Interface which will call ipvs APIs. +func New(exec utilexec.Interface) Interface { + ihandle, err := ipvs.New("") + if err != nil { + glog.Errorf("IPVS interface can't be initialized, error: %v", err) + return nil + } + return &runner{ + exec: exec, + ipvsHandle: ihandle, + } +} + +// EnsureVirtualServerAddressBind is part of Interface. +func (runner *runner) EnsureVirtualServerAddressBind(vs *VirtualServer, dummyDev string) (exist bool, err error) { + addr := vs.Address.String() + "/32" + args := []string{"addr", "add", addr, "dev", dummyDev} + out, err := runner.exec.Command(cmdIP, args...).CombinedOutput() + if err != nil { + // "exit status 2" will be returned if the address is already bound to dummy device + if ee, ok := err.(utilexec.ExitError); ok { + if ee.Exited() && ee.ExitStatus() == 2 { + return true, nil + } + } + return false, fmt.Errorf("error bind address: %s to dummy interface: %s, err: %v: %s", vs.Address.String(), dummyDev, err, out) + } + return false, nil +} + +// UnbindVirtualServerAddress is part of Interface. +func (runner *runner) UnbindVirtualServerAddress(vs *VirtualServer, dummyDev string) error { + addr := vs.Address.String() + "/32" + args := []string{"addr", "del", addr, "dev", dummyDev} + out, err := runner.exec.Command(cmdIP, args...).CombinedOutput() + if err != nil { + return fmt.Errorf("error unbind address: %s from dummy interface: %s, err: %v: %s", vs.Address.String(), dummyDev, err, out) + } + return nil +} + +// AddVirtualServer is part of Interface. +func (runner *runner) AddVirtualServer(vs *VirtualServer) error { + eSvc, err := toBackendService(vs) + if err != nil { + return err + } + return runner.ipvsHandle.NewService(eSvc) +} + +// UpdateVirtualServer is part of Interface. +func (runner *runner) UpdateVirtualServer(vs *VirtualServer) error { + bSvc, err := toBackendService(vs) + if err != nil { + return err + } + return runner.ipvsHandle.UpdateService(bSvc) +} + +// DeleteVirtualServer is part of Interface. +func (runner *runner) DeleteVirtualServer(vs *VirtualServer) error { + bSvc, err := toBackendService(vs) + if err != nil { + return err + } + return runner.ipvsHandle.DelService(bSvc) +} + +// GetVirtualServer is part of Interface. +func (runner *runner) GetVirtualServer(vs *VirtualServer) (*VirtualServer, error) { + bSvc, err := toBackendService(vs) + if err != nil { + return nil, err + } + ipvsService, err := runner.ipvsHandle.GetService(bSvc) + if err != nil { + return nil, err + } + virtualServer, err := toVirtualServer(ipvsService) + if err != nil { + return nil, err + } + return virtualServer, nil +} + +// GetVirtualServers is part of Interface. +func (runner *runner) GetVirtualServers() ([]*VirtualServer, error) { + ipvsServices, err := runner.ipvsHandle.GetServices() + if err != nil { + return nil, err + } + vss := make([]*VirtualServer, 0) + for _, ipvsService := range ipvsServices { + vs, err := toVirtualServer(ipvsService) + if err != nil { + return nil, err + } + vss = append(vss, vs) + } + return vss, nil +} + +// Flush is part of Interface. Currently we delete IPVS services one by one +func (runner *runner) Flush() error { + vss, err := runner.GetVirtualServers() + if err != nil { + return err + } + for _, vs := range vss { + err := runner.DeleteVirtualServer(vs) + // TODO: aggregate errors? + if err != nil { + return err + } + } + return nil +} + +// AddRealServer is part of Interface. +func (runner *runner) AddRealServer(vs *VirtualServer, rs *RealServer) error { + bSvc, err := toBackendService(vs) + if err != nil { + return err + } + bDst, err := toBackendDestination(rs) + if err != nil { + return err + } + return runner.ipvsHandle.NewDestination(bSvc, bDst) +} + +// DeleteRealServer is part of Interface. +func (runner *runner) DeleteRealServer(vs *VirtualServer, rs *RealServer) error { + bSvc, err := toBackendService(vs) + if err != nil { + return err + } + bDst, err := toBackendDestination(rs) + if err != nil { + return err + } + return runner.ipvsHandle.DelDestination(bSvc, bDst) +} + +// GetRealServers is part of Interface. +func (runner *runner) GetRealServers(vs *VirtualServer) ([]*RealServer, error) { + bSvc, err := toBackendService(vs) + if err != nil { + return nil, err + } + bDestinations, err := runner.ipvsHandle.GetDestinations(bSvc) + if err != nil { + return nil, err + } + realServers := make([]*RealServer, 0) + for _, dest := range bDestinations { + dst, err := toRealServer(dest) + // TODO: aggregate errors? + if err != nil { + return nil, err + } + realServers = append(realServers, dst) + } + return realServers, nil +} + +// toVirtualServer converts an IPVS service representation to the equivalent virtual server structure. +func toVirtualServer(svc *ipvs.Service) (*VirtualServer, error) { + if svc == nil { + return nil, errors.New("ipvs svc should not be empty") + } + vs := &VirtualServer{ + Address: svc.Address, + Port: svc.Port, + Scheduler: svc.SchedName, + Protocol: protocolNumbeToString(ProtoType(svc.Protocol)), + Flags: ServiceFlags(svc.Flags), + Timeout: svc.Timeout, + } + + if vs.Address == nil { + if svc.AddressFamily == syscall.AF_INET { + vs.Address = net.IPv4zero + } else { + vs.Address = net.IPv6zero + } + } + return vs, nil +} + +// toRealServer converts an IPVS destination representation to the equivalent real server structure. +func toRealServer(dst *ipvs.Destination) (*RealServer, error) { + if dst == nil { + return nil, errors.New("ipvs destination should not be empty") + } + return &RealServer{ + Address: dst.Address, + Port: dst.Port, + Weight: dst.Weight, + }, nil +} + +// toBackendService converts an IPVS real server representation to the equivalent "backend" service structure. +func toBackendService(vs *VirtualServer) (*ipvs.Service, error) { + if vs == nil { + return nil, errors.New("virtual server should not be empty") + } + bakSvc := &ipvs.Service{ + Address: vs.Address, + Protocol: stringToProtocolNumber(vs.Protocol), + Port: vs.Port, + SchedName: vs.Scheduler, + Flags: uint32(vs.Flags), + Timeout: vs.Timeout, + } + + if ip4 := vs.Address.To4(); ip4 != nil { + bakSvc.AddressFamily = syscall.AF_INET + bakSvc.Netmask = 0xffffffff + } else { + bakSvc.AddressFamily = syscall.AF_INET6 + bakSvc.Netmask = 128 + } + return bakSvc, nil +} + +// toBackendDestination converts an IPVS real server representation to the equivalent "backend" destination structure. +func toBackendDestination(rs *RealServer) (*ipvs.Destination, error) { + if rs == nil { + return nil, errors.New("real server should not be empty") + } + return &ipvs.Destination{ + Address: rs.Address, + Port: rs.Port, + Weight: rs.Weight, + }, nil +} + +// stringToProtocolNumber returns the protocol value for the given name +func stringToProtocolNumber(protocol string) uint16 { + switch strings.ToLower(protocol) { + case "tcp": + return uint16(syscall.IPPROTO_TCP) + case "udp": + return uint16(syscall.IPPROTO_UDP) + } + return uint16(0) +} + +// protocolNumbeToString returns the name for the given protocol value. +func protocolNumbeToString(proto ProtoType) string { + switch proto { + case syscall.IPPROTO_TCP: + return "TCP" + case syscall.IPPROTO_UDP: + return "UDP" + } + return "" +} + +// ProtoType is IPVS service protocol type +type ProtoType uint16 diff --git a/pkg/util/ipvs/ipvs_linux_test.go b/pkg/util/ipvs/ipvs_linux_test.go new file mode 100644 index 0000000000000..59142c59e521d --- /dev/null +++ b/pkg/util/ipvs/ipvs_linux_test.go @@ -0,0 +1,448 @@ +// +build linux + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ipvs + +import ( + "net" + "reflect" + "syscall" + "testing" + + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/utils/exec" + fakeexec "k8s.io/utils/exec/testing" + + "github.com/docker/libnetwork/ipvs" +) + +const dummyDevice = "kube-ipvs0" + +func TestEnsureVirtualServerAddressBind(t *testing.T) { + vs := &VirtualServer{ + Address: net.ParseIP("10.20.30.40"), + Port: uint16(1234), + Protocol: string("TCP"), + } + fcmd := fakeexec.FakeCmd{ + CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{ + // Success. + func() ([]byte, error) { return []byte{}, nil }, + // Exists. + func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 2} }, + }, + } + fexec := fakeexec.FakeExec{ + CommandScript: []fakeexec.FakeCommandAction{ + func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, + func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, + }, + } + runner := New(&fexec) + // Success. + exists, err := runner.EnsureVirtualServerAddressBind(vs, dummyDevice) + if err != nil { + t.Errorf("expected success, got %v", err) + } + if exists { + t.Errorf("expected exists = false") + } + if fcmd.CombinedOutputCalls != 1 { + t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls) + } + if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ip", "addr", "add", "10.20.30.40/32", "dev", "kube-ipvs0") { + t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0]) + } + // Exists. + exists, err = runner.EnsureVirtualServerAddressBind(vs, dummyDevice) + if err != nil { + t.Errorf("expected success, got %v", err) + } + if !exists { + t.Errorf("expected exists = true") + } +} + +func TestUnbindVirtualServerAddress(t *testing.T) { + svc := &VirtualServer{ + Address: net.ParseIP("10.20.30.41"), + Port: uint16(80), + Protocol: string("TCP"), + } + fcmd := fakeexec.FakeCmd{ + CombinedOutputScript: []fakeexec.FakeCombinedOutputAction{ + // Success. + func() ([]byte, error) { return []byte{}, nil }, + // Failure. + func() ([]byte, error) { return nil, &fakeexec.FakeExitError{Status: 2} }, + }, + } + fexec := fakeexec.FakeExec{ + CommandScript: []fakeexec.FakeCommandAction{ + func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, + func(cmd string, args ...string) exec.Cmd { return fakeexec.InitFakeCmd(&fcmd, cmd, args...) }, + }, + } + runner := New(&fexec) + // Success. + err := runner.UnbindVirtualServerAddress(svc, dummyDevice) + if err != nil { + t.Errorf("expected success, got %v", err) + } + if fcmd.CombinedOutputCalls != 1 { + t.Errorf("expected 1 CombinedOutput() calls, got %d", fcmd.CombinedOutputCalls) + } + if !sets.NewString(fcmd.CombinedOutputLog[0]...).HasAll("ip", "addr", "del", "10.20.30.41/32", "dev", "kube-ipvs0") { + t.Errorf("wrong CombinedOutput() log, got %s", fcmd.CombinedOutputLog[0]) + } + // Failure. + err = runner.UnbindVirtualServerAddress(svc, dummyDevice) + if err == nil { + t.Errorf("expected failure") + } +} + +func Test_toFrontendService(t *testing.T) { + Tests := []struct { + ipvsService ipvs.Service + virtualServer VirtualServer + }{ + { + ipvs.Service{ + Protocol: syscall.IPPROTO_TCP, + Port: 80, + FWMark: 0, + SchedName: "", + Flags: 0, + Timeout: 0, + Netmask: 0xffffffff, + AddressFamily: syscall.AF_INET, + Address: nil, + PEName: "", + }, + VirtualServer{ + Address: net.ParseIP("0.0.0.0"), + Protocol: "TCP", + Port: 80, + Scheduler: "", + Flags: 0, + Timeout: 0, + }, + }, + { + ipvs.Service{ + Protocol: syscall.IPPROTO_UDP, + Port: 33434, + FWMark: 0, + SchedName: "wlc", + Flags: 1234, + Timeout: 100, + Netmask: 128, + AddressFamily: syscall.AF_INET6, + Address: net.ParseIP("2012::beef"), + PEName: "", + }, + VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "UDP", + Port: 33434, + Scheduler: "wlc", + Flags: 1234, + Timeout: 100, + }, + }, + { + ipvs.Service{ + Protocol: 0, + Port: 0, + FWMark: 0, + SchedName: "lc", + Flags: 0, + Timeout: 0, + Netmask: 0xffffffff, + AddressFamily: syscall.AF_INET, + Address: net.ParseIP("1.2.3.4"), + PEName: "", + }, + VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Protocol: "", + Port: 0, + Scheduler: "lc", + Flags: 0, + Timeout: 0, + }, + }, + { + ipvs.Service{ + Protocol: 0, + Port: 0, + FWMark: 0, + SchedName: "wrr", + Flags: 0, + Timeout: 0, + Netmask: 128, + AddressFamily: syscall.AF_INET6, + Address: nil, + PEName: "", + }, + VirtualServer{ + Address: net.ParseIP("::0"), + Protocol: "", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + }, + } + + for i := range Tests { + got, err := toVirtualServer(&Tests[i].ipvsService) + if err != nil { + t.Errorf("case: %d, unexpected error: %v", i, err) + } + if !reflect.DeepEqual(*got, Tests[i].virtualServer) { + t.Errorf("case: %d, got %#v, want %#v", i, *got, Tests[i].virtualServer) + } + } +} + +func Test_toBackendService(t *testing.T) { + Tests := []struct { + ipvsService ipvs.Service + virtualServer VirtualServer + }{ + { + ipvs.Service{ + Protocol: syscall.IPPROTO_TCP, + Port: 80, + FWMark: 0, + SchedName: "", + Flags: 0, + Timeout: 0, + Netmask: 0xffffffff, + AddressFamily: syscall.AF_INET, + Address: net.ParseIP("0.0.0.0"), + PEName: "", + }, + VirtualServer{ + Address: net.ParseIP("0.0.0.0"), + Protocol: "TCP", + Port: 80, + Scheduler: "", + Flags: 0, + Timeout: 0, + }, + }, + { + ipvs.Service{ + Protocol: syscall.IPPROTO_UDP, + Port: 33434, + FWMark: 0, + SchedName: "wlc", + Flags: 1234, + Timeout: 100, + Netmask: 128, + AddressFamily: syscall.AF_INET6, + Address: net.ParseIP("2012::beef"), + PEName: "", + }, + VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "UDP", + Port: 33434, + Scheduler: "wlc", + Flags: 1234, + Timeout: 100, + }, + }, + { + ipvs.Service{ + Protocol: 0, + Port: 0, + FWMark: 0, + SchedName: "lc", + Flags: 0, + Timeout: 0, + Netmask: 0xffffffff, + AddressFamily: syscall.AF_INET, + Address: net.ParseIP("1.2.3.4"), + PEName: "", + }, + VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Protocol: "", + Port: 0, + Scheduler: "lc", + Flags: 0, + Timeout: 0, + }, + }, + { + ipvs.Service{ + Protocol: 0, + Port: 0, + FWMark: 0, + SchedName: "wrr", + Flags: 0, + Timeout: 0, + Netmask: 128, + AddressFamily: syscall.AF_INET6, + Address: net.ParseIP("::0"), + PEName: "", + }, + VirtualServer{ + Address: net.ParseIP("::0"), + Protocol: "", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + }, + } + + for i := range Tests { + got, err := toBackendService(&Tests[i].virtualServer) + if err != nil { + t.Errorf("case: %d, unexpected error: %v", i, err) + } + if !reflect.DeepEqual(*got, Tests[i].ipvsService) { + t.Errorf("case: %d - got %#v, want %#v", i, *got, Tests[i].ipvsService) + } + } +} + +func Test_toFrontendDestination(t *testing.T) { + Tests := []struct { + ipvsDestination ipvs.Destination + realServer RealServer + }{ + { + ipvs.Destination{ + Port: 54321, + ConnectionFlags: 0, + Weight: 1, + Address: net.ParseIP("1.2.3.4"), + }, + RealServer{ + Address: net.ParseIP("1.2.3.4"), + Port: 54321, + Weight: 1, + }, + }, + { + ipvs.Destination{ + Port: 53, + ConnectionFlags: 0, + Weight: 1, + Address: net.ParseIP("2002::cafe"), + }, + RealServer{ + Address: net.ParseIP("2002::cafe"), + Port: 53, + Weight: 1, + }, + }, + } + for i := range Tests { + got, err := toRealServer(&Tests[i].ipvsDestination) + if err != nil { + t.Errorf("case %d unexpected error: %d", i, err) + } + if !reflect.DeepEqual(*got, Tests[i].realServer) { + t.Errorf("case %d Failed to translate Destination - got %#v, want %#v", i, *got, Tests[i].realServer) + } + } +} + +func Test_toBackendDestination(t *testing.T) { + Tests := []struct { + realServer RealServer + ipvsDestination ipvs.Destination + }{ + { + RealServer{ + Address: net.ParseIP("1.2.3.4"), + Port: 54321, + Weight: 1, + }, + ipvs.Destination{ + Port: 54321, + ConnectionFlags: 0, + Weight: 1, + Address: net.ParseIP("1.2.3.4"), + }, + }, + { + RealServer{ + Address: net.ParseIP("2002::cafe"), + Port: 53, + Weight: 1, + }, + ipvs.Destination{ + Port: 53, + ConnectionFlags: 0, + Weight: 1, + Address: net.ParseIP("2002::cafe"), + }, + }, + } + for i := range Tests { + got, err := toBackendDestination(&Tests[i].realServer) + if err != nil { + t.Errorf("case %d unexpected error: %d", i, err) + } + if !reflect.DeepEqual(*got, Tests[i].ipvsDestination) { + t.Errorf("case %d Failed to translate Destination - got %#v, want %#v", i, *got, Tests[i].ipvsDestination) + } + } +} + +func Test_stringToProtocolNumber(t *testing.T) { + tests := []string{ + "TCP", "UDP", "ICMP", + } + expecteds := []uint16{ + uint16(syscall.IPPROTO_TCP), uint16(syscall.IPPROTO_UDP), uint16(0), + } + for i := range tests { + got := stringToProtocolNumber(tests[i]) + if got != expecteds[i] { + t.Errorf("stringToProtocolNumber() failed - got %#v, want %#v", + got, expecteds[i]) + } + } +} + +func Test_protocolNumberToString(t *testing.T) { + tests := []ProtoType{ + syscall.IPPROTO_TCP, syscall.IPPROTO_UDP, ProtoType(0), + } + expecteds := []string{ + "TCP", "UDP", "", + } + for i := range tests { + got := protocolNumbeToString(tests[i]) + if got != expecteds[i] { + t.Errorf("protocolNumbeToString() failed - got %#v, want %#v", + got, expecteds[i]) + } + } +} diff --git a/pkg/util/ipvs/ipvs_test.go b/pkg/util/ipvs/ipvs_test.go new file mode 100644 index 0000000000000..b4abe93831879 --- /dev/null +++ b/pkg/util/ipvs/ipvs_test.go @@ -0,0 +1,265 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ipvs + +import ( + "net" + "testing" +) + +func TestVirtualServerEqual(t *testing.T) { + Tests := []struct { + svcA *VirtualServer + svcB *VirtualServer + equal bool + reason string + }{ + { + svcA: &VirtualServer{ + Address: net.ParseIP("10.20.30.40"), + Protocol: "", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + svcB: &VirtualServer{ + Address: net.ParseIP("10.20.30.41"), + Protocol: "", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + equal: false, + reason: "IPv4 address not equal", + }, + { + svcA: &VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + svcB: &VirtualServer{ + Address: net.ParseIP("2017::beef"), + Protocol: "", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + equal: false, + reason: "IPv6 address not equal", + }, + { + svcA: &VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "TCP", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + svcB: &VirtualServer{ + Address: net.ParseIP("2012::beeef"), + Protocol: "UDP", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + equal: false, + reason: "Protocol not equal", + }, + { + svcA: &VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "TCP", + Port: 80, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + svcB: &VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "TCP", + Port: 8080, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + equal: false, + reason: "Port not equal", + }, + { + svcA: &VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Protocol: "TCP", + Port: 80, + Scheduler: "rr", + Flags: 0, + Timeout: 0, + }, + svcB: &VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Protocol: "TCP", + Port: 80, + Scheduler: "wlc", + Flags: 0, + Timeout: 0, + }, + equal: false, + reason: "Scheduler not equal", + }, + { + svcA: &VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Protocol: "TCP", + Port: 80, + Scheduler: "rr", + Flags: 2, + Timeout: 0, + }, + svcB: &VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Protocol: "TCP", + Port: 80, + Scheduler: "rr", + Flags: 3, + Timeout: 0, + }, + equal: false, + reason: "Flags not equal", + }, + { + svcA: &VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 0, + }, + svcB: &VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "", + Port: 0, + Scheduler: "wrr", + Flags: 0, + Timeout: 10800, + }, + equal: false, + reason: "Timeout not equal", + }, + { + svcA: &VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Protocol: "TCP", + Port: 80, + Scheduler: "rr", + Flags: 0x1, + Timeout: 10800, + }, + svcB: &VirtualServer{ + Address: net.ParseIP("1.2.3.4"), + Protocol: "TCP", + Port: 80, + Scheduler: "rr", + Flags: 0x1, + Timeout: 10800, + }, + equal: true, + reason: "All fields equal", + }, + } + + for i := range Tests { + equal := Tests[i].svcA.Equal(Tests[i].svcB) + if equal != Tests[i].equal { + t.Errorf("case: %d got %v, expected %v, reason: %s", i, equal, Tests[i].equal, Tests[i].reason) + } + } +} + +func TestFrontendServiceString(t *testing.T) { + Tests := []struct { + svc *VirtualServer + expected string + }{ + { + svc: &VirtualServer{ + Address: net.ParseIP("10.20.30.40"), + Protocol: "TCP", + Port: 80, + }, + expected: "10.20.30.40:80/TCP", + }, + { + svc: &VirtualServer{ + Address: net.ParseIP("2012::beef"), + Protocol: "UDP", + Port: 8080, + }, + expected: "[2012::beef]:8080/UDP", + }, + { + svc: &VirtualServer{ + Address: net.ParseIP("10.20.30.41"), + Protocol: "ESP", + Port: 1234, + }, + expected: "10.20.30.41:1234/ESP", + }, + } + + for i := range Tests { + if Tests[i].expected != Tests[i].svc.String() { + t.Errorf("case: %d got %v, expected %v", i, Tests[i].svc.String(), Tests[i].expected) + } + } +} + +func TestFrontendDestinationString(t *testing.T) { + Tests := []struct { + svc *RealServer + expected string + }{ + { + svc: &RealServer{ + Address: net.ParseIP("10.20.30.40"), + Port: 80, + }, + expected: "10.20.30.40:80", + }, + { + svc: &RealServer{ + Address: net.ParseIP("2012::beef"), + Port: 8080, + }, + expected: "[2012::beef]:8080", + }, + } + + for i := range Tests { + if Tests[i].expected != Tests[i].svc.String() { + t.Errorf("case: %d got %v, expected %v", i, Tests[i].svc.String(), Tests[i].expected) + } + } +} diff --git a/pkg/util/ipvs/ipvs_unsupported.go b/pkg/util/ipvs/ipvs_unsupported.go new file mode 100644 index 0000000000000..c2ccce9143bb6 --- /dev/null +++ b/pkg/util/ipvs/ipvs_unsupported.go @@ -0,0 +1,79 @@ +// +build !linux + +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package ipvs + +import ( + "fmt" + + utilexec "k8s.io/utils/exec" +) + +// New returns a dummy Interface for unsupported platform. +func New(utilexec.Interface) Interface { + return &runner{} +} + +type runner struct { +} + +func (runner *runner) Flush() error { + return fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) EnsureVirtualServerAddressBind(*VirtualServer, string) (bool, error) { + return false, fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) UnbindVirtualServerAddress(*VirtualServer, string) error { + return fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) AddVirtualServer(*VirtualServer) error { + return fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) UpdateVirtualServer(*VirtualServer) error { + return fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) DeleteVirtualServer(*VirtualServer) error { + return fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) GetVirtualServer(*VirtualServer) (*VirtualServer, error) { + return nil, fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) GetVirtualServers() ([]*VirtualServer, error) { + return nil, fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) AddRealServer(*VirtualServer, *RealServer) error { + return fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) GetRealServers(*VirtualServer) ([]*RealServer, error) { + return nil, fmt.Errorf("IPVS not supported for this platform") +} + +func (runner *runner) DeleteRealServer(*VirtualServer, *RealServer) error { + return fmt.Errorf("IPVS not supported for this platform") +} + +var _ = Interface(&runner{}) diff --git a/pkg/util/ipvs/testing/BUILD b/pkg/util/ipvs/testing/BUILD new file mode 100644 index 0000000000000..199a1068780e1 --- /dev/null +++ b/pkg/util/ipvs/testing/BUILD @@ -0,0 +1,28 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = ["fake.go"], + tags = ["automanaged"], + deps = ["//pkg/util/ipvs:go_default_library"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/pkg/util/ipvs/testing/fake.go b/pkg/util/ipvs/testing/fake.go new file mode 100644 index 0000000000000..de4acf546e156 --- /dev/null +++ b/pkg/util/ipvs/testing/fake.go @@ -0,0 +1,168 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package testing + +import ( + "fmt" + + utilipvs "k8s.io/kubernetes/pkg/util/ipvs" +) + +//FakeIPVS no-op implementation of ipvs Interface +type FakeIPVS struct { + Scheduler string + Services map[serviceKey]*utilipvs.VirtualServer + Destinations map[serviceKey][]*utilipvs.RealServer +} + +type serviceKey struct { + IP string + Port uint16 + Protocol string +} + +func (s *serviceKey) String() string { + return fmt.Sprintf("%s:%d/%s", s.IP, s.Port, s.Protocol) +} + +//NewFake creates a fake ipvs strucuter +func NewFake() *FakeIPVS { + return &FakeIPVS{ + Services: make(map[serviceKey]*utilipvs.VirtualServer), + Destinations: make(map[serviceKey][]*utilipvs.RealServer), + } +} + +func toServiceKey(serv *utilipvs.VirtualServer) serviceKey { + return serviceKey{ + IP: serv.Address.To4().String(), + Port: serv.Port, + Protocol: serv.Protocol, + } +} + +//EnsureVirtualServerAddressBind is a fake implementation +func (*FakeIPVS) EnsureVirtualServerAddressBind(serv *utilipvs.VirtualServer, dev string) (exist bool, err error) { + return true, nil +} + +//UnbindVirtualServerAddress is a fake implementation +func (*FakeIPVS) UnbindVirtualServerAddress(serv *utilipvs.VirtualServer, dev string) error { + return nil +} + +//AddVirtualServer is a fake implementation +func (f *FakeIPVS) AddVirtualServer(serv *utilipvs.VirtualServer) error { + if serv == nil { + return fmt.Errorf("Failed to add service: service can't be nil") + } + key := toServiceKey(serv) + f.Services[key] = serv + // make sure no destination present when creating new service + f.Destinations = make(map[serviceKey][]*utilipvs.RealServer) + return nil +} + +//UpdateVirtualServer is a fake implementation +func (f *FakeIPVS) UpdateVirtualServer(serv *utilipvs.VirtualServer) error { + if serv == nil { + return fmt.Errorf("Failed to update service, service can't be nil") + } + return nil +} + +//DeleteVirtualServer is a fake implementation +func (f *FakeIPVS) DeleteVirtualServer(serv *utilipvs.VirtualServer) error { + if serv == nil { + return fmt.Errorf("Failed to delete service: service can't be nil") + } + key := toServiceKey(serv) + delete(f.Services, key) + // clear specific destinations as well + f.Destinations[key] = nil + return nil +} + +//GetVirtualServer is a fake implementation +func (f *FakeIPVS) GetVirtualServer(serv *utilipvs.VirtualServer) (*utilipvs.VirtualServer, error) { + if serv == nil { + return nil, fmt.Errorf("Failed to get service: service can't be nil") + } + key := toServiceKey(serv) + svc, found := f.Services[key] + if found { + return svc, nil + } + return nil, fmt.Errorf("Not found serv: %v", key.String()) +} + +//GetVirtualServers is a fake implementation +func (f *FakeIPVS) GetVirtualServers() ([]*utilipvs.VirtualServer, error) { + res := make([]*utilipvs.VirtualServer, 0) + for _, svc := range f.Services { + res = append(res, svc) + } + return res, nil +} + +//Flush is a fake implementation +func (f *FakeIPVS) Flush() error { + // directly drop old data + f.Services = nil + f.Destinations = nil + return nil +} + +//AddRealServer is a fake implementation +func (f *FakeIPVS) AddRealServer(serv *utilipvs.VirtualServer, dest *utilipvs.RealServer) error { + if serv == nil || dest == nil { + return fmt.Errorf("Failed to add destination for service, neither service nor destination shouldn't be nil") + } + key := toServiceKey(serv) + if _, ok := f.Services[key]; !ok { + return fmt.Errorf("Failed to add destination for service %v, service not found", key.String()) + } + dests := f.Destinations[key] + if dests == nil { + dests = make([]*utilipvs.RealServer, 0) + f.Destinations[key] = dests + } + f.Destinations[key] = append(f.Destinations[key], dest) + return nil +} + +//GetRealServers is a fake implementation +func (f *FakeIPVS) GetRealServers(serv *utilipvs.VirtualServer) ([]*utilipvs.RealServer, error) { + if serv == nil { + return nil, fmt.Errorf("Failed to get destination for nil service") + } + key := toServiceKey(serv) + if _, ok := f.Services[key]; !ok { + return nil, fmt.Errorf("Failed to get destinations for service %v, service not found", key.String()) + } + return f.Destinations[key], nil +} + +//DeleteRealServer is a fake implementation +func (*FakeIPVS) DeleteRealServer(serv *utilipvs.VirtualServer, dest *utilipvs.RealServer) error { + if serv == nil || dest == nil { + return fmt.Errorf("Failed to delete destination, neither service nor destination can't be nil") + } + return nil +} + +var _ = utilipvs.Interface(&FakeIPVS{}) diff --git a/vendor/BUILD b/vendor/BUILD index 5250904625235..db6bb3da42788 100644 --- a/vendor/BUILD +++ b/vendor/BUILD @@ -140,6 +140,7 @@ filegroup( "//vendor/github.com/docker/go-connections/sockets:all-srcs", "//vendor/github.com/docker/go-connections/tlsconfig:all-srcs", "//vendor/github.com/docker/go-units:all-srcs", + "//vendor/github.com/docker/libnetwork/ipvs:all-srcs", "//vendor/github.com/docker/spdystream:all-srcs", "//vendor/github.com/elazarl/go-bindata-assetfs:all-srcs", "//vendor/github.com/elazarl/goproxy:all-srcs", @@ -306,6 +307,7 @@ filegroup( "//vendor/github.com/syndtr/gocapability/capability:all-srcs", "//vendor/github.com/ugorji/go/codec:all-srcs", "//vendor/github.com/vishvananda/netlink:all-srcs", + "//vendor/github.com/vishvananda/netns:all-srcs", "//vendor/github.com/vmware/govmomi:all-srcs", "//vendor/github.com/vmware/photon-controller-go-sdk/SSPI:all-srcs", "//vendor/github.com/vmware/photon-controller-go-sdk/photon:all-srcs", diff --git a/vendor/github.com/vishvananda/netlink/BUILD b/vendor/github.com/vishvananda/netlink/BUILD new file mode 100644 index 0000000000000..8eb0340a4cd09 --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/BUILD @@ -0,0 +1,75 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "addr.go", + "class.go", + "conntrack_unspecified.go", + "filter.go", + "genetlink_unspecified.go", + "handle_unspecified.go", + "link.go", + "neigh.go", + "netlink.go", + "netlink_unspecified.go", + "order.go", + "protinfo.go", + "qdisc.go", + "route.go", + "route_unspecified.go", + "rule.go", + "socket.go", + "xfrm.go", + "xfrm_policy.go", + "xfrm_state.go", + ] + select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "addr_linux.go", + "bpf_linux.go", + "bridge_linux.go", + "class_linux.go", + "conntrack_linux.go", + "filter_linux.go", + "genetlink_linux.go", + "gtp_linux.go", + "handle_linux.go", + "link_linux.go", + "link_tuntap_linux.go", + "neigh_linux.go", + "netlink_linux.go", + "protinfo_linux.go", + "qdisc_linux.go", + "route_linux.go", + "rule_linux.go", + "socket_linux.go", + "xfrm_monitor_linux.go", + "xfrm_policy_linux.go", + "xfrm_state_linux.go", + ], + "//conditions:default": [], + }), + cgo = True, + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/vishvananda/netlink/nl:go_default_library", + "//vendor/github.com/vishvananda/netns:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//vendor/github.com/vishvananda/netlink/nl:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/vishvananda/netlink/nl/BUILD b/vendor/github.com/vishvananda/netlink/nl/BUILD new file mode 100644 index 0000000000000..e9f3cf5aec5c6 --- /dev/null +++ b/vendor/github.com/vishvananda/netlink/nl/BUILD @@ -0,0 +1,47 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "nl_unspecified.go", + "syscall.go", + ] + select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "addr_linux.go", + "bridge_linux.go", + "conntrack_linux.go", + "genetlink_linux.go", + "link_linux.go", + "mpls_linux.go", + "nl_linux.go", + "route_linux.go", + "tc_linux.go", + "xfrm_linux.go", + "xfrm_monitor_linux.go", + "xfrm_policy_linux.go", + "xfrm_state_linux.go", + ], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "//vendor/github.com/vishvananda/netns:go_default_library", + ], + "//conditions:default": [], + }), +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/vendor/github.com/vishvananda/netns/BUILD b/vendor/github.com/vishvananda/netns/BUILD index 2665ac8cd3007..47eb850f9bee4 100644 --- a/vendor/github.com/vishvananda/netns/BUILD +++ b/vendor/github.com/vishvananda/netns/BUILD @@ -11,8 +11,13 @@ go_library( name = "go_default_library", srcs = [ "netns.go", - "netns_linux.go", - ], + "netns_unspecified.go", + ] + select({ + "@io_bazel_rules_go//go/platform:linux_amd64": [ + "netns_linux.go", + ], + "//conditions:default": [], + }), tags = ["automanaged"], )