From b485f7b5b425ba6cf18b19d70c29c8f4a17f84fa Mon Sep 17 00:00:00 2001 From: Zihong Zheng Date: Fri, 16 Feb 2018 19:09:33 -0800 Subject: [PATCH 1/8] [kube-proxy] Move Service/EndpointInfo common codes to change tracker --- pkg/proxy/endpoints.go | 79 ++++++- pkg/proxy/endpoints_test.go | 334 +++++++++++++---------------- pkg/proxy/iptables/proxier.go | 205 +++++------------- pkg/proxy/iptables/proxier_test.go | 173 +++++++-------- pkg/proxy/ipvs/proxier.go | 256 ++++++---------------- pkg/proxy/ipvs/proxier_test.go | 236 ++++++++++---------- pkg/proxy/service.go | 129 +++++++++-- pkg/proxy/service_test.go | 112 +++------- pkg/proxy/types.go | 21 +- 9 files changed, 701 insertions(+), 844 deletions(-) diff --git a/pkg/proxy/endpoints.go b/pkg/proxy/endpoints.go index 62f3aabbbd5..8f1ae4260f0 100644 --- a/pkg/proxy/endpoints.go +++ b/pkg/proxy/endpoints.go @@ -17,16 +17,63 @@ limitations under the License. package proxy import ( + "net" "reflect" + "strconv" "sync" "github.com/golang/glog" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/record" api "k8s.io/kubernetes/pkg/apis/core" + utilproxy "k8s.io/kubernetes/pkg/proxy/util" ) +// EndpointInfoCommon contains common endpoint information. +type EndpointInfoCommon struct { + Endpoint string // TODO: should be an endpointString type + // IsLocal indicates whether the endpoint is running in same host as kube-proxy. + IsLocal bool +} + +var _ Endpoint = &EndpointInfoCommon{} + +// String is part of proxy.Endpoint interface. +func (info *EndpointInfoCommon) String() string { + return info.Endpoint +} + +// IsLocal is part of proxy.Endpoint interface. +func (info *EndpointInfoCommon) GetIsLocal() bool { + return info.IsLocal +} + +// IP returns just the IP part of the endpoint, it's a part of proxy.Endpoint interface. +func (info *EndpointInfoCommon) IP() string { + return utilproxy.IPPart(info.Endpoint) +} + +// Port returns just the Port part of the endpoint. +func (info *EndpointInfoCommon) Port() (int, error) { + return utilproxy.PortPart(info.Endpoint) +} + +// Equal is part of proxy.Endpoint interface. +func (info *EndpointInfoCommon) Equal(other Endpoint) bool { + return info.String() == other.String() && info.GetIsLocal() == other.GetIsLocal() +} + +func newEndpointInfoCommon(IP string, port int, isLocal bool) *EndpointInfoCommon { + return &EndpointInfoCommon{ + Endpoint: net.JoinHostPort(IP, strconv.Itoa(port)), + IsLocal: isLocal, + } +} + +type customizeEndpointInfoFunc func(IP string, port int, isLocal bool, info *EndpointInfoCommon) Endpoint + // EndpointChangeTracker carries state about uncommitted changes to an arbitrary number of // Endpoints, keyed by their namespace and name. type EndpointChangeTracker struct { @@ -36,13 +83,21 @@ type EndpointChangeTracker struct { hostname string // items maps a service to is endpointsChange. items map[types.NamespacedName]*endpointsChange + // customizeEndpointInfo allows proxier to inject customized infomation when processing endpoint. + customizeEndpointInfo customizeEndpointInfoFunc + // isIPv6Mode indicates if change tracker is under IPv6/IPv4 mode. Nil means not applicable. + isIPv6Mode *bool + recorder record.EventRecorder } // NewEndpointChangeTracker initializes an EndpointsChangeMap -func NewEndpointChangeTracker(hostname string) *EndpointChangeTracker { +func NewEndpointChangeTracker(hostname string, customizeEndpointInfo customizeEndpointInfoFunc, isIPv6Mode *bool, recorder record.EventRecorder) *EndpointChangeTracker { return &EndpointChangeTracker{ hostname: hostname, items: make(map[types.NamespacedName]*endpointsChange), + customizeEndpointInfo: customizeEndpointInfo, + isIPv6Mode: isIPv6Mode, + recorder: recorder, } } @@ -54,7 +109,7 @@ func NewEndpointChangeTracker(hostname string) *EndpointChangeTracker { // - pass as the pair. // Delete item // - pass as the pair. -func (ect *EndpointChangeTracker) Update(previous, current *api.Endpoints, makeEndpoints func(IP string, port int, isLocal bool) Endpoint) bool { +func (ect *EndpointChangeTracker) Update(previous, current *api.Endpoints) bool { endpoints := current if endpoints == nil { endpoints = previous @@ -71,10 +126,10 @@ func (ect *EndpointChangeTracker) Update(previous, current *api.Endpoints, makeE change, exists := ect.items[namespacedName] if !exists { change = &endpointsChange{} - change.previous = endpointsToEndpointsMap(previous, ect.hostname, makeEndpoints) + change.previous = ect.endpointsToEndpointsMap(previous) ect.items[namespacedName] = change } - change.current = endpointsToEndpointsMap(current, ect.hostname, makeEndpoints) + change.current = ect.endpointsToEndpointsMap(current) // if change.previous equal to change.current, it means no change if reflect.DeepEqual(change.previous, change.current) { delete(ect.items, namespacedName) @@ -118,14 +173,14 @@ func UpdateEndpointsMap(endpointsMap EndpointsMap, changes *EndpointChangeTracke return result } -// EndpointsMap maps a service to one of its endpoint. +// EndpointsMap maps a service to one of its Endpoint. type EndpointsMap map[ServicePortName][]Endpoint // endpointsToEndpointsMap translates single Endpoints object to EndpointsMap. // This function is used for incremental updated of endpointsMap. // // NOTE: endpoints object should NOT be modified. -func endpointsToEndpointsMap(endpoints *api.Endpoints, hostname string, makeEndpoints func(IP string, port int, isLocal bool) Endpoint) EndpointsMap { +func (ect *EndpointChangeTracker) endpointsToEndpointsMap(endpoints *api.Endpoints) EndpointsMap { if endpoints == nil { return nil } @@ -151,9 +206,13 @@ func endpointsToEndpointsMap(endpoints *api.Endpoints, hostname string, makeEndp glog.Warningf("ignoring invalid endpoint port %s with empty host", port.Name) continue } - isLocal := addr.NodeName != nil && *addr.NodeName == hostname - epInfo := makeEndpoints(addr.IP, int(port.Port), isLocal) - endpointsMap[svcPortName] = append(endpointsMap[svcPortName], epInfo) + isLocal := addr.NodeName != nil && *addr.NodeName == ect.hostname + epInfoCommon := newEndpointInfoCommon(addr.IP, int(port.Port), isLocal) + if ect.customizeEndpointInfo != nil { + endpointsMap[svcPortName] = append(endpointsMap[svcPortName], ect.customizeEndpointInfo(addr.IP, int(port.Port), isLocal, epInfoCommon)) + } else { + endpointsMap[svcPortName] = append(endpointsMap[svcPortName], epInfoCommon) + } } if glog.V(3) { newEPList := []string{} @@ -203,7 +262,7 @@ func GetLocalEndpointIPs(endpointsMap EndpointsMap) map[types.NamespacedName]set localIPs := make(map[types.NamespacedName]sets.String) for svcPortName, epList := range endpointsMap { for _, ep := range epList { - if ep.IsLocal() { + if ep.GetIsLocal() { nsn := svcPortName.NamespacedName if localIPs[nsn] == nil { localIPs[nsn] = sets.NewString() diff --git a/pkg/proxy/endpoints_test.go b/pkg/proxy/endpoints_test.go index 76c68e47910..664a804c646 100644 --- a/pkg/proxy/endpoints_test.go +++ b/pkg/proxy/endpoints_test.go @@ -17,9 +17,7 @@ limitations under the License. package proxy import ( - "net" "reflect" - "strconv" "testing" "github.com/davecgh/go-spew/spew" @@ -30,48 +28,16 @@ import ( api "k8s.io/kubernetes/pkg/apis/core" ) -type fakeEndpointsInfo struct { - endpoint string - isLocal bool -} - -func newFakeEndpointsInfo(IP string, port int, isLocal bool) Endpoint { - return &fakeEndpointsInfo{ - endpoint: net.JoinHostPort(IP, strconv.Itoa(port)), - isLocal: isLocal, - } -} - -func (f *fakeEndpointsInfo) String() string { - return f.endpoint -} - -func (f *fakeEndpointsInfo) IsLocal() bool { - return f.isLocal -} - -func (f *fakeEndpointsInfo) IP() string { - // Must be IP:port - host, _, _ := net.SplitHostPort(f.endpoint) - return host -} - -func (f *fakeEndpointsInfo) Equal(other Endpoint) bool { - return f.String() == other.String() && - f.IsLocal() == other.IsLocal() && - f.IP() == other.IP() -} - func (proxier *FakeProxier) addEndpoints(endpoints *api.Endpoints) { - proxier.endpointsChanges.Update(nil, endpoints, newFakeEndpointsInfo) + proxier.endpointsChanges.Update(nil, endpoints) } func (proxier *FakeProxier) updateEndpoints(oldEndpoints, endpoints *api.Endpoints) { - proxier.endpointsChanges.Update(oldEndpoints, endpoints, newFakeEndpointsInfo) + proxier.endpointsChanges.Update(oldEndpoints, endpoints) } func (proxier *FakeProxier) deleteEndpoints(endpoints *api.Endpoints) { - proxier.endpointsChanges.Update(endpoints, nil, newFakeEndpointsInfo) + proxier.endpointsChanges.Update(endpoints, nil) } func TestGetLocalEndpointIPs(t *testing.T) { @@ -86,7 +52,7 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[1]: unnamed port endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", ""): []Endpoint{ - &fakeEndpointsInfo{endpoint: "1.1.1.1:11", isLocal: false}, + &EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expected: map[types.NamespacedName]sets.String{}, @@ -94,7 +60,7 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[2]: unnamed port local endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", ""): []Endpoint{ - &fakeEndpointsInfo{endpoint: "1.1.1.1:11", isLocal: true}, + &EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -104,12 +70,12 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[3]: named local and non-local ports for the same IP. endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", "p11"): []Endpoint{ - &fakeEndpointsInfo{endpoint: "1.1.1.1:11", isLocal: false}, - &fakeEndpointsInfo{endpoint: "1.1.1.2:11", isLocal: true}, + &EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}, + &EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): []Endpoint{ - &fakeEndpointsInfo{endpoint: "1.1.1.1:12", isLocal: false}, - &fakeEndpointsInfo{endpoint: "1.1.1.2:12", isLocal: true}, + &EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}, + &EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -119,21 +85,21 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[4]: named local and non-local ports for different IPs. endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", "p11"): []Endpoint{ - &fakeEndpointsInfo{endpoint: "1.1.1.1:11", isLocal: false}, + &EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns2", "ep2", "p22"): []Endpoint{ - &fakeEndpointsInfo{endpoint: "2.2.2.2:22", isLocal: true}, - &fakeEndpointsInfo{endpoint: "2.2.2.22:22", isLocal: true}, + &EndpointInfoCommon{Endpoint: "2.2.2.2:22", IsLocal: true}, + &EndpointInfoCommon{Endpoint: "2.2.2.22:22", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p23"): []Endpoint{ - &fakeEndpointsInfo{endpoint: "2.2.2.3:23", isLocal: true}, + &EndpointInfoCommon{Endpoint: "2.2.2.3:23", IsLocal: true}, }, makeServicePortName("ns4", "ep4", "p44"): []Endpoint{ - &fakeEndpointsInfo{endpoint: "4.4.4.4:44", isLocal: true}, - &fakeEndpointsInfo{endpoint: "4.4.4.5:44", isLocal: false}, + &EndpointInfoCommon{Endpoint: "4.4.4.4:44", IsLocal: true}, + &EndpointInfoCommon{Endpoint: "4.4.4.5:44", IsLocal: false}, }, makeServicePortName("ns4", "ep4", "p45"): []Endpoint{ - &fakeEndpointsInfo{endpoint: "4.4.4.6:45", isLocal: true}, + &EndpointInfoCommon{Endpoint: "4.4.4.6:45", IsLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -164,14 +130,16 @@ func makeTestEndpoints(namespace, name string, eptFunc func(*api.Endpoints)) *ap } // This is a coarse test, but it offers some modicum of confidence as the code is evolved. -func Test_endpointsToEndpointsMap(t *testing.T) { +func TestEndpointsToEndpointsMap(t *testing.T) { + epTracker := NewEndpointChangeTracker("test-hostname", nil, nil, nil) + testCases := []struct { newEndpoints *api.Endpoints - expected map[ServicePortName][]*fakeEndpointsInfo + expected map[ServicePortName][]*EndpointInfoCommon }{{ // Case[0]: nothing newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) {}), - expected: map[ServicePortName][]*fakeEndpointsInfo{}, + expected: map[ServicePortName][]*EndpointInfoCommon{}, }, { // Case[1]: no changes, unnamed port newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { @@ -187,9 +155,9 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*fakeEndpointsInfo{ + expected: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, }, { @@ -207,9 +175,9 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*fakeEndpointsInfo{ + expected: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "port"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, }, { @@ -226,15 +194,15 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*fakeEndpointsInfo{ + expected: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, }, { // Case[4]: remove port newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) {}), - expected: map[ServicePortName][]*fakeEndpointsInfo{}, + expected: map[ServicePortName][]*EndpointInfoCommon{}, }, { // Case[5]: new IP and port newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { @@ -255,14 +223,14 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*fakeEndpointsInfo{ + expected: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p1"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "2.2.2.2:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "2.2.2.2:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p2"): { - {endpoint: "1.1.1.1:22", isLocal: false}, - {endpoint: "2.2.2.2:22", isLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false}, + {Endpoint: "2.2.2.2:22", IsLocal: false}, }, }, }, { @@ -280,9 +248,9 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*fakeEndpointsInfo{ + expected: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p1"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, }, { @@ -300,9 +268,9 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*fakeEndpointsInfo{ + expected: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p2"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, }, { @@ -320,16 +288,16 @@ func Test_endpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*fakeEndpointsInfo{ + expected: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p1"): { - {endpoint: "1.1.1.1:22", isLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false}, }, }, }} for tci, tc := range testCases { // outputs - newEndpoints := endpointsToEndpointsMap(tc.newEndpoints, "host", newFakeEndpointsInfo) + newEndpoints := epTracker.endpointsToEndpointsMap(tc.newEndpoints) if len(newEndpoints) != len(tc.expected) { t.Errorf("[%d] expected %d new, got %d: %v", tci, len(tc.expected), len(newEndpoints), spew.Sdump(newEndpoints)) @@ -339,7 +307,7 @@ func Test_endpointsToEndpointsMap(t *testing.T) { t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(tc.expected[x]), x, len(newEndpoints[x])) } else { for i := range newEndpoints[x] { - ep := newEndpoints[x][i].(*fakeEndpointsInfo) + ep := newEndpoints[x][i].(*EndpointInfoCommon) if *ep != *(tc.expected[x][i]) { t.Errorf("[%d] expected new[%v][%d] to be %v, got %v", tci, x, i, tc.expected[x][i], *ep) } @@ -661,15 +629,15 @@ func TestUpdateEndpointsMap(t *testing.T) { // or non-nil) and must be of equal length. previousEndpoints []*api.Endpoints currentEndpoints []*api.Endpoints - oldEndpoints map[ServicePortName][]*fakeEndpointsInfo - expectedResult map[ServicePortName][]*fakeEndpointsInfo + oldEndpoints map[ServicePortName][]*EndpointInfoCommon + expectedResult map[ServicePortName][]*EndpointInfoCommon expectedStaleEndpoints []ServiceEndpoint expectedStaleServiceNames map[ServicePortName]bool expectedHealthchecks map[types.NamespacedName]int }{{ // Case[0]: nothing - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{}, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{}, + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{}, + expectedResult: map[ServicePortName][]*EndpointInfoCommon{}, expectedStaleEndpoints: []ServiceEndpoint{}, expectedStaleServiceNames: map[ServicePortName]bool{}, expectedHealthchecks: map[types.NamespacedName]int{}, @@ -681,14 +649,14 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPort), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -702,14 +670,14 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortLocal), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -725,20 +693,20 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsets), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -752,26 +720,26 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, + {Endpoint: "1.1.1.3:13", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, + {Endpoint: "1.1.1.3:13", IsLocal: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -789,56 +757,56 @@ func TestUpdateEndpointsMap(t *testing.T) { makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1), makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, - {endpoint: "1.1.1.4:13", isLocal: true}, + {Endpoint: "1.1.1.3:13", IsLocal: false}, + {Endpoint: "1.1.1.4:13", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p14"): { - {endpoint: "1.1.1.3:14", isLocal: false}, - {endpoint: "1.1.1.4:14", isLocal: true}, + {Endpoint: "1.1.1.3:14", IsLocal: false}, + {Endpoint: "1.1.1.4:14", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p21"): { - {endpoint: "2.2.2.1:21", isLocal: false}, - {endpoint: "2.2.2.2:21", isLocal: true}, + {Endpoint: "2.2.2.1:21", IsLocal: false}, + {Endpoint: "2.2.2.2:21", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.1:22", isLocal: false}, - {endpoint: "2.2.2.2:22", isLocal: true}, + {Endpoint: "2.2.2.1:22", IsLocal: false}, + {Endpoint: "2.2.2.2:22", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, - {endpoint: "1.1.1.4:13", isLocal: true}, + {Endpoint: "1.1.1.3:13", IsLocal: false}, + {Endpoint: "1.1.1.4:13", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p14"): { - {endpoint: "1.1.1.3:14", isLocal: false}, - {endpoint: "1.1.1.4:14", isLocal: true}, + {Endpoint: "1.1.1.3:14", IsLocal: false}, + {Endpoint: "1.1.1.4:14", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p21"): { - {endpoint: "2.2.2.1:21", isLocal: false}, - {endpoint: "2.2.2.2:21", isLocal: true}, + {Endpoint: "2.2.2.1:21", IsLocal: false}, + {Endpoint: "2.2.2.2:21", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.1:22", isLocal: false}, - {endpoint: "2.2.2.2:22", isLocal: true}, + {Endpoint: "2.2.2.1:22", IsLocal: false}, + {Endpoint: "2.2.2.2:22", IsLocal: true}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -855,10 +823,10 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPortLocal), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{}, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{}, + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -876,12 +844,12 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ nil, }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{}, + expectedResult: map[ServicePortName][]*EndpointInfoCommon{}, expectedStaleEndpoints: []ServiceEndpoint{{ Endpoint: "1.1.1.1:11", ServicePortName: makeServicePortName("ns1", "ep1", ""), @@ -896,19 +864,19 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -926,19 +894,19 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPort), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -961,17 +929,17 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsetsWithLocal), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -989,17 +957,17 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPort), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1016,14 +984,14 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortRenamed), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11-2"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1042,14 +1010,14 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortRenumbered), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:22", isLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1072,41 +1040,41 @@ func TestUpdateEndpointsMap(t *testing.T) { makeTestEndpoints("ns3", "ep3", complexAfter3), makeTestEndpoints("ns4", "ep4", complexAfter4), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.2:22", isLocal: true}, - {endpoint: "2.2.2.22:22", isLocal: true}, + {Endpoint: "2.2.2.2:22", IsLocal: true}, + {Endpoint: "2.2.2.22:22", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p23"): { - {endpoint: "2.2.2.3:23", isLocal: true}, + {Endpoint: "2.2.2.3:23", IsLocal: true}, }, makeServicePortName("ns4", "ep4", "p44"): { - {endpoint: "4.4.4.4:44", isLocal: true}, - {endpoint: "4.4.4.5:44", isLocal: true}, + {Endpoint: "4.4.4.4:44", IsLocal: true}, + {Endpoint: "4.4.4.5:44", IsLocal: true}, }, makeServicePortName("ns4", "ep4", "p45"): { - {endpoint: "4.4.4.6:45", isLocal: true}, + {Endpoint: "4.4.4.6:45", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.11:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.11:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p122"): { - {endpoint: "1.1.1.2:122", isLocal: false}, + {Endpoint: "1.1.1.2:122", IsLocal: false}, }, makeServicePortName("ns3", "ep3", "p33"): { - {endpoint: "3.3.3.3:33", isLocal: false}, + {Endpoint: "3.3.3.3:33", IsLocal: false}, }, makeServicePortName("ns4", "ep4", "p44"): { - {endpoint: "4.4.4.4:44", isLocal: true}, + {Endpoint: "4.4.4.4:44", IsLocal: true}, }, }, expectedStaleEndpoints: []ServiceEndpoint{{ @@ -1141,10 +1109,10 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPort), }, - oldEndpoints: map[ServicePortName][]*fakeEndpointsInfo{}, - expectedResult: map[ServicePortName][]*fakeEndpointsInfo{ + oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{}, + expectedResult: map[ServicePortName][]*EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []ServiceEndpoint{}, @@ -1224,7 +1192,7 @@ func TestUpdateEndpointsMap(t *testing.T) { } } -func compareEndpointsMaps(t *testing.T, tci int, newMap EndpointsMap, expected map[ServicePortName][]*fakeEndpointsInfo) { +func compareEndpointsMaps(t *testing.T, tci int, newMap EndpointsMap, expected map[ServicePortName][]*EndpointInfoCommon) { if len(newMap) != len(expected) { t.Errorf("[%d] expected %d results, got %d: %v", tci, len(expected), len(newMap), newMap) } @@ -1233,7 +1201,7 @@ func compareEndpointsMaps(t *testing.T, tci int, newMap EndpointsMap, expected m t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(expected[x]), x, len(newMap[x])) } else { for i := range expected[x] { - newEp, ok := newMap[x][i].(*fakeEndpointsInfo) + newEp, ok := newMap[x][i].(*EndpointInfoCommon) if !ok { t.Errorf("Failed to cast endpointsInfo") continue diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index 3ec67c6e50f..80f7f54fde9 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -38,9 +38,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/record" - apiservice "k8s.io/kubernetes/pkg/api/service" api "k8s.io/kubernetes/pkg/apis/core" - "k8s.io/kubernetes/pkg/apis/core/helper" "k8s.io/kubernetes/pkg/proxy" "k8s.io/kubernetes/pkg/proxy/healthcheck" "k8s.io/kubernetes/pkg/proxy/metrics" @@ -141,17 +139,7 @@ const sysctlBridgeCallIPTables = "net/bridge/bridge-nf-call-iptables" // internal struct for string service information type serviceInfo struct { - clusterIP net.IP - port int - protocol api.Protocol - nodePort int - loadBalancerStatus api.LoadBalancerStatus - sessionAffinityType api.ServiceAffinity - stickyMaxAgeSeconds int - externalIPs []string - loadBalancerSourceRanges []string - onlyNodeLocalEndpoints bool - healthCheckNodePort int + *proxy.ServiceInfoCommon // The following fields are computed and stored for performance reasons. serviceNameString string servicePortChainName utiliptables.Chain @@ -160,47 +148,13 @@ type serviceInfo struct { } // returns a new proxy.ServicePort which abstracts a serviceInfo -func newServiceInfo(port *api.ServicePort, service *api.Service) proxy.ServicePort { - onlyNodeLocalEndpoints := false - if apiservice.RequestsOnlyLocalTraffic(service) { - onlyNodeLocalEndpoints = true - } - var stickyMaxAgeSeconds int - if service.Spec.SessionAffinity == api.ServiceAffinityClientIP { - // Kube-apiserver side guarantees SessionAffinityConfig won't be nil when session affinity type is ClientIP - stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) - } - info := &serviceInfo{ - clusterIP: net.ParseIP(service.Spec.ClusterIP), - port: int(port.Port), - protocol: port.Protocol, - nodePort: int(port.NodePort), - // Deep-copy in case the service instance changes - loadBalancerStatus: *helper.LoadBalancerStatusDeepCopy(&service.Status.LoadBalancer), - sessionAffinityType: service.Spec.SessionAffinity, - stickyMaxAgeSeconds: stickyMaxAgeSeconds, - externalIPs: make([]string, len(service.Spec.ExternalIPs)), - loadBalancerSourceRanges: make([]string, len(service.Spec.LoadBalancerSourceRanges)), - onlyNodeLocalEndpoints: onlyNodeLocalEndpoints, - } - - copy(info.loadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges) - copy(info.externalIPs, service.Spec.ExternalIPs) - - svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} - svcPortName := proxy.ServicePortName{NamespacedName: svcName, Port: port.Name} - - if apiservice.NeedsHealthCheck(service) { - p := service.Spec.HealthCheckNodePort - if p == 0 { - glog.Errorf("Service %q has no healthcheck nodeport", svcName.String()) - } else { - info.healthCheckNodePort = int(p) - } - } +func customizeServiceInfo(port *api.ServicePort, service *api.Service, infoCommon *proxy.ServiceInfoCommon) proxy.ServicePort { + info := &serviceInfo{ServiceInfoCommon: infoCommon} // Store the following for performance reasons. - protocol := strings.ToLower(string(info.protocol)) + svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} + svcPortName := proxy.ServicePortName{NamespacedName: svcName, Port: port.Name} + protocol := strings.ToLower(string(info.Protocol)) info.serviceNameString = svcPortName.String() info.servicePortChainName = servicePortChainName(info.serviceNameString, protocol) info.serviceFirewallChainName = serviceFirewallChainName(info.serviceNameString, protocol) @@ -209,37 +163,9 @@ func newServiceInfo(port *api.ServicePort, service *api.Service) proxy.ServicePo return info } -// ClusterIP is part of proxy.ServicePort interface. -func (info *serviceInfo) ClusterIP() string { - return info.clusterIP.String() -} - -// Port is part of proxy.ServicePort interface. -func (info *serviceInfo) Port() int { - return info.port -} - -// Protocol is part of proxy.ServicePort interface. -func (info *serviceInfo) Protocol() api.Protocol { - return info.protocol -} - -// String is part of proxy.ServicePort interface. -func (info *serviceInfo) String() string { - return fmt.Sprintf("%s:%d/%s", info.clusterIP, info.port, info.protocol) -} - -// HealthCheckNodePort is part of proxy.ServicePort interface. -func (info *serviceInfo) HealthCheckNodePort() int { - return info.healthCheckNodePort -} - -var _ proxy.ServicePort = &serviceInfo{} - // internal struct for endpoints information type endpointsInfo struct { - endpoint string // TODO: should be an endpointString type - isLocal bool + *proxy.EndpointInfoCommon // The following fields we lazily compute and store here for performance // reasons. If the protocol is the same as you expect it to be, then the // chainName can be reused, otherwise it should be recomputed. @@ -248,52 +174,32 @@ type endpointsInfo struct { } // returns a new proxy.Endpoint which abstracts a endpointsInfo -func newEndpointsInfo(IP string, port int, isLocal bool) proxy.Endpoint { - return &endpointsInfo{ - endpoint: net.JoinHostPort(IP, strconv.Itoa(port)), - isLocal: isLocal, - } +func customizeEndpointInfo(IP string, port int, isLocal bool, infoCommon *proxy.EndpointInfoCommon) proxy.Endpoint { + return &endpointsInfo{EndpointInfoCommon: infoCommon} } -// IsLocal is part of proxy.Endpoint interface. -func (e *endpointsInfo) IsLocal() bool { - return e.isLocal -} - -// IP is part of proxy.Endpoint interface. -func (e *endpointsInfo) IP() string { - return utilproxy.IPPart(e.endpoint) -} - -// Equal is part of proxy.Endpoint interface. +// Equal overrides the Equal() function imlemented by proxy.EndpointInfoCommon. func (e *endpointsInfo) Equal(other proxy.Endpoint) bool { o, ok := other.(*endpointsInfo) if !ok { glog.Errorf("Failed to cast endpointsInfo") return false } - return e.endpoint == o.endpoint && - e.isLocal == o.isLocal && + return e.Endpoint == o.Endpoint && + e.IsLocal == o.IsLocal && e.protocol == o.protocol && e.chainName == o.chainName } -// String is part of proxy.Endpoint interface. -func (e *endpointsInfo) String() string { - return e.endpoint -} - // Returns the endpoint chain name for a given endpointsInfo. func (e *endpointsInfo) endpointChain(svcNameString, protocol string) utiliptables.Chain { if e.protocol != protocol { e.protocol = protocol - e.chainName = servicePortEndpointChainName(svcNameString, protocol, e.endpoint) + e.chainName = servicePortEndpointChainName(svcNameString, protocol, e.Endpoint) } return e.chainName } -var _ proxy.Endpoint = &endpointsInfo{} - // Proxier is an iptables based proxy for connections between a localhost:lport // and services that provide the actual backends. type Proxier struct { @@ -406,12 +312,13 @@ func NewProxier(ipt utiliptables.Interface, healthChecker := healthcheck.NewServer(hostname, recorder, nil, nil) // use default implementations of deps + isIPv6 := ipt.IsIpv6() proxier := &Proxier{ portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable), serviceMap: make(proxy.ServiceMap), - serviceChanges: proxy.NewServiceChangeTracker(), + serviceChanges: proxy.NewServiceChangeTracker(customizeServiceInfo, &isIPv6, recorder), endpointsMap: make(proxy.EndpointsMap), - endpointsChanges: proxy.NewEndpointChangeTracker(hostname), + endpointsChanges: proxy.NewEndpointChangeTracker(hostname, customizeEndpointInfo, &isIPv6, recorder), iptables: ipt, masqueradeAll: masqueradeAll, masqueradeMark: masqueradeMark, @@ -592,19 +499,19 @@ func (proxier *Proxier) isInitialized() bool { } func (proxier *Proxier) OnServiceAdd(service *api.Service) { - if proxier.serviceChanges.Update(nil, service, newServiceInfo) && proxier.isInitialized() { + if proxier.serviceChanges.Update(nil, service) && proxier.isInitialized() { proxier.syncRunner.Run() } } func (proxier *Proxier) OnServiceUpdate(oldService, service *api.Service) { - if proxier.serviceChanges.Update(oldService, service, newServiceInfo) && proxier.isInitialized() { + if proxier.serviceChanges.Update(oldService, service) && proxier.isInitialized() { proxier.syncRunner.Run() } } func (proxier *Proxier) OnServiceDelete(service *api.Service) { - if proxier.serviceChanges.Update(service, nil, newServiceInfo) && proxier.isInitialized() { + if proxier.serviceChanges.Update(service, nil) && proxier.isInitialized() { proxier.syncRunner.Run() } } @@ -620,19 +527,19 @@ func (proxier *Proxier) OnServiceSynced() { } func (proxier *Proxier) OnEndpointsAdd(endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(nil, endpoints, newEndpointsInfo) && proxier.isInitialized() { + if proxier.endpointsChanges.Update(nil, endpoints) && proxier.isInitialized() { proxier.syncRunner.Run() } } func (proxier *Proxier) OnEndpointsUpdate(oldEndpoints, endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(oldEndpoints, endpoints, newEndpointsInfo) && proxier.isInitialized() { + if proxier.endpointsChanges.Update(oldEndpoints, endpoints) && proxier.isInitialized() { proxier.syncRunner.Run() } } func (proxier *Proxier) OnEndpointsDelete(endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(endpoints, nil, newEndpointsInfo) && proxier.isInitialized() { + if proxier.endpointsChanges.Update(endpoints, nil) && proxier.isInitialized() { proxier.syncRunner.Run() } } @@ -693,9 +600,9 @@ func servicePortEndpointChainName(servicePortName string, protocol string, endpo // TODO: move it to util func (proxier *Proxier) deleteEndpointConnections(connectionMap []proxy.ServiceEndpoint) { for _, epSvcPair := range connectionMap { - if svcInfo, ok := proxier.serviceMap[epSvcPair.ServicePortName]; ok && svcInfo.Protocol() == api.ProtocolUDP { + if svcInfo, ok := proxier.serviceMap[epSvcPair.ServicePortName]; ok && svcInfo.GetProtocol() == api.ProtocolUDP { endpointIP := utilproxy.IPPart(epSvcPair.Endpoint) - err := conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.ClusterIP(), endpointIP, v1.ProtocolUDP) + err := conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.GetClusterIP(), endpointIP, v1.ProtocolUDP) if err != nil { glog.Errorf("Failed to delete %s endpoint connections, error: %v", epSvcPair.ServicePortName.String(), err) } @@ -730,9 +637,9 @@ func (proxier *Proxier) syncProxyRules() { staleServices := serviceUpdateResult.UDPStaleClusterIP // merge stale services gathered from updateEndpointsMap for _, svcPortName := range endpointUpdateResult.StaleServiceNames { - if svcInfo, ok := proxier.serviceMap[svcPortName]; ok && svcInfo != nil && svcInfo.Protocol() == api.ProtocolUDP { - glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.ClusterIP()) - staleServices.Insert(svcInfo.ClusterIP()) + if svcInfo, ok := proxier.serviceMap[svcPortName]; ok && svcInfo != nil && svcInfo.GetProtocol() == api.ProtocolUDP { + glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.GetClusterIP()) + staleServices.Insert(svcInfo.GetClusterIP()) } } @@ -851,8 +758,8 @@ func (proxier *Proxier) syncProxyRules() { glog.Errorf("Failed to cast serviceInfo %q", svcName.String()) continue } - isIPv6 := conntrack.IsIPv6(svcInfo.clusterIP) - protocol := strings.ToLower(string(svcInfo.protocol)) + isIPv6 := conntrack.IsIPv6(svcInfo.ClusterIP) + protocol := strings.ToLower(string(svcInfo.Protocol)) svcNameString := svcInfo.serviceNameString hasEndpoints := len(proxier.endpointsMap[svcName]) > 0 @@ -868,7 +775,7 @@ func (proxier *Proxier) syncProxyRules() { } svcXlbChain := svcInfo.serviceLBChainName - if svcInfo.onlyNodeLocalEndpoints { + if svcInfo.OnlyNodeLocalEndpoints { // Only for services request OnlyLocal traffic // create the per-service LB chain, retaining counters if possible. if lbChain, ok := existingNATChains[svcXlbChain]; ok { @@ -885,8 +792,8 @@ func (proxier *Proxier) syncProxyRules() { "-A", string(kubeServicesChain), "-m", "comment", "--comment", fmt.Sprintf(`"%s cluster IP"`, svcNameString), "-m", protocol, "-p", protocol, - "-d", utilproxy.ToCIDR(svcInfo.clusterIP), - "--dport", strconv.Itoa(svcInfo.port), + "-d", utilproxy.ToCIDR(svcInfo.ClusterIP), + "--dport", strconv.Itoa(svcInfo.Port), ) if proxier.masqueradeAll { writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) @@ -904,14 +811,14 @@ func (proxier *Proxier) syncProxyRules() { "-A", string(kubeServicesChain), "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString), "-m", protocol, "-p", protocol, - "-d", utilproxy.ToCIDR(svcInfo.clusterIP), - "--dport", strconv.Itoa(svcInfo.port), + "-d", utilproxy.ToCIDR(svcInfo.ClusterIP), + "--dport", strconv.Itoa(svcInfo.Port), "-j", "REJECT", ) } // Capture externalIPs. - for _, externalIP := range svcInfo.externalIPs { + for _, externalIP := range svcInfo.ExternalIPs { // If the "external" IP happens to be an IP that is local to this // machine, hold the local port open so no other process can open it // (because the socket might open but it would never work). @@ -921,7 +828,7 @@ func (proxier *Proxier) syncProxyRules() { lp := utilproxy.LocalPort{ Description: "externalIP for " + svcNameString, IP: externalIP, - Port: svcInfo.Port(), + Port: svcInfo.Port, Protocol: protocol, } if proxier.portsMap[lp] != nil { @@ -952,7 +859,7 @@ func (proxier *Proxier) syncProxyRules() { "-m", "comment", "--comment", fmt.Sprintf(`"%s external IP"`, svcNameString), "-m", protocol, "-p", protocol, "-d", utilproxy.ToCIDR(net.ParseIP(externalIP)), - "--dport", strconv.Itoa(svcInfo.port), + "--dport", strconv.Itoa(svcInfo.Port), ) // We have to SNAT packets to external IPs. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) @@ -975,7 +882,7 @@ func (proxier *Proxier) syncProxyRules() { "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString), "-m", protocol, "-p", protocol, "-d", utilproxy.ToCIDR(net.ParseIP(externalIP)), - "--dport", strconv.Itoa(svcInfo.port), + "--dport", strconv.Itoa(svcInfo.Port), "-j", "REJECT", ) } @@ -984,7 +891,7 @@ func (proxier *Proxier) syncProxyRules() { // Capture load-balancer ingress. if hasEndpoints { fwChain := svcInfo.serviceFirewallChainName - for _, ingress := range svcInfo.loadBalancerStatus.Ingress { + for _, ingress := range svcInfo.LoadBalancerStatus.Ingress { if ingress.IP != "" { // create service firewall chain if chain, ok := existingNATChains[fwChain]; ok { @@ -1002,7 +909,7 @@ func (proxier *Proxier) syncProxyRules() { "-m", "comment", "--comment", fmt.Sprintf(`"%s loadbalancer IP"`, svcNameString), "-m", protocol, "-p", protocol, "-d", utilproxy.ToCIDR(net.ParseIP(ingress.IP)), - "--dport", strconv.Itoa(svcInfo.port), + "--dport", strconv.Itoa(svcInfo.Port), ) // jump to service firewall chain writeLine(proxier.natRules, append(args, "-j", string(fwChain))...) @@ -1016,18 +923,18 @@ func (proxier *Proxier) syncProxyRules() { chosenChain := svcXlbChain // If we are proxying globally, we need to masquerade in case we cross nodes. // If we are proxying only locally, we can retain the source IP. - if !svcInfo.onlyNodeLocalEndpoints { + if !svcInfo.OnlyNodeLocalEndpoints { writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) chosenChain = svcChain } - if len(svcInfo.loadBalancerSourceRanges) == 0 { + if len(svcInfo.LoadBalancerSourceRanges) == 0 { // allow all sources, so jump directly to the KUBE-SVC or KUBE-XLB chain writeLine(proxier.natRules, append(args, "-j", string(chosenChain))...) } else { // firewall filter based on each source range allowFromNode := false - for _, src := range svcInfo.loadBalancerSourceRanges { + for _, src := range svcInfo.LoadBalancerSourceRanges { writeLine(proxier.natRules, append(args, "-s", src, "-j", string(chosenChain))...) // ignore error because it has been validated _, cidr, _ := net.ParseCIDR(src) @@ -1054,13 +961,13 @@ func (proxier *Proxier) syncProxyRules() { // Capture nodeports. If we had more than 2 rules it might be // worthwhile to make a new per-service chain for nodeport rules, but // with just 2 rules it ends up being a waste and a cognitive burden. - if svcInfo.nodePort != 0 { + if svcInfo.NodePort != 0 { // Hold the local port open so no other process can open it // (because the socket might open but it would never work). lp := utilproxy.LocalPort{ Description: "nodePort for " + svcNameString, IP: "", - Port: svcInfo.nodePort, + Port: svcInfo.NodePort, Protocol: protocol, } if proxier.portsMap[lp] != nil { @@ -1090,9 +997,9 @@ func (proxier *Proxier) syncProxyRules() { "-A", string(kubeNodePortsChain), "-m", "comment", "--comment", svcNameString, "-m", protocol, "-p", protocol, - "--dport", strconv.Itoa(svcInfo.nodePort), + "--dport", strconv.Itoa(svcInfo.NodePort), ) - if !svcInfo.onlyNodeLocalEndpoints { + if !svcInfo.OnlyNodeLocalEndpoints { // Nodeports need SNAT, unless they're local. writeLine(proxier.natRules, append(args, "-j", string(KubeMarkMasqChain))...) // Jump to the service chain. @@ -1115,7 +1022,7 @@ func (proxier *Proxier) syncProxyRules() { "-m", "comment", "--comment", fmt.Sprintf(`"%s has no endpoints"`, svcNameString), "-m", "addrtype", "--dst-type", "LOCAL", "-m", protocol, "-p", protocol, - "--dport", strconv.Itoa(svcInfo.nodePort), + "--dport", strconv.Itoa(svcInfo.NodePort), "-j", "REJECT", ) } @@ -1151,13 +1058,13 @@ func (proxier *Proxier) syncProxyRules() { } // First write session affinity rules, if applicable. - if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP { + if svcInfo.SessionAffinityType == api.ServiceAffinityClientIP { for _, endpointChain := range endpointChains { writeLine(proxier.natRules, "-A", string(svcChain), "-m", "comment", "--comment", svcNameString, "-m", "recent", "--name", string(endpointChain), - "--rcheck", "--seconds", strconv.Itoa(svcInfo.stickyMaxAgeSeconds), "--reap", + "--rcheck", "--seconds", strconv.Itoa(svcInfo.StickyMaxAgeSeconds), "--reap", "-j", string(endpointChain)) } } @@ -1196,16 +1103,16 @@ func (proxier *Proxier) syncProxyRules() { "-s", utilproxy.ToCIDR(net.ParseIP(epIP)), "-j", string(KubeMarkMasqChain))...) // Update client-affinity lists. - if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP { + if svcInfo.SessionAffinityType == api.ServiceAffinityClientIP { args = append(args, "-m", "recent", "--name", string(endpointChain), "--set") } // DNAT to final destination. - args = append(args, "-m", protocol, "-p", protocol, "-j", "DNAT", "--to-destination", endpoints[i].endpoint) + args = append(args, "-m", protocol, "-p", protocol, "-j", "DNAT", "--to-destination", endpoints[i].Endpoint) writeLine(proxier.natRules, args...) } // The logic below this applies only if this service is marked as OnlyLocal - if !svcInfo.onlyNodeLocalEndpoints { + if !svcInfo.OnlyNodeLocalEndpoints { continue } @@ -1214,7 +1121,7 @@ func (proxier *Proxier) syncProxyRules() { localEndpoints := make([]*endpointsInfo, 0) localEndpointChains := make([]utiliptables.Chain, 0) for i := range endpointChains { - if endpoints[i].isLocal { + if endpoints[i].IsLocal { // These slices parallel each other; must be kept in sync localEndpoints = append(localEndpoints, endpoints[i]) localEndpointChains = append(localEndpointChains, endpointChains[i]) @@ -1247,13 +1154,13 @@ func (proxier *Proxier) syncProxyRules() { writeLine(proxier.natRules, args...) } else { // First write session affinity rules only over local endpoints, if applicable. - if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP { + if svcInfo.SessionAffinityType == api.ServiceAffinityClientIP { for _, endpointChain := range localEndpointChains { writeLine(proxier.natRules, "-A", string(svcXlbChain), "-m", "comment", "--comment", svcNameString, "-m", "recent", "--name", string(endpointChain), - "--rcheck", "--seconds", strconv.Itoa(svcInfo.stickyMaxAgeSeconds), "--reap", + "--rcheck", "--seconds", strconv.Itoa(svcInfo.StickyMaxAgeSeconds), "--reap", "-j", string(endpointChain)) } } diff --git a/pkg/proxy/iptables/proxier_test.go b/pkg/proxy/iptables/proxier_test.go index e335df23ab6..734e5bde4f3 100644 --- a/pkg/proxy/iptables/proxier_test.go +++ b/pkg/proxy/iptables/proxier_test.go @@ -179,12 +179,14 @@ func TestGetChainLinesMultipleTables(t *testing.T) { func newFakeServiceInfo(service proxy.ServicePortName, ip net.IP, port int, protocol api.Protocol, onlyNodeLocalEndpoints bool) *serviceInfo { return &serviceInfo{ - sessionAffinityType: api.ServiceAffinityNone, // default - stickyMaxAgeSeconds: int(api.DefaultClientIPServiceAffinitySeconds), // default - clusterIP: ip, - port: port, - protocol: protocol, - onlyNodeLocalEndpoints: onlyNodeLocalEndpoints, + ServiceInfoCommon: &proxy.ServiceInfoCommon{ + SessionAffinityType: api.ServiceAffinityNone, // default + StickyMaxAgeSeconds: int(api.DefaultClientIPServiceAffinitySeconds), // default + ClusterIP: ip, + Port: port, + Protocol: protocol, + OnlyNodeLocalEndpoints: onlyNodeLocalEndpoints, + }, } } @@ -391,9 +393,9 @@ func NewFakeProxier(ipt utiliptables.Interface) *Proxier { p := &Proxier{ exec: &fakeexec.FakeExec{}, serviceMap: make(proxy.ServiceMap), - serviceChanges: proxy.NewServiceChangeTracker(), + serviceChanges: proxy.NewServiceChangeTracker(customizeServiceInfo, nil, nil), endpointsMap: make(proxy.EndpointsMap), - endpointsChanges: proxy.NewEndpointChangeTracker(testHostname), + endpointsChanges: proxy.NewEndpointChangeTracker(testHostname, customizeEndpointInfo, nil, nil), iptables: ipt, clusterCIDR: "10.0.0.0/24", hostname: testHostname, @@ -821,7 +823,7 @@ func TestExternalIPsReject(t *testing.T) { kubeSvcRules := ipt.GetRules(string(kubeExternalServicesChain)) if !hasJump(kubeSvcRules, iptablestest.Reject, svcExternalIPs, svcPort) { - errorf(fmt.Sprintf("Failed to a %v rule for externalIP %v with no endpoints", iptablestest.Reject, svcPortName), kubeSvcRules, t) + errorf(fmt.Sprintf("Failed to find a %v rule for externalIP %v with no endpoints", iptablestest.Reject, svcPortName), kubeSvcRules, t) } } @@ -1379,7 +1381,10 @@ func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expe t.Errorf("Failed to cast endpointsInfo") continue } - if *newEp != *(expected[x][i]) { + if newEp.Endpoint != expected[x][i].Endpoint || + newEp.IsLocal != expected[x][i].IsLocal || + newEp.protocol != expected[x][i].protocol || + newEp.chainName != expected[x][i].chainName { t.Errorf("[%d] expected new[%v][%d] to be %v, got %v", tci, x, i, expected[x][i], newEp) } } @@ -1721,12 +1726,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1742,12 +1747,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1765,18 +1770,18 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1792,24 +1797,24 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:13", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:13", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1829,54 +1834,54 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, - {endpoint: "1.1.1.4:13", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:13", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.4:13", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p14"): { - {endpoint: "1.1.1.3:14", isLocal: false}, - {endpoint: "1.1.1.4:14", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:14", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.4:14", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p21"): { - {endpoint: "2.2.2.1:21", isLocal: false}, - {endpoint: "2.2.2.2:21", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.1:21", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:21", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.1:22", isLocal: false}, - {endpoint: "2.2.2.2:22", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.1:22", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:22", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, - {endpoint: "1.1.1.4:13", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:13", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.4:13", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p14"): { - {endpoint: "1.1.1.3:14", isLocal: false}, - {endpoint: "1.1.1.4:14", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:14", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.4:14", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p21"): { - {endpoint: "2.2.2.1:21", isLocal: false}, - {endpoint: "2.2.2.2:21", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.1:21", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:21", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.1:22", isLocal: false}, - {endpoint: "2.2.2.2:22", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.1:22", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:22", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1896,7 +1901,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1916,7 +1921,7 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, @@ -1936,17 +1941,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1966,17 +1971,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2001,15 +2006,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2029,15 +2034,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2056,12 +2061,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11-2"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2082,12 +2087,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:22", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:22", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2112,39 +2117,39 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.2:22", isLocal: true}, - {endpoint: "2.2.2.22:22", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:22", IsLocal: true}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.22:22", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p23"): { - {endpoint: "2.2.2.3:23", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.3:23", IsLocal: true}}, }, makeServicePortName("ns4", "ep4", "p44"): { - {endpoint: "4.4.4.4:44", isLocal: true}, - {endpoint: "4.4.4.5:44", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "4.4.4.4:44", IsLocal: true}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "4.4.4.5:44", IsLocal: true}}, }, makeServicePortName("ns4", "ep4", "p45"): { - {endpoint: "4.4.4.6:45", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "4.4.4.6:45", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.11:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.11:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p122"): { - {endpoint: "1.1.1.2:122", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:122", IsLocal: false}}, }, makeServicePortName("ns3", "ep3", "p33"): { - {endpoint: "3.3.3.3:33", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "3.3.3.3:33", IsLocal: false}}, }, makeServicePortName("ns4", "ep4", "p44"): { - {endpoint: "4.4.4.4:44", isLocal: true}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "4.4.4.4:44", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2182,7 +2187,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index ad2f74449cb..3a0261a1f96 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -37,9 +37,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/client-go/tools/record" - apiservice "k8s.io/kubernetes/pkg/api/service" api "k8s.io/kubernetes/pkg/apis/core" - "k8s.io/kubernetes/pkg/apis/core/helper" "k8s.io/kubernetes/pkg/proxy" "k8s.io/kubernetes/pkg/proxy/healthcheck" "k8s.io/kubernetes/pkg/proxy/metrics" @@ -291,6 +289,10 @@ func NewProxier(ipt utiliptables.Interface, nodeIP = net.ParseIP("127.0.0.1") } + isIPv6 := conntrack.IsIPv6(nodeIP) + + glog.V(2).Infof("nodeIP: %v, isIPv6: %v", nodeIP, isIPv6) + if len(clusterCIDR) == 0 { glog.Warningf("clusterCIDR not specified, unable to distinguish between internal and external traffic") } @@ -302,16 +304,12 @@ func NewProxier(ipt utiliptables.Interface, healthChecker := healthcheck.NewServer(hostname, recorder, nil, nil) // use default implementations of deps - isIPv6 := conntrack.IsIPv6(nodeIP) - - glog.V(2).Infof("nodeIP: %v, isIPv6: %v", nodeIP, isIPv6) - proxier := &Proxier{ portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable), serviceMap: make(proxy.ServiceMap), - serviceChanges: proxy.NewServiceChangeTracker(), + serviceChanges: proxy.NewServiceChangeTracker(customizeServiceInfo, &isIPv6, recorder), endpointsMap: make(proxy.EndpointsMap), - endpointsChanges: proxy.NewEndpointChangeTracker(hostname), + endpointsChanges: proxy.NewEndpointChangeTracker(hostname, nil, &isIPv6, recorder), syncPeriod: syncPeriod, minSyncPeriod: minSyncPeriod, iptables: ipt, @@ -353,140 +351,23 @@ func NewProxier(ipt utiliptables.Interface, // internal struct for string service information type serviceInfo struct { - clusterIP net.IP - port int - protocol api.Protocol - nodePort int - loadBalancerStatus api.LoadBalancerStatus - sessionAffinityType api.ServiceAffinity - stickyMaxAgeSeconds int - externalIPs []string - loadBalancerSourceRanges []string - onlyNodeLocalEndpoints bool - healthCheckNodePort int + *proxy.ServiceInfoCommon // The following fields are computed and stored for performance reasons. serviceNameString string } // returns a new proxy.ServicePort which abstracts a serviceInfo -func newServiceInfo(port *api.ServicePort, service *api.Service) proxy.ServicePort { - onlyNodeLocalEndpoints := false - if apiservice.RequestsOnlyLocalTraffic(service) { - onlyNodeLocalEndpoints = true - } - var stickyMaxAgeSeconds int - if service.Spec.SessionAffinity == api.ServiceAffinityClientIP { - stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) - } - info := &serviceInfo{ - clusterIP: net.ParseIP(service.Spec.ClusterIP), - port: int(port.Port), - protocol: port.Protocol, - nodePort: int(port.NodePort), - // Deep-copy in case the service instance changes - loadBalancerStatus: *helper.LoadBalancerStatusDeepCopy(&service.Status.LoadBalancer), - sessionAffinityType: service.Spec.SessionAffinity, - stickyMaxAgeSeconds: stickyMaxAgeSeconds, - externalIPs: make([]string, len(service.Spec.ExternalIPs)), - loadBalancerSourceRanges: make([]string, len(service.Spec.LoadBalancerSourceRanges)), - onlyNodeLocalEndpoints: onlyNodeLocalEndpoints, - } - - copy(info.loadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges) - copy(info.externalIPs, service.Spec.ExternalIPs) - - svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} - svcPortName := proxy.ServicePortName{NamespacedName: svcName, Port: port.Name} - - if apiservice.NeedsHealthCheck(service) { - p := service.Spec.HealthCheckNodePort - if p == 0 { - glog.Errorf("Service %q has no healthcheck nodeport", svcName.String()) - } else { - info.healthCheckNodePort = int(p) - } - } +func customizeServiceInfo(port *api.ServicePort, service *api.Service, infoCommon *proxy.ServiceInfoCommon) proxy.ServicePort { + info := &serviceInfo{ServiceInfoCommon: infoCommon} // Store the following for performance reasons. + svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} + svcPortName := proxy.ServicePortName{NamespacedName: svcName, Port: port.Name} info.serviceNameString = svcPortName.String() return info } -// ClusterIP is part of ServicePort interface. -func (info *serviceInfo) ClusterIP() string { - return info.clusterIP.String() -} - -// Port is part of ServicePort interface. -func (info *serviceInfo) Port() int { - return info.port -} - -// Protocol is part of ServicePort interface. -func (info *serviceInfo) Protocol() api.Protocol { - return info.protocol -} - -// String is part of ServicePort interface. -func (info *serviceInfo) String() string { - return fmt.Sprintf("%s:%d/%s", info.clusterIP, info.port, info.protocol) -} - -// HealthCheckNodePort is part of ServicePort interface. -func (info *serviceInfo) HealthCheckNodePort() int { - return info.healthCheckNodePort -} - -var _ proxy.ServicePort = &serviceInfo{} - -// internal struct for endpoints information -type endpointsInfo struct { - endpoint string // TODO: should be an endpointString type - isLocal bool -} - -// returns a new proxy.Endpoint which abstracts a endpointsInfo -func newEndpointsInfo(IP string, port int, isLocal bool) proxy.Endpoint { - return &endpointsInfo{ - endpoint: net.JoinHostPort(IP, strconv.Itoa(port)), - isLocal: isLocal, - } -} - -// IsLocal is part of proxy.Endpoint interface. -func (e *endpointsInfo) IsLocal() bool { - return e.isLocal -} - -// String is part of proxy.Endpoint interface. -func (e *endpointsInfo) String() string { - return fmt.Sprintf("%v", e.endpoint) -} - -// IP returns just the IP part of the endpoint, it's a part of proxy.Endpoints interface. -func (e *endpointsInfo) IP() string { - return utilproxy.IPPart(e.endpoint) -} - -// PortPart returns just the Port part of the endpoint. -func (e *endpointsInfo) PortPart() (int, error) { - return utilproxy.PortPart(e.endpoint) -} - -// Equal is part of proxy.Endpoint interface. -func (e *endpointsInfo) Equal(other proxy.Endpoint) bool { - o, ok := other.(*endpointsInfo) - if !ok { - glog.Errorf("Failed to cast endpointsInfo") - return false - } - return e.endpoint == o.endpoint && - e.isLocal == o.isLocal -} - -var _ proxy.Endpoint = &endpointsInfo{} - // KernelHandler can handle the current installed kernel modules. type KernelHandler interface { GetModules() ([]string, error) @@ -668,21 +549,21 @@ func (proxier *Proxier) isInitialized() bool { // OnServiceAdd is called whenever creation of new service object is observed. func (proxier *Proxier) OnServiceAdd(service *api.Service) { - if proxier.serviceChanges.Update(nil, service, newServiceInfo) && proxier.isInitialized() { + if proxier.serviceChanges.Update(nil, service) && proxier.isInitialized() { proxier.syncRunner.Run() } } // OnServiceUpdate is called whenever modification of an existing service object is observed. func (proxier *Proxier) OnServiceUpdate(oldService, service *api.Service) { - if proxier.serviceChanges.Update(oldService, service, newServiceInfo) && proxier.isInitialized() { + if proxier.serviceChanges.Update(oldService, service) && proxier.isInitialized() { proxier.syncRunner.Run() } } // OnServiceDelete is called whenever deletion of an existing service object is observed. func (proxier *Proxier) OnServiceDelete(service *api.Service) { - if proxier.serviceChanges.Update(service, nil, newServiceInfo) && proxier.isInitialized() { + if proxier.serviceChanges.Update(service, nil) && proxier.isInitialized() { proxier.syncRunner.Run() } } @@ -700,21 +581,21 @@ func (proxier *Proxier) OnServiceSynced() { // OnEndpointsAdd is called whenever creation of new endpoints object is observed. func (proxier *Proxier) OnEndpointsAdd(endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(nil, endpoints, newEndpointsInfo) && proxier.isInitialized() { + if proxier.endpointsChanges.Update(nil, endpoints) && proxier.isInitialized() { proxier.syncRunner.Run() } } // OnEndpointsUpdate is called whenever modification of an existing endpoints object is observed. func (proxier *Proxier) OnEndpointsUpdate(oldEndpoints, endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(oldEndpoints, endpoints, newEndpointsInfo) && proxier.isInitialized() { + if proxier.endpointsChanges.Update(oldEndpoints, endpoints) && proxier.isInitialized() { proxier.syncRunner.Run() } } // OnEndpointsDelete is called whenever deletion of an existing endpoints object is observed. func (proxier *Proxier) OnEndpointsDelete(endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(endpoints, nil, newEndpointsInfo) && proxier.isInitialized() { + if proxier.endpointsChanges.Update(endpoints, nil) && proxier.isInitialized() { proxier.syncRunner.Run() } } @@ -757,9 +638,9 @@ func (proxier *Proxier) syncProxyRules() { staleServices := serviceUpdateResult.UDPStaleClusterIP // merge stale services gathered from updateEndpointsMap for _, svcPortName := range endpointUpdateResult.StaleServiceNames { - if svcInfo, ok := proxier.serviceMap[svcPortName]; ok && svcInfo != nil && svcInfo.Protocol() == api.ProtocolUDP { - glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.ClusterIP()) - staleServices.Insert(svcInfo.ClusterIP()) + if svcInfo, ok := proxier.serviceMap[svcPortName]; ok && svcInfo != nil && svcInfo.GetProtocol() == api.ProtocolUDP { + glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.GetClusterIP()) + staleServices.Insert(svcInfo.GetClusterIP()) } } @@ -868,20 +749,20 @@ func (proxier *Proxier) syncProxyRules() { glog.Errorf("Failed to cast serviceInfo %q", svcName.String()) continue } - protocol := strings.ToLower(string(svcInfo.protocol)) + protocol := strings.ToLower(string(svcInfo.Protocol)) // Precompute svcNameString; with many services the many calls // to ServicePortName.String() show up in CPU profiles. svcNameString := svcName.String() // Handle traffic that loops back to the originator with SNAT. for _, e := range proxier.endpointsMap[svcName] { - ep, ok := e.(*endpointsInfo) + ep, ok := e.(*proxy.EndpointInfoCommon) if !ok { - glog.Errorf("Failed to cast endpointsInfo %q", e.String()) + glog.Errorf("Failed to cast EndpointInfoCommon %q", e.String()) continue } epIP := ep.IP() - epPort, err := ep.PortPart() + epPort, err := ep.Port() // Error parsing this endpoint has been logged. Skip to next endpoint. if epIP == "" || err != nil { continue @@ -903,8 +784,8 @@ func (proxier *Proxier) syncProxyRules() { // Capture the clusterIP. // ipset call entry := &utilipset.Entry{ - IP: svcInfo.clusterIP.String(), - Port: svcInfo.port, + IP: svcInfo.ClusterIP.String(), + Port: svcInfo.Port, Protocol: protocol, SetType: utilipset.HashIPPort, } @@ -920,15 +801,15 @@ func (proxier *Proxier) syncProxyRules() { } // ipvs call serv := &utilipvs.VirtualServer{ - Address: svcInfo.clusterIP, - Port: uint16(svcInfo.port), - Protocol: string(svcInfo.protocol), + Address: svcInfo.ClusterIP, + Port: uint16(svcInfo.Port), + Protocol: string(svcInfo.Protocol), Scheduler: proxier.ipvsScheduler, } // Set session affinity flag and timeout for IPVS service - if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP { + if svcInfo.SessionAffinityType == api.ServiceAffinityClientIP { serv.Flags |= utilipvs.FlagPersistent - serv.Timeout = uint32(svcInfo.stickyMaxAgeSeconds) + serv.Timeout = uint32(svcInfo.StickyMaxAgeSeconds) } // We need to bind ClusterIP to dummy interface, so set `bindAddr` parameter to `true` in syncService() if err := proxier.syncService(svcNameString, serv, true); err == nil { @@ -943,14 +824,14 @@ func (proxier *Proxier) syncProxyRules() { } // Capture externalIPs. - for _, externalIP := range svcInfo.externalIPs { + for _, externalIP := range svcInfo.ExternalIPs { if local, err := utilproxy.IsLocalIP(externalIP); err != nil { glog.Errorf("can't determine if IP is local, assuming not: %v", err) } else if local { lp := utilproxy.LocalPort{ Description: "externalIP for " + svcNameString, IP: externalIP, - Port: svcInfo.port, + Port: svcInfo.Port, Protocol: protocol, } if proxier.portsMap[lp] != nil { @@ -978,7 +859,7 @@ func (proxier *Proxier) syncProxyRules() { // ipset call entry := &utilipset.Entry{ IP: externalIP, - Port: svcInfo.port, + Port: svcInfo.Port, Protocol: protocol, SetType: utilipset.HashIPPort, } @@ -992,18 +873,18 @@ func (proxier *Proxier) syncProxyRules() { // ipvs call serv := &utilipvs.VirtualServer{ Address: net.ParseIP(externalIP), - Port: uint16(svcInfo.port), - Protocol: string(svcInfo.protocol), + Port: uint16(svcInfo.Port), + Protocol: string(svcInfo.Protocol), Scheduler: proxier.ipvsScheduler, } - if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP { + if svcInfo.SessionAffinityType == api.ServiceAffinityClientIP { serv.Flags |= utilipvs.FlagPersistent - serv.Timeout = uint32(svcInfo.stickyMaxAgeSeconds) + serv.Timeout = uint32(svcInfo.StickyMaxAgeSeconds) } // There is no need to bind externalIP to dummy interface, so set parameter `bindAddr` to `false`. if err := proxier.syncService(svcNameString, serv, false); err == nil { activeIPVSServices[serv.String()] = true - if err := proxier.syncEndpoint(svcName, svcInfo.onlyNodeLocalEndpoints, serv); err != nil { + if err := proxier.syncEndpoint(svcName, svcInfo.OnlyNodeLocalEndpoints, serv); err != nil { glog.Errorf("Failed to sync endpoint for service: %v, err: %v", serv, err) } } else { @@ -1012,12 +893,12 @@ func (proxier *Proxier) syncProxyRules() { } // Capture load-balancer ingress. - for _, ingress := range svcInfo.loadBalancerStatus.Ingress { + for _, ingress := range svcInfo.LoadBalancerStatus.Ingress { if ingress.IP != "" { // ipset call entry = &utilipset.Entry{ IP: ingress.IP, - Port: svcInfo.port, + Port: svcInfo.Port, Protocol: protocol, SetType: utilipset.HashIPPort, } @@ -1025,14 +906,14 @@ func (proxier *Proxier) syncProxyRules() { // proxier.kubeServiceAccessSet.activeEntries.Insert(entry.String()) // If we are proxying globally, we need to masquerade in case we cross nodes. // If we are proxying only locally, we can retain the source IP. - if !svcInfo.onlyNodeLocalEndpoints { + if !svcInfo.OnlyNodeLocalEndpoints { if valid := proxier.lbMasqSet.validateEntry(entry); !valid { glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.lbMasqSet.Name)) continue } proxier.lbMasqSet.activeEntries.Insert(entry.String()) } - if len(svcInfo.loadBalancerSourceRanges) != 0 { + if len(svcInfo.LoadBalancerSourceRanges) != 0 { // The service firewall rules are created based on ServiceSpec.loadBalancerSourceRanges field. // This currently works for loadbalancers that preserves source ips. // For loadbalancers which direct traffic to service NodePort, the firewall rules will not apply. @@ -1043,11 +924,11 @@ func (proxier *Proxier) syncProxyRules() { proxier.lbIngressSet.activeEntries.Insert(entry.String()) allowFromNode := false - for _, src := range svcInfo.loadBalancerSourceRanges { + for _, src := range svcInfo.LoadBalancerSourceRanges { // ipset call entry = &utilipset.Entry{ IP: ingress.IP, - Port: svcInfo.port, + Port: svcInfo.Port, Protocol: protocol, Net: src, SetType: utilipset.HashIPPortNet, @@ -1071,7 +952,7 @@ func (proxier *Proxier) syncProxyRules() { if allowFromNode { entry = &utilipset.Entry{ IP: ingress.IP, - Port: svcInfo.port, + Port: svcInfo.Port, Protocol: protocol, IP2: ingress.IP, SetType: utilipset.HashIPPortIP, @@ -1088,18 +969,18 @@ func (proxier *Proxier) syncProxyRules() { // ipvs call serv := &utilipvs.VirtualServer{ Address: net.ParseIP(ingress.IP), - Port: uint16(svcInfo.port), - Protocol: string(svcInfo.protocol), + Port: uint16(svcInfo.Port), + Protocol: string(svcInfo.Protocol), Scheduler: proxier.ipvsScheduler, } - if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP { + if svcInfo.SessionAffinityType == api.ServiceAffinityClientIP { serv.Flags |= utilipvs.FlagPersistent - serv.Timeout = uint32(svcInfo.stickyMaxAgeSeconds) + serv.Timeout = uint32(svcInfo.StickyMaxAgeSeconds) } // There is no need to bind LB ingress.IP to dummy interface, so set parameter `bindAddr` to `false`. if err := proxier.syncService(svcNameString, serv, false); err == nil { activeIPVSServices[serv.String()] = true - if err := proxier.syncEndpoint(svcName, svcInfo.onlyNodeLocalEndpoints, serv); err != nil { + if err := proxier.syncEndpoint(svcName, svcInfo.OnlyNodeLocalEndpoints, serv); err != nil { glog.Errorf("Failed to sync endpoint for service: %v, err: %v", serv, err) } } else { @@ -1108,11 +989,11 @@ func (proxier *Proxier) syncProxyRules() { } } - if svcInfo.nodePort != 0 { + if svcInfo.NodePort != 0 { lp := utilproxy.LocalPort{ Description: "nodePort for " + svcNameString, IP: "", - Port: svcInfo.nodePort, + Port: svcInfo.NodePort, Protocol: protocol, } if proxier.portsMap[lp] != nil { @@ -1125,7 +1006,7 @@ func (proxier *Proxier) syncProxyRules() { continue } if lp.Protocol == "udp" { - isIPv6 := conntrack.IsIPv6(svcInfo.clusterIP) + isIPv6 := conntrack.IsIPv6(svcInfo.ClusterIP) conntrack.ClearEntriesForPort(proxier.exec, lp.Port, isIPv6, clientv1.ProtocolUDP) } replacementPortsMap[lp] = socket @@ -1133,10 +1014,10 @@ func (proxier *Proxier) syncProxyRules() { // Nodeports need SNAT, unless they're local. // ipset call - if !svcInfo.onlyNodeLocalEndpoints { + if !svcInfo.OnlyNodeLocalEndpoints { entry = &utilipset.Entry{ // No need to provide ip info - Port: svcInfo.nodePort, + Port: svcInfo.NodePort, Protocol: protocol, SetType: utilipset.BitmapPort, } @@ -1182,18 +1063,18 @@ func (proxier *Proxier) syncProxyRules() { // ipvs call serv := &utilipvs.VirtualServer{ Address: nodeIP, - Port: uint16(svcInfo.nodePort), - Protocol: string(svcInfo.protocol), + Port: uint16(svcInfo.NodePort), + Protocol: string(svcInfo.Protocol), Scheduler: proxier.ipvsScheduler, } - if svcInfo.sessionAffinityType == api.ServiceAffinityClientIP { + if svcInfo.SessionAffinityType == api.ServiceAffinityClientIP { serv.Flags |= utilipvs.FlagPersistent - serv.Timeout = uint32(svcInfo.stickyMaxAgeSeconds) + serv.Timeout = uint32(svcInfo.StickyMaxAgeSeconds) } // There is no need to bind Node IP to dummy interface, so set parameter `bindAddr` to `false`. if err := proxier.syncService(svcNameString, serv, false); err == nil { activeIPVSServices[serv.String()] = true - if err := proxier.syncEndpoint(svcName, svcInfo.onlyNodeLocalEndpoints, serv); err != nil { + if err := proxier.syncEndpoint(svcName, svcInfo.OnlyNodeLocalEndpoints, serv); err != nil { glog.Errorf("Failed to sync endpoint for service: %v, err: %v", serv, err) } } else { @@ -1383,9 +1264,9 @@ func (proxier *Proxier) syncProxyRules() { // This assumes the proxier mutex is held func (proxier *Proxier) deleteEndpointConnections(connectionMap []proxy.ServiceEndpoint) { for _, epSvcPair := range connectionMap { - if svcInfo, ok := proxier.serviceMap[epSvcPair.ServicePortName]; ok && svcInfo.Protocol() == api.ProtocolUDP { + if svcInfo, ok := proxier.serviceMap[epSvcPair.ServicePortName]; ok && svcInfo.GetProtocol() == api.ProtocolUDP { endpointIP := utilproxy.IPPart(epSvcPair.Endpoint) - err := conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.ClusterIP(), endpointIP, clientv1.ProtocolUDP) + err := conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.GetClusterIP(), endpointIP, clientv1.ProtocolUDP) if err != nil { glog.Errorf("Failed to delete %s endpoint connections, error: %v", epSvcPair.ServicePortName.String(), err) } @@ -1447,14 +1328,9 @@ func (proxier *Proxier) syncEndpoint(svcPortName proxy.ServicePortName, onlyNode curEndpoints.Insert(des.String()) } - for _, eps := range proxier.endpointsMap[svcPortName] { - epInfo, ok := eps.(*endpointsInfo) - if !ok { - glog.Errorf("Failed to cast endpointsInfo") - continue - } - if !onlyNodeLocalEndpoints || onlyNodeLocalEndpoints && epInfo.isLocal { - newEndpoints.Insert(epInfo.endpoint) + for _, epInfo := range proxier.endpointsMap[svcPortName] { + if !onlyNodeLocalEndpoints || onlyNodeLocalEndpoints && epInfo.GetIsLocal() { + newEndpoints.Insert(epInfo.String()) } } diff --git a/pkg/proxy/ipvs/proxier_test.go b/pkg/proxy/ipvs/proxier_test.go index a26e7a38b49..1b5480c21b8 100644 --- a/pkg/proxy/ipvs/proxier_test.go +++ b/pkg/proxy/ipvs/proxier_test.go @@ -33,7 +33,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" netlinktest "k8s.io/kubernetes/pkg/proxy/ipvs/testing" - proxyutil "k8s.io/kubernetes/pkg/proxy/util" + utilproxy "k8s.io/kubernetes/pkg/proxy/util" proxyutiltest "k8s.io/kubernetes/pkg/proxy/util/testing" utilipset "k8s.io/kubernetes/pkg/util/ipset" ipsettest "k8s.io/kubernetes/pkg/util/ipset/testing" @@ -67,12 +67,12 @@ func newFakeHealthChecker() *fakeHealthChecker { // fakePortOpener implements portOpener. type fakePortOpener struct { - openPorts []*proxyutil.LocalPort + openPorts []*utilproxy.LocalPort } // OpenLocalPort fakes out the listen() and bind() used by syncProxyRules // to lock a local port. -func (f *fakePortOpener) OpenLocalPort(lp *proxyutil.LocalPort) (proxyutil.Closeable, error) { +func (f *fakePortOpener) OpenLocalPort(lp *utilproxy.LocalPort) (utilproxy.Closeable, error) { f.openPorts = append(f.openPorts, lp) return nil, nil } @@ -121,16 +121,16 @@ func NewFakeProxier(ipt utiliptables.Interface, ipvs utilipvs.Interface, ipset u return &Proxier{ exec: fexec, serviceMap: make(proxy.ServiceMap), - serviceChanges: proxy.NewServiceChangeTracker(), + serviceChanges: proxy.NewServiceChangeTracker(customizeServiceInfo, nil, nil), endpointsMap: make(proxy.EndpointsMap), - endpointsChanges: proxy.NewEndpointChangeTracker(testHostname), + endpointsChanges: proxy.NewEndpointChangeTracker(testHostname, nil, nil, nil), iptables: ipt, ipvs: ipvs, ipset: ipset, clusterCIDR: "10.0.0.0/24", hostname: testHostname, - portsMap: make(map[proxyutil.LocalPort]proxyutil.Closeable), - portMapper: &fakePortOpener{[]*proxyutil.LocalPort{}}, + portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable), + portMapper: &fakePortOpener{[]*utilproxy.LocalPort{}}, healthChecker: newFakeHealthChecker(), ipvsScheduler: DefaultScheduler, ipGetter: &fakeIPGetter{nodeIPs: nodeIPs}, @@ -1581,15 +1581,15 @@ func Test_updateEndpointsMap(t *testing.T) { // or non-nil) and must be of equal length. previousEndpoints []*api.Endpoints currentEndpoints []*api.Endpoints - oldEndpoints map[proxy.ServicePortName][]*endpointsInfo - expectedResult map[proxy.ServicePortName][]*endpointsInfo + oldEndpoints map[proxy.ServicePortName][]*proxy.EndpointInfoCommon + expectedResult map[proxy.ServicePortName][]*proxy.EndpointInfoCommon expectedStaleEndpoints []proxy.ServiceEndpoint expectedStaleServiceNames map[proxy.ServicePortName]bool expectedHealthchecks map[types.NamespacedName]int }{{ // Case[0]: nothing - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, expectedHealthchecks: map[types.NamespacedName]int{}, @@ -1601,14 +1601,14 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPort), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1622,14 +1622,14 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1645,20 +1645,20 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsets), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1672,26 +1672,26 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, + {Endpoint: "1.1.1.3:13", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, + {Endpoint: "1.1.1.3:13", IsLocal: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1709,56 +1709,56 @@ func Test_updateEndpointsMap(t *testing.T) { makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1), makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, - {endpoint: "1.1.1.4:13", isLocal: true}, + {Endpoint: "1.1.1.3:13", IsLocal: false}, + {Endpoint: "1.1.1.4:13", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p14"): { - {endpoint: "1.1.1.3:14", isLocal: false}, - {endpoint: "1.1.1.4:14", isLocal: true}, + {Endpoint: "1.1.1.3:14", IsLocal: false}, + {Endpoint: "1.1.1.4:14", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p21"): { - {endpoint: "2.2.2.1:21", isLocal: false}, - {endpoint: "2.2.2.2:21", isLocal: true}, + {Endpoint: "2.2.2.1:21", IsLocal: false}, + {Endpoint: "2.2.2.2:21", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.1:22", isLocal: false}, - {endpoint: "2.2.2.2:22", isLocal: true}, + {Endpoint: "2.2.2.1:22", IsLocal: false}, + {Endpoint: "2.2.2.2:22", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p13"): { - {endpoint: "1.1.1.3:13", isLocal: false}, - {endpoint: "1.1.1.4:13", isLocal: true}, + {Endpoint: "1.1.1.3:13", IsLocal: false}, + {Endpoint: "1.1.1.4:13", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p14"): { - {endpoint: "1.1.1.3:14", isLocal: false}, - {endpoint: "1.1.1.4:14", isLocal: true}, + {Endpoint: "1.1.1.3:14", IsLocal: false}, + {Endpoint: "1.1.1.4:14", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p21"): { - {endpoint: "2.2.2.1:21", isLocal: false}, - {endpoint: "2.2.2.2:21", isLocal: true}, + {Endpoint: "2.2.2.1:21", IsLocal: false}, + {Endpoint: "2.2.2.2:21", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.1:22", isLocal: false}, - {endpoint: "2.2.2.2:22", isLocal: true}, + {Endpoint: "2.2.2.1:22", IsLocal: false}, + {Endpoint: "2.2.2.2:22", IsLocal: true}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1775,10 +1775,10 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPortLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1796,12 +1796,12 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ nil, }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ Endpoint: "1.1.1.1:11", ServicePortName: makeServicePortName("ns1", "ep1", ""), @@ -1816,19 +1816,19 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1846,19 +1846,19 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPort), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.2:11", isLocal: true}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.1:12", isLocal: false}, - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.1:12", IsLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -1881,17 +1881,17 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsetsWithLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: true}, + {Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1909,17 +1909,17 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPort), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -1936,14 +1936,14 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortRenamed), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11-2"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -1962,14 +1962,14 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortRenumbered), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:22", isLocal: false}, + {Endpoint: "1.1.1.1:22", IsLocal: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -1992,41 +1992,41 @@ func Test_updateEndpointsMap(t *testing.T) { makeTestEndpoints("ns3", "ep3", complexAfter3), makeTestEndpoints("ns4", "ep4", complexAfter4), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns2", "ep2", "p22"): { - {endpoint: "2.2.2.2:22", isLocal: true}, - {endpoint: "2.2.2.22:22", isLocal: true}, + {Endpoint: "2.2.2.2:22", IsLocal: true}, + {Endpoint: "2.2.2.22:22", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p23"): { - {endpoint: "2.2.2.3:23", isLocal: true}, + {Endpoint: "2.2.2.3:23", IsLocal: true}, }, makeServicePortName("ns4", "ep4", "p44"): { - {endpoint: "4.4.4.4:44", isLocal: true}, - {endpoint: "4.4.4.5:44", isLocal: true}, + {Endpoint: "4.4.4.4:44", IsLocal: true}, + {Endpoint: "4.4.4.5:44", IsLocal: true}, }, makeServicePortName("ns4", "ep4", "p45"): { - {endpoint: "4.4.4.6:45", isLocal: true}, + {Endpoint: "4.4.4.6:45", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", "p11"): { - {endpoint: "1.1.1.1:11", isLocal: false}, - {endpoint: "1.1.1.11:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "1.1.1.11:11", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p12"): { - {endpoint: "1.1.1.2:12", isLocal: false}, + {Endpoint: "1.1.1.2:12", IsLocal: false}, }, makeServicePortName("ns1", "ep1", "p122"): { - {endpoint: "1.1.1.2:122", isLocal: false}, + {Endpoint: "1.1.1.2:122", IsLocal: false}, }, makeServicePortName("ns3", "ep3", "p33"): { - {endpoint: "3.3.3.3:33", isLocal: false}, + {Endpoint: "3.3.3.3:33", IsLocal: false}, }, makeServicePortName("ns4", "ep4", "p44"): { - {endpoint: "4.4.4.4:44", isLocal: true}, + {Endpoint: "4.4.4.4:44", IsLocal: true}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2061,10 +2061,10 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPort), }, - oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, - expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, + expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ makeServicePortName("ns1", "ep1", ""): { - {endpoint: "1.1.1.1:11", isLocal: false}, + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2148,7 +2148,7 @@ func Test_updateEndpointsMap(t *testing.T) { } } -func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expected map[proxy.ServicePortName][]*endpointsInfo) { +func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expected map[proxy.ServicePortName][]*proxy.EndpointInfoCommon) { if len(newMap) != len(expected) { t.Errorf("[%d] expected %d results, got %d: %v", tci, len(expected), len(newMap), newMap) } @@ -2157,9 +2157,9 @@ func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expe t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(expected[x]), x, len(newMap[x])) } else { for i := range expected[x] { - newEp, ok := newMap[x][i].(*endpointsInfo) + newEp, ok := newMap[x][i].(*proxy.EndpointInfoCommon) if !ok { - t.Errorf("Failed to cast endpointsInfo") + t.Errorf("Failed to cast proxy.EndpointInfoCommon") continue } if *newEp != *(expected[x][i]) { diff --git a/pkg/proxy/service.go b/pkg/proxy/service.go index 82407ab1970..515bdaa1303 100644 --- a/pkg/proxy/service.go +++ b/pkg/proxy/service.go @@ -17,6 +17,8 @@ limitations under the License. package proxy import ( + "fmt" + "net" "reflect" "sync" @@ -24,10 +26,91 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/record" + apiservice "k8s.io/kubernetes/pkg/api/service" api "k8s.io/kubernetes/pkg/apis/core" - proxyutil "k8s.io/kubernetes/pkg/proxy/util" + "k8s.io/kubernetes/pkg/apis/core/helper" + utilproxy "k8s.io/kubernetes/pkg/proxy/util" ) +// ServiceInfoCommon contains common service information. +type ServiceInfoCommon struct { + ClusterIP net.IP + Port int + Protocol api.Protocol + NodePort int + LoadBalancerStatus api.LoadBalancerStatus + SessionAffinityType api.ServiceAffinity + StickyMaxAgeSeconds int + ExternalIPs []string + LoadBalancerSourceRanges []string + HealthCheckNodePort int + OnlyNodeLocalEndpoints bool +} + +var _ ServicePort = &ServiceInfoCommon{} + +// String is part of ServicePort interface. +func (info *ServiceInfoCommon) String() string { + return fmt.Sprintf("%s:%d/%s", info.ClusterIP, info.Port, info.Protocol) +} + +// GetClusterIP is part of ServicePort interface. +func (info *ServiceInfoCommon) GetClusterIP() string { + return info.ClusterIP.String() +} + +// GetProtocol is part of ServicePort interface. +func (info *ServiceInfoCommon) GetProtocol() api.Protocol { + return info.Protocol +} + +// GetHealthCheckNodePort is part of ServicePort interface. +func (info *ServiceInfoCommon) GetHealthCheckNodePort() int { + return info.HealthCheckNodePort +} + +func (sct *ServiceChangeTracker) newServiceInfoCommon(port *api.ServicePort, service *api.Service) *ServiceInfoCommon { + onlyNodeLocalEndpoints := false + if apiservice.RequestsOnlyLocalTraffic(service) { + onlyNodeLocalEndpoints = true + } + var stickyMaxAgeSeconds int + if service.Spec.SessionAffinity == api.ServiceAffinityClientIP { + // Kube-apiserver side guarantees SessionAffinityConfig won't be nil when session affinity type is ClientIP + stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) + } + info := &ServiceInfoCommon{ + ClusterIP: net.ParseIP(service.Spec.ClusterIP), + Port: int(port.Port), + Protocol: port.Protocol, + NodePort: int(port.NodePort), + // Deep-copy in case the service instance changes + LoadBalancerStatus: *helper.LoadBalancerStatusDeepCopy(&service.Status.LoadBalancer), + SessionAffinityType: service.Spec.SessionAffinity, + StickyMaxAgeSeconds: stickyMaxAgeSeconds, + OnlyNodeLocalEndpoints: onlyNodeLocalEndpoints, + } + + info.ExternalIPs = make([]string, len(service.Spec.ExternalIPs)) + info.LoadBalancerSourceRanges = make([]string, len(service.Spec.LoadBalancerSourceRanges)) + copy(info.LoadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges) + copy(info.ExternalIPs, service.Spec.ExternalIPs) + + if apiservice.NeedsHealthCheck(service) { + p := service.Spec.HealthCheckNodePort + if p == 0 { + glog.Errorf("Service %s/%s has no healthcheck nodeport", service.Namespace, service.Name) + } else { + info.HealthCheckNodePort = int(p) + } + } + + return info +} + +type customizeServiceInfoFunc func(*api.ServicePort, *api.Service, *ServiceInfoCommon) ServicePort + // serviceChange contains all changes to services that happened since proxy rules were synced. For a single object, // changes are accumulated, i.e. previous is state from before applying the changes, // current is state after applying all of the changes. @@ -43,12 +126,20 @@ type ServiceChangeTracker struct { lock sync.Mutex // items maps a service to its serviceChange. items map[types.NamespacedName]*serviceChange + // customizeServiceInfo allows proxier to inject customized infomation when processing service. + customizeServiceInfo customizeServiceInfoFunc + // isIPv6Mode indicates if change tracker is under IPv6/IPv4 mode. Nil means not applicable. + isIPv6Mode *bool + recorder record.EventRecorder } // NewServiceChangeTracker initializes a ServiceChangeTracker -func NewServiceChangeTracker() *ServiceChangeTracker { +func NewServiceChangeTracker(customizeServiceInfo customizeServiceInfoFunc, isIPv6Mode *bool, recorder record.EventRecorder) *ServiceChangeTracker { return &ServiceChangeTracker{ - items: make(map[types.NamespacedName]*serviceChange), + items: make(map[types.NamespacedName]*serviceChange), + customizeServiceInfo: customizeServiceInfo, + isIPv6Mode: isIPv6Mode, + recorder: recorder, } } @@ -60,10 +151,7 @@ func NewServiceChangeTracker() *ServiceChangeTracker { // - pass as the pair. // Delete item // - pass as the pair. -// -// makeServicePort() return a proxy.ServicePort based on the given Service and its ServicePort. We inject makeServicePort() -// so that giving caller side a chance to initialize proxy.ServicePort interface. -func (sct *ServiceChangeTracker) Update(previous, current *api.Service, makeServicePort func(servicePort *api.ServicePort, service *api.Service) ServicePort) bool { +func (sct *ServiceChangeTracker) Update(previous, current *api.Service) bool { svc := current if svc == nil { svc = previous @@ -80,10 +168,10 @@ func (sct *ServiceChangeTracker) Update(previous, current *api.Service, makeServ change, exists := sct.items[namespacedName] if !exists { change = &serviceChange{} - change.previous = serviceToServiceMap(previous, makeServicePort) + change.previous = sct.serviceToServiceMap(previous) sct.items[namespacedName] = change } - change.current = serviceToServiceMap(current, makeServicePort) + change.current = sct.serviceToServiceMap(current) // if change.previous equal to change.current, it means no change if reflect.DeepEqual(change.previous, change.current) { delete(sct.items, namespacedName) @@ -110,28 +198,26 @@ func UpdateServiceMap(serviceMap ServiceMap, changes *ServiceChangeTracker) (res // computing this incrementally similarly to serviceMap. result.HCServiceNodePorts = make(map[types.NamespacedName]uint16) for svcPortName, info := range serviceMap { - if info.HealthCheckNodePort() != 0 { - result.HCServiceNodePorts[svcPortName.NamespacedName] = uint16(info.HealthCheckNodePort()) + if info.GetHealthCheckNodePort() != 0 { + result.HCServiceNodePorts[svcPortName.NamespacedName] = uint16(info.GetHealthCheckNodePort()) } } return result } -// ServiceMap maps a service to its ServicePort information. +// ServiceMap maps a service to its ServicePort. type ServiceMap map[ServicePortName]ServicePort // serviceToServiceMap translates a single Service object to a ServiceMap. -// makeServicePort() return a proxy.ServicePort based on the given Service and its ServicePort. We inject makeServicePort() -// so that giving caller side a chance to initialize proxy.ServicePort interface. // // NOTE: service object should NOT be modified. -func serviceToServiceMap(service *api.Service, makeServicePort func(servicePort *api.ServicePort, service *api.Service) ServicePort) ServiceMap { +func (sct *ServiceChangeTracker) serviceToServiceMap(service *api.Service) ServiceMap { if service == nil { return nil } svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} - if proxyutil.ShouldSkipService(svcName, service) { + if utilproxy.ShouldSkipService(svcName, service) { return nil } @@ -139,7 +225,12 @@ func serviceToServiceMap(service *api.Service, makeServicePort func(servicePort for i := range service.Spec.Ports { servicePort := &service.Spec.Ports[i] svcPortName := ServicePortName{NamespacedName: svcName, Port: servicePort.Name} - serviceMap[svcPortName] = makeServicePort(servicePort, service) + svcInfoCommon := sct.newServiceInfoCommon(servicePort, service) + if sct.customizeServiceInfo != nil { + serviceMap[svcPortName] = sct.customizeServiceInfo(servicePort, service, svcInfoCommon) + } else { + serviceMap[svcPortName] = svcInfoCommon + } } return serviceMap } @@ -213,8 +304,8 @@ func (sm *ServiceMap) unmerge(other ServiceMap, UDPStaleClusterIP sets.String) { info, exists := (*sm)[svcPortName] if exists { glog.V(1).Infof("Removing service port %q", svcPortName) - if info.Protocol() == api.ProtocolUDP { - UDPStaleClusterIP.Insert(info.ClusterIP()) + if info.GetProtocol() == api.ProtocolUDP { + UDPStaleClusterIP.Insert(info.GetClusterIP()) } delete(*sm, svcPortName) } else { diff --git a/pkg/proxy/service_test.go b/pkg/proxy/service_test.go index ed2ad7d556e..0a24b1c0fee 100644 --- a/pkg/proxy/service_test.go +++ b/pkg/proxy/service_test.go @@ -17,9 +17,7 @@ limitations under the License. package proxy import ( - "fmt" "net" - "reflect" "testing" "github.com/davecgh/go-spew/spew" @@ -27,59 +25,19 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" - apiservice "k8s.io/kubernetes/pkg/api/service" api "k8s.io/kubernetes/pkg/apis/core" ) const testHostname = "test-hostname" -// fake implementation for service info. -type fakeServiceInfo struct { - clusterIP net.IP - port int - protocol api.Protocol - healthCheckNodePort int -} - -func (f *fakeServiceInfo) String() string { - return fmt.Sprintf("%s:%d/%s", f.clusterIP, f.port, f.protocol) -} - -func (f *fakeServiceInfo) ClusterIP() string { - return f.clusterIP.String() -} - -func (f *fakeServiceInfo) Protocol() api.Protocol { - return f.protocol -} - -func (f *fakeServiceInfo) HealthCheckNodePort() int { - return f.healthCheckNodePort -} - -func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int) *fakeServiceInfo { - info := &fakeServiceInfo{ - clusterIP: net.ParseIP(clusterIP), - port: port, - protocol: api.Protocol(protocol), +func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int) *ServiceInfoCommon { + info := &ServiceInfoCommon{ + ClusterIP: net.ParseIP(clusterIP), + Port: port, + Protocol: api.Protocol(protocol), } if healthcheckNodePort != 0 { - info.healthCheckNodePort = healthcheckNodePort - } - return info -} - -func newFakeServiceInfo(servicePort *api.ServicePort, service *api.Service) ServicePort { - info := &fakeServiceInfo{ - clusterIP: net.ParseIP(service.Spec.ClusterIP), - port: int(servicePort.Port), - protocol: servicePort.Protocol, - } - if apiservice.NeedsHealthCheck(service) { - p := service.Spec.HealthCheckNodePort - if p != 0 { - info.healthCheckNodePort = int(p) - } + info.HealthCheckNodePort = healthcheckNodePort } return info } @@ -120,15 +78,17 @@ func makeServicePortName(ns, name, port string) ServicePortName { } } -func Test_serviceToServiceMap(t *testing.T) { +func TestServiceToServiceMap(t *testing.T) { + svcTracker := NewServiceChangeTracker(nil, nil, nil) + testCases := []struct { service *api.Service - expected map[ServicePortName]*fakeServiceInfo + expected map[ServicePortName]*ServiceInfoCommon }{ { // Case[0]: nothing service: nil, - expected: map[ServicePortName]*fakeServiceInfo{}, + expected: map[ServicePortName]*ServiceInfoCommon{}, }, { // Case[1]: headless service @@ -137,7 +97,7 @@ func Test_serviceToServiceMap(t *testing.T) { svc.Spec.ClusterIP = api.ClusterIPNone svc.Spec.Ports = addTestPort(svc.Spec.Ports, "rpc", "UDP", 1234, 0, 0) }), - expected: map[ServicePortName]*fakeServiceInfo{}, + expected: map[ServicePortName]*ServiceInfoCommon{}, }, { // Case[2]: headless service without port @@ -145,7 +105,7 @@ func Test_serviceToServiceMap(t *testing.T) { svc.Spec.Type = api.ServiceTypeClusterIP svc.Spec.ClusterIP = api.ClusterIPNone }), - expected: map[ServicePortName]*fakeServiceInfo{}, + expected: map[ServicePortName]*ServiceInfoCommon{}, }, { // Case[3]: cluster ip service @@ -155,7 +115,7 @@ func Test_serviceToServiceMap(t *testing.T) { svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 0) svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "UDP", 1235, 5321, 0) }), - expected: map[ServicePortName]*fakeServiceInfo{ + expected: map[ServicePortName]*ServiceInfoCommon{ makeServicePortName("ns2", "cluster-ip", "p1"): makeTestServiceInfo("172.16.55.4", 1234, "UDP", 0), makeServicePortName("ns2", "cluster-ip", "p2"): makeTestServiceInfo("172.16.55.4", 1235, "UDP", 0), }, @@ -168,7 +128,7 @@ func Test_serviceToServiceMap(t *testing.T) { svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 345, 678, 0) svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 344, 677, 0) }), - expected: map[ServicePortName]*fakeServiceInfo{ + expected: map[ServicePortName]*ServiceInfoCommon{ makeServicePortName("ns2", "node-port", "port1"): makeTestServiceInfo("172.16.55.10", 345, "UDP", 0), makeServicePortName("ns2", "node-port", "port2"): makeTestServiceInfo("172.16.55.10", 344, "TCP", 0), }, @@ -187,7 +147,7 @@ func Test_serviceToServiceMap(t *testing.T) { }, } }), - expected: map[ServicePortName]*fakeServiceInfo{ + expected: map[ServicePortName]*ServiceInfoCommon{ makeServicePortName("ns1", "load-balancer", "port3"): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0), makeServicePortName("ns1", "load-balancer", "port4"): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0), }, @@ -208,7 +168,7 @@ func Test_serviceToServiceMap(t *testing.T) { svc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeLocal svc.Spec.HealthCheckNodePort = 345 }), - expected: map[ServicePortName]*fakeServiceInfo{ + expected: map[ServicePortName]*ServiceInfoCommon{ makeServicePortName("ns1", "only-local-load-balancer", "portx"): makeTestServiceInfo("172.16.55.12", 8677, "UDP", 345), makeServicePortName("ns1", "only-local-load-balancer", "porty"): makeTestServiceInfo("172.16.55.12", 8678, "UDP", 345), }, @@ -221,21 +181,24 @@ func Test_serviceToServiceMap(t *testing.T) { svc.Spec.ExternalName = "foo2.bar.com" svc.Spec.Ports = addTestPort(svc.Spec.Ports, "portz", "UDP", 1235, 5321, 0) }), - expected: map[ServicePortName]*fakeServiceInfo{}, + expected: map[ServicePortName]*ServiceInfoCommon{}, }, } for tci, tc := range testCases { // outputs - newServices := serviceToServiceMap(tc.service, newFakeServiceInfo) + newServices := svcTracker.serviceToServiceMap(tc.service) if len(newServices) != len(tc.expected) { t.Errorf("[%d] expected %d new, got %d: %v", tci, len(tc.expected), len(newServices), spew.Sdump(newServices)) } for x := range tc.expected { - svc := newServices[x].(*fakeServiceInfo) - if !reflect.DeepEqual(svc, tc.expected[x]) { - t.Errorf("[%d] expected new[%v]to be %v, got %v", tci, x, tc.expected[x], *svc) + svcInfo := newServices[x].(*ServiceInfoCommon) + if !svcInfo.ClusterIP.Equal(tc.expected[x].ClusterIP) || + svcInfo.Port != tc.expected[x].Port || + svcInfo.Protocol != tc.expected[x].Protocol || + svcInfo.HealthCheckNodePort != tc.expected[x].HealthCheckNodePort { + t.Errorf("[%d] expected new[%v]to be %v, got %v", tci, x, tc.expected[x], *svcInfo) } } } @@ -252,9 +215,9 @@ type FakeProxier struct { func newFakeProxier() *FakeProxier { return &FakeProxier{ serviceMap: make(ServiceMap), - serviceChanges: NewServiceChangeTracker(), + serviceChanges: NewServiceChangeTracker(nil, nil, nil), endpointsMap: make(EndpointsMap), - endpointsChanges: NewEndpointChangeTracker(testHostname), + endpointsChanges: NewEndpointChangeTracker(testHostname, nil, nil, nil), } } @@ -265,30 +228,15 @@ func makeServiceMap(fake *FakeProxier, allServices ...*api.Service) { } func (fake *FakeProxier) addService(service *api.Service) { - fake.serviceChanges.Update(nil, service, makeServicePort) + fake.serviceChanges.Update(nil, service) } func (fake *FakeProxier) updateService(oldService *api.Service, service *api.Service) { - fake.serviceChanges.Update(oldService, service, makeServicePort) + fake.serviceChanges.Update(oldService, service) } func (fake *FakeProxier) deleteService(service *api.Service) { - fake.serviceChanges.Update(service, nil, makeServicePort) -} - -func makeServicePort(port *api.ServicePort, service *api.Service) ServicePort { - info := &fakeServiceInfo{ - clusterIP: net.ParseIP(service.Spec.ClusterIP), - port: int(port.Port), - protocol: port.Protocol, - } - if apiservice.NeedsHealthCheck(service) { - p := service.Spec.HealthCheckNodePort - if p != 0 { - info.healthCheckNodePort = int(p) - } - } - return info + fake.serviceChanges.Update(service, nil) } func TestUpdateServiceMapHeadless(t *testing.T) { diff --git a/pkg/proxy/types.go b/pkg/proxy/types.go index 613c570897d..438635639d1 100644 --- a/pkg/proxy/types.go +++ b/pkg/proxy/types.go @@ -48,23 +48,26 @@ func (spn ServicePortName) String() string { type ServicePort interface { // String returns service string. An example format can be: `IP:Port/Protocol`. String() string - // ClusterIP returns service cluster IP. - ClusterIP() string - // Protocol returns service protocol. - Protocol() api.Protocol - // HealthCheckNodePort returns service health check node port if present. If return 0, it means not present. - HealthCheckNodePort() int + // GetClusterIP returns service cluster IP. + GetClusterIP() string + // GetProtocol returns service protocol. + GetProtocol() api.Protocol + // GetHealthCheckNodePort returns service health check node port if present. If return 0, it means not present. + GetHealthCheckNodePort() int } // Endpoint in an interface which abstracts information about an endpoint. +// TODO: Rename functions to be consistent with ServicePort. type Endpoint interface { // String returns endpoint string. An example format can be: `IP:Port`. // We take the returned value as ServiceEndpoint.Endpoint. String() string - // IsLocal returns true if the endpoint is running in same host as kube-proxy, otherwise returns false. - IsLocal() bool - // IP returns IP part of endpoints. + // GetIsLocal returns true if the endpoint is running in same host as kube-proxy, otherwise returns false. + GetIsLocal() bool + // IP returns IP part of the endpoint. IP() string + // Port returns the Port part of the endpoint. + Port() (int, error) // Equal checks if two endpoints are equal. Equal(Endpoint) bool } From dfbec1a63a2e1a83394b9eac733ba3ffcd2cc8f1 Mon Sep 17 00:00:00 2001 From: Zihong Zheng Date: Fri, 16 Feb 2018 19:13:33 -0800 Subject: [PATCH 2/8] [kube-proxy] Move ipv6 related funcs to utils pkg --- .../network/hostport/hostport_manager.go | 3 +- pkg/proxy/iptables/proxier.go | 5 +- pkg/proxy/ipvs/proxier.go | 5 +- pkg/proxy/util/utils.go | 6 +- pkg/util/conntrack/conntrack.go | 17 +-- pkg/util/conntrack/conntrack_test.go | 102 +-------------- pkg/util/net/OWNERS | 4 + pkg/util/net/net.go | 32 +++++ pkg/util/net/net_test.go | 118 ++++++++++++++++++ 9 files changed, 171 insertions(+), 121 deletions(-) create mode 100644 pkg/util/net/OWNERS create mode 100644 pkg/util/net/net.go create mode 100644 pkg/util/net/net_test.go diff --git a/pkg/kubelet/network/hostport/hostport_manager.go b/pkg/kubelet/network/hostport/hostport_manager.go index 9d9100a014d..3177ac5adff 100644 --- a/pkg/kubelet/network/hostport/hostport_manager.go +++ b/pkg/kubelet/network/hostport/hostport_manager.go @@ -31,6 +31,7 @@ import ( iptablesproxy "k8s.io/kubernetes/pkg/proxy/iptables" "k8s.io/kubernetes/pkg/util/conntrack" utiliptables "k8s.io/kubernetes/pkg/util/iptables" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/utils/exec" ) @@ -165,7 +166,7 @@ func (hm *hostportManager) Add(id string, podPortMapping *PodPortMapping, natInt // clean up opened host port if encounter any error return utilerrors.NewAggregate([]error{err, hm.closeHostports(hostportMappings)}) } - isIpv6 := conntrack.IsIPv6(podPortMapping.IP) + isIpv6 := utilnet.IsIPv6(podPortMapping.IP) // Remove conntrack entries just after adding the new iptables rules. If the conntrack entry is removed along with // the IP tables rule, it can be the case that the packets received by the node after iptables rule removal will diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index 80f7f54fde9..1b7e8ca55c5 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -46,6 +46,7 @@ import ( "k8s.io/kubernetes/pkg/util/async" "k8s.io/kubernetes/pkg/util/conntrack" utiliptables "k8s.io/kubernetes/pkg/util/iptables" + utilnet "k8s.io/kubernetes/pkg/util/net" utilsysctl "k8s.io/kubernetes/pkg/util/sysctl" utilversion "k8s.io/kubernetes/pkg/util/version" utilexec "k8s.io/utils/exec" @@ -758,7 +759,7 @@ func (proxier *Proxier) syncProxyRules() { glog.Errorf("Failed to cast serviceInfo %q", svcName.String()) continue } - isIPv6 := conntrack.IsIPv6(svcInfo.ClusterIP) + isIPv6 := utilnet.IsIPv6(svcInfo.ClusterIP) protocol := strings.ToLower(string(svcInfo.Protocol)) svcNameString := svcInfo.serviceNameString hasEndpoints := len(proxier.endpointsMap[svcName]) > 0 @@ -1223,7 +1224,7 @@ func (proxier *Proxier) syncProxyRules() { break } // Ignore IP addresses with incorrect version - if isIPv6 && !conntrack.IsIPv6String(address) || !isIPv6 && conntrack.IsIPv6String(address) { + if isIPv6 && !utilnet.IsIPv6String(address) || !isIPv6 && utilnet.IsIPv6String(address) { glog.Errorf("IP address %s has incorrect IP version", address) continue } diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index 3a0261a1f96..cd561050a1d 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -47,6 +47,7 @@ import ( utilipset "k8s.io/kubernetes/pkg/util/ipset" utiliptables "k8s.io/kubernetes/pkg/util/iptables" utilipvs "k8s.io/kubernetes/pkg/util/ipvs" + utilnet "k8s.io/kubernetes/pkg/util/net" utilsysctl "k8s.io/kubernetes/pkg/util/sysctl" utilexec "k8s.io/utils/exec" ) @@ -289,7 +290,7 @@ func NewProxier(ipt utiliptables.Interface, nodeIP = net.ParseIP("127.0.0.1") } - isIPv6 := conntrack.IsIPv6(nodeIP) + isIPv6 := utilnet.IsIPv6(nodeIP) glog.V(2).Infof("nodeIP: %v, isIPv6: %v", nodeIP, isIPv6) @@ -1006,7 +1007,7 @@ func (proxier *Proxier) syncProxyRules() { continue } if lp.Protocol == "udp" { - isIPv6 := conntrack.IsIPv6(svcInfo.ClusterIP) + isIPv6 := utilnet.IsIPv6(svcInfo.ClusterIP) conntrack.ClearEntriesForPort(proxier.exec, lp.Port, isIPv6, clientv1.ProtocolUDP) } replacementPortsMap[lp] = socket diff --git a/pkg/proxy/util/utils.go b/pkg/proxy/util/utils.go index 037cbdd1e9c..93cf26323a1 100644 --- a/pkg/proxy/util/utils.go +++ b/pkg/proxy/util/utils.go @@ -24,7 +24,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core/helper" - "k8s.io/kubernetes/pkg/util/conntrack" + utilnet "k8s.io/kubernetes/pkg/util/net" "github.com/golang/glog" ) @@ -117,10 +117,10 @@ func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) return nil, fmt.Errorf("error parsing CIDR for interface %s, error: %v", itf.Name, err) } if ipNet.Contains(ip) { - if conntrack.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) { + if utilnet.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) { uniqueAddressList.Insert(ip.String()) } - if !conntrack.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) { + if !utilnet.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) { uniqueAddressList.Insert(ip.String()) } } diff --git a/pkg/util/conntrack/conntrack.go b/pkg/util/conntrack/conntrack.go index bc08c2d6d7a..353bc0d0c25 100644 --- a/pkg/util/conntrack/conntrack.go +++ b/pkg/util/conntrack/conntrack.go @@ -18,11 +18,11 @@ package conntrack import ( "fmt" - "net" "strconv" "strings" "k8s.io/api/core/v1" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/utils/exec" ) @@ -31,17 +31,6 @@ import ( // NoConnectionToDelete is the error string returned by conntrack when no matching connections are found const NoConnectionToDelete = "0 flow entries have been deleted" -// IsIPv6 returns true if the given ip address is a valid ipv6 address -func IsIPv6(netIP net.IP) bool { - return netIP != nil && netIP.To4() == nil -} - -// IsIPv6String returns true if the given string is a valid ipv6 address -func IsIPv6String(ip string) bool { - netIP := net.ParseIP(ip) - return IsIPv6(netIP) -} - func protoStr(proto v1.Protocol) string { return strings.ToLower(string(proto)) } @@ -56,7 +45,7 @@ func parametersWithFamily(isIPv6 bool, parameters ...string) []string { // ClearEntriesForIP uses the conntrack tool to delete the conntrack entries // for the UDP connections specified by the given service IP func ClearEntriesForIP(execer exec.Interface, ip string, protocol v1.Protocol) error { - parameters := parametersWithFamily(IsIPv6String(ip), "-D", "--orig-dst", ip, "-p", protoStr(protocol)) + parameters := parametersWithFamily(utilnet.IsIPv6String(ip), "-D", "--orig-dst", ip, "-p", protoStr(protocol)) err := Exec(execer, parameters...) if err != nil && !strings.Contains(err.Error(), NoConnectionToDelete) { // TODO: Better handling for deletion failure. When failure occur, stale udp connection may not get flushed. @@ -107,7 +96,7 @@ func ClearEntriesForPort(execer exec.Interface, port int, isIPv6 bool, protocol // ClearEntriesForNAT uses the conntrack tool to delete the conntrack entries // for connections specified by the {origin, dest} IP pair. func ClearEntriesForNAT(execer exec.Interface, origin, dest string, protocol v1.Protocol) error { - parameters := parametersWithFamily(IsIPv6String(origin), "-D", "--orig-dst", origin, "--dst-nat", dest, + parameters := parametersWithFamily(utilnet.IsIPv6String(origin), "-D", "--orig-dst", origin, "--dst-nat", dest, "-p", protoStr(protocol)) err := Exec(execer, parameters...) if err != nil && !strings.Contains(err.Error(), NoConnectionToDelete) { diff --git a/pkg/util/conntrack/conntrack_test.go b/pkg/util/conntrack/conntrack_test.go index c11fac76fce..6e1c18735fb 100644 --- a/pkg/util/conntrack/conntrack_test.go +++ b/pkg/util/conntrack/conntrack_test.go @@ -18,11 +18,11 @@ package conntrack import ( "fmt" - "net" "strings" "testing" "k8s.io/api/core/v1" + utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/utils/exec" fakeexec "k8s.io/utils/exec/testing" ) @@ -119,7 +119,7 @@ func TestClearUDPConntrackForIP(t *testing.T) { if err := ClearEntriesForIP(&fexec, tc.ip, v1.ProtocolUDP); err != nil { t.Errorf("%s test case:, Unexpected error: %v", tc.name, err) } - expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s -p udp", tc.ip) + familyParamStr(IsIPv6String(tc.ip)) + expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s -p udp", tc.ip) + familyParamStr(utilnet.IsIPv6String(tc.ip)) execCommand := strings.Join(fcmd.CombinedOutputLog[svcCount], " ") if expectCommand != execCommand { t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand) @@ -223,7 +223,7 @@ func TestDeleteUDPConnections(t *testing.T) { if err != nil { t.Errorf("%s test case: unexpected error: %v", tc.name, err) } - expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s --dst-nat %s -p udp", tc.origin, tc.dest) + familyParamStr(IsIPv6String(tc.origin)) + expectCommand := fmt.Sprintf("conntrack -D --orig-dst %s --dst-nat %s -p udp", tc.origin, tc.dest) + familyParamStr(utilnet.IsIPv6String(tc.origin)) execCommand := strings.Join(fcmd.CombinedOutputLog[i], " ") if expectCommand != execCommand { t.Errorf("%s test case: Expect command: %s, but executed %s", tc.name, expectCommand, execCommand) @@ -234,99 +234,3 @@ func TestDeleteUDPConnections(t *testing.T) { t.Errorf("Expect command executed %d times, but got %d", svcCount, fexec.CommandCalls) } } - -func TestIsIPv6String(t *testing.T) { - testCases := []struct { - ip string - expectIPv6 bool - }{ - { - ip: "127.0.0.1", - expectIPv6: false, - }, - { - ip: "192.168.0.0", - expectIPv6: false, - }, - { - ip: "1.2.3.4", - expectIPv6: false, - }, - { - ip: "bad ip", - expectIPv6: false, - }, - { - ip: "::1", - expectIPv6: true, - }, - { - ip: "fd00::600d:f00d", - expectIPv6: true, - }, - { - ip: "2001:db8::5", - expectIPv6: true, - }, - } - for i := range testCases { - isIPv6 := IsIPv6String(testCases[i].ip) - if isIPv6 != testCases[i].expectIPv6 { - t.Errorf("[%d] Expect ipv6 %v, got %v", i+1, testCases[i].expectIPv6, isIPv6) - } - } -} - -func TestIsIPv6(t *testing.T) { - testCases := []struct { - ip net.IP - expectIPv6 bool - }{ - { - ip: net.IPv4zero, - expectIPv6: false, - }, - { - ip: net.IPv4bcast, - expectIPv6: false, - }, - { - ip: net.ParseIP("127.0.0.1"), - expectIPv6: false, - }, - { - ip: net.ParseIP("10.20.40.40"), - expectIPv6: false, - }, - { - ip: net.ParseIP("172.17.3.0"), - expectIPv6: false, - }, - { - ip: nil, - expectIPv6: false, - }, - { - ip: net.IPv6loopback, - expectIPv6: true, - }, - { - ip: net.IPv6zero, - expectIPv6: true, - }, - { - ip: net.ParseIP("fd00::600d:f00d"), - expectIPv6: true, - }, - { - ip: net.ParseIP("2001:db8::5"), - expectIPv6: true, - }, - } - for i := range testCases { - isIPv6 := IsIPv6(testCases[i].ip) - if isIPv6 != testCases[i].expectIPv6 { - t.Errorf("[%d] Expect ipv6 %v, got %v", i+1, testCases[i].expectIPv6, isIPv6) - } - } -} diff --git a/pkg/util/net/OWNERS b/pkg/util/net/OWNERS new file mode 100644 index 00000000000..064cbc393ef --- /dev/null +++ b/pkg/util/net/OWNERS @@ -0,0 +1,4 @@ +reviewers: + - sig-network-reviewers +approvers: + - sig-network-approvers diff --git a/pkg/util/net/net.go b/pkg/util/net/net.go new file mode 100644 index 00000000000..ea0ae022bb7 --- /dev/null +++ b/pkg/util/net/net.go @@ -0,0 +1,32 @@ +/* +Copyright 2018 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 net + +import ( + "net" +) + +// IsIPv6 returns if netIP is IPv6. +func IsIPv6(netIP net.IP) bool { + return netIP != nil && netIP.To4() == nil +} + +// IsIPv6String returns if ip is IPv6. +func IsIPv6String(ip string) bool { + netIP := net.ParseIP(ip) + return IsIPv6(netIP) +} diff --git a/pkg/util/net/net_test.go b/pkg/util/net/net_test.go new file mode 100644 index 00000000000..a01af105551 --- /dev/null +++ b/pkg/util/net/net_test.go @@ -0,0 +1,118 @@ +/* +Copyright 2018 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 net + +import ( + "net" + "testing" +) + +func TestIsIPv6String(t *testing.T) { + testCases := []struct { + ip string + expectIPv6 bool + }{ + { + ip: "127.0.0.1", + expectIPv6: false, + }, + { + ip: "192.168.0.0", + expectIPv6: false, + }, + { + ip: "1.2.3.4", + expectIPv6: false, + }, + { + ip: "bad ip", + expectIPv6: false, + }, + { + ip: "::1", + expectIPv6: true, + }, + { + ip: "fd00::600d:f00d", + expectIPv6: true, + }, + { + ip: "2001:db8::5", + expectIPv6: true, + }, + } + for i := range testCases { + isIPv6 := IsIPv6String(testCases[i].ip) + if isIPv6 != testCases[i].expectIPv6 { + t.Errorf("[%d] Expect ipv6 %v, got %v", i+1, testCases[i].expectIPv6, isIPv6) + } + } +} + +func TestIsIPv6(t *testing.T) { + testCases := []struct { + ip net.IP + expectIPv6 bool + }{ + { + ip: net.IPv4zero, + expectIPv6: false, + }, + { + ip: net.IPv4bcast, + expectIPv6: false, + }, + { + ip: net.ParseIP("127.0.0.1"), + expectIPv6: false, + }, + { + ip: net.ParseIP("10.20.40.40"), + expectIPv6: false, + }, + { + ip: net.ParseIP("172.17.3.0"), + expectIPv6: false, + }, + { + ip: nil, + expectIPv6: false, + }, + { + ip: net.IPv6loopback, + expectIPv6: true, + }, + { + ip: net.IPv6zero, + expectIPv6: true, + }, + { + ip: net.ParseIP("fd00::600d:f00d"), + expectIPv6: true, + }, + { + ip: net.ParseIP("2001:db8::5"), + expectIPv6: true, + }, + } + for i := range testCases { + isIPv6 := IsIPv6(testCases[i].ip) + if isIPv6 != testCases[i].expectIPv6 { + t.Errorf("[%d] Expect ipv6 %v, got %v", i+1, testCases[i].expectIPv6, isIPv6) + } + } +} From ca032528be510c37e5da8cae6867200424de65fd Mon Sep 17 00:00:00 2001 From: Zihong Zheng Date: Fri, 16 Feb 2018 20:13:40 -0800 Subject: [PATCH 3/8] [kube-proxy] Add more IP version related utils --- pkg/proxy/util/utils.go | 17 ++++ pkg/util/net/net.go | 29 +++++++ pkg/util/net/net_test.go | 168 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) diff --git a/pkg/proxy/util/utils.go b/pkg/proxy/util/utils.go index 93cf26323a1..d766a1d4ebb 100644 --- a/pkg/proxy/util/utils.go +++ b/pkg/proxy/util/utils.go @@ -20,8 +20,10 @@ import ( "fmt" "net" + "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/tools/record" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core/helper" utilnet "k8s.io/kubernetes/pkg/util/net" @@ -129,3 +131,18 @@ func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) } return uniqueAddressList, nil } + +// LogAndEmitIncorrectIPVersionEvent logs and emits incorrect IP version event. +func LogAndEmitIncorrectIPVersionEvent(recorder record.EventRecorder, fieldName, fieldValue, svcNamespace, svcName string, svcUID types.UID) { + errMsg := fmt.Sprintf("%s in %s has incorrect IP version", fieldValue, fieldName) + glog.Errorf("%s (service %s/%s).", errMsg, svcNamespace, svcName) + if recorder != nil { + recorder.Eventf( + &v1.ObjectReference{ + Kind: "Service", + Name: svcName, + Namespace: svcNamespace, + UID: svcUID, + }, v1.EventTypeWarning, "KubeProxyIncorrectIPVersion", errMsg) + } +} diff --git a/pkg/util/net/net.go b/pkg/util/net/net.go index ea0ae022bb7..f838864cf5b 100644 --- a/pkg/util/net/net.go +++ b/pkg/util/net/net.go @@ -30,3 +30,32 @@ func IsIPv6String(ip string) bool { netIP := net.ParseIP(ip) return IsIPv6(netIP) } + +// IsIPv6CIDR returns if cidr is IPv6. +// This assumes cidr is a valid CIDR. +func IsIPv6CIDR(cidr string) bool { + ip, _, _ := net.ParseCIDR(cidr) + return IsIPv6(ip) +} + +// FilterIncorrectIPVersion filters out the incorrect IP version case from a slice of IP strings. +func FilterIncorrectIPVersion(ipStrings []string, isIPv6Mode bool) ([]string, []string) { + return filterWithCondition(ipStrings, isIPv6Mode, IsIPv6String) +} + +// FilterIncorrectCIDRVersion filters out the incorrect IP version case from a slice of CIDR strings. +func FilterIncorrectCIDRVersion(ipStrings []string, isIPv6Mode bool) ([]string, []string) { + return filterWithCondition(ipStrings, isIPv6Mode, IsIPv6CIDR) +} + +func filterWithCondition(strs []string, expectedCondition bool, conditionFunc func(string) bool) ([]string, []string) { + var corrects, incorrects []string + for _, str := range strs { + if conditionFunc(str) != expectedCondition { + incorrects = append(incorrects, str) + } else { + corrects = append(corrects, str) + } + } + return corrects, incorrects +} diff --git a/pkg/util/net/net_test.go b/pkg/util/net/net_test.go index a01af105551..c2d2f30f775 100644 --- a/pkg/util/net/net_test.go +++ b/pkg/util/net/net_test.go @@ -18,6 +18,7 @@ package net import ( "net" + "reflect" "testing" ) @@ -116,3 +117,170 @@ func TestIsIPv6(t *testing.T) { } } } + +func TestIsIPv6CIDR(t *testing.T) { + testCases := []struct { + desc string + cidr string + expectResult bool + }{ + { + desc: "ipv4 CIDR 1", + cidr: "10.0.0.0/8", + expectResult: false, + }, + { + desc: "ipv4 CIDR 2", + cidr: "192.168.0.0/16", + expectResult: false, + }, + { + desc: "ipv6 CIDR 1", + cidr: "::/1", + expectResult: true, + }, + { + desc: "ipv6 CIDR 2", + cidr: "2000::/10", + expectResult: true, + }, + { + desc: "ipv6 CIDR 3", + cidr: "2001:db8::/32", + expectResult: true, + }, + } + + for _, tc := range testCases { + res := IsIPv6CIDR(tc.cidr) + if res != tc.expectResult { + t.Errorf("%v: want IsIPv6CIDR=%v, got %v", tc.desc, tc.expectResult, res) + } + } +} + +func TestFilterIncorrectIPVersion(t *testing.T) { + testCases := []struct { + desc string + isIPv6 bool + ipStrings []string + expectCorrects []string + expectIncorrects []string + }{ + { + desc: "all ipv4 strings in ipv4 mode", + isIPv6: false, + ipStrings: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1"}, + expectCorrects: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1"}, + expectIncorrects: nil, + }, + { + desc: "all ipv6 strings in ipv4 mode", + isIPv6: false, + ipStrings: []string{"::1", "fd00::600d:f00d", "2001:db8::5"}, + expectCorrects: nil, + expectIncorrects: []string{"::1", "fd00::600d:f00d", "2001:db8::5"}, + }, + { + desc: "mixed versions in ipv4 mode", + isIPv6: false, + ipStrings: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1", "::1", "fd00::600d:f00d", "2001:db8::5"}, + expectCorrects: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1"}, + expectIncorrects: []string{"::1", "fd00::600d:f00d", "2001:db8::5"}, + }, + { + desc: "all ipv4 strings in ipv6 mode", + isIPv6: true, + ipStrings: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1"}, + expectCorrects: nil, + expectIncorrects: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1"}, + }, + { + desc: "all ipv6 strings in ipv6 mode", + isIPv6: true, + ipStrings: []string{"::1", "fd00::600d:f00d", "2001:db8::5"}, + expectCorrects: []string{"::1", "fd00::600d:f00d", "2001:db8::5"}, + expectIncorrects: nil, + }, + { + desc: "mixed versions in ipv6 mode", + isIPv6: true, + ipStrings: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1", "::1", "fd00::600d:f00d", "2001:db8::5"}, + expectCorrects: []string{"::1", "fd00::600d:f00d", "2001:db8::5"}, + expectIncorrects: []string{"10.0.0.1", "192.168.0.1", "127.0.0.1"}, + }, + } + + for _, tc := range testCases { + corrects, incorrects := FilterIncorrectIPVersion(tc.ipStrings, tc.isIPv6) + if !reflect.DeepEqual(tc.expectCorrects, corrects) { + t.Errorf("%v: want corrects=%v, got %v", tc.desc, tc.expectCorrects, corrects) + } + if !reflect.DeepEqual(tc.expectIncorrects, incorrects) { + t.Errorf("%v: want incorrects=%v, got %v", tc.desc, tc.expectIncorrects, incorrects) + } + } +} + +func TestFilterIncorrectCIDRVersion(t *testing.T) { + testCases := []struct { + desc string + isIPv6 bool + cidrStrings []string + expectCorrects []string + expectIncorrects []string + }{ + { + desc: "all ipv4 strings in ipv4 mode", + isIPv6: false, + cidrStrings: []string{"0.0.0.0/1", "1.0.0.0/1"}, + expectCorrects: []string{"0.0.0.0/1", "1.0.0.0/1"}, + expectIncorrects: nil, + }, + { + desc: "all ipv6 strings in ipv4 mode", + isIPv6: false, + cidrStrings: []string{"2001:db8::/32", "2001:0db8:0123:4567::/64"}, + expectCorrects: nil, + expectIncorrects: []string{"2001:db8::/32", "2001:0db8:0123:4567::/64"}, + }, + { + desc: "mixed versions in ipv4 mode", + isIPv6: false, + cidrStrings: []string{"0.0.0.0/1", "1.0.0.0/1", "2001:db8::/32", "2001:0db8:0123:4567::/64"}, + expectCorrects: []string{"0.0.0.0/1", "1.0.0.0/1"}, + expectIncorrects: []string{"2001:db8::/32", "2001:0db8:0123:4567::/64"}, + }, + { + desc: "all ipv4 strings in ipv6 mode", + isIPv6: true, + cidrStrings: []string{"0.0.0.0/1", "1.0.0.0/1"}, + expectCorrects: nil, + expectIncorrects: []string{"0.0.0.0/1", "1.0.0.0/1"}, + }, + { + desc: "all ipv6 strings in ipv6 mode", + isIPv6: true, + cidrStrings: []string{"2001:db8::/32", "2001:0db8:0123:4567::/64"}, + expectCorrects: []string{"2001:db8::/32", "2001:0db8:0123:4567::/64"}, + expectIncorrects: nil, + }, + { + desc: "mixed versions in ipv6 mode", + isIPv6: true, + cidrStrings: []string{"0.0.0.0/1", "1.0.0.0/1", "2001:db8::/32", "2001:0db8:0123:4567::/64"}, + expectCorrects: []string{"2001:db8::/32", "2001:0db8:0123:4567::/64"}, + expectIncorrects: []string{"0.0.0.0/1", "1.0.0.0/1"}, + }, + } + + for _, tc := range testCases { + corrects, incorrects := FilterIncorrectCIDRVersion(tc.cidrStrings, tc.isIPv6) + if !reflect.DeepEqual(tc.expectCorrects, corrects) { + t.Errorf("%v: want corrects=%v, got %v", tc.desc, tc.expectCorrects, corrects) + } + if !reflect.DeepEqual(tc.expectIncorrects, incorrects) { + t.Errorf("%v: want incorrects=%v, got %v", tc.desc, tc.expectIncorrects, incorrects) + } + } +} From 2ae45e9f1b57e02a00a3018243cb51d7610ccef4 Mon Sep 17 00:00:00 2001 From: Zihong Zheng Date: Fri, 16 Feb 2018 19:13:14 -0800 Subject: [PATCH 4/8] [kube-proxy] Make the import name of utilproxy consistent --- pkg/proxy/userspace/proxier.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/proxy/userspace/proxier.go b/pkg/proxy/userspace/proxier.go index 7fdf1024db0..3fc49c06426 100644 --- a/pkg/proxy/userspace/proxier.go +++ b/pkg/proxy/userspace/proxier.go @@ -36,7 +36,7 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" - proxyutil "k8s.io/kubernetes/pkg/proxy/util" + utilproxy "k8s.io/kubernetes/pkg/proxy/util" "k8s.io/kubernetes/pkg/util/conntrack" "k8s.io/kubernetes/pkg/util/iptables" utilexec "k8s.io/utils/exec" @@ -588,7 +588,7 @@ func (proxier *Proxier) openPortal(service proxy.ServicePortName, info *ServiceI } func (proxier *Proxier) openOnePortal(portal portal, protocol api.Protocol, proxyIP net.IP, proxyPort int, name proxy.ServicePortName) error { - if local, err := proxyutil.IsLocalIP(portal.ip.String()); err != nil { + if local, err := utilproxy.IsLocalIP(portal.ip.String()); err != nil { return fmt.Errorf("can't determine if IP %s is local, assuming not: %v", portal.ip, err) } else if local { err := proxier.claimNodePort(portal.ip, portal.port, protocol, name) @@ -767,7 +767,7 @@ func (proxier *Proxier) closePortal(service proxy.ServicePortName, info *Service func (proxier *Proxier) closeOnePortal(portal portal, protocol api.Protocol, proxyIP net.IP, proxyPort int, name proxy.ServicePortName) []error { el := []error{} - if local, err := proxyutil.IsLocalIP(portal.ip.String()); err != nil { + if local, err := utilproxy.IsLocalIP(portal.ip.String()); err != nil { el = append(el, fmt.Errorf("can't determine if IP %s is local, assuming not: %v", portal.ip, err)) } else if local { if err := proxier.releaseNodePort(portal.ip, portal.port, protocol, name); err != nil { @@ -967,7 +967,7 @@ func iptablesCommonPortalArgs(destIP net.IP, addPhysicalInterfaceMatch bool, add } if destIP != nil { - args = append(args, "-d", proxyutil.ToCIDR(destIP)) + args = append(args, "-d", utilproxy.ToCIDR(destIP)) } if addPhysicalInterfaceMatch { From 95cde4fb98eb20462c07f673913a9019ff377453 Mon Sep 17 00:00:00 2001 From: Zihong Zheng Date: Fri, 16 Feb 2018 20:15:00 -0800 Subject: [PATCH 5/8] [kube-proxy] Harden change tracker and proxiers for unmatched IP versions --- pkg/proxy/endpoints.go | 8 ++++++++ pkg/proxy/iptables/proxier.go | 2 ++ pkg/proxy/ipvs/proxier.go | 2 ++ pkg/proxy/service.go | 31 +++++++++++++++++++++++++++---- 4 files changed, 39 insertions(+), 4 deletions(-) diff --git a/pkg/proxy/endpoints.go b/pkg/proxy/endpoints.go index 8f1ae4260f0..e2bcde43a72 100644 --- a/pkg/proxy/endpoints.go +++ b/pkg/proxy/endpoints.go @@ -29,6 +29,7 @@ import ( "k8s.io/client-go/tools/record" api "k8s.io/kubernetes/pkg/apis/core" utilproxy "k8s.io/kubernetes/pkg/proxy/util" + utilnet "k8s.io/kubernetes/pkg/util/net" ) // EndpointInfoCommon contains common endpoint information. @@ -206,6 +207,13 @@ func (ect *EndpointChangeTracker) endpointsToEndpointsMap(endpoints *api.Endpoin glog.Warningf("ignoring invalid endpoint port %s with empty host", port.Name) continue } + // Filter out the incorrect IP version case. + if ect.isIPv6Mode != nil && utilnet.IsIPv6String(addr.IP) != *ect.isIPv6Mode { + // Emit event on the corresponding service which had a different + // IP version than the endpoint. + utilproxy.LogAndEmitIncorrectIPVersionEvent(ect.recorder, "endpoints", addr.IP, endpoints.Name, endpoints.Namespace, "") + continue + } isLocal := addr.NodeName != nil && *addr.NodeName == ect.hostname epInfoCommon := newEndpointInfoCommon(addr.IP, int(port.Port), isLocal) if ect.customizeEndpointInfo != nil { diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index 1b7e8ca55c5..03fb477a20f 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -309,6 +309,8 @@ func NewProxier(ipt utiliptables.Interface, if len(clusterCIDR) == 0 { glog.Warningf("clusterCIDR not specified, unable to distinguish between internal and external traffic") + } else if utilnet.IsIPv6CIDR(clusterCIDR) != ipt.IsIpv6() { + return nil, fmt.Errorf("clusterCIDR %s has incorrect IP version: expect isIPv6=%t", clusterCIDR, ipt.IsIpv6()) } healthChecker := healthcheck.NewServer(hostname, recorder, nil, nil) // use default implementations of deps diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index cd561050a1d..6cff2c7bc57 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -296,6 +296,8 @@ func NewProxier(ipt utiliptables.Interface, if len(clusterCIDR) == 0 { glog.Warningf("clusterCIDR not specified, unable to distinguish between internal and external traffic") + } else if utilnet.IsIPv6CIDR(clusterCIDR) != isIPv6 { + return nil, fmt.Errorf("clusterCIDR %s has incorrect IP version: expect isIPv6=%t", clusterCIDR, isIPv6) } if len(scheduler) == 0 { diff --git a/pkg/proxy/service.go b/pkg/proxy/service.go index 515bdaa1303..4421ad32558 100644 --- a/pkg/proxy/service.go +++ b/pkg/proxy/service.go @@ -20,6 +20,7 @@ import ( "fmt" "net" "reflect" + "strings" "sync" "github.com/golang/glog" @@ -31,6 +32,7 @@ import ( api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/apis/core/helper" utilproxy "k8s.io/kubernetes/pkg/proxy/util" + utilnet "k8s.io/kubernetes/pkg/util/net" ) // ServiceInfoCommon contains common service information. @@ -92,10 +94,23 @@ func (sct *ServiceChangeTracker) newServiceInfoCommon(port *api.ServicePort, ser OnlyNodeLocalEndpoints: onlyNodeLocalEndpoints, } - info.ExternalIPs = make([]string, len(service.Spec.ExternalIPs)) - info.LoadBalancerSourceRanges = make([]string, len(service.Spec.LoadBalancerSourceRanges)) - copy(info.LoadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges) - copy(info.ExternalIPs, service.Spec.ExternalIPs) + if sct.isIPv6Mode == nil { + info.ExternalIPs = make([]string, len(service.Spec.ExternalIPs)) + info.LoadBalancerSourceRanges = make([]string, len(service.Spec.LoadBalancerSourceRanges)) + copy(info.LoadBalancerSourceRanges, service.Spec.LoadBalancerSourceRanges) + copy(info.ExternalIPs, service.Spec.ExternalIPs) + } else { + // Filter out the incorrect IP version case. + var incorrectIPs []string + info.ExternalIPs, incorrectIPs = utilnet.FilterIncorrectIPVersion(service.Spec.ExternalIPs, *sct.isIPv6Mode) + if len(incorrectIPs) > 0 { + utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "externalIPs", strings.Join(incorrectIPs, ","), service.Namespace, service.Name, service.UID) + } + info.LoadBalancerSourceRanges, incorrectIPs = utilnet.FilterIncorrectCIDRVersion(service.Spec.LoadBalancerSourceRanges, *sct.isIPv6Mode) + if len(incorrectIPs) > 0 { + utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "loadBalancerSourceRanges", strings.Join(incorrectIPs, ","), service.Namespace, service.Name, service.UID) + } + } if apiservice.NeedsHealthCheck(service) { p := service.Spec.HealthCheckNodePort @@ -221,6 +236,14 @@ func (sct *ServiceChangeTracker) serviceToServiceMap(service *api.Service) Servi return nil } + if len(service.Spec.ClusterIP) != 0 { + // Filter out the incorrect IP version case. + if sct.isIPv6Mode != nil && utilnet.IsIPv6String(service.Spec.ClusterIP) != *sct.isIPv6Mode { + utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "clusterIP", service.Spec.ClusterIP, service.Namespace, service.Name, service.UID) + return nil + } + } + serviceMap := make(ServiceMap) for i := range service.Spec.Ports { servicePort := &service.Spec.Ports[i] From 06064498de75df820596a75a336226db8de6993e Mon Sep 17 00:00:00 2001 From: Zihong Zheng Date: Mon, 19 Feb 2018 17:50:34 -0800 Subject: [PATCH 6/8] [kube-proxy] Unit test for unmatched IP version --- pkg/proxy/endpoints_test.go | 358 ++++++++++++++++++++++-------------- pkg/proxy/service_test.go | 210 +++++++++++++++++++-- 2 files changed, 407 insertions(+), 161 deletions(-) diff --git a/pkg/proxy/endpoints_test.go b/pkg/proxy/endpoints_test.go index 664a804c646..6c1602d4e3e 100644 --- a/pkg/proxy/endpoints_test.go +++ b/pkg/proxy/endpoints_test.go @@ -133,183 +133,259 @@ func makeTestEndpoints(namespace, name string, eptFunc func(*api.Endpoints)) *ap func TestEndpointsToEndpointsMap(t *testing.T) { epTracker := NewEndpointChangeTracker("test-hostname", nil, nil, nil) + trueVal := true + falseVal := false + testCases := []struct { + desc string newEndpoints *api.Endpoints expected map[ServicePortName][]*EndpointInfoCommon - }{{ - // Case[0]: nothing - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) {}), - expected: map[ServicePortName][]*EndpointInfoCommon{}, - }, { - // Case[1]: no changes, unnamed port - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { - ept.Subsets = []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{{ - IP: "1.1.1.1", - }}, - Ports: []api.EndpointPort{{ - Name: "", - Port: 11, - }}, + isIPv6Mode *bool + }{ + { + desc: "nothing", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) {}), + expected: map[ServicePortName][]*EndpointInfoCommon{}, + }, + { + desc: "no changes, unnamed port", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "", + Port: 11, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", ""): { + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, - } - }), - expected: map[ServicePortName][]*EndpointInfoCommon{ - makeServicePortName("ns1", "ep1", ""): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - }, { - // Case[2]: no changes, named port - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { - ept.Subsets = []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{{ - IP: "1.1.1.1", - }}, - Ports: []api.EndpointPort{{ - Name: "port", - Port: 11, - }}, + { + desc: "no changes, named port", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "port", + Port: 11, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", "port"): { + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, - } - }), - expected: map[ServicePortName][]*EndpointInfoCommon{ - makeServicePortName("ns1", "ep1", "port"): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - }, { - // Case[3]: new port - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { - ept.Subsets = []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{{ - IP: "1.1.1.1", - }}, - Ports: []api.EndpointPort{{ - Port: 11, - }}, + { + desc: "new port", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Port: 11, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", ""): { + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, - } - }), - expected: map[ServicePortName][]*EndpointInfoCommon{ - makeServicePortName("ns1", "ep1", ""): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - }, { - // Case[4]: remove port - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) {}), - expected: map[ServicePortName][]*EndpointInfoCommon{}, - }, { - // Case[5]: new IP and port - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { - ept.Subsets = []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{{ - IP: "1.1.1.1", - }, { - IP: "2.2.2.2", - }}, - Ports: []api.EndpointPort{{ - Name: "p1", - Port: 11, - }, { - Name: "p2", - Port: 22, - }}, + { + desc: "remove port", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) {}), + expected: map[ServicePortName][]*EndpointInfoCommon{}, + }, + { + desc: "new IP and port", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }, { + IP: "2.2.2.2", + }}, + Ports: []api.EndpointPort{{ + Name: "p1", + Port: 11, + }, { + Name: "p2", + Port: 22, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", "p1"): { + {Endpoint: "1.1.1.1:11", IsLocal: false}, + {Endpoint: "2.2.2.2:11", IsLocal: false}, + }, + makeServicePortName("ns1", "ep1", "p2"): { + {Endpoint: "1.1.1.1:22", IsLocal: false}, + {Endpoint: "2.2.2.2:22", IsLocal: false}, }, - } - }), - expected: map[ServicePortName][]*EndpointInfoCommon{ - makeServicePortName("ns1", "ep1", "p1"): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, - {Endpoint: "2.2.2.2:11", IsLocal: false}, - }, - makeServicePortName("ns1", "ep1", "p2"): { - {Endpoint: "1.1.1.1:22", IsLocal: false}, - {Endpoint: "2.2.2.2:22", IsLocal: false}, }, }, - }, { - // Case[6]: remove IP and port - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { - ept.Subsets = []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{{ - IP: "1.1.1.1", - }}, - Ports: []api.EndpointPort{{ - Name: "p1", - Port: 11, - }}, + { + desc: "remove IP and port", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p1", + Port: 11, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", "p1"): { + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, - } - }), - expected: map[ServicePortName][]*EndpointInfoCommon{ - makeServicePortName("ns1", "ep1", "p1"): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - }, { - // Case[7]: rename port - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { - ept.Subsets = []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{{ - IP: "1.1.1.1", - }}, - Ports: []api.EndpointPort{{ - Name: "p2", - Port: 11, - }}, + { + desc: "rename port", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p2", + Port: 11, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", "p2"): { + {Endpoint: "1.1.1.1:11", IsLocal: false}, }, - } - }), - expected: map[ServicePortName][]*EndpointInfoCommon{ - makeServicePortName("ns1", "ep1", "p2"): { - {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - }, { - // Case[8]: renumber port - newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { - ept.Subsets = []api.EndpointSubset{ - { - Addresses: []api.EndpointAddress{{ - IP: "1.1.1.1", - }}, - Ports: []api.EndpointPort{{ - Name: "p1", - Port: 22, - }}, + { + desc: "renumber port", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }}, + Ports: []api.EndpointPort{{ + Name: "p1", + Port: 22, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", "p1"): { + {Endpoint: "1.1.1.1:22", IsLocal: false}, }, - } - }), - expected: map[ServicePortName][]*EndpointInfoCommon{ - makeServicePortName("ns1", "ep1", "p1"): { - {Endpoint: "1.1.1.1:22", IsLocal: false}, }, }, - }} + { + desc: "should omit IPv6 address in IPv4 mode", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }, { + IP: "2001:db8:85a3:0:0:8a2e:370:7334", + }}, + Ports: []api.EndpointPort{{ + Name: "p1", + Port: 11, + }, { + Name: "p2", + Port: 22, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", "p1"): { + {Endpoint: "1.1.1.1:11", IsLocal: false}, + }, + makeServicePortName("ns1", "ep1", "p2"): { + {Endpoint: "1.1.1.1:22", IsLocal: false}, + }, + }, + isIPv6Mode: &falseVal, + }, + { + desc: "should omit IPv4 address in IPv6 mode", + newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) { + ept.Subsets = []api.EndpointSubset{ + { + Addresses: []api.EndpointAddress{{ + IP: "1.1.1.1", + }, { + IP: "2001:db8:85a3:0:0:8a2e:370:7334", + }}, + Ports: []api.EndpointPort{{ + Name: "p1", + Port: 11, + }, { + Name: "p2", + Port: 22, + }}, + }, + } + }), + expected: map[ServicePortName][]*EndpointInfoCommon{ + makeServicePortName("ns1", "ep1", "p1"): { + {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:11", IsLocal: false}, + }, + makeServicePortName("ns1", "ep1", "p2"): { + {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:22", IsLocal: false}, + }, + }, + isIPv6Mode: &trueVal, + }, + } - for tci, tc := range testCases { + for _, tc := range testCases { + epTracker.isIPv6Mode = tc.isIPv6Mode // outputs newEndpoints := epTracker.endpointsToEndpointsMap(tc.newEndpoints) if len(newEndpoints) != len(tc.expected) { - t.Errorf("[%d] expected %d new, got %d: %v", tci, len(tc.expected), len(newEndpoints), spew.Sdump(newEndpoints)) + t.Errorf("[%s] expected %d new, got %d: %v", tc.desc, len(tc.expected), len(newEndpoints), spew.Sdump(newEndpoints)) } for x := range tc.expected { if len(newEndpoints[x]) != len(tc.expected[x]) { - t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(tc.expected[x]), x, len(newEndpoints[x])) + t.Errorf("[%s] expected %d endpoints for %v, got %d", tc.desc, len(tc.expected[x]), x, len(newEndpoints[x])) } else { for i := range newEndpoints[x] { ep := newEndpoints[x][i].(*EndpointInfoCommon) if *ep != *(tc.expected[x][i]) { - t.Errorf("[%d] expected new[%v][%d] to be %v, got %v", tci, x, i, tc.expected[x][i], *ep) + t.Errorf("[%s] expected new[%v][%d] to be %v, got %v", tc.desc, x, i, tc.expected[x][i], *ep) } } } diff --git a/pkg/proxy/service_test.go b/pkg/proxy/service_test.go index 0a24b1c0fee..03b85d12d0c 100644 --- a/pkg/proxy/service_test.go +++ b/pkg/proxy/service_test.go @@ -25,12 +25,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/sets" api "k8s.io/kubernetes/pkg/apis/core" ) const testHostname = "test-hostname" -func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int) *ServiceInfoCommon { +func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int, svcInfoFuncs ...func(*ServiceInfoCommon)) *ServiceInfoCommon { info := &ServiceInfoCommon{ ClusterIP: net.ParseIP(clusterIP), Port: port, @@ -39,6 +40,9 @@ func makeTestServiceInfo(clusterIP string, port int, protocol string, healthchec if healthcheckNodePort != 0 { info.HealthCheckNodePort = healthcheckNodePort } + for _, svcInfoFunc := range svcInfoFuncs { + svcInfoFunc(info) + } return info } @@ -81,17 +85,28 @@ func makeServicePortName(ns, name, port string) ServicePortName { func TestServiceToServiceMap(t *testing.T) { svcTracker := NewServiceChangeTracker(nil, nil, nil) + trueVal := true + falseVal := false + testClusterIPv4 := "10.0.0.1" + testExternalIPv4 := "8.8.8.8" + testSourceRangeIPv4 := "0.0.0.0/1" + testClusterIPv6 := "2001:db8:85a3:0:0:8a2e:370:7334" + testExternalIPv6 := "2001:db8:85a3:0:0:8a2e:370:7335" + testSourceRangeIPv6 := "2001:db8::/32" + testCases := []struct { - service *api.Service - expected map[ServicePortName]*ServiceInfoCommon + desc string + service *api.Service + expected map[ServicePortName]*ServiceInfoCommon + isIPv6Mode *bool }{ { - // Case[0]: nothing + desc: "nothing", service: nil, expected: map[ServicePortName]*ServiceInfoCommon{}, }, { - // Case[1]: headless service + desc: "headless service", service: makeTestService("ns2", "headless", func(svc *api.Service) { svc.Spec.Type = api.ServiceTypeClusterIP svc.Spec.ClusterIP = api.ClusterIPNone @@ -100,7 +115,7 @@ func TestServiceToServiceMap(t *testing.T) { expected: map[ServicePortName]*ServiceInfoCommon{}, }, { - // Case[2]: headless service without port + desc: "headless service without port", service: makeTestService("ns2", "headless-without-port", func(svc *api.Service) { svc.Spec.Type = api.ServiceTypeClusterIP svc.Spec.ClusterIP = api.ClusterIPNone @@ -108,7 +123,7 @@ func TestServiceToServiceMap(t *testing.T) { expected: map[ServicePortName]*ServiceInfoCommon{}, }, { - // Case[3]: cluster ip service + desc: "cluster ip service", service: makeTestService("ns2", "cluster-ip", func(svc *api.Service) { svc.Spec.Type = api.ServiceTypeClusterIP svc.Spec.ClusterIP = "172.16.55.4" @@ -121,7 +136,7 @@ func TestServiceToServiceMap(t *testing.T) { }, }, { - // Case[4]: nodeport service + desc: "nodeport service", service: makeTestService("ns2", "node-port", func(svc *api.Service) { svc.Spec.Type = api.ServiceTypeNodePort svc.Spec.ClusterIP = "172.16.55.10" @@ -134,7 +149,7 @@ func TestServiceToServiceMap(t *testing.T) { }, }, { - // Case[5]: load balancer service + desc: "load balancer service", service: makeTestService("ns1", "load-balancer", func(svc *api.Service) { svc.Spec.Type = api.ServiceTypeLoadBalancer svc.Spec.ClusterIP = "172.16.55.11" @@ -153,7 +168,7 @@ func TestServiceToServiceMap(t *testing.T) { }, }, { - // Case[6]: load balancer service with only local traffic policy + desc: "load balancer service with only local traffic policy", service: makeTestService("ns1", "only-local-load-balancer", func(svc *api.Service) { svc.Spec.Type = api.ServiceTypeLoadBalancer svc.Spec.ClusterIP = "172.16.55.12" @@ -174,7 +189,7 @@ func TestServiceToServiceMap(t *testing.T) { }, }, { - // Case[7]: external name service + desc: "external name service", service: makeTestService("ns2", "external-name", func(svc *api.Service) { svc.Spec.Type = api.ServiceTypeExternalName svc.Spec.ClusterIP = "172.16.55.4" // Should be ignored @@ -183,22 +198,177 @@ func TestServiceToServiceMap(t *testing.T) { }), expected: map[ServicePortName]*ServiceInfoCommon{}, }, + { + desc: "service with ipv6 clusterIP under ipv4 mode, service should be filtered", + service: &api.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "invalidIPv6InIPV4Mode", + Namespace: "test", + }, + Spec: api.ServiceSpec{ + ClusterIP: testClusterIPv6, + Ports: []api.ServicePort{ + { + Name: "testPort", + Port: int32(12345), + Protocol: api.ProtocolTCP, + }, + }, + }, + }, + isIPv6Mode: &falseVal, + }, + { + desc: "service with ipv4 clusterIP under ipv6 mode, service should be filtered", + service: &api.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "invalidIPv4InIPV6Mode", + Namespace: "test", + }, + Spec: api.ServiceSpec{ + ClusterIP: testClusterIPv4, + Ports: []api.ServicePort{ + { + Name: "testPort", + Port: int32(12345), + Protocol: api.ProtocolTCP, + }, + }, + }, + }, + isIPv6Mode: &trueVal, + }, + { + desc: "service with ipv4 configurations under ipv4 mode", + service: &api.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "validIPv4", + Namespace: "test", + }, + Spec: api.ServiceSpec{ + ClusterIP: testClusterIPv4, + ExternalIPs: []string{testExternalIPv4}, + LoadBalancerSourceRanges: []string{testSourceRangeIPv4}, + Ports: []api.ServicePort{ + { + Name: "testPort", + Port: int32(12345), + Protocol: api.ProtocolTCP, + }, + }, + }, + }, + expected: map[ServicePortName]*ServiceInfoCommon{ + makeServicePortName("test", "validIPv4", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *ServiceInfoCommon) { + info.ExternalIPs = []string{testExternalIPv4} + info.LoadBalancerSourceRanges = []string{testSourceRangeIPv4} + }), + }, + isIPv6Mode: &falseVal, + }, + { + desc: "service with ipv6 configurations under ipv6 mode", + service: &api.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "validIPv6", + Namespace: "test", + }, + Spec: api.ServiceSpec{ + ClusterIP: testClusterIPv6, + ExternalIPs: []string{testExternalIPv6}, + LoadBalancerSourceRanges: []string{testSourceRangeIPv6}, + Ports: []api.ServicePort{ + { + Name: "testPort", + Port: int32(12345), + Protocol: api.ProtocolTCP, + }, + }, + }, + }, + expected: map[ServicePortName]*ServiceInfoCommon{ + makeServicePortName("test", "validIPv6", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *ServiceInfoCommon) { + info.ExternalIPs = []string{testExternalIPv6} + info.LoadBalancerSourceRanges = []string{testSourceRangeIPv6} + }), + }, + isIPv6Mode: &trueVal, + }, + { + desc: "service with both ipv4 and ipv6 configurations under ipv4 mode, ipv6 fields should be filtered", + service: &api.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "filterIPv6InIPV4Mode", + Namespace: "test", + }, + Spec: api.ServiceSpec{ + ClusterIP: testClusterIPv4, + ExternalIPs: []string{testExternalIPv4, testExternalIPv6}, + LoadBalancerSourceRanges: []string{testSourceRangeIPv4, testSourceRangeIPv6}, + Ports: []api.ServicePort{ + { + Name: "testPort", + Port: int32(12345), + Protocol: api.ProtocolTCP, + }, + }, + }, + }, + expected: map[ServicePortName]*ServiceInfoCommon{ + makeServicePortName("test", "filterIPv6InIPV4Mode", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *ServiceInfoCommon) { + info.ExternalIPs = []string{testExternalIPv4} + info.LoadBalancerSourceRanges = []string{testSourceRangeIPv4} + }), + }, + isIPv6Mode: &falseVal, + }, + { + desc: "service with both ipv4 and ipv6 configurations under ipv6 mode, ipv4 fields should be filtered", + service: &api.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "filterIPv4InIPV6Mode", + Namespace: "test", + }, + Spec: api.ServiceSpec{ + ClusterIP: testClusterIPv6, + ExternalIPs: []string{testExternalIPv4, testExternalIPv6}, + LoadBalancerSourceRanges: []string{testSourceRangeIPv4, testSourceRangeIPv6}, + Ports: []api.ServicePort{ + { + Name: "testPort", + Port: int32(12345), + Protocol: api.ProtocolTCP, + }, + }, + }, + }, + expected: map[ServicePortName]*ServiceInfoCommon{ + makeServicePortName("test", "filterIPv4InIPV6Mode", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *ServiceInfoCommon) { + info.ExternalIPs = []string{testExternalIPv6} + info.LoadBalancerSourceRanges = []string{testSourceRangeIPv6} + }), + }, + isIPv6Mode: &trueVal, + }, } - for tci, tc := range testCases { + for _, tc := range testCases { + svcTracker.isIPv6Mode = tc.isIPv6Mode // outputs newServices := svcTracker.serviceToServiceMap(tc.service) if len(newServices) != len(tc.expected) { - t.Errorf("[%d] expected %d new, got %d: %v", tci, len(tc.expected), len(newServices), spew.Sdump(newServices)) + t.Errorf("[%s] expected %d new, got %d: %v", tc.desc, len(tc.expected), len(newServices), spew.Sdump(newServices)) } - for x := range tc.expected { - svcInfo := newServices[x].(*ServiceInfoCommon) - if !svcInfo.ClusterIP.Equal(tc.expected[x].ClusterIP) || - svcInfo.Port != tc.expected[x].Port || - svcInfo.Protocol != tc.expected[x].Protocol || - svcInfo.HealthCheckNodePort != tc.expected[x].HealthCheckNodePort { - t.Errorf("[%d] expected new[%v]to be %v, got %v", tci, x, tc.expected[x], *svcInfo) + for svcKey, expectedInfo := range tc.expected { + svcInfo := newServices[svcKey].(*ServiceInfoCommon) + if !svcInfo.ClusterIP.Equal(expectedInfo.ClusterIP) || + svcInfo.Port != expectedInfo.Port || + svcInfo.Protocol != expectedInfo.Protocol || + svcInfo.HealthCheckNodePort != expectedInfo.HealthCheckNodePort || + !sets.NewString(svcInfo.ExternalIPs...).Equal(sets.NewString(expectedInfo.ExternalIPs...)) || + !sets.NewString(svcInfo.LoadBalancerSourceRanges...).Equal(sets.NewString(expectedInfo.LoadBalancerSourceRanges...)) { + t.Errorf("[%s] expected new[%v]to be %v, got %v", tc.desc, svcKey, expectedInfo, *svcInfo) } } } From f6eed81f211d929592ddb236535f306a277ff372 Mon Sep 17 00:00:00 2001 From: Zihong Zheng Date: Sat, 24 Feb 2018 13:32:55 -0800 Subject: [PATCH 7/8] [kube-proxy] Mass service/endpoint info functions rename and comments --- pkg/proxy/endpoints.go | 54 +++++----- pkg/proxy/endpoints_test.go | 124 +++++++++++------------ pkg/proxy/iptables/proxier.go | 41 ++++---- pkg/proxy/iptables/proxier_test.go | 154 ++++++++++++++--------------- pkg/proxy/ipvs/proxier.go | 34 +++---- pkg/proxy/ipvs/proxier_test.go | 76 +++++++------- pkg/proxy/service.go | 52 +++++----- pkg/proxy/service_test.go | 40 ++++---- pkg/proxy/types.go | 4 +- 9 files changed, 287 insertions(+), 292 deletions(-) diff --git a/pkg/proxy/endpoints.go b/pkg/proxy/endpoints.go index e2bcde43a72..36f53c98996 100644 --- a/pkg/proxy/endpoints.go +++ b/pkg/proxy/endpoints.go @@ -32,48 +32,51 @@ import ( utilnet "k8s.io/kubernetes/pkg/util/net" ) -// EndpointInfoCommon contains common endpoint information. -type EndpointInfoCommon struct { +// BaseEndpointInfo contains base information that defines an endpoint. +// This could be used directly by proxier while processing endpoints, +// or can be used for constructing a more specific EndpointInfo struct +// defined by the proxier if needed. +type BaseEndpointInfo struct { Endpoint string // TODO: should be an endpointString type // IsLocal indicates whether the endpoint is running in same host as kube-proxy. IsLocal bool } -var _ Endpoint = &EndpointInfoCommon{} +var _ Endpoint = &BaseEndpointInfo{} // String is part of proxy.Endpoint interface. -func (info *EndpointInfoCommon) String() string { +func (info *BaseEndpointInfo) String() string { return info.Endpoint } -// IsLocal is part of proxy.Endpoint interface. -func (info *EndpointInfoCommon) GetIsLocal() bool { +// GetIsLocal is part of proxy.Endpoint interface. +func (info *BaseEndpointInfo) GetIsLocal() bool { return info.IsLocal } // IP returns just the IP part of the endpoint, it's a part of proxy.Endpoint interface. -func (info *EndpointInfoCommon) IP() string { +func (info *BaseEndpointInfo) IP() string { return utilproxy.IPPart(info.Endpoint) } // Port returns just the Port part of the endpoint. -func (info *EndpointInfoCommon) Port() (int, error) { +func (info *BaseEndpointInfo) Port() (int, error) { return utilproxy.PortPart(info.Endpoint) } // Equal is part of proxy.Endpoint interface. -func (info *EndpointInfoCommon) Equal(other Endpoint) bool { +func (info *BaseEndpointInfo) Equal(other Endpoint) bool { return info.String() == other.String() && info.GetIsLocal() == other.GetIsLocal() } -func newEndpointInfoCommon(IP string, port int, isLocal bool) *EndpointInfoCommon { - return &EndpointInfoCommon{ +func newBaseEndpointInfo(IP string, port int, isLocal bool) *BaseEndpointInfo { + return &BaseEndpointInfo{ Endpoint: net.JoinHostPort(IP, strconv.Itoa(port)), IsLocal: isLocal, } } -type customizeEndpointInfoFunc func(IP string, port int, isLocal bool, info *EndpointInfoCommon) Endpoint +type makeEndpointFunc func(info *BaseEndpointInfo) Endpoint // EndpointChangeTracker carries state about uncommitted changes to an arbitrary number of // Endpoints, keyed by their namespace and name. @@ -84,21 +87,21 @@ type EndpointChangeTracker struct { hostname string // items maps a service to is endpointsChange. items map[types.NamespacedName]*endpointsChange - // customizeEndpointInfo allows proxier to inject customized infomation when processing endpoint. - customizeEndpointInfo customizeEndpointInfoFunc + // makeEndpointInfo allows proxier to inject customized information when processing endpoint. + makeEndpointInfo makeEndpointFunc // isIPv6Mode indicates if change tracker is under IPv6/IPv4 mode. Nil means not applicable. isIPv6Mode *bool recorder record.EventRecorder } // NewEndpointChangeTracker initializes an EndpointsChangeMap -func NewEndpointChangeTracker(hostname string, customizeEndpointInfo customizeEndpointInfoFunc, isIPv6Mode *bool, recorder record.EventRecorder) *EndpointChangeTracker { +func NewEndpointChangeTracker(hostname string, makeEndpointInfo makeEndpointFunc, isIPv6Mode *bool, recorder record.EventRecorder) *EndpointChangeTracker { return &EndpointChangeTracker{ - hostname: hostname, - items: make(map[types.NamespacedName]*endpointsChange), - customizeEndpointInfo: customizeEndpointInfo, - isIPv6Mode: isIPv6Mode, - recorder: recorder, + hostname: hostname, + items: make(map[types.NamespacedName]*endpointsChange), + makeEndpointInfo: makeEndpointInfo, + isIPv6Mode: isIPv6Mode, + recorder: recorder, } } @@ -174,7 +177,7 @@ func UpdateEndpointsMap(endpointsMap EndpointsMap, changes *EndpointChangeTracke return result } -// EndpointsMap maps a service to one of its Endpoint. +// EndpointsMap maps a service name to a list of all its Endpoints. type EndpointsMap map[ServicePortName][]Endpoint // endpointsToEndpointsMap translates single Endpoints object to EndpointsMap. @@ -208,6 +211,7 @@ func (ect *EndpointChangeTracker) endpointsToEndpointsMap(endpoints *api.Endpoin continue } // Filter out the incorrect IP version case. + // Any endpoint port that contains incorrect IP version will be ignored. if ect.isIPv6Mode != nil && utilnet.IsIPv6String(addr.IP) != *ect.isIPv6Mode { // Emit event on the corresponding service which had a different // IP version than the endpoint. @@ -215,11 +219,11 @@ func (ect *EndpointChangeTracker) endpointsToEndpointsMap(endpoints *api.Endpoin continue } isLocal := addr.NodeName != nil && *addr.NodeName == ect.hostname - epInfoCommon := newEndpointInfoCommon(addr.IP, int(port.Port), isLocal) - if ect.customizeEndpointInfo != nil { - endpointsMap[svcPortName] = append(endpointsMap[svcPortName], ect.customizeEndpointInfo(addr.IP, int(port.Port), isLocal, epInfoCommon)) + baseEndpointInfo := newBaseEndpointInfo(addr.IP, int(port.Port), isLocal) + if ect.makeEndpointInfo != nil { + endpointsMap[svcPortName] = append(endpointsMap[svcPortName], ect.makeEndpointInfo(baseEndpointInfo)) } else { - endpointsMap[svcPortName] = append(endpointsMap[svcPortName], epInfoCommon) + endpointsMap[svcPortName] = append(endpointsMap[svcPortName], baseEndpointInfo) } } if glog.V(3) { diff --git a/pkg/proxy/endpoints_test.go b/pkg/proxy/endpoints_test.go index 6c1602d4e3e..c04f3aa4986 100644 --- a/pkg/proxy/endpoints_test.go +++ b/pkg/proxy/endpoints_test.go @@ -52,7 +52,7 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[1]: unnamed port endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", ""): []Endpoint{ - &EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, expected: map[types.NamespacedName]sets.String{}, @@ -60,7 +60,7 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[2]: unnamed port local endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", ""): []Endpoint{ - &EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -70,12 +70,12 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[3]: named local and non-local ports for the same IP. endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", "p11"): []Endpoint{ - &EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}, - &EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}, }, makeServicePortName("ns1", "ep1", "p12"): []Endpoint{ - &EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}, - &EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -85,21 +85,21 @@ func TestGetLocalEndpointIPs(t *testing.T) { // Case[4]: named local and non-local ports for different IPs. endpointsMap: EndpointsMap{ makeServicePortName("ns1", "ep1", "p11"): []Endpoint{ - &EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}, }, makeServicePortName("ns2", "ep2", "p22"): []Endpoint{ - &EndpointInfoCommon{Endpoint: "2.2.2.2:22", IsLocal: true}, - &EndpointInfoCommon{Endpoint: "2.2.2.22:22", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true}, }, makeServicePortName("ns2", "ep2", "p23"): []Endpoint{ - &EndpointInfoCommon{Endpoint: "2.2.2.3:23", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true}, }, makeServicePortName("ns4", "ep4", "p44"): []Endpoint{ - &EndpointInfoCommon{Endpoint: "4.4.4.4:44", IsLocal: true}, - &EndpointInfoCommon{Endpoint: "4.4.4.5:44", IsLocal: false}, + &BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: false}, }, makeServicePortName("ns4", "ep4", "p45"): []Endpoint{ - &EndpointInfoCommon{Endpoint: "4.4.4.6:45", IsLocal: true}, + &BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true}, }, }, expected: map[types.NamespacedName]sets.String{ @@ -139,13 +139,13 @@ func TestEndpointsToEndpointsMap(t *testing.T) { testCases := []struct { desc string newEndpoints *api.Endpoints - expected map[ServicePortName][]*EndpointInfoCommon + expected map[ServicePortName][]*BaseEndpointInfo isIPv6Mode *bool }{ { desc: "nothing", newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) {}), - expected: map[ServicePortName][]*EndpointInfoCommon{}, + expected: map[ServicePortName][]*BaseEndpointInfo{}, }, { desc: "no changes, unnamed port", @@ -162,7 +162,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -183,7 +183,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "port"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -203,7 +203,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -212,7 +212,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { { desc: "remove port", newEndpoints: makeTestEndpoints("ns1", "ep1", func(ept *api.Endpoints) {}), - expected: map[ServicePortName][]*EndpointInfoCommon{}, + expected: map[ServicePortName][]*BaseEndpointInfo{}, }, { desc: "new IP and port", @@ -234,7 +234,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "2.2.2.2:11", IsLocal: false}, @@ -260,7 +260,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -281,7 +281,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p2"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -302,7 +302,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1"): { {Endpoint: "1.1.1.1:22", IsLocal: false}, }, @@ -328,7 +328,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -358,7 +358,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { }, } }), - expected: map[ServicePortName][]*EndpointInfoCommon{ + expected: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p1"): { {Endpoint: "[2001:db8:85a3:0:0:8a2e:370:7334]:11", IsLocal: false}, }, @@ -383,7 +383,7 @@ func TestEndpointsToEndpointsMap(t *testing.T) { t.Errorf("[%s] expected %d endpoints for %v, got %d", tc.desc, len(tc.expected[x]), x, len(newEndpoints[x])) } else { for i := range newEndpoints[x] { - ep := newEndpoints[x][i].(*EndpointInfoCommon) + ep := newEndpoints[x][i].(*BaseEndpointInfo) if *ep != *(tc.expected[x][i]) { t.Errorf("[%s] expected new[%v][%d] to be %v, got %v", tc.desc, x, i, tc.expected[x][i], *ep) } @@ -705,15 +705,15 @@ func TestUpdateEndpointsMap(t *testing.T) { // or non-nil) and must be of equal length. previousEndpoints []*api.Endpoints currentEndpoints []*api.Endpoints - oldEndpoints map[ServicePortName][]*EndpointInfoCommon - expectedResult map[ServicePortName][]*EndpointInfoCommon + oldEndpoints map[ServicePortName][]*BaseEndpointInfo + expectedResult map[ServicePortName][]*BaseEndpointInfo expectedStaleEndpoints []ServiceEndpoint expectedStaleServiceNames map[ServicePortName]bool expectedHealthchecks map[types.NamespacedName]int }{{ // Case[0]: nothing - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{}, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{}, + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{}, + expectedResult: map[ServicePortName][]*BaseEndpointInfo{}, expectedStaleEndpoints: []ServiceEndpoint{}, expectedStaleServiceNames: map[ServicePortName]bool{}, expectedHealthchecks: map[types.NamespacedName]int{}, @@ -725,12 +725,12 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPort), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -746,12 +746,12 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortLocal), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, @@ -769,7 +769,7 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsets), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -777,7 +777,7 @@ func TestUpdateEndpointsMap(t *testing.T) { {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -796,7 +796,7 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, @@ -807,7 +807,7 @@ func TestUpdateEndpointsMap(t *testing.T) { {Endpoint: "1.1.1.3:13", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, @@ -833,7 +833,7 @@ func TestUpdateEndpointsMap(t *testing.T) { makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1), makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.2:11", IsLocal: true}, @@ -859,7 +859,7 @@ func TestUpdateEndpointsMap(t *testing.T) { {Endpoint: "2.2.2.2:22", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.2:11", IsLocal: true}, @@ -899,8 +899,8 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPortLocal), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{}, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{}, + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, @@ -920,12 +920,12 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ nil, }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{}, + expectedResult: map[ServicePortName][]*BaseEndpointInfo{}, expectedStaleEndpoints: []ServiceEndpoint{{ Endpoint: "1.1.1.1:11", ServicePortName: makeServicePortName("ns1", "ep1", ""), @@ -940,12 +940,12 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.2:11", IsLocal: true}, @@ -970,7 +970,7 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPort), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.2:11", IsLocal: true}, @@ -980,7 +980,7 @@ func TestUpdateEndpointsMap(t *testing.T) { {Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1005,12 +1005,12 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsetsWithLocal), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1033,7 +1033,7 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPort), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1041,7 +1041,7 @@ func TestUpdateEndpointsMap(t *testing.T) { {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1060,12 +1060,12 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortRenamed), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11-2"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1086,12 +1086,12 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortRenumbered), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:22", IsLocal: false}, }, @@ -1116,7 +1116,7 @@ func TestUpdateEndpointsMap(t *testing.T) { makeTestEndpoints("ns3", "ep3", complexAfter3), makeTestEndpoints("ns4", "ep4", complexAfter4), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1135,7 +1135,7 @@ func TestUpdateEndpointsMap(t *testing.T) { {Endpoint: "4.4.4.6:45", IsLocal: true}, }, }, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.11:11", IsLocal: false}, @@ -1185,8 +1185,8 @@ func TestUpdateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPort), }, - oldEndpoints: map[ServicePortName][]*EndpointInfoCommon{}, - expectedResult: map[ServicePortName][]*EndpointInfoCommon{ + oldEndpoints: map[ServicePortName][]*BaseEndpointInfo{}, + expectedResult: map[ServicePortName][]*BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1268,7 +1268,7 @@ func TestUpdateEndpointsMap(t *testing.T) { } } -func compareEndpointsMaps(t *testing.T, tci int, newMap EndpointsMap, expected map[ServicePortName][]*EndpointInfoCommon) { +func compareEndpointsMaps(t *testing.T, tci int, newMap EndpointsMap, expected map[ServicePortName][]*BaseEndpointInfo) { if len(newMap) != len(expected) { t.Errorf("[%d] expected %d results, got %d: %v", tci, len(expected), len(newMap), newMap) } @@ -1277,7 +1277,7 @@ func compareEndpointsMaps(t *testing.T, tci int, newMap EndpointsMap, expected m t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(expected[x]), x, len(newMap[x])) } else { for i := range expected[x] { - newEp, ok := newMap[x][i].(*EndpointInfoCommon) + newEp, ok := newMap[x][i].(*BaseEndpointInfo) if !ok { t.Errorf("Failed to cast endpointsInfo") continue diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index 03fb477a20f..4b57e044065 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -140,7 +140,7 @@ const sysctlBridgeCallIPTables = "net/bridge/bridge-nf-call-iptables" // internal struct for string service information type serviceInfo struct { - *proxy.ServiceInfoCommon + *proxy.BaseServiceInfo // The following fields are computed and stored for performance reasons. serviceNameString string servicePortChainName utiliptables.Chain @@ -149,8 +149,8 @@ type serviceInfo struct { } // returns a new proxy.ServicePort which abstracts a serviceInfo -func customizeServiceInfo(port *api.ServicePort, service *api.Service, infoCommon *proxy.ServiceInfoCommon) proxy.ServicePort { - info := &serviceInfo{ServiceInfoCommon: infoCommon} +func newServiceInfo(port *api.ServicePort, service *api.Service, baseInfo *proxy.BaseServiceInfo) proxy.ServicePort { + info := &serviceInfo{BaseServiceInfo: baseInfo} // Store the following for performance reasons. svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} @@ -166,7 +166,7 @@ func customizeServiceInfo(port *api.ServicePort, service *api.Service, infoCommo // internal struct for endpoints information type endpointsInfo struct { - *proxy.EndpointInfoCommon + *proxy.BaseEndpointInfo // The following fields we lazily compute and store here for performance // reasons. If the protocol is the same as you expect it to be, then the // chainName can be reused, otherwise it should be recomputed. @@ -175,11 +175,11 @@ type endpointsInfo struct { } // returns a new proxy.Endpoint which abstracts a endpointsInfo -func customizeEndpointInfo(IP string, port int, isLocal bool, infoCommon *proxy.EndpointInfoCommon) proxy.Endpoint { - return &endpointsInfo{EndpointInfoCommon: infoCommon} +func newEndpointInfo(baseInfo *proxy.BaseEndpointInfo) proxy.Endpoint { + return &endpointsInfo{BaseEndpointInfo: baseInfo} } -// Equal overrides the Equal() function imlemented by proxy.EndpointInfoCommon. +// Equal overrides the Equal() function imlemented by proxy.BaseEndpointInfo. func (e *endpointsInfo) Equal(other proxy.Endpoint) bool { o, ok := other.(*endpointsInfo) if !ok { @@ -319,9 +319,9 @@ func NewProxier(ipt utiliptables.Interface, proxier := &Proxier{ portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable), serviceMap: make(proxy.ServiceMap), - serviceChanges: proxy.NewServiceChangeTracker(customizeServiceInfo, &isIPv6, recorder), + serviceChanges: proxy.NewServiceChangeTracker(newServiceInfo, &isIPv6, recorder), endpointsMap: make(proxy.EndpointsMap), - endpointsChanges: proxy.NewEndpointChangeTracker(hostname, customizeEndpointInfo, &isIPv6, recorder), + endpointsChanges: proxy.NewEndpointChangeTracker(hostname, newEndpointInfo, &isIPv6, recorder), iptables: ipt, masqueradeAll: masqueradeAll, masqueradeMark: masqueradeMark, @@ -502,9 +502,7 @@ func (proxier *Proxier) isInitialized() bool { } func (proxier *Proxier) OnServiceAdd(service *api.Service) { - if proxier.serviceChanges.Update(nil, service) && proxier.isInitialized() { - proxier.syncRunner.Run() - } + proxier.OnServiceUpdate(nil, service) } func (proxier *Proxier) OnServiceUpdate(oldService, service *api.Service) { @@ -514,9 +512,8 @@ func (proxier *Proxier) OnServiceUpdate(oldService, service *api.Service) { } func (proxier *Proxier) OnServiceDelete(service *api.Service) { - if proxier.serviceChanges.Update(service, nil) && proxier.isInitialized() { - proxier.syncRunner.Run() - } + proxier.OnServiceUpdate(service, nil) + } func (proxier *Proxier) OnServiceSynced() { @@ -530,9 +527,7 @@ func (proxier *Proxier) OnServiceSynced() { } func (proxier *Proxier) OnEndpointsAdd(endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(nil, endpoints) && proxier.isInitialized() { - proxier.syncRunner.Run() - } + proxier.OnEndpointsUpdate(nil, endpoints) } func (proxier *Proxier) OnEndpointsUpdate(oldEndpoints, endpoints *api.Endpoints) { @@ -542,9 +537,7 @@ func (proxier *Proxier) OnEndpointsUpdate(oldEndpoints, endpoints *api.Endpoints } func (proxier *Proxier) OnEndpointsDelete(endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(endpoints, nil) && proxier.isInitialized() { - proxier.syncRunner.Run() - } + proxier.OnEndpointsUpdate(endpoints, nil) } func (proxier *Proxier) OnEndpointsSynced() { @@ -605,7 +598,7 @@ func (proxier *Proxier) deleteEndpointConnections(connectionMap []proxy.ServiceE for _, epSvcPair := range connectionMap { if svcInfo, ok := proxier.serviceMap[epSvcPair.ServicePortName]; ok && svcInfo.GetProtocol() == api.ProtocolUDP { endpointIP := utilproxy.IPPart(epSvcPair.Endpoint) - err := conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.GetClusterIP(), endpointIP, v1.ProtocolUDP) + err := conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.ClusterIPString(), endpointIP, v1.ProtocolUDP) if err != nil { glog.Errorf("Failed to delete %s endpoint connections, error: %v", epSvcPair.ServicePortName.String(), err) } @@ -641,8 +634,8 @@ func (proxier *Proxier) syncProxyRules() { // merge stale services gathered from updateEndpointsMap for _, svcPortName := range endpointUpdateResult.StaleServiceNames { if svcInfo, ok := proxier.serviceMap[svcPortName]; ok && svcInfo != nil && svcInfo.GetProtocol() == api.ProtocolUDP { - glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.GetClusterIP()) - staleServices.Insert(svcInfo.GetClusterIP()) + glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.ClusterIPString()) + staleServices.Insert(svcInfo.ClusterIPString()) } } diff --git a/pkg/proxy/iptables/proxier_test.go b/pkg/proxy/iptables/proxier_test.go index 734e5bde4f3..65be9536ee8 100644 --- a/pkg/proxy/iptables/proxier_test.go +++ b/pkg/proxy/iptables/proxier_test.go @@ -179,7 +179,7 @@ func TestGetChainLinesMultipleTables(t *testing.T) { func newFakeServiceInfo(service proxy.ServicePortName, ip net.IP, port int, protocol api.Protocol, onlyNodeLocalEndpoints bool) *serviceInfo { return &serviceInfo{ - ServiceInfoCommon: &proxy.ServiceInfoCommon{ + BaseServiceInfo: &proxy.BaseServiceInfo{ SessionAffinityType: api.ServiceAffinityNone, // default StickyMaxAgeSeconds: int(api.DefaultClientIPServiceAffinitySeconds), // default ClusterIP: ip, @@ -393,9 +393,9 @@ func NewFakeProxier(ipt utiliptables.Interface) *Proxier { p := &Proxier{ exec: &fakeexec.FakeExec{}, serviceMap: make(proxy.ServiceMap), - serviceChanges: proxy.NewServiceChangeTracker(customizeServiceInfo, nil, nil), + serviceChanges: proxy.NewServiceChangeTracker(newServiceInfo, nil, nil), endpointsMap: make(proxy.EndpointsMap), - endpointsChanges: proxy.NewEndpointChangeTracker(testHostname, customizeEndpointInfo, nil, nil), + endpointsChanges: proxy.NewEndpointChangeTracker(testHostname, newEndpointInfo, nil, nil), iptables: ipt, clusterCIDR: "10.0.0.0/24", hostname: testHostname, @@ -1726,12 +1726,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1747,12 +1747,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1770,18 +1770,18 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1797,24 +1797,24 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p13"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:13", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p13"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:13", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1834,54 +1834,54 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p13"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:13", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.4:13", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:13", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p14"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:14", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.4:14", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:14", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:14", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p21"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.1:21", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:21", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:21", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:21", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p22"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.1:22", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:22", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:22", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p13"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:13", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.4:13", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:13", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:13", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p14"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.3:14", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.4:14", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.3:14", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.4:14", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p21"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.1:21", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:21", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:21", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:21", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p22"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.1:22", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:22", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.1:22", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1901,7 +1901,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1921,7 +1921,7 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{}, @@ -1941,17 +1941,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -1971,17 +1971,17 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:11", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:11", IsLocal: true}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:12", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2006,15 +2006,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, @@ -2034,15 +2034,15 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2061,12 +2061,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11-2"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2087,12 +2087,12 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:22", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:22", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2117,39 +2117,39 @@ func Test_updateEndpointsMap(t *testing.T) { }, oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, makeServicePortName("ns2", "ep2", "p22"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.2:22", IsLocal: true}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.22:22", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.2:22", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.22:22", IsLocal: true}}, }, makeServicePortName("ns2", "ep2", "p23"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "2.2.2.3:23", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "2.2.2.3:23", IsLocal: true}}, }, makeServicePortName("ns4", "ep4", "p44"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "4.4.4.4:44", IsLocal: true}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "4.4.4.5:44", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.5:44", IsLocal: true}}, }, makeServicePortName("ns4", "ep4", "p45"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "4.4.4.6:45", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.6:45", IsLocal: true}}, }, }, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", "p11"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.11:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.11:11", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p12"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:12", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:12", IsLocal: false}}, }, makeServicePortName("ns1", "ep1", "p122"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.2:122", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.2:122", IsLocal: false}}, }, makeServicePortName("ns3", "ep3", "p33"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "3.3.3.3:33", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "3.3.3.3:33", IsLocal: false}}, }, makeServicePortName("ns4", "ep4", "p44"): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "4.4.4.4:44", IsLocal: true}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "4.4.4.4:44", IsLocal: true}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ @@ -2187,7 +2187,7 @@ func Test_updateEndpointsMap(t *testing.T) { oldEndpoints: map[proxy.ServicePortName][]*endpointsInfo{}, expectedResult: map[proxy.ServicePortName][]*endpointsInfo{ makeServicePortName("ns1", "ep1", ""): { - {EndpointInfoCommon: &proxy.EndpointInfoCommon{Endpoint: "1.1.1.1:11", IsLocal: false}}, + {BaseEndpointInfo: &proxy.BaseEndpointInfo{Endpoint: "1.1.1.1:11", IsLocal: false}}, }, }, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, diff --git a/pkg/proxy/ipvs/proxier.go b/pkg/proxy/ipvs/proxier.go index 6cff2c7bc57..7f0e7630fdb 100644 --- a/pkg/proxy/ipvs/proxier.go +++ b/pkg/proxy/ipvs/proxier.go @@ -310,7 +310,7 @@ func NewProxier(ipt utiliptables.Interface, proxier := &Proxier{ portsMap: make(map[utilproxy.LocalPort]utilproxy.Closeable), serviceMap: make(proxy.ServiceMap), - serviceChanges: proxy.NewServiceChangeTracker(customizeServiceInfo, &isIPv6, recorder), + serviceChanges: proxy.NewServiceChangeTracker(newServiceInfo, &isIPv6, recorder), endpointsMap: make(proxy.EndpointsMap), endpointsChanges: proxy.NewEndpointChangeTracker(hostname, nil, &isIPv6, recorder), syncPeriod: syncPeriod, @@ -354,14 +354,14 @@ func NewProxier(ipt utiliptables.Interface, // internal struct for string service information type serviceInfo struct { - *proxy.ServiceInfoCommon + *proxy.BaseServiceInfo // The following fields are computed and stored for performance reasons. serviceNameString string } // returns a new proxy.ServicePort which abstracts a serviceInfo -func customizeServiceInfo(port *api.ServicePort, service *api.Service, infoCommon *proxy.ServiceInfoCommon) proxy.ServicePort { - info := &serviceInfo{ServiceInfoCommon: infoCommon} +func newServiceInfo(port *api.ServicePort, service *api.Service, baseInfo *proxy.BaseServiceInfo) proxy.ServicePort { + info := &serviceInfo{BaseServiceInfo: baseInfo} // Store the following for performance reasons. svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name} @@ -552,9 +552,7 @@ func (proxier *Proxier) isInitialized() bool { // OnServiceAdd is called whenever creation of new service object is observed. func (proxier *Proxier) OnServiceAdd(service *api.Service) { - if proxier.serviceChanges.Update(nil, service) && proxier.isInitialized() { - proxier.syncRunner.Run() - } + proxier.OnServiceUpdate(nil, service) } // OnServiceUpdate is called whenever modification of an existing service object is observed. @@ -566,9 +564,7 @@ func (proxier *Proxier) OnServiceUpdate(oldService, service *api.Service) { // OnServiceDelete is called whenever deletion of an existing service object is observed. func (proxier *Proxier) OnServiceDelete(service *api.Service) { - if proxier.serviceChanges.Update(service, nil) && proxier.isInitialized() { - proxier.syncRunner.Run() - } + proxier.OnServiceUpdate(service, nil) } // OnServiceSynced is called once all the initial even handlers were called and the state is fully propagated to local cache. @@ -584,9 +580,7 @@ func (proxier *Proxier) OnServiceSynced() { // OnEndpointsAdd is called whenever creation of new endpoints object is observed. func (proxier *Proxier) OnEndpointsAdd(endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(nil, endpoints) && proxier.isInitialized() { - proxier.syncRunner.Run() - } + proxier.OnEndpointsUpdate(nil, endpoints) } // OnEndpointsUpdate is called whenever modification of an existing endpoints object is observed. @@ -598,9 +592,7 @@ func (proxier *Proxier) OnEndpointsUpdate(oldEndpoints, endpoints *api.Endpoints // OnEndpointsDelete is called whenever deletion of an existing endpoints object is observed. func (proxier *Proxier) OnEndpointsDelete(endpoints *api.Endpoints) { - if proxier.endpointsChanges.Update(endpoints, nil) && proxier.isInitialized() { - proxier.syncRunner.Run() - } + proxier.OnEndpointsUpdate(endpoints, nil) } // OnEndpointsSynced is called once all the initial event handlers were called and the state is fully propagated to local cache. @@ -642,8 +634,8 @@ func (proxier *Proxier) syncProxyRules() { // merge stale services gathered from updateEndpointsMap for _, svcPortName := range endpointUpdateResult.StaleServiceNames { if svcInfo, ok := proxier.serviceMap[svcPortName]; ok && svcInfo != nil && svcInfo.GetProtocol() == api.ProtocolUDP { - glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.GetClusterIP()) - staleServices.Insert(svcInfo.GetClusterIP()) + glog.V(2).Infof("Stale udp service %v -> %s", svcPortName, svcInfo.ClusterIPString()) + staleServices.Insert(svcInfo.ClusterIPString()) } } @@ -759,9 +751,9 @@ func (proxier *Proxier) syncProxyRules() { // Handle traffic that loops back to the originator with SNAT. for _, e := range proxier.endpointsMap[svcName] { - ep, ok := e.(*proxy.EndpointInfoCommon) + ep, ok := e.(*proxy.BaseEndpointInfo) if !ok { - glog.Errorf("Failed to cast EndpointInfoCommon %q", e.String()) + glog.Errorf("Failed to cast BaseEndpointInfo %q", e.String()) continue } epIP := ep.IP() @@ -1269,7 +1261,7 @@ func (proxier *Proxier) deleteEndpointConnections(connectionMap []proxy.ServiceE for _, epSvcPair := range connectionMap { if svcInfo, ok := proxier.serviceMap[epSvcPair.ServicePortName]; ok && svcInfo.GetProtocol() == api.ProtocolUDP { endpointIP := utilproxy.IPPart(epSvcPair.Endpoint) - err := conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.GetClusterIP(), endpointIP, clientv1.ProtocolUDP) + err := conntrack.ClearEntriesForNAT(proxier.exec, svcInfo.ClusterIPString(), endpointIP, clientv1.ProtocolUDP) if err != nil { glog.Errorf("Failed to delete %s endpoint connections, error: %v", epSvcPair.ServicePortName.String(), err) } diff --git a/pkg/proxy/ipvs/proxier_test.go b/pkg/proxy/ipvs/proxier_test.go index 1b5480c21b8..904c5c051fb 100644 --- a/pkg/proxy/ipvs/proxier_test.go +++ b/pkg/proxy/ipvs/proxier_test.go @@ -121,7 +121,7 @@ func NewFakeProxier(ipt utiliptables.Interface, ipvs utilipvs.Interface, ipset u return &Proxier{ exec: fexec, serviceMap: make(proxy.ServiceMap), - serviceChanges: proxy.NewServiceChangeTracker(customizeServiceInfo, nil, nil), + serviceChanges: proxy.NewServiceChangeTracker(newServiceInfo, nil, nil), endpointsMap: make(proxy.EndpointsMap), endpointsChanges: proxy.NewEndpointChangeTracker(testHostname, nil, nil, nil), iptables: ipt, @@ -1581,15 +1581,15 @@ func Test_updateEndpointsMap(t *testing.T) { // or non-nil) and must be of equal length. previousEndpoints []*api.Endpoints currentEndpoints []*api.Endpoints - oldEndpoints map[proxy.ServicePortName][]*proxy.EndpointInfoCommon - expectedResult map[proxy.ServicePortName][]*proxy.EndpointInfoCommon + oldEndpoints map[proxy.ServicePortName][]*proxy.BaseEndpointInfo + expectedResult map[proxy.ServicePortName][]*proxy.BaseEndpointInfo expectedStaleEndpoints []proxy.ServiceEndpoint expectedStaleServiceNames map[proxy.ServicePortName]bool expectedHealthchecks map[types.NamespacedName]int }{{ // Case[0]: nothing - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{}, + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{}, expectedStaleEndpoints: []proxy.ServiceEndpoint{}, expectedStaleServiceNames: map[proxy.ServicePortName]bool{}, expectedHealthchecks: map[types.NamespacedName]int{}, @@ -1601,12 +1601,12 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPort), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1622,12 +1622,12 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, @@ -1645,7 +1645,7 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsets), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1653,7 +1653,7 @@ func Test_updateEndpointsMap(t *testing.T) { {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1672,7 +1672,7 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsetsMultiplePortsLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, @@ -1683,7 +1683,7 @@ func Test_updateEndpointsMap(t *testing.T) { {Endpoint: "1.1.1.3:13", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, @@ -1709,7 +1709,7 @@ func Test_updateEndpointsMap(t *testing.T) { makeTestEndpoints("ns1", "ep1", multipleSubsetsIPsPorts1), makeTestEndpoints("ns2", "ep2", multipleSubsetsIPsPorts2), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.2:11", IsLocal: true}, @@ -1735,7 +1735,7 @@ func Test_updateEndpointsMap(t *testing.T) { {Endpoint: "2.2.2.2:22", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.2:11", IsLocal: true}, @@ -1775,8 +1775,8 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPortLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{}, + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, @@ -1796,12 +1796,12 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ nil, }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{}, expectedStaleEndpoints: []proxy.ServiceEndpoint{{ Endpoint: "1.1.1.1:11", ServicePortName: makeServicePortName("ns1", "ep1", ""), @@ -1816,12 +1816,12 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortsLocalNoLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.2:11", IsLocal: true}, @@ -1846,7 +1846,7 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPort), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.2:11", IsLocal: true}, @@ -1856,7 +1856,7 @@ func Test_updateEndpointsMap(t *testing.T) { {Endpoint: "1.1.1.2:12", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1881,12 +1881,12 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", multipleSubsetsWithLocal), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1909,7 +1909,7 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPort), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1917,7 +1917,7 @@ func Test_updateEndpointsMap(t *testing.T) { {Endpoint: "1.1.1.2:12", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1936,12 +1936,12 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortRenamed), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11-2"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -1962,12 +1962,12 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", namedPortRenumbered), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:22", IsLocal: false}, }, @@ -1992,7 +1992,7 @@ func Test_updateEndpointsMap(t *testing.T) { makeTestEndpoints("ns3", "ep3", complexAfter3), makeTestEndpoints("ns4", "ep4", complexAfter4), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -2011,7 +2011,7 @@ func Test_updateEndpointsMap(t *testing.T) { {Endpoint: "4.4.4.6:45", IsLocal: true}, }, }, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", "p11"): { {Endpoint: "1.1.1.1:11", IsLocal: false}, {Endpoint: "1.1.1.11:11", IsLocal: false}, @@ -2061,8 +2061,8 @@ func Test_updateEndpointsMap(t *testing.T) { currentEndpoints: []*api.Endpoints{ makeTestEndpoints("ns1", "ep1", unnamedPort), }, - oldEndpoints: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{}, - expectedResult: map[proxy.ServicePortName][]*proxy.EndpointInfoCommon{ + oldEndpoints: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{}, + expectedResult: map[proxy.ServicePortName][]*proxy.BaseEndpointInfo{ makeServicePortName("ns1", "ep1", ""): { {Endpoint: "1.1.1.1:11", IsLocal: false}, }, @@ -2148,7 +2148,7 @@ func Test_updateEndpointsMap(t *testing.T) { } } -func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expected map[proxy.ServicePortName][]*proxy.EndpointInfoCommon) { +func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expected map[proxy.ServicePortName][]*proxy.BaseEndpointInfo) { if len(newMap) != len(expected) { t.Errorf("[%d] expected %d results, got %d: %v", tci, len(expected), len(newMap), newMap) } @@ -2157,9 +2157,9 @@ func compareEndpointsMaps(t *testing.T, tci int, newMap proxy.EndpointsMap, expe t.Errorf("[%d] expected %d endpoints for %v, got %d", tci, len(expected[x]), x, len(newMap[x])) } else { for i := range expected[x] { - newEp, ok := newMap[x][i].(*proxy.EndpointInfoCommon) + newEp, ok := newMap[x][i].(*proxy.BaseEndpointInfo) if !ok { - t.Errorf("Failed to cast proxy.EndpointInfoCommon") + t.Errorf("Failed to cast proxy.BaseEndpointInfo") continue } if *newEp != *(expected[x][i]) { diff --git a/pkg/proxy/service.go b/pkg/proxy/service.go index 4421ad32558..23911a43c5a 100644 --- a/pkg/proxy/service.go +++ b/pkg/proxy/service.go @@ -35,8 +35,11 @@ import ( utilnet "k8s.io/kubernetes/pkg/util/net" ) -// ServiceInfoCommon contains common service information. -type ServiceInfoCommon struct { +// BaseServiceInfo contains base information that defines a service. +// This could be used directly by proxier while processing services, +// or can be used for constructing a more specific ServiceInfo struct +// defined by the proxier if needed. +type BaseServiceInfo struct { ClusterIP net.IP Port int Protocol api.Protocol @@ -50,29 +53,29 @@ type ServiceInfoCommon struct { OnlyNodeLocalEndpoints bool } -var _ ServicePort = &ServiceInfoCommon{} +var _ ServicePort = &BaseServiceInfo{} // String is part of ServicePort interface. -func (info *ServiceInfoCommon) String() string { +func (info *BaseServiceInfo) String() string { return fmt.Sprintf("%s:%d/%s", info.ClusterIP, info.Port, info.Protocol) } -// GetClusterIP is part of ServicePort interface. -func (info *ServiceInfoCommon) GetClusterIP() string { +// ClusterIPString is part of ServicePort interface. +func (info *BaseServiceInfo) ClusterIPString() string { return info.ClusterIP.String() } // GetProtocol is part of ServicePort interface. -func (info *ServiceInfoCommon) GetProtocol() api.Protocol { +func (info *BaseServiceInfo) GetProtocol() api.Protocol { return info.Protocol } // GetHealthCheckNodePort is part of ServicePort interface. -func (info *ServiceInfoCommon) GetHealthCheckNodePort() int { +func (info *BaseServiceInfo) GetHealthCheckNodePort() int { return info.HealthCheckNodePort } -func (sct *ServiceChangeTracker) newServiceInfoCommon(port *api.ServicePort, service *api.Service) *ServiceInfoCommon { +func (sct *ServiceChangeTracker) newBaseServiceInfo(port *api.ServicePort, service *api.Service) *BaseServiceInfo { onlyNodeLocalEndpoints := false if apiservice.RequestsOnlyLocalTraffic(service) { onlyNodeLocalEndpoints = true @@ -82,7 +85,7 @@ func (sct *ServiceChangeTracker) newServiceInfoCommon(port *api.ServicePort, ser // Kube-apiserver side guarantees SessionAffinityConfig won't be nil when session affinity type is ClientIP stickyMaxAgeSeconds = int(*service.Spec.SessionAffinityConfig.ClientIP.TimeoutSeconds) } - info := &ServiceInfoCommon{ + info := &BaseServiceInfo{ ClusterIP: net.ParseIP(service.Spec.ClusterIP), Port: int(port.Port), Protocol: port.Protocol, @@ -101,6 +104,8 @@ func (sct *ServiceChangeTracker) newServiceInfoCommon(port *api.ServicePort, ser copy(info.ExternalIPs, service.Spec.ExternalIPs) } else { // Filter out the incorrect IP version case. + // If ExternalIPs and LoadBalancerSourceRanges on service contains incorrect IP versions, + // only filter out the incorrect ones. var incorrectIPs []string info.ExternalIPs, incorrectIPs = utilnet.FilterIncorrectIPVersion(service.Spec.ExternalIPs, *sct.isIPv6Mode) if len(incorrectIPs) > 0 { @@ -124,7 +129,7 @@ func (sct *ServiceChangeTracker) newServiceInfoCommon(port *api.ServicePort, ser return info } -type customizeServiceInfoFunc func(*api.ServicePort, *api.Service, *ServiceInfoCommon) ServicePort +type makeServicePortFunc func(*api.ServicePort, *api.Service, *BaseServiceInfo) ServicePort // serviceChange contains all changes to services that happened since proxy rules were synced. For a single object, // changes are accumulated, i.e. previous is state from before applying the changes, @@ -141,20 +146,20 @@ type ServiceChangeTracker struct { lock sync.Mutex // items maps a service to its serviceChange. items map[types.NamespacedName]*serviceChange - // customizeServiceInfo allows proxier to inject customized infomation when processing service. - customizeServiceInfo customizeServiceInfoFunc + // makeServiceInfo allows proxier to inject customized information when processing service. + makeServiceInfo makeServicePortFunc // isIPv6Mode indicates if change tracker is under IPv6/IPv4 mode. Nil means not applicable. isIPv6Mode *bool recorder record.EventRecorder } // NewServiceChangeTracker initializes a ServiceChangeTracker -func NewServiceChangeTracker(customizeServiceInfo customizeServiceInfoFunc, isIPv6Mode *bool, recorder record.EventRecorder) *ServiceChangeTracker { +func NewServiceChangeTracker(makeServiceInfo makeServicePortFunc, isIPv6Mode *bool, recorder record.EventRecorder) *ServiceChangeTracker { return &ServiceChangeTracker{ - items: make(map[types.NamespacedName]*serviceChange), - customizeServiceInfo: customizeServiceInfo, - isIPv6Mode: isIPv6Mode, - recorder: recorder, + items: make(map[types.NamespacedName]*serviceChange), + makeServiceInfo: makeServiceInfo, + isIPv6Mode: isIPv6Mode, + recorder: recorder, } } @@ -238,6 +243,7 @@ func (sct *ServiceChangeTracker) serviceToServiceMap(service *api.Service) Servi if len(service.Spec.ClusterIP) != 0 { // Filter out the incorrect IP version case. + // If ClusterIP on service has incorrect IP version, service itself will be ignored. if sct.isIPv6Mode != nil && utilnet.IsIPv6String(service.Spec.ClusterIP) != *sct.isIPv6Mode { utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "clusterIP", service.Spec.ClusterIP, service.Namespace, service.Name, service.UID) return nil @@ -248,11 +254,11 @@ func (sct *ServiceChangeTracker) serviceToServiceMap(service *api.Service) Servi for i := range service.Spec.Ports { servicePort := &service.Spec.Ports[i] svcPortName := ServicePortName{NamespacedName: svcName, Port: servicePort.Name} - svcInfoCommon := sct.newServiceInfoCommon(servicePort, service) - if sct.customizeServiceInfo != nil { - serviceMap[svcPortName] = sct.customizeServiceInfo(servicePort, service, svcInfoCommon) + baseSvcInfo := sct.newBaseServiceInfo(servicePort, service) + if sct.makeServiceInfo != nil { + serviceMap[svcPortName] = sct.makeServiceInfo(servicePort, service, baseSvcInfo) } else { - serviceMap[svcPortName] = svcInfoCommon + serviceMap[svcPortName] = baseSvcInfo } } return serviceMap @@ -328,7 +334,7 @@ func (sm *ServiceMap) unmerge(other ServiceMap, UDPStaleClusterIP sets.String) { if exists { glog.V(1).Infof("Removing service port %q", svcPortName) if info.GetProtocol() == api.ProtocolUDP { - UDPStaleClusterIP.Insert(info.GetClusterIP()) + UDPStaleClusterIP.Insert(info.ClusterIPString()) } delete(*sm, svcPortName) } else { diff --git a/pkg/proxy/service_test.go b/pkg/proxy/service_test.go index 03b85d12d0c..22508971f86 100644 --- a/pkg/proxy/service_test.go +++ b/pkg/proxy/service_test.go @@ -31,8 +31,8 @@ import ( const testHostname = "test-hostname" -func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int, svcInfoFuncs ...func(*ServiceInfoCommon)) *ServiceInfoCommon { - info := &ServiceInfoCommon{ +func makeTestServiceInfo(clusterIP string, port int, protocol string, healthcheckNodePort int, svcInfoFuncs ...func(*BaseServiceInfo)) *BaseServiceInfo { + info := &BaseServiceInfo{ ClusterIP: net.ParseIP(clusterIP), Port: port, Protocol: api.Protocol(protocol), @@ -97,13 +97,13 @@ func TestServiceToServiceMap(t *testing.T) { testCases := []struct { desc string service *api.Service - expected map[ServicePortName]*ServiceInfoCommon + expected map[ServicePortName]*BaseServiceInfo isIPv6Mode *bool }{ { desc: "nothing", service: nil, - expected: map[ServicePortName]*ServiceInfoCommon{}, + expected: map[ServicePortName]*BaseServiceInfo{}, }, { desc: "headless service", @@ -112,7 +112,7 @@ func TestServiceToServiceMap(t *testing.T) { svc.Spec.ClusterIP = api.ClusterIPNone svc.Spec.Ports = addTestPort(svc.Spec.Ports, "rpc", "UDP", 1234, 0, 0) }), - expected: map[ServicePortName]*ServiceInfoCommon{}, + expected: map[ServicePortName]*BaseServiceInfo{}, }, { desc: "headless service without port", @@ -120,7 +120,7 @@ func TestServiceToServiceMap(t *testing.T) { svc.Spec.Type = api.ServiceTypeClusterIP svc.Spec.ClusterIP = api.ClusterIPNone }), - expected: map[ServicePortName]*ServiceInfoCommon{}, + expected: map[ServicePortName]*BaseServiceInfo{}, }, { desc: "cluster ip service", @@ -130,7 +130,7 @@ func TestServiceToServiceMap(t *testing.T) { svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p1", "UDP", 1234, 4321, 0) svc.Spec.Ports = addTestPort(svc.Spec.Ports, "p2", "UDP", 1235, 5321, 0) }), - expected: map[ServicePortName]*ServiceInfoCommon{ + expected: map[ServicePortName]*BaseServiceInfo{ makeServicePortName("ns2", "cluster-ip", "p1"): makeTestServiceInfo("172.16.55.4", 1234, "UDP", 0), makeServicePortName("ns2", "cluster-ip", "p2"): makeTestServiceInfo("172.16.55.4", 1235, "UDP", 0), }, @@ -143,7 +143,7 @@ func TestServiceToServiceMap(t *testing.T) { svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port1", "UDP", 345, 678, 0) svc.Spec.Ports = addTestPort(svc.Spec.Ports, "port2", "TCP", 344, 677, 0) }), - expected: map[ServicePortName]*ServiceInfoCommon{ + expected: map[ServicePortName]*BaseServiceInfo{ makeServicePortName("ns2", "node-port", "port1"): makeTestServiceInfo("172.16.55.10", 345, "UDP", 0), makeServicePortName("ns2", "node-port", "port2"): makeTestServiceInfo("172.16.55.10", 344, "TCP", 0), }, @@ -162,7 +162,7 @@ func TestServiceToServiceMap(t *testing.T) { }, } }), - expected: map[ServicePortName]*ServiceInfoCommon{ + expected: map[ServicePortName]*BaseServiceInfo{ makeServicePortName("ns1", "load-balancer", "port3"): makeTestServiceInfo("172.16.55.11", 8675, "UDP", 0), makeServicePortName("ns1", "load-balancer", "port4"): makeTestServiceInfo("172.16.55.11", 8676, "UDP", 0), }, @@ -183,7 +183,7 @@ func TestServiceToServiceMap(t *testing.T) { svc.Spec.ExternalTrafficPolicy = api.ServiceExternalTrafficPolicyTypeLocal svc.Spec.HealthCheckNodePort = 345 }), - expected: map[ServicePortName]*ServiceInfoCommon{ + expected: map[ServicePortName]*BaseServiceInfo{ makeServicePortName("ns1", "only-local-load-balancer", "portx"): makeTestServiceInfo("172.16.55.12", 8677, "UDP", 345), makeServicePortName("ns1", "only-local-load-balancer", "porty"): makeTestServiceInfo("172.16.55.12", 8678, "UDP", 345), }, @@ -196,7 +196,7 @@ func TestServiceToServiceMap(t *testing.T) { svc.Spec.ExternalName = "foo2.bar.com" svc.Spec.Ports = addTestPort(svc.Spec.Ports, "portz", "UDP", 1235, 5321, 0) }), - expected: map[ServicePortName]*ServiceInfoCommon{}, + expected: map[ServicePortName]*BaseServiceInfo{}, }, { desc: "service with ipv6 clusterIP under ipv4 mode, service should be filtered", @@ -258,8 +258,8 @@ func TestServiceToServiceMap(t *testing.T) { }, }, }, - expected: map[ServicePortName]*ServiceInfoCommon{ - makeServicePortName("test", "validIPv4", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *ServiceInfoCommon) { + expected: map[ServicePortName]*BaseServiceInfo{ + makeServicePortName("test", "validIPv4", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *BaseServiceInfo) { info.ExternalIPs = []string{testExternalIPv4} info.LoadBalancerSourceRanges = []string{testSourceRangeIPv4} }), @@ -286,8 +286,8 @@ func TestServiceToServiceMap(t *testing.T) { }, }, }, - expected: map[ServicePortName]*ServiceInfoCommon{ - makeServicePortName("test", "validIPv6", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *ServiceInfoCommon) { + expected: map[ServicePortName]*BaseServiceInfo{ + makeServicePortName("test", "validIPv6", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *BaseServiceInfo) { info.ExternalIPs = []string{testExternalIPv6} info.LoadBalancerSourceRanges = []string{testSourceRangeIPv6} }), @@ -314,8 +314,8 @@ func TestServiceToServiceMap(t *testing.T) { }, }, }, - expected: map[ServicePortName]*ServiceInfoCommon{ - makeServicePortName("test", "filterIPv6InIPV4Mode", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *ServiceInfoCommon) { + expected: map[ServicePortName]*BaseServiceInfo{ + makeServicePortName("test", "filterIPv6InIPV4Mode", "testPort"): makeTestServiceInfo(testClusterIPv4, 12345, "TCP", 0, func(info *BaseServiceInfo) { info.ExternalIPs = []string{testExternalIPv4} info.LoadBalancerSourceRanges = []string{testSourceRangeIPv4} }), @@ -342,8 +342,8 @@ func TestServiceToServiceMap(t *testing.T) { }, }, }, - expected: map[ServicePortName]*ServiceInfoCommon{ - makeServicePortName("test", "filterIPv4InIPV6Mode", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *ServiceInfoCommon) { + expected: map[ServicePortName]*BaseServiceInfo{ + makeServicePortName("test", "filterIPv4InIPV6Mode", "testPort"): makeTestServiceInfo(testClusterIPv6, 12345, "TCP", 0, func(info *BaseServiceInfo) { info.ExternalIPs = []string{testExternalIPv6} info.LoadBalancerSourceRanges = []string{testSourceRangeIPv6} }), @@ -361,7 +361,7 @@ func TestServiceToServiceMap(t *testing.T) { t.Errorf("[%s] expected %d new, got %d: %v", tc.desc, len(tc.expected), len(newServices), spew.Sdump(newServices)) } for svcKey, expectedInfo := range tc.expected { - svcInfo := newServices[svcKey].(*ServiceInfoCommon) + svcInfo := newServices[svcKey].(*BaseServiceInfo) if !svcInfo.ClusterIP.Equal(expectedInfo.ClusterIP) || svcInfo.Port != expectedInfo.Port || svcInfo.Protocol != expectedInfo.Protocol || diff --git a/pkg/proxy/types.go b/pkg/proxy/types.go index 438635639d1..a3cb4d35e55 100644 --- a/pkg/proxy/types.go +++ b/pkg/proxy/types.go @@ -48,8 +48,8 @@ func (spn ServicePortName) String() string { type ServicePort interface { // String returns service string. An example format can be: `IP:Port/Protocol`. String() string - // GetClusterIP returns service cluster IP. - GetClusterIP() string + // ClusterIPString returns service cluster IP in string format. + ClusterIPString() string // GetProtocol returns service protocol. GetProtocol() api.Protocol // GetHealthCheckNodePort returns service health check node port if present. If return 0, it means not present. From 6004452bedf2d7f089a036f9a8364989918a4408 Mon Sep 17 00:00:00 2001 From: Zihong Zheng Date: Mon, 26 Feb 2018 18:51:49 -0800 Subject: [PATCH 8/8] Auto-updated BUILD files --- pkg/kubelet/network/hostport/BUILD | 1 + pkg/proxy/BUILD | 5 ++++- pkg/proxy/iptables/BUILD | 3 +-- pkg/proxy/ipvs/BUILD | 3 +-- pkg/proxy/util/BUILD | 4 +++- pkg/util/conntrack/BUILD | 2 ++ pkg/util/net/BUILD | 14 ++++++++++++++ 7 files changed, 26 insertions(+), 6 deletions(-) diff --git a/pkg/kubelet/network/hostport/BUILD b/pkg/kubelet/network/hostport/BUILD index 839f72904c3..7cc35a9c27a 100644 --- a/pkg/kubelet/network/hostport/BUILD +++ b/pkg/kubelet/network/hostport/BUILD @@ -19,6 +19,7 @@ go_library( "//pkg/proxy/iptables:go_default_library", "//pkg/util/conntrack:go_default_library", "//pkg/util/iptables:go_default_library", + "//pkg/util/net:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", diff --git a/pkg/proxy/BUILD b/pkg/proxy/BUILD index feae3f38dd9..ba71f18ca30 100644 --- a/pkg/proxy/BUILD +++ b/pkg/proxy/BUILD @@ -16,11 +16,15 @@ go_library( ], importpath = "k8s.io/kubernetes/pkg/proxy", deps = [ + "//pkg/api/service:go_default_library", "//pkg/apis/core:go_default_library", + "//pkg/apis/core/helper:go_default_library", "//pkg/proxy/util:go_default_library", + "//pkg/util/net:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//vendor/k8s.io/client-go/tools/record:go_default_library", ], ) @@ -57,7 +61,6 @@ go_test( ], embed = [":go_default_library"], deps = [ - "//pkg/api/service:go_default_library", "//pkg/apis/core:go_default_library", "//vendor/github.com/davecgh/go-spew/spew:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/pkg/proxy/iptables/BUILD b/pkg/proxy/iptables/BUILD index 8fba4ce5105..c8bdf903a79 100644 --- a/pkg/proxy/iptables/BUILD +++ b/pkg/proxy/iptables/BUILD @@ -13,9 +13,7 @@ go_library( ], importpath = "k8s.io/kubernetes/pkg/proxy/iptables", deps = [ - "//pkg/api/service:go_default_library", "//pkg/apis/core:go_default_library", - "//pkg/apis/core/helper:go_default_library", "//pkg/proxy:go_default_library", "//pkg/proxy/healthcheck:go_default_library", "//pkg/proxy/metrics:go_default_library", @@ -23,6 +21,7 @@ go_library( "//pkg/util/async:go_default_library", "//pkg/util/conntrack:go_default_library", "//pkg/util/iptables:go_default_library", + "//pkg/util/net:go_default_library", "//pkg/util/sysctl:go_default_library", "//pkg/util/version:go_default_library", "//vendor/github.com/golang/glog:go_default_library", diff --git a/pkg/proxy/ipvs/BUILD b/pkg/proxy/ipvs/BUILD index d55681bda13..2bb1b01d100 100644 --- a/pkg/proxy/ipvs/BUILD +++ b/pkg/proxy/ipvs/BUILD @@ -78,9 +78,7 @@ go_library( }), importpath = "k8s.io/kubernetes/pkg/proxy/ipvs", deps = [ - "//pkg/api/service:go_default_library", "//pkg/apis/core:go_default_library", - "//pkg/apis/core/helper:go_default_library", "//pkg/proxy:go_default_library", "//pkg/proxy/healthcheck:go_default_library", "//pkg/proxy/metrics:go_default_library", @@ -90,6 +88,7 @@ go_library( "//pkg/util/ipset:go_default_library", "//pkg/util/iptables:go_default_library", "//pkg/util/ipvs:go_default_library", + "//pkg/util/net:go_default_library", "//pkg/util/sysctl:go_default_library", "//pkg/util/version:go_default_library", "//vendor/github.com/golang/glog:go_default_library", diff --git a/pkg/proxy/util/BUILD b/pkg/proxy/util/BUILD index 91f6feaad8b..91e24087a43 100644 --- a/pkg/proxy/util/BUILD +++ b/pkg/proxy/util/BUILD @@ -13,10 +13,12 @@ go_library( deps = [ "//pkg/apis/core:go_default_library", "//pkg/apis/core/helper:go_default_library", - "//pkg/util/conntrack:go_default_library", + "//pkg/util/net:go_default_library", "//vendor/github.com/golang/glog:go_default_library", + "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", + "//vendor/k8s.io/client-go/tools/record:go_default_library", ], ) diff --git a/pkg/util/conntrack/BUILD b/pkg/util/conntrack/BUILD index b71382a38d4..a17d15316cb 100644 --- a/pkg/util/conntrack/BUILD +++ b/pkg/util/conntrack/BUILD @@ -8,6 +8,7 @@ go_library( importpath = "k8s.io/kubernetes/pkg/util/conntrack", visibility = ["//visibility:public"], deps = [ + "//pkg/util/net:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", ], @@ -20,6 +21,7 @@ go_test( ], embed = [":go_default_library"], deps = [ + "//pkg/util/net:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/utils/exec:go_default_library", "//vendor/k8s.io/utils/exec/testing:go_default_library", diff --git a/pkg/util/net/BUILD b/pkg/util/net/BUILD index d52a7782248..0d2a302e1e1 100644 --- a/pkg/util/net/BUILD +++ b/pkg/util/net/BUILD @@ -1,3 +1,5 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") + package(default_visibility = ["//visibility:public"]) filegroup( @@ -15,3 +17,15 @@ filegroup( ], tags = ["automanaged"], ) + +go_library( + name = "go_default_library", + srcs = ["net.go"], + importpath = "k8s.io/kubernetes/pkg/util/net", +) + +go_test( + name = "go_default_test", + srcs = ["net_test.go"], + embed = [":go_default_library"], +)