Skip to content

Commit 2884ee8

Browse files
authoredMar 30, 2018
Merge pull request #19080 from danwinship/subnet-tracking
Prevent incorrect deletion of HostSubnet OVS flows
2 parents c232b23 + ad8877b commit 2884ee8

File tree

6 files changed

+461
-209
lines changed

6 files changed

+461
-209
lines changed
 

‎pkg/network/node/node.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,6 @@ type OsdnNode struct {
114114
host knetwork.Host
115115
kubeletCniPlugin knetwork.NetworkPlugin
116116

117-
hostSubnetMap map[string]*networkapi.HostSubnet
118-
119117
kubeInformers kinternalinformers.SharedInformerFactory
120118
networkInformers networkinformers.SharedInformerFactory
121119

@@ -183,7 +181,6 @@ func New(c *OsdnNodeConfig) (network.NodeInterface, error) {
183181
mtu: c.MTU,
184182
egressPolicies: make(map[uint32][]networkapi.EgressNetworkPolicy),
185183
egressDNS: common.NewEgressDNS(),
186-
hostSubnetMap: make(map[string]*networkapi.HostSubnet),
187184
kubeInformers: c.KubeInformers,
188185
networkInformers: c.NetworkInformers,
189186
egressIP: newEgressIPWatcher(oc, c.SelfIP, c.MasqueradeBit),
@@ -333,7 +330,8 @@ func (node *OsdnNode) Start() error {
333330
return fmt.Errorf("node SDN setup failed: %v", err)
334331
}
335332

336-
node.SubnetStartNode()
333+
hsw := newHostSubnetWatcher(node.oc, node.localIP, node.networkInfo)
334+
hsw.Start(node.networkInformers)
337335

338336
if err = node.policy.Start(node); err != nil {
339337
return err

‎pkg/network/node/ovscontroller.go

+18-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package node
44

55
import (
6+
"crypto/sha256"
67
"fmt"
78
"net"
89
"sort"
@@ -34,7 +35,7 @@ const (
3435
Vxlan0 = "vxlan0"
3536

3637
// rule versioning; increment each time flow rules change
37-
ruleVersion = 6
38+
ruleVersion = 7
3839

3940
ruleVersionTable = 253
4041
)
@@ -503,26 +504,34 @@ func (oc *ovsController) UpdateEgressNetworkPolicyRules(policies []networkapi.Eg
503504
}
504505
}
505506

507+
func hostSubnetCookie(subnet *networkapi.HostSubnet) uint32 {
508+
hash := sha256.Sum256([]byte(subnet.UID))
509+
return (uint32(hash[0]) << 24) | (uint32(hash[1]) << 16) | (uint32(hash[2]) << 8) | uint32(hash[3])
510+
}
511+
506512
func (oc *ovsController) AddHostSubnetRules(subnet *networkapi.HostSubnet) error {
513+
cookie := hostSubnetCookie(subnet)
507514
otx := oc.ovs.NewTransaction()
508515

509-
otx.AddFlow("table=10, priority=100, tun_src=%s, actions=goto_table:30", subnet.HostIP)
516+
otx.AddFlow("table=10, priority=100, cookie=0x%08x, tun_src=%s, actions=goto_table:30", cookie, subnet.HostIP)
510517
if vnid, ok := subnet.Annotations[networkapi.FixedVNIDHostAnnotation]; ok {
511-
otx.AddFlow("table=50, priority=100, arp, nw_dst=%s, actions=load:%s->NXM_NX_TUN_ID[0..31],set_field:%s->tun_dst,output:1", subnet.Subnet, vnid, subnet.HostIP)
512-
otx.AddFlow("table=90, priority=100, ip, nw_dst=%s, actions=load:%s->NXM_NX_TUN_ID[0..31],set_field:%s->tun_dst,output:1", subnet.Subnet, vnid, subnet.HostIP)
518+
otx.AddFlow("table=50, priority=100, cookie=0x%08x, arp, nw_dst=%s, actions=load:%s->NXM_NX_TUN_ID[0..31],set_field:%s->tun_dst,output:1", cookie, subnet.Subnet, vnid, subnet.HostIP)
519+
otx.AddFlow("table=90, priority=100, cookie=0x%08x, ip, nw_dst=%s, actions=load:%s->NXM_NX_TUN_ID[0..31],set_field:%s->tun_dst,output:1", cookie, subnet.Subnet, vnid, subnet.HostIP)
513520
} else {
514-
otx.AddFlow("table=50, priority=100, arp, nw_dst=%s, actions=move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],set_field:%s->tun_dst,output:1", subnet.Subnet, subnet.HostIP)
515-
otx.AddFlow("table=90, priority=100, ip, nw_dst=%s, actions=move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],set_field:%s->tun_dst,output:1", subnet.Subnet, subnet.HostIP)
521+
otx.AddFlow("table=50, priority=100, cookie=0x%08x, arp, nw_dst=%s, actions=move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],set_field:%s->tun_dst,output:1", cookie, subnet.Subnet, subnet.HostIP)
522+
otx.AddFlow("table=90, priority=100, cookie=0x%08x, ip, nw_dst=%s, actions=move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],set_field:%s->tun_dst,output:1", cookie, subnet.Subnet, subnet.HostIP)
516523
}
517524

518525
return otx.EndTransaction()
519526
}
520527

521528
func (oc *ovsController) DeleteHostSubnetRules(subnet *networkapi.HostSubnet) error {
529+
cookie := hostSubnetCookie(subnet)
530+
522531
otx := oc.ovs.NewTransaction()
523-
otx.DeleteFlows("table=10, tun_src=%s", subnet.HostIP)
524-
otx.DeleteFlows("table=50, arp, nw_dst=%s", subnet.Subnet)
525-
otx.DeleteFlows("table=90, ip, nw_dst=%s", subnet.Subnet)
532+
otx.DeleteFlows("table=10, cookie=0x%08x, tun_src=%s", cookie, subnet.HostIP)
533+
otx.DeleteFlows("table=50, cookie=0x%08x, arp, nw_dst=%s", cookie, subnet.Subnet)
534+
otx.DeleteFlows("table=90, cookie=0x%08x, ip, nw_dst=%s", cookie, subnet.Subnet)
526535
return otx.EndTransaction()
527536
}
528537

‎pkg/network/node/ovscontroller_test.go

+1-119
Original file line numberDiff line numberDiff line change
@@ -103,62 +103,6 @@ func assertFlowChanges(origFlows, newFlows []string, changes ...flowChange) erro
103103
return nil
104104
}
105105

106-
func TestOVSHostSubnet(t *testing.T) {
107-
ovsif, oc, origFlows := setupOVSController(t)
108-
109-
hs := networkapi.HostSubnet{
110-
TypeMeta: metav1.TypeMeta{
111-
Kind: "HostSubnet",
112-
},
113-
ObjectMeta: metav1.ObjectMeta{
114-
Name: "node2",
115-
},
116-
Host: "node2",
117-
HostIP: "192.168.1.2",
118-
Subnet: "10.129.0.0/23",
119-
}
120-
err := oc.AddHostSubnetRules(&hs)
121-
if err != nil {
122-
t.Fatalf("Unexpected error adding HostSubnet rules: %v", err)
123-
}
124-
125-
flows, err := ovsif.DumpFlows("")
126-
if err != nil {
127-
t.Fatalf("Unexpected error dumping flows: %v", err)
128-
}
129-
err = assertFlowChanges(origFlows, flows,
130-
flowChange{
131-
kind: flowAdded,
132-
match: []string{"table=10", "tun_src=192.168.1.2"},
133-
},
134-
flowChange{
135-
kind: flowAdded,
136-
match: []string{"table=50", "arp", "arp_tpa=10.129.0.0/23", "192.168.1.2->tun_dst"},
137-
},
138-
flowChange{
139-
kind: flowAdded,
140-
match: []string{"table=90", "ip", "nw_dst=10.129.0.0/23", "192.168.1.2->tun_dst"},
141-
},
142-
)
143-
if err != nil {
144-
t.Fatalf("Unexpected flow changes: %v\nOrig: %#v\nNew: %#v", err, origFlows, flows)
145-
}
146-
147-
err = oc.DeleteHostSubnetRules(&hs)
148-
if err != nil {
149-
t.Fatalf("Unexpected error deleting HostSubnet rules: %v", err)
150-
}
151-
flows, err = ovsif.DumpFlows("")
152-
if err != nil {
153-
t.Fatalf("Unexpected error dumping flows: %v", err)
154-
}
155-
err = assertFlowChanges(origFlows, flows) // no changes
156-
157-
if err != nil {
158-
t.Fatalf("Unexpected flow changes: %v\nOrig: %#v\nNew: %#v", err, origFlows, flows)
159-
}
160-
}
161-
162106
func TestOVSService(t *testing.T) {
163107
ovsif, oc, origFlows := setupOVSController(t)
164108

@@ -361,10 +305,9 @@ func TestGetPodDetails(t *testing.T) {
361305
}
362306
}
363307

364-
func TestOVSMulticast(t *testing.T) {
308+
func TestOVSLocalMulticast(t *testing.T) {
365309
ovsif, oc, origFlows := setupOVSController(t)
366310

367-
// local flows
368311
err := oc.UpdateLocalMulticastFlows(99, true, []int{4, 5, 6})
369312
if err != nil {
370313
t.Fatalf("Unexpected error adding multicast flows: %v", err)
@@ -413,67 +356,6 @@ func TestOVSMulticast(t *testing.T) {
413356
if err != nil {
414357
t.Fatalf("Unexpected flow changes: %v\nOrig: %#v\nNew: %#v", err, origFlows, flows)
415358
}
416-
417-
// VXLAN
418-
err = oc.UpdateVXLANMulticastFlows([]string{"192.168.1.2", "192.168.1.5", "192.168.1.3"})
419-
if err != nil {
420-
t.Fatalf("Unexpected error adding multicast flows: %v", err)
421-
}
422-
flows, err = ovsif.DumpFlows("")
423-
if err != nil {
424-
t.Fatalf("Unexpected error dumping flows: %v", err)
425-
}
426-
err = assertFlowChanges(origFlows, flows,
427-
flowChange{
428-
kind: flowRemoved,
429-
match: []string{"table=111", "goto_table:120"},
430-
noMatch: []string{"->tun_dst"},
431-
},
432-
flowChange{
433-
kind: flowAdded,
434-
match: []string{"table=111", "192.168.1.2->tun_dst", "192.168.1.3->tun_dst", "192.168.1.5->tun_dst"},
435-
},
436-
)
437-
if err != nil {
438-
t.Fatalf("Unexpected flow changes: %v\nOrig: %#v\nNew: %#v", err, origFlows, flows)
439-
}
440-
441-
err = oc.UpdateVXLANMulticastFlows([]string{"192.168.1.5", "192.168.1.3"})
442-
if err != nil {
443-
t.Fatalf("Unexpected error adding multicast flows: %v", err)
444-
}
445-
flows, err = ovsif.DumpFlows("")
446-
if err != nil {
447-
t.Fatalf("Unexpected error dumping flows: %v", err)
448-
}
449-
err = assertFlowChanges(origFlows, flows,
450-
flowChange{
451-
kind: flowRemoved,
452-
match: []string{"table=111", "goto_table:120"},
453-
noMatch: []string{"->tun_dst"},
454-
},
455-
flowChange{
456-
kind: flowAdded,
457-
match: []string{"table=111", "192.168.1.3->tun_dst", "192.168.1.5->tun_dst"},
458-
noMatch: []string{"192.168.1.2"},
459-
},
460-
)
461-
if err != nil {
462-
t.Fatalf("Unexpected flow changes: %v\nOrig: %#v\nNew: %#v", err, origFlows, flows)
463-
}
464-
465-
err = oc.UpdateVXLANMulticastFlows([]string{})
466-
if err != nil {
467-
t.Fatalf("Unexpected error adding multicast flows: %v", err)
468-
}
469-
flows, err = ovsif.DumpFlows("")
470-
if err != nil {
471-
t.Fatalf("Unexpected error dumping flows: %v", err)
472-
}
473-
err = assertFlowChanges(origFlows, flows) // no changes
474-
if err != nil {
475-
t.Fatalf("Unexpected flow changes: %v\nOrig: %#v\nNew: %#v", err, origFlows, flows)
476-
}
477359
}
478360

479361
var enp1 = networkapi.EgressNetworkPolicy{

‎pkg/network/node/sdn_controller.go

-16
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ import (
1010

1111
"github.com/golang/glog"
1212

13-
networkapi "github.com/openshift/origin/pkg/network/apis/network"
14-
"github.com/openshift/origin/pkg/network/common"
1513
"github.com/openshift/origin/pkg/util/netutils"
1614

1715
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
@@ -208,20 +206,6 @@ func (plugin *OsdnNode) updateEgressNetworkPolicyRules(vnid uint32) {
208206
}
209207
}
210208

211-
func (plugin *OsdnNode) AddHostSubnetRules(subnet *networkapi.HostSubnet) {
212-
glog.Infof("AddHostSubnetRules for %s", common.HostSubnetToString(subnet))
213-
if err := plugin.oc.AddHostSubnetRules(subnet); err != nil {
214-
utilruntime.HandleError(fmt.Errorf("Error adding OVS flows for subnet %q: %v", subnet.Subnet, err))
215-
}
216-
}
217-
218-
func (plugin *OsdnNode) DeleteHostSubnetRules(subnet *networkapi.HostSubnet) {
219-
glog.Infof("DeleteHostSubnetRules for %s", common.HostSubnetToString(subnet))
220-
if err := plugin.oc.DeleteHostSubnetRules(subnet); err != nil {
221-
utilruntime.HandleError(fmt.Errorf("Error deleting OVS flows for subnet %q: %v", subnet.Subnet, err))
222-
}
223-
}
224-
225209
func (plugin *OsdnNode) AddServiceRules(service *kapi.Service, netID uint32) {
226210
glog.V(5).Infof("AddServiceRules for %v", service)
227211
if err := plugin.oc.AddServiceRules(service, netID); err != nil {

‎pkg/network/node/subnets.go

+102-61
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,118 @@ import (
1010

1111
kapierrors "k8s.io/apimachinery/pkg/api/errors"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
ktypes "k8s.io/apimachinery/pkg/types"
14+
kerrors "k8s.io/apimachinery/pkg/util/errors"
1315
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
1416
utilwait "k8s.io/apimachinery/pkg/util/wait"
1517
"k8s.io/apimachinery/pkg/watch"
1618

1719
networkapi "github.com/openshift/origin/pkg/network/apis/network"
1820
"github.com/openshift/origin/pkg/network/common"
21+
networkinformers "github.com/openshift/origin/pkg/network/generated/informers/internalversion"
1922
)
2023

21-
func (node *OsdnNode) SubnetStartNode() {
22-
node.watchSubnets()
24+
type hostSubnetWatcher struct {
25+
oc *ovsController
26+
localIP string
27+
networkInfo *common.NetworkInfo
28+
29+
hostSubnetMap map[ktypes.UID]*networkapi.HostSubnet
30+
}
31+
32+
func newHostSubnetWatcher(oc *ovsController, localIP string, networkInfo *common.NetworkInfo) *hostSubnetWatcher {
33+
return &hostSubnetWatcher{
34+
oc: oc,
35+
localIP: localIP,
36+
networkInfo: networkInfo,
37+
38+
hostSubnetMap: make(map[ktypes.UID]*networkapi.HostSubnet),
39+
}
40+
}
41+
42+
func (hsw *hostSubnetWatcher) Start(networkInformers networkinformers.SharedInformerFactory) {
43+
funcs := common.InformerFuncs(&networkapi.HostSubnet{}, hsw.handleAddOrUpdateHostSubnet, hsw.handleDeleteHostSubnet)
44+
networkInformers.Network().InternalVersion().HostSubnets().Informer().AddEventHandler(funcs)
45+
}
46+
47+
func (hsw *hostSubnetWatcher) handleAddOrUpdateHostSubnet(obj, _ interface{}, eventType watch.EventType) {
48+
hs := obj.(*networkapi.HostSubnet)
49+
glog.V(5).Infof("Watch %s event for HostSubnet %q", eventType, hs.Name)
50+
51+
if err := hsw.updateHostSubnet(hs); err != nil {
52+
utilruntime.HandleError(err)
53+
}
54+
}
55+
56+
func (hsw *hostSubnetWatcher) handleDeleteHostSubnet(obj interface{}) {
57+
hs := obj.(*networkapi.HostSubnet)
58+
glog.V(5).Infof("Watch %s event for HostSubnet %q", watch.Deleted, hs.Name)
59+
60+
if err := hsw.deleteHostSubnet(hs); err != nil {
61+
utilruntime.HandleError(err)
62+
}
2363
}
2464

25-
func (node *OsdnNode) watchSubnets() {
26-
funcs := common.InformerFuncs(&networkapi.HostSubnet{}, node.handleAddOrUpdateHostSubnet, node.handleDeleteHostSubnet)
27-
node.networkInformers.Network().InternalVersion().HostSubnets().Informer().AddEventHandler(funcs)
65+
func (hsw *hostSubnetWatcher) updateHostSubnet(hs *networkapi.HostSubnet) error {
66+
if hs.HostIP == hsw.localIP {
67+
return nil
68+
}
69+
oldSubnet, exists := hsw.hostSubnetMap[hs.UID]
70+
if exists {
71+
if oldSubnet.HostIP == hs.HostIP {
72+
return nil
73+
} else {
74+
// Delete old subnet rules (ignore errors)
75+
hsw.oc.DeleteHostSubnetRules(oldSubnet)
76+
}
77+
}
78+
if err := hsw.networkInfo.ValidateNodeIP(hs.HostIP); err != nil {
79+
return fmt.Errorf("ignoring invalid subnet for node %s: %v", hs.HostIP, err)
80+
}
81+
82+
hsw.hostSubnetMap[hs.UID] = hs
83+
84+
errList := []error{}
85+
if err := hsw.oc.AddHostSubnetRules(hs); err != nil {
86+
errList = append(errList, fmt.Errorf("error adding OVS flows for subnet %q: %v", hs.Subnet, err))
87+
}
88+
// Update multicast rules after all other changes have been processed
89+
if err := hsw.updateVXLANMulticastRules(); err != nil {
90+
errList = append(errList, fmt.Errorf("error updating OVS VXLAN multicast flows: %v", err))
91+
}
92+
93+
return kerrors.NewAggregate(errList)
94+
}
95+
96+
func (hsw *hostSubnetWatcher) deleteHostSubnet(hs *networkapi.HostSubnet) error {
97+
if hs.HostIP == hsw.localIP {
98+
return nil
99+
}
100+
if _, exists := hsw.hostSubnetMap[hs.UID]; !exists {
101+
return nil
102+
}
103+
104+
delete(hsw.hostSubnetMap, hs.UID)
105+
106+
errList := []error{}
107+
if err := hsw.oc.DeleteHostSubnetRules(hs); err != nil {
108+
errList = append(errList, fmt.Errorf("error deleting OVS flows for subnet %q: %v", hs.Subnet, err))
109+
}
110+
if err := hsw.updateVXLANMulticastRules(); err != nil {
111+
errList = append(errList, fmt.Errorf("error updating OVS VXLAN multicast flows: %v", err))
112+
}
113+
114+
return kerrors.NewAggregate(errList)
115+
}
116+
117+
func (hsw *hostSubnetWatcher) updateVXLANMulticastRules() error {
118+
remoteIPs := make([]string, 0, len(hsw.hostSubnetMap))
119+
for _, subnet := range hsw.hostSubnetMap {
120+
if subnet.HostIP != hsw.localIP {
121+
remoteIPs = append(remoteIPs, subnet.HostIP)
122+
}
123+
}
124+
return hsw.oc.UpdateVXLANMulticastFlows(remoteIPs)
28125
}
29126

30127
func (node *OsdnNode) getLocalSubnet() (string, error) {
@@ -68,59 +165,3 @@ func (node *OsdnNode) getLocalSubnet() (string, error) {
68165

69166
return subnet.Subnet, nil
70167
}
71-
72-
func (node *OsdnNode) handleAddOrUpdateHostSubnet(obj, _ interface{}, eventType watch.EventType) {
73-
hs := obj.(*networkapi.HostSubnet)
74-
glog.V(5).Infof("Watch %s event for HostSubnet %q", eventType, hs.Name)
75-
76-
if hs.HostIP == node.localIP {
77-
return
78-
}
79-
oldSubnet, exists := node.hostSubnetMap[string(hs.UID)]
80-
if exists {
81-
if oldSubnet.HostIP == hs.HostIP {
82-
return
83-
} else {
84-
// Delete old subnet rules
85-
node.DeleteHostSubnetRules(oldSubnet)
86-
}
87-
}
88-
if err := node.networkInfo.ValidateNodeIP(hs.HostIP); err != nil {
89-
glog.Warningf("Ignoring invalid subnet for node %s: %v", hs.HostIP, err)
90-
return
91-
}
92-
node.AddHostSubnetRules(hs)
93-
node.hostSubnetMap[string(hs.UID)] = hs
94-
95-
// Update multicast rules after all other changes have been processed
96-
node.updateVXLANMulticastRules()
97-
}
98-
99-
func (node *OsdnNode) handleDeleteHostSubnet(obj interface{}) {
100-
hs := obj.(*networkapi.HostSubnet)
101-
glog.V(5).Infof("Watch %s event for HostSubnet %q", watch.Deleted, hs.Name)
102-
103-
if hs.HostIP == node.localIP {
104-
return
105-
}
106-
if _, exists := node.hostSubnetMap[string(hs.UID)]; !exists {
107-
return
108-
}
109-
110-
delete(node.hostSubnetMap, string(hs.UID))
111-
node.DeleteHostSubnetRules(hs)
112-
113-
node.updateVXLANMulticastRules()
114-
}
115-
116-
func (node *OsdnNode) updateVXLANMulticastRules() {
117-
remoteIPs := make([]string, 0, len(node.hostSubnetMap))
118-
for _, subnet := range node.hostSubnetMap {
119-
if subnet.HostIP != node.localIP {
120-
remoteIPs = append(remoteIPs, subnet.HostIP)
121-
}
122-
}
123-
if err := node.oc.UpdateVXLANMulticastFlows(remoteIPs); err != nil {
124-
utilruntime.HandleError(fmt.Errorf("Error updating OVS VXLAN multicast flows: %v", err))
125-
}
126-
}

‎pkg/network/node/subnets_test.go

+338
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
package node
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
"testing"
7+
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
ktypes "k8s.io/apimachinery/pkg/types"
10+
11+
networkapi "github.com/openshift/origin/pkg/network/apis/network"
12+
"github.com/openshift/origin/pkg/network/common"
13+
)
14+
15+
func assertHostSubnetFlowChanges(hsw *hostSubnetWatcher, flows *[]string, changes ...flowChange) error {
16+
oldFlows := *flows
17+
newFlows, err := hsw.oc.ovs.DumpFlows("")
18+
if err != nil {
19+
return fmt.Errorf("unexpected error dumping OVS flows: %v", err)
20+
}
21+
22+
err = assertFlowChanges(oldFlows, newFlows, changes...)
23+
if err != nil {
24+
return fmt.Errorf("unexpected flow changes: %v\nOrig:\n%s\nNew:\n%s", err,
25+
strings.Join(oldFlows, "\n"), strings.Join(newFlows, "\n"))
26+
}
27+
28+
*flows = newFlows
29+
return nil
30+
}
31+
32+
func setupHostSubnetWatcher(t *testing.T) (*hostSubnetWatcher, []string) {
33+
_, oc, _ := setupOVSController(t)
34+
35+
networkInfo, err := common.ParseNetworkInfo(
36+
[]networkapi.ClusterNetworkEntry{
37+
{
38+
CIDR: "10.128.0.0/14",
39+
HostSubnetLength: 9,
40+
},
41+
},
42+
"172.30.0.0/16",
43+
)
44+
if err != nil {
45+
t.Fatalf("unexpected error parsing network info: %v", err)
46+
}
47+
48+
hsw := newHostSubnetWatcher(oc, oc.localIP, networkInfo)
49+
50+
flows, err := hsw.oc.ovs.DumpFlows("")
51+
if err != nil {
52+
t.Fatalf("unexpected error dumping OVS flows: %v", err)
53+
}
54+
55+
return hsw, flows
56+
}
57+
58+
func makeHostSubnet(name, hostIP, subnet string) *networkapi.HostSubnet {
59+
return &networkapi.HostSubnet{
60+
TypeMeta: metav1.TypeMeta{
61+
Kind: "HostSubnet",
62+
},
63+
ObjectMeta: metav1.ObjectMeta{
64+
Name: name,
65+
UID: ktypes.UID(name + "-uid"),
66+
},
67+
Host: name,
68+
HostIP: hostIP,
69+
Subnet: subnet,
70+
}
71+
}
72+
73+
func TestHostSubnetWatcher(t *testing.T) {
74+
hsw, flows := setupHostSubnetWatcher(t)
75+
76+
hs1 := makeHostSubnet("node1", "192.168.0.2", "10.128.0.0/23")
77+
hs2 := makeHostSubnet("node2", "192.168.1.2", "10.129.0.0/23")
78+
79+
err := hsw.updateHostSubnet(hs1)
80+
if err != nil {
81+
t.Fatalf("Unexpected error adding HostSubnet: %v", err)
82+
}
83+
err = assertHostSubnetFlowChanges(hsw, &flows,
84+
flowChange{
85+
kind: flowAdded,
86+
match: []string{"table=10", "tun_src=192.168.0.2"},
87+
},
88+
flowChange{
89+
kind: flowAdded,
90+
match: []string{"table=50", "arp", "arp_tpa=10.128.0.0/23", "192.168.0.2->tun_dst"},
91+
},
92+
flowChange{
93+
kind: flowAdded,
94+
match: []string{"table=90", "ip", "nw_dst=10.128.0.0/23", "192.168.0.2->tun_dst"},
95+
},
96+
flowChange{
97+
kind: flowRemoved,
98+
match: []string{"table=111", "goto_table:120"},
99+
noMatch: []string{"->tun_dst"},
100+
},
101+
flowChange{
102+
kind: flowAdded,
103+
match: []string{"table=111", "192.168.0.2->tun_dst"},
104+
},
105+
)
106+
if err != nil {
107+
t.Fatalf("%v", err)
108+
}
109+
110+
err = hsw.updateHostSubnet(hs2)
111+
if err != nil {
112+
t.Fatalf("Unexpected error adding HostSubnet: %v", err)
113+
}
114+
err = assertHostSubnetFlowChanges(hsw, &flows,
115+
flowChange{
116+
kind: flowAdded,
117+
match: []string{"table=10", "tun_src=192.168.1.2"},
118+
},
119+
flowChange{
120+
kind: flowAdded,
121+
match: []string{"table=50", "arp", "arp_tpa=10.129.0.0/23", "192.168.1.2->tun_dst"},
122+
},
123+
flowChange{
124+
kind: flowAdded,
125+
match: []string{"table=90", "ip", "nw_dst=10.129.0.0/23", "192.168.1.2->tun_dst"},
126+
},
127+
flowChange{
128+
kind: flowRemoved,
129+
match: []string{"table=111", "192.168.0.2->tun_dst"},
130+
},
131+
flowChange{
132+
kind: flowAdded,
133+
match: []string{"table=111", "192.168.0.2->tun_dst", "192.168.1.2->tun_dst"},
134+
},
135+
)
136+
if err != nil {
137+
t.Fatalf("%v", err)
138+
}
139+
140+
err = hsw.deleteHostSubnet(hs1)
141+
if err != nil {
142+
t.Fatalf("Unexpected error deleting HostSubnet: %v", err)
143+
}
144+
err = assertHostSubnetFlowChanges(hsw, &flows,
145+
flowChange{
146+
kind: flowRemoved,
147+
match: []string{"table=10", "tun_src=192.168.0.2"},
148+
},
149+
flowChange{
150+
kind: flowRemoved,
151+
match: []string{"table=50", "arp", "arp_tpa=10.128.0.0/23", "192.168.0.2->tun_dst"},
152+
},
153+
flowChange{
154+
kind: flowRemoved,
155+
match: []string{"table=90", "ip", "nw_dst=10.128.0.0/23", "192.168.0.2->tun_dst"},
156+
},
157+
flowChange{
158+
kind: flowRemoved,
159+
match: []string{"table=111", "192.168.0.2->tun_dst", "192.168.1.2->tun_dst"},
160+
},
161+
flowChange{
162+
kind: flowAdded,
163+
match: []string{"table=111", "192.168.1.2->tun_dst"},
164+
noMatch: []string{"192.168.0.2"},
165+
},
166+
)
167+
if err != nil {
168+
t.Fatalf("%v", err)
169+
}
170+
171+
err = hsw.deleteHostSubnet(hs2)
172+
if err != nil {
173+
t.Fatalf("Unexpected error deleting HostSubnet: %v", err)
174+
}
175+
err = assertHostSubnetFlowChanges(hsw, &flows,
176+
flowChange{
177+
kind: flowRemoved,
178+
match: []string{"table=10", "tun_src=192.168.1.2"},
179+
},
180+
flowChange{
181+
kind: flowRemoved,
182+
match: []string{"table=50", "arp", "arp_tpa=10.129.0.0/23", "192.168.1.2->tun_dst"},
183+
},
184+
flowChange{
185+
kind: flowRemoved,
186+
match: []string{"table=90", "ip", "nw_dst=10.129.0.0/23", "192.168.1.2->tun_dst"},
187+
},
188+
flowChange{
189+
kind: flowRemoved,
190+
match: []string{"table=111", "192.168.1.2->tun_dst"},
191+
},
192+
flowChange{
193+
kind: flowAdded,
194+
match: []string{"table=111", "goto_table:120"},
195+
noMatch: []string{"tun_dst"},
196+
},
197+
)
198+
if err != nil {
199+
t.Fatalf("%v", err)
200+
}
201+
}
202+
203+
func TestHostSubnetReassignment(t *testing.T) {
204+
hsw, flows := setupHostSubnetWatcher(t)
205+
206+
hs1orig := makeHostSubnet("node1", "192.168.0.2", "10.128.0.0/23")
207+
hs2orig := makeHostSubnet("node2", "192.168.1.2", "10.129.0.0/23")
208+
209+
// Create original HostSubnets
210+
211+
err := hsw.updateHostSubnet(hs1orig)
212+
if err != nil {
213+
t.Fatalf("Unexpected error adding HostSubnet: %v", err)
214+
}
215+
err = hsw.updateHostSubnet(hs2orig)
216+
if err != nil {
217+
t.Fatalf("Unexpected error adding HostSubnet: %v", err)
218+
}
219+
220+
err = assertHostSubnetFlowChanges(hsw, &flows,
221+
flowChange{
222+
kind: flowAdded,
223+
match: []string{"table=10", "tun_src=192.168.0.2"},
224+
},
225+
flowChange{
226+
kind: flowAdded,
227+
match: []string{"table=10", "tun_src=192.168.1.2"},
228+
},
229+
flowChange{
230+
kind: flowAdded,
231+
match: []string{"table=50", "arp", "arp_tpa=10.128.0.0/23", "192.168.0.2->tun_dst"},
232+
},
233+
flowChange{
234+
kind: flowAdded,
235+
match: []string{"table=50", "arp", "arp_tpa=10.129.0.0/23", "192.168.1.2->tun_dst"},
236+
},
237+
flowChange{
238+
kind: flowAdded,
239+
match: []string{"table=90", "ip", "nw_dst=10.128.0.0/23", "192.168.0.2->tun_dst"},
240+
},
241+
flowChange{
242+
kind: flowAdded,
243+
match: []string{"table=90", "ip", "nw_dst=10.129.0.0/23", "192.168.1.2->tun_dst"},
244+
},
245+
flowChange{
246+
kind: flowRemoved,
247+
match: []string{"table=111", "goto_table:120"},
248+
noMatch: []string{"->tun_dst"},
249+
},
250+
flowChange{
251+
kind: flowAdded,
252+
match: []string{"table=111", "192.168.0.2->tun_dst", "192.168.1.2->tun_dst"},
253+
},
254+
)
255+
if err != nil {
256+
t.Fatalf("%v", err)
257+
}
258+
259+
// Now both nodes go offline (without their Node objects being deleted), reboot and
260+
// get assigned the opposite IPs after reboot. They reregister with the master, which
261+
// updates their Node IPs, which causes the SDN master to update their HostSubnets.
262+
// After the first update, we'll have two HostSubnets with the same HostIP, which
263+
// used to cause us to break things when we got the second update.
264+
265+
hs1new := hs1orig.DeepCopy()
266+
hs1new.HostIP = hs2orig.HostIP
267+
hs2new := hs2orig.DeepCopy()
268+
hs2new.HostIP = hs1orig.HostIP
269+
270+
err = hsw.updateHostSubnet(hs1new)
271+
if err != nil {
272+
t.Fatalf("Unexpected error adding HostSubnet: %v", err)
273+
}
274+
err = hsw.updateHostSubnet(hs2new)
275+
if err != nil {
276+
t.Fatalf("Unexpected error adding HostSubnet: %v", err)
277+
}
278+
279+
err = assertHostSubnetFlowChanges(hsw, &flows,
280+
// (We have to check for these table=10 removes+adds because they're not
281+
// actually identical; the cookies will have changed.)
282+
flowChange{
283+
kind: flowRemoved,
284+
match: []string{"table=10", "tun_src=192.168.0.2"},
285+
},
286+
flowChange{
287+
kind: flowAdded,
288+
match: []string{"table=10", "tun_src=192.168.0.2"},
289+
},
290+
flowChange{
291+
kind: flowRemoved,
292+
match: []string{"table=10", "tun_src=192.168.1.2"},
293+
},
294+
flowChange{
295+
kind: flowAdded,
296+
match: []string{"table=10", "tun_src=192.168.1.2"},
297+
},
298+
299+
flowChange{
300+
kind: flowRemoved,
301+
match: []string{"table=50", "arp", "arp_tpa=10.128.0.0/23", "192.168.0.2->tun_dst"},
302+
},
303+
flowChange{
304+
kind: flowAdded,
305+
match: []string{"table=50", "arp", "arp_tpa=10.128.0.0/23", "192.168.1.2->tun_dst"},
306+
},
307+
308+
flowChange{
309+
kind: flowRemoved,
310+
match: []string{"table=50", "arp", "arp_tpa=10.129.0.0/23", "192.168.1.2->tun_dst"},
311+
},
312+
flowChange{
313+
kind: flowAdded,
314+
match: []string{"table=50", "arp", "arp_tpa=10.129.0.0/23", "192.168.0.2->tun_dst"},
315+
},
316+
317+
flowChange{
318+
kind: flowRemoved,
319+
match: []string{"table=90", "ip", "nw_dst=10.128.0.0/23", "192.168.0.2->tun_dst"},
320+
},
321+
flowChange{
322+
kind: flowAdded,
323+
match: []string{"table=90", "ip", "nw_dst=10.128.0.0/23", "192.168.1.2->tun_dst"},
324+
},
325+
326+
flowChange{
327+
kind: flowRemoved,
328+
match: []string{"table=90", "ip", "nw_dst=10.129.0.0/23", "192.168.1.2->tun_dst"},
329+
},
330+
flowChange{
331+
kind: flowAdded,
332+
match: []string{"table=90", "ip", "nw_dst=10.129.0.0/23", "192.168.0.2->tun_dst"},
333+
},
334+
)
335+
if err != nil {
336+
t.Fatalf("%v", err)
337+
}
338+
}

0 commit comments

Comments
 (0)
Please sign in to comment.