docker_cli_network_unix_test.go 71 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787
  1. //go:build !windows
  2. package main
  3. import (
  4. "encoding/json"
  5. "fmt"
  6. "net"
  7. "net/http"
  8. "net/http/httptest"
  9. "os"
  10. "strings"
  11. "testing"
  12. "time"
  13. "github.com/docker/docker/api/types"
  14. "github.com/docker/docker/api/types/versions/v1p20"
  15. "github.com/docker/docker/integration-cli/cli"
  16. "github.com/docker/docker/integration-cli/daemon"
  17. "github.com/docker/docker/libnetwork/driverapi"
  18. remoteapi "github.com/docker/docker/libnetwork/drivers/remote/api"
  19. "github.com/docker/docker/libnetwork/ipamapi"
  20. remoteipam "github.com/docker/docker/libnetwork/ipams/remote/api"
  21. "github.com/docker/docker/libnetwork/netlabel"
  22. "github.com/docker/docker/pkg/stringid"
  23. "github.com/docker/docker/runconfig"
  24. testdaemon "github.com/docker/docker/testutil/daemon"
  25. "github.com/vishvananda/netlink"
  26. "golang.org/x/sys/unix"
  27. "gotest.tools/v3/assert"
  28. "gotest.tools/v3/icmd"
  29. )
  30. const (
  31. dummyNetworkDriver = "dummy-network-driver"
  32. dummyIPAMDriver = "dummy-ipam-driver"
  33. )
  34. var remoteDriverNetworkRequest remoteapi.CreateNetworkRequest
  35. func (s *DockerNetworkSuite) SetUpTest(c *testing.T) {
  36. s.d = daemon.New(c, dockerBinary, dockerdBinary, testdaemon.WithEnvironment(testEnv.Execution))
  37. }
  38. func (s *DockerNetworkSuite) TearDownTest(c *testing.T) {
  39. if s.d != nil {
  40. s.d.Stop(c)
  41. s.ds.TearDownTest(c)
  42. }
  43. }
  44. func (s *DockerNetworkSuite) SetUpSuite(c *testing.T) {
  45. mux := http.NewServeMux()
  46. s.server = httptest.NewServer(mux)
  47. assert.Assert(c, s.server != nil, "Failed to start an HTTP Server")
  48. setupRemoteNetworkDrivers(c, mux, s.server.URL, dummyNetworkDriver, dummyIPAMDriver)
  49. }
  50. func setupRemoteNetworkDrivers(c *testing.T, mux *http.ServeMux, url, netDrv, ipamDrv string) {
  51. mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) {
  52. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  53. fmt.Fprintf(w, `{"Implements": ["%s", "%s"]}`, driverapi.NetworkPluginEndpointType, ipamapi.PluginEndpointType)
  54. })
  55. // Network driver implementation
  56. mux.HandleFunc(fmt.Sprintf("/%s.GetCapabilities", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  57. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  58. fmt.Fprintf(w, `{"Scope":"local"}`)
  59. })
  60. mux.HandleFunc(fmt.Sprintf("/%s.CreateNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  61. err := json.NewDecoder(r.Body).Decode(&remoteDriverNetworkRequest)
  62. if err != nil {
  63. http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
  64. return
  65. }
  66. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  67. fmt.Fprintf(w, "null")
  68. })
  69. mux.HandleFunc(fmt.Sprintf("/%s.DeleteNetwork", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  70. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  71. fmt.Fprintf(w, "null")
  72. })
  73. mux.HandleFunc(fmt.Sprintf("/%s.CreateEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  74. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  75. fmt.Fprintf(w, `{"Interface":{"MacAddress":"a0:b1:c2:d3:e4:f5"}}`)
  76. })
  77. mux.HandleFunc(fmt.Sprintf("/%s.Join", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  78. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  79. veth := &netlink.Veth{
  80. LinkAttrs: netlink.LinkAttrs{Name: "randomIfName", TxQLen: 0}, PeerName: "cnt0",
  81. }
  82. if err := netlink.LinkAdd(veth); err != nil {
  83. fmt.Fprintf(w, `{"Error":"failed to add veth pair: `+err.Error()+`"}`)
  84. } else {
  85. fmt.Fprintf(w, `{"InterfaceName":{ "SrcName":"cnt0", "DstPrefix":"veth"}}`)
  86. }
  87. })
  88. mux.HandleFunc(fmt.Sprintf("/%s.Leave", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  89. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  90. fmt.Fprintf(w, "null")
  91. })
  92. mux.HandleFunc(fmt.Sprintf("/%s.DeleteEndpoint", driverapi.NetworkPluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  93. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  94. if link, err := netlink.LinkByName("cnt0"); err == nil {
  95. netlink.LinkDel(link)
  96. }
  97. fmt.Fprintf(w, "null")
  98. })
  99. // IPAM Driver implementation
  100. var (
  101. poolRequest remoteipam.RequestPoolRequest
  102. poolReleaseReq remoteipam.ReleasePoolRequest
  103. addressRequest remoteipam.RequestAddressRequest
  104. addressReleaseReq remoteipam.ReleaseAddressRequest
  105. lAS = "localAS"
  106. gAS = "globalAS"
  107. pool = "172.28.0.0/16"
  108. poolID = lAS + "/" + pool
  109. gw = "172.28.255.254/16"
  110. )
  111. mux.HandleFunc(fmt.Sprintf("/%s.GetDefaultAddressSpaces", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  112. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  113. fmt.Fprintf(w, `{"LocalDefaultAddressSpace":"`+lAS+`", "GlobalDefaultAddressSpace": "`+gAS+`"}`)
  114. })
  115. mux.HandleFunc(fmt.Sprintf("/%s.RequestPool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  116. err := json.NewDecoder(r.Body).Decode(&poolRequest)
  117. if err != nil {
  118. http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
  119. return
  120. }
  121. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  122. if poolRequest.AddressSpace != lAS && poolRequest.AddressSpace != gAS {
  123. fmt.Fprintf(w, `{"Error":"Unknown address space in pool request: `+poolRequest.AddressSpace+`"}`)
  124. } else if poolRequest.Pool != "" && poolRequest.Pool != pool {
  125. fmt.Fprintf(w, `{"Error":"Cannot handle explicit pool requests yet"}`)
  126. } else {
  127. fmt.Fprintf(w, `{"PoolID":"`+poolID+`", "Pool":"`+pool+`"}`)
  128. }
  129. })
  130. mux.HandleFunc(fmt.Sprintf("/%s.RequestAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  131. err := json.NewDecoder(r.Body).Decode(&addressRequest)
  132. if err != nil {
  133. http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
  134. return
  135. }
  136. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  137. // make sure libnetwork is now querying on the expected pool id
  138. if addressRequest.PoolID != poolID {
  139. fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
  140. } else if addressRequest.Address != "" {
  141. fmt.Fprintf(w, `{"Error":"Cannot handle explicit address requests yet"}`)
  142. } else {
  143. fmt.Fprintf(w, `{"Address":"`+gw+`"}`)
  144. }
  145. })
  146. mux.HandleFunc(fmt.Sprintf("/%s.ReleaseAddress", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  147. err := json.NewDecoder(r.Body).Decode(&addressReleaseReq)
  148. if err != nil {
  149. http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
  150. return
  151. }
  152. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  153. // make sure libnetwork is now asking to release the expected address from the expected poolid
  154. if addressRequest.PoolID != poolID {
  155. fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
  156. } else if addressReleaseReq.Address != gw {
  157. fmt.Fprintf(w, `{"Error":"unknown address"}`)
  158. } else {
  159. fmt.Fprintf(w, "null")
  160. }
  161. })
  162. mux.HandleFunc(fmt.Sprintf("/%s.ReleasePool", ipamapi.PluginEndpointType), func(w http.ResponseWriter, r *http.Request) {
  163. err := json.NewDecoder(r.Body).Decode(&poolReleaseReq)
  164. if err != nil {
  165. http.Error(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
  166. return
  167. }
  168. w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1+json")
  169. // make sure libnetwork is now asking to release the expected poolid
  170. if addressRequest.PoolID != poolID {
  171. fmt.Fprintf(w, `{"Error":"unknown pool id"}`)
  172. } else {
  173. fmt.Fprintf(w, "null")
  174. }
  175. })
  176. err := os.MkdirAll("/etc/docker/plugins", 0o755)
  177. assert.NilError(c, err)
  178. fileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", netDrv)
  179. err = os.WriteFile(fileName, []byte(url), 0o644)
  180. assert.NilError(c, err)
  181. ipamFileName := fmt.Sprintf("/etc/docker/plugins/%s.spec", ipamDrv)
  182. err = os.WriteFile(ipamFileName, []byte(url), 0o644)
  183. assert.NilError(c, err)
  184. }
  185. func (s *DockerNetworkSuite) TearDownSuite(c *testing.T) {
  186. if s.server == nil {
  187. return
  188. }
  189. s.server.Close()
  190. err := os.RemoveAll("/etc/docker/plugins")
  191. assert.NilError(c, err)
  192. }
  193. func assertNwIsAvailable(c *testing.T, name string) {
  194. if !isNwPresent(c, name) {
  195. c.Fatalf("Network %s not found in network ls o/p", name)
  196. }
  197. }
  198. func assertNwNotAvailable(c *testing.T, name string) {
  199. if isNwPresent(c, name) {
  200. c.Fatalf("Found network %s in network ls o/p", name)
  201. }
  202. }
  203. func isNwPresent(c *testing.T, name string) bool {
  204. out, _ := dockerCmd(c, "network", "ls")
  205. lines := strings.Split(out, "\n")
  206. for i := 1; i < len(lines)-1; i++ {
  207. netFields := strings.Fields(lines[i])
  208. if netFields[1] == name {
  209. return true
  210. }
  211. }
  212. return false
  213. }
  214. // assertNwList checks network list retrieved with ls command
  215. // equals to expected network list
  216. // note: out should be `network ls [option]` result
  217. func assertNwList(c *testing.T, out string, expectNws []string) {
  218. lines := strings.Split(out, "\n")
  219. var nwList []string
  220. for _, line := range lines[1 : len(lines)-1] {
  221. netFields := strings.Fields(line)
  222. // wrap all network name in nwList
  223. nwList = append(nwList, netFields[1])
  224. }
  225. // network ls should contains all expected networks
  226. assert.DeepEqual(c, nwList, expectNws)
  227. }
  228. func getNwResource(c *testing.T, name string) *types.NetworkResource {
  229. out, _ := dockerCmd(c, "network", "inspect", name)
  230. var nr []types.NetworkResource
  231. err := json.Unmarshal([]byte(out), &nr)
  232. assert.NilError(c, err)
  233. return &nr[0]
  234. }
  235. func (s *DockerNetworkSuite) TestDockerNetworkLsDefault(c *testing.T) {
  236. defaults := []string{"bridge", "host", "none"}
  237. for _, nn := range defaults {
  238. assertNwIsAvailable(c, nn)
  239. }
  240. }
  241. func (s *DockerNetworkSuite) TestDockerNetworkCreatePredefined(c *testing.T) {
  242. predefined := []string{"bridge", "host", "none", "default"}
  243. for _, net := range predefined {
  244. // predefined networks can't be created again
  245. out, _, err := dockerCmdWithError("network", "create", net)
  246. assert.ErrorContains(c, err, "", out)
  247. }
  248. }
  249. func (s *DockerNetworkSuite) TestDockerNetworkCreateHostBind(c *testing.T) {
  250. dockerCmd(c, "network", "create", "--subnet=192.168.10.0/24", "--gateway=192.168.10.1", "-o", "com.docker.network.bridge.host_binding_ipv4=192.168.10.1", "testbind")
  251. assertNwIsAvailable(c, "testbind")
  252. out := runSleepingContainer(c, "--net=testbind", "-p", "5000:5000")
  253. id := strings.TrimSpace(out)
  254. assert.NilError(c, waitRun(id))
  255. out, _ = dockerCmd(c, "ps")
  256. assert.Assert(c, strings.Contains(out, "192.168.10.1:5000->5000/tcp"))
  257. }
  258. func (s *DockerNetworkSuite) TestDockerNetworkRmPredefined(c *testing.T) {
  259. predefined := []string{"bridge", "host", "none", "default"}
  260. for _, net := range predefined {
  261. // predefined networks can't be removed
  262. out, _, err := dockerCmdWithError("network", "rm", net)
  263. assert.ErrorContains(c, err, "", out)
  264. }
  265. }
  266. func (s *DockerNetworkSuite) TestDockerNetworkLsFilter(c *testing.T) {
  267. testRequires(c, OnlyDefaultNetworks)
  268. testNet := "testnet1"
  269. testLabel := "foo"
  270. testValue := "bar"
  271. out, _ := dockerCmd(c, "network", "create", "dev")
  272. defer func() {
  273. dockerCmd(c, "network", "rm", "dev")
  274. dockerCmd(c, "network", "rm", testNet)
  275. }()
  276. networkID := strings.TrimSpace(out)
  277. // filter with partial ID
  278. // only show 'dev' network
  279. out, _ = dockerCmd(c, "network", "ls", "-f", "id="+networkID[0:5])
  280. assertNwList(c, out, []string{"dev"})
  281. out, _ = dockerCmd(c, "network", "ls", "-f", "name=dge")
  282. assertNwList(c, out, []string{"bridge"})
  283. // only show built-in network (bridge, none, host)
  284. out, _ = dockerCmd(c, "network", "ls", "-f", "type=builtin")
  285. assertNwList(c, out, []string{"bridge", "host", "none"})
  286. // only show custom networks (dev)
  287. out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom")
  288. assertNwList(c, out, []string{"dev"})
  289. // show all networks with filter
  290. // it should be equivalent of ls without option
  291. out, _ = dockerCmd(c, "network", "ls", "-f", "type=custom", "-f", "type=builtin")
  292. assertNwList(c, out, []string{"bridge", "dev", "host", "none"})
  293. dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
  294. assertNwIsAvailable(c, testNet)
  295. out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel)
  296. assertNwList(c, out, []string{testNet})
  297. out, _ = dockerCmd(c, "network", "ls", "-f", "label="+testLabel+"="+testValue)
  298. assertNwList(c, out, []string{testNet})
  299. out, _ = dockerCmd(c, "network", "ls", "-f", "label=nonexistent")
  300. outArr := strings.Split(strings.TrimSpace(out), "\n")
  301. assert.Equal(c, len(outArr), 1, fmt.Sprintf("%s\n", out))
  302. out, _ = dockerCmd(c, "network", "ls", "-f", "driver=null")
  303. assertNwList(c, out, []string{"none"})
  304. out, _ = dockerCmd(c, "network", "ls", "-f", "driver=host")
  305. assertNwList(c, out, []string{"host"})
  306. out, _ = dockerCmd(c, "network", "ls", "-f", "driver=bridge")
  307. assertNwList(c, out, []string{"bridge", "dev", testNet})
  308. }
  309. func (s *DockerNetworkSuite) TestDockerNetworkCreateDelete(c *testing.T) {
  310. dockerCmd(c, "network", "create", "test")
  311. assertNwIsAvailable(c, "test")
  312. dockerCmd(c, "network", "rm", "test")
  313. assertNwNotAvailable(c, "test")
  314. }
  315. func (s *DockerNetworkSuite) TestDockerNetworkCreateLabel(c *testing.T) {
  316. testNet := "testnetcreatelabel"
  317. testLabel := "foo"
  318. testValue := "bar"
  319. dockerCmd(c, "network", "create", "--label", testLabel+"="+testValue, testNet)
  320. assertNwIsAvailable(c, testNet)
  321. out, _, err := dockerCmdWithError("network", "inspect", "--format={{ .Labels."+testLabel+" }}", testNet)
  322. assert.NilError(c, err)
  323. assert.Equal(c, strings.TrimSpace(out), testValue)
  324. dockerCmd(c, "network", "rm", testNet)
  325. assertNwNotAvailable(c, testNet)
  326. }
  327. func (s *DockerCLINetworkSuite) TestDockerNetworkDeleteNotExists(c *testing.T) {
  328. out, _, err := dockerCmdWithError("network", "rm", "test")
  329. assert.ErrorContains(c, err, "", out)
  330. }
  331. func (s *DockerCLINetworkSuite) TestDockerNetworkDeleteMultiple(c *testing.T) {
  332. dockerCmd(c, "network", "create", "testDelMulti0")
  333. assertNwIsAvailable(c, "testDelMulti0")
  334. dockerCmd(c, "network", "create", "testDelMulti1")
  335. assertNwIsAvailable(c, "testDelMulti1")
  336. dockerCmd(c, "network", "create", "testDelMulti2")
  337. assertNwIsAvailable(c, "testDelMulti2")
  338. out, _ := dockerCmd(c, "run", "-d", "--net", "testDelMulti2", "busybox", "top")
  339. containerID := strings.TrimSpace(out)
  340. waitRun(containerID)
  341. // delete three networks at the same time, since testDelMulti2
  342. // contains active container, its deletion should fail.
  343. out, _, err := dockerCmdWithError("network", "rm", "testDelMulti0", "testDelMulti1", "testDelMulti2")
  344. // err should not be nil due to deleting testDelMulti2 failed.
  345. assert.Assert(c, err != nil, "out: %s", out)
  346. // testDelMulti2 should fail due to network has active endpoints
  347. assert.Assert(c, strings.Contains(out, "has active endpoints"))
  348. assertNwNotAvailable(c, "testDelMulti0")
  349. assertNwNotAvailable(c, "testDelMulti1")
  350. // testDelMulti2 can't be deleted, so it should exist
  351. assertNwIsAvailable(c, "testDelMulti2")
  352. }
  353. func (s *DockerCLINetworkSuite) TestDockerNetworkInspect(c *testing.T) {
  354. out, _ := dockerCmd(c, "network", "inspect", "host")
  355. var networkResources []types.NetworkResource
  356. err := json.Unmarshal([]byte(out), &networkResources)
  357. assert.NilError(c, err)
  358. assert.Equal(c, len(networkResources), 1)
  359. out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Name }}", "host")
  360. assert.Equal(c, strings.TrimSpace(out), "host")
  361. }
  362. func (s *DockerCLINetworkSuite) TestDockerNetworkInspectWithID(c *testing.T) {
  363. out, _ := dockerCmd(c, "network", "create", "test2")
  364. networkID := strings.TrimSpace(out)
  365. assertNwIsAvailable(c, "test2")
  366. out, _ = dockerCmd(c, "network", "inspect", "--format={{ .Id }}", "test2")
  367. assert.Equal(c, strings.TrimSpace(out), networkID)
  368. out, _ = dockerCmd(c, "network", "inspect", "--format={{ .ID }}", "test2")
  369. assert.Equal(c, strings.TrimSpace(out), networkID)
  370. }
  371. func (s *DockerCLINetworkSuite) TestDockerInspectMultipleNetwork(c *testing.T) {
  372. result := dockerCmdWithResult("network", "inspect", "host", "none")
  373. result.Assert(c, icmd.Success)
  374. var networkResources []types.NetworkResource
  375. err := json.Unmarshal([]byte(result.Stdout()), &networkResources)
  376. assert.NilError(c, err)
  377. assert.Equal(c, len(networkResources), 2)
  378. }
  379. func (s *DockerCLINetworkSuite) TestDockerInspectMultipleNetworksIncludingNonexistent(c *testing.T) {
  380. // non-existent network was not at the beginning of the inspect list
  381. // This should print an error, return an exitCode 1 and print the host network
  382. result := dockerCmdWithResult("network", "inspect", "host", "nonexistent")
  383. result.Assert(c, icmd.Expected{
  384. ExitCode: 1,
  385. Err: "Error: No such network: nonexistent",
  386. Out: "host",
  387. })
  388. var networkResources []types.NetworkResource
  389. err := json.Unmarshal([]byte(result.Stdout()), &networkResources)
  390. assert.NilError(c, err)
  391. assert.Equal(c, len(networkResources), 1)
  392. // Only one non-existent network to inspect
  393. // Should print an error and return an exitCode, nothing else
  394. result = dockerCmdWithResult("network", "inspect", "nonexistent")
  395. result.Assert(c, icmd.Expected{
  396. ExitCode: 1,
  397. Err: "Error: No such network: nonexistent",
  398. Out: "[]",
  399. })
  400. // non-existent network was at the beginning of the inspect list
  401. // Should not fail fast, and still print host network but print an error
  402. result = dockerCmdWithResult("network", "inspect", "nonexistent", "host")
  403. result.Assert(c, icmd.Expected{
  404. ExitCode: 1,
  405. Err: "Error: No such network: nonexistent",
  406. Out: "host",
  407. })
  408. networkResources = []types.NetworkResource{}
  409. err = json.Unmarshal([]byte(result.Stdout()), &networkResources)
  410. assert.NilError(c, err)
  411. assert.Equal(c, len(networkResources), 1)
  412. }
  413. func (s *DockerCLINetworkSuite) TestDockerInspectNetworkWithContainerName(c *testing.T) {
  414. dockerCmd(c, "network", "create", "brNetForInspect")
  415. assertNwIsAvailable(c, "brNetForInspect")
  416. defer func() {
  417. dockerCmd(c, "network", "rm", "brNetForInspect")
  418. assertNwNotAvailable(c, "brNetForInspect")
  419. }()
  420. out, _ := dockerCmd(c, "run", "-d", "--name", "testNetInspect1", "--net", "brNetForInspect", "busybox", "top")
  421. assert.Assert(c, waitRun("testNetInspect1") == nil)
  422. containerID := strings.TrimSpace(out)
  423. defer func() {
  424. // we don't stop container by name, because we'll rename it later
  425. dockerCmd(c, "stop", containerID)
  426. }()
  427. out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect")
  428. var networkResources []types.NetworkResource
  429. err := json.Unmarshal([]byte(out), &networkResources)
  430. assert.NilError(c, err)
  431. assert.Equal(c, len(networkResources), 1)
  432. container, ok := networkResources[0].Containers[containerID]
  433. assert.Assert(c, ok)
  434. assert.Equal(c, container.Name, "testNetInspect1")
  435. // rename container and check docker inspect output update
  436. newName := "HappyNewName"
  437. dockerCmd(c, "rename", "testNetInspect1", newName)
  438. // check whether network inspect works properly
  439. out, _ = dockerCmd(c, "network", "inspect", "brNetForInspect")
  440. var newNetRes []types.NetworkResource
  441. err = json.Unmarshal([]byte(out), &newNetRes)
  442. assert.NilError(c, err)
  443. assert.Equal(c, len(newNetRes), 1)
  444. container1, ok := newNetRes[0].Containers[containerID]
  445. assert.Assert(c, ok)
  446. assert.Equal(c, container1.Name, newName)
  447. }
  448. func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *testing.T) {
  449. dockerCmd(c, "network", "create", "test")
  450. assertNwIsAvailable(c, "test")
  451. nr := getNwResource(c, "test")
  452. assert.Equal(c, nr.Name, "test")
  453. assert.Equal(c, len(nr.Containers), 0)
  454. // run a container
  455. out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
  456. assert.Assert(c, waitRun("test") == nil)
  457. containerID := strings.TrimSpace(out)
  458. // connect the container to the test network
  459. dockerCmd(c, "network", "connect", "test", containerID)
  460. // inspect the network to make sure container is connected
  461. nr = getNetworkResource(c, nr.ID)
  462. assert.Equal(c, len(nr.Containers), 1)
  463. // check if container IP matches network inspect
  464. ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
  465. assert.NilError(c, err)
  466. containerIP := findContainerIP(c, "test", "test")
  467. assert.Equal(c, ip.String(), containerIP)
  468. // disconnect container from the network
  469. dockerCmd(c, "network", "disconnect", "test", containerID)
  470. nr = getNwResource(c, "test")
  471. assert.Equal(c, nr.Name, "test")
  472. assert.Equal(c, len(nr.Containers), 0)
  473. // run another container
  474. out, _ = dockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top")
  475. assert.Assert(c, waitRun("test2") == nil)
  476. containerID = strings.TrimSpace(out)
  477. nr = getNwResource(c, "test")
  478. assert.Equal(c, nr.Name, "test")
  479. assert.Equal(c, len(nr.Containers), 1)
  480. // force disconnect the container to the test network
  481. dockerCmd(c, "network", "disconnect", "-f", "test", containerID)
  482. nr = getNwResource(c, "test")
  483. assert.Equal(c, nr.Name, "test")
  484. assert.Equal(c, len(nr.Containers), 0)
  485. dockerCmd(c, "network", "rm", "test")
  486. assertNwNotAvailable(c, "test")
  487. }
  488. func (s *DockerNetworkSuite) TestDockerNetworkIPAMMultipleNetworks(c *testing.T) {
  489. testRequires(c, testEnv.IsLocalDaemon)
  490. // test0 bridge network
  491. dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test1")
  492. assertNwIsAvailable(c, "test1")
  493. // test2 bridge network does not overlap
  494. dockerCmd(c, "network", "create", "--subnet=192.169.0.0/16", "test2")
  495. assertNwIsAvailable(c, "test2")
  496. // for networks w/o ipam specified, docker will choose proper non-overlapping subnets
  497. dockerCmd(c, "network", "create", "test3")
  498. assertNwIsAvailable(c, "test3")
  499. dockerCmd(c, "network", "create", "test4")
  500. assertNwIsAvailable(c, "test4")
  501. dockerCmd(c, "network", "create", "test5")
  502. assertNwIsAvailable(c, "test5")
  503. // test network with multiple subnets
  504. // bridge network doesn't support multiple subnets. hence, use a dummy driver that supports
  505. dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "--subnet=192.170.0.0/16", "--subnet=192.171.0.0/16", "test6")
  506. assertNwIsAvailable(c, "test6")
  507. // test network with multiple subnets with valid ipam combinations
  508. // also check same subnet across networks when the driver supports it.
  509. dockerCmd(c, "network", "create", "-d", dummyNetworkDriver,
  510. "--subnet=192.172.0.0/16", "--subnet=192.173.0.0/16",
  511. "--gateway=192.172.0.100", "--gateway=192.173.0.100",
  512. "--ip-range=192.172.1.0/24",
  513. "--aux-address", "a=192.172.1.5", "--aux-address", "b=192.172.1.6",
  514. "--aux-address", "c=192.173.1.5", "--aux-address", "d=192.173.1.6",
  515. "test7")
  516. assertNwIsAvailable(c, "test7")
  517. // cleanup
  518. for i := 1; i < 8; i++ {
  519. dockerCmd(c, "network", "rm", fmt.Sprintf("test%d", i))
  520. }
  521. }
  522. func (s *DockerNetworkSuite) TestDockerNetworkCustomIPAM(c *testing.T) {
  523. testRequires(c, testEnv.IsLocalDaemon)
  524. // Create a bridge network using custom ipam driver
  525. dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "br0")
  526. assertNwIsAvailable(c, "br0")
  527. // Verify expected network ipam fields are there
  528. nr := getNetworkResource(c, "br0")
  529. assert.Equal(c, nr.Driver, "bridge")
  530. assert.Equal(c, nr.IPAM.Driver, dummyIPAMDriver)
  531. // remove network and exercise remote ipam driver
  532. dockerCmd(c, "network", "rm", "br0")
  533. assertNwNotAvailable(c, "br0")
  534. }
  535. func (s *DockerNetworkSuite) TestDockerNetworkIPAMOptions(c *testing.T) {
  536. testRequires(c, testEnv.IsLocalDaemon)
  537. // Create a bridge network using custom ipam driver and options
  538. dockerCmd(c, "network", "create", "--ipam-driver", dummyIPAMDriver, "--ipam-opt", "opt1=drv1", "--ipam-opt", "opt2=drv2", "br0")
  539. assertNwIsAvailable(c, "br0")
  540. // Verify expected network ipam options
  541. nr := getNetworkResource(c, "br0")
  542. opts := nr.IPAM.Options
  543. assert.Equal(c, opts["opt1"], "drv1")
  544. assert.Equal(c, opts["opt2"], "drv2")
  545. }
  546. func (s *DockerNetworkSuite) TestDockerNetworkNullIPAMDriver(c *testing.T) {
  547. testRequires(c, testEnv.IsLocalDaemon)
  548. // Create a network with null ipam driver
  549. _, _, err := dockerCmdWithError("network", "create", "-d", dummyNetworkDriver, "--ipam-driver", "null", "test000")
  550. assert.NilError(c, err)
  551. assertNwIsAvailable(c, "test000")
  552. // Verify the inspect data contains the default subnet provided by the null
  553. // ipam driver and no gateway, as the null ipam driver does not provide one
  554. nr := getNetworkResource(c, "test000")
  555. assert.Equal(c, nr.IPAM.Driver, "null")
  556. assert.Equal(c, len(nr.IPAM.Config), 1)
  557. assert.Equal(c, nr.IPAM.Config[0].Subnet, "0.0.0.0/0")
  558. assert.Equal(c, nr.IPAM.Config[0].Gateway, "")
  559. }
  560. func (s *DockerNetworkSuite) TestDockerNetworkInspectDefault(c *testing.T) {
  561. nr := getNetworkResource(c, "none")
  562. assert.Equal(c, nr.Driver, "null")
  563. assert.Equal(c, nr.Scope, "local")
  564. assert.Equal(c, nr.Internal, false)
  565. assert.Equal(c, nr.EnableIPv6, false)
  566. assert.Equal(c, nr.IPAM.Driver, "default")
  567. assert.Equal(c, len(nr.IPAM.Config), 0)
  568. nr = getNetworkResource(c, "host")
  569. assert.Equal(c, nr.Driver, "host")
  570. assert.Equal(c, nr.Scope, "local")
  571. assert.Equal(c, nr.Internal, false)
  572. assert.Equal(c, nr.EnableIPv6, false)
  573. assert.Equal(c, nr.IPAM.Driver, "default")
  574. assert.Equal(c, len(nr.IPAM.Config), 0)
  575. nr = getNetworkResource(c, "bridge")
  576. assert.Equal(c, nr.Driver, "bridge")
  577. assert.Equal(c, nr.Scope, "local")
  578. assert.Equal(c, nr.Internal, false)
  579. assert.Equal(c, nr.EnableIPv6, false)
  580. assert.Equal(c, nr.IPAM.Driver, "default")
  581. assert.Equal(c, len(nr.IPAM.Config), 1)
  582. }
  583. func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomUnspecified(c *testing.T) {
  584. // if unspecified, network subnet will be selected from inside preferred pool
  585. dockerCmd(c, "network", "create", "test01")
  586. assertNwIsAvailable(c, "test01")
  587. nr := getNetworkResource(c, "test01")
  588. assert.Equal(c, nr.Driver, "bridge")
  589. assert.Equal(c, nr.Scope, "local")
  590. assert.Equal(c, nr.Internal, false)
  591. assert.Equal(c, nr.EnableIPv6, false)
  592. assert.Equal(c, nr.IPAM.Driver, "default")
  593. assert.Equal(c, len(nr.IPAM.Config), 1)
  594. dockerCmd(c, "network", "rm", "test01")
  595. assertNwNotAvailable(c, "test01")
  596. }
  597. func (s *DockerNetworkSuite) TestDockerNetworkInspectCustomSpecified(c *testing.T) {
  598. dockerCmd(c, "network", "create", "--driver=bridge", "--ipv6", "--subnet=fd80:24e2:f998:72d6::/64", "--subnet=172.28.0.0/16", "--ip-range=172.28.5.0/24", "--gateway=172.28.5.254", "br0")
  599. assertNwIsAvailable(c, "br0")
  600. nr := getNetworkResource(c, "br0")
  601. assert.Equal(c, nr.Driver, "bridge")
  602. assert.Equal(c, nr.Scope, "local")
  603. assert.Equal(c, nr.Internal, false)
  604. assert.Equal(c, nr.EnableIPv6, true)
  605. assert.Equal(c, nr.IPAM.Driver, "default")
  606. assert.Equal(c, len(nr.IPAM.Config), 2)
  607. assert.Equal(c, nr.IPAM.Config[0].Subnet, "172.28.0.0/16")
  608. assert.Equal(c, nr.IPAM.Config[0].IPRange, "172.28.5.0/24")
  609. assert.Equal(c, nr.IPAM.Config[0].Gateway, "172.28.5.254")
  610. assert.Equal(c, nr.Internal, false)
  611. dockerCmd(c, "network", "rm", "br0")
  612. assertNwNotAvailable(c, "br0")
  613. }
  614. func (s *DockerNetworkSuite) TestDockerNetworkIPAMInvalidCombinations(c *testing.T) {
  615. // network with ip-range out of subnet range
  616. _, _, err := dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--ip-range=192.170.0.0/16", "test")
  617. assert.ErrorContains(c, err, "")
  618. // network with multiple gateways for a single subnet
  619. _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--gateway=192.168.0.1", "--gateway=192.168.0.2", "test")
  620. assert.ErrorContains(c, err, "")
  621. // Multiple overlapping subnets in the same network must fail
  622. _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.0.0/16", "--subnet=192.168.1.0/16", "test")
  623. assert.ErrorContains(c, err, "")
  624. // overlapping subnets across networks must fail
  625. // create a valid test0 network
  626. dockerCmd(c, "network", "create", "--subnet=192.168.0.0/16", "test0")
  627. assertNwIsAvailable(c, "test0")
  628. // create an overlapping test1 network
  629. _, _, err = dockerCmdWithError("network", "create", "--subnet=192.168.128.0/17", "test1")
  630. assert.ErrorContains(c, err, "")
  631. dockerCmd(c, "network", "rm", "test0")
  632. assertNwNotAvailable(c, "test0")
  633. }
  634. func (s *DockerNetworkSuite) TestDockerNetworkDriverOptions(c *testing.T) {
  635. testRequires(c, testEnv.IsLocalDaemon)
  636. dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, "-o", "opt1=drv1", "-o", "opt2=drv2", "testopt")
  637. assertNwIsAvailable(c, "testopt")
  638. gopts := remoteDriverNetworkRequest.Options[netlabel.GenericData]
  639. assert.Assert(c, gopts != nil)
  640. opts, ok := gopts.(map[string]interface{})
  641. assert.Equal(c, ok, true)
  642. assert.Equal(c, opts["opt1"], "drv1")
  643. assert.Equal(c, opts["opt2"], "drv2")
  644. dockerCmd(c, "network", "rm", "testopt")
  645. assertNwNotAvailable(c, "testopt")
  646. }
  647. func (s *DockerNetworkSuite) TestDockerPluginV2NetworkDriver(c *testing.T) {
  648. testRequires(c, DaemonIsLinux, IsAmd64, Network)
  649. var (
  650. npName = "tiborvass/test-docker-netplugin"
  651. npTag = "latest"
  652. npNameWithTag = npName + ":" + npTag
  653. )
  654. _, _, err := dockerCmdWithError("plugin", "install", "--grant-all-permissions", npNameWithTag)
  655. assert.NilError(c, err)
  656. out, _, err := dockerCmdWithError("plugin", "ls")
  657. assert.NilError(c, err)
  658. assert.Assert(c, strings.Contains(out, npName))
  659. assert.Assert(c, strings.Contains(out, npTag))
  660. assert.Assert(c, strings.Contains(out, "true"))
  661. dockerCmd(c, "network", "create", "-d", npNameWithTag, "v2net")
  662. assertNwIsAvailable(c, "v2net")
  663. dockerCmd(c, "network", "rm", "v2net")
  664. assertNwNotAvailable(c, "v2net")
  665. }
  666. func (s *DockerDaemonSuite) TestDockerNetworkNoDiscoveryDefaultBridgeNetwork(c *testing.T) {
  667. // On default bridge network built-in service discovery should not happen
  668. hostsFile := "/etc/hosts"
  669. bridgeName := "external-bridge"
  670. bridgeIP := "192.169.255.254/24"
  671. createInterface(c, "bridge", bridgeName, bridgeIP)
  672. defer deleteInterface(c, bridgeName)
  673. s.d.StartWithBusybox(c, "--bridge", bridgeName)
  674. defer s.d.Restart(c)
  675. // run two containers and store first container's etc/hosts content
  676. out, err := s.d.Cmd("run", "-d", "busybox", "top")
  677. assert.NilError(c, err)
  678. cid1 := strings.TrimSpace(out)
  679. defer s.d.Cmd("stop", cid1)
  680. hosts, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
  681. assert.NilError(c, err)
  682. out, err = s.d.Cmd("run", "-d", "--name", "container2", "busybox", "top")
  683. assert.NilError(c, err)
  684. cid2 := strings.TrimSpace(out)
  685. // verify first container's etc/hosts file has not changed after spawning the second named container
  686. hostsPost, err := s.d.Cmd("exec", cid1, "cat", hostsFile)
  687. assert.NilError(c, err)
  688. assert.Equal(c, hosts, hostsPost, fmt.Sprintf("Unexpected %s change on second container creation", hostsFile))
  689. // stop container 2 and verify first container's etc/hosts has not changed
  690. _, err = s.d.Cmd("stop", cid2)
  691. assert.NilError(c, err)
  692. hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
  693. assert.NilError(c, err)
  694. assert.Equal(c, hosts, hostsPost, fmt.Sprintf("Unexpected %s change on second container creation", hostsFile))
  695. // but discovery is on when connecting to non default bridge network
  696. network := "anotherbridge"
  697. out, err = s.d.Cmd("network", "create", network)
  698. assert.NilError(c, err, out)
  699. defer s.d.Cmd("network", "rm", network)
  700. out, err = s.d.Cmd("network", "connect", network, cid1)
  701. assert.NilError(c, err, out)
  702. hosts, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
  703. assert.NilError(c, err)
  704. hostsPost, err = s.d.Cmd("exec", cid1, "cat", hostsFile)
  705. assert.NilError(c, err)
  706. assert.Equal(c, hosts, hostsPost, fmt.Sprintf("Unexpected %s change on second network connection", hostsFile))
  707. }
  708. func (s *DockerNetworkSuite) TestDockerNetworkAnonymousEndpoint(c *testing.T) {
  709. testRequires(c, NotArm)
  710. hostsFile := "/etc/hosts"
  711. cstmBridgeNw := "custom-bridge-nw"
  712. cstmBridgeNw1 := "custom-bridge-nw1"
  713. dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw)
  714. assertNwIsAvailable(c, cstmBridgeNw)
  715. // run two anonymous containers and store their etc/hosts content
  716. out, _ := dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
  717. cid1 := strings.TrimSpace(out)
  718. hosts1 := readContainerFileWithExec(c, cid1, hostsFile)
  719. out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "busybox", "top")
  720. cid2 := strings.TrimSpace(out)
  721. // verify first container etc/hosts file has not changed
  722. hosts1post := readContainerFileWithExec(c, cid1, hostsFile)
  723. assert.Equal(c, string(hosts1), string(hosts1post), fmt.Sprintf("Unexpected %s change on anonymous container creation", hostsFile))
  724. // Connect the 2nd container to a new network and verify the
  725. // first container /etc/hosts file still hasn't changed.
  726. dockerCmd(c, "network", "create", "-d", "bridge", cstmBridgeNw1)
  727. assertNwIsAvailable(c, cstmBridgeNw1)
  728. dockerCmd(c, "network", "connect", cstmBridgeNw1, cid2)
  729. hosts2 := readContainerFileWithExec(c, cid2, hostsFile)
  730. hosts1post = readContainerFileWithExec(c, cid1, hostsFile)
  731. assert.Equal(c, string(hosts1), string(hosts1post), fmt.Sprintf("Unexpected %s change on container connect", hostsFile))
  732. // start a named container
  733. cName := "AnyName"
  734. out, _ = dockerCmd(c, "run", "-d", "--net", cstmBridgeNw, "--name", cName, "busybox", "top")
  735. cid3 := strings.TrimSpace(out)
  736. // verify that container 1 and 2 can ping the named container
  737. dockerCmd(c, "exec", cid1, "ping", "-c", "1", cName)
  738. dockerCmd(c, "exec", cid2, "ping", "-c", "1", cName)
  739. // Stop named container and verify first two containers' etc/hosts file hasn't changed
  740. dockerCmd(c, "stop", cid3)
  741. hosts1post = readContainerFileWithExec(c, cid1, hostsFile)
  742. assert.Equal(c, string(hosts1), string(hosts1post), fmt.Sprintf("Unexpected %s change on name container creation", hostsFile))
  743. hosts2post := readContainerFileWithExec(c, cid2, hostsFile)
  744. assert.Equal(c, string(hosts2), string(hosts2post), fmt.Sprintf("Unexpected %s change on name container creation", hostsFile))
  745. // verify that container 1 and 2 can't ping the named container now
  746. _, _, err := dockerCmdWithError("exec", cid1, "ping", "-c", "1", cName)
  747. assert.ErrorContains(c, err, "")
  748. _, _, err = dockerCmdWithError("exec", cid2, "ping", "-c", "1", cName)
  749. assert.ErrorContains(c, err, "")
  750. }
  751. func (s *DockerNetworkSuite) TestDockerNetworkLinkOnDefaultNetworkOnly(c *testing.T) {
  752. // Legacy Link feature must work only on default network, and not across networks
  753. cnt1 := "container1"
  754. cnt2 := "container2"
  755. network := "anotherbridge"
  756. // Run first container on default network
  757. dockerCmd(c, "run", "-d", "--name", cnt1, "busybox", "top")
  758. // Create another network and run the second container on it
  759. dockerCmd(c, "network", "create", network)
  760. assertNwIsAvailable(c, network)
  761. dockerCmd(c, "run", "-d", "--net", network, "--name", cnt2, "busybox", "top")
  762. // Try launching a container on default network, linking to the first container. Must succeed
  763. dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt1, cnt1), "busybox", "top")
  764. // Try launching a container on default network, linking to the second container. Must fail
  765. _, _, err := dockerCmdWithError("run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
  766. assert.ErrorContains(c, err, "")
  767. // Connect second container to default network. Now a container on default network can link to it
  768. dockerCmd(c, "network", "connect", "bridge", cnt2)
  769. dockerCmd(c, "run", "-d", "--link", fmt.Sprintf("%s:%s", cnt2, cnt2), "busybox", "top")
  770. }
  771. func (s *DockerNetworkSuite) TestDockerNetworkOverlayPortMapping(c *testing.T) {
  772. testRequires(c, testEnv.IsLocalDaemon)
  773. // Verify exposed ports are present in ps output when running a container on
  774. // a network managed by a driver which does not provide the default gateway
  775. // for the container
  776. nwn := "ov"
  777. ctn := "bb"
  778. port1 := 80
  779. port2 := 443
  780. expose1 := fmt.Sprintf("--expose=%d", port1)
  781. expose2 := fmt.Sprintf("--expose=%d", port2)
  782. dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
  783. assertNwIsAvailable(c, nwn)
  784. dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, expose1, expose2, "busybox", "top")
  785. // Check docker ps o/p for last created container reports the unpublished ports
  786. unpPort1 := fmt.Sprintf("%d/tcp", port1)
  787. unpPort2 := fmt.Sprintf("%d/tcp", port2)
  788. out, _ := dockerCmd(c, "ps", "-n=1")
  789. // Missing unpublished ports in docker ps output
  790. assert.Assert(c, strings.Contains(out, unpPort1))
  791. // Missing unpublished ports in docker ps output
  792. assert.Assert(c, strings.Contains(out, unpPort2))
  793. }
  794. func (s *DockerNetworkSuite) TestDockerNetworkDriverUngracefulRestart(c *testing.T) {
  795. testRequires(c, DaemonIsLinux, NotUserNamespace, testEnv.IsLocalDaemon)
  796. dnd := "dnd"
  797. did := "did"
  798. mux := http.NewServeMux()
  799. server := httptest.NewServer(mux)
  800. setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
  801. s.d.StartWithBusybox(c)
  802. _, err := s.d.Cmd("network", "create", "-d", dnd, "--subnet", "1.1.1.0/24", "net1")
  803. assert.NilError(c, err)
  804. _, err = s.d.Cmd("run", "-d", "--net", "net1", "--name", "foo", "--ip", "1.1.1.10", "busybox", "top")
  805. assert.NilError(c, err)
  806. // Kill daemon and restart
  807. assert.Assert(c, s.d.Kill() == nil)
  808. server.Close()
  809. startTime := time.Now().Unix()
  810. s.d.Restart(c)
  811. lapse := time.Now().Unix() - startTime
  812. if lapse > 60 {
  813. // In normal scenarios, daemon restart takes ~1 second.
  814. // Plugin retry mechanism can delay the daemon start. systemd may not like it.
  815. // Avoid accessing plugins during daemon bootup
  816. c.Logf("daemon restart took too long : %d seconds", lapse)
  817. }
  818. // Restart the custom dummy plugin
  819. mux = http.NewServeMux()
  820. server = httptest.NewServer(mux)
  821. setupRemoteNetworkDrivers(c, mux, server.URL, dnd, did)
  822. // trying to reuse the same ip must succeed
  823. _, err = s.d.Cmd("run", "-d", "--net", "net1", "--name", "bar", "--ip", "1.1.1.10", "busybox", "top")
  824. assert.NilError(c, err)
  825. }
  826. func (s *DockerNetworkSuite) TestDockerNetworkMacInspect(c *testing.T) {
  827. testRequires(c, testEnv.IsLocalDaemon)
  828. // Verify endpoint MAC address is correctly populated in container's network settings
  829. nwn := "ov"
  830. ctn := "bb"
  831. dockerCmd(c, "network", "create", "-d", dummyNetworkDriver, nwn)
  832. assertNwIsAvailable(c, nwn)
  833. dockerCmd(c, "run", "-d", "--net", nwn, "--name", ctn, "busybox", "top")
  834. mac := inspectField(c, ctn, "NetworkSettings.Networks."+nwn+".MacAddress")
  835. assert.Equal(c, mac, "a0:b1:c2:d3:e4:f5")
  836. }
  837. func (s *DockerCLINetworkSuite) TestInspectAPIMultipleNetworks(c *testing.T) {
  838. dockerCmd(c, "network", "create", "mybridge1")
  839. dockerCmd(c, "network", "create", "mybridge2")
  840. out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
  841. id := strings.TrimSpace(out)
  842. assert.NilError(c, waitRun(id))
  843. dockerCmd(c, "network", "connect", "mybridge1", id)
  844. dockerCmd(c, "network", "connect", "mybridge2", id)
  845. body := getInspectBody(c, "v1.20", id)
  846. var inspect120 v1p20.ContainerJSON
  847. err := json.Unmarshal(body, &inspect120)
  848. assert.NilError(c, err)
  849. versionedIP := inspect120.NetworkSettings.IPAddress
  850. body = getInspectBody(c, "v1.21", id)
  851. var inspect121 types.ContainerJSON
  852. err = json.Unmarshal(body, &inspect121)
  853. assert.NilError(c, err)
  854. assert.Equal(c, len(inspect121.NetworkSettings.Networks), 3)
  855. bridge := inspect121.NetworkSettings.Networks["bridge"]
  856. assert.Equal(c, bridge.IPAddress, versionedIP)
  857. assert.Equal(c, bridge.IPAddress, inspect121.NetworkSettings.IPAddress)
  858. }
  859. func connectContainerToNetworks(c *testing.T, d *daemon.Daemon, cName string, nws []string) {
  860. // Run a container on the default network
  861. out, err := d.Cmd("run", "-d", "--name", cName, "busybox", "top")
  862. assert.NilError(c, err, out)
  863. // Attach the container to other networks
  864. for _, nw := range nws {
  865. out, err = d.Cmd("network", "create", nw)
  866. assert.NilError(c, err, out)
  867. out, err = d.Cmd("network", "connect", nw, cName)
  868. assert.NilError(c, err, out)
  869. }
  870. }
  871. func verifyContainerIsConnectedToNetworks(c *testing.T, d *daemon.Daemon, cName string, nws []string) {
  872. // Verify container is connected to all the networks
  873. for _, nw := range nws {
  874. out, err := d.Cmd("inspect", "-f", fmt.Sprintf("{{.NetworkSettings.Networks.%s}}", nw), cName)
  875. assert.NilError(c, err, out)
  876. assert.Assert(c, out != "<no value>\n")
  877. }
  878. }
  879. func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksGracefulDaemonRestart(c *testing.T) {
  880. testRequires(c, testEnv.IsLocalDaemon)
  881. cName := "bb"
  882. nwList := []string{"nw1", "nw2", "nw3"}
  883. s.d.StartWithBusybox(c)
  884. connectContainerToNetworks(c, s.d, cName, nwList)
  885. verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  886. // Reload daemon
  887. s.d.Restart(c)
  888. _, err := s.d.Cmd("start", cName)
  889. assert.NilError(c, err)
  890. verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  891. }
  892. func (s *DockerNetworkSuite) TestDockerNetworkMultipleNetworksUngracefulDaemonRestart(c *testing.T) {
  893. testRequires(c, testEnv.IsLocalDaemon)
  894. cName := "cc"
  895. nwList := []string{"nw1", "nw2", "nw3"}
  896. s.d.StartWithBusybox(c)
  897. connectContainerToNetworks(c, s.d, cName, nwList)
  898. verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  899. // Kill daemon and restart
  900. assert.Assert(c, s.d.Kill() == nil)
  901. s.d.Restart(c)
  902. // Restart container
  903. _, err := s.d.Cmd("start", cName)
  904. assert.NilError(c, err)
  905. verifyContainerIsConnectedToNetworks(c, s.d, cName, nwList)
  906. }
  907. func (s *DockerNetworkSuite) TestDockerNetworkRunNetByID(c *testing.T) {
  908. out, _ := dockerCmd(c, "network", "create", "one")
  909. containerOut, _, err := dockerCmdWithError("run", "-d", "--net", strings.TrimSpace(out), "busybox", "top")
  910. assert.Assert(c, err == nil, containerOut)
  911. }
  912. func (s *DockerNetworkSuite) TestDockerNetworkHostModeUngracefulDaemonRestart(c *testing.T) {
  913. testRequires(c, DaemonIsLinux, NotUserNamespace, testEnv.IsLocalDaemon)
  914. s.d.StartWithBusybox(c)
  915. // Run a few containers on host network
  916. for i := 0; i < 10; i++ {
  917. cName := fmt.Sprintf("hostc-%d", i)
  918. out, err := s.d.Cmd("run", "-d", "--name", cName, "--net=host", "--restart=always", "busybox", "top")
  919. assert.NilError(c, err, out)
  920. // verify container has finished starting before killing daemon
  921. err = s.d.WaitRun(cName)
  922. assert.NilError(c, err)
  923. }
  924. // Kill daemon ungracefully and restart
  925. assert.Assert(c, s.d.Kill() == nil)
  926. s.d.Restart(c)
  927. // make sure all the containers are up and running
  928. for i := 0; i < 10; i++ {
  929. err := s.d.WaitRun(fmt.Sprintf("hostc-%d", i))
  930. assert.NilError(c, err)
  931. }
  932. }
  933. func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *testing.T) {
  934. dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
  935. assert.Assert(c, waitRun("container1") == nil)
  936. dockerCmd(c, "network", "disconnect", "bridge", "container1")
  937. out, _, err := dockerCmdWithError("network", "connect", "host", "container1")
  938. assert.ErrorContains(c, err, "", out)
  939. assert.Assert(c, strings.Contains(out, runconfig.ErrConflictHostNetwork.Error()))
  940. }
  941. func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *testing.T) {
  942. dockerCmd(c, "run", "-d", "--name", "container1", "--net=host", "busybox", "top")
  943. assert.Assert(c, waitRun("container1") == nil)
  944. out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1")
  945. assert.Assert(c, err != nil, "Should err out disconnect from host")
  946. assert.Assert(c, strings.Contains(out, runconfig.ErrConflictHostNetwork.Error()))
  947. }
  948. func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *testing.T) {
  949. testRequires(c, NotArm)
  950. dockerCmd(c, "network", "create", "test1")
  951. dockerCmd(c, "run", "-d", "--name", "c1", "-p", "5000:5000", "busybox", "top")
  952. assert.Assert(c, waitRun("c1") == nil)
  953. dockerCmd(c, "network", "connect", "test1", "c1")
  954. }
  955. func verifyPortMap(c *testing.T, container, port, originalMapping string, mustBeEqual bool) {
  956. currentMapping, _ := dockerCmd(c, "port", container, port)
  957. if mustBeEqual {
  958. assert.Equal(c, currentMapping, originalMapping)
  959. } else {
  960. assert.Assert(c, currentMapping != originalMapping)
  961. }
  962. }
  963. func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectWithPortMapping(c *testing.T) {
  964. // Connect and disconnect a container with explicit and non-explicit
  965. // host port mapping to/from networks which do cause and do not cause
  966. // the container default gateway to change, and verify docker port cmd
  967. // returns congruent information
  968. testRequires(c, NotArm)
  969. cnt := "c1"
  970. dockerCmd(c, "network", "create", "aaa")
  971. dockerCmd(c, "network", "create", "ccc")
  972. dockerCmd(c, "run", "-d", "--name", cnt, "-p", "9000:90", "-p", "70", "busybox", "top")
  973. assert.Assert(c, waitRun(cnt) == nil)
  974. curPortMap, _ := dockerCmd(c, "port", cnt, "70")
  975. curExplPortMap, _ := dockerCmd(c, "port", cnt, "90")
  976. // Connect to a network which causes the container's default gw switch
  977. dockerCmd(c, "network", "connect", "aaa", cnt)
  978. verifyPortMap(c, cnt, "70", curPortMap, false)
  979. verifyPortMap(c, cnt, "90", curExplPortMap, true)
  980. // Read current mapping
  981. curPortMap, _ = dockerCmd(c, "port", cnt, "70")
  982. // Disconnect from a network which causes the container's default gw switch
  983. dockerCmd(c, "network", "disconnect", "aaa", cnt)
  984. verifyPortMap(c, cnt, "70", curPortMap, false)
  985. verifyPortMap(c, cnt, "90", curExplPortMap, true)
  986. // Read current mapping
  987. curPortMap, _ = dockerCmd(c, "port", cnt, "70")
  988. // Connect to a network which does not cause the container's default gw switch
  989. dockerCmd(c, "network", "connect", "ccc", cnt)
  990. verifyPortMap(c, cnt, "70", curPortMap, true)
  991. verifyPortMap(c, cnt, "90", curExplPortMap, true)
  992. }
  993. func (s *DockerNetworkSuite) TestDockerNetworkConnectWithMac(c *testing.T) {
  994. macAddress := "02:42:ac:11:00:02"
  995. dockerCmd(c, "network", "create", "mynetwork")
  996. dockerCmd(c, "run", "--name=test", "-d", "--mac-address", macAddress, "busybox", "top")
  997. assert.Assert(c, waitRun("test") == nil)
  998. mac1 := inspectField(c, "test", "NetworkSettings.Networks.bridge.MacAddress")
  999. assert.Equal(c, strings.TrimSpace(mac1), macAddress)
  1000. dockerCmd(c, "network", "connect", "mynetwork", "test")
  1001. mac2 := inspectField(c, "test", "NetworkSettings.Networks.mynetwork.MacAddress")
  1002. assert.Assert(c, strings.TrimSpace(mac2) != strings.TrimSpace(mac1))
  1003. }
  1004. func (s *DockerNetworkSuite) TestDockerNetworkInspectCreatedContainer(c *testing.T) {
  1005. dockerCmd(c, "create", "--name", "test", "busybox")
  1006. networks := inspectField(c, "test", "NetworkSettings.Networks")
  1007. assert.Assert(c, strings.Contains(networks, "bridge"), "Should return 'bridge' network")
  1008. }
  1009. func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMultipleNetworks(c *testing.T) {
  1010. dockerCmd(c, "network", "create", "test")
  1011. dockerCmd(c, "run", "--name=foo", "-d", "busybox", "top")
  1012. assert.Assert(c, waitRun("foo") == nil)
  1013. dockerCmd(c, "network", "connect", "test", "foo")
  1014. dockerCmd(c, "restart", "foo")
  1015. networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1016. assert.Assert(c, strings.Contains(networks, "bridge"), "Should contain 'bridge' network")
  1017. assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1018. }
  1019. func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *testing.T) {
  1020. testRequires(c, testEnv.IsLocalDaemon)
  1021. dockerCmd(c, "network", "create", "test")
  1022. dockerCmd(c, "create", "--name=foo", "busybox", "top")
  1023. dockerCmd(c, "network", "connect", "test", "foo")
  1024. networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1025. assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1026. // Restart docker daemon to test the config has persisted to disk
  1027. s.d.Restart(c)
  1028. networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1029. assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1030. // start the container and test if we can ping it from another container in the same network
  1031. dockerCmd(c, "start", "foo")
  1032. assert.Assert(c, waitRun("foo") == nil)
  1033. ip := inspectField(c, "foo", "NetworkSettings.Networks.test.IPAddress")
  1034. ip = strings.TrimSpace(ip)
  1035. dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip))
  1036. dockerCmd(c, "stop", "foo")
  1037. // Test disconnect
  1038. dockerCmd(c, "network", "disconnect", "test", "foo")
  1039. networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1040. assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1041. // Restart docker daemon to test the config has persisted to disk
  1042. s.d.Restart(c)
  1043. networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1044. assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1045. }
  1046. func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *testing.T) {
  1047. dockerCmd(c, "network", "create", "test")
  1048. dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top")
  1049. networks := inspectField(c, "foo", "NetworkSettings.Networks")
  1050. assert.Assert(c, strings.Contains(networks, "test"), "Should contain 'test' network")
  1051. // Stop container and remove network
  1052. dockerCmd(c, "stop", "foo")
  1053. dockerCmd(c, "network", "rm", "test")
  1054. // Test disconnecting stopped container from nonexisting network
  1055. dockerCmd(c, "network", "disconnect", "-f", "test", "foo")
  1056. networks = inspectField(c, "foo", "NetworkSettings.Networks")
  1057. assert.Assert(c, !strings.Contains(networks, "test"), "Should not contain 'test' network")
  1058. }
  1059. func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *testing.T) {
  1060. // create two networks
  1061. dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
  1062. assertNwIsAvailable(c, "n0")
  1063. dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--ip-range=172.30.5.0/24", "--subnet=2001:db8:abcd::/64", "--ip-range=2001:db8:abcd::/80", "n1")
  1064. assertNwIsAvailable(c, "n1")
  1065. // run a container on first network specifying the ip addresses
  1066. dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1067. assert.Assert(c, waitRun("c0") == nil)
  1068. verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1069. verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1070. // connect the container to the second network specifying an ip addresses
  1071. dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n1", "c0")
  1072. verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1073. verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1074. // Stop and restart the container
  1075. dockerCmd(c, "stop", "c0")
  1076. dockerCmd(c, "start", "c0")
  1077. // verify requested addresses are applied and configs are still there
  1078. verifyIPAddressConfig(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1079. verifyIPAddresses(c, "c0", "n0", "172.28.99.88", "2001:db8:1234::9988")
  1080. verifyIPAddressConfig(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1081. verifyIPAddresses(c, "c0", "n1", "172.30.55.44", "2001:db8:abcd::5544")
  1082. // Still it should fail to connect to the default network with a specified IP (whatever ip)
  1083. out, _, err := dockerCmdWithError("network", "connect", "--ip", "172.21.55.44", "bridge", "c0")
  1084. assert.Assert(c, err != nil, "out: %s", out)
  1085. assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndIP.Error()))
  1086. }
  1087. func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIPStoppedContainer(c *testing.T) {
  1088. // create a container
  1089. dockerCmd(c, "create", "--name", "c0", "busybox", "top")
  1090. // create a network
  1091. dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.30.0.0/16", "--subnet=2001:db8:abcd::/64", "n0")
  1092. assertNwIsAvailable(c, "n0")
  1093. // connect the container to the network specifying an ip addresses
  1094. dockerCmd(c, "network", "connect", "--ip", "172.30.55.44", "--ip6", "2001:db8:abcd::5544", "n0", "c0")
  1095. verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1096. // start the container, verify config has not changed and ip addresses are assigned
  1097. dockerCmd(c, "start", "c0")
  1098. assert.Assert(c, waitRun("c0") == nil)
  1099. verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1100. verifyIPAddresses(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1101. // stop the container and check ip config has not changed
  1102. dockerCmd(c, "stop", "c0")
  1103. verifyIPAddressConfig(c, "c0", "n0", "172.30.55.44", "2001:db8:abcd::5544")
  1104. }
  1105. func (s *DockerNetworkSuite) TestDockerNetworkUnsupportedRequiredIP(c *testing.T) {
  1106. // requested IP is not supported on predefined networks
  1107. for _, mode := range []string{"none", "host", "bridge", "default"} {
  1108. checkUnsupportedNetworkAndIP(c, mode)
  1109. }
  1110. // requested IP is not supported on networks with no user defined subnets
  1111. dockerCmd(c, "network", "create", "n0")
  1112. assertNwIsAvailable(c, "n0")
  1113. out, _, err := dockerCmdWithError("run", "-d", "--ip", "172.28.99.88", "--net", "n0", "busybox", "top")
  1114. assert.Assert(c, err != nil, "out: %s", out)
  1115. assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()))
  1116. out, _, err = dockerCmdWithError("run", "-d", "--ip6", "2001:db8:1234::9988", "--net", "n0", "busybox", "top")
  1117. assert.Assert(c, err != nil, "out: %s", out)
  1118. assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkNoSubnetAndIP.Error()))
  1119. dockerCmd(c, "network", "rm", "n0")
  1120. assertNwNotAvailable(c, "n0")
  1121. }
  1122. func checkUnsupportedNetworkAndIP(c *testing.T, nwMode string) {
  1123. out, _, err := dockerCmdWithError("run", "-d", "--net", nwMode, "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1124. assert.Assert(c, err != nil, "out: %s", out)
  1125. assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndIP.Error()))
  1126. }
  1127. func verifyIPAddressConfig(c *testing.T, cName, nwname, ipv4, ipv6 string) {
  1128. if ipv4 != "" {
  1129. out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv4Address", nwname))
  1130. assert.Equal(c, strings.TrimSpace(out), ipv4)
  1131. }
  1132. if ipv6 != "" {
  1133. out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAMConfig.IPv6Address", nwname))
  1134. assert.Equal(c, strings.TrimSpace(out), ipv6)
  1135. }
  1136. }
  1137. func verifyIPAddresses(c *testing.T, cName, nwname, ipv4, ipv6 string) {
  1138. out := inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.IPAddress", nwname))
  1139. assert.Equal(c, strings.TrimSpace(out), ipv4)
  1140. out = inspectField(c, cName, fmt.Sprintf("NetworkSettings.Networks.%s.GlobalIPv6Address", nwname))
  1141. assert.Equal(c, strings.TrimSpace(out), ipv6)
  1142. }
  1143. func (s *DockerNetworkSuite) TestDockerNetworkConnectLinkLocalIP(c *testing.T) {
  1144. // create one test network
  1145. dockerCmd(c, "network", "create", "--ipv6", "--subnet=2001:db8:1234::/64", "n0")
  1146. assertNwIsAvailable(c, "n0")
  1147. // run a container with incorrect link-local address
  1148. _, _, err := dockerCmdWithError("run", "--link-local-ip", "169.253.5.5", "busybox", "true")
  1149. assert.ErrorContains(c, err, "")
  1150. _, _, err = dockerCmdWithError("run", "--link-local-ip", "2001:db8::89", "busybox", "true")
  1151. assert.ErrorContains(c, err, "")
  1152. // run two containers with link-local ip on the test network
  1153. dockerCmd(c, "run", "-d", "--name", "c0", "--net=n0", "--link-local-ip", "169.254.7.7", "--link-local-ip", "fe80::254:77", "busybox", "top")
  1154. assert.Assert(c, waitRun("c0") == nil)
  1155. dockerCmd(c, "run", "-d", "--name", "c1", "--net=n0", "--link-local-ip", "169.254.8.8", "--link-local-ip", "fe80::254:88", "busybox", "top")
  1156. assert.Assert(c, waitRun("c1") == nil)
  1157. // run a container on the default network and connect it to the test network specifying a link-local address
  1158. dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
  1159. assert.Assert(c, waitRun("c2") == nil)
  1160. dockerCmd(c, "network", "connect", "--link-local-ip", "169.254.9.9", "n0", "c2")
  1161. // verify the three containers can ping each other via the link-local addresses
  1162. _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1163. assert.NilError(c, err)
  1164. _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1165. assert.NilError(c, err)
  1166. _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1167. assert.NilError(c, err)
  1168. // Stop and restart the three containers
  1169. dockerCmd(c, "stop", "c0")
  1170. dockerCmd(c, "stop", "c1")
  1171. dockerCmd(c, "stop", "c2")
  1172. dockerCmd(c, "start", "c0")
  1173. dockerCmd(c, "start", "c1")
  1174. dockerCmd(c, "start", "c2")
  1175. // verify the ping again
  1176. _, _, err = dockerCmdWithError("exec", "c0", "ping", "-c", "1", "169.254.8.8")
  1177. assert.NilError(c, err)
  1178. _, _, err = dockerCmdWithError("exec", "c1", "ping", "-c", "1", "169.254.9.9")
  1179. assert.NilError(c, err)
  1180. _, _, err = dockerCmdWithError("exec", "c2", "ping", "-c", "1", "169.254.7.7")
  1181. assert.NilError(c, err)
  1182. }
  1183. func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectDisconnectLink(c *testing.T) {
  1184. testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1185. dockerCmd(c, "network", "create", "-d", "bridge", "foo1")
  1186. dockerCmd(c, "network", "create", "-d", "bridge", "foo2")
  1187. dockerCmd(c, "run", "-d", "--net=foo1", "--name=first", "busybox", "top")
  1188. assert.Assert(c, waitRun("first") == nil)
  1189. // run a container in a user-defined network with a link for an existing container
  1190. // and a link for a container that doesn't exist
  1191. dockerCmd(c, "run", "-d", "--net=foo1", "--name=second", "--link=first:FirstInFoo1",
  1192. "--link=third:bar", "busybox", "top")
  1193. assert.Assert(c, waitRun("second") == nil)
  1194. // ping to first and its alias FirstInFoo1 must succeed
  1195. _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1196. assert.NilError(c, err)
  1197. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1198. assert.NilError(c, err)
  1199. // connect first container to foo2 network
  1200. dockerCmd(c, "network", "connect", "foo2", "first")
  1201. // connect second container to foo2 network with a different alias for first container
  1202. dockerCmd(c, "network", "connect", "--link=first:FirstInFoo2", "foo2", "second")
  1203. // ping the new alias in network foo2
  1204. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1205. assert.NilError(c, err)
  1206. // disconnect first container from foo1 network
  1207. dockerCmd(c, "network", "disconnect", "foo1", "first")
  1208. // link in foo1 network must fail
  1209. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo1")
  1210. assert.ErrorContains(c, err, "")
  1211. // link in foo2 network must succeed
  1212. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "FirstInFoo2")
  1213. assert.NilError(c, err)
  1214. }
  1215. func (s *DockerNetworkSuite) TestDockerNetworkDisconnectDefault(c *testing.T) {
  1216. netWorkName1 := "test1"
  1217. netWorkName2 := "test2"
  1218. containerName := "foo"
  1219. dockerCmd(c, "network", "create", netWorkName1)
  1220. dockerCmd(c, "network", "create", netWorkName2)
  1221. dockerCmd(c, "create", "--name", containerName, "busybox", "top")
  1222. dockerCmd(c, "network", "connect", netWorkName1, containerName)
  1223. dockerCmd(c, "network", "connect", netWorkName2, containerName)
  1224. dockerCmd(c, "network", "disconnect", "bridge", containerName)
  1225. dockerCmd(c, "start", containerName)
  1226. assert.Assert(c, waitRun(containerName) == nil)
  1227. networks := inspectField(c, containerName, "NetworkSettings.Networks")
  1228. assert.Assert(c, strings.Contains(networks, netWorkName1), fmt.Sprintf("Should contain '%s' network", netWorkName1))
  1229. assert.Assert(c, strings.Contains(networks, netWorkName2), fmt.Sprintf("Should contain '%s' network", netWorkName2))
  1230. assert.Assert(c, !strings.Contains(networks, "bridge"), "Should not contain 'bridge' network")
  1231. }
  1232. func (s *DockerNetworkSuite) TestDockerNetworkConnectWithAliasOnDefaultNetworks(c *testing.T) {
  1233. testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1234. defaults := []string{"bridge", "host", "none"}
  1235. out, _ := dockerCmd(c, "run", "-d", "--net=none", "busybox", "top")
  1236. containerID := strings.TrimSpace(out)
  1237. for _, net := range defaults {
  1238. res, _, err := dockerCmdWithError("network", "connect", "--alias", "alias"+net, net, containerID)
  1239. assert.ErrorContains(c, err, "")
  1240. assert.Assert(c, strings.Contains(res, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1241. }
  1242. }
  1243. func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectDisconnectAlias(c *testing.T) {
  1244. testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm)
  1245. dockerCmd(c, "network", "create", "-d", "bridge", "net1")
  1246. dockerCmd(c, "network", "create", "-d", "bridge", "net2")
  1247. cid, _ := dockerCmd(c, "run", "-d", "--net=net1", "--name=first", "--net-alias=foo", "busybox:glibc", "top")
  1248. assert.Assert(c, waitRun("first") == nil)
  1249. dockerCmd(c, "run", "-d", "--net=net1", "--name=second", "busybox:glibc", "top")
  1250. assert.Assert(c, waitRun("second") == nil)
  1251. // ping first container and its alias
  1252. _, _, err := dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1253. assert.NilError(c, err)
  1254. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1255. assert.NilError(c, err)
  1256. // ping first container's short-id alias
  1257. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1258. assert.NilError(c, err)
  1259. // connect first container to net2 network
  1260. dockerCmd(c, "network", "connect", "--alias=bar", "net2", "first")
  1261. // connect second container to foo2 network with a different alias for first container
  1262. dockerCmd(c, "network", "connect", "net2", "second")
  1263. // ping the new alias in network foo2
  1264. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1265. assert.NilError(c, err)
  1266. // disconnect first container from net1 network
  1267. dockerCmd(c, "network", "disconnect", "net1", "first")
  1268. // ping to net1 scoped alias "foo" must fail
  1269. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "foo")
  1270. assert.ErrorContains(c, err, "")
  1271. // ping to net2 scoped alias "bar" must still succeed
  1272. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "bar")
  1273. assert.NilError(c, err)
  1274. // ping to net2 scoped alias short-id must still succeed
  1275. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", stringid.TruncateID(cid))
  1276. assert.NilError(c, err)
  1277. // verify the alias option is rejected when running on predefined network
  1278. out, _, err := dockerCmdWithError("run", "--rm", "--name=any", "--net-alias=any", "busybox:glibc", "true")
  1279. assert.Assert(c, err != nil, "out: %s", out)
  1280. assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1281. // verify the alias option is rejected when connecting to predefined network
  1282. out, _, err = dockerCmdWithError("network", "connect", "--alias=any", "bridge", "first")
  1283. assert.Assert(c, err != nil, "out: %s", out)
  1284. assert.Assert(c, strings.Contains(out, runconfig.ErrUnsupportedNetworkAndAlias.Error()))
  1285. }
  1286. func (s *DockerCLINetworkSuite) TestUserDefinedNetworkConnectivity(c *testing.T) {
  1287. testRequires(c, DaemonIsLinux, NotUserNamespace)
  1288. dockerCmd(c, "network", "create", "-d", "bridge", "br.net1")
  1289. dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c1.net1", "busybox:glibc", "top")
  1290. assert.Assert(c, waitRun("c1.net1") == nil)
  1291. dockerCmd(c, "run", "-d", "--net=br.net1", "--name=c2.net1", "busybox:glibc", "top")
  1292. assert.Assert(c, waitRun("c2.net1") == nil)
  1293. // ping first container by its unqualified name
  1294. _, _, err := dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1")
  1295. assert.NilError(c, err)
  1296. // ping first container by its qualified name
  1297. _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1")
  1298. assert.NilError(c, err)
  1299. // ping with first qualified name masked by an additional domain. should fail
  1300. _, _, err = dockerCmdWithError("exec", "c2.net1", "ping", "-c", "1", "c1.net1.br.net1.google.com")
  1301. assert.ErrorContains(c, err, "")
  1302. }
  1303. func (s *DockerCLINetworkSuite) TestEmbeddedDNSInvalidInput(c *testing.T) {
  1304. testRequires(c, DaemonIsLinux, NotUserNamespace)
  1305. dockerCmd(c, "network", "create", "-d", "bridge", "nw1")
  1306. // Sending garbage to embedded DNS shouldn't crash the daemon
  1307. dockerCmd(c, "run", "-i", "--net=nw1", "--name=c1", "debian:bullseye-slim", "bash", "-c", "echo InvalidQuery > /dev/udp/127.0.0.11/53")
  1308. }
  1309. func (s *DockerCLINetworkSuite) TestDockerNetworkConnectFailsNoInspectChange(c *testing.T) {
  1310. dockerCmd(c, "run", "-d", "--name=bb", "busybox", "top")
  1311. assert.Assert(c, waitRun("bb") == nil)
  1312. defer dockerCmd(c, "stop", "bb")
  1313. ns0 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1314. // A failing redundant network connect should not alter current container's endpoint settings
  1315. _, _, err := dockerCmdWithError("network", "connect", "bridge", "bb")
  1316. assert.ErrorContains(c, err, "")
  1317. ns1 := inspectField(c, "bb", "NetworkSettings.Networks.bridge")
  1318. assert.Equal(c, ns1, ns0)
  1319. }
  1320. func (s *DockerCLINetworkSuite) TestDockerNetworkInternalMode(c *testing.T) {
  1321. dockerCmd(c, "network", "create", "--driver=bridge", "--internal", "internal")
  1322. assertNwIsAvailable(c, "internal")
  1323. nr := getNetworkResource(c, "internal")
  1324. assert.Assert(c, nr.Internal)
  1325. dockerCmd(c, "run", "-d", "--net=internal", "--name=first", "busybox:glibc", "top")
  1326. assert.Assert(c, waitRun("first") == nil)
  1327. dockerCmd(c, "run", "-d", "--net=internal", "--name=second", "busybox:glibc", "top")
  1328. assert.Assert(c, waitRun("second") == nil)
  1329. out, _, err := dockerCmdWithError("exec", "first", "ping", "-W", "4", "-c", "1", "8.8.8.8")
  1330. assert.ErrorContains(c, err, "")
  1331. assert.Assert(c, strings.Contains(out, "100% packet loss"))
  1332. _, _, err = dockerCmdWithError("exec", "second", "ping", "-c", "1", "first")
  1333. assert.NilError(c, err)
  1334. }
  1335. // Test for #21401
  1336. func (s *DockerNetworkSuite) TestDockerNetworkCreateDeleteSpecialCharacters(c *testing.T) {
  1337. dockerCmd(c, "network", "create", "test@#$")
  1338. assertNwIsAvailable(c, "test@#$")
  1339. dockerCmd(c, "network", "rm", "test@#$")
  1340. assertNwNotAvailable(c, "test@#$")
  1341. dockerCmd(c, "network", "create", "kiwl$%^")
  1342. assertNwIsAvailable(c, "kiwl$%^")
  1343. dockerCmd(c, "network", "rm", "kiwl$%^")
  1344. assertNwNotAvailable(c, "kiwl$%^")
  1345. }
  1346. func (s *DockerDaemonSuite) TestDaemonRestartRestoreBridgeNetwork(t *testing.T) {
  1347. s.d.StartWithBusybox(t, "--live-restore")
  1348. defer s.d.Stop(t)
  1349. oldCon := "old"
  1350. _, err := s.d.Cmd("run", "-d", "--name", oldCon, "-p", "80:80", "busybox", "top")
  1351. if err != nil {
  1352. t.Fatal(err)
  1353. }
  1354. oldContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", oldCon)
  1355. if err != nil {
  1356. t.Fatal(err)
  1357. }
  1358. // Kill the daemon
  1359. if err := s.d.Kill(); err != nil {
  1360. t.Fatal(err)
  1361. }
  1362. // restart the daemon
  1363. s.d.Start(t, "--live-restore")
  1364. // start a new container, the new container's ip should not be the same with
  1365. // old running container.
  1366. newCon := "new"
  1367. _, err = s.d.Cmd("run", "-d", "--name", newCon, "busybox", "top")
  1368. if err != nil {
  1369. t.Fatal(err)
  1370. }
  1371. newContainerIP, err := s.d.Cmd("inspect", "-f", "{{ .NetworkSettings.Networks.bridge.IPAddress }}", newCon)
  1372. if err != nil {
  1373. t.Fatal(err)
  1374. }
  1375. if strings.Compare(strings.TrimSpace(oldContainerIP), strings.TrimSpace(newContainerIP)) == 0 {
  1376. t.Fatalf("new container ip should not equal to old running container ip")
  1377. }
  1378. // start a new container, the new container should ping old running container
  1379. _, err = s.d.Cmd("run", "-t", "busybox", "ping", "-c", "1", oldContainerIP)
  1380. if err != nil {
  1381. t.Fatal(err)
  1382. }
  1383. // start a new container, trying to publish port 80:80 should fail
  1384. out, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1385. if err == nil || !strings.Contains(out, "Bind for 0.0.0.0:80 failed: port is already allocated") {
  1386. t.Fatalf("80 port is allocated to old running container, it should failed on allocating to new container")
  1387. }
  1388. // kill old running container and try to allocate again
  1389. _, err = s.d.Cmd("kill", oldCon)
  1390. if err != nil {
  1391. t.Fatal(err)
  1392. }
  1393. id, err := s.d.Cmd("run", "-p", "80:80", "-d", "busybox", "top")
  1394. if err != nil {
  1395. t.Fatal(err)
  1396. }
  1397. // Cleanup because these containers will not be shut down by daemon
  1398. out, err = s.d.Cmd("stop", newCon)
  1399. if err != nil {
  1400. t.Fatalf("err: %v %v", err, out)
  1401. }
  1402. _, err = s.d.Cmd("stop", strings.TrimSpace(id))
  1403. if err != nil {
  1404. t.Fatal(err)
  1405. }
  1406. }
  1407. func (s *DockerNetworkSuite) TestDockerNetworkFlagAlias(c *testing.T) {
  1408. dockerCmd(c, "network", "create", "user")
  1409. output, status := dockerCmd(c, "run", "--rm", "--network=user", "--network-alias=foo", "busybox", "true")
  1410. assert.Equal(c, status, 0, fmt.Sprintf("unexpected status code %d (%s)", status, output))
  1411. output, status, _ = dockerCmdWithError("run", "--rm", "--network=user", "--net-alias=foo", "--network-alias=bar", "busybox", "true")
  1412. assert.Equal(c, status, 0, fmt.Sprintf("unexpected status code %d (%s)", status, output))
  1413. }
  1414. func (s *DockerNetworkSuite) TestDockerNetworkValidateIP(c *testing.T) {
  1415. _, _, err := dockerCmdWithError("network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "mynet")
  1416. assert.NilError(c, err)
  1417. assertNwIsAvailable(c, "mynet")
  1418. _, _, err = dockerCmdWithError("run", "-d", "--name", "mynet0", "--net=mynet", "--ip", "172.28.99.88", "--ip6", "2001:db8:1234::9988", "busybox", "top")
  1419. assert.NilError(c, err)
  1420. assert.Assert(c, waitRun("mynet0") == nil)
  1421. verifyIPAddressConfig(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1422. verifyIPAddresses(c, "mynet0", "mynet", "172.28.99.88", "2001:db8:1234::9988")
  1423. _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "mynet_ip", "--ip6", "2001:db8:1234::9999", "busybox", "top")
  1424. assert.ErrorContains(c, err, "invalid IPv4 address")
  1425. _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip", "172.28.99.99", "--ip6", "mynet_ip6", "busybox", "top")
  1426. assert.ErrorContains(c, err, "invalid IPv6 address")
  1427. // This is a case of IPv4 address to `--ip6`
  1428. _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "172.28.99.99", "busybox", "top")
  1429. assert.ErrorContains(c, err, "invalid IPv6 address")
  1430. // This is a special case of an IPv4-mapped IPv6 address
  1431. _, _, err = dockerCmdWithError("run", "--net=mynet", "--ip6", "::ffff:172.28.99.99", "busybox", "top")
  1432. assert.ErrorContains(c, err, "invalid IPv6 address")
  1433. }
  1434. // Test case for 26220
  1435. func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromBridge(c *testing.T) {
  1436. out, _ := dockerCmd(c, "network", "inspect", "--format", "{{.Id}}", "bridge")
  1437. network := strings.TrimSpace(out)
  1438. name := "test"
  1439. dockerCmd(c, "create", "--name", name, "busybox", "top")
  1440. _, _, err := dockerCmdWithError("network", "disconnect", network, name)
  1441. assert.NilError(c, err)
  1442. }
  1443. // TestConntrackFlowsLeak covers the failure scenario of ticket: https://github.com/docker/docker/issues/8795
  1444. // Validates that conntrack is correctly cleaned once a container is destroyed
  1445. func (s *DockerNetworkSuite) TestConntrackFlowsLeak(c *testing.T) {
  1446. testRequires(c, IsAmd64, DaemonIsLinux, Network, testEnv.IsLocalDaemon)
  1447. // Create a new network
  1448. cli.DockerCmd(c, "network", "create", "--subnet=192.168.10.0/24", "--gateway=192.168.10.1", "-o", "com.docker.network.bridge.host_binding_ipv4=192.168.10.1", "testbind")
  1449. assertNwIsAvailable(c, "testbind")
  1450. // Launch the server, this will remain listening on an exposed port and reply to any request in a ping/pong fashion
  1451. cmd := "while true; do echo hello | nc -w 1 -l -u -p 8080; done"
  1452. cli.DockerCmd(c, "run", "-d", "--name", "server", "--net", "testbind", "-p", "8080:8080/udp", "busybox", "sh", "-c", cmd)
  1453. // Launch a container client, here the objective is to create a flow that is natted in order to expose the bug
  1454. cmd = "echo world | nc -w 1 -u 192.168.10.1 8080"
  1455. cli.DockerCmd(c, "run", "-d", "--name", "client", "--net=host", "busybox", "sh", "-c", cmd)
  1456. // Get all the flows using netlink
  1457. flows, err := netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET)
  1458. assert.NilError(c, err)
  1459. var flowMatch int
  1460. for _, flow := range flows {
  1461. // count only the flows that we are interested in, skipping others that can be laying around the host
  1462. if flow.Forward.Protocol == unix.IPPROTO_UDP &&
  1463. flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
  1464. flow.Forward.DstPort == 8080 {
  1465. flowMatch++
  1466. }
  1467. }
  1468. // The client should have created only 1 flow
  1469. assert.Equal(c, flowMatch, 1)
  1470. // Now delete the server, this will trigger the conntrack cleanup
  1471. cli.DockerCmd(c, "rm", "-fv", "server")
  1472. // Fetch again all the flows and validate that there is no server flow in the conntrack laying around
  1473. flows, err = netlink.ConntrackTableList(netlink.ConntrackTable, unix.AF_INET)
  1474. assert.NilError(c, err)
  1475. flowMatch = 0
  1476. for _, flow := range flows {
  1477. if flow.Forward.Protocol == unix.IPPROTO_UDP &&
  1478. flow.Forward.DstIP.Equal(net.ParseIP("192.168.10.1")) &&
  1479. flow.Forward.DstPort == 8080 {
  1480. flowMatch++
  1481. }
  1482. }
  1483. // All the flows have to be gone
  1484. assert.Equal(c, flowMatch, 0)
  1485. }