diff --git a/pkg/network/common/egressip.go b/pkg/network/common/egressip.go index edea2db2c5fd..c2da0635c3c7 100644 --- a/pkg/network/common/egressip.go +++ b/pkg/network/common/egressip.go @@ -8,6 +8,7 @@ import ( "github.com/golang/glog" + ktypes "k8s.io/apimachinery/pkg/types" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/watch" @@ -63,6 +64,7 @@ type EgressIPTracker struct { watcher EgressIPWatcher + nodes map[ktypes.UID]*nodeEgress nodesByNodeIP map[string]*nodeEgress namespacesByVNID map[uint32]*namespaceEgress egressIPs map[string]*egressIPInfo @@ -77,6 +79,7 @@ func NewEgressIPTracker(watcher EgressIPWatcher) *EgressIPTracker { return &EgressIPTracker{ watcher: watcher, + nodes: make(map[ktypes.UID]*nodeEgress), nodesByNodeIP: make(map[string]*nodeEgress), namespacesByVNID: make(map[uint32]*namespaceEgress), egressIPs: make(map[string]*egressIPInfo), @@ -167,9 +170,10 @@ func (eit *EgressIPTracker) handleDeleteHostSubnet(obj interface{}) { hs := obj.(*networkapi.HostSubnet) glog.V(5).Infof("Watch %s event for HostSubnet %q", watch.Deleted, hs.Name) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - HostIP: hs.HostIP, - }) + hs = hs.DeepCopy() + hs.EgressCIDRs = nil + hs.EgressIPs = nil + eit.UpdateHostSubnetEgress(hs) } func (eit *EgressIPTracker) UpdateHostSubnetEgress(hs *networkapi.HostSubnet) { @@ -185,7 +189,7 @@ func (eit *EgressIPTracker) UpdateHostSubnetEgress(hs *networkapi.HostSubnet) { sdnIP = netutils.GenerateDefaultGateway(cidr).String() } - node := eit.nodesByNodeIP[hs.HostIP] + node := eit.nodes[hs.UID] if node == nil { if len(hs.EgressIPs) == 0 && len(hs.EgressCIDRs) == 0 { return @@ -196,9 +200,11 @@ func (eit *EgressIPTracker) UpdateHostSubnetEgress(hs *networkapi.HostSubnet) { sdnIP: sdnIP, requestedIPs: sets.NewString(), } + eit.nodes[hs.UID] = node eit.nodesByNodeIP[hs.HostIP] = node } else if len(hs.EgressIPs) == 0 && len(hs.EgressCIDRs) == 0 { - delete(eit.nodesByNodeIP, hs.HostIP) + delete(eit.nodes, hs.UID) + delete(eit.nodesByNodeIP, node.nodeIP) } // Process EgressCIDRs @@ -218,6 +224,28 @@ func (eit *EgressIPTracker) UpdateHostSubnetEgress(hs *networkapi.HostSubnet) { eit.updateEgressCIDRs = true } + if node.nodeIP != hs.HostIP { + // We have to clean up the old egress IP mappings and call syncEgressIPs + // before we can change node.nodeIP + movedEgressIPs := make([]string, 0, node.requestedIPs.Len()) + for _, ip := range node.requestedIPs.UnsortedList() { + eg := eit.egressIPs[ip] + if eg.assignedNodeIP == node.nodeIP { + movedEgressIPs = append(movedEgressIPs, ip) + eit.deleteNodeEgressIP(node, ip) + } + } + eit.syncEgressIPs() + + delete(eit.nodesByNodeIP, node.nodeIP) + node.nodeIP = hs.HostIP + eit.nodesByNodeIP[node.nodeIP] = node + + for _, ip := range movedEgressIPs { + eit.addNodeEgressIP(node, ip) + } + } + // Process new and removed EgressIPs oldRequestedIPs := node.requestedIPs node.requestedIPs = sets.NewString(hs.EgressIPs...) @@ -448,7 +476,7 @@ func (eit *EgressIPTracker) findEgressIPAllocation(ip net.IP, allocation map[str bestNode := "" otherNodes := false - for _, node := range eit.nodesByNodeIP { + for _, node := range eit.nodes { egressIPs, exists := allocation[node.nodeName] if !exists { continue @@ -478,7 +506,7 @@ func (eit *EgressIPTracker) ReallocateEgressIPs() map[string][]string { allocation := make(map[string][]string) changed := make(map[string]bool) alreadyAllocated := make(map[string]bool) - for _, node := range eit.nodesByNodeIP { + for _, node := range eit.nodes { if len(node.parsedCIDRs) > 0 { allocation[node.nodeName] = make([]string, 0, node.requestedIPs.Len()) } @@ -534,7 +562,7 @@ func (eit *EgressIPTracker) ReallocateEgressIPs() map[string][]string { } // Remove unchanged nodes from the return value - for _, node := range eit.nodesByNodeIP { + for _, node := range eit.nodes { if !changed[node.nodeName] { delete(allocation, node.nodeName) } diff --git a/pkg/network/common/egressip_test.go b/pkg/network/common/egressip_test.go index 158ac201074e..db14b5393529 100644 --- a/pkg/network/common/egressip_test.go +++ b/pkg/network/common/egressip_test.go @@ -2,8 +2,11 @@ package common import ( "fmt" + "strings" "testing" + ktypes "k8s.io/apimachinery/pkg/types" + networkapi "github.com/openshift/origin/pkg/network/apis/network" ) @@ -75,15 +78,31 @@ func setupEgressIPTracker(t *testing.T) (*EgressIPTracker, *testEIPWatcher) { return NewEgressIPTracker(watcher), watcher } +func updateHostSubnetEgress(eit *EgressIPTracker, hs *networkapi.HostSubnet) { + if hs.Host == "" { + hs.Host = "node-" + hs.HostIP[strings.LastIndex(hs.HostIP, ".")+1:] + } + hs.Name = hs.Host + hs.UID = ktypes.UID(hs.Name) + eit.UpdateHostSubnetEgress(hs) +} + +func updateNetNamespaceEgress(eit *EgressIPTracker, ns *networkapi.NetNamespace) { + if ns.NetName == "" { + ns.NetName = fmt.Sprintf("ns-%d", ns.NetID) + } + ns.Name = ns.NetName + ns.UID = ktypes.UID(ns.Name) + eit.UpdateNetNamespaceEgress(ns) +} + func TestEgressIP(t *testing.T) { eit, w := setupEgressIPTracker(t) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", }) eit.DeleteNetNamespaceEgress(42) @@ -96,8 +115,7 @@ func TestEgressIP(t *testing.T) { } // Assign NetNamespace.EgressIP first, then HostSubnet.EgressIP - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.100"}, }) @@ -108,8 +126,7 @@ func TestEgressIP(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100"}, // Added .100 }) @@ -122,13 +139,11 @@ func TestEgressIP(t *testing.T) { } // Assign HostSubnet.EgressIP first, then NetNamespace.EgressIP - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100", "172.17.0.101"}, // Added .101 }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-5", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.5", EgressIPs: []string{"172.17.0.105"}, }) @@ -137,8 +152,7 @@ func TestEgressIP(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-43", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 43, EgressIPs: []string{"172.17.0.105"}, }) @@ -151,8 +165,7 @@ func TestEgressIP(t *testing.T) { } // Change NetNamespace.EgressIP - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-43", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 43, EgressIPs: []string{"172.17.0.101"}, }) @@ -166,8 +179,7 @@ func TestEgressIP(t *testing.T) { } // Assign another EgressIP... - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-44", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 44, EgressIPs: []string{"172.17.0.104"}, }) @@ -178,8 +190,7 @@ func TestEgressIP(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.102", "172.17.0.104"}, // Added .102, .104 }) @@ -192,8 +203,7 @@ func TestEgressIP(t *testing.T) { } // Change Namespace EgressIP - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-44", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 44, EgressIPs: []string{"172.17.0.102"}, }) @@ -207,8 +217,7 @@ func TestEgressIP(t *testing.T) { } // Assign HostSubnet.EgressIP first, then NetNamespace.EgressIP - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.102", "172.17.0.103"}, // Added .103, Dropped .104 }) @@ -217,8 +226,7 @@ func TestEgressIP(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-45", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 45, EgressIPs: []string{"172.17.0.103"}, }) @@ -241,8 +249,7 @@ func TestEgressIP(t *testing.T) { } // Add namespace EgressIP back again after having removed it... - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-44", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 44, EgressIPs: []string{"172.17.0.102"}, }) @@ -255,8 +262,7 @@ func TestEgressIP(t *testing.T) { } // Drop node EgressIPs - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100"}, // Dropped .101 }) @@ -268,8 +274,7 @@ func TestEgressIP(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.102"}, // Dropped .103 }) @@ -282,8 +287,7 @@ func TestEgressIP(t *testing.T) { } // Add them back, swapped - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100", "172.17.0.103"}, // Added .103 }) @@ -295,8 +299,7 @@ func TestEgressIP(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.101", "172.17.0.102"}, // Added .101 }) @@ -312,13 +315,11 @@ func TestEgressIP(t *testing.T) { func TestMultipleNamespaceEgressIPs(t *testing.T) { eit, w := setupEgressIPTracker(t) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.100"}, }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100"}, }) @@ -334,8 +335,7 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { } // Prepending a second, unavailable, namespace egress IP should have no effect - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.101", "172.17.0.100"}, }) @@ -345,8 +345,7 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { } // Now assigning that IP to a node should switch OVS to use that since it's first in the list - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.101"}, }) @@ -359,8 +358,7 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { } // Swapping the order in the NetNamespace should swap back - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.100", "172.17.0.101"}, }) @@ -372,8 +370,7 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { } // Removing the inactive egress IP from its node should have no effect - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.200"}, }) @@ -385,8 +382,7 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { } // Removing the remaining egress IP should now kill the namespace - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{}, }) @@ -399,13 +395,11 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { } // Now add the egress IPs back... - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100"}, }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.101"}, }) @@ -420,8 +414,7 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { // Assigning either the used or the unused Egress IP to another namespace should // break this namespace - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-43", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 43, EgressIPs: []string{"172.17.0.100"}, }) @@ -444,8 +437,7 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-44", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 44, EgressIPs: []string{"172.17.0.101"}, }) @@ -472,13 +464,11 @@ func TestMultipleNamespaceEgressIPs(t *testing.T) { func TestDuplicateNodeEgressIPs(t *testing.T) { eit, w := setupEgressIPTracker(t) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.100"}, }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100"}, }) @@ -496,8 +486,7 @@ func TestDuplicateNodeEgressIPs(t *testing.T) { // Adding the Egress IP to another node should not work and should cause the // namespace to start dropping traffic. (And in particular, should not result // in a ClaimEgressIP for the new IP.) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.100"}, }) @@ -510,8 +499,7 @@ func TestDuplicateNodeEgressIPs(t *testing.T) { } // Removing the duplicate node egressIP should restore traffic to the broken namespace - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{}, }) @@ -524,8 +512,7 @@ func TestDuplicateNodeEgressIPs(t *testing.T) { } // As above, but with a different node IP - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-5", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.5", EgressIPs: []string{"172.17.0.100"}, }) @@ -547,8 +534,7 @@ func TestDuplicateNodeEgressIPs(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.100"}, }) @@ -561,8 +547,7 @@ func TestDuplicateNodeEgressIPs(t *testing.T) { // Removing the original egress node should result in the "duplicate" egress node // now being used. - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{}, }) @@ -578,13 +563,11 @@ func TestDuplicateNodeEgressIPs(t *testing.T) { func TestDuplicateNamespaceEgressIPs(t *testing.T) { eit, w := setupEgressIPTracker(t) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.100"}, }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100"}, }) @@ -601,8 +584,7 @@ func TestDuplicateNamespaceEgressIPs(t *testing.T) { // Adding the Egress IP to another namespace should not work and should cause both // namespaces to start dropping traffic. - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-43", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 43, EgressIPs: []string{"172.17.0.100"}, }) @@ -627,8 +609,7 @@ func TestDuplicateNamespaceEgressIPs(t *testing.T) { } // Add duplicate back, re-breaking it - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-43", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 43, EgressIPs: []string{"172.17.0.100"}, }) @@ -643,8 +624,7 @@ func TestDuplicateNamespaceEgressIPs(t *testing.T) { // Now remove and re-add the Node EgressIP; the namespace should stay broken // whether the IP is assigned to a node or not. - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{}, }) @@ -653,8 +633,7 @@ func TestDuplicateNamespaceEgressIPs(t *testing.T) { t.Fatalf("%v", err) } - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100"}, }) @@ -679,18 +658,15 @@ func TestDuplicateNamespaceEgressIPs(t *testing.T) { func TestOfflineEgressIPs(t *testing.T) { eit, w := setupEgressIPTracker(t) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{"172.17.0.100"}, }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{"172.17.0.101"}, }) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.100", "172.17.0.101"}, }) @@ -751,8 +727,7 @@ func updateAllocations(eit *EgressIPTracker, allocation map[string][]string) { for nodeName, egressIPs := range allocation { for _, node := range eit.nodesByNodeIP { if node.nodeName == nodeName { - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: nodeName, + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: node.nodeIP, EgressIPs: egressIPs, EgressCIDRs: node.requestedCIDRs.List(), @@ -766,20 +741,17 @@ func updateAllocations(eit *EgressIPTracker, allocation map[string][]string) { func TestEgressCIDRAllocation(t *testing.T) { eit, w := setupEgressIPTracker(t) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: []string{}, EgressCIDRs: []string{"172.17.0.100/32", "172.17.0.101/32", "172.17.0.102/32", "172.17.0.103/32", "172.17.1.0/24"}, }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-4", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.4", EgressIPs: []string{}, EgressCIDRs: []string{"172.17.0.0/24"}, }) - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-5", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.5", EgressIPs: []string{}, EgressCIDRs: []string{}, @@ -794,13 +766,11 @@ func TestEgressCIDRAllocation(t *testing.T) { } // Either of these could be assigned to either node, but they should be balanced - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-42", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 42, EgressIPs: []string{"172.17.0.100"}, }) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-43", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 43, EgressIPs: []string{"172.17.0.101"}, }) @@ -844,13 +814,11 @@ func TestEgressCIDRAllocation(t *testing.T) { // First can only be assigned to node3. Second *could* be assigned to either, but // must get assigned to node4 for balance - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-44", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 44, EgressIPs: []string{"172.17.1.1"}, }) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-45", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 45, EgressIPs: []string{"172.17.0.102"}, }) @@ -879,13 +847,11 @@ func TestEgressCIDRAllocation(t *testing.T) { // Manually assigning egress IPs to the node with no EgressCIDRs should have no // effect on automatic assignments (though it will result in a spurious "update // egress CIDRs" notification). - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-5", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.5", EgressIPs: []string{"172.17.2.100"}, }) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-50", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 50, EgressIPs: []string{"172.17.2.100"}, }) @@ -908,18 +874,15 @@ func TestEgressCIDRAllocation(t *testing.T) { } // First two can only be assigned to node4. Last must get assigned to node3 for balance - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-46", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 46, EgressIPs: []string{"172.17.0.200"}, }) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-47", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 47, EgressIPs: []string{"172.17.0.201"}, }) - eit.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ - NetName: "ns-48", + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ NetID: 48, EgressIPs: []string{"172.17.0.103"}, }) @@ -951,8 +914,7 @@ func TestEgressCIDRAllocation(t *testing.T) { // Dropping an Egress CIDR will drop the Egress IP(s) that came from that CIDR. // If we then reallocate, the dropped Egress IP(s) might be allocated to new nodes. - eit.UpdateHostSubnetEgress(&networkapi.HostSubnet{ - Host: "node-3", + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ HostIP: "172.17.0.3", EgressIPs: allocation["node-3"], EgressCIDRs: []string{"172.17.0.100/32", "172.17.0.101/32", "172.17.0.102/32", "172.17.1.0/24"}, // removed "172.17.0.103/32" @@ -985,3 +947,57 @@ func TestEgressCIDRAllocation(t *testing.T) { t.Fatalf("%v", err) } } + +func TestEgressNodeRenumbering(t *testing.T) { + eit, w := setupEgressIPTracker(t) + + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ + Host: "alpha", + HostIP: "172.17.0.3", + EgressIPs: []string{"172.17.0.100"}, + }) + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ + Host: "beta", + HostIP: "172.17.0.4", + EgressIPs: []string{"172.17.0.101"}, + }) + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ + Host: "gamma", + HostIP: "172.17.0.5", + EgressIPs: []string{"172.17.0.102"}, + }) + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ + NetID: 42, + EgressIPs: []string{"172.17.0.100"}, + }) + updateNetNamespaceEgress(eit, &networkapi.NetNamespace{ + NetID: 43, + EgressIPs: []string{"172.17.0.101"}, + }) + + err := w.assertChanges( + "claim 172.17.0.100 on 172.17.0.3 for namespace 42", + "namespace 42 via 172.17.0.100 on 172.17.0.3", + "claim 172.17.0.101 on 172.17.0.4 for namespace 43", + "namespace 43 via 172.17.0.101 on 172.17.0.4", + ) + if err != nil { + t.Fatalf("%v", err) + } + + // Renumber one of the hosts + updateHostSubnetEgress(eit, &networkapi.HostSubnet{ + Host: "beta", + HostIP: "172.17.0.6", + EgressIPs: []string{"172.17.0.101"}, + }) + err = w.assertChanges( + "release 172.17.0.101 on 172.17.0.4", + "namespace 43 dropped", + "claim 172.17.0.101 on 172.17.0.6 for namespace 43", + "namespace 43 via 172.17.0.101 on 172.17.0.6", + ) + if err != nil { + t.Fatalf("%v", err) + } +} diff --git a/pkg/network/node/egressip_test.go b/pkg/network/node/egressip_test.go index 40685ee2a26b..d0656a98c4a6 100644 --- a/pkg/network/node/egressip_test.go +++ b/pkg/network/node/egressip_test.go @@ -9,6 +9,9 @@ import ( "strings" "testing" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + ktypes "k8s.io/apimachinery/pkg/types" + networkapi "github.com/openshift/origin/pkg/network/apis/network" ) @@ -144,14 +147,26 @@ func setupEgressIPWatcher(t *testing.T) (*egressIPWatcher, []string) { } func updateNodeEgress(eip *egressIPWatcher, nodeIP string, egressIPs []string) { + name := "node-" + nodeIP[strings.LastIndex(nodeIP, ".")+1:] eip.tracker.UpdateHostSubnetEgress(&networkapi.HostSubnet{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + UID: ktypes.UID(name), + }, + Host: name, HostIP: nodeIP, EgressIPs: egressIPs, }) } func updateNamespaceEgress(eip *egressIPWatcher, vnid uint32, egressIPs []string) { + name := fmt.Sprintf("ns-%d", vnid) eip.tracker.UpdateNetNamespaceEgress(&networkapi.NetNamespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + UID: ktypes.UID(name), + }, + NetName: name, NetID: vnid, EgressIPs: egressIPs, }) @@ -707,3 +722,62 @@ func TestMarkForVNID(t *testing.T) { } } } + +func TestEgressNodeRenumbering(t *testing.T) { + eip, flows := setupEgressIPWatcher(t) + + eip.tracker.UpdateHostSubnetEgress(&networkapi.HostSubnet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "alpha", + UID: ktypes.UID("alpha"), + }, + Host: "alpha", + HostIP: "172.17.0.3", + EgressIPs: []string{"172.17.0.100"}, + }) + eip.tracker.UpdateHostSubnetEgress(&networkapi.HostSubnet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "beta", + UID: ktypes.UID("beta"), + }, + Host: "beta", + HostIP: "172.17.0.4", + EgressIPs: []string{"172.17.0.101"}, + }) + eip.tracker.UpdateHostSubnetEgress(&networkapi.HostSubnet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "gamma", + UID: ktypes.UID("gamma"), + }, + Host: "gamma", + HostIP: "172.17.0.5", + EgressIPs: []string{"172.17.0.102"}, + }) + updateNamespaceEgress(eip, 42, []string{"172.17.0.100"}) + updateNamespaceEgress(eip, 43, []string{"172.17.0.101"}) + + err := assertOVSChanges(eip, &flows, + egressOVSChange{vnid: 42, egress: Remote, remote: "172.17.0.3"}, + egressOVSChange{vnid: 43, egress: Local}, + ) + if err != nil { + t.Fatalf("%v", err) + } + + // Renumber one of the hosts + eip.tracker.UpdateHostSubnetEgress(&networkapi.HostSubnet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "beta", + UID: ktypes.UID("beta"), + }, + Host: "beta", + HostIP: "172.17.0.6", + EgressIPs: []string{"172.17.0.101"}, + }) + err = assertOVSChanges(eip, &flows, + egressOVSChange{vnid: 43, egress: Remote, remote: "172.17.0.6"}, + ) + if err != nil { + t.Fatalf("%v", err) + } +}