github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/ipvs/ipvs_test.go (about) 1 // +build linux 2 3 package ipvs 4 5 import ( 6 "fmt" 7 "net" 8 "os/exec" 9 "strings" 10 "syscall" 11 "testing" 12 13 "github.com/docker/libnetwork/testutils" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 "github.com/vishvananda/netlink" 17 "github.com/vishvananda/netlink/nl" 18 ) 19 20 var ( 21 schedMethods = []string{ 22 RoundRobin, 23 LeastConnection, 24 DestinationHashing, 25 SourceHashing, 26 } 27 28 protocols = []string{ 29 "TCP", 30 "UDP", 31 "FWM", 32 } 33 34 fwdMethods = []uint32{ 35 ConnectionFlagMasq, 36 ConnectionFlagTunnel, 37 ConnectionFlagDirectRoute, 38 } 39 40 fwdMethodStrings = []string{ 41 "Masq", 42 "Tunnel", 43 "Route", 44 } 45 ) 46 47 func checkDestination(t *testing.T, checkPresent bool, protocol, serviceAddress, realAddress, fwdMethod string) { 48 var ( 49 realServerStart bool 50 realServers []string 51 ) 52 53 out, err := exec.Command("ipvsadm", "-Ln").CombinedOutput() 54 require.NoError(t, err) 55 56 for _, o := range strings.Split(string(out), "\n") { 57 cmpStr := serviceAddress 58 if protocol == "FWM" { 59 cmpStr = " " + cmpStr 60 } 61 62 if strings.Contains(o, cmpStr) { 63 realServerStart = true 64 continue 65 } 66 67 if realServerStart { 68 if !strings.Contains(o, "->") { 69 break 70 } 71 72 realServers = append(realServers, o) 73 } 74 } 75 76 for _, r := range realServers { 77 if strings.Contains(r, realAddress) { 78 parts := strings.Fields(r) 79 assert.Equal(t, fwdMethod, parts[2]) 80 return 81 } 82 } 83 84 if checkPresent { 85 t.Fatalf("Did not find the destination %s fwdMethod %s in ipvs output", realAddress, fwdMethod) 86 } 87 } 88 89 func checkService(t *testing.T, checkPresent bool, protocol, schedMethod, serviceAddress string) { 90 out, err := exec.Command("ipvsadm", "-Ln").CombinedOutput() 91 require.NoError(t, err) 92 93 for _, o := range strings.Split(string(out), "\n") { 94 cmpStr := serviceAddress 95 if protocol == "FWM" { 96 cmpStr = " " + cmpStr 97 } 98 99 if strings.Contains(o, cmpStr) { 100 parts := strings.Split(o, " ") 101 assert.Equal(t, protocol, parts[0]) 102 assert.Equal(t, serviceAddress, parts[2]) 103 assert.Equal(t, schedMethod, parts[3]) 104 105 if !checkPresent { 106 t.Fatalf("Did not expect the service %s in ipvs output", serviceAddress) 107 } 108 109 return 110 } 111 } 112 113 if checkPresent { 114 t.Fatalf("Did not find the service %s in ipvs output", serviceAddress) 115 } 116 } 117 118 func TestGetFamily(t *testing.T) { 119 if testutils.RunningOnCircleCI() { 120 t.Skipf("Skipping as not supported on CIRCLE CI kernel") 121 } 122 123 id, err := getIPVSFamily() 124 require.NoError(t, err) 125 assert.NotEqual(t, 0, id) 126 } 127 128 func TestService(t *testing.T) { 129 if testutils.RunningOnCircleCI() { 130 t.Skipf("Skipping as not supported on CIRCLE CI kernel") 131 } 132 133 defer testutils.SetupTestOSContext(t)() 134 135 i, err := New("") 136 require.NoError(t, err) 137 138 for _, protocol := range protocols { 139 for _, schedMethod := range schedMethods { 140 var serviceAddress string 141 142 s := Service{ 143 AddressFamily: nl.FAMILY_V4, 144 SchedName: schedMethod, 145 } 146 147 switch protocol { 148 case "FWM": 149 s.FWMark = 1234 150 serviceAddress = fmt.Sprintf("%d", 1234) 151 case "TCP": 152 s.Protocol = syscall.IPPROTO_TCP 153 s.Port = 80 154 s.Address = net.ParseIP("1.2.3.4") 155 s.Netmask = 0xFFFFFFFF 156 serviceAddress = "1.2.3.4:80" 157 case "UDP": 158 s.Protocol = syscall.IPPROTO_UDP 159 s.Port = 53 160 s.Address = net.ParseIP("2.3.4.5") 161 serviceAddress = "2.3.4.5:53" 162 } 163 164 err := i.NewService(&s) 165 assert.NoError(t, err) 166 checkService(t, true, protocol, schedMethod, serviceAddress) 167 var lastMethod string 168 for _, updateSchedMethod := range schedMethods { 169 if updateSchedMethod == schedMethod { 170 continue 171 } 172 173 s.SchedName = updateSchedMethod 174 err = i.UpdateService(&s) 175 assert.NoError(t, err) 176 checkService(t, true, protocol, updateSchedMethod, serviceAddress) 177 lastMethod = updateSchedMethod 178 } 179 180 err = i.DelService(&s) 181 checkService(t, false, protocol, lastMethod, serviceAddress) 182 } 183 } 184 185 } 186 187 func createDummyInterface(t *testing.T) { 188 if testutils.RunningOnCircleCI() { 189 t.Skipf("Skipping as not supported on CIRCLE CI kernel") 190 } 191 192 dummy := &netlink.Dummy{ 193 LinkAttrs: netlink.LinkAttrs{ 194 Name: "dummy", 195 }, 196 } 197 198 err := netlink.LinkAdd(dummy) 199 require.NoError(t, err) 200 201 dummyLink, err := netlink.LinkByName("dummy") 202 require.NoError(t, err) 203 204 ip, ipNet, err := net.ParseCIDR("10.1.1.1/24") 205 require.NoError(t, err) 206 207 ipNet.IP = ip 208 209 ipAddr := &netlink.Addr{IPNet: ipNet, Label: ""} 210 err = netlink.AddrAdd(dummyLink, ipAddr) 211 require.NoError(t, err) 212 } 213 214 func TestDestination(t *testing.T) { 215 defer testutils.SetupTestOSContext(t)() 216 217 createDummyInterface(t) 218 i, err := New("") 219 require.NoError(t, err) 220 221 for _, protocol := range protocols { 222 var serviceAddress string 223 224 s := Service{ 225 AddressFamily: nl.FAMILY_V4, 226 SchedName: RoundRobin, 227 } 228 229 switch protocol { 230 case "FWM": 231 s.FWMark = 1234 232 serviceAddress = fmt.Sprintf("%d", 1234) 233 case "TCP": 234 s.Protocol = syscall.IPPROTO_TCP 235 s.Port = 80 236 s.Address = net.ParseIP("1.2.3.4") 237 s.Netmask = 0xFFFFFFFF 238 serviceAddress = "1.2.3.4:80" 239 case "UDP": 240 s.Protocol = syscall.IPPROTO_UDP 241 s.Port = 53 242 s.Address = net.ParseIP("2.3.4.5") 243 serviceAddress = "2.3.4.5:53" 244 } 245 246 err := i.NewService(&s) 247 assert.NoError(t, err) 248 checkService(t, true, protocol, RoundRobin, serviceAddress) 249 250 s.SchedName = "" 251 for j, fwdMethod := range fwdMethods { 252 d1 := Destination{ 253 AddressFamily: nl.FAMILY_V4, 254 Address: net.ParseIP("10.1.1.2"), 255 Port: 5000, 256 Weight: 1, 257 ConnectionFlags: fwdMethod, 258 } 259 260 realAddress := "10.1.1.2:5000" 261 err := i.NewDestination(&s, &d1) 262 assert.NoError(t, err) 263 checkDestination(t, true, protocol, serviceAddress, realAddress, fwdMethodStrings[j]) 264 d2 := Destination{ 265 AddressFamily: nl.FAMILY_V4, 266 Address: net.ParseIP("10.1.1.3"), 267 Port: 5000, 268 Weight: 1, 269 ConnectionFlags: fwdMethod, 270 } 271 272 realAddress = "10.1.1.3:5000" 273 err = i.NewDestination(&s, &d2) 274 assert.NoError(t, err) 275 checkDestination(t, true, protocol, serviceAddress, realAddress, fwdMethodStrings[j]) 276 277 d3 := Destination{ 278 AddressFamily: nl.FAMILY_V4, 279 Address: net.ParseIP("10.1.1.4"), 280 Port: 5000, 281 Weight: 1, 282 ConnectionFlags: fwdMethod, 283 } 284 285 realAddress = "10.1.1.4:5000" 286 err = i.NewDestination(&s, &d3) 287 assert.NoError(t, err) 288 checkDestination(t, true, protocol, serviceAddress, realAddress, fwdMethodStrings[j]) 289 290 for m, updateFwdMethod := range fwdMethods { 291 if updateFwdMethod == fwdMethod { 292 continue 293 } 294 d1.ConnectionFlags = updateFwdMethod 295 realAddress = "10.1.1.2:5000" 296 err = i.UpdateDestination(&s, &d1) 297 assert.NoError(t, err) 298 checkDestination(t, true, protocol, serviceAddress, realAddress, fwdMethodStrings[m]) 299 300 d2.ConnectionFlags = updateFwdMethod 301 realAddress = "10.1.1.3:5000" 302 err = i.UpdateDestination(&s, &d2) 303 assert.NoError(t, err) 304 checkDestination(t, true, protocol, serviceAddress, realAddress, fwdMethodStrings[m]) 305 306 d3.ConnectionFlags = updateFwdMethod 307 realAddress = "10.1.1.4:5000" 308 err = i.UpdateDestination(&s, &d3) 309 assert.NoError(t, err) 310 checkDestination(t, true, protocol, serviceAddress, realAddress, fwdMethodStrings[m]) 311 } 312 313 err = i.DelDestination(&s, &d1) 314 assert.NoError(t, err) 315 err = i.DelDestination(&s, &d2) 316 assert.NoError(t, err) 317 err = i.DelDestination(&s, &d3) 318 assert.NoError(t, err) 319 } 320 } 321 }