Browse code

libnetwork/drivers/bridge: rename some linux-only files

This makes it easier to spot if code is only used on Linux. Note that "all of"
the bridge driver is Linux-only.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2023/08/10 19:34:24
Showing 34 changed files
1 1
deleted file mode 100644
... ...
@@ -1,1504 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"context"
7
-	"errors"
8
-	"fmt"
9
-	"net"
10
-	"os"
11
-	"os/exec"
12
-	"strconv"
13
-	"sync"
14
-
15
-	"github.com/containerd/containerd/log"
16
-	"github.com/docker/docker/libnetwork/datastore"
17
-	"github.com/docker/docker/libnetwork/driverapi"
18
-	"github.com/docker/docker/libnetwork/iptables"
19
-	"github.com/docker/docker/libnetwork/netlabel"
20
-	"github.com/docker/docker/libnetwork/netutils"
21
-	"github.com/docker/docker/libnetwork/ns"
22
-	"github.com/docker/docker/libnetwork/options"
23
-	"github.com/docker/docker/libnetwork/portallocator"
24
-	"github.com/docker/docker/libnetwork/portmapper"
25
-	"github.com/docker/docker/libnetwork/scope"
26
-	"github.com/docker/docker/libnetwork/types"
27
-	"github.com/vishvananda/netlink"
28
-)
29
-
30
-const (
31
-	NetworkType                = "bridge"
32
-	vethPrefix                 = "veth"
33
-	vethLen                    = len(vethPrefix) + 7
34
-	defaultContainerVethPrefix = "eth"
35
-	maxAllocatePortAttempts    = 10
36
-)
37
-
38
-const (
39
-	// DefaultGatewayV4AuxKey represents the default-gateway configured by the user
40
-	DefaultGatewayV4AuxKey = "DefaultGatewayIPv4"
41
-	// DefaultGatewayV6AuxKey represents the ipv6 default-gateway configured by the user
42
-	DefaultGatewayV6AuxKey = "DefaultGatewayIPv6"
43
-)
44
-
45
-type defaultBridgeNetworkConflict struct {
46
-	ID string
47
-}
48
-
49
-func (d defaultBridgeNetworkConflict) Error() string {
50
-	return fmt.Sprintf("Stale default bridge network %s", d.ID)
51
-}
52
-
53
-type (
54
-	iptableCleanFunc   func() error
55
-	iptablesCleanFuncs []iptableCleanFunc
56
-)
57
-
58
-// configuration info for the "bridge" driver.
59
-type configuration struct {
60
-	EnableIPForwarding  bool
61
-	EnableIPTables      bool
62
-	EnableIP6Tables     bool
63
-	EnableUserlandProxy bool
64
-	UserlandProxyPath   string
65
-}
66
-
67
-// networkConfiguration for network specific configuration
68
-type networkConfiguration struct {
69
-	ID                   string
70
-	BridgeName           string
71
-	EnableIPv6           bool
72
-	EnableIPMasquerade   bool
73
-	EnableICC            bool
74
-	InhibitIPv4          bool
75
-	Mtu                  int
76
-	DefaultBindingIP     net.IP
77
-	DefaultBridge        bool
78
-	HostIP               net.IP
79
-	ContainerIfacePrefix string
80
-	// Internal fields set after ipam data parsing
81
-	AddressIPv4        *net.IPNet
82
-	AddressIPv6        *net.IPNet
83
-	DefaultGatewayIPv4 net.IP
84
-	DefaultGatewayIPv6 net.IP
85
-	dbIndex            uint64
86
-	dbExists           bool
87
-	Internal           bool
88
-
89
-	BridgeIfaceCreator ifaceCreator
90
-}
91
-
92
-// ifaceCreator represents how the bridge interface was created
93
-type ifaceCreator int8
94
-
95
-const (
96
-	ifaceCreatorUnknown ifaceCreator = iota
97
-	ifaceCreatedByLibnetwork
98
-	ifaceCreatedByUser
99
-)
100
-
101
-// endpointConfiguration represents the user specified configuration for the sandbox endpoint
102
-type endpointConfiguration struct {
103
-	MacAddress net.HardwareAddr
104
-}
105
-
106
-// containerConfiguration represents the user specified configuration for a container
107
-type containerConfiguration struct {
108
-	ParentEndpoints []string
109
-	ChildEndpoints  []string
110
-}
111
-
112
-// connectivityConfiguration represents the user specified configuration regarding the external connectivity
113
-type connectivityConfiguration struct {
114
-	PortBindings []types.PortBinding
115
-	ExposedPorts []types.TransportPort
116
-}
117
-
118
-type bridgeEndpoint struct {
119
-	id              string
120
-	nid             string
121
-	srcName         string
122
-	addr            *net.IPNet
123
-	addrv6          *net.IPNet
124
-	macAddress      net.HardwareAddr
125
-	config          *endpointConfiguration // User specified parameters
126
-	containerConfig *containerConfiguration
127
-	extConnConfig   *connectivityConfiguration
128
-	portMapping     []types.PortBinding // Operation port bindings
129
-	dbIndex         uint64
130
-	dbExists        bool
131
-}
132
-
133
-type bridgeNetwork struct {
134
-	id            string
135
-	bridge        *bridgeInterface // The bridge's L3 interface
136
-	config        *networkConfiguration
137
-	endpoints     map[string]*bridgeEndpoint // key: endpoint id
138
-	portMapper    *portmapper.PortMapper
139
-	portMapperV6  *portmapper.PortMapper
140
-	driver        *driver // The network's driver
141
-	iptCleanFuncs iptablesCleanFuncs
142
-	sync.Mutex
143
-}
144
-
145
-type driver struct {
146
-	config            configuration
147
-	natChain          *iptables.ChainInfo
148
-	filterChain       *iptables.ChainInfo
149
-	isolationChain1   *iptables.ChainInfo
150
-	isolationChain2   *iptables.ChainInfo
151
-	natChainV6        *iptables.ChainInfo
152
-	filterChainV6     *iptables.ChainInfo
153
-	isolationChain1V6 *iptables.ChainInfo
154
-	isolationChain2V6 *iptables.ChainInfo
155
-	networks          map[string]*bridgeNetwork
156
-	store             *datastore.Store
157
-	nlh               *netlink.Handle
158
-	configNetwork     sync.Mutex
159
-	portAllocator     *portallocator.PortAllocator // Overridable for tests.
160
-	sync.Mutex
161
-}
162
-
163
-// New constructs a new bridge driver
164
-func newDriver() *driver {
165
-	return &driver{
166
-		networks:      map[string]*bridgeNetwork{},
167
-		portAllocator: portallocator.Get(),
168
-	}
169
-}
170
-
171
-// Register registers a new instance of bridge driver.
172
-func Register(r driverapi.Registerer, config map[string]interface{}) error {
173
-	d := newDriver()
174
-	if err := d.configure(config); err != nil {
175
-		return err
176
-	}
177
-	return r.RegisterDriver(NetworkType, d, driverapi.Capability{
178
-		DataScope:         scope.Local,
179
-		ConnectivityScope: scope.Local,
180
-	})
181
-}
182
-
183
-// Validate performs a static validation on the network configuration parameters.
184
-// Whatever can be assessed a priori before attempting any programming.
185
-func (c *networkConfiguration) Validate() error {
186
-	if c.Mtu < 0 {
187
-		return ErrInvalidMtu(c.Mtu)
188
-	}
189
-
190
-	// If bridge v4 subnet is specified
191
-	if c.AddressIPv4 != nil {
192
-		// If default gw is specified, it must be part of bridge subnet
193
-		if c.DefaultGatewayIPv4 != nil {
194
-			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
195
-				return &ErrInvalidGateway{}
196
-			}
197
-		}
198
-	}
199
-
200
-	// If default v6 gw is specified, AddressIPv6 must be specified and gw must belong to AddressIPv6 subnet
201
-	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
202
-		if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) {
203
-			return &ErrInvalidGateway{}
204
-		}
205
-	}
206
-	return nil
207
-}
208
-
209
-// Conflicts check if two NetworkConfiguration objects overlap
210
-func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
211
-	if o == nil {
212
-		return errors.New("same configuration")
213
-	}
214
-
215
-	// Also empty, because only one network with empty name is allowed
216
-	if c.BridgeName == o.BridgeName {
217
-		return errors.New("networks have same bridge name")
218
-	}
219
-
220
-	// They must be in different subnets
221
-	if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
222
-		(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
223
-		return errors.New("networks have overlapping IPv4")
224
-	}
225
-
226
-	// They must be in different v6 subnets
227
-	if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) &&
228
-		(c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) {
229
-		return errors.New("networks have overlapping IPv6")
230
-	}
231
-
232
-	return nil
233
-}
234
-
235
-func (c *networkConfiguration) fromLabels(labels map[string]string) error {
236
-	var err error
237
-	for label, value := range labels {
238
-		switch label {
239
-		case BridgeName:
240
-			c.BridgeName = value
241
-		case netlabel.DriverMTU:
242
-			if c.Mtu, err = strconv.Atoi(value); err != nil {
243
-				return parseErr(label, value, err.Error())
244
-			}
245
-		case netlabel.EnableIPv6:
246
-			if c.EnableIPv6, err = strconv.ParseBool(value); err != nil {
247
-				return parseErr(label, value, err.Error())
248
-			}
249
-		case EnableIPMasquerade:
250
-			if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil {
251
-				return parseErr(label, value, err.Error())
252
-			}
253
-		case EnableICC:
254
-			if c.EnableICC, err = strconv.ParseBool(value); err != nil {
255
-				return parseErr(label, value, err.Error())
256
-			}
257
-		case InhibitIPv4:
258
-			if c.InhibitIPv4, err = strconv.ParseBool(value); err != nil {
259
-				return parseErr(label, value, err.Error())
260
-			}
261
-		case DefaultBridge:
262
-			if c.DefaultBridge, err = strconv.ParseBool(value); err != nil {
263
-				return parseErr(label, value, err.Error())
264
-			}
265
-		case DefaultBindingIP:
266
-			if c.DefaultBindingIP = net.ParseIP(value); c.DefaultBindingIP == nil {
267
-				return parseErr(label, value, "nil ip")
268
-			}
269
-		case netlabel.ContainerIfacePrefix:
270
-			c.ContainerIfacePrefix = value
271
-		case netlabel.HostIP:
272
-			if c.HostIP = net.ParseIP(value); c.HostIP == nil {
273
-				return parseErr(label, value, "nil ip")
274
-			}
275
-		}
276
-	}
277
-
278
-	return nil
279
-}
280
-
281
-func parseErr(label, value, errString string) error {
282
-	return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString)
283
-}
284
-
285
-func (n *bridgeNetwork) registerIptCleanFunc(clean iptableCleanFunc) {
286
-	n.iptCleanFuncs = append(n.iptCleanFuncs, clean)
287
-}
288
-
289
-func (n *bridgeNetwork) getDriverChains(version iptables.IPVersion) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
290
-	n.Lock()
291
-	defer n.Unlock()
292
-
293
-	if n.driver == nil {
294
-		return nil, nil, nil, nil, types.BadRequestErrorf("no driver found")
295
-	}
296
-
297
-	if version == iptables.IPv6 {
298
-		return n.driver.natChainV6, n.driver.filterChainV6, n.driver.isolationChain1V6, n.driver.isolationChain2V6, nil
299
-	}
300
-
301
-	return n.driver.natChain, n.driver.filterChain, n.driver.isolationChain1, n.driver.isolationChain2, nil
302
-}
303
-
304
-func (n *bridgeNetwork) getNetworkBridgeName() string {
305
-	n.Lock()
306
-	config := n.config
307
-	n.Unlock()
308
-
309
-	return config.BridgeName
310
-}
311
-
312
-func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
313
-	if eid == "" {
314
-		return nil, InvalidEndpointIDError(eid)
315
-	}
316
-
317
-	n.Lock()
318
-	defer n.Unlock()
319
-	if ep, ok := n.endpoints[eid]; ok {
320
-		return ep, nil
321
-	}
322
-
323
-	return nil, nil
324
-}
325
-
326
-// Install/Removes the iptables rules needed to isolate this network
327
-// from each of the other networks
328
-func (n *bridgeNetwork) isolateNetwork(enable bool) error {
329
-	n.Lock()
330
-	thisConfig := n.config
331
-	n.Unlock()
332
-
333
-	if thisConfig.Internal {
334
-		return nil
335
-	}
336
-
337
-	// Install the rules to isolate this network against each of the other networks
338
-	if n.driver.config.EnableIP6Tables {
339
-		err := setINC(iptables.IPv6, thisConfig.BridgeName, enable)
340
-		if err != nil {
341
-			return err
342
-		}
343
-	}
344
-
345
-	if n.driver.config.EnableIPTables {
346
-		return setINC(iptables.IPv4, thisConfig.BridgeName, enable)
347
-	}
348
-	return nil
349
-}
350
-
351
-func (d *driver) configure(option map[string]interface{}) error {
352
-	var (
353
-		config            configuration
354
-		err               error
355
-		natChain          *iptables.ChainInfo
356
-		filterChain       *iptables.ChainInfo
357
-		isolationChain1   *iptables.ChainInfo
358
-		isolationChain2   *iptables.ChainInfo
359
-		natChainV6        *iptables.ChainInfo
360
-		filterChainV6     *iptables.ChainInfo
361
-		isolationChain1V6 *iptables.ChainInfo
362
-		isolationChain2V6 *iptables.ChainInfo
363
-	)
364
-
365
-	switch opt := option[netlabel.GenericData].(type) {
366
-	case options.Generic:
367
-		opaqueConfig, err := options.GenerateFromModel(opt, &configuration{})
368
-		if err != nil {
369
-			return err
370
-		}
371
-		config = *opaqueConfig.(*configuration)
372
-	case *configuration:
373
-		config = *opt
374
-	case nil:
375
-		// No GenericData option set. Use defaults.
376
-	default:
377
-		return &ErrInvalidDriverConfig{}
378
-	}
379
-
380
-	if config.EnableIPTables || config.EnableIP6Tables {
381
-		if _, err := os.Stat("/proc/sys/net/bridge"); err != nil {
382
-			if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil {
383
-				log.G(context.TODO()).Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err)
384
-			}
385
-		}
386
-	}
387
-
388
-	if config.EnableIPTables {
389
-		removeIPChains(iptables.IPv4)
390
-
391
-		natChain, filterChain, isolationChain1, isolationChain2, err = setupIPChains(config, iptables.IPv4)
392
-		if err != nil {
393
-			return err
394
-		}
395
-
396
-		// Make sure on firewall reload, first thing being re-played is chains creation
397
-		iptables.OnReloaded(func() {
398
-			log.G(context.TODO()).Debugf("Recreating iptables chains on firewall reload")
399
-			if _, _, _, _, err := setupIPChains(config, iptables.IPv4); err != nil {
400
-				log.G(context.TODO()).WithError(err).Error("Error reloading iptables chains")
401
-			}
402
-		})
403
-	}
404
-
405
-	if config.EnableIP6Tables {
406
-		removeIPChains(iptables.IPv6)
407
-
408
-		natChainV6, filterChainV6, isolationChain1V6, isolationChain2V6, err = setupIPChains(config, iptables.IPv6)
409
-		if err != nil {
410
-			return err
411
-		}
412
-
413
-		// Make sure on firewall reload, first thing being re-played is chains creation
414
-		iptables.OnReloaded(func() {
415
-			log.G(context.TODO()).Debugf("Recreating ip6tables chains on firewall reload")
416
-			if _, _, _, _, err := setupIPChains(config, iptables.IPv6); err != nil {
417
-				log.G(context.TODO()).WithError(err).Error("Error reloading ip6tables chains")
418
-			}
419
-		})
420
-	}
421
-
422
-	if config.EnableIPForwarding {
423
-		err = setupIPForwarding(config.EnableIPTables, config.EnableIP6Tables)
424
-		if err != nil {
425
-			log.G(context.TODO()).Warn(err)
426
-			return err
427
-		}
428
-	}
429
-
430
-	d.Lock()
431
-	d.natChain = natChain
432
-	d.filterChain = filterChain
433
-	d.isolationChain1 = isolationChain1
434
-	d.isolationChain2 = isolationChain2
435
-	d.natChainV6 = natChainV6
436
-	d.filterChainV6 = filterChainV6
437
-	d.isolationChain1V6 = isolationChain1V6
438
-	d.isolationChain2V6 = isolationChain2V6
439
-	d.config = config
440
-	d.Unlock()
441
-
442
-	return d.initStore(option)
443
-}
444
-
445
-func (d *driver) getNetwork(id string) (*bridgeNetwork, error) {
446
-	d.Lock()
447
-	defer d.Unlock()
448
-
449
-	if id == "" {
450
-		return nil, types.BadRequestErrorf("invalid network id: %s", id)
451
-	}
452
-
453
-	if nw, ok := d.networks[id]; ok {
454
-		return nw, nil
455
-	}
456
-
457
-	return nil, types.NotFoundErrorf("network not found: %s", id)
458
-}
459
-
460
-func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) {
461
-	var (
462
-		err    error
463
-		config *networkConfiguration
464
-	)
465
-
466
-	switch opt := data.(type) {
467
-	case *networkConfiguration:
468
-		config = opt
469
-	case map[string]string:
470
-		config = &networkConfiguration{
471
-			EnableICC:          true,
472
-			EnableIPMasquerade: true,
473
-		}
474
-		err = config.fromLabels(opt)
475
-	case options.Generic:
476
-		var opaqueConfig interface{}
477
-		if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil {
478
-			config = opaqueConfig.(*networkConfiguration)
479
-		}
480
-	default:
481
-		err = types.BadRequestErrorf("do not recognize network configuration format: %T", opt)
482
-	}
483
-
484
-	return config, err
485
-}
486
-
487
-func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
488
-	if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 {
489
-		return types.ForbiddenErrorf("bridge driver doesn't support multiple subnets")
490
-	}
491
-
492
-	if len(ipamV4Data) == 0 {
493
-		return types.BadRequestErrorf("bridge network %s requires ipv4 configuration", id)
494
-	}
495
-
496
-	if ipamV4Data[0].Gateway != nil {
497
-		c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway)
498
-	}
499
-
500
-	if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok {
501
-		c.DefaultGatewayIPv4 = gw.IP
502
-	}
503
-
504
-	if len(ipamV6Data) > 0 {
505
-		c.AddressIPv6 = ipamV6Data[0].Pool
506
-
507
-		if ipamV6Data[0].Gateway != nil {
508
-			c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway)
509
-		}
510
-
511
-		if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok {
512
-			c.DefaultGatewayIPv6 = gw.IP
513
-		}
514
-	}
515
-
516
-	return nil
517
-}
518
-
519
-func parseNetworkOptions(id string, option options.Generic) (*networkConfiguration, error) {
520
-	var (
521
-		err    error
522
-		config = &networkConfiguration{}
523
-	)
524
-
525
-	// Parse generic label first, config will be re-assigned
526
-	if genData, ok := option[netlabel.GenericData]; ok && genData != nil {
527
-		if config, err = parseNetworkGenericOptions(genData); err != nil {
528
-			return nil, err
529
-		}
530
-	}
531
-
532
-	// Process well-known labels next
533
-	if val, ok := option[netlabel.EnableIPv6]; ok {
534
-		config.EnableIPv6 = val.(bool)
535
-	}
536
-
537
-	if val, ok := option[netlabel.Internal]; ok {
538
-		if internal, ok := val.(bool); ok && internal {
539
-			config.Internal = true
540
-		}
541
-	}
542
-
543
-	// Finally validate the configuration
544
-	if err = config.Validate(); err != nil {
545
-		return nil, err
546
-	}
547
-
548
-	if config.BridgeName == "" && !config.DefaultBridge {
549
-		config.BridgeName = "br-" + id[:12]
550
-	}
551
-
552
-	exists, err := bridgeInterfaceExists(config.BridgeName)
553
-	if err != nil {
554
-		return nil, err
555
-	}
556
-
557
-	if !exists {
558
-		config.BridgeIfaceCreator = ifaceCreatedByLibnetwork
559
-	} else {
560
-		config.BridgeIfaceCreator = ifaceCreatedByUser
561
-	}
562
-
563
-	config.ID = id
564
-	return config, nil
565
-}
566
-
567
-// Return a slice of networks over which caller can iterate safely
568
-func (d *driver) getNetworks() []*bridgeNetwork {
569
-	d.Lock()
570
-	defer d.Unlock()
571
-
572
-	ls := make([]*bridgeNetwork, 0, len(d.networks))
573
-	for _, nw := range d.networks {
574
-		ls = append(ls, nw)
575
-	}
576
-	return ls
577
-}
578
-
579
-func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
580
-	return nil, types.NotImplementedErrorf("not implemented")
581
-}
582
-
583
-func (d *driver) NetworkFree(id string) error {
584
-	return types.NotImplementedErrorf("not implemented")
585
-}
586
-
587
-func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
588
-}
589
-
590
-func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
591
-	return "", nil
592
-}
593
-
594
-// Create a new network using bridge plugin
595
-func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
596
-	if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
597
-		return types.BadRequestErrorf("ipv4 pool is empty")
598
-	}
599
-	// Sanity checks
600
-	d.Lock()
601
-	if _, ok := d.networks[id]; ok {
602
-		d.Unlock()
603
-		return types.ForbiddenErrorf("network %s exists", id)
604
-	}
605
-	d.Unlock()
606
-
607
-	// Parse and validate the config. It should not be conflict with existing networks' config
608
-	config, err := parseNetworkOptions(id, option)
609
-	if err != nil {
610
-		return err
611
-	}
612
-
613
-	if err = config.processIPAM(id, ipV4Data, ipV6Data); err != nil {
614
-		return err
615
-	}
616
-
617
-	// start the critical section, from this point onward we are dealing with the list of networks
618
-	// so to be consistent we cannot allow that the list changes
619
-	d.configNetwork.Lock()
620
-	defer d.configNetwork.Unlock()
621
-
622
-	// check network conflicts
623
-	if err = d.checkConflict(config); err != nil {
624
-		nerr, ok := err.(defaultBridgeNetworkConflict)
625
-		if !ok {
626
-			return err
627
-		}
628
-		// Got a conflict with a stale default network, clean that up and continue
629
-		log.G(context.TODO()).Warn(nerr)
630
-		if err := d.deleteNetwork(nerr.ID); err != nil {
631
-			log.G(context.TODO()).WithError(err).Debug("Error while cleaning up network on conflict")
632
-		}
633
-	}
634
-
635
-	// there is no conflict, now create the network
636
-	if err = d.createNetwork(config); err != nil {
637
-		return err
638
-	}
639
-
640
-	return d.storeUpdate(config)
641
-}
642
-
643
-func (d *driver) checkConflict(config *networkConfiguration) error {
644
-	networkList := d.getNetworks()
645
-	for _, nw := range networkList {
646
-		nw.Lock()
647
-		nwConfig := nw.config
648
-		nw.Unlock()
649
-		if err := nwConfig.Conflicts(config); err != nil {
650
-			if nwConfig.DefaultBridge {
651
-				// We encountered and identified a stale default network
652
-				// We must delete it as libnetwork is the source of truth
653
-				// The default network being created must be the only one
654
-				// This can happen only from docker 1.12 on ward
655
-				log.G(context.TODO()).Infof("Found stale default bridge network %s (%s)", nwConfig.ID, nwConfig.BridgeName)
656
-				return defaultBridgeNetworkConflict{nwConfig.ID}
657
-			}
658
-
659
-			return types.ForbiddenErrorf("cannot create network %s (%s): conflicts with network %s (%s): %s",
660
-				config.ID, config.BridgeName, nwConfig.ID, nwConfig.BridgeName, err.Error())
661
-		}
662
-	}
663
-	return nil
664
-}
665
-
666
-func (d *driver) createNetwork(config *networkConfiguration) (err error) {
667
-	// Initialize handle when needed
668
-	d.Lock()
669
-	if d.nlh == nil {
670
-		d.nlh = ns.NlHandle()
671
-	}
672
-	d.Unlock()
673
-
674
-	// Create or retrieve the bridge L3 interface
675
-	bridgeIface, err := newInterface(d.nlh, config)
676
-	if err != nil {
677
-		return err
678
-	}
679
-
680
-	// Create and set network handler in driver
681
-	network := &bridgeNetwork{
682
-		id:           config.ID,
683
-		endpoints:    make(map[string]*bridgeEndpoint),
684
-		config:       config,
685
-		portMapper:   portmapper.NewWithPortAllocator(d.portAllocator, d.config.UserlandProxyPath),
686
-		portMapperV6: portmapper.NewWithPortAllocator(d.portAllocator, d.config.UserlandProxyPath),
687
-		bridge:       bridgeIface,
688
-		driver:       d,
689
-	}
690
-
691
-	d.Lock()
692
-	d.networks[config.ID] = network
693
-	d.Unlock()
694
-
695
-	// On failure make sure to reset driver network handler to nil
696
-	defer func() {
697
-		if err != nil {
698
-			d.Lock()
699
-			delete(d.networks, config.ID)
700
-			d.Unlock()
701
-		}
702
-	}()
703
-
704
-	// Add inter-network communication rules.
705
-	setupNetworkIsolationRules := func(config *networkConfiguration, i *bridgeInterface) error {
706
-		if err := network.isolateNetwork(true); err != nil {
707
-			if err = network.isolateNetwork(false); err != nil {
708
-				log.G(context.TODO()).Warnf("Failed on removing the inter-network iptables rules on cleanup: %v", err)
709
-			}
710
-			return err
711
-		}
712
-		// register the cleanup function
713
-		network.registerIptCleanFunc(func() error {
714
-			return network.isolateNetwork(false)
715
-		})
716
-		return nil
717
-	}
718
-
719
-	// Prepare the bridge setup configuration
720
-	bridgeSetup := newBridgeSetup(config, bridgeIface)
721
-
722
-	// If the bridge interface doesn't exist, we need to start the setup steps
723
-	// by creating a new device and assigning it an IPv4 address.
724
-	bridgeAlreadyExists := bridgeIface.exists()
725
-	if !bridgeAlreadyExists {
726
-		bridgeSetup.queueStep(setupDevice)
727
-		bridgeSetup.queueStep(setupDefaultSysctl)
728
-	}
729
-
730
-	// For the default bridge, set expected sysctls
731
-	if config.DefaultBridge {
732
-		bridgeSetup.queueStep(setupDefaultSysctl)
733
-	}
734
-
735
-	// Even if a bridge exists try to setup IPv4.
736
-	bridgeSetup.queueStep(setupBridgeIPv4)
737
-
738
-	enableIPv6Forwarding := d.config.EnableIPForwarding && config.AddressIPv6 != nil
739
-
740
-	// Conditionally queue setup steps depending on configuration values.
741
-	for _, step := range []struct {
742
-		Condition bool
743
-		Fn        setupStep
744
-	}{
745
-		// Enable IPv6 on the bridge if required. We do this even for a
746
-		// previously  existing bridge, as it may be here from a previous
747
-		// installation where IPv6 wasn't supported yet and needs to be
748
-		// assigned an IPv6 link-local address.
749
-		{config.EnableIPv6, setupBridgeIPv6},
750
-
751
-		// We ensure that the bridge has the expectedIPv4 and IPv6 addresses in
752
-		// the case of a previously existing device.
753
-		{bridgeAlreadyExists && !config.InhibitIPv4, setupVerifyAndReconcile},
754
-
755
-		// Enable IPv6 Forwarding
756
-		{enableIPv6Forwarding, setupIPv6Forwarding},
757
-
758
-		// Setup Loopback Addresses Routing
759
-		{!d.config.EnableUserlandProxy, setupLoopbackAddressesRouting},
760
-
761
-		// Setup IPTables.
762
-		{d.config.EnableIPTables, network.setupIP4Tables},
763
-
764
-		// Setup IP6Tables.
765
-		{config.EnableIPv6 && d.config.EnableIP6Tables, network.setupIP6Tables},
766
-
767
-		// We want to track firewalld configuration so that
768
-		// if it is started/reloaded, the rules can be applied correctly
769
-		{d.config.EnableIPTables, network.setupFirewalld},
770
-		// same for IPv6
771
-		{config.EnableIPv6 && d.config.EnableIP6Tables, network.setupFirewalld6},
772
-
773
-		// Setup DefaultGatewayIPv4
774
-		{config.DefaultGatewayIPv4 != nil, setupGatewayIPv4},
775
-
776
-		// Setup DefaultGatewayIPv6
777
-		{config.DefaultGatewayIPv6 != nil, setupGatewayIPv6},
778
-
779
-		// Add inter-network communication rules.
780
-		{d.config.EnableIPTables, setupNetworkIsolationRules},
781
-
782
-		// Configure bridge networking filtering if ICC is off and IP tables are enabled
783
-		{!config.EnableICC && d.config.EnableIPTables, setupBridgeNetFiltering},
784
-	} {
785
-		if step.Condition {
786
-			bridgeSetup.queueStep(step.Fn)
787
-		}
788
-	}
789
-
790
-	// Apply the prepared list of steps, and abort at the first error.
791
-	bridgeSetup.queueStep(setupDeviceUp)
792
-	return bridgeSetup.apply()
793
-}
794
-
795
-func (d *driver) DeleteNetwork(nid string) error {
796
-	d.configNetwork.Lock()
797
-	defer d.configNetwork.Unlock()
798
-
799
-	return d.deleteNetwork(nid)
800
-}
801
-
802
-func (d *driver) deleteNetwork(nid string) error {
803
-	var err error
804
-
805
-	// Get network handler and remove it from driver
806
-	d.Lock()
807
-	n, ok := d.networks[nid]
808
-	d.Unlock()
809
-
810
-	if !ok {
811
-		return types.InternalMaskableErrorf("network %s does not exist", nid)
812
-	}
813
-
814
-	n.Lock()
815
-	config := n.config
816
-	n.Unlock()
817
-
818
-	// delele endpoints belong to this network
819
-	for _, ep := range n.endpoints {
820
-		if err := n.releasePorts(ep); err != nil {
821
-			log.G(context.TODO()).Warn(err)
822
-		}
823
-		if link, err := d.nlh.LinkByName(ep.srcName); err == nil {
824
-			if err := d.nlh.LinkDel(link); err != nil {
825
-				log.G(context.TODO()).WithError(err).Errorf("Failed to delete interface (%s)'s link on endpoint (%s) delete", ep.srcName, ep.id)
826
-			}
827
-		}
828
-
829
-		if err := d.storeDelete(ep); err != nil {
830
-			log.G(context.TODO()).Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err)
831
-		}
832
-	}
833
-
834
-	d.Lock()
835
-	delete(d.networks, nid)
836
-	d.Unlock()
837
-
838
-	// On failure set network handler back in driver, but
839
-	// only if is not already taken over by some other thread
840
-	defer func() {
841
-		if err != nil {
842
-			d.Lock()
843
-			if _, ok := d.networks[nid]; !ok {
844
-				d.networks[nid] = n
845
-			}
846
-			d.Unlock()
847
-		}
848
-	}()
849
-
850
-	switch config.BridgeIfaceCreator {
851
-	case ifaceCreatedByLibnetwork, ifaceCreatorUnknown:
852
-		// We only delete the bridge if it was created by the bridge driver and
853
-		// it is not the default one (to keep the backward compatible behavior.)
854
-		if !config.DefaultBridge {
855
-			if err := d.nlh.LinkDel(n.bridge.Link); err != nil {
856
-				log.G(context.TODO()).Warnf("Failed to remove bridge interface %s on network %s delete: %v", config.BridgeName, nid, err)
857
-			}
858
-		}
859
-	case ifaceCreatedByUser:
860
-		// Don't delete the bridge interface if it was not created by libnetwork.
861
-	}
862
-
863
-	// clean all relevant iptables rules
864
-	for _, cleanFunc := range n.iptCleanFuncs {
865
-		if errClean := cleanFunc(); errClean != nil {
866
-			log.G(context.TODO()).Warnf("Failed to clean iptables rules for bridge network: %v", errClean)
867
-		}
868
-	}
869
-	return d.storeDelete(config)
870
-}
871
-
872
-func addToBridge(nlh *netlink.Handle, ifaceName, bridgeName string) error {
873
-	lnk, err := nlh.LinkByName(ifaceName)
874
-	if err != nil {
875
-		return fmt.Errorf("could not find interface %s: %v", ifaceName, err)
876
-	}
877
-	if err := nlh.LinkSetMaster(lnk, &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}); err != nil {
878
-		log.G(context.TODO()).WithError(err).Errorf("Failed to add %s to bridge via netlink", ifaceName)
879
-		return err
880
-	}
881
-	return nil
882
-}
883
-
884
-func setHairpinMode(nlh *netlink.Handle, link netlink.Link, enable bool) error {
885
-	err := nlh.LinkSetHairpin(link, enable)
886
-	if err != nil {
887
-		return fmt.Errorf("unable to set hairpin mode on %s via netlink: %v",
888
-			link.Attrs().Name, err)
889
-	}
890
-	return nil
891
-}
892
-
893
-func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
894
-	if ifInfo == nil {
895
-		return errors.New("invalid interface info passed")
896
-	}
897
-
898
-	// Get the network handler and make sure it exists
899
-	d.Lock()
900
-	n, ok := d.networks[nid]
901
-	dconfig := d.config
902
-	d.Unlock()
903
-
904
-	if !ok {
905
-		return types.NotFoundErrorf("network %s does not exist", nid)
906
-	}
907
-	if n == nil {
908
-		return driverapi.ErrNoNetwork(nid)
909
-	}
910
-
911
-	// Sanity check
912
-	n.Lock()
913
-	if n.id != nid {
914
-		n.Unlock()
915
-		return InvalidNetworkIDError(nid)
916
-	}
917
-	n.Unlock()
918
-
919
-	// Check if endpoint id is good and retrieve correspondent endpoint
920
-	ep, err := n.getEndpoint(eid)
921
-	if err != nil {
922
-		return err
923
-	}
924
-
925
-	// Endpoint with that id exists either on desired or other sandbox
926
-	if ep != nil {
927
-		return driverapi.ErrEndpointExists(eid)
928
-	}
929
-
930
-	// Try to convert the options to endpoint configuration
931
-	epConfig, err := parseEndpointOptions(epOptions)
932
-	if err != nil {
933
-		return err
934
-	}
935
-
936
-	// Create and add the endpoint
937
-	n.Lock()
938
-	endpoint := &bridgeEndpoint{id: eid, nid: nid, config: epConfig}
939
-	n.endpoints[eid] = endpoint
940
-	n.Unlock()
941
-
942
-	// On failure make sure to remove the endpoint
943
-	defer func() {
944
-		if err != nil {
945
-			n.Lock()
946
-			delete(n.endpoints, eid)
947
-			n.Unlock()
948
-		}
949
-	}()
950
-
951
-	// Generate a name for what will be the host side pipe interface
952
-	hostIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
953
-	if err != nil {
954
-		return err
955
-	}
956
-
957
-	// Generate a name for what will be the sandbox side pipe interface
958
-	containerIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
959
-	if err != nil {
960
-		return err
961
-	}
962
-
963
-	// Generate and add the interface pipe host <-> sandbox
964
-	veth := &netlink.Veth{
965
-		LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
966
-		PeerName:  containerIfName,
967
-	}
968
-	if err = d.nlh.LinkAdd(veth); err != nil {
969
-		return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err)
970
-	}
971
-
972
-	// Get the host side pipe interface handler
973
-	host, err := d.nlh.LinkByName(hostIfName)
974
-	if err != nil {
975
-		return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err)
976
-	}
977
-	defer func() {
978
-		if err != nil {
979
-			if err := d.nlh.LinkDel(host); err != nil {
980
-				log.G(context.TODO()).WithError(err).Warnf("Failed to delete host side interface (%s)'s link", hostIfName)
981
-			}
982
-		}
983
-	}()
984
-
985
-	// Get the sandbox side pipe interface handler
986
-	sbox, err := d.nlh.LinkByName(containerIfName)
987
-	if err != nil {
988
-		return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err)
989
-	}
990
-	defer func() {
991
-		if err != nil {
992
-			if err := d.nlh.LinkDel(sbox); err != nil {
993
-				log.G(context.TODO()).WithError(err).Warnf("Failed to delete sandbox side interface (%s)'s link", containerIfName)
994
-			}
995
-		}
996
-	}()
997
-
998
-	n.Lock()
999
-	config := n.config
1000
-	n.Unlock()
1001
-
1002
-	// Add bridge inherited attributes to pipe interfaces
1003
-	if config.Mtu != 0 {
1004
-		err = d.nlh.LinkSetMTU(host, config.Mtu)
1005
-		if err != nil {
1006
-			return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err)
1007
-		}
1008
-		err = d.nlh.LinkSetMTU(sbox, config.Mtu)
1009
-		if err != nil {
1010
-			return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err)
1011
-		}
1012
-	}
1013
-
1014
-	// Attach host side pipe interface into the bridge
1015
-	if err = addToBridge(d.nlh, hostIfName, config.BridgeName); err != nil {
1016
-		return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
1017
-	}
1018
-
1019
-	if !dconfig.EnableUserlandProxy {
1020
-		err = setHairpinMode(d.nlh, host, true)
1021
-		if err != nil {
1022
-			return err
1023
-		}
1024
-	}
1025
-
1026
-	// Store the sandbox side pipe interface parameters
1027
-	endpoint.srcName = containerIfName
1028
-	endpoint.macAddress = ifInfo.MacAddress()
1029
-	endpoint.addr = ifInfo.Address()
1030
-	endpoint.addrv6 = ifInfo.AddressIPv6()
1031
-
1032
-	// Set the sbox's MAC if not provided. If specified, use the one configured by user, otherwise generate one based on IP.
1033
-	if endpoint.macAddress == nil {
1034
-		endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
1035
-		if err = ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
1036
-			return err
1037
-		}
1038
-	}
1039
-
1040
-	// Up the host interface after finishing all netlink configuration
1041
-	if err = d.nlh.LinkSetUp(host); err != nil {
1042
-		return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
1043
-	}
1044
-
1045
-	if endpoint.addrv6 == nil && config.EnableIPv6 {
1046
-		var ip6 net.IP
1047
-		network := n.bridge.bridgeIPv6
1048
-		if config.AddressIPv6 != nil {
1049
-			network = config.AddressIPv6
1050
-		}
1051
-
1052
-		ones, _ := network.Mask.Size()
1053
-		if ones > 80 {
1054
-			err = types.ForbiddenErrorf("Cannot self generate an IPv6 address on network %v: At least 48 host bits are needed.", network)
1055
-			return err
1056
-		}
1057
-
1058
-		ip6 = make(net.IP, len(network.IP))
1059
-		copy(ip6, network.IP)
1060
-		for i, h := range endpoint.macAddress {
1061
-			ip6[i+10] = h
1062
-		}
1063
-
1064
-		endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
1065
-		if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
1066
-			return err
1067
-		}
1068
-	}
1069
-
1070
-	if err = d.storeUpdate(endpoint); err != nil {
1071
-		return fmt.Errorf("failed to save bridge endpoint %.7s to store: %v", endpoint.id, err)
1072
-	}
1073
-
1074
-	return nil
1075
-}
1076
-
1077
-func (d *driver) DeleteEndpoint(nid, eid string) error {
1078
-	var err error
1079
-
1080
-	// Get the network handler and make sure it exists
1081
-	d.Lock()
1082
-	n, ok := d.networks[nid]
1083
-	d.Unlock()
1084
-
1085
-	if !ok {
1086
-		return types.InternalMaskableErrorf("network %s does not exist", nid)
1087
-	}
1088
-	if n == nil {
1089
-		return driverapi.ErrNoNetwork(nid)
1090
-	}
1091
-
1092
-	// Sanity Check
1093
-	n.Lock()
1094
-	if n.id != nid {
1095
-		n.Unlock()
1096
-		return InvalidNetworkIDError(nid)
1097
-	}
1098
-	n.Unlock()
1099
-
1100
-	// Check endpoint id and if an endpoint is actually there
1101
-	ep, err := n.getEndpoint(eid)
1102
-	if err != nil {
1103
-		return err
1104
-	}
1105
-	if ep == nil {
1106
-		return EndpointNotFoundError(eid)
1107
-	}
1108
-
1109
-	// Remove it
1110
-	n.Lock()
1111
-	delete(n.endpoints, eid)
1112
-	n.Unlock()
1113
-
1114
-	// On failure make sure to set back ep in n.endpoints, but only
1115
-	// if it hasn't been taken over already by some other thread.
1116
-	defer func() {
1117
-		if err != nil {
1118
-			n.Lock()
1119
-			if _, ok := n.endpoints[eid]; !ok {
1120
-				n.endpoints[eid] = ep
1121
-			}
1122
-			n.Unlock()
1123
-		}
1124
-	}()
1125
-
1126
-	// Try removal of link. Discard error: it is a best effort.
1127
-	// Also make sure defer does not see this error either.
1128
-	if link, err := d.nlh.LinkByName(ep.srcName); err == nil {
1129
-		if err := d.nlh.LinkDel(link); err != nil {
1130
-			log.G(context.TODO()).WithError(err).Errorf("Failed to delete interface (%s)'s link on endpoint (%s) delete", ep.srcName, ep.id)
1131
-		}
1132
-	}
1133
-
1134
-	if err := d.storeDelete(ep); err != nil {
1135
-		log.G(context.TODO()).Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err)
1136
-	}
1137
-
1138
-	return nil
1139
-}
1140
-
1141
-func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
1142
-	// Get the network handler and make sure it exists
1143
-	d.Lock()
1144
-	n, ok := d.networks[nid]
1145
-	d.Unlock()
1146
-	if !ok {
1147
-		return nil, types.NotFoundErrorf("network %s does not exist", nid)
1148
-	}
1149
-	if n == nil {
1150
-		return nil, driverapi.ErrNoNetwork(nid)
1151
-	}
1152
-
1153
-	// Sanity check
1154
-	n.Lock()
1155
-	if n.id != nid {
1156
-		n.Unlock()
1157
-		return nil, InvalidNetworkIDError(nid)
1158
-	}
1159
-	n.Unlock()
1160
-
1161
-	// Check if endpoint id is good and retrieve correspondent endpoint
1162
-	ep, err := n.getEndpoint(eid)
1163
-	if err != nil {
1164
-		return nil, err
1165
-	}
1166
-	if ep == nil {
1167
-		return nil, driverapi.ErrNoEndpoint(eid)
1168
-	}
1169
-
1170
-	m := make(map[string]interface{})
1171
-
1172
-	if ep.extConnConfig != nil && ep.extConnConfig.ExposedPorts != nil {
1173
-		// Return a copy of the config data
1174
-		epc := make([]types.TransportPort, 0, len(ep.extConnConfig.ExposedPorts))
1175
-		for _, tp := range ep.extConnConfig.ExposedPorts {
1176
-			epc = append(epc, tp.GetCopy())
1177
-		}
1178
-		m[netlabel.ExposedPorts] = epc
1179
-	}
1180
-
1181
-	if ep.portMapping != nil {
1182
-		// Return a copy of the operational data
1183
-		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
1184
-		for _, pm := range ep.portMapping {
1185
-			pmc = append(pmc, pm.GetCopy())
1186
-		}
1187
-		m[netlabel.PortMap] = pmc
1188
-	}
1189
-
1190
-	if len(ep.macAddress) != 0 {
1191
-		m[netlabel.MacAddress] = ep.macAddress
1192
-	}
1193
-
1194
-	return m, nil
1195
-}
1196
-
1197
-// Join method is invoked when a Sandbox is attached to an endpoint.
1198
-func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
1199
-	network, err := d.getNetwork(nid)
1200
-	if err != nil {
1201
-		return err
1202
-	}
1203
-
1204
-	endpoint, err := network.getEndpoint(eid)
1205
-	if err != nil {
1206
-		return err
1207
-	}
1208
-
1209
-	if endpoint == nil {
1210
-		return EndpointNotFoundError(eid)
1211
-	}
1212
-
1213
-	endpoint.containerConfig, err = parseContainerOptions(options)
1214
-	if err != nil {
1215
-		return err
1216
-	}
1217
-
1218
-	iNames := jinfo.InterfaceName()
1219
-	containerVethPrefix := defaultContainerVethPrefix
1220
-	if network.config.ContainerIfacePrefix != "" {
1221
-		containerVethPrefix = network.config.ContainerIfacePrefix
1222
-	}
1223
-	err = iNames.SetNames(endpoint.srcName, containerVethPrefix)
1224
-	if err != nil {
1225
-		return err
1226
-	}
1227
-
1228
-	err = jinfo.SetGateway(network.bridge.gatewayIPv4)
1229
-	if err != nil {
1230
-		return err
1231
-	}
1232
-
1233
-	err = jinfo.SetGatewayIPv6(network.bridge.gatewayIPv6)
1234
-	if err != nil {
1235
-		return err
1236
-	}
1237
-
1238
-	return nil
1239
-}
1240
-
1241
-// Leave method is invoked when a Sandbox detaches from an endpoint.
1242
-func (d *driver) Leave(nid, eid string) error {
1243
-	network, err := d.getNetwork(nid)
1244
-	if err != nil {
1245
-		return types.InternalMaskableErrorf("%s", err)
1246
-	}
1247
-
1248
-	endpoint, err := network.getEndpoint(eid)
1249
-	if err != nil {
1250
-		return err
1251
-	}
1252
-
1253
-	if endpoint == nil {
1254
-		return EndpointNotFoundError(eid)
1255
-	}
1256
-
1257
-	if !network.config.EnableICC {
1258
-		if err = d.link(network, endpoint, false); err != nil {
1259
-			return err
1260
-		}
1261
-	}
1262
-
1263
-	return nil
1264
-}
1265
-
1266
-func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
1267
-	network, err := d.getNetwork(nid)
1268
-	if err != nil {
1269
-		return err
1270
-	}
1271
-
1272
-	endpoint, err := network.getEndpoint(eid)
1273
-	if err != nil {
1274
-		return err
1275
-	}
1276
-
1277
-	if endpoint == nil {
1278
-		return EndpointNotFoundError(eid)
1279
-	}
1280
-
1281
-	endpoint.extConnConfig, err = parseConnectivityOptions(options)
1282
-	if err != nil {
1283
-		return err
1284
-	}
1285
-
1286
-	// Program any required port mapping and store them in the endpoint
1287
-	endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIP, d.config.EnableUserlandProxy)
1288
-	if err != nil {
1289
-		return err
1290
-	}
1291
-
1292
-	defer func() {
1293
-		if err != nil {
1294
-			if e := network.releasePorts(endpoint); e != nil {
1295
-				log.G(context.TODO()).Errorf("Failed to release ports allocated for the bridge endpoint %s on failure %v because of %v",
1296
-					eid, err, e)
1297
-			}
1298
-			endpoint.portMapping = nil
1299
-		}
1300
-	}()
1301
-
1302
-	// Clean the connection tracker state of the host for the specific endpoint. This is needed because some flows may
1303
-	// be bound to the local proxy, or to the host (for UDP packets), and won't be redirected to the new endpoints.
1304
-	clearConntrackEntries(d.nlh, endpoint)
1305
-
1306
-	if err = d.storeUpdate(endpoint); err != nil {
1307
-		return fmt.Errorf("failed to update bridge endpoint %.7s to store: %v", endpoint.id, err)
1308
-	}
1309
-
1310
-	if !network.config.EnableICC {
1311
-		return d.link(network, endpoint, true)
1312
-	}
1313
-
1314
-	return nil
1315
-}
1316
-
1317
-func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
1318
-	network, err := d.getNetwork(nid)
1319
-	if err != nil {
1320
-		return err
1321
-	}
1322
-
1323
-	endpoint, err := network.getEndpoint(eid)
1324
-	if err != nil {
1325
-		return err
1326
-	}
1327
-
1328
-	if endpoint == nil {
1329
-		return EndpointNotFoundError(eid)
1330
-	}
1331
-
1332
-	err = network.releasePorts(endpoint)
1333
-	if err != nil {
1334
-		log.G(context.TODO()).Warn(err)
1335
-	}
1336
-
1337
-	endpoint.portMapping = nil
1338
-
1339
-	// Clean the connection tracker state of the host for the specific endpoint. This is a precautionary measure to
1340
-	// avoid new endpoints getting the same IP address to receive unexpected packets due to bad conntrack state leading
1341
-	// to bad NATing.
1342
-	clearConntrackEntries(d.nlh, endpoint)
1343
-
1344
-	if err = d.storeUpdate(endpoint); err != nil {
1345
-		return fmt.Errorf("failed to update bridge endpoint %.7s to store: %v", endpoint.id, err)
1346
-	}
1347
-
1348
-	return nil
1349
-}
1350
-
1351
-func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, enable bool) (retErr error) {
1352
-	cc := endpoint.containerConfig
1353
-	ec := endpoint.extConnConfig
1354
-	if cc == nil || ec == nil || (len(cc.ParentEndpoints) == 0 && len(cc.ChildEndpoints) == 0) {
1355
-		// nothing to do
1356
-		return nil
1357
-	}
1358
-
1359
-	// Try to keep things atomic. addedLinks keeps track of links that were
1360
-	// successfully added. If any error occurred, then roll back all.
1361
-	var addedLinks []*link
1362
-	defer func() {
1363
-		if retErr == nil {
1364
-			return
1365
-		}
1366
-		for _, l := range addedLinks {
1367
-			l.Disable()
1368
-		}
1369
-	}()
1370
-
1371
-	if ec.ExposedPorts != nil {
1372
-		for _, p := range cc.ParentEndpoints {
1373
-			parentEndpoint, err := network.getEndpoint(p)
1374
-			if err != nil {
1375
-				return err
1376
-			}
1377
-			if parentEndpoint == nil {
1378
-				return InvalidEndpointIDError(p)
1379
-			}
1380
-
1381
-			l, err := newLink(parentEndpoint.addr.IP, endpoint.addr.IP, ec.ExposedPorts, network.config.BridgeName)
1382
-			if err != nil {
1383
-				return err
1384
-			}
1385
-			if enable {
1386
-				if err := l.Enable(); err != nil {
1387
-					return err
1388
-				}
1389
-				addedLinks = append(addedLinks, l)
1390
-			} else {
1391
-				l.Disable()
1392
-			}
1393
-		}
1394
-	}
1395
-
1396
-	for _, c := range cc.ChildEndpoints {
1397
-		childEndpoint, err := network.getEndpoint(c)
1398
-		if err != nil {
1399
-			return err
1400
-		}
1401
-		if childEndpoint == nil {
1402
-			return InvalidEndpointIDError(c)
1403
-		}
1404
-		if childEndpoint.extConnConfig == nil || childEndpoint.extConnConfig.ExposedPorts == nil {
1405
-			continue
1406
-		}
1407
-
1408
-		l, err := newLink(endpoint.addr.IP, childEndpoint.addr.IP, childEndpoint.extConnConfig.ExposedPorts, network.config.BridgeName)
1409
-		if err != nil {
1410
-			return err
1411
-		}
1412
-		if enable {
1413
-			if err := l.Enable(); err != nil {
1414
-				return err
1415
-			}
1416
-			addedLinks = append(addedLinks, l)
1417
-		} else {
1418
-			l.Disable()
1419
-		}
1420
-	}
1421
-
1422
-	return nil
1423
-}
1424
-
1425
-func (d *driver) Type() string {
1426
-	return NetworkType
1427
-}
1428
-
1429
-func (d *driver) IsBuiltIn() bool {
1430
-	return true
1431
-}
1432
-
1433
-func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) {
1434
-	if epOptions == nil {
1435
-		return nil, nil
1436
-	}
1437
-
1438
-	ec := &endpointConfiguration{}
1439
-
1440
-	if opt, ok := epOptions[netlabel.MacAddress]; ok {
1441
-		if mac, ok := opt.(net.HardwareAddr); ok {
1442
-			ec.MacAddress = mac
1443
-		} else {
1444
-			return nil, &ErrInvalidEndpointConfig{}
1445
-		}
1446
-	}
1447
-
1448
-	return ec, nil
1449
-}
1450
-
1451
-func parseContainerOptions(cOptions map[string]interface{}) (*containerConfiguration, error) {
1452
-	if cOptions == nil {
1453
-		return nil, nil
1454
-	}
1455
-	genericData := cOptions[netlabel.GenericData]
1456
-	if genericData == nil {
1457
-		return nil, nil
1458
-	}
1459
-	switch opt := genericData.(type) {
1460
-	case options.Generic:
1461
-		opaqueConfig, err := options.GenerateFromModel(opt, &containerConfiguration{})
1462
-		if err != nil {
1463
-			return nil, err
1464
-		}
1465
-		return opaqueConfig.(*containerConfiguration), nil
1466
-	case *containerConfiguration:
1467
-		return opt, nil
1468
-	default:
1469
-		return nil, nil
1470
-	}
1471
-}
1472
-
1473
-func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) {
1474
-	if cOptions == nil {
1475
-		return nil, nil
1476
-	}
1477
-
1478
-	cc := &connectivityConfiguration{}
1479
-
1480
-	if opt, ok := cOptions[netlabel.PortMap]; ok {
1481
-		if pb, ok := opt.([]types.PortBinding); ok {
1482
-			cc.PortBindings = pb
1483
-		} else {
1484
-			return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt)
1485
-		}
1486
-	}
1487
-
1488
-	if opt, ok := cOptions[netlabel.ExposedPorts]; ok {
1489
-		if ports, ok := opt.([]types.TransportPort); ok {
1490
-			cc.ExposedPorts = ports
1491
-		} else {
1492
-			return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt)
1493
-		}
1494
-	}
1495
-
1496
-	return cc, nil
1497
-}
1498
-
1499
-func electMacAddress(epConfig *endpointConfiguration, ip net.IP) net.HardwareAddr {
1500
-	if epConfig != nil && epConfig.MacAddress != nil {
1501
-		return epConfig.MacAddress
1502
-	}
1503
-	return netutils.GenerateMACFromIP(ip)
1504
-}
1505 1
new file mode 100644
... ...
@@ -0,0 +1,1502 @@
0
+package bridge
1
+
2
+import (
3
+	"context"
4
+	"errors"
5
+	"fmt"
6
+	"net"
7
+	"os"
8
+	"os/exec"
9
+	"strconv"
10
+	"sync"
11
+
12
+	"github.com/containerd/containerd/log"
13
+	"github.com/docker/docker/libnetwork/datastore"
14
+	"github.com/docker/docker/libnetwork/driverapi"
15
+	"github.com/docker/docker/libnetwork/iptables"
16
+	"github.com/docker/docker/libnetwork/netlabel"
17
+	"github.com/docker/docker/libnetwork/netutils"
18
+	"github.com/docker/docker/libnetwork/ns"
19
+	"github.com/docker/docker/libnetwork/options"
20
+	"github.com/docker/docker/libnetwork/portallocator"
21
+	"github.com/docker/docker/libnetwork/portmapper"
22
+	"github.com/docker/docker/libnetwork/scope"
23
+	"github.com/docker/docker/libnetwork/types"
24
+	"github.com/vishvananda/netlink"
25
+)
26
+
27
+const (
28
+	NetworkType                = "bridge"
29
+	vethPrefix                 = "veth"
30
+	vethLen                    = len(vethPrefix) + 7
31
+	defaultContainerVethPrefix = "eth"
32
+	maxAllocatePortAttempts    = 10
33
+)
34
+
35
+const (
36
+	// DefaultGatewayV4AuxKey represents the default-gateway configured by the user
37
+	DefaultGatewayV4AuxKey = "DefaultGatewayIPv4"
38
+	// DefaultGatewayV6AuxKey represents the ipv6 default-gateway configured by the user
39
+	DefaultGatewayV6AuxKey = "DefaultGatewayIPv6"
40
+)
41
+
42
+type defaultBridgeNetworkConflict struct {
43
+	ID string
44
+}
45
+
46
+func (d defaultBridgeNetworkConflict) Error() string {
47
+	return fmt.Sprintf("Stale default bridge network %s", d.ID)
48
+}
49
+
50
+type (
51
+	iptableCleanFunc   func() error
52
+	iptablesCleanFuncs []iptableCleanFunc
53
+)
54
+
55
+// configuration info for the "bridge" driver.
56
+type configuration struct {
57
+	EnableIPForwarding  bool
58
+	EnableIPTables      bool
59
+	EnableIP6Tables     bool
60
+	EnableUserlandProxy bool
61
+	UserlandProxyPath   string
62
+}
63
+
64
+// networkConfiguration for network specific configuration
65
+type networkConfiguration struct {
66
+	ID                   string
67
+	BridgeName           string
68
+	EnableIPv6           bool
69
+	EnableIPMasquerade   bool
70
+	EnableICC            bool
71
+	InhibitIPv4          bool
72
+	Mtu                  int
73
+	DefaultBindingIP     net.IP
74
+	DefaultBridge        bool
75
+	HostIP               net.IP
76
+	ContainerIfacePrefix string
77
+	// Internal fields set after ipam data parsing
78
+	AddressIPv4        *net.IPNet
79
+	AddressIPv6        *net.IPNet
80
+	DefaultGatewayIPv4 net.IP
81
+	DefaultGatewayIPv6 net.IP
82
+	dbIndex            uint64
83
+	dbExists           bool
84
+	Internal           bool
85
+
86
+	BridgeIfaceCreator ifaceCreator
87
+}
88
+
89
+// ifaceCreator represents how the bridge interface was created
90
+type ifaceCreator int8
91
+
92
+const (
93
+	ifaceCreatorUnknown ifaceCreator = iota
94
+	ifaceCreatedByLibnetwork
95
+	ifaceCreatedByUser
96
+)
97
+
98
+// endpointConfiguration represents the user specified configuration for the sandbox endpoint
99
+type endpointConfiguration struct {
100
+	MacAddress net.HardwareAddr
101
+}
102
+
103
+// containerConfiguration represents the user specified configuration for a container
104
+type containerConfiguration struct {
105
+	ParentEndpoints []string
106
+	ChildEndpoints  []string
107
+}
108
+
109
+// connectivityConfiguration represents the user specified configuration regarding the external connectivity
110
+type connectivityConfiguration struct {
111
+	PortBindings []types.PortBinding
112
+	ExposedPorts []types.TransportPort
113
+}
114
+
115
+type bridgeEndpoint struct {
116
+	id              string
117
+	nid             string
118
+	srcName         string
119
+	addr            *net.IPNet
120
+	addrv6          *net.IPNet
121
+	macAddress      net.HardwareAddr
122
+	config          *endpointConfiguration // User specified parameters
123
+	containerConfig *containerConfiguration
124
+	extConnConfig   *connectivityConfiguration
125
+	portMapping     []types.PortBinding // Operation port bindings
126
+	dbIndex         uint64
127
+	dbExists        bool
128
+}
129
+
130
+type bridgeNetwork struct {
131
+	id            string
132
+	bridge        *bridgeInterface // The bridge's L3 interface
133
+	config        *networkConfiguration
134
+	endpoints     map[string]*bridgeEndpoint // key: endpoint id
135
+	portMapper    *portmapper.PortMapper
136
+	portMapperV6  *portmapper.PortMapper
137
+	driver        *driver // The network's driver
138
+	iptCleanFuncs iptablesCleanFuncs
139
+	sync.Mutex
140
+}
141
+
142
+type driver struct {
143
+	config            configuration
144
+	natChain          *iptables.ChainInfo
145
+	filterChain       *iptables.ChainInfo
146
+	isolationChain1   *iptables.ChainInfo
147
+	isolationChain2   *iptables.ChainInfo
148
+	natChainV6        *iptables.ChainInfo
149
+	filterChainV6     *iptables.ChainInfo
150
+	isolationChain1V6 *iptables.ChainInfo
151
+	isolationChain2V6 *iptables.ChainInfo
152
+	networks          map[string]*bridgeNetwork
153
+	store             *datastore.Store
154
+	nlh               *netlink.Handle
155
+	configNetwork     sync.Mutex
156
+	portAllocator     *portallocator.PortAllocator // Overridable for tests.
157
+	sync.Mutex
158
+}
159
+
160
+// New constructs a new bridge driver
161
+func newDriver() *driver {
162
+	return &driver{
163
+		networks:      map[string]*bridgeNetwork{},
164
+		portAllocator: portallocator.Get(),
165
+	}
166
+}
167
+
168
+// Register registers a new instance of bridge driver.
169
+func Register(r driverapi.Registerer, config map[string]interface{}) error {
170
+	d := newDriver()
171
+	if err := d.configure(config); err != nil {
172
+		return err
173
+	}
174
+	return r.RegisterDriver(NetworkType, d, driverapi.Capability{
175
+		DataScope:         scope.Local,
176
+		ConnectivityScope: scope.Local,
177
+	})
178
+}
179
+
180
+// Validate performs a static validation on the network configuration parameters.
181
+// Whatever can be assessed a priori before attempting any programming.
182
+func (c *networkConfiguration) Validate() error {
183
+	if c.Mtu < 0 {
184
+		return ErrInvalidMtu(c.Mtu)
185
+	}
186
+
187
+	// If bridge v4 subnet is specified
188
+	if c.AddressIPv4 != nil {
189
+		// If default gw is specified, it must be part of bridge subnet
190
+		if c.DefaultGatewayIPv4 != nil {
191
+			if !c.AddressIPv4.Contains(c.DefaultGatewayIPv4) {
192
+				return &ErrInvalidGateway{}
193
+			}
194
+		}
195
+	}
196
+
197
+	// If default v6 gw is specified, AddressIPv6 must be specified and gw must belong to AddressIPv6 subnet
198
+	if c.EnableIPv6 && c.DefaultGatewayIPv6 != nil {
199
+		if c.AddressIPv6 == nil || !c.AddressIPv6.Contains(c.DefaultGatewayIPv6) {
200
+			return &ErrInvalidGateway{}
201
+		}
202
+	}
203
+	return nil
204
+}
205
+
206
+// Conflicts check if two NetworkConfiguration objects overlap
207
+func (c *networkConfiguration) Conflicts(o *networkConfiguration) error {
208
+	if o == nil {
209
+		return errors.New("same configuration")
210
+	}
211
+
212
+	// Also empty, because only one network with empty name is allowed
213
+	if c.BridgeName == o.BridgeName {
214
+		return errors.New("networks have same bridge name")
215
+	}
216
+
217
+	// They must be in different subnets
218
+	if (c.AddressIPv4 != nil && o.AddressIPv4 != nil) &&
219
+		(c.AddressIPv4.Contains(o.AddressIPv4.IP) || o.AddressIPv4.Contains(c.AddressIPv4.IP)) {
220
+		return errors.New("networks have overlapping IPv4")
221
+	}
222
+
223
+	// They must be in different v6 subnets
224
+	if (c.AddressIPv6 != nil && o.AddressIPv6 != nil) &&
225
+		(c.AddressIPv6.Contains(o.AddressIPv6.IP) || o.AddressIPv6.Contains(c.AddressIPv6.IP)) {
226
+		return errors.New("networks have overlapping IPv6")
227
+	}
228
+
229
+	return nil
230
+}
231
+
232
+func (c *networkConfiguration) fromLabels(labels map[string]string) error {
233
+	var err error
234
+	for label, value := range labels {
235
+		switch label {
236
+		case BridgeName:
237
+			c.BridgeName = value
238
+		case netlabel.DriverMTU:
239
+			if c.Mtu, err = strconv.Atoi(value); err != nil {
240
+				return parseErr(label, value, err.Error())
241
+			}
242
+		case netlabel.EnableIPv6:
243
+			if c.EnableIPv6, err = strconv.ParseBool(value); err != nil {
244
+				return parseErr(label, value, err.Error())
245
+			}
246
+		case EnableIPMasquerade:
247
+			if c.EnableIPMasquerade, err = strconv.ParseBool(value); err != nil {
248
+				return parseErr(label, value, err.Error())
249
+			}
250
+		case EnableICC:
251
+			if c.EnableICC, err = strconv.ParseBool(value); err != nil {
252
+				return parseErr(label, value, err.Error())
253
+			}
254
+		case InhibitIPv4:
255
+			if c.InhibitIPv4, err = strconv.ParseBool(value); err != nil {
256
+				return parseErr(label, value, err.Error())
257
+			}
258
+		case DefaultBridge:
259
+			if c.DefaultBridge, err = strconv.ParseBool(value); err != nil {
260
+				return parseErr(label, value, err.Error())
261
+			}
262
+		case DefaultBindingIP:
263
+			if c.DefaultBindingIP = net.ParseIP(value); c.DefaultBindingIP == nil {
264
+				return parseErr(label, value, "nil ip")
265
+			}
266
+		case netlabel.ContainerIfacePrefix:
267
+			c.ContainerIfacePrefix = value
268
+		case netlabel.HostIP:
269
+			if c.HostIP = net.ParseIP(value); c.HostIP == nil {
270
+				return parseErr(label, value, "nil ip")
271
+			}
272
+		}
273
+	}
274
+
275
+	return nil
276
+}
277
+
278
+func parseErr(label, value, errString string) error {
279
+	return types.BadRequestErrorf("failed to parse %s value: %v (%s)", label, value, errString)
280
+}
281
+
282
+func (n *bridgeNetwork) registerIptCleanFunc(clean iptableCleanFunc) {
283
+	n.iptCleanFuncs = append(n.iptCleanFuncs, clean)
284
+}
285
+
286
+func (n *bridgeNetwork) getDriverChains(version iptables.IPVersion) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
287
+	n.Lock()
288
+	defer n.Unlock()
289
+
290
+	if n.driver == nil {
291
+		return nil, nil, nil, nil, types.BadRequestErrorf("no driver found")
292
+	}
293
+
294
+	if version == iptables.IPv6 {
295
+		return n.driver.natChainV6, n.driver.filterChainV6, n.driver.isolationChain1V6, n.driver.isolationChain2V6, nil
296
+	}
297
+
298
+	return n.driver.natChain, n.driver.filterChain, n.driver.isolationChain1, n.driver.isolationChain2, nil
299
+}
300
+
301
+func (n *bridgeNetwork) getNetworkBridgeName() string {
302
+	n.Lock()
303
+	config := n.config
304
+	n.Unlock()
305
+
306
+	return config.BridgeName
307
+}
308
+
309
+func (n *bridgeNetwork) getEndpoint(eid string) (*bridgeEndpoint, error) {
310
+	if eid == "" {
311
+		return nil, InvalidEndpointIDError(eid)
312
+	}
313
+
314
+	n.Lock()
315
+	defer n.Unlock()
316
+	if ep, ok := n.endpoints[eid]; ok {
317
+		return ep, nil
318
+	}
319
+
320
+	return nil, nil
321
+}
322
+
323
+// Install/Removes the iptables rules needed to isolate this network
324
+// from each of the other networks
325
+func (n *bridgeNetwork) isolateNetwork(enable bool) error {
326
+	n.Lock()
327
+	thisConfig := n.config
328
+	n.Unlock()
329
+
330
+	if thisConfig.Internal {
331
+		return nil
332
+	}
333
+
334
+	// Install the rules to isolate this network against each of the other networks
335
+	if n.driver.config.EnableIP6Tables {
336
+		err := setINC(iptables.IPv6, thisConfig.BridgeName, enable)
337
+		if err != nil {
338
+			return err
339
+		}
340
+	}
341
+
342
+	if n.driver.config.EnableIPTables {
343
+		return setINC(iptables.IPv4, thisConfig.BridgeName, enable)
344
+	}
345
+	return nil
346
+}
347
+
348
+func (d *driver) configure(option map[string]interface{}) error {
349
+	var (
350
+		config            configuration
351
+		err               error
352
+		natChain          *iptables.ChainInfo
353
+		filterChain       *iptables.ChainInfo
354
+		isolationChain1   *iptables.ChainInfo
355
+		isolationChain2   *iptables.ChainInfo
356
+		natChainV6        *iptables.ChainInfo
357
+		filterChainV6     *iptables.ChainInfo
358
+		isolationChain1V6 *iptables.ChainInfo
359
+		isolationChain2V6 *iptables.ChainInfo
360
+	)
361
+
362
+	switch opt := option[netlabel.GenericData].(type) {
363
+	case options.Generic:
364
+		opaqueConfig, err := options.GenerateFromModel(opt, &configuration{})
365
+		if err != nil {
366
+			return err
367
+		}
368
+		config = *opaqueConfig.(*configuration)
369
+	case *configuration:
370
+		config = *opt
371
+	case nil:
372
+		// No GenericData option set. Use defaults.
373
+	default:
374
+		return &ErrInvalidDriverConfig{}
375
+	}
376
+
377
+	if config.EnableIPTables || config.EnableIP6Tables {
378
+		if _, err := os.Stat("/proc/sys/net/bridge"); err != nil {
379
+			if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil {
380
+				log.G(context.TODO()).Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err)
381
+			}
382
+		}
383
+	}
384
+
385
+	if config.EnableIPTables {
386
+		removeIPChains(iptables.IPv4)
387
+
388
+		natChain, filterChain, isolationChain1, isolationChain2, err = setupIPChains(config, iptables.IPv4)
389
+		if err != nil {
390
+			return err
391
+		}
392
+
393
+		// Make sure on firewall reload, first thing being re-played is chains creation
394
+		iptables.OnReloaded(func() {
395
+			log.G(context.TODO()).Debugf("Recreating iptables chains on firewall reload")
396
+			if _, _, _, _, err := setupIPChains(config, iptables.IPv4); err != nil {
397
+				log.G(context.TODO()).WithError(err).Error("Error reloading iptables chains")
398
+			}
399
+		})
400
+	}
401
+
402
+	if config.EnableIP6Tables {
403
+		removeIPChains(iptables.IPv6)
404
+
405
+		natChainV6, filterChainV6, isolationChain1V6, isolationChain2V6, err = setupIPChains(config, iptables.IPv6)
406
+		if err != nil {
407
+			return err
408
+		}
409
+
410
+		// Make sure on firewall reload, first thing being re-played is chains creation
411
+		iptables.OnReloaded(func() {
412
+			log.G(context.TODO()).Debugf("Recreating ip6tables chains on firewall reload")
413
+			if _, _, _, _, err := setupIPChains(config, iptables.IPv6); err != nil {
414
+				log.G(context.TODO()).WithError(err).Error("Error reloading ip6tables chains")
415
+			}
416
+		})
417
+	}
418
+
419
+	if config.EnableIPForwarding {
420
+		err = setupIPForwarding(config.EnableIPTables, config.EnableIP6Tables)
421
+		if err != nil {
422
+			log.G(context.TODO()).Warn(err)
423
+			return err
424
+		}
425
+	}
426
+
427
+	d.Lock()
428
+	d.natChain = natChain
429
+	d.filterChain = filterChain
430
+	d.isolationChain1 = isolationChain1
431
+	d.isolationChain2 = isolationChain2
432
+	d.natChainV6 = natChainV6
433
+	d.filterChainV6 = filterChainV6
434
+	d.isolationChain1V6 = isolationChain1V6
435
+	d.isolationChain2V6 = isolationChain2V6
436
+	d.config = config
437
+	d.Unlock()
438
+
439
+	return d.initStore(option)
440
+}
441
+
442
+func (d *driver) getNetwork(id string) (*bridgeNetwork, error) {
443
+	d.Lock()
444
+	defer d.Unlock()
445
+
446
+	if id == "" {
447
+		return nil, types.BadRequestErrorf("invalid network id: %s", id)
448
+	}
449
+
450
+	if nw, ok := d.networks[id]; ok {
451
+		return nw, nil
452
+	}
453
+
454
+	return nil, types.NotFoundErrorf("network not found: %s", id)
455
+}
456
+
457
+func parseNetworkGenericOptions(data interface{}) (*networkConfiguration, error) {
458
+	var (
459
+		err    error
460
+		config *networkConfiguration
461
+	)
462
+
463
+	switch opt := data.(type) {
464
+	case *networkConfiguration:
465
+		config = opt
466
+	case map[string]string:
467
+		config = &networkConfiguration{
468
+			EnableICC:          true,
469
+			EnableIPMasquerade: true,
470
+		}
471
+		err = config.fromLabels(opt)
472
+	case options.Generic:
473
+		var opaqueConfig interface{}
474
+		if opaqueConfig, err = options.GenerateFromModel(opt, config); err == nil {
475
+			config = opaqueConfig.(*networkConfiguration)
476
+		}
477
+	default:
478
+		err = types.BadRequestErrorf("do not recognize network configuration format: %T", opt)
479
+	}
480
+
481
+	return config, err
482
+}
483
+
484
+func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
485
+	if len(ipamV4Data) > 1 || len(ipamV6Data) > 1 {
486
+		return types.ForbiddenErrorf("bridge driver doesn't support multiple subnets")
487
+	}
488
+
489
+	if len(ipamV4Data) == 0 {
490
+		return types.BadRequestErrorf("bridge network %s requires ipv4 configuration", id)
491
+	}
492
+
493
+	if ipamV4Data[0].Gateway != nil {
494
+		c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway)
495
+	}
496
+
497
+	if gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey]; ok {
498
+		c.DefaultGatewayIPv4 = gw.IP
499
+	}
500
+
501
+	if len(ipamV6Data) > 0 {
502
+		c.AddressIPv6 = ipamV6Data[0].Pool
503
+
504
+		if ipamV6Data[0].Gateway != nil {
505
+			c.AddressIPv6 = types.GetIPNetCopy(ipamV6Data[0].Gateway)
506
+		}
507
+
508
+		if gw, ok := ipamV6Data[0].AuxAddresses[DefaultGatewayV6AuxKey]; ok {
509
+			c.DefaultGatewayIPv6 = gw.IP
510
+		}
511
+	}
512
+
513
+	return nil
514
+}
515
+
516
+func parseNetworkOptions(id string, option options.Generic) (*networkConfiguration, error) {
517
+	var (
518
+		err    error
519
+		config = &networkConfiguration{}
520
+	)
521
+
522
+	// Parse generic label first, config will be re-assigned
523
+	if genData, ok := option[netlabel.GenericData]; ok && genData != nil {
524
+		if config, err = parseNetworkGenericOptions(genData); err != nil {
525
+			return nil, err
526
+		}
527
+	}
528
+
529
+	// Process well-known labels next
530
+	if val, ok := option[netlabel.EnableIPv6]; ok {
531
+		config.EnableIPv6 = val.(bool)
532
+	}
533
+
534
+	if val, ok := option[netlabel.Internal]; ok {
535
+		if internal, ok := val.(bool); ok && internal {
536
+			config.Internal = true
537
+		}
538
+	}
539
+
540
+	// Finally validate the configuration
541
+	if err = config.Validate(); err != nil {
542
+		return nil, err
543
+	}
544
+
545
+	if config.BridgeName == "" && !config.DefaultBridge {
546
+		config.BridgeName = "br-" + id[:12]
547
+	}
548
+
549
+	exists, err := bridgeInterfaceExists(config.BridgeName)
550
+	if err != nil {
551
+		return nil, err
552
+	}
553
+
554
+	if !exists {
555
+		config.BridgeIfaceCreator = ifaceCreatedByLibnetwork
556
+	} else {
557
+		config.BridgeIfaceCreator = ifaceCreatedByUser
558
+	}
559
+
560
+	config.ID = id
561
+	return config, nil
562
+}
563
+
564
+// Return a slice of networks over which caller can iterate safely
565
+func (d *driver) getNetworks() []*bridgeNetwork {
566
+	d.Lock()
567
+	defer d.Unlock()
568
+
569
+	ls := make([]*bridgeNetwork, 0, len(d.networks))
570
+	for _, nw := range d.networks {
571
+		ls = append(ls, nw)
572
+	}
573
+	return ls
574
+}
575
+
576
+func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
577
+	return nil, types.NotImplementedErrorf("not implemented")
578
+}
579
+
580
+func (d *driver) NetworkFree(id string) error {
581
+	return types.NotImplementedErrorf("not implemented")
582
+}
583
+
584
+func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
585
+}
586
+
587
+func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
588
+	return "", nil
589
+}
590
+
591
+// Create a new network using bridge plugin
592
+func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
593
+	if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
594
+		return types.BadRequestErrorf("ipv4 pool is empty")
595
+	}
596
+	// Sanity checks
597
+	d.Lock()
598
+	if _, ok := d.networks[id]; ok {
599
+		d.Unlock()
600
+		return types.ForbiddenErrorf("network %s exists", id)
601
+	}
602
+	d.Unlock()
603
+
604
+	// Parse and validate the config. It should not be conflict with existing networks' config
605
+	config, err := parseNetworkOptions(id, option)
606
+	if err != nil {
607
+		return err
608
+	}
609
+
610
+	if err = config.processIPAM(id, ipV4Data, ipV6Data); err != nil {
611
+		return err
612
+	}
613
+
614
+	// start the critical section, from this point onward we are dealing with the list of networks
615
+	// so to be consistent we cannot allow that the list changes
616
+	d.configNetwork.Lock()
617
+	defer d.configNetwork.Unlock()
618
+
619
+	// check network conflicts
620
+	if err = d.checkConflict(config); err != nil {
621
+		nerr, ok := err.(defaultBridgeNetworkConflict)
622
+		if !ok {
623
+			return err
624
+		}
625
+		// Got a conflict with a stale default network, clean that up and continue
626
+		log.G(context.TODO()).Warn(nerr)
627
+		if err := d.deleteNetwork(nerr.ID); err != nil {
628
+			log.G(context.TODO()).WithError(err).Debug("Error while cleaning up network on conflict")
629
+		}
630
+	}
631
+
632
+	// there is no conflict, now create the network
633
+	if err = d.createNetwork(config); err != nil {
634
+		return err
635
+	}
636
+
637
+	return d.storeUpdate(config)
638
+}
639
+
640
+func (d *driver) checkConflict(config *networkConfiguration) error {
641
+	networkList := d.getNetworks()
642
+	for _, nw := range networkList {
643
+		nw.Lock()
644
+		nwConfig := nw.config
645
+		nw.Unlock()
646
+		if err := nwConfig.Conflicts(config); err != nil {
647
+			if nwConfig.DefaultBridge {
648
+				// We encountered and identified a stale default network
649
+				// We must delete it as libnetwork is the source of truth
650
+				// The default network being created must be the only one
651
+				// This can happen only from docker 1.12 on ward
652
+				log.G(context.TODO()).Infof("Found stale default bridge network %s (%s)", nwConfig.ID, nwConfig.BridgeName)
653
+				return defaultBridgeNetworkConflict{nwConfig.ID}
654
+			}
655
+
656
+			return types.ForbiddenErrorf("cannot create network %s (%s): conflicts with network %s (%s): %s",
657
+				config.ID, config.BridgeName, nwConfig.ID, nwConfig.BridgeName, err.Error())
658
+		}
659
+	}
660
+	return nil
661
+}
662
+
663
+func (d *driver) createNetwork(config *networkConfiguration) (err error) {
664
+	// Initialize handle when needed
665
+	d.Lock()
666
+	if d.nlh == nil {
667
+		d.nlh = ns.NlHandle()
668
+	}
669
+	d.Unlock()
670
+
671
+	// Create or retrieve the bridge L3 interface
672
+	bridgeIface, err := newInterface(d.nlh, config)
673
+	if err != nil {
674
+		return err
675
+	}
676
+
677
+	// Create and set network handler in driver
678
+	network := &bridgeNetwork{
679
+		id:           config.ID,
680
+		endpoints:    make(map[string]*bridgeEndpoint),
681
+		config:       config,
682
+		portMapper:   portmapper.NewWithPortAllocator(d.portAllocator, d.config.UserlandProxyPath),
683
+		portMapperV6: portmapper.NewWithPortAllocator(d.portAllocator, d.config.UserlandProxyPath),
684
+		bridge:       bridgeIface,
685
+		driver:       d,
686
+	}
687
+
688
+	d.Lock()
689
+	d.networks[config.ID] = network
690
+	d.Unlock()
691
+
692
+	// On failure make sure to reset driver network handler to nil
693
+	defer func() {
694
+		if err != nil {
695
+			d.Lock()
696
+			delete(d.networks, config.ID)
697
+			d.Unlock()
698
+		}
699
+	}()
700
+
701
+	// Add inter-network communication rules.
702
+	setupNetworkIsolationRules := func(config *networkConfiguration, i *bridgeInterface) error {
703
+		if err := network.isolateNetwork(true); err != nil {
704
+			if err = network.isolateNetwork(false); err != nil {
705
+				log.G(context.TODO()).Warnf("Failed on removing the inter-network iptables rules on cleanup: %v", err)
706
+			}
707
+			return err
708
+		}
709
+		// register the cleanup function
710
+		network.registerIptCleanFunc(func() error {
711
+			return network.isolateNetwork(false)
712
+		})
713
+		return nil
714
+	}
715
+
716
+	// Prepare the bridge setup configuration
717
+	bridgeSetup := newBridgeSetup(config, bridgeIface)
718
+
719
+	// If the bridge interface doesn't exist, we need to start the setup steps
720
+	// by creating a new device and assigning it an IPv4 address.
721
+	bridgeAlreadyExists := bridgeIface.exists()
722
+	if !bridgeAlreadyExists {
723
+		bridgeSetup.queueStep(setupDevice)
724
+		bridgeSetup.queueStep(setupDefaultSysctl)
725
+	}
726
+
727
+	// For the default bridge, set expected sysctls
728
+	if config.DefaultBridge {
729
+		bridgeSetup.queueStep(setupDefaultSysctl)
730
+	}
731
+
732
+	// Even if a bridge exists try to setup IPv4.
733
+	bridgeSetup.queueStep(setupBridgeIPv4)
734
+
735
+	enableIPv6Forwarding := d.config.EnableIPForwarding && config.AddressIPv6 != nil
736
+
737
+	// Conditionally queue setup steps depending on configuration values.
738
+	for _, step := range []struct {
739
+		Condition bool
740
+		Fn        setupStep
741
+	}{
742
+		// Enable IPv6 on the bridge if required. We do this even for a
743
+		// previously  existing bridge, as it may be here from a previous
744
+		// installation where IPv6 wasn't supported yet and needs to be
745
+		// assigned an IPv6 link-local address.
746
+		{config.EnableIPv6, setupBridgeIPv6},
747
+
748
+		// We ensure that the bridge has the expectedIPv4 and IPv6 addresses in
749
+		// the case of a previously existing device.
750
+		{bridgeAlreadyExists && !config.InhibitIPv4, setupVerifyAndReconcile},
751
+
752
+		// Enable IPv6 Forwarding
753
+		{enableIPv6Forwarding, setupIPv6Forwarding},
754
+
755
+		// Setup Loopback Addresses Routing
756
+		{!d.config.EnableUserlandProxy, setupLoopbackAddressesRouting},
757
+
758
+		// Setup IPTables.
759
+		{d.config.EnableIPTables, network.setupIP4Tables},
760
+
761
+		// Setup IP6Tables.
762
+		{config.EnableIPv6 && d.config.EnableIP6Tables, network.setupIP6Tables},
763
+
764
+		// We want to track firewalld configuration so that
765
+		// if it is started/reloaded, the rules can be applied correctly
766
+		{d.config.EnableIPTables, network.setupFirewalld},
767
+		// same for IPv6
768
+		{config.EnableIPv6 && d.config.EnableIP6Tables, network.setupFirewalld6},
769
+
770
+		// Setup DefaultGatewayIPv4
771
+		{config.DefaultGatewayIPv4 != nil, setupGatewayIPv4},
772
+
773
+		// Setup DefaultGatewayIPv6
774
+		{config.DefaultGatewayIPv6 != nil, setupGatewayIPv6},
775
+
776
+		// Add inter-network communication rules.
777
+		{d.config.EnableIPTables, setupNetworkIsolationRules},
778
+
779
+		// Configure bridge networking filtering if ICC is off and IP tables are enabled
780
+		{!config.EnableICC && d.config.EnableIPTables, setupBridgeNetFiltering},
781
+	} {
782
+		if step.Condition {
783
+			bridgeSetup.queueStep(step.Fn)
784
+		}
785
+	}
786
+
787
+	// Apply the prepared list of steps, and abort at the first error.
788
+	bridgeSetup.queueStep(setupDeviceUp)
789
+	return bridgeSetup.apply()
790
+}
791
+
792
+func (d *driver) DeleteNetwork(nid string) error {
793
+	d.configNetwork.Lock()
794
+	defer d.configNetwork.Unlock()
795
+
796
+	return d.deleteNetwork(nid)
797
+}
798
+
799
+func (d *driver) deleteNetwork(nid string) error {
800
+	var err error
801
+
802
+	// Get network handler and remove it from driver
803
+	d.Lock()
804
+	n, ok := d.networks[nid]
805
+	d.Unlock()
806
+
807
+	if !ok {
808
+		return types.InternalMaskableErrorf("network %s does not exist", nid)
809
+	}
810
+
811
+	n.Lock()
812
+	config := n.config
813
+	n.Unlock()
814
+
815
+	// delele endpoints belong to this network
816
+	for _, ep := range n.endpoints {
817
+		if err := n.releasePorts(ep); err != nil {
818
+			log.G(context.TODO()).Warn(err)
819
+		}
820
+		if link, err := d.nlh.LinkByName(ep.srcName); err == nil {
821
+			if err := d.nlh.LinkDel(link); err != nil {
822
+				log.G(context.TODO()).WithError(err).Errorf("Failed to delete interface (%s)'s link on endpoint (%s) delete", ep.srcName, ep.id)
823
+			}
824
+		}
825
+
826
+		if err := d.storeDelete(ep); err != nil {
827
+			log.G(context.TODO()).Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err)
828
+		}
829
+	}
830
+
831
+	d.Lock()
832
+	delete(d.networks, nid)
833
+	d.Unlock()
834
+
835
+	// On failure set network handler back in driver, but
836
+	// only if is not already taken over by some other thread
837
+	defer func() {
838
+		if err != nil {
839
+			d.Lock()
840
+			if _, ok := d.networks[nid]; !ok {
841
+				d.networks[nid] = n
842
+			}
843
+			d.Unlock()
844
+		}
845
+	}()
846
+
847
+	switch config.BridgeIfaceCreator {
848
+	case ifaceCreatedByLibnetwork, ifaceCreatorUnknown:
849
+		// We only delete the bridge if it was created by the bridge driver and
850
+		// it is not the default one (to keep the backward compatible behavior.)
851
+		if !config.DefaultBridge {
852
+			if err := d.nlh.LinkDel(n.bridge.Link); err != nil {
853
+				log.G(context.TODO()).Warnf("Failed to remove bridge interface %s on network %s delete: %v", config.BridgeName, nid, err)
854
+			}
855
+		}
856
+	case ifaceCreatedByUser:
857
+		// Don't delete the bridge interface if it was not created by libnetwork.
858
+	}
859
+
860
+	// clean all relevant iptables rules
861
+	for _, cleanFunc := range n.iptCleanFuncs {
862
+		if errClean := cleanFunc(); errClean != nil {
863
+			log.G(context.TODO()).Warnf("Failed to clean iptables rules for bridge network: %v", errClean)
864
+		}
865
+	}
866
+	return d.storeDelete(config)
867
+}
868
+
869
+func addToBridge(nlh *netlink.Handle, ifaceName, bridgeName string) error {
870
+	lnk, err := nlh.LinkByName(ifaceName)
871
+	if err != nil {
872
+		return fmt.Errorf("could not find interface %s: %v", ifaceName, err)
873
+	}
874
+	if err := nlh.LinkSetMaster(lnk, &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: bridgeName}}); err != nil {
875
+		log.G(context.TODO()).WithError(err).Errorf("Failed to add %s to bridge via netlink", ifaceName)
876
+		return err
877
+	}
878
+	return nil
879
+}
880
+
881
+func setHairpinMode(nlh *netlink.Handle, link netlink.Link, enable bool) error {
882
+	err := nlh.LinkSetHairpin(link, enable)
883
+	if err != nil {
884
+		return fmt.Errorf("unable to set hairpin mode on %s via netlink: %v",
885
+			link.Attrs().Name, err)
886
+	}
887
+	return nil
888
+}
889
+
890
+func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
891
+	if ifInfo == nil {
892
+		return errors.New("invalid interface info passed")
893
+	}
894
+
895
+	// Get the network handler and make sure it exists
896
+	d.Lock()
897
+	n, ok := d.networks[nid]
898
+	dconfig := d.config
899
+	d.Unlock()
900
+
901
+	if !ok {
902
+		return types.NotFoundErrorf("network %s does not exist", nid)
903
+	}
904
+	if n == nil {
905
+		return driverapi.ErrNoNetwork(nid)
906
+	}
907
+
908
+	// Sanity check
909
+	n.Lock()
910
+	if n.id != nid {
911
+		n.Unlock()
912
+		return InvalidNetworkIDError(nid)
913
+	}
914
+	n.Unlock()
915
+
916
+	// Check if endpoint id is good and retrieve correspondent endpoint
917
+	ep, err := n.getEndpoint(eid)
918
+	if err != nil {
919
+		return err
920
+	}
921
+
922
+	// Endpoint with that id exists either on desired or other sandbox
923
+	if ep != nil {
924
+		return driverapi.ErrEndpointExists(eid)
925
+	}
926
+
927
+	// Try to convert the options to endpoint configuration
928
+	epConfig, err := parseEndpointOptions(epOptions)
929
+	if err != nil {
930
+		return err
931
+	}
932
+
933
+	// Create and add the endpoint
934
+	n.Lock()
935
+	endpoint := &bridgeEndpoint{id: eid, nid: nid, config: epConfig}
936
+	n.endpoints[eid] = endpoint
937
+	n.Unlock()
938
+
939
+	// On failure make sure to remove the endpoint
940
+	defer func() {
941
+		if err != nil {
942
+			n.Lock()
943
+			delete(n.endpoints, eid)
944
+			n.Unlock()
945
+		}
946
+	}()
947
+
948
+	// Generate a name for what will be the host side pipe interface
949
+	hostIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
950
+	if err != nil {
951
+		return err
952
+	}
953
+
954
+	// Generate a name for what will be the sandbox side pipe interface
955
+	containerIfName, err := netutils.GenerateIfaceName(d.nlh, vethPrefix, vethLen)
956
+	if err != nil {
957
+		return err
958
+	}
959
+
960
+	// Generate and add the interface pipe host <-> sandbox
961
+	veth := &netlink.Veth{
962
+		LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
963
+		PeerName:  containerIfName,
964
+	}
965
+	if err = d.nlh.LinkAdd(veth); err != nil {
966
+		return types.InternalErrorf("failed to add the host (%s) <=> sandbox (%s) pair interfaces: %v", hostIfName, containerIfName, err)
967
+	}
968
+
969
+	// Get the host side pipe interface handler
970
+	host, err := d.nlh.LinkByName(hostIfName)
971
+	if err != nil {
972
+		return types.InternalErrorf("failed to find host side interface %s: %v", hostIfName, err)
973
+	}
974
+	defer func() {
975
+		if err != nil {
976
+			if err := d.nlh.LinkDel(host); err != nil {
977
+				log.G(context.TODO()).WithError(err).Warnf("Failed to delete host side interface (%s)'s link", hostIfName)
978
+			}
979
+		}
980
+	}()
981
+
982
+	// Get the sandbox side pipe interface handler
983
+	sbox, err := d.nlh.LinkByName(containerIfName)
984
+	if err != nil {
985
+		return types.InternalErrorf("failed to find sandbox side interface %s: %v", containerIfName, err)
986
+	}
987
+	defer func() {
988
+		if err != nil {
989
+			if err := d.nlh.LinkDel(sbox); err != nil {
990
+				log.G(context.TODO()).WithError(err).Warnf("Failed to delete sandbox side interface (%s)'s link", containerIfName)
991
+			}
992
+		}
993
+	}()
994
+
995
+	n.Lock()
996
+	config := n.config
997
+	n.Unlock()
998
+
999
+	// Add bridge inherited attributes to pipe interfaces
1000
+	if config.Mtu != 0 {
1001
+		err = d.nlh.LinkSetMTU(host, config.Mtu)
1002
+		if err != nil {
1003
+			return types.InternalErrorf("failed to set MTU on host interface %s: %v", hostIfName, err)
1004
+		}
1005
+		err = d.nlh.LinkSetMTU(sbox, config.Mtu)
1006
+		if err != nil {
1007
+			return types.InternalErrorf("failed to set MTU on sandbox interface %s: %v", containerIfName, err)
1008
+		}
1009
+	}
1010
+
1011
+	// Attach host side pipe interface into the bridge
1012
+	if err = addToBridge(d.nlh, hostIfName, config.BridgeName); err != nil {
1013
+		return fmt.Errorf("adding interface %s to bridge %s failed: %v", hostIfName, config.BridgeName, err)
1014
+	}
1015
+
1016
+	if !dconfig.EnableUserlandProxy {
1017
+		err = setHairpinMode(d.nlh, host, true)
1018
+		if err != nil {
1019
+			return err
1020
+		}
1021
+	}
1022
+
1023
+	// Store the sandbox side pipe interface parameters
1024
+	endpoint.srcName = containerIfName
1025
+	endpoint.macAddress = ifInfo.MacAddress()
1026
+	endpoint.addr = ifInfo.Address()
1027
+	endpoint.addrv6 = ifInfo.AddressIPv6()
1028
+
1029
+	// Set the sbox's MAC if not provided. If specified, use the one configured by user, otherwise generate one based on IP.
1030
+	if endpoint.macAddress == nil {
1031
+		endpoint.macAddress = electMacAddress(epConfig, endpoint.addr.IP)
1032
+		if err = ifInfo.SetMacAddress(endpoint.macAddress); err != nil {
1033
+			return err
1034
+		}
1035
+	}
1036
+
1037
+	// Up the host interface after finishing all netlink configuration
1038
+	if err = d.nlh.LinkSetUp(host); err != nil {
1039
+		return fmt.Errorf("could not set link up for host interface %s: %v", hostIfName, err)
1040
+	}
1041
+
1042
+	if endpoint.addrv6 == nil && config.EnableIPv6 {
1043
+		var ip6 net.IP
1044
+		network := n.bridge.bridgeIPv6
1045
+		if config.AddressIPv6 != nil {
1046
+			network = config.AddressIPv6
1047
+		}
1048
+
1049
+		ones, _ := network.Mask.Size()
1050
+		if ones > 80 {
1051
+			err = types.ForbiddenErrorf("Cannot self generate an IPv6 address on network %v: At least 48 host bits are needed.", network)
1052
+			return err
1053
+		}
1054
+
1055
+		ip6 = make(net.IP, len(network.IP))
1056
+		copy(ip6, network.IP)
1057
+		for i, h := range endpoint.macAddress {
1058
+			ip6[i+10] = h
1059
+		}
1060
+
1061
+		endpoint.addrv6 = &net.IPNet{IP: ip6, Mask: network.Mask}
1062
+		if err = ifInfo.SetIPAddress(endpoint.addrv6); err != nil {
1063
+			return err
1064
+		}
1065
+	}
1066
+
1067
+	if err = d.storeUpdate(endpoint); err != nil {
1068
+		return fmt.Errorf("failed to save bridge endpoint %.7s to store: %v", endpoint.id, err)
1069
+	}
1070
+
1071
+	return nil
1072
+}
1073
+
1074
+func (d *driver) DeleteEndpoint(nid, eid string) error {
1075
+	var err error
1076
+
1077
+	// Get the network handler and make sure it exists
1078
+	d.Lock()
1079
+	n, ok := d.networks[nid]
1080
+	d.Unlock()
1081
+
1082
+	if !ok {
1083
+		return types.InternalMaskableErrorf("network %s does not exist", nid)
1084
+	}
1085
+	if n == nil {
1086
+		return driverapi.ErrNoNetwork(nid)
1087
+	}
1088
+
1089
+	// Sanity Check
1090
+	n.Lock()
1091
+	if n.id != nid {
1092
+		n.Unlock()
1093
+		return InvalidNetworkIDError(nid)
1094
+	}
1095
+	n.Unlock()
1096
+
1097
+	// Check endpoint id and if an endpoint is actually there
1098
+	ep, err := n.getEndpoint(eid)
1099
+	if err != nil {
1100
+		return err
1101
+	}
1102
+	if ep == nil {
1103
+		return EndpointNotFoundError(eid)
1104
+	}
1105
+
1106
+	// Remove it
1107
+	n.Lock()
1108
+	delete(n.endpoints, eid)
1109
+	n.Unlock()
1110
+
1111
+	// On failure make sure to set back ep in n.endpoints, but only
1112
+	// if it hasn't been taken over already by some other thread.
1113
+	defer func() {
1114
+		if err != nil {
1115
+			n.Lock()
1116
+			if _, ok := n.endpoints[eid]; !ok {
1117
+				n.endpoints[eid] = ep
1118
+			}
1119
+			n.Unlock()
1120
+		}
1121
+	}()
1122
+
1123
+	// Try removal of link. Discard error: it is a best effort.
1124
+	// Also make sure defer does not see this error either.
1125
+	if link, err := d.nlh.LinkByName(ep.srcName); err == nil {
1126
+		if err := d.nlh.LinkDel(link); err != nil {
1127
+			log.G(context.TODO()).WithError(err).Errorf("Failed to delete interface (%s)'s link on endpoint (%s) delete", ep.srcName, ep.id)
1128
+		}
1129
+	}
1130
+
1131
+	if err := d.storeDelete(ep); err != nil {
1132
+		log.G(context.TODO()).Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err)
1133
+	}
1134
+
1135
+	return nil
1136
+}
1137
+
1138
+func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
1139
+	// Get the network handler and make sure it exists
1140
+	d.Lock()
1141
+	n, ok := d.networks[nid]
1142
+	d.Unlock()
1143
+	if !ok {
1144
+		return nil, types.NotFoundErrorf("network %s does not exist", nid)
1145
+	}
1146
+	if n == nil {
1147
+		return nil, driverapi.ErrNoNetwork(nid)
1148
+	}
1149
+
1150
+	// Sanity check
1151
+	n.Lock()
1152
+	if n.id != nid {
1153
+		n.Unlock()
1154
+		return nil, InvalidNetworkIDError(nid)
1155
+	}
1156
+	n.Unlock()
1157
+
1158
+	// Check if endpoint id is good and retrieve correspondent endpoint
1159
+	ep, err := n.getEndpoint(eid)
1160
+	if err != nil {
1161
+		return nil, err
1162
+	}
1163
+	if ep == nil {
1164
+		return nil, driverapi.ErrNoEndpoint(eid)
1165
+	}
1166
+
1167
+	m := make(map[string]interface{})
1168
+
1169
+	if ep.extConnConfig != nil && ep.extConnConfig.ExposedPorts != nil {
1170
+		// Return a copy of the config data
1171
+		epc := make([]types.TransportPort, 0, len(ep.extConnConfig.ExposedPorts))
1172
+		for _, tp := range ep.extConnConfig.ExposedPorts {
1173
+			epc = append(epc, tp.GetCopy())
1174
+		}
1175
+		m[netlabel.ExposedPorts] = epc
1176
+	}
1177
+
1178
+	if ep.portMapping != nil {
1179
+		// Return a copy of the operational data
1180
+		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
1181
+		for _, pm := range ep.portMapping {
1182
+			pmc = append(pmc, pm.GetCopy())
1183
+		}
1184
+		m[netlabel.PortMap] = pmc
1185
+	}
1186
+
1187
+	if len(ep.macAddress) != 0 {
1188
+		m[netlabel.MacAddress] = ep.macAddress
1189
+	}
1190
+
1191
+	return m, nil
1192
+}
1193
+
1194
+// Join method is invoked when a Sandbox is attached to an endpoint.
1195
+func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
1196
+	network, err := d.getNetwork(nid)
1197
+	if err != nil {
1198
+		return err
1199
+	}
1200
+
1201
+	endpoint, err := network.getEndpoint(eid)
1202
+	if err != nil {
1203
+		return err
1204
+	}
1205
+
1206
+	if endpoint == nil {
1207
+		return EndpointNotFoundError(eid)
1208
+	}
1209
+
1210
+	endpoint.containerConfig, err = parseContainerOptions(options)
1211
+	if err != nil {
1212
+		return err
1213
+	}
1214
+
1215
+	iNames := jinfo.InterfaceName()
1216
+	containerVethPrefix := defaultContainerVethPrefix
1217
+	if network.config.ContainerIfacePrefix != "" {
1218
+		containerVethPrefix = network.config.ContainerIfacePrefix
1219
+	}
1220
+	err = iNames.SetNames(endpoint.srcName, containerVethPrefix)
1221
+	if err != nil {
1222
+		return err
1223
+	}
1224
+
1225
+	err = jinfo.SetGateway(network.bridge.gatewayIPv4)
1226
+	if err != nil {
1227
+		return err
1228
+	}
1229
+
1230
+	err = jinfo.SetGatewayIPv6(network.bridge.gatewayIPv6)
1231
+	if err != nil {
1232
+		return err
1233
+	}
1234
+
1235
+	return nil
1236
+}
1237
+
1238
+// Leave method is invoked when a Sandbox detaches from an endpoint.
1239
+func (d *driver) Leave(nid, eid string) error {
1240
+	network, err := d.getNetwork(nid)
1241
+	if err != nil {
1242
+		return types.InternalMaskableErrorf("%s", err)
1243
+	}
1244
+
1245
+	endpoint, err := network.getEndpoint(eid)
1246
+	if err != nil {
1247
+		return err
1248
+	}
1249
+
1250
+	if endpoint == nil {
1251
+		return EndpointNotFoundError(eid)
1252
+	}
1253
+
1254
+	if !network.config.EnableICC {
1255
+		if err = d.link(network, endpoint, false); err != nil {
1256
+			return err
1257
+		}
1258
+	}
1259
+
1260
+	return nil
1261
+}
1262
+
1263
+func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
1264
+	network, err := d.getNetwork(nid)
1265
+	if err != nil {
1266
+		return err
1267
+	}
1268
+
1269
+	endpoint, err := network.getEndpoint(eid)
1270
+	if err != nil {
1271
+		return err
1272
+	}
1273
+
1274
+	if endpoint == nil {
1275
+		return EndpointNotFoundError(eid)
1276
+	}
1277
+
1278
+	endpoint.extConnConfig, err = parseConnectivityOptions(options)
1279
+	if err != nil {
1280
+		return err
1281
+	}
1282
+
1283
+	// Program any required port mapping and store them in the endpoint
1284
+	endpoint.portMapping, err = network.allocatePorts(endpoint, network.config.DefaultBindingIP, d.config.EnableUserlandProxy)
1285
+	if err != nil {
1286
+		return err
1287
+	}
1288
+
1289
+	defer func() {
1290
+		if err != nil {
1291
+			if e := network.releasePorts(endpoint); e != nil {
1292
+				log.G(context.TODO()).Errorf("Failed to release ports allocated for the bridge endpoint %s on failure %v because of %v",
1293
+					eid, err, e)
1294
+			}
1295
+			endpoint.portMapping = nil
1296
+		}
1297
+	}()
1298
+
1299
+	// Clean the connection tracker state of the host for the specific endpoint. This is needed because some flows may
1300
+	// be bound to the local proxy, or to the host (for UDP packets), and won't be redirected to the new endpoints.
1301
+	clearConntrackEntries(d.nlh, endpoint)
1302
+
1303
+	if err = d.storeUpdate(endpoint); err != nil {
1304
+		return fmt.Errorf("failed to update bridge endpoint %.7s to store: %v", endpoint.id, err)
1305
+	}
1306
+
1307
+	if !network.config.EnableICC {
1308
+		return d.link(network, endpoint, true)
1309
+	}
1310
+
1311
+	return nil
1312
+}
1313
+
1314
+func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
1315
+	network, err := d.getNetwork(nid)
1316
+	if err != nil {
1317
+		return err
1318
+	}
1319
+
1320
+	endpoint, err := network.getEndpoint(eid)
1321
+	if err != nil {
1322
+		return err
1323
+	}
1324
+
1325
+	if endpoint == nil {
1326
+		return EndpointNotFoundError(eid)
1327
+	}
1328
+
1329
+	err = network.releasePorts(endpoint)
1330
+	if err != nil {
1331
+		log.G(context.TODO()).Warn(err)
1332
+	}
1333
+
1334
+	endpoint.portMapping = nil
1335
+
1336
+	// Clean the connection tracker state of the host for the specific endpoint. This is a precautionary measure to
1337
+	// avoid new endpoints getting the same IP address to receive unexpected packets due to bad conntrack state leading
1338
+	// to bad NATing.
1339
+	clearConntrackEntries(d.nlh, endpoint)
1340
+
1341
+	if err = d.storeUpdate(endpoint); err != nil {
1342
+		return fmt.Errorf("failed to update bridge endpoint %.7s to store: %v", endpoint.id, err)
1343
+	}
1344
+
1345
+	return nil
1346
+}
1347
+
1348
+func (d *driver) link(network *bridgeNetwork, endpoint *bridgeEndpoint, enable bool) (retErr error) {
1349
+	cc := endpoint.containerConfig
1350
+	ec := endpoint.extConnConfig
1351
+	if cc == nil || ec == nil || (len(cc.ParentEndpoints) == 0 && len(cc.ChildEndpoints) == 0) {
1352
+		// nothing to do
1353
+		return nil
1354
+	}
1355
+
1356
+	// Try to keep things atomic. addedLinks keeps track of links that were
1357
+	// successfully added. If any error occurred, then roll back all.
1358
+	var addedLinks []*link
1359
+	defer func() {
1360
+		if retErr == nil {
1361
+			return
1362
+		}
1363
+		for _, l := range addedLinks {
1364
+			l.Disable()
1365
+		}
1366
+	}()
1367
+
1368
+	if ec.ExposedPorts != nil {
1369
+		for _, p := range cc.ParentEndpoints {
1370
+			parentEndpoint, err := network.getEndpoint(p)
1371
+			if err != nil {
1372
+				return err
1373
+			}
1374
+			if parentEndpoint == nil {
1375
+				return InvalidEndpointIDError(p)
1376
+			}
1377
+
1378
+			l, err := newLink(parentEndpoint.addr.IP, endpoint.addr.IP, ec.ExposedPorts, network.config.BridgeName)
1379
+			if err != nil {
1380
+				return err
1381
+			}
1382
+			if enable {
1383
+				if err := l.Enable(); err != nil {
1384
+					return err
1385
+				}
1386
+				addedLinks = append(addedLinks, l)
1387
+			} else {
1388
+				l.Disable()
1389
+			}
1390
+		}
1391
+	}
1392
+
1393
+	for _, c := range cc.ChildEndpoints {
1394
+		childEndpoint, err := network.getEndpoint(c)
1395
+		if err != nil {
1396
+			return err
1397
+		}
1398
+		if childEndpoint == nil {
1399
+			return InvalidEndpointIDError(c)
1400
+		}
1401
+		if childEndpoint.extConnConfig == nil || childEndpoint.extConnConfig.ExposedPorts == nil {
1402
+			continue
1403
+		}
1404
+
1405
+		l, err := newLink(endpoint.addr.IP, childEndpoint.addr.IP, childEndpoint.extConnConfig.ExposedPorts, network.config.BridgeName)
1406
+		if err != nil {
1407
+			return err
1408
+		}
1409
+		if enable {
1410
+			if err := l.Enable(); err != nil {
1411
+				return err
1412
+			}
1413
+			addedLinks = append(addedLinks, l)
1414
+		} else {
1415
+			l.Disable()
1416
+		}
1417
+	}
1418
+
1419
+	return nil
1420
+}
1421
+
1422
+func (d *driver) Type() string {
1423
+	return NetworkType
1424
+}
1425
+
1426
+func (d *driver) IsBuiltIn() bool {
1427
+	return true
1428
+}
1429
+
1430
+func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) {
1431
+	if epOptions == nil {
1432
+		return nil, nil
1433
+	}
1434
+
1435
+	ec := &endpointConfiguration{}
1436
+
1437
+	if opt, ok := epOptions[netlabel.MacAddress]; ok {
1438
+		if mac, ok := opt.(net.HardwareAddr); ok {
1439
+			ec.MacAddress = mac
1440
+		} else {
1441
+			return nil, &ErrInvalidEndpointConfig{}
1442
+		}
1443
+	}
1444
+
1445
+	return ec, nil
1446
+}
1447
+
1448
+func parseContainerOptions(cOptions map[string]interface{}) (*containerConfiguration, error) {
1449
+	if cOptions == nil {
1450
+		return nil, nil
1451
+	}
1452
+	genericData := cOptions[netlabel.GenericData]
1453
+	if genericData == nil {
1454
+		return nil, nil
1455
+	}
1456
+	switch opt := genericData.(type) {
1457
+	case options.Generic:
1458
+		opaqueConfig, err := options.GenerateFromModel(opt, &containerConfiguration{})
1459
+		if err != nil {
1460
+			return nil, err
1461
+		}
1462
+		return opaqueConfig.(*containerConfiguration), nil
1463
+	case *containerConfiguration:
1464
+		return opt, nil
1465
+	default:
1466
+		return nil, nil
1467
+	}
1468
+}
1469
+
1470
+func parseConnectivityOptions(cOptions map[string]interface{}) (*connectivityConfiguration, error) {
1471
+	if cOptions == nil {
1472
+		return nil, nil
1473
+	}
1474
+
1475
+	cc := &connectivityConfiguration{}
1476
+
1477
+	if opt, ok := cOptions[netlabel.PortMap]; ok {
1478
+		if pb, ok := opt.([]types.PortBinding); ok {
1479
+			cc.PortBindings = pb
1480
+		} else {
1481
+			return nil, types.BadRequestErrorf("Invalid port mapping data in connectivity configuration: %v", opt)
1482
+		}
1483
+	}
1484
+
1485
+	if opt, ok := cOptions[netlabel.ExposedPorts]; ok {
1486
+		if ports, ok := opt.([]types.TransportPort); ok {
1487
+			cc.ExposedPorts = ports
1488
+		} else {
1489
+			return nil, types.BadRequestErrorf("Invalid exposed ports data in connectivity configuration: %v", opt)
1490
+		}
1491
+	}
1492
+
1493
+	return cc, nil
1494
+}
1495
+
1496
+func electMacAddress(epConfig *endpointConfiguration, ip net.IP) net.HardwareAddr {
1497
+	if epConfig != nil && epConfig.MacAddress != nil {
1498
+		return epConfig.MacAddress
1499
+	}
1500
+	return netutils.GenerateMACFromIP(ip)
1501
+}
0 1502
new file mode 100644
... ...
@@ -0,0 +1,1165 @@
0
+package bridge
1
+
2
+import (
3
+	"bytes"
4
+	"encoding/json"
5
+	"fmt"
6
+	"net"
7
+	"regexp"
8
+	"strconv"
9
+	"testing"
10
+
11
+	"github.com/docker/docker/internal/testutils/netnsutils"
12
+	"github.com/docker/docker/libnetwork/driverapi"
13
+	"github.com/docker/docker/libnetwork/ipamutils"
14
+	"github.com/docker/docker/libnetwork/iptables"
15
+	"github.com/docker/docker/libnetwork/netlabel"
16
+	"github.com/docker/docker/libnetwork/netutils"
17
+	"github.com/docker/docker/libnetwork/options"
18
+	"github.com/docker/docker/libnetwork/portallocator"
19
+	"github.com/docker/docker/libnetwork/types"
20
+	"github.com/vishvananda/netlink"
21
+)
22
+
23
+func TestEndpointMarshalling(t *testing.T) {
24
+	ip1, _ := types.ParseCIDR("172.22.0.9/16")
25
+	ip2, _ := types.ParseCIDR("2001:db8::9")
26
+	mac, _ := net.ParseMAC("ac:bd:24:57:66:77")
27
+	e := &bridgeEndpoint{
28
+		id:         "d2c015a1fe5930650cbcd50493efba0500bcebd8ee1f4401a16319f8a567de33",
29
+		nid:        "ee33fbb43c323f1920b6b35a0101552ac22ede960d0e5245e9738bccc68b2415",
30
+		addr:       ip1,
31
+		addrv6:     ip2,
32
+		macAddress: mac,
33
+		srcName:    "veth123456",
34
+		config:     &endpointConfiguration{MacAddress: mac},
35
+		containerConfig: &containerConfiguration{
36
+			ParentEndpoints: []string{"one", "due", "three"},
37
+			ChildEndpoints:  []string{"four", "five", "six"},
38
+		},
39
+		extConnConfig: &connectivityConfiguration{
40
+			ExposedPorts: []types.TransportPort{
41
+				{
42
+					Proto: 6,
43
+					Port:  uint16(18),
44
+				},
45
+			},
46
+			PortBindings: []types.PortBinding{
47
+				{
48
+					Proto:       6,
49
+					IP:          net.ParseIP("17210.33.9.56"),
50
+					Port:        uint16(18),
51
+					HostPort:    uint16(3000),
52
+					HostPortEnd: uint16(14000),
53
+				},
54
+			},
55
+		},
56
+		portMapping: []types.PortBinding{
57
+			{
58
+				Proto:       17,
59
+				IP:          net.ParseIP("172.33.9.56"),
60
+				Port:        uint16(99),
61
+				HostIP:      net.ParseIP("10.10.100.2"),
62
+				HostPort:    uint16(9900),
63
+				HostPortEnd: uint16(10000),
64
+			},
65
+			{
66
+				Proto:       6,
67
+				IP:          net.ParseIP("171.33.9.56"),
68
+				Port:        uint16(55),
69
+				HostIP:      net.ParseIP("10.11.100.2"),
70
+				HostPort:    uint16(5500),
71
+				HostPortEnd: uint16(55000),
72
+			},
73
+		},
74
+	}
75
+
76
+	b, err := json.Marshal(e)
77
+	if err != nil {
78
+		t.Fatal(err)
79
+	}
80
+
81
+	ee := &bridgeEndpoint{}
82
+	err = json.Unmarshal(b, ee)
83
+	if err != nil {
84
+		t.Fatal(err)
85
+	}
86
+
87
+	if e.id != ee.id || e.nid != ee.nid || e.srcName != ee.srcName || !bytes.Equal(e.macAddress, ee.macAddress) ||
88
+		!types.CompareIPNet(e.addr, ee.addr) || !types.CompareIPNet(e.addrv6, ee.addrv6) ||
89
+		!compareEpConfig(e.config, ee.config) ||
90
+		!compareContainerConfig(e.containerConfig, ee.containerConfig) ||
91
+		!compareConnConfig(e.extConnConfig, ee.extConnConfig) ||
92
+		!compareBindings(e.portMapping, ee.portMapping) {
93
+		t.Fatalf("JSON marsh/unmarsh failed.\nOriginal:\n%#v\nDecoded:\n%#v", e, ee)
94
+	}
95
+}
96
+
97
+func compareEpConfig(a, b *endpointConfiguration) bool {
98
+	if a == b {
99
+		return true
100
+	}
101
+	if a == nil || b == nil {
102
+		return false
103
+	}
104
+	return bytes.Equal(a.MacAddress, b.MacAddress)
105
+}
106
+
107
+func compareContainerConfig(a, b *containerConfiguration) bool {
108
+	if a == b {
109
+		return true
110
+	}
111
+	if a == nil || b == nil {
112
+		return false
113
+	}
114
+	if len(a.ParentEndpoints) != len(b.ParentEndpoints) ||
115
+		len(a.ChildEndpoints) != len(b.ChildEndpoints) {
116
+		return false
117
+	}
118
+	for i := 0; i < len(a.ParentEndpoints); i++ {
119
+		if a.ParentEndpoints[i] != b.ParentEndpoints[i] {
120
+			return false
121
+		}
122
+	}
123
+	for i := 0; i < len(a.ChildEndpoints); i++ {
124
+		if a.ChildEndpoints[i] != b.ChildEndpoints[i] {
125
+			return false
126
+		}
127
+	}
128
+	return true
129
+}
130
+
131
+func compareConnConfig(a, b *connectivityConfiguration) bool {
132
+	if a == b {
133
+		return true
134
+	}
135
+	if a == nil || b == nil {
136
+		return false
137
+	}
138
+	if len(a.ExposedPorts) != len(b.ExposedPorts) ||
139
+		len(a.PortBindings) != len(b.PortBindings) {
140
+		return false
141
+	}
142
+	for i := 0; i < len(a.ExposedPorts); i++ {
143
+		if !a.ExposedPorts[i].Equal(&b.ExposedPorts[i]) {
144
+			return false
145
+		}
146
+	}
147
+	for i := 0; i < len(a.PortBindings); i++ {
148
+		if !comparePortBinding(&a.PortBindings[i], &b.PortBindings[i]) {
149
+			return false
150
+		}
151
+	}
152
+	return true
153
+}
154
+
155
+// comparePortBinding returns whether the given PortBindings are equal.
156
+func comparePortBinding(p *types.PortBinding, o *types.PortBinding) bool {
157
+	if p == o {
158
+		return true
159
+	}
160
+
161
+	if o == nil {
162
+		return false
163
+	}
164
+
165
+	if p.Proto != o.Proto || p.Port != o.Port ||
166
+		p.HostPort != o.HostPort || p.HostPortEnd != o.HostPortEnd {
167
+		return false
168
+	}
169
+
170
+	if p.IP != nil {
171
+		if !p.IP.Equal(o.IP) {
172
+			return false
173
+		}
174
+	} else {
175
+		if o.IP != nil {
176
+			return false
177
+		}
178
+	}
179
+
180
+	if p.HostIP != nil {
181
+		if !p.HostIP.Equal(o.HostIP) {
182
+			return false
183
+		}
184
+	} else {
185
+		if o.HostIP != nil {
186
+			return false
187
+		}
188
+	}
189
+
190
+	return true
191
+}
192
+
193
+func compareBindings(a, b []types.PortBinding) bool {
194
+	if len(a) != len(b) {
195
+		return false
196
+	}
197
+	for i := 0; i < len(a); i++ {
198
+		if !comparePortBinding(&a[i], &b[i]) {
199
+			return false
200
+		}
201
+	}
202
+	return true
203
+}
204
+
205
+func getIPv4Data(t *testing.T, iface string) []driverapi.IPAMData {
206
+	ipd := driverapi.IPAMData{AddressSpace: "full"}
207
+	nw, err := netutils.FindAvailableNetwork(ipamutils.GetLocalScopeDefaultNetworks())
208
+	if err != nil {
209
+		t.Fatal(err)
210
+	}
211
+	ipd.Pool = nw
212
+	// Set network gateway to X.X.X.1
213
+	ipd.Gateway = types.GetIPNetCopy(nw)
214
+	ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1
215
+	return []driverapi.IPAMData{ipd}
216
+}
217
+
218
+func TestCreateFullOptions(t *testing.T) {
219
+	defer netnsutils.SetupTestOSContext(t)()
220
+	d := newDriver()
221
+
222
+	config := &configuration{
223
+		EnableIPForwarding: true,
224
+		EnableIPTables:     true,
225
+	}
226
+
227
+	// Test this scenario: Default gw address does not belong to
228
+	// container network and it's greater than bridge address
229
+	cnw, _ := types.ParseCIDR("172.16.122.0/24")
230
+	bnw, _ := types.ParseCIDR("172.16.0.0/24")
231
+	br, _ := types.ParseCIDR("172.16.0.1/16")
232
+	defgw, _ := types.ParseCIDR("172.16.0.100/16")
233
+
234
+	genericOption := make(map[string]interface{})
235
+	genericOption[netlabel.GenericData] = config
236
+
237
+	if err := d.configure(genericOption); err != nil {
238
+		t.Fatalf("Failed to setup driver config: %v", err)
239
+	}
240
+
241
+	netOption := make(map[string]interface{})
242
+	netOption[netlabel.EnableIPv6] = true
243
+	netOption[netlabel.GenericData] = &networkConfiguration{
244
+		BridgeName: DefaultBridgeName,
245
+	}
246
+
247
+	ipdList := []driverapi.IPAMData{
248
+		{
249
+			Pool:         bnw,
250
+			Gateway:      br,
251
+			AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
252
+		},
253
+	}
254
+	err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil)
255
+	if err != nil {
256
+		t.Fatalf("Failed to create bridge: %v", err)
257
+	}
258
+
259
+	// Verify the IP address allocated for the endpoint belongs to the container network
260
+	epOptions := make(map[string]interface{})
261
+	te := newTestEndpoint(cnw, 10)
262
+	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
263
+	if err != nil {
264
+		t.Fatalf("Failed to create an endpoint : %s", err.Error())
265
+	}
266
+
267
+	if !cnw.Contains(te.Interface().Address().IP) {
268
+		t.Fatalf("endpoint got assigned address outside of container network(%s): %s", cnw.String(), te.Interface().Address())
269
+	}
270
+}
271
+
272
+func TestCreateNoConfig(t *testing.T) {
273
+	defer netnsutils.SetupTestOSContext(t)()
274
+	d := newDriver()
275
+
276
+	netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
277
+	genericOption := make(map[string]interface{})
278
+	genericOption[netlabel.GenericData] = netconfig
279
+
280
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
281
+		t.Fatalf("Failed to create bridge: %v", err)
282
+	}
283
+}
284
+
285
+func TestCreateFullOptionsLabels(t *testing.T) {
286
+	defer netnsutils.SetupTestOSContext(t)()
287
+	d := newDriver()
288
+
289
+	config := &configuration{
290
+		EnableIPForwarding: true,
291
+	}
292
+	genericOption := make(map[string]interface{})
293
+	genericOption[netlabel.GenericData] = config
294
+
295
+	if err := d.configure(genericOption); err != nil {
296
+		t.Fatalf("Failed to setup driver config: %v", err)
297
+	}
298
+
299
+	bndIPs := "127.0.0.1"
300
+	testHostIP := "1.2.3.4"
301
+	nwV6s := "2001:db8:2600:2700:2800::/80"
302
+	gwV6s := "2001:db8:2600:2700:2800::25/80"
303
+	nwV6, _ := types.ParseCIDR(nwV6s)
304
+	gwV6, _ := types.ParseCIDR(gwV6s)
305
+
306
+	labels := map[string]string{
307
+		BridgeName:         DefaultBridgeName,
308
+		DefaultBridge:      "true",
309
+		EnableICC:          "true",
310
+		EnableIPMasquerade: "true",
311
+		DefaultBindingIP:   bndIPs,
312
+		netlabel.HostIP:    testHostIP,
313
+	}
314
+
315
+	netOption := make(map[string]interface{})
316
+	netOption[netlabel.EnableIPv6] = true
317
+	netOption[netlabel.GenericData] = labels
318
+
319
+	ipdList := getIPv4Data(t, "")
320
+	ipd6List := []driverapi.IPAMData{
321
+		{
322
+			Pool: nwV6,
323
+			AuxAddresses: map[string]*net.IPNet{
324
+				DefaultGatewayV6AuxKey: gwV6,
325
+			},
326
+		},
327
+	}
328
+
329
+	err := d.CreateNetwork("dummy", netOption, nil, ipdList, ipd6List)
330
+	if err != nil {
331
+		t.Fatalf("Failed to create bridge: %v", err)
332
+	}
333
+
334
+	nw, ok := d.networks["dummy"]
335
+	if !ok {
336
+		t.Fatal("Cannot find dummy network in bridge driver")
337
+	}
338
+
339
+	if nw.config.BridgeName != DefaultBridgeName {
340
+		t.Fatal("incongruent name in bridge network")
341
+	}
342
+
343
+	if !nw.config.EnableIPv6 {
344
+		t.Fatal("incongruent EnableIPv6 in bridge network")
345
+	}
346
+
347
+	if !nw.config.EnableICC {
348
+		t.Fatal("incongruent EnableICC in bridge network")
349
+	}
350
+
351
+	if !nw.config.EnableIPMasquerade {
352
+		t.Fatal("incongruent EnableIPMasquerade in bridge network")
353
+	}
354
+
355
+	bndIP := net.ParseIP(bndIPs)
356
+	if !bndIP.Equal(nw.config.DefaultBindingIP) {
357
+		t.Fatalf("Unexpected: %v", nw.config.DefaultBindingIP)
358
+	}
359
+
360
+	hostIP := net.ParseIP(testHostIP)
361
+	if !hostIP.Equal(nw.config.HostIP) {
362
+		t.Fatalf("Unexpected: %v", nw.config.HostIP)
363
+	}
364
+
365
+	if !types.CompareIPNet(nw.config.AddressIPv6, nwV6) {
366
+		t.Fatalf("Unexpected: %v", nw.config.AddressIPv6)
367
+	}
368
+
369
+	if !gwV6.IP.Equal(nw.config.DefaultGatewayIPv6) {
370
+		t.Fatalf("Unexpected: %v", nw.config.DefaultGatewayIPv6)
371
+	}
372
+
373
+	// In short here we are testing --fixed-cidr-v6 daemon option
374
+	// plus --mac-address run option
375
+	mac, _ := net.ParseMAC("aa:bb:cc:dd:ee:ff")
376
+	epOptions := map[string]interface{}{netlabel.MacAddress: mac}
377
+	te := newTestEndpoint(ipdList[0].Pool, 20)
378
+	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
379
+	if err != nil {
380
+		t.Fatal(err)
381
+	}
382
+
383
+	if !nwV6.Contains(te.Interface().AddressIPv6().IP) {
384
+		t.Fatalf("endpoint got assigned address outside of container network(%s): %s", nwV6.String(), te.Interface().AddressIPv6())
385
+	}
386
+	if te.Interface().AddressIPv6().IP.String() != "2001:db8:2600:2700:2800:aabb:ccdd:eeff" {
387
+		t.Fatalf("Unexpected endpoint IPv6 address: %v", te.Interface().AddressIPv6().IP)
388
+	}
389
+}
390
+
391
+func TestCreate(t *testing.T) {
392
+	defer netnsutils.SetupTestOSContext(t)()
393
+
394
+	d := newDriver()
395
+
396
+	if err := d.configure(nil); err != nil {
397
+		t.Fatalf("Failed to setup driver config: %v", err)
398
+	}
399
+
400
+	netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
401
+	genericOption := make(map[string]interface{})
402
+	genericOption[netlabel.GenericData] = netconfig
403
+
404
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
405
+		t.Fatalf("Failed to create bridge: %v", err)
406
+	}
407
+
408
+	err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil)
409
+	if err == nil {
410
+		t.Fatal("Expected bridge driver to refuse creation of second network with default name")
411
+	}
412
+	if _, ok := err.(types.ForbiddenError); !ok {
413
+		t.Fatal("Creation of second network with default name failed with unexpected error type")
414
+	}
415
+}
416
+
417
+func TestCreateFail(t *testing.T) {
418
+	defer netnsutils.SetupTestOSContext(t)()
419
+
420
+	d := newDriver()
421
+
422
+	if err := d.configure(nil); err != nil {
423
+		t.Fatalf("Failed to setup driver config: %v", err)
424
+	}
425
+
426
+	netconfig := &networkConfiguration{BridgeName: "dummy0", DefaultBridge: true}
427
+	genericOption := make(map[string]interface{})
428
+	genericOption[netlabel.GenericData] = netconfig
429
+
430
+	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err == nil {
431
+		t.Fatal("Bridge creation was expected to fail")
432
+	}
433
+}
434
+
435
+func TestCreateMultipleNetworks(t *testing.T) {
436
+	defer netnsutils.SetupTestOSContext(t)()
437
+
438
+	d := newDriver()
439
+
440
+	config := &configuration{
441
+		EnableIPTables: true,
442
+	}
443
+	genericOption := make(map[string]interface{})
444
+	genericOption[netlabel.GenericData] = config
445
+
446
+	if err := d.configure(genericOption); err != nil {
447
+		t.Fatalf("Failed to setup driver config: %v", err)
448
+	}
449
+
450
+	config1 := &networkConfiguration{BridgeName: "net_test_1"}
451
+	genericOption = make(map[string]interface{})
452
+	genericOption[netlabel.GenericData] = config1
453
+	if err := d.CreateNetwork("1", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
454
+		t.Fatalf("Failed to create bridge: %v", err)
455
+	}
456
+
457
+	verifyV4INCEntries(d.networks, t)
458
+
459
+	config2 := &networkConfiguration{BridgeName: "net_test_2"}
460
+	genericOption[netlabel.GenericData] = config2
461
+	if err := d.CreateNetwork("2", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
462
+		t.Fatalf("Failed to create bridge: %v", err)
463
+	}
464
+
465
+	verifyV4INCEntries(d.networks, t)
466
+
467
+	config3 := &networkConfiguration{BridgeName: "net_test_3"}
468
+	genericOption[netlabel.GenericData] = config3
469
+	if err := d.CreateNetwork("3", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
470
+		t.Fatalf("Failed to create bridge: %v", err)
471
+	}
472
+
473
+	verifyV4INCEntries(d.networks, t)
474
+
475
+	config4 := &networkConfiguration{BridgeName: "net_test_4"}
476
+	genericOption[netlabel.GenericData] = config4
477
+	if err := d.CreateNetwork("4", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
478
+		t.Fatalf("Failed to create bridge: %v", err)
479
+	}
480
+
481
+	verifyV4INCEntries(d.networks, t)
482
+
483
+	if err := d.DeleteNetwork("1"); err != nil {
484
+		t.Log(err)
485
+	}
486
+	verifyV4INCEntries(d.networks, t)
487
+
488
+	if err := d.DeleteNetwork("2"); err != nil {
489
+		t.Log(err)
490
+	}
491
+	verifyV4INCEntries(d.networks, t)
492
+
493
+	if err := d.DeleteNetwork("3"); err != nil {
494
+		t.Log(err)
495
+	}
496
+	verifyV4INCEntries(d.networks, t)
497
+
498
+	if err := d.DeleteNetwork("4"); err != nil {
499
+		t.Log(err)
500
+	}
501
+	verifyV4INCEntries(d.networks, t)
502
+}
503
+
504
+// Verify the network isolation rules are installed for each network
505
+func verifyV4INCEntries(networks map[string]*bridgeNetwork, t *testing.T) {
506
+	iptable := iptables.GetIptable(iptables.IPv4)
507
+	out1, err := iptable.Raw("-S", IsolationChain1)
508
+	if err != nil {
509
+		t.Fatal(err)
510
+	}
511
+	out2, err := iptable.Raw("-S", IsolationChain2)
512
+	if err != nil {
513
+		t.Fatal(err)
514
+	}
515
+
516
+	for _, n := range networks {
517
+		re := regexp.MustCompile(fmt.Sprintf("-i %s ! -o %s -j %s", n.config.BridgeName, n.config.BridgeName, IsolationChain2))
518
+		matches := re.FindAllString(string(out1[:]), -1)
519
+		if len(matches) != 1 {
520
+			t.Fatalf("Cannot find expected inter-network isolation rules in IP Tables for network %s:\n%s.", n.id, string(out1[:]))
521
+		}
522
+		re = regexp.MustCompile(fmt.Sprintf("-o %s -j DROP", n.config.BridgeName))
523
+		matches = re.FindAllString(string(out2[:]), -1)
524
+		if len(matches) != 1 {
525
+			t.Fatalf("Cannot find expected inter-network isolation rules in IP Tables for network %s:\n%s.", n.id, string(out2[:]))
526
+		}
527
+	}
528
+}
529
+
530
+type testInterface struct {
531
+	mac     net.HardwareAddr
532
+	addr    *net.IPNet
533
+	addrv6  *net.IPNet
534
+	srcName string
535
+	dstName string
536
+}
537
+
538
+type testEndpoint struct {
539
+	iface  *testInterface
540
+	gw     net.IP
541
+	gw6    net.IP
542
+	routes []types.StaticRoute
543
+}
544
+
545
+func newTestEndpoint(nw *net.IPNet, ordinal byte) *testEndpoint {
546
+	addr := types.GetIPNetCopy(nw)
547
+	addr.IP[len(addr.IP)-1] = ordinal
548
+	return &testEndpoint{iface: &testInterface{addr: addr}}
549
+}
550
+
551
+func (te *testEndpoint) Interface() driverapi.InterfaceInfo {
552
+	if te.iface != nil {
553
+		return te.iface
554
+	}
555
+
556
+	return nil
557
+}
558
+
559
+func (i *testInterface) MacAddress() net.HardwareAddr {
560
+	return i.mac
561
+}
562
+
563
+func (i *testInterface) Address() *net.IPNet {
564
+	return i.addr
565
+}
566
+
567
+func (i *testInterface) AddressIPv6() *net.IPNet {
568
+	return i.addrv6
569
+}
570
+
571
+func (i *testInterface) SetMacAddress(mac net.HardwareAddr) error {
572
+	if i.mac != nil {
573
+		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", i.mac, mac)
574
+	}
575
+	if mac == nil {
576
+		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
577
+	}
578
+	i.mac = types.GetMacCopy(mac)
579
+	return nil
580
+}
581
+
582
+func (i *testInterface) SetIPAddress(address *net.IPNet) error {
583
+	if address.IP == nil {
584
+		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
585
+	}
586
+	if address.IP.To4() == nil {
587
+		return setAddress(&i.addrv6, address)
588
+	}
589
+	return setAddress(&i.addr, address)
590
+}
591
+
592
+func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
593
+	if *ifaceAddr != nil {
594
+		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
595
+	}
596
+	*ifaceAddr = types.GetIPNetCopy(address)
597
+	return nil
598
+}
599
+
600
+func (i *testInterface) SetNames(srcName string, dstName string) error {
601
+	i.srcName = srcName
602
+	i.dstName = dstName
603
+	return nil
604
+}
605
+
606
+func (te *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo {
607
+	if te.iface != nil {
608
+		return te.iface
609
+	}
610
+
611
+	return nil
612
+}
613
+
614
+func (te *testEndpoint) SetGateway(gw net.IP) error {
615
+	te.gw = gw
616
+	return nil
617
+}
618
+
619
+func (te *testEndpoint) SetGatewayIPv6(gw6 net.IP) error {
620
+	te.gw6 = gw6
621
+	return nil
622
+}
623
+
624
+func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
625
+	te.routes = append(te.routes, types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop})
626
+	return nil
627
+}
628
+
629
+func (te *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
630
+	return nil
631
+}
632
+
633
+func (te *testEndpoint) DisableGatewayService() {}
634
+
635
+func TestQueryEndpointInfo(t *testing.T) {
636
+	testQueryEndpointInfo(t, true)
637
+}
638
+
639
+func TestQueryEndpointInfoHairpin(t *testing.T) {
640
+	testQueryEndpointInfo(t, false)
641
+}
642
+
643
+func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
644
+	defer netnsutils.SetupTestOSContext(t)()
645
+	d := newDriver()
646
+	d.portAllocator = portallocator.NewInstance()
647
+
648
+	config := &configuration{
649
+		EnableIPTables:      true,
650
+		EnableUserlandProxy: ulPxyEnabled,
651
+	}
652
+	genericOption := make(map[string]interface{})
653
+	genericOption[netlabel.GenericData] = config
654
+
655
+	if err := d.configure(genericOption); err != nil {
656
+		t.Fatalf("Failed to setup driver config: %v", err)
657
+	}
658
+
659
+	netconfig := &networkConfiguration{
660
+		BridgeName: DefaultBridgeName,
661
+		EnableICC:  false,
662
+	}
663
+	genericOption = make(map[string]interface{})
664
+	genericOption[netlabel.GenericData] = netconfig
665
+
666
+	ipdList := getIPv4Data(t, "")
667
+	err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
668
+	if err != nil {
669
+		t.Fatalf("Failed to create bridge: %v", err)
670
+	}
671
+
672
+	sbOptions := make(map[string]interface{})
673
+	sbOptions[netlabel.PortMap] = getPortMapping()
674
+
675
+	te := newTestEndpoint(ipdList[0].Pool, 11)
676
+	err = d.CreateEndpoint("net1", "ep1", te.Interface(), nil)
677
+	if err != nil {
678
+		t.Fatalf("Failed to create an endpoint : %s", err.Error())
679
+	}
680
+
681
+	err = d.Join("net1", "ep1", "sbox", te, sbOptions)
682
+	if err != nil {
683
+		t.Fatalf("Failed to join the endpoint: %v", err)
684
+	}
685
+
686
+	err = d.ProgramExternalConnectivity("net1", "ep1", sbOptions)
687
+	if err != nil {
688
+		t.Fatalf("Failed to program external connectivity: %v", err)
689
+	}
690
+
691
+	network, ok := d.networks["net1"]
692
+	if !ok {
693
+		t.Fatalf("Cannot find network %s inside driver", "net1")
694
+	}
695
+	ep := network.endpoints["ep1"]
696
+	data, err := d.EndpointOperInfo(network.id, ep.id)
697
+	if err != nil {
698
+		t.Fatalf("Failed to ask for endpoint operational data:  %v", err)
699
+	}
700
+	pmd, ok := data[netlabel.PortMap]
701
+	if !ok {
702
+		t.Fatal("Endpoint operational data does not contain port mapping data")
703
+	}
704
+	pm, ok := pmd.([]types.PortBinding)
705
+	if !ok {
706
+		t.Fatal("Unexpected format for port mapping in endpoint operational data")
707
+	}
708
+	if len(ep.portMapping) != len(pm) {
709
+		t.Fatal("Incomplete data for port mapping in endpoint operational data")
710
+	}
711
+	for i, pb := range ep.portMapping {
712
+		if !comparePortBinding(&pb, &pm[i]) {
713
+			t.Fatal("Unexpected data for port mapping in endpoint operational data")
714
+		}
715
+	}
716
+
717
+	err = d.RevokeExternalConnectivity("net1", "ep1")
718
+	if err != nil {
719
+		t.Fatal(err)
720
+	}
721
+
722
+	// release host mapped ports
723
+	err = d.Leave("net1", "ep1")
724
+	if err != nil {
725
+		t.Fatal(err)
726
+	}
727
+}
728
+
729
+func getExposedPorts() []types.TransportPort {
730
+	return []types.TransportPort{
731
+		{Proto: types.TCP, Port: uint16(5000)},
732
+		{Proto: types.UDP, Port: uint16(400)},
733
+		{Proto: types.TCP, Port: uint16(600)},
734
+	}
735
+}
736
+
737
+func getPortMapping() []types.PortBinding {
738
+	return []types.PortBinding{
739
+		{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
740
+		{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
741
+		{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
742
+	}
743
+}
744
+
745
+func TestLinkContainers(t *testing.T) {
746
+	defer netnsutils.SetupTestOSContext(t)()
747
+
748
+	d := newDriver()
749
+	iptable := iptables.GetIptable(iptables.IPv4)
750
+
751
+	config := &configuration{
752
+		EnableIPTables: true,
753
+	}
754
+	genericOption := make(map[string]interface{})
755
+	genericOption[netlabel.GenericData] = config
756
+
757
+	if err := d.configure(genericOption); err != nil {
758
+		t.Fatalf("Failed to setup driver config: %v", err)
759
+	}
760
+
761
+	netconfig := &networkConfiguration{
762
+		BridgeName: DefaultBridgeName,
763
+		EnableICC:  false,
764
+	}
765
+	genericOption = make(map[string]interface{})
766
+	genericOption[netlabel.GenericData] = netconfig
767
+
768
+	ipdList := getIPv4Data(t, "")
769
+	err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
770
+	if err != nil {
771
+		t.Fatalf("Failed to create bridge: %v", err)
772
+	}
773
+
774
+	te1 := newTestEndpoint(ipdList[0].Pool, 11)
775
+	err = d.CreateEndpoint("net1", "ep1", te1.Interface(), nil)
776
+	if err != nil {
777
+		t.Fatalf("Failed to create an endpoint : %s", err.Error())
778
+	}
779
+
780
+	exposedPorts := getExposedPorts()
781
+	sbOptions := make(map[string]interface{})
782
+	sbOptions[netlabel.ExposedPorts] = exposedPorts
783
+
784
+	err = d.Join("net1", "ep1", "sbox", te1, sbOptions)
785
+	if err != nil {
786
+		t.Fatalf("Failed to join the endpoint: %v", err)
787
+	}
788
+
789
+	err = d.ProgramExternalConnectivity("net1", "ep1", sbOptions)
790
+	if err != nil {
791
+		t.Fatalf("Failed to program external connectivity: %v", err)
792
+	}
793
+
794
+	addr1 := te1.iface.addr
795
+	if addr1.IP.To4() == nil {
796
+		t.Fatal("No Ipv4 address assigned to the endpoint:  ep1")
797
+	}
798
+
799
+	te2 := newTestEndpoint(ipdList[0].Pool, 22)
800
+	err = d.CreateEndpoint("net1", "ep2", te2.Interface(), nil)
801
+	if err != nil {
802
+		t.Fatalf("Failed to create an endpoint : %s", err.Error())
803
+	}
804
+
805
+	addr2 := te2.iface.addr
806
+	if addr2.IP.To4() == nil {
807
+		t.Fatal("No Ipv4 address assigned to the endpoint:  ep2")
808
+	}
809
+
810
+	sbOptions = make(map[string]interface{})
811
+	sbOptions[netlabel.GenericData] = options.Generic{
812
+		"ChildEndpoints": []string{"ep1"},
813
+	}
814
+
815
+	err = d.Join("net1", "ep2", "", te2, sbOptions)
816
+	if err != nil {
817
+		t.Fatal("Failed to link ep1 and ep2")
818
+	}
819
+
820
+	err = d.ProgramExternalConnectivity("net1", "ep2", sbOptions)
821
+	if err != nil {
822
+		t.Fatalf("Failed to program external connectivity: %v", err)
823
+	}
824
+
825
+	out, _ := iptable.Raw("-L", DockerChain)
826
+	for _, pm := range exposedPorts {
827
+		regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
828
+		re := regexp.MustCompile(regex)
829
+		matches := re.FindAllString(string(out[:]), -1)
830
+		if len(matches) != 1 {
831
+			t.Fatalf("IP Tables programming failed %s", string(out[:]))
832
+		}
833
+
834
+		regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
835
+		matched, _ := regexp.MatchString(regex, string(out[:]))
836
+		if !matched {
837
+			t.Fatalf("IP Tables programming failed %s", string(out[:]))
838
+		}
839
+	}
840
+
841
+	err = d.RevokeExternalConnectivity("net1", "ep2")
842
+	if err != nil {
843
+		t.Fatalf("Failed to revoke external connectivity: %v", err)
844
+	}
845
+
846
+	err = d.Leave("net1", "ep2")
847
+	if err != nil {
848
+		t.Fatal("Failed to unlink ep1 and ep2")
849
+	}
850
+
851
+	out, _ = iptable.Raw("-L", DockerChain)
852
+	for _, pm := range exposedPorts {
853
+		regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
854
+		re := regexp.MustCompile(regex)
855
+		matches := re.FindAllString(string(out[:]), -1)
856
+		if len(matches) != 0 {
857
+			t.Fatalf("Leave should have deleted relevant IPTables rules  %s", string(out[:]))
858
+		}
859
+
860
+		regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
861
+		matched, _ := regexp.MatchString(regex, string(out[:]))
862
+		if matched {
863
+			t.Fatalf("Leave should have deleted relevant IPTables rules  %s", string(out[:]))
864
+		}
865
+	}
866
+
867
+	// Error condition test with an invalid endpoint-id "ep4"
868
+	sbOptions = make(map[string]interface{})
869
+	sbOptions[netlabel.GenericData] = options.Generic{
870
+		"ChildEndpoints": []string{"ep1", "ep4"},
871
+	}
872
+
873
+	err = d.Join("net1", "ep2", "", te2, sbOptions)
874
+	if err != nil {
875
+		t.Fatal(err)
876
+	}
877
+	err = d.ProgramExternalConnectivity("net1", "ep2", sbOptions)
878
+	if err != nil {
879
+		out, _ = iptable.Raw("-L", DockerChain)
880
+		for _, pm := range exposedPorts {
881
+			regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
882
+			re := regexp.MustCompile(regex)
883
+			matches := re.FindAllString(string(out[:]), -1)
884
+			if len(matches) != 0 {
885
+				t.Fatalf("Error handling should rollback relevant IPTables rules  %s", string(out[:]))
886
+			}
887
+
888
+			regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
889
+			matched, _ := regexp.MatchString(regex, string(out[:]))
890
+			if matched {
891
+				t.Fatalf("Error handling should rollback relevant IPTables rules  %s", string(out[:]))
892
+			}
893
+		}
894
+	} else {
895
+		t.Fatal("Expected Join to fail given link conditions are not satisfied")
896
+	}
897
+}
898
+
899
+func TestValidateConfig(t *testing.T) {
900
+	defer netnsutils.SetupTestOSContext(t)()
901
+
902
+	// Test mtu
903
+	c := networkConfiguration{Mtu: -2}
904
+	err := c.Validate()
905
+	if err == nil {
906
+		t.Fatal("Failed to detect invalid MTU number")
907
+	}
908
+
909
+	c.Mtu = 9000
910
+	err = c.Validate()
911
+	if err != nil {
912
+		t.Fatal("unexpected validation error on MTU number")
913
+	}
914
+
915
+	// Bridge network
916
+	_, network, _ := net.ParseCIDR("172.28.0.0/16")
917
+	c = networkConfiguration{
918
+		AddressIPv4: network,
919
+	}
920
+
921
+	err = c.Validate()
922
+	if err != nil {
923
+		t.Fatal(err)
924
+	}
925
+
926
+	// Test v4 gw
927
+	c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234")
928
+	err = c.Validate()
929
+	if err == nil {
930
+		t.Fatal("Failed to detect invalid default gateway")
931
+	}
932
+
933
+	c.DefaultGatewayIPv4 = net.ParseIP("172.28.30.234")
934
+	err = c.Validate()
935
+	if err != nil {
936
+		t.Fatal("Unexpected validation error on default gateway")
937
+	}
938
+
939
+	// Test v6 gw
940
+	_, v6nw, _ := net.ParseCIDR("2001:db8:ae:b004::/64")
941
+	c = networkConfiguration{
942
+		EnableIPv6:         true,
943
+		AddressIPv6:        v6nw,
944
+		DefaultGatewayIPv6: net.ParseIP("2001:db8:ac:b004::bad:a55"),
945
+	}
946
+	err = c.Validate()
947
+	if err == nil {
948
+		t.Fatal("Failed to detect invalid v6 default gateway")
949
+	}
950
+
951
+	c.DefaultGatewayIPv6 = net.ParseIP("2001:db8:ae:b004::bad:a55")
952
+	err = c.Validate()
953
+	if err != nil {
954
+		t.Fatal("Unexpected validation error on v6 default gateway")
955
+	}
956
+
957
+	c.AddressIPv6 = nil
958
+	err = c.Validate()
959
+	if err == nil {
960
+		t.Fatal("Failed to detect invalid v6 default gateway")
961
+	}
962
+
963
+	c.AddressIPv6 = nil
964
+	err = c.Validate()
965
+	if err == nil {
966
+		t.Fatal("Failed to detect invalid v6 default gateway")
967
+	}
968
+}
969
+
970
+func TestSetDefaultGw(t *testing.T) {
971
+	defer netnsutils.SetupTestOSContext(t)()
972
+
973
+	d := newDriver()
974
+
975
+	if err := d.configure(nil); err != nil {
976
+		t.Fatalf("Failed to setup driver config: %v", err)
977
+	}
978
+
979
+	_, subnetv6, _ := net.ParseCIDR("2001:db8:ea9:9abc:b0c4::/80")
980
+
981
+	ipdList := getIPv4Data(t, "")
982
+	gw4 := types.GetIPCopy(ipdList[0].Pool.IP).To4()
983
+	gw4[3] = 254
984
+	gw6 := net.ParseIP("2001:db8:ea9:9abc:b0c4::254")
985
+
986
+	config := &networkConfiguration{
987
+		BridgeName:         DefaultBridgeName,
988
+		AddressIPv6:        subnetv6,
989
+		DefaultGatewayIPv4: gw4,
990
+		DefaultGatewayIPv6: gw6,
991
+	}
992
+
993
+	genericOption := make(map[string]interface{})
994
+	genericOption[netlabel.EnableIPv6] = true
995
+	genericOption[netlabel.GenericData] = config
996
+
997
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
998
+	if err != nil {
999
+		t.Fatalf("Failed to create bridge: %v", err)
1000
+	}
1001
+
1002
+	te := newTestEndpoint(ipdList[0].Pool, 10)
1003
+	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
1004
+	if err != nil {
1005
+		t.Fatalf("Failed to create endpoint: %v", err)
1006
+	}
1007
+
1008
+	err = d.Join("dummy", "ep", "sbox", te, nil)
1009
+	if err != nil {
1010
+		t.Fatalf("Failed to join endpoint: %v", err)
1011
+	}
1012
+
1013
+	if !gw4.Equal(te.gw) {
1014
+		t.Fatalf("Failed to configure default gateway. Expected %v. Found %v", gw4, te.gw)
1015
+	}
1016
+
1017
+	if !gw6.Equal(te.gw6) {
1018
+		t.Fatalf("Failed to configure default gateway. Expected %v. Found %v", gw6, te.gw6)
1019
+	}
1020
+}
1021
+
1022
+func TestCleanupIptableRules(t *testing.T) {
1023
+	defer netnsutils.SetupTestOSContext(t)()
1024
+	bridgeChain := []iptables.ChainInfo{
1025
+		{Name: DockerChain, Table: iptables.Nat},
1026
+		{Name: DockerChain, Table: iptables.Filter},
1027
+		{Name: IsolationChain1, Table: iptables.Filter},
1028
+	}
1029
+
1030
+	ipVersions := []iptables.IPVersion{iptables.IPv4, iptables.IPv6}
1031
+
1032
+	for _, version := range ipVersions {
1033
+		if _, _, _, _, err := setupIPChains(configuration{EnableIPTables: true}, version); err != nil {
1034
+			t.Fatalf("Error setting up ip chains for %s: %v", version, err)
1035
+		}
1036
+
1037
+		iptable := iptables.GetIptable(version)
1038
+		for _, chainInfo := range bridgeChain {
1039
+			if !iptable.ExistChain(chainInfo.Name, chainInfo.Table) {
1040
+				t.Fatalf("iptables version %s chain %s of %s table should have been created", version, chainInfo.Name, chainInfo.Table)
1041
+			}
1042
+		}
1043
+		removeIPChains(version)
1044
+		for _, chainInfo := range bridgeChain {
1045
+			if iptable.ExistChain(chainInfo.Name, chainInfo.Table) {
1046
+				t.Fatalf("iptables version %s chain %s of %s table should have been deleted", version, chainInfo.Name, chainInfo.Table)
1047
+			}
1048
+		}
1049
+	}
1050
+}
1051
+
1052
+func TestCreateWithExistingBridge(t *testing.T) {
1053
+	defer netnsutils.SetupTestOSContext(t)()
1054
+	d := newDriver()
1055
+
1056
+	if err := d.configure(nil); err != nil {
1057
+		t.Fatalf("Failed to setup driver config: %v", err)
1058
+	}
1059
+
1060
+	brName := "br111"
1061
+	br := &netlink.Bridge{
1062
+		LinkAttrs: netlink.LinkAttrs{
1063
+			Name: brName,
1064
+		},
1065
+	}
1066
+	if err := netlink.LinkAdd(br); err != nil {
1067
+		t.Fatalf("Failed to create bridge interface: %v", err)
1068
+	}
1069
+	defer netlink.LinkDel(br)
1070
+	if err := netlink.LinkSetUp(br); err != nil {
1071
+		t.Fatalf("Failed to set bridge interface up: %v", err)
1072
+	}
1073
+
1074
+	ip := net.IP{192, 168, 122, 1}
1075
+	addr := &netlink.Addr{IPNet: &net.IPNet{
1076
+		IP:   ip,
1077
+		Mask: net.IPv4Mask(255, 255, 255, 0),
1078
+	}}
1079
+	if err := netlink.AddrAdd(br, addr); err != nil {
1080
+		t.Fatalf("Failed to add IP address to bridge: %v", err)
1081
+	}
1082
+
1083
+	netconfig := &networkConfiguration{BridgeName: brName}
1084
+	genericOption := make(map[string]interface{})
1085
+	genericOption[netlabel.GenericData] = netconfig
1086
+
1087
+	ipv4Data := []driverapi.IPAMData{{
1088
+		AddressSpace: "full",
1089
+		Pool:         types.GetIPNetCopy(addr.IPNet),
1090
+		Gateway:      types.GetIPNetCopy(addr.IPNet),
1091
+	}}
1092
+	// Set network gateway to X.X.X.1
1093
+	ipv4Data[0].Gateway.IP[len(ipv4Data[0].Gateway.IP)-1] = 1
1094
+
1095
+	if err := d.CreateNetwork(brName, genericOption, nil, ipv4Data, nil); err != nil {
1096
+		t.Fatalf("Failed to create bridge network: %v", err)
1097
+	}
1098
+
1099
+	nw, err := d.getNetwork(brName)
1100
+	if err != nil {
1101
+		t.Fatalf("Failed to getNetwork(%s): %v", brName, err)
1102
+	}
1103
+
1104
+	addrs4, _, err := nw.bridge.addresses()
1105
+	if err != nil {
1106
+		t.Fatalf("Failed to get the bridge network's address: %v", err)
1107
+	}
1108
+
1109
+	if !addrs4[0].IP.Equal(ip) {
1110
+		t.Fatal("Creating bridge network with existing bridge interface unexpectedly modified the IP address of the bridge")
1111
+	}
1112
+
1113
+	if err := d.DeleteNetwork(brName); err != nil {
1114
+		t.Fatalf("Failed to delete network %s: %v", brName, err)
1115
+	}
1116
+
1117
+	if _, err := netlink.LinkByName(brName); err != nil {
1118
+		t.Fatal("Deleting bridge network that using existing bridge interface unexpectedly deleted the bridge interface")
1119
+	}
1120
+}
1121
+
1122
+func TestCreateParallel(t *testing.T) {
1123
+	c := netnsutils.SetupTestOSContextEx(t)
1124
+	defer c.Cleanup(t)
1125
+
1126
+	d := newDriver()
1127
+	d.portAllocator = portallocator.NewInstance()
1128
+
1129
+	if err := d.configure(nil); err != nil {
1130
+		t.Fatalf("Failed to setup driver config: %v", err)
1131
+	}
1132
+
1133
+	ipV4Data := getIPv4Data(t, "docker0")
1134
+
1135
+	ch := make(chan error, 100)
1136
+	for i := 0; i < 100; i++ {
1137
+		name := "net" + strconv.Itoa(i)
1138
+		c.Go(t, func() {
1139
+			config := &networkConfiguration{BridgeName: name}
1140
+			genericOption := make(map[string]interface{})
1141
+			genericOption[netlabel.GenericData] = config
1142
+			if err := d.CreateNetwork(name, genericOption, nil, ipV4Data, nil); err != nil {
1143
+				ch <- fmt.Errorf("failed to create %s", name)
1144
+				return
1145
+			}
1146
+			if err := d.CreateNetwork(name, genericOption, nil, ipV4Data, nil); err == nil {
1147
+				ch <- fmt.Errorf("failed was able to create overlap %s", name)
1148
+				return
1149
+			}
1150
+			ch <- nil
1151
+		})
1152
+	}
1153
+	// wait for the go routines
1154
+	var success int
1155
+	for i := 0; i < 100; i++ {
1156
+		val := <-ch
1157
+		if val == nil {
1158
+			success++
1159
+		}
1160
+	}
1161
+	if success != 1 {
1162
+		t.Fatalf("Success should be 1 instead: %d", success)
1163
+	}
1164
+}
0 1165
deleted file mode 100644
... ...
@@ -1,1167 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"bytes"
7
-	"encoding/json"
8
-	"fmt"
9
-	"net"
10
-	"regexp"
11
-	"strconv"
12
-	"testing"
13
-
14
-	"github.com/docker/docker/internal/testutils/netnsutils"
15
-	"github.com/docker/docker/libnetwork/driverapi"
16
-	"github.com/docker/docker/libnetwork/ipamutils"
17
-	"github.com/docker/docker/libnetwork/iptables"
18
-	"github.com/docker/docker/libnetwork/netlabel"
19
-	"github.com/docker/docker/libnetwork/netutils"
20
-	"github.com/docker/docker/libnetwork/options"
21
-	"github.com/docker/docker/libnetwork/portallocator"
22
-	"github.com/docker/docker/libnetwork/types"
23
-	"github.com/vishvananda/netlink"
24
-)
25
-
26
-func TestEndpointMarshalling(t *testing.T) {
27
-	ip1, _ := types.ParseCIDR("172.22.0.9/16")
28
-	ip2, _ := types.ParseCIDR("2001:db8::9")
29
-	mac, _ := net.ParseMAC("ac:bd:24:57:66:77")
30
-	e := &bridgeEndpoint{
31
-		id:         "d2c015a1fe5930650cbcd50493efba0500bcebd8ee1f4401a16319f8a567de33",
32
-		nid:        "ee33fbb43c323f1920b6b35a0101552ac22ede960d0e5245e9738bccc68b2415",
33
-		addr:       ip1,
34
-		addrv6:     ip2,
35
-		macAddress: mac,
36
-		srcName:    "veth123456",
37
-		config:     &endpointConfiguration{MacAddress: mac},
38
-		containerConfig: &containerConfiguration{
39
-			ParentEndpoints: []string{"one", "due", "three"},
40
-			ChildEndpoints:  []string{"four", "five", "six"},
41
-		},
42
-		extConnConfig: &connectivityConfiguration{
43
-			ExposedPorts: []types.TransportPort{
44
-				{
45
-					Proto: 6,
46
-					Port:  uint16(18),
47
-				},
48
-			},
49
-			PortBindings: []types.PortBinding{
50
-				{
51
-					Proto:       6,
52
-					IP:          net.ParseIP("17210.33.9.56"),
53
-					Port:        uint16(18),
54
-					HostPort:    uint16(3000),
55
-					HostPortEnd: uint16(14000),
56
-				},
57
-			},
58
-		},
59
-		portMapping: []types.PortBinding{
60
-			{
61
-				Proto:       17,
62
-				IP:          net.ParseIP("172.33.9.56"),
63
-				Port:        uint16(99),
64
-				HostIP:      net.ParseIP("10.10.100.2"),
65
-				HostPort:    uint16(9900),
66
-				HostPortEnd: uint16(10000),
67
-			},
68
-			{
69
-				Proto:       6,
70
-				IP:          net.ParseIP("171.33.9.56"),
71
-				Port:        uint16(55),
72
-				HostIP:      net.ParseIP("10.11.100.2"),
73
-				HostPort:    uint16(5500),
74
-				HostPortEnd: uint16(55000),
75
-			},
76
-		},
77
-	}
78
-
79
-	b, err := json.Marshal(e)
80
-	if err != nil {
81
-		t.Fatal(err)
82
-	}
83
-
84
-	ee := &bridgeEndpoint{}
85
-	err = json.Unmarshal(b, ee)
86
-	if err != nil {
87
-		t.Fatal(err)
88
-	}
89
-
90
-	if e.id != ee.id || e.nid != ee.nid || e.srcName != ee.srcName || !bytes.Equal(e.macAddress, ee.macAddress) ||
91
-		!types.CompareIPNet(e.addr, ee.addr) || !types.CompareIPNet(e.addrv6, ee.addrv6) ||
92
-		!compareEpConfig(e.config, ee.config) ||
93
-		!compareContainerConfig(e.containerConfig, ee.containerConfig) ||
94
-		!compareConnConfig(e.extConnConfig, ee.extConnConfig) ||
95
-		!compareBindings(e.portMapping, ee.portMapping) {
96
-		t.Fatalf("JSON marsh/unmarsh failed.\nOriginal:\n%#v\nDecoded:\n%#v", e, ee)
97
-	}
98
-}
99
-
100
-func compareEpConfig(a, b *endpointConfiguration) bool {
101
-	if a == b {
102
-		return true
103
-	}
104
-	if a == nil || b == nil {
105
-		return false
106
-	}
107
-	return bytes.Equal(a.MacAddress, b.MacAddress)
108
-}
109
-
110
-func compareContainerConfig(a, b *containerConfiguration) bool {
111
-	if a == b {
112
-		return true
113
-	}
114
-	if a == nil || b == nil {
115
-		return false
116
-	}
117
-	if len(a.ParentEndpoints) != len(b.ParentEndpoints) ||
118
-		len(a.ChildEndpoints) != len(b.ChildEndpoints) {
119
-		return false
120
-	}
121
-	for i := 0; i < len(a.ParentEndpoints); i++ {
122
-		if a.ParentEndpoints[i] != b.ParentEndpoints[i] {
123
-			return false
124
-		}
125
-	}
126
-	for i := 0; i < len(a.ChildEndpoints); i++ {
127
-		if a.ChildEndpoints[i] != b.ChildEndpoints[i] {
128
-			return false
129
-		}
130
-	}
131
-	return true
132
-}
133
-
134
-func compareConnConfig(a, b *connectivityConfiguration) bool {
135
-	if a == b {
136
-		return true
137
-	}
138
-	if a == nil || b == nil {
139
-		return false
140
-	}
141
-	if len(a.ExposedPorts) != len(b.ExposedPorts) ||
142
-		len(a.PortBindings) != len(b.PortBindings) {
143
-		return false
144
-	}
145
-	for i := 0; i < len(a.ExposedPorts); i++ {
146
-		if !a.ExposedPorts[i].Equal(&b.ExposedPorts[i]) {
147
-			return false
148
-		}
149
-	}
150
-	for i := 0; i < len(a.PortBindings); i++ {
151
-		if !comparePortBinding(&a.PortBindings[i], &b.PortBindings[i]) {
152
-			return false
153
-		}
154
-	}
155
-	return true
156
-}
157
-
158
-// comparePortBinding returns whether the given PortBindings are equal.
159
-func comparePortBinding(p *types.PortBinding, o *types.PortBinding) bool {
160
-	if p == o {
161
-		return true
162
-	}
163
-
164
-	if o == nil {
165
-		return false
166
-	}
167
-
168
-	if p.Proto != o.Proto || p.Port != o.Port ||
169
-		p.HostPort != o.HostPort || p.HostPortEnd != o.HostPortEnd {
170
-		return false
171
-	}
172
-
173
-	if p.IP != nil {
174
-		if !p.IP.Equal(o.IP) {
175
-			return false
176
-		}
177
-	} else {
178
-		if o.IP != nil {
179
-			return false
180
-		}
181
-	}
182
-
183
-	if p.HostIP != nil {
184
-		if !p.HostIP.Equal(o.HostIP) {
185
-			return false
186
-		}
187
-	} else {
188
-		if o.HostIP != nil {
189
-			return false
190
-		}
191
-	}
192
-
193
-	return true
194
-}
195
-
196
-func compareBindings(a, b []types.PortBinding) bool {
197
-	if len(a) != len(b) {
198
-		return false
199
-	}
200
-	for i := 0; i < len(a); i++ {
201
-		if !comparePortBinding(&a[i], &b[i]) {
202
-			return false
203
-		}
204
-	}
205
-	return true
206
-}
207
-
208
-func getIPv4Data(t *testing.T, iface string) []driverapi.IPAMData {
209
-	ipd := driverapi.IPAMData{AddressSpace: "full"}
210
-	nw, err := netutils.FindAvailableNetwork(ipamutils.GetLocalScopeDefaultNetworks())
211
-	if err != nil {
212
-		t.Fatal(err)
213
-	}
214
-	ipd.Pool = nw
215
-	// Set network gateway to X.X.X.1
216
-	ipd.Gateway = types.GetIPNetCopy(nw)
217
-	ipd.Gateway.IP[len(ipd.Gateway.IP)-1] = 1
218
-	return []driverapi.IPAMData{ipd}
219
-}
220
-
221
-func TestCreateFullOptions(t *testing.T) {
222
-	defer netnsutils.SetupTestOSContext(t)()
223
-	d := newDriver()
224
-
225
-	config := &configuration{
226
-		EnableIPForwarding: true,
227
-		EnableIPTables:     true,
228
-	}
229
-
230
-	// Test this scenario: Default gw address does not belong to
231
-	// container network and it's greater than bridge address
232
-	cnw, _ := types.ParseCIDR("172.16.122.0/24")
233
-	bnw, _ := types.ParseCIDR("172.16.0.0/24")
234
-	br, _ := types.ParseCIDR("172.16.0.1/16")
235
-	defgw, _ := types.ParseCIDR("172.16.0.100/16")
236
-
237
-	genericOption := make(map[string]interface{})
238
-	genericOption[netlabel.GenericData] = config
239
-
240
-	if err := d.configure(genericOption); err != nil {
241
-		t.Fatalf("Failed to setup driver config: %v", err)
242
-	}
243
-
244
-	netOption := make(map[string]interface{})
245
-	netOption[netlabel.EnableIPv6] = true
246
-	netOption[netlabel.GenericData] = &networkConfiguration{
247
-		BridgeName: DefaultBridgeName,
248
-	}
249
-
250
-	ipdList := []driverapi.IPAMData{
251
-		{
252
-			Pool:         bnw,
253
-			Gateway:      br,
254
-			AuxAddresses: map[string]*net.IPNet{DefaultGatewayV4AuxKey: defgw},
255
-		},
256
-	}
257
-	err := d.CreateNetwork("dummy", netOption, nil, ipdList, nil)
258
-	if err != nil {
259
-		t.Fatalf("Failed to create bridge: %v", err)
260
-	}
261
-
262
-	// Verify the IP address allocated for the endpoint belongs to the container network
263
-	epOptions := make(map[string]interface{})
264
-	te := newTestEndpoint(cnw, 10)
265
-	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
266
-	if err != nil {
267
-		t.Fatalf("Failed to create an endpoint : %s", err.Error())
268
-	}
269
-
270
-	if !cnw.Contains(te.Interface().Address().IP) {
271
-		t.Fatalf("endpoint got assigned address outside of container network(%s): %s", cnw.String(), te.Interface().Address())
272
-	}
273
-}
274
-
275
-func TestCreateNoConfig(t *testing.T) {
276
-	defer netnsutils.SetupTestOSContext(t)()
277
-	d := newDriver()
278
-
279
-	netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
280
-	genericOption := make(map[string]interface{})
281
-	genericOption[netlabel.GenericData] = netconfig
282
-
283
-	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
284
-		t.Fatalf("Failed to create bridge: %v", err)
285
-	}
286
-}
287
-
288
-func TestCreateFullOptionsLabels(t *testing.T) {
289
-	defer netnsutils.SetupTestOSContext(t)()
290
-	d := newDriver()
291
-
292
-	config := &configuration{
293
-		EnableIPForwarding: true,
294
-	}
295
-	genericOption := make(map[string]interface{})
296
-	genericOption[netlabel.GenericData] = config
297
-
298
-	if err := d.configure(genericOption); err != nil {
299
-		t.Fatalf("Failed to setup driver config: %v", err)
300
-	}
301
-
302
-	bndIPs := "127.0.0.1"
303
-	testHostIP := "1.2.3.4"
304
-	nwV6s := "2001:db8:2600:2700:2800::/80"
305
-	gwV6s := "2001:db8:2600:2700:2800::25/80"
306
-	nwV6, _ := types.ParseCIDR(nwV6s)
307
-	gwV6, _ := types.ParseCIDR(gwV6s)
308
-
309
-	labels := map[string]string{
310
-		BridgeName:         DefaultBridgeName,
311
-		DefaultBridge:      "true",
312
-		EnableICC:          "true",
313
-		EnableIPMasquerade: "true",
314
-		DefaultBindingIP:   bndIPs,
315
-		netlabel.HostIP:    testHostIP,
316
-	}
317
-
318
-	netOption := make(map[string]interface{})
319
-	netOption[netlabel.EnableIPv6] = true
320
-	netOption[netlabel.GenericData] = labels
321
-
322
-	ipdList := getIPv4Data(t, "")
323
-	ipd6List := []driverapi.IPAMData{
324
-		{
325
-			Pool: nwV6,
326
-			AuxAddresses: map[string]*net.IPNet{
327
-				DefaultGatewayV6AuxKey: gwV6,
328
-			},
329
-		},
330
-	}
331
-
332
-	err := d.CreateNetwork("dummy", netOption, nil, ipdList, ipd6List)
333
-	if err != nil {
334
-		t.Fatalf("Failed to create bridge: %v", err)
335
-	}
336
-
337
-	nw, ok := d.networks["dummy"]
338
-	if !ok {
339
-		t.Fatal("Cannot find dummy network in bridge driver")
340
-	}
341
-
342
-	if nw.config.BridgeName != DefaultBridgeName {
343
-		t.Fatal("incongruent name in bridge network")
344
-	}
345
-
346
-	if !nw.config.EnableIPv6 {
347
-		t.Fatal("incongruent EnableIPv6 in bridge network")
348
-	}
349
-
350
-	if !nw.config.EnableICC {
351
-		t.Fatal("incongruent EnableICC in bridge network")
352
-	}
353
-
354
-	if !nw.config.EnableIPMasquerade {
355
-		t.Fatal("incongruent EnableIPMasquerade in bridge network")
356
-	}
357
-
358
-	bndIP := net.ParseIP(bndIPs)
359
-	if !bndIP.Equal(nw.config.DefaultBindingIP) {
360
-		t.Fatalf("Unexpected: %v", nw.config.DefaultBindingIP)
361
-	}
362
-
363
-	hostIP := net.ParseIP(testHostIP)
364
-	if !hostIP.Equal(nw.config.HostIP) {
365
-		t.Fatalf("Unexpected: %v", nw.config.HostIP)
366
-	}
367
-
368
-	if !types.CompareIPNet(nw.config.AddressIPv6, nwV6) {
369
-		t.Fatalf("Unexpected: %v", nw.config.AddressIPv6)
370
-	}
371
-
372
-	if !gwV6.IP.Equal(nw.config.DefaultGatewayIPv6) {
373
-		t.Fatalf("Unexpected: %v", nw.config.DefaultGatewayIPv6)
374
-	}
375
-
376
-	// In short here we are testing --fixed-cidr-v6 daemon option
377
-	// plus --mac-address run option
378
-	mac, _ := net.ParseMAC("aa:bb:cc:dd:ee:ff")
379
-	epOptions := map[string]interface{}{netlabel.MacAddress: mac}
380
-	te := newTestEndpoint(ipdList[0].Pool, 20)
381
-	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), epOptions)
382
-	if err != nil {
383
-		t.Fatal(err)
384
-	}
385
-
386
-	if !nwV6.Contains(te.Interface().AddressIPv6().IP) {
387
-		t.Fatalf("endpoint got assigned address outside of container network(%s): %s", nwV6.String(), te.Interface().AddressIPv6())
388
-	}
389
-	if te.Interface().AddressIPv6().IP.String() != "2001:db8:2600:2700:2800:aabb:ccdd:eeff" {
390
-		t.Fatalf("Unexpected endpoint IPv6 address: %v", te.Interface().AddressIPv6().IP)
391
-	}
392
-}
393
-
394
-func TestCreate(t *testing.T) {
395
-	defer netnsutils.SetupTestOSContext(t)()
396
-
397
-	d := newDriver()
398
-
399
-	if err := d.configure(nil); err != nil {
400
-		t.Fatalf("Failed to setup driver config: %v", err)
401
-	}
402
-
403
-	netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
404
-	genericOption := make(map[string]interface{})
405
-	genericOption[netlabel.GenericData] = netconfig
406
-
407
-	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
408
-		t.Fatalf("Failed to create bridge: %v", err)
409
-	}
410
-
411
-	err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil)
412
-	if err == nil {
413
-		t.Fatal("Expected bridge driver to refuse creation of second network with default name")
414
-	}
415
-	if _, ok := err.(types.ForbiddenError); !ok {
416
-		t.Fatal("Creation of second network with default name failed with unexpected error type")
417
-	}
418
-}
419
-
420
-func TestCreateFail(t *testing.T) {
421
-	defer netnsutils.SetupTestOSContext(t)()
422
-
423
-	d := newDriver()
424
-
425
-	if err := d.configure(nil); err != nil {
426
-		t.Fatalf("Failed to setup driver config: %v", err)
427
-	}
428
-
429
-	netconfig := &networkConfiguration{BridgeName: "dummy0", DefaultBridge: true}
430
-	genericOption := make(map[string]interface{})
431
-	genericOption[netlabel.GenericData] = netconfig
432
-
433
-	if err := d.CreateNetwork("dummy", genericOption, nil, getIPv4Data(t, ""), nil); err == nil {
434
-		t.Fatal("Bridge creation was expected to fail")
435
-	}
436
-}
437
-
438
-func TestCreateMultipleNetworks(t *testing.T) {
439
-	defer netnsutils.SetupTestOSContext(t)()
440
-
441
-	d := newDriver()
442
-
443
-	config := &configuration{
444
-		EnableIPTables: true,
445
-	}
446
-	genericOption := make(map[string]interface{})
447
-	genericOption[netlabel.GenericData] = config
448
-
449
-	if err := d.configure(genericOption); err != nil {
450
-		t.Fatalf("Failed to setup driver config: %v", err)
451
-	}
452
-
453
-	config1 := &networkConfiguration{BridgeName: "net_test_1"}
454
-	genericOption = make(map[string]interface{})
455
-	genericOption[netlabel.GenericData] = config1
456
-	if err := d.CreateNetwork("1", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
457
-		t.Fatalf("Failed to create bridge: %v", err)
458
-	}
459
-
460
-	verifyV4INCEntries(d.networks, t)
461
-
462
-	config2 := &networkConfiguration{BridgeName: "net_test_2"}
463
-	genericOption[netlabel.GenericData] = config2
464
-	if err := d.CreateNetwork("2", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
465
-		t.Fatalf("Failed to create bridge: %v", err)
466
-	}
467
-
468
-	verifyV4INCEntries(d.networks, t)
469
-
470
-	config3 := &networkConfiguration{BridgeName: "net_test_3"}
471
-	genericOption[netlabel.GenericData] = config3
472
-	if err := d.CreateNetwork("3", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
473
-		t.Fatalf("Failed to create bridge: %v", err)
474
-	}
475
-
476
-	verifyV4INCEntries(d.networks, t)
477
-
478
-	config4 := &networkConfiguration{BridgeName: "net_test_4"}
479
-	genericOption[netlabel.GenericData] = config4
480
-	if err := d.CreateNetwork("4", genericOption, nil, getIPv4Data(t, ""), nil); err != nil {
481
-		t.Fatalf("Failed to create bridge: %v", err)
482
-	}
483
-
484
-	verifyV4INCEntries(d.networks, t)
485
-
486
-	if err := d.DeleteNetwork("1"); err != nil {
487
-		t.Log(err)
488
-	}
489
-	verifyV4INCEntries(d.networks, t)
490
-
491
-	if err := d.DeleteNetwork("2"); err != nil {
492
-		t.Log(err)
493
-	}
494
-	verifyV4INCEntries(d.networks, t)
495
-
496
-	if err := d.DeleteNetwork("3"); err != nil {
497
-		t.Log(err)
498
-	}
499
-	verifyV4INCEntries(d.networks, t)
500
-
501
-	if err := d.DeleteNetwork("4"); err != nil {
502
-		t.Log(err)
503
-	}
504
-	verifyV4INCEntries(d.networks, t)
505
-}
506
-
507
-// Verify the network isolation rules are installed for each network
508
-func verifyV4INCEntries(networks map[string]*bridgeNetwork, t *testing.T) {
509
-	iptable := iptables.GetIptable(iptables.IPv4)
510
-	out1, err := iptable.Raw("-S", IsolationChain1)
511
-	if err != nil {
512
-		t.Fatal(err)
513
-	}
514
-	out2, err := iptable.Raw("-S", IsolationChain2)
515
-	if err != nil {
516
-		t.Fatal(err)
517
-	}
518
-
519
-	for _, n := range networks {
520
-		re := regexp.MustCompile(fmt.Sprintf("-i %s ! -o %s -j %s", n.config.BridgeName, n.config.BridgeName, IsolationChain2))
521
-		matches := re.FindAllString(string(out1[:]), -1)
522
-		if len(matches) != 1 {
523
-			t.Fatalf("Cannot find expected inter-network isolation rules in IP Tables for network %s:\n%s.", n.id, string(out1[:]))
524
-		}
525
-		re = regexp.MustCompile(fmt.Sprintf("-o %s -j DROP", n.config.BridgeName))
526
-		matches = re.FindAllString(string(out2[:]), -1)
527
-		if len(matches) != 1 {
528
-			t.Fatalf("Cannot find expected inter-network isolation rules in IP Tables for network %s:\n%s.", n.id, string(out2[:]))
529
-		}
530
-	}
531
-}
532
-
533
-type testInterface struct {
534
-	mac     net.HardwareAddr
535
-	addr    *net.IPNet
536
-	addrv6  *net.IPNet
537
-	srcName string
538
-	dstName string
539
-}
540
-
541
-type testEndpoint struct {
542
-	iface  *testInterface
543
-	gw     net.IP
544
-	gw6    net.IP
545
-	routes []types.StaticRoute
546
-}
547
-
548
-func newTestEndpoint(nw *net.IPNet, ordinal byte) *testEndpoint {
549
-	addr := types.GetIPNetCopy(nw)
550
-	addr.IP[len(addr.IP)-1] = ordinal
551
-	return &testEndpoint{iface: &testInterface{addr: addr}}
552
-}
553
-
554
-func (te *testEndpoint) Interface() driverapi.InterfaceInfo {
555
-	if te.iface != nil {
556
-		return te.iface
557
-	}
558
-
559
-	return nil
560
-}
561
-
562
-func (i *testInterface) MacAddress() net.HardwareAddr {
563
-	return i.mac
564
-}
565
-
566
-func (i *testInterface) Address() *net.IPNet {
567
-	return i.addr
568
-}
569
-
570
-func (i *testInterface) AddressIPv6() *net.IPNet {
571
-	return i.addrv6
572
-}
573
-
574
-func (i *testInterface) SetMacAddress(mac net.HardwareAddr) error {
575
-	if i.mac != nil {
576
-		return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", i.mac, mac)
577
-	}
578
-	if mac == nil {
579
-		return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
580
-	}
581
-	i.mac = types.GetMacCopy(mac)
582
-	return nil
583
-}
584
-
585
-func (i *testInterface) SetIPAddress(address *net.IPNet) error {
586
-	if address.IP == nil {
587
-		return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
588
-	}
589
-	if address.IP.To4() == nil {
590
-		return setAddress(&i.addrv6, address)
591
-	}
592
-	return setAddress(&i.addr, address)
593
-}
594
-
595
-func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
596
-	if *ifaceAddr != nil {
597
-		return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
598
-	}
599
-	*ifaceAddr = types.GetIPNetCopy(address)
600
-	return nil
601
-}
602
-
603
-func (i *testInterface) SetNames(srcName string, dstName string) error {
604
-	i.srcName = srcName
605
-	i.dstName = dstName
606
-	return nil
607
-}
608
-
609
-func (te *testEndpoint) InterfaceName() driverapi.InterfaceNameInfo {
610
-	if te.iface != nil {
611
-		return te.iface
612
-	}
613
-
614
-	return nil
615
-}
616
-
617
-func (te *testEndpoint) SetGateway(gw net.IP) error {
618
-	te.gw = gw
619
-	return nil
620
-}
621
-
622
-func (te *testEndpoint) SetGatewayIPv6(gw6 net.IP) error {
623
-	te.gw6 = gw6
624
-	return nil
625
-}
626
-
627
-func (te *testEndpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
628
-	te.routes = append(te.routes, types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop})
629
-	return nil
630
-}
631
-
632
-func (te *testEndpoint) AddTableEntry(tableName string, key string, value []byte) error {
633
-	return nil
634
-}
635
-
636
-func (te *testEndpoint) DisableGatewayService() {}
637
-
638
-func TestQueryEndpointInfo(t *testing.T) {
639
-	testQueryEndpointInfo(t, true)
640
-}
641
-
642
-func TestQueryEndpointInfoHairpin(t *testing.T) {
643
-	testQueryEndpointInfo(t, false)
644
-}
645
-
646
-func testQueryEndpointInfo(t *testing.T, ulPxyEnabled bool) {
647
-	defer netnsutils.SetupTestOSContext(t)()
648
-	d := newDriver()
649
-	d.portAllocator = portallocator.NewInstance()
650
-
651
-	config := &configuration{
652
-		EnableIPTables:      true,
653
-		EnableUserlandProxy: ulPxyEnabled,
654
-	}
655
-	genericOption := make(map[string]interface{})
656
-	genericOption[netlabel.GenericData] = config
657
-
658
-	if err := d.configure(genericOption); err != nil {
659
-		t.Fatalf("Failed to setup driver config: %v", err)
660
-	}
661
-
662
-	netconfig := &networkConfiguration{
663
-		BridgeName: DefaultBridgeName,
664
-		EnableICC:  false,
665
-	}
666
-	genericOption = make(map[string]interface{})
667
-	genericOption[netlabel.GenericData] = netconfig
668
-
669
-	ipdList := getIPv4Data(t, "")
670
-	err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
671
-	if err != nil {
672
-		t.Fatalf("Failed to create bridge: %v", err)
673
-	}
674
-
675
-	sbOptions := make(map[string]interface{})
676
-	sbOptions[netlabel.PortMap] = getPortMapping()
677
-
678
-	te := newTestEndpoint(ipdList[0].Pool, 11)
679
-	err = d.CreateEndpoint("net1", "ep1", te.Interface(), nil)
680
-	if err != nil {
681
-		t.Fatalf("Failed to create an endpoint : %s", err.Error())
682
-	}
683
-
684
-	err = d.Join("net1", "ep1", "sbox", te, sbOptions)
685
-	if err != nil {
686
-		t.Fatalf("Failed to join the endpoint: %v", err)
687
-	}
688
-
689
-	err = d.ProgramExternalConnectivity("net1", "ep1", sbOptions)
690
-	if err != nil {
691
-		t.Fatalf("Failed to program external connectivity: %v", err)
692
-	}
693
-
694
-	network, ok := d.networks["net1"]
695
-	if !ok {
696
-		t.Fatalf("Cannot find network %s inside driver", "net1")
697
-	}
698
-	ep := network.endpoints["ep1"]
699
-	data, err := d.EndpointOperInfo(network.id, ep.id)
700
-	if err != nil {
701
-		t.Fatalf("Failed to ask for endpoint operational data:  %v", err)
702
-	}
703
-	pmd, ok := data[netlabel.PortMap]
704
-	if !ok {
705
-		t.Fatal("Endpoint operational data does not contain port mapping data")
706
-	}
707
-	pm, ok := pmd.([]types.PortBinding)
708
-	if !ok {
709
-		t.Fatal("Unexpected format for port mapping in endpoint operational data")
710
-	}
711
-	if len(ep.portMapping) != len(pm) {
712
-		t.Fatal("Incomplete data for port mapping in endpoint operational data")
713
-	}
714
-	for i, pb := range ep.portMapping {
715
-		if !comparePortBinding(&pb, &pm[i]) {
716
-			t.Fatal("Unexpected data for port mapping in endpoint operational data")
717
-		}
718
-	}
719
-
720
-	err = d.RevokeExternalConnectivity("net1", "ep1")
721
-	if err != nil {
722
-		t.Fatal(err)
723
-	}
724
-
725
-	// release host mapped ports
726
-	err = d.Leave("net1", "ep1")
727
-	if err != nil {
728
-		t.Fatal(err)
729
-	}
730
-}
731
-
732
-func getExposedPorts() []types.TransportPort {
733
-	return []types.TransportPort{
734
-		{Proto: types.TCP, Port: uint16(5000)},
735
-		{Proto: types.UDP, Port: uint16(400)},
736
-		{Proto: types.TCP, Port: uint16(600)},
737
-	}
738
-}
739
-
740
-func getPortMapping() []types.PortBinding {
741
-	return []types.PortBinding{
742
-		{Proto: types.TCP, Port: uint16(230), HostPort: uint16(23000)},
743
-		{Proto: types.UDP, Port: uint16(200), HostPort: uint16(22000)},
744
-		{Proto: types.TCP, Port: uint16(120), HostPort: uint16(12000)},
745
-	}
746
-}
747
-
748
-func TestLinkContainers(t *testing.T) {
749
-	defer netnsutils.SetupTestOSContext(t)()
750
-
751
-	d := newDriver()
752
-	iptable := iptables.GetIptable(iptables.IPv4)
753
-
754
-	config := &configuration{
755
-		EnableIPTables: true,
756
-	}
757
-	genericOption := make(map[string]interface{})
758
-	genericOption[netlabel.GenericData] = config
759
-
760
-	if err := d.configure(genericOption); err != nil {
761
-		t.Fatalf("Failed to setup driver config: %v", err)
762
-	}
763
-
764
-	netconfig := &networkConfiguration{
765
-		BridgeName: DefaultBridgeName,
766
-		EnableICC:  false,
767
-	}
768
-	genericOption = make(map[string]interface{})
769
-	genericOption[netlabel.GenericData] = netconfig
770
-
771
-	ipdList := getIPv4Data(t, "")
772
-	err := d.CreateNetwork("net1", genericOption, nil, ipdList, nil)
773
-	if err != nil {
774
-		t.Fatalf("Failed to create bridge: %v", err)
775
-	}
776
-
777
-	te1 := newTestEndpoint(ipdList[0].Pool, 11)
778
-	err = d.CreateEndpoint("net1", "ep1", te1.Interface(), nil)
779
-	if err != nil {
780
-		t.Fatalf("Failed to create an endpoint : %s", err.Error())
781
-	}
782
-
783
-	exposedPorts := getExposedPorts()
784
-	sbOptions := make(map[string]interface{})
785
-	sbOptions[netlabel.ExposedPorts] = exposedPorts
786
-
787
-	err = d.Join("net1", "ep1", "sbox", te1, sbOptions)
788
-	if err != nil {
789
-		t.Fatalf("Failed to join the endpoint: %v", err)
790
-	}
791
-
792
-	err = d.ProgramExternalConnectivity("net1", "ep1", sbOptions)
793
-	if err != nil {
794
-		t.Fatalf("Failed to program external connectivity: %v", err)
795
-	}
796
-
797
-	addr1 := te1.iface.addr
798
-	if addr1.IP.To4() == nil {
799
-		t.Fatal("No Ipv4 address assigned to the endpoint:  ep1")
800
-	}
801
-
802
-	te2 := newTestEndpoint(ipdList[0].Pool, 22)
803
-	err = d.CreateEndpoint("net1", "ep2", te2.Interface(), nil)
804
-	if err != nil {
805
-		t.Fatalf("Failed to create an endpoint : %s", err.Error())
806
-	}
807
-
808
-	addr2 := te2.iface.addr
809
-	if addr2.IP.To4() == nil {
810
-		t.Fatal("No Ipv4 address assigned to the endpoint:  ep2")
811
-	}
812
-
813
-	sbOptions = make(map[string]interface{})
814
-	sbOptions[netlabel.GenericData] = options.Generic{
815
-		"ChildEndpoints": []string{"ep1"},
816
-	}
817
-
818
-	err = d.Join("net1", "ep2", "", te2, sbOptions)
819
-	if err != nil {
820
-		t.Fatal("Failed to link ep1 and ep2")
821
-	}
822
-
823
-	err = d.ProgramExternalConnectivity("net1", "ep2", sbOptions)
824
-	if err != nil {
825
-		t.Fatalf("Failed to program external connectivity: %v", err)
826
-	}
827
-
828
-	out, _ := iptable.Raw("-L", DockerChain)
829
-	for _, pm := range exposedPorts {
830
-		regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
831
-		re := regexp.MustCompile(regex)
832
-		matches := re.FindAllString(string(out[:]), -1)
833
-		if len(matches) != 1 {
834
-			t.Fatalf("IP Tables programming failed %s", string(out[:]))
835
-		}
836
-
837
-		regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
838
-		matched, _ := regexp.MatchString(regex, string(out[:]))
839
-		if !matched {
840
-			t.Fatalf("IP Tables programming failed %s", string(out[:]))
841
-		}
842
-	}
843
-
844
-	err = d.RevokeExternalConnectivity("net1", "ep2")
845
-	if err != nil {
846
-		t.Fatalf("Failed to revoke external connectivity: %v", err)
847
-	}
848
-
849
-	err = d.Leave("net1", "ep2")
850
-	if err != nil {
851
-		t.Fatal("Failed to unlink ep1 and ep2")
852
-	}
853
-
854
-	out, _ = iptable.Raw("-L", DockerChain)
855
-	for _, pm := range exposedPorts {
856
-		regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
857
-		re := regexp.MustCompile(regex)
858
-		matches := re.FindAllString(string(out[:]), -1)
859
-		if len(matches) != 0 {
860
-			t.Fatalf("Leave should have deleted relevant IPTables rules  %s", string(out[:]))
861
-		}
862
-
863
-		regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
864
-		matched, _ := regexp.MatchString(regex, string(out[:]))
865
-		if matched {
866
-			t.Fatalf("Leave should have deleted relevant IPTables rules  %s", string(out[:]))
867
-		}
868
-	}
869
-
870
-	// Error condition test with an invalid endpoint-id "ep4"
871
-	sbOptions = make(map[string]interface{})
872
-	sbOptions[netlabel.GenericData] = options.Generic{
873
-		"ChildEndpoints": []string{"ep1", "ep4"},
874
-	}
875
-
876
-	err = d.Join("net1", "ep2", "", te2, sbOptions)
877
-	if err != nil {
878
-		t.Fatal(err)
879
-	}
880
-	err = d.ProgramExternalConnectivity("net1", "ep2", sbOptions)
881
-	if err != nil {
882
-		out, _ = iptable.Raw("-L", DockerChain)
883
-		for _, pm := range exposedPorts {
884
-			regex := fmt.Sprintf("%s dpt:%d", pm.Proto.String(), pm.Port)
885
-			re := regexp.MustCompile(regex)
886
-			matches := re.FindAllString(string(out[:]), -1)
887
-			if len(matches) != 0 {
888
-				t.Fatalf("Error handling should rollback relevant IPTables rules  %s", string(out[:]))
889
-			}
890
-
891
-			regex = fmt.Sprintf("%s spt:%d", pm.Proto.String(), pm.Port)
892
-			matched, _ := regexp.MatchString(regex, string(out[:]))
893
-			if matched {
894
-				t.Fatalf("Error handling should rollback relevant IPTables rules  %s", string(out[:]))
895
-			}
896
-		}
897
-	} else {
898
-		t.Fatal("Expected Join to fail given link conditions are not satisfied")
899
-	}
900
-}
901
-
902
-func TestValidateConfig(t *testing.T) {
903
-	defer netnsutils.SetupTestOSContext(t)()
904
-
905
-	// Test mtu
906
-	c := networkConfiguration{Mtu: -2}
907
-	err := c.Validate()
908
-	if err == nil {
909
-		t.Fatal("Failed to detect invalid MTU number")
910
-	}
911
-
912
-	c.Mtu = 9000
913
-	err = c.Validate()
914
-	if err != nil {
915
-		t.Fatal("unexpected validation error on MTU number")
916
-	}
917
-
918
-	// Bridge network
919
-	_, network, _ := net.ParseCIDR("172.28.0.0/16")
920
-	c = networkConfiguration{
921
-		AddressIPv4: network,
922
-	}
923
-
924
-	err = c.Validate()
925
-	if err != nil {
926
-		t.Fatal(err)
927
-	}
928
-
929
-	// Test v4 gw
930
-	c.DefaultGatewayIPv4 = net.ParseIP("172.27.30.234")
931
-	err = c.Validate()
932
-	if err == nil {
933
-		t.Fatal("Failed to detect invalid default gateway")
934
-	}
935
-
936
-	c.DefaultGatewayIPv4 = net.ParseIP("172.28.30.234")
937
-	err = c.Validate()
938
-	if err != nil {
939
-		t.Fatal("Unexpected validation error on default gateway")
940
-	}
941
-
942
-	// Test v6 gw
943
-	_, v6nw, _ := net.ParseCIDR("2001:db8:ae:b004::/64")
944
-	c = networkConfiguration{
945
-		EnableIPv6:         true,
946
-		AddressIPv6:        v6nw,
947
-		DefaultGatewayIPv6: net.ParseIP("2001:db8:ac:b004::bad:a55"),
948
-	}
949
-	err = c.Validate()
950
-	if err == nil {
951
-		t.Fatal("Failed to detect invalid v6 default gateway")
952
-	}
953
-
954
-	c.DefaultGatewayIPv6 = net.ParseIP("2001:db8:ae:b004::bad:a55")
955
-	err = c.Validate()
956
-	if err != nil {
957
-		t.Fatal("Unexpected validation error on v6 default gateway")
958
-	}
959
-
960
-	c.AddressIPv6 = nil
961
-	err = c.Validate()
962
-	if err == nil {
963
-		t.Fatal("Failed to detect invalid v6 default gateway")
964
-	}
965
-
966
-	c.AddressIPv6 = nil
967
-	err = c.Validate()
968
-	if err == nil {
969
-		t.Fatal("Failed to detect invalid v6 default gateway")
970
-	}
971
-}
972
-
973
-func TestSetDefaultGw(t *testing.T) {
974
-	defer netnsutils.SetupTestOSContext(t)()
975
-
976
-	d := newDriver()
977
-
978
-	if err := d.configure(nil); err != nil {
979
-		t.Fatalf("Failed to setup driver config: %v", err)
980
-	}
981
-
982
-	_, subnetv6, _ := net.ParseCIDR("2001:db8:ea9:9abc:b0c4::/80")
983
-
984
-	ipdList := getIPv4Data(t, "")
985
-	gw4 := types.GetIPCopy(ipdList[0].Pool.IP).To4()
986
-	gw4[3] = 254
987
-	gw6 := net.ParseIP("2001:db8:ea9:9abc:b0c4::254")
988
-
989
-	config := &networkConfiguration{
990
-		BridgeName:         DefaultBridgeName,
991
-		AddressIPv6:        subnetv6,
992
-		DefaultGatewayIPv4: gw4,
993
-		DefaultGatewayIPv6: gw6,
994
-	}
995
-
996
-	genericOption := make(map[string]interface{})
997
-	genericOption[netlabel.EnableIPv6] = true
998
-	genericOption[netlabel.GenericData] = config
999
-
1000
-	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
1001
-	if err != nil {
1002
-		t.Fatalf("Failed to create bridge: %v", err)
1003
-	}
1004
-
1005
-	te := newTestEndpoint(ipdList[0].Pool, 10)
1006
-	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
1007
-	if err != nil {
1008
-		t.Fatalf("Failed to create endpoint: %v", err)
1009
-	}
1010
-
1011
-	err = d.Join("dummy", "ep", "sbox", te, nil)
1012
-	if err != nil {
1013
-		t.Fatalf("Failed to join endpoint: %v", err)
1014
-	}
1015
-
1016
-	if !gw4.Equal(te.gw) {
1017
-		t.Fatalf("Failed to configure default gateway. Expected %v. Found %v", gw4, te.gw)
1018
-	}
1019
-
1020
-	if !gw6.Equal(te.gw6) {
1021
-		t.Fatalf("Failed to configure default gateway. Expected %v. Found %v", gw6, te.gw6)
1022
-	}
1023
-}
1024
-
1025
-func TestCleanupIptableRules(t *testing.T) {
1026
-	defer netnsutils.SetupTestOSContext(t)()
1027
-	bridgeChain := []iptables.ChainInfo{
1028
-		{Name: DockerChain, Table: iptables.Nat},
1029
-		{Name: DockerChain, Table: iptables.Filter},
1030
-		{Name: IsolationChain1, Table: iptables.Filter},
1031
-	}
1032
-
1033
-	ipVersions := []iptables.IPVersion{iptables.IPv4, iptables.IPv6}
1034
-
1035
-	for _, version := range ipVersions {
1036
-		if _, _, _, _, err := setupIPChains(configuration{EnableIPTables: true}, version); err != nil {
1037
-			t.Fatalf("Error setting up ip chains for %s: %v", version, err)
1038
-		}
1039
-
1040
-		iptable := iptables.GetIptable(version)
1041
-		for _, chainInfo := range bridgeChain {
1042
-			if !iptable.ExistChain(chainInfo.Name, chainInfo.Table) {
1043
-				t.Fatalf("iptables version %s chain %s of %s table should have been created", version, chainInfo.Name, chainInfo.Table)
1044
-			}
1045
-		}
1046
-		removeIPChains(version)
1047
-		for _, chainInfo := range bridgeChain {
1048
-			if iptable.ExistChain(chainInfo.Name, chainInfo.Table) {
1049
-				t.Fatalf("iptables version %s chain %s of %s table should have been deleted", version, chainInfo.Name, chainInfo.Table)
1050
-			}
1051
-		}
1052
-	}
1053
-}
1054
-
1055
-func TestCreateWithExistingBridge(t *testing.T) {
1056
-	defer netnsutils.SetupTestOSContext(t)()
1057
-	d := newDriver()
1058
-
1059
-	if err := d.configure(nil); err != nil {
1060
-		t.Fatalf("Failed to setup driver config: %v", err)
1061
-	}
1062
-
1063
-	brName := "br111"
1064
-	br := &netlink.Bridge{
1065
-		LinkAttrs: netlink.LinkAttrs{
1066
-			Name: brName,
1067
-		},
1068
-	}
1069
-	if err := netlink.LinkAdd(br); err != nil {
1070
-		t.Fatalf("Failed to create bridge interface: %v", err)
1071
-	}
1072
-	defer netlink.LinkDel(br)
1073
-	if err := netlink.LinkSetUp(br); err != nil {
1074
-		t.Fatalf("Failed to set bridge interface up: %v", err)
1075
-	}
1076
-
1077
-	ip := net.IP{192, 168, 122, 1}
1078
-	addr := &netlink.Addr{IPNet: &net.IPNet{
1079
-		IP:   ip,
1080
-		Mask: net.IPv4Mask(255, 255, 255, 0),
1081
-	}}
1082
-	if err := netlink.AddrAdd(br, addr); err != nil {
1083
-		t.Fatalf("Failed to add IP address to bridge: %v", err)
1084
-	}
1085
-
1086
-	netconfig := &networkConfiguration{BridgeName: brName}
1087
-	genericOption := make(map[string]interface{})
1088
-	genericOption[netlabel.GenericData] = netconfig
1089
-
1090
-	ipv4Data := []driverapi.IPAMData{{
1091
-		AddressSpace: "full",
1092
-		Pool:         types.GetIPNetCopy(addr.IPNet),
1093
-		Gateway:      types.GetIPNetCopy(addr.IPNet),
1094
-	}}
1095
-	// Set network gateway to X.X.X.1
1096
-	ipv4Data[0].Gateway.IP[len(ipv4Data[0].Gateway.IP)-1] = 1
1097
-
1098
-	if err := d.CreateNetwork(brName, genericOption, nil, ipv4Data, nil); err != nil {
1099
-		t.Fatalf("Failed to create bridge network: %v", err)
1100
-	}
1101
-
1102
-	nw, err := d.getNetwork(brName)
1103
-	if err != nil {
1104
-		t.Fatalf("Failed to getNetwork(%s): %v", brName, err)
1105
-	}
1106
-
1107
-	addrs4, _, err := nw.bridge.addresses()
1108
-	if err != nil {
1109
-		t.Fatalf("Failed to get the bridge network's address: %v", err)
1110
-	}
1111
-
1112
-	if !addrs4[0].IP.Equal(ip) {
1113
-		t.Fatal("Creating bridge network with existing bridge interface unexpectedly modified the IP address of the bridge")
1114
-	}
1115
-
1116
-	if err := d.DeleteNetwork(brName); err != nil {
1117
-		t.Fatalf("Failed to delete network %s: %v", brName, err)
1118
-	}
1119
-
1120
-	if _, err := netlink.LinkByName(brName); err != nil {
1121
-		t.Fatal("Deleting bridge network that using existing bridge interface unexpectedly deleted the bridge interface")
1122
-	}
1123
-}
1124
-
1125
-func TestCreateParallel(t *testing.T) {
1126
-	c := netnsutils.SetupTestOSContextEx(t)
1127
-	defer c.Cleanup(t)
1128
-
1129
-	d := newDriver()
1130
-	d.portAllocator = portallocator.NewInstance()
1131
-
1132
-	if err := d.configure(nil); err != nil {
1133
-		t.Fatalf("Failed to setup driver config: %v", err)
1134
-	}
1135
-
1136
-	ipV4Data := getIPv4Data(t, "docker0")
1137
-
1138
-	ch := make(chan error, 100)
1139
-	for i := 0; i < 100; i++ {
1140
-		name := "net" + strconv.Itoa(i)
1141
-		c.Go(t, func() {
1142
-			config := &networkConfiguration{BridgeName: name}
1143
-			genericOption := make(map[string]interface{})
1144
-			genericOption[netlabel.GenericData] = config
1145
-			if err := d.CreateNetwork(name, genericOption, nil, ipV4Data, nil); err != nil {
1146
-				ch <- fmt.Errorf("failed to create %s", name)
1147
-				return
1148
-			}
1149
-			if err := d.CreateNetwork(name, genericOption, nil, ipV4Data, nil); err == nil {
1150
-				ch <- fmt.Errorf("failed was able to create overlap %s", name)
1151
-				return
1152
-			}
1153
-			ch <- nil
1154
-		})
1155
-	}
1156
-	// wait for the go routines
1157
-	var success int
1158
-	for i := 0; i < 100; i++ {
1159
-		val := <-ch
1160
-		if val == nil {
1161
-			success++
1162
-		}
1163
-	}
1164
-	if success != 1 {
1165
-		t.Fatalf("Success should be 1 instead: %d", success)
1166
-	}
1167
-}
1168 1
deleted file mode 100644
... ...
@@ -1,93 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"context"
7
-	"fmt"
8
-	"net"
9
-
10
-	"github.com/containerd/containerd/log"
11
-	"github.com/vishvananda/netlink"
12
-)
13
-
14
-const (
15
-	// DefaultBridgeName is the default name for the bridge interface managed
16
-	// by the driver when unspecified by the caller.
17
-	DefaultBridgeName = "docker0"
18
-)
19
-
20
-// Interface models the bridge network device.
21
-type bridgeInterface struct {
22
-	Link        netlink.Link
23
-	bridgeIPv4  *net.IPNet
24
-	bridgeIPv6  *net.IPNet
25
-	gatewayIPv4 net.IP
26
-	gatewayIPv6 net.IP
27
-	nlh         *netlink.Handle
28
-}
29
-
30
-// newInterface creates a new bridge interface structure. It attempts to find
31
-// an already existing device identified by the configuration BridgeName field,
32
-// or the default bridge name when unspecified, but doesn't attempt to create
33
-// one when missing
34
-func newInterface(nlh *netlink.Handle, config *networkConfiguration) (*bridgeInterface, error) {
35
-	var err error
36
-	i := &bridgeInterface{nlh: nlh}
37
-
38
-	// Initialize the bridge name to the default if unspecified.
39
-	if config.BridgeName == "" {
40
-		config.BridgeName = DefaultBridgeName
41
-	}
42
-
43
-	// Attempt to find an existing bridge named with the specified name.
44
-	i.Link, err = nlh.LinkByName(config.BridgeName)
45
-	if err != nil {
46
-		log.G(context.TODO()).Debugf("Did not find any interface with name %s: %v", config.BridgeName, err)
47
-	} else if _, ok := i.Link.(*netlink.Bridge); !ok {
48
-		return nil, fmt.Errorf("existing interface %s is not a bridge", i.Link.Attrs().Name)
49
-	}
50
-	return i, nil
51
-}
52
-
53
-// exists indicates if the existing bridge interface exists on the system.
54
-func (i *bridgeInterface) exists() bool {
55
-	return i.Link != nil
56
-}
57
-
58
-// addresses returns all IPv4 addresses and all IPv6 addresses for the bridge interface.
59
-func (i *bridgeInterface) addresses() ([]netlink.Addr, []netlink.Addr, error) {
60
-	if !i.exists() {
61
-		// A nonexistent interface, by definition, cannot have any addresses.
62
-		return nil, nil, nil
63
-	}
64
-	v4addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V4)
65
-	if err != nil {
66
-		return nil, nil, fmt.Errorf("Failed to retrieve V4 addresses: %v", err)
67
-	}
68
-
69
-	v6addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V6)
70
-	if err != nil {
71
-		return nil, nil, fmt.Errorf("Failed to retrieve V6 addresses: %v", err)
72
-	}
73
-
74
-	if len(v4addr) == 0 {
75
-		return nil, v6addr, nil
76
-	}
77
-	return v4addr, v6addr, nil
78
-}
79
-
80
-func (i *bridgeInterface) programIPv6Address() error {
81
-	_, nlAddressList, err := i.addresses()
82
-	if err != nil {
83
-		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: fmt.Errorf("failed to retrieve address list: %v", err)}
84
-	}
85
-	nlAddr := netlink.Addr{IPNet: i.bridgeIPv6}
86
-	if findIPv6Address(nlAddr, nlAddressList) {
87
-		return nil
88
-	}
89
-	if err := i.nlh.AddrAdd(i.Link, &nlAddr); err != nil {
90
-		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
91
-	}
92
-	return nil
93
-}
94 1
new file mode 100644
... ...
@@ -0,0 +1,91 @@
0
+package bridge
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+	"net"
6
+
7
+	"github.com/containerd/containerd/log"
8
+	"github.com/vishvananda/netlink"
9
+)
10
+
11
+const (
12
+	// DefaultBridgeName is the default name for the bridge interface managed
13
+	// by the driver when unspecified by the caller.
14
+	DefaultBridgeName = "docker0"
15
+)
16
+
17
+// Interface models the bridge network device.
18
+type bridgeInterface struct {
19
+	Link        netlink.Link
20
+	bridgeIPv4  *net.IPNet
21
+	bridgeIPv6  *net.IPNet
22
+	gatewayIPv4 net.IP
23
+	gatewayIPv6 net.IP
24
+	nlh         *netlink.Handle
25
+}
26
+
27
+// newInterface creates a new bridge interface structure. It attempts to find
28
+// an already existing device identified by the configuration BridgeName field,
29
+// or the default bridge name when unspecified, but doesn't attempt to create
30
+// one when missing
31
+func newInterface(nlh *netlink.Handle, config *networkConfiguration) (*bridgeInterface, error) {
32
+	var err error
33
+	i := &bridgeInterface{nlh: nlh}
34
+
35
+	// Initialize the bridge name to the default if unspecified.
36
+	if config.BridgeName == "" {
37
+		config.BridgeName = DefaultBridgeName
38
+	}
39
+
40
+	// Attempt to find an existing bridge named with the specified name.
41
+	i.Link, err = nlh.LinkByName(config.BridgeName)
42
+	if err != nil {
43
+		log.G(context.TODO()).Debugf("Did not find any interface with name %s: %v", config.BridgeName, err)
44
+	} else if _, ok := i.Link.(*netlink.Bridge); !ok {
45
+		return nil, fmt.Errorf("existing interface %s is not a bridge", i.Link.Attrs().Name)
46
+	}
47
+	return i, nil
48
+}
49
+
50
+// exists indicates if the existing bridge interface exists on the system.
51
+func (i *bridgeInterface) exists() bool {
52
+	return i.Link != nil
53
+}
54
+
55
+// addresses returns all IPv4 addresses and all IPv6 addresses for the bridge interface.
56
+func (i *bridgeInterface) addresses() ([]netlink.Addr, []netlink.Addr, error) {
57
+	if !i.exists() {
58
+		// A nonexistent interface, by definition, cannot have any addresses.
59
+		return nil, nil, nil
60
+	}
61
+	v4addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V4)
62
+	if err != nil {
63
+		return nil, nil, fmt.Errorf("Failed to retrieve V4 addresses: %v", err)
64
+	}
65
+
66
+	v6addr, err := i.nlh.AddrList(i.Link, netlink.FAMILY_V6)
67
+	if err != nil {
68
+		return nil, nil, fmt.Errorf("Failed to retrieve V6 addresses: %v", err)
69
+	}
70
+
71
+	if len(v4addr) == 0 {
72
+		return nil, v6addr, nil
73
+	}
74
+	return v4addr, v6addr, nil
75
+}
76
+
77
+func (i *bridgeInterface) programIPv6Address() error {
78
+	_, nlAddressList, err := i.addresses()
79
+	if err != nil {
80
+		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: fmt.Errorf("failed to retrieve address list: %v", err)}
81
+	}
82
+	nlAddr := netlink.Addr{IPNet: i.bridgeIPv6}
83
+	if findIPv6Address(nlAddr, nlAddressList) {
84
+		return nil
85
+	}
86
+	if err := i.nlh.AddrAdd(i.Link, &nlAddr); err != nil {
87
+		return &IPv6AddrAddError{IP: i.bridgeIPv6, Err: err}
88
+	}
89
+	return nil
90
+}
0 91
new file mode 100644
... ...
@@ -0,0 +1,50 @@
0
+package bridge
1
+
2
+import (
3
+	"testing"
4
+
5
+	"github.com/docker/docker/internal/testutils/netnsutils"
6
+	"github.com/vishvananda/netlink"
7
+)
8
+
9
+func TestInterfaceDefaultName(t *testing.T) {
10
+	defer netnsutils.SetupTestOSContext(t)()
11
+
12
+	nh, err := netlink.NewHandle()
13
+	if err != nil {
14
+		t.Fatal(err)
15
+	}
16
+	config := &networkConfiguration{}
17
+	_, err = newInterface(nh, config)
18
+	if err != nil {
19
+		t.Fatalf("newInterface() failed: %v", err)
20
+	}
21
+
22
+	if config.BridgeName != DefaultBridgeName {
23
+		t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName)
24
+	}
25
+}
26
+
27
+func TestAddressesEmptyInterface(t *testing.T) {
28
+	defer netnsutils.SetupTestOSContext(t)()
29
+
30
+	nh, err := netlink.NewHandle()
31
+	if err != nil {
32
+		t.Fatal(err)
33
+	}
34
+	inf, err := newInterface(nh, &networkConfiguration{})
35
+	if err != nil {
36
+		t.Fatalf("newInterface() failed: %v", err)
37
+	}
38
+
39
+	addrsv4, addrsv6, err := inf.addresses()
40
+	if err != nil {
41
+		t.Fatalf("Failed to get addresses of default interface: %v", err)
42
+	}
43
+	if len(addrsv4) != 0 {
44
+		t.Fatalf("Default interface has unexpected IPv4: %s", addrsv4)
45
+	}
46
+	if len(addrsv6) != 0 {
47
+		t.Fatalf("Default interface has unexpected IPv6: %v", addrsv6)
48
+	}
49
+}
0 50
deleted file mode 100644
... ...
@@ -1,52 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"testing"
7
-
8
-	"github.com/docker/docker/internal/testutils/netnsutils"
9
-	"github.com/vishvananda/netlink"
10
-)
11
-
12
-func TestInterfaceDefaultName(t *testing.T) {
13
-	defer netnsutils.SetupTestOSContext(t)()
14
-
15
-	nh, err := netlink.NewHandle()
16
-	if err != nil {
17
-		t.Fatal(err)
18
-	}
19
-	config := &networkConfiguration{}
20
-	_, err = newInterface(nh, config)
21
-	if err != nil {
22
-		t.Fatalf("newInterface() failed: %v", err)
23
-	}
24
-
25
-	if config.BridgeName != DefaultBridgeName {
26
-		t.Fatalf("Expected default interface name %q, got %q", DefaultBridgeName, config.BridgeName)
27
-	}
28
-}
29
-
30
-func TestAddressesEmptyInterface(t *testing.T) {
31
-	defer netnsutils.SetupTestOSContext(t)()
32
-
33
-	nh, err := netlink.NewHandle()
34
-	if err != nil {
35
-		t.Fatal(err)
36
-	}
37
-	inf, err := newInterface(nh, &networkConfiguration{})
38
-	if err != nil {
39
-		t.Fatalf("newInterface() failed: %v", err)
40
-	}
41
-
42
-	addrsv4, addrsv6, err := inf.addresses()
43
-	if err != nil {
44
-		t.Fatalf("Failed to get addresses of default interface: %v", err)
45
-	}
46
-	if len(addrsv4) != 0 {
47
-		t.Fatalf("Default interface has unexpected IPv4: %s", addrsv4)
48
-	}
49
-	if len(addrsv6) != 0 {
50
-		t.Fatalf("Default interface has unexpected IPv6: %v", addrsv6)
51
-	}
52
-}
53 1
new file mode 100644
... ...
@@ -0,0 +1,220 @@
0
+package bridge
1
+
2
+import (
3
+	"testing"
4
+
5
+	"github.com/docker/docker/internal/testutils/netnsutils"
6
+	"github.com/docker/docker/libnetwork/driverapi"
7
+	"github.com/docker/docker/libnetwork/netlabel"
8
+	"github.com/vishvananda/netlink"
9
+)
10
+
11
+func TestLinkCreate(t *testing.T) {
12
+	defer netnsutils.SetupTestOSContext(t)()
13
+	d := newDriver()
14
+
15
+	if err := d.configure(nil); err != nil {
16
+		t.Fatalf("Failed to setup driver config: %v", err)
17
+	}
18
+
19
+	mtu := 1490
20
+	config := &networkConfiguration{
21
+		BridgeName: DefaultBridgeName,
22
+		Mtu:        mtu,
23
+		EnableIPv6: true,
24
+	}
25
+	genericOption := make(map[string]interface{})
26
+	genericOption[netlabel.GenericData] = config
27
+
28
+	ipdList := getIPv4Data(t, "")
29
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
30
+	if err != nil {
31
+		t.Fatalf("Failed to create bridge: %v", err)
32
+	}
33
+
34
+	te := newTestEndpoint(ipdList[0].Pool, 10)
35
+	err = d.CreateEndpoint("dummy", "", te.Interface(), nil)
36
+	if err != nil {
37
+		if _, ok := err.(InvalidEndpointIDError); !ok {
38
+			t.Fatalf("Failed with a wrong error :%s", err.Error())
39
+		}
40
+	} else {
41
+		t.Fatal("Failed to detect invalid config")
42
+	}
43
+
44
+	// Good endpoint creation
45
+	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
46
+	if err != nil {
47
+		t.Fatalf("Failed to create a link: %s", err.Error())
48
+	}
49
+
50
+	err = d.Join("dummy", "ep", "sbox", te, nil)
51
+	if err != nil {
52
+		t.Fatalf("Failed to create a link: %s", err.Error())
53
+	}
54
+
55
+	// Verify sbox endpoint interface inherited MTU value from bridge config
56
+	sboxLnk, err := netlink.LinkByName(te.iface.srcName)
57
+	if err != nil {
58
+		t.Fatal(err)
59
+	}
60
+	if mtu != sboxLnk.Attrs().MTU {
61
+		t.Fatal("Sandbox endpoint interface did not inherit bridge interface MTU config")
62
+	}
63
+	// TODO: if we could get peer name from (sboxLnk.(*netlink.Veth)).PeerName
64
+	// then we could check the MTU on hostLnk as well.
65
+
66
+	te1 := newTestEndpoint(ipdList[0].Pool, 11)
67
+	err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
68
+	if err == nil {
69
+		t.Fatal("Failed to detect duplicate endpoint id on same network")
70
+	}
71
+
72
+	if te.iface.dstName == "" {
73
+		t.Fatal("Invalid Dstname returned")
74
+	}
75
+
76
+	_, err = netlink.LinkByName(te.iface.srcName)
77
+	if err != nil {
78
+		t.Fatalf("Could not find source link %s: %v", te.iface.srcName, err)
79
+	}
80
+
81
+	n, ok := d.networks["dummy"]
82
+	if !ok {
83
+		t.Fatalf("Cannot find network %s inside driver", "dummy")
84
+	}
85
+	ip := te.iface.addr.IP
86
+	if !n.bridge.bridgeIPv4.Contains(ip) {
87
+		t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), n.bridge.bridgeIPv4.String())
88
+	}
89
+
90
+	ip6 := te.iface.addrv6.IP
91
+	if !n.bridge.bridgeIPv6.Contains(ip6) {
92
+		t.Fatalf("IP %s is not a valid ip in the subnet %s", ip6.String(), bridgeIPv6.String())
93
+	}
94
+
95
+	if !te.gw.Equal(n.bridge.bridgeIPv4.IP) {
96
+		t.Fatalf("Invalid default gateway. Expected %s. Got %s", n.bridge.bridgeIPv4.IP.String(),
97
+			te.gw.String())
98
+	}
99
+
100
+	if !te.gw6.Equal(n.bridge.bridgeIPv6.IP) {
101
+		t.Fatalf("Invalid default gateway for IPv6. Expected %s. Got %s", n.bridge.bridgeIPv6.IP.String(),
102
+			te.gw6.String())
103
+	}
104
+}
105
+
106
+func TestLinkCreateTwo(t *testing.T) {
107
+	defer netnsutils.SetupTestOSContext(t)()
108
+	d := newDriver()
109
+
110
+	if err := d.configure(nil); err != nil {
111
+		t.Fatalf("Failed to setup driver config: %v", err)
112
+	}
113
+
114
+	config := &networkConfiguration{
115
+		BridgeName: DefaultBridgeName,
116
+		EnableIPv6: true,
117
+	}
118
+	genericOption := make(map[string]interface{})
119
+	genericOption[netlabel.GenericData] = config
120
+
121
+	ipdList := getIPv4Data(t, "")
122
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
123
+	if err != nil {
124
+		t.Fatalf("Failed to create bridge: %v", err)
125
+	}
126
+
127
+	te1 := newTestEndpoint(ipdList[0].Pool, 11)
128
+	err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
129
+	if err != nil {
130
+		t.Fatalf("Failed to create a link: %s", err.Error())
131
+	}
132
+
133
+	te2 := newTestEndpoint(ipdList[0].Pool, 12)
134
+	err = d.CreateEndpoint("dummy", "ep", te2.Interface(), nil)
135
+	if err != nil {
136
+		if _, ok := err.(driverapi.ErrEndpointExists); !ok {
137
+			t.Fatalf("Failed with a wrong error: %s", err.Error())
138
+		}
139
+	} else {
140
+		t.Fatal("Expected to fail while trying to add same endpoint twice")
141
+	}
142
+}
143
+
144
+func TestLinkCreateNoEnableIPv6(t *testing.T) {
145
+	defer netnsutils.SetupTestOSContext(t)()
146
+	d := newDriver()
147
+
148
+	if err := d.configure(nil); err != nil {
149
+		t.Fatalf("Failed to setup driver config: %v", err)
150
+	}
151
+
152
+	config := &networkConfiguration{
153
+		BridgeName: DefaultBridgeName,
154
+	}
155
+	genericOption := make(map[string]interface{})
156
+	genericOption[netlabel.GenericData] = config
157
+
158
+	ipdList := getIPv4Data(t, "")
159
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
160
+	if err != nil {
161
+		t.Fatalf("Failed to create bridge: %v", err)
162
+	}
163
+	te := newTestEndpoint(ipdList[0].Pool, 30)
164
+	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
165
+	if err != nil {
166
+		t.Fatalf("Failed to create a link: %s", err.Error())
167
+	}
168
+
169
+	iface := te.iface
170
+	if iface.addrv6 != nil && iface.addrv6.IP.To16() != nil {
171
+		t.Fatalf("Expected IPv6 address to be nil when IPv6 is not enabled. Got IPv6 = %s", iface.addrv6.String())
172
+	}
173
+
174
+	if te.gw6.To16() != nil {
175
+		t.Fatalf("Expected GatewayIPv6 to be nil when IPv6 is not enabled. Got GatewayIPv6 = %s", te.gw6.String())
176
+	}
177
+}
178
+
179
+func TestLinkDelete(t *testing.T) {
180
+	defer netnsutils.SetupTestOSContext(t)()
181
+	d := newDriver()
182
+
183
+	if err := d.configure(nil); err != nil {
184
+		t.Fatalf("Failed to setup driver config: %v", err)
185
+	}
186
+
187
+	config := &networkConfiguration{
188
+		BridgeName: DefaultBridgeName,
189
+		EnableIPv6: true,
190
+	}
191
+	genericOption := make(map[string]interface{})
192
+	genericOption[netlabel.GenericData] = config
193
+
194
+	ipdList := getIPv4Data(t, "")
195
+	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
196
+	if err != nil {
197
+		t.Fatalf("Failed to create bridge: %v", err)
198
+	}
199
+
200
+	te := newTestEndpoint(ipdList[0].Pool, 30)
201
+	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
202
+	if err != nil {
203
+		t.Fatalf("Failed to create a link: %s", err.Error())
204
+	}
205
+
206
+	err = d.DeleteEndpoint("dummy", "")
207
+	if err != nil {
208
+		if _, ok := err.(InvalidEndpointIDError); !ok {
209
+			t.Fatalf("Failed with a wrong error :%s", err.Error())
210
+		}
211
+	} else {
212
+		t.Fatal("Failed to detect invalid config")
213
+	}
214
+
215
+	err = d.DeleteEndpoint("dummy", "ep1")
216
+	if err != nil {
217
+		t.Fatal(err)
218
+	}
219
+}
0 220
deleted file mode 100644
... ...
@@ -1,222 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"testing"
7
-
8
-	"github.com/docker/docker/internal/testutils/netnsutils"
9
-	"github.com/docker/docker/libnetwork/driverapi"
10
-	"github.com/docker/docker/libnetwork/netlabel"
11
-	"github.com/vishvananda/netlink"
12
-)
13
-
14
-func TestLinkCreate(t *testing.T) {
15
-	defer netnsutils.SetupTestOSContext(t)()
16
-	d := newDriver()
17
-
18
-	if err := d.configure(nil); err != nil {
19
-		t.Fatalf("Failed to setup driver config: %v", err)
20
-	}
21
-
22
-	mtu := 1490
23
-	config := &networkConfiguration{
24
-		BridgeName: DefaultBridgeName,
25
-		Mtu:        mtu,
26
-		EnableIPv6: true,
27
-	}
28
-	genericOption := make(map[string]interface{})
29
-	genericOption[netlabel.GenericData] = config
30
-
31
-	ipdList := getIPv4Data(t, "")
32
-	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
33
-	if err != nil {
34
-		t.Fatalf("Failed to create bridge: %v", err)
35
-	}
36
-
37
-	te := newTestEndpoint(ipdList[0].Pool, 10)
38
-	err = d.CreateEndpoint("dummy", "", te.Interface(), nil)
39
-	if err != nil {
40
-		if _, ok := err.(InvalidEndpointIDError); !ok {
41
-			t.Fatalf("Failed with a wrong error :%s", err.Error())
42
-		}
43
-	} else {
44
-		t.Fatal("Failed to detect invalid config")
45
-	}
46
-
47
-	// Good endpoint creation
48
-	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
49
-	if err != nil {
50
-		t.Fatalf("Failed to create a link: %s", err.Error())
51
-	}
52
-
53
-	err = d.Join("dummy", "ep", "sbox", te, nil)
54
-	if err != nil {
55
-		t.Fatalf("Failed to create a link: %s", err.Error())
56
-	}
57
-
58
-	// Verify sbox endpoint interface inherited MTU value from bridge config
59
-	sboxLnk, err := netlink.LinkByName(te.iface.srcName)
60
-	if err != nil {
61
-		t.Fatal(err)
62
-	}
63
-	if mtu != sboxLnk.Attrs().MTU {
64
-		t.Fatal("Sandbox endpoint interface did not inherit bridge interface MTU config")
65
-	}
66
-	// TODO: if we could get peer name from (sboxLnk.(*netlink.Veth)).PeerName
67
-	// then we could check the MTU on hostLnk as well.
68
-
69
-	te1 := newTestEndpoint(ipdList[0].Pool, 11)
70
-	err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
71
-	if err == nil {
72
-		t.Fatal("Failed to detect duplicate endpoint id on same network")
73
-	}
74
-
75
-	if te.iface.dstName == "" {
76
-		t.Fatal("Invalid Dstname returned")
77
-	}
78
-
79
-	_, err = netlink.LinkByName(te.iface.srcName)
80
-	if err != nil {
81
-		t.Fatalf("Could not find source link %s: %v", te.iface.srcName, err)
82
-	}
83
-
84
-	n, ok := d.networks["dummy"]
85
-	if !ok {
86
-		t.Fatalf("Cannot find network %s inside driver", "dummy")
87
-	}
88
-	ip := te.iface.addr.IP
89
-	if !n.bridge.bridgeIPv4.Contains(ip) {
90
-		t.Fatalf("IP %s is not a valid ip in the subnet %s", ip.String(), n.bridge.bridgeIPv4.String())
91
-	}
92
-
93
-	ip6 := te.iface.addrv6.IP
94
-	if !n.bridge.bridgeIPv6.Contains(ip6) {
95
-		t.Fatalf("IP %s is not a valid ip in the subnet %s", ip6.String(), bridgeIPv6.String())
96
-	}
97
-
98
-	if !te.gw.Equal(n.bridge.bridgeIPv4.IP) {
99
-		t.Fatalf("Invalid default gateway. Expected %s. Got %s", n.bridge.bridgeIPv4.IP.String(),
100
-			te.gw.String())
101
-	}
102
-
103
-	if !te.gw6.Equal(n.bridge.bridgeIPv6.IP) {
104
-		t.Fatalf("Invalid default gateway for IPv6. Expected %s. Got %s", n.bridge.bridgeIPv6.IP.String(),
105
-			te.gw6.String())
106
-	}
107
-}
108
-
109
-func TestLinkCreateTwo(t *testing.T) {
110
-	defer netnsutils.SetupTestOSContext(t)()
111
-	d := newDriver()
112
-
113
-	if err := d.configure(nil); err != nil {
114
-		t.Fatalf("Failed to setup driver config: %v", err)
115
-	}
116
-
117
-	config := &networkConfiguration{
118
-		BridgeName: DefaultBridgeName,
119
-		EnableIPv6: true,
120
-	}
121
-	genericOption := make(map[string]interface{})
122
-	genericOption[netlabel.GenericData] = config
123
-
124
-	ipdList := getIPv4Data(t, "")
125
-	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
126
-	if err != nil {
127
-		t.Fatalf("Failed to create bridge: %v", err)
128
-	}
129
-
130
-	te1 := newTestEndpoint(ipdList[0].Pool, 11)
131
-	err = d.CreateEndpoint("dummy", "ep", te1.Interface(), nil)
132
-	if err != nil {
133
-		t.Fatalf("Failed to create a link: %s", err.Error())
134
-	}
135
-
136
-	te2 := newTestEndpoint(ipdList[0].Pool, 12)
137
-	err = d.CreateEndpoint("dummy", "ep", te2.Interface(), nil)
138
-	if err != nil {
139
-		if _, ok := err.(driverapi.ErrEndpointExists); !ok {
140
-			t.Fatalf("Failed with a wrong error: %s", err.Error())
141
-		}
142
-	} else {
143
-		t.Fatal("Expected to fail while trying to add same endpoint twice")
144
-	}
145
-}
146
-
147
-func TestLinkCreateNoEnableIPv6(t *testing.T) {
148
-	defer netnsutils.SetupTestOSContext(t)()
149
-	d := newDriver()
150
-
151
-	if err := d.configure(nil); err != nil {
152
-		t.Fatalf("Failed to setup driver config: %v", err)
153
-	}
154
-
155
-	config := &networkConfiguration{
156
-		BridgeName: DefaultBridgeName,
157
-	}
158
-	genericOption := make(map[string]interface{})
159
-	genericOption[netlabel.GenericData] = config
160
-
161
-	ipdList := getIPv4Data(t, "")
162
-	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
163
-	if err != nil {
164
-		t.Fatalf("Failed to create bridge: %v", err)
165
-	}
166
-	te := newTestEndpoint(ipdList[0].Pool, 30)
167
-	err = d.CreateEndpoint("dummy", "ep", te.Interface(), nil)
168
-	if err != nil {
169
-		t.Fatalf("Failed to create a link: %s", err.Error())
170
-	}
171
-
172
-	iface := te.iface
173
-	if iface.addrv6 != nil && iface.addrv6.IP.To16() != nil {
174
-		t.Fatalf("Expected IPv6 address to be nil when IPv6 is not enabled. Got IPv6 = %s", iface.addrv6.String())
175
-	}
176
-
177
-	if te.gw6.To16() != nil {
178
-		t.Fatalf("Expected GatewayIPv6 to be nil when IPv6 is not enabled. Got GatewayIPv6 = %s", te.gw6.String())
179
-	}
180
-}
181
-
182
-func TestLinkDelete(t *testing.T) {
183
-	defer netnsutils.SetupTestOSContext(t)()
184
-	d := newDriver()
185
-
186
-	if err := d.configure(nil); err != nil {
187
-		t.Fatalf("Failed to setup driver config: %v", err)
188
-	}
189
-
190
-	config := &networkConfiguration{
191
-		BridgeName: DefaultBridgeName,
192
-		EnableIPv6: true,
193
-	}
194
-	genericOption := make(map[string]interface{})
195
-	genericOption[netlabel.GenericData] = config
196
-
197
-	ipdList := getIPv4Data(t, "")
198
-	err := d.CreateNetwork("dummy", genericOption, nil, ipdList, nil)
199
-	if err != nil {
200
-		t.Fatalf("Failed to create bridge: %v", err)
201
-	}
202
-
203
-	te := newTestEndpoint(ipdList[0].Pool, 30)
204
-	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
205
-	if err != nil {
206
-		t.Fatalf("Failed to create a link: %s", err.Error())
207
-	}
208
-
209
-	err = d.DeleteEndpoint("dummy", "")
210
-	if err != nil {
211
-		if _, ok := err.(InvalidEndpointIDError); !ok {
212
-			t.Fatalf("Failed with a wrong error :%s", err.Error())
213
-		}
214
-	} else {
215
-		t.Fatal("Failed to detect invalid config")
216
-	}
217
-
218
-	err = d.DeleteEndpoint("dummy", "ep1")
219
-	if err != nil {
220
-		t.Fatal(err)
221
-	}
222
-}
223 1
deleted file mode 100644
... ...
@@ -1,246 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"bytes"
7
-	"context"
8
-	"errors"
9
-	"fmt"
10
-	"net"
11
-	"sync"
12
-
13
-	"github.com/containerd/containerd/log"
14
-	"github.com/docker/docker/libnetwork/types"
15
-	"github.com/ishidawataru/sctp"
16
-)
17
-
18
-func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
19
-	if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
20
-		return nil, nil
21
-	}
22
-
23
-	defHostIP := net.IPv4zero // 0.0.0.0
24
-	if reqDefBindIP != nil {
25
-		defHostIP = reqDefBindIP
26
-	}
27
-
28
-	var containerIPv6 net.IP
29
-	if ep.addrv6 != nil {
30
-		containerIPv6 = ep.addrv6.IP
31
-	}
32
-
33
-	pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, containerIPv6, defHostIP, ulPxyEnabled)
34
-	if err != nil {
35
-		return nil, err
36
-	}
37
-	return pb, nil
38
-}
39
-
40
-func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIPv4, containerIPv6, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
41
-	bs := make([]types.PortBinding, 0, len(bindings))
42
-	for _, c := range bindings {
43
-		bIPv4 := c.GetCopy()
44
-		bIPv6 := c.GetCopy()
45
-		// Allocate IPv4 Port mappings
46
-		if ok := n.validatePortBindingIPv4(&bIPv4, containerIPv4, defHostIP); ok {
47
-			if err := n.allocatePort(&bIPv4, ulPxyEnabled); err != nil {
48
-				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
49
-				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
50
-					log.G(context.TODO()).Warnf("allocation failure for %v, failed to clear previously allocated ipv4 port bindings: %v", bIPv4, cuErr)
51
-				}
52
-				return nil, err
53
-			}
54
-			bs = append(bs, bIPv4)
55
-		}
56
-
57
-		// skip adding implicit v6 addr, when the kernel was booted with `ipv6.disable=1`
58
-		// https://github.com/moby/moby/issues/42288
59
-		isV6Binding := c.HostIP != nil && c.HostIP.To4() == nil
60
-		if !isV6Binding && !IsV6Listenable() {
61
-			continue
62
-		}
63
-
64
-		// Allocate IPv6 Port mappings
65
-		// If the container has no IPv6 address, allow proxying host IPv6 traffic to it
66
-		// by setting up the binding with the IPv4 interface if the userland proxy is enabled
67
-		// This change was added to keep backward compatibility
68
-		containerIP := containerIPv6
69
-		if ulPxyEnabled && (containerIPv6 == nil) {
70
-			containerIP = containerIPv4
71
-		}
72
-		if ok := n.validatePortBindingIPv6(&bIPv6, containerIP, defHostIP); ok {
73
-			if err := n.allocatePort(&bIPv6, ulPxyEnabled); err != nil {
74
-				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
75
-				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
76
-					log.G(context.TODO()).Warnf("allocation failure for %v, failed to clear previously allocated ipv6 port bindings: %v", bIPv6, cuErr)
77
-				}
78
-				return nil, err
79
-			}
80
-			bs = append(bs, bIPv6)
81
-		}
82
-	}
83
-	return bs, nil
84
-}
85
-
86
-// validatePortBindingIPv4 validates the port binding, populates the missing Host IP field and returns true
87
-// if this is a valid IPv4 binding, else returns false
88
-func (n *bridgeNetwork) validatePortBindingIPv4(bnd *types.PortBinding, containerIPv4, defHostIP net.IP) bool {
89
-	// Return early if there is a valid Host IP, but its not a IPv4 address
90
-	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() == nil {
91
-		return false
92
-	}
93
-	// Adjust the host address in the operational binding
94
-	if len(bnd.HostIP) == 0 {
95
-		// Return early if the default binding address is an IPv6 address
96
-		if defHostIP.To4() == nil {
97
-			return false
98
-		}
99
-		bnd.HostIP = defHostIP
100
-	}
101
-	bnd.IP = containerIPv4
102
-	return true
103
-}
104
-
105
-// validatePortBindingIPv6 validates the port binding, populates the missing Host IP field and returns true
106
-// if this is a valid IPv6 binding, else returns false
107
-func (n *bridgeNetwork) validatePortBindingIPv6(bnd *types.PortBinding, containerIP, defHostIP net.IP) bool {
108
-	// Return early if there is no container endpoint
109
-	if containerIP == nil {
110
-		return false
111
-	}
112
-	// Return early if there is a valid Host IP, which is a IPv4 address
113
-	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() != nil {
114
-		return false
115
-	}
116
-
117
-	// Setup a binding to  "::" if Host IP is empty and the default binding IP is 0.0.0.0
118
-	if len(bnd.HostIP) == 0 {
119
-		if defHostIP.Equal(net.IPv4zero) {
120
-			bnd.HostIP = net.IPv6zero
121
-			// If the default binding IP is an IPv6 address, use it
122
-		} else if defHostIP.To4() == nil {
123
-			bnd.HostIP = defHostIP
124
-			// Return false if default binding ip is an IPv4 address
125
-		} else {
126
-			return false
127
-		}
128
-	}
129
-	bnd.IP = containerIP
130
-	return true
131
-}
132
-
133
-func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, ulPxyEnabled bool) error {
134
-	var (
135
-		host net.Addr
136
-		err  error
137
-	)
138
-
139
-	// Adjust HostPortEnd if this is not a range.
140
-	if bnd.HostPortEnd == 0 {
141
-		bnd.HostPortEnd = bnd.HostPort
142
-	}
143
-
144
-	// Construct the container side transport address
145
-	container, err := bnd.ContainerAddr()
146
-	if err != nil {
147
-		return err
148
-	}
149
-
150
-	portmapper := n.portMapper
151
-
152
-	if bnd.HostIP.To4() == nil {
153
-		portmapper = n.portMapperV6
154
-	}
155
-
156
-	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
157
-	for i := 0; i < maxAllocatePortAttempts; i++ {
158
-		if host, err = portmapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
159
-			break
160
-		}
161
-		// There is no point in immediately retrying to map an explicitly chosen port.
162
-		if bnd.HostPort != 0 {
163
-			log.G(context.TODO()).Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
164
-			break
165
-		}
166
-		log.G(context.TODO()).Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
167
-	}
168
-	if err != nil {
169
-		return err
170
-	}
171
-
172
-	// Save the host port (regardless it was or not specified in the binding)
173
-	switch netAddr := host.(type) {
174
-	case *net.TCPAddr:
175
-		bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
176
-		return nil
177
-	case *net.UDPAddr:
178
-		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
179
-		return nil
180
-	case *sctp.SCTPAddr:
181
-		bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
182
-		return nil
183
-	default:
184
-		// For completeness
185
-		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
186
-	}
187
-}
188
-
189
-func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
190
-	return n.releasePortsInternal(ep.portMapping)
191
-}
192
-
193
-func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
194
-	var errorBuf bytes.Buffer
195
-
196
-	// Attempt to release all port bindings, do not stop on failure
197
-	for _, m := range bindings {
198
-		if err := n.releasePort(m); err != nil {
199
-			errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
200
-		}
201
-	}
202
-
203
-	if errorBuf.Len() != 0 {
204
-		return errors.New(errorBuf.String())
205
-	}
206
-	return nil
207
-}
208
-
209
-func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
210
-	// Construct the host side transport address
211
-	host, err := bnd.HostAddr()
212
-	if err != nil {
213
-		return err
214
-	}
215
-
216
-	portmapper := n.portMapper
217
-
218
-	if bnd.HostIP.To4() == nil {
219
-		portmapper = n.portMapperV6
220
-	}
221
-
222
-	return portmapper.Unmap(host)
223
-}
224
-
225
-var (
226
-	v6ListenableCached bool
227
-	v6ListenableOnce   sync.Once
228
-)
229
-
230
-// IsV6Listenable returns true when `[::1]:0` is listenable.
231
-// IsV6Listenable returns false mostly when the kernel was booted with `ipv6.disable=1` option.
232
-func IsV6Listenable() bool {
233
-	v6ListenableOnce.Do(func() {
234
-		ln, err := net.Listen("tcp6", "[::1]:0")
235
-		if err != nil {
236
-			// When the kernel was booted with `ipv6.disable=1`,
237
-			// we get err "listen tcp6 [::1]:0: socket: address family not supported by protocol"
238
-			// https://github.com/moby/moby/issues/42288
239
-			log.G(context.TODO()).Debugf("port_mapping: v6Listenable=false (%v)", err)
240
-		} else {
241
-			v6ListenableCached = true
242
-			ln.Close()
243
-		}
244
-	})
245
-	return v6ListenableCached
246
-}
247 1
new file mode 100644
... ...
@@ -0,0 +1,244 @@
0
+package bridge
1
+
2
+import (
3
+	"bytes"
4
+	"context"
5
+	"errors"
6
+	"fmt"
7
+	"net"
8
+	"sync"
9
+
10
+	"github.com/containerd/containerd/log"
11
+	"github.com/docker/docker/libnetwork/types"
12
+	"github.com/ishidawataru/sctp"
13
+)
14
+
15
+func (n *bridgeNetwork) allocatePorts(ep *bridgeEndpoint, reqDefBindIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
16
+	if ep.extConnConfig == nil || ep.extConnConfig.PortBindings == nil {
17
+		return nil, nil
18
+	}
19
+
20
+	defHostIP := net.IPv4zero // 0.0.0.0
21
+	if reqDefBindIP != nil {
22
+		defHostIP = reqDefBindIP
23
+	}
24
+
25
+	var containerIPv6 net.IP
26
+	if ep.addrv6 != nil {
27
+		containerIPv6 = ep.addrv6.IP
28
+	}
29
+
30
+	pb, err := n.allocatePortsInternal(ep.extConnConfig.PortBindings, ep.addr.IP, containerIPv6, defHostIP, ulPxyEnabled)
31
+	if err != nil {
32
+		return nil, err
33
+	}
34
+	return pb, nil
35
+}
36
+
37
+func (n *bridgeNetwork) allocatePortsInternal(bindings []types.PortBinding, containerIPv4, containerIPv6, defHostIP net.IP, ulPxyEnabled bool) ([]types.PortBinding, error) {
38
+	bs := make([]types.PortBinding, 0, len(bindings))
39
+	for _, c := range bindings {
40
+		bIPv4 := c.GetCopy()
41
+		bIPv6 := c.GetCopy()
42
+		// Allocate IPv4 Port mappings
43
+		if ok := n.validatePortBindingIPv4(&bIPv4, containerIPv4, defHostIP); ok {
44
+			if err := n.allocatePort(&bIPv4, ulPxyEnabled); err != nil {
45
+				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
46
+				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
47
+					log.G(context.TODO()).Warnf("allocation failure for %v, failed to clear previously allocated ipv4 port bindings: %v", bIPv4, cuErr)
48
+				}
49
+				return nil, err
50
+			}
51
+			bs = append(bs, bIPv4)
52
+		}
53
+
54
+		// skip adding implicit v6 addr, when the kernel was booted with `ipv6.disable=1`
55
+		// https://github.com/moby/moby/issues/42288
56
+		isV6Binding := c.HostIP != nil && c.HostIP.To4() == nil
57
+		if !isV6Binding && !IsV6Listenable() {
58
+			continue
59
+		}
60
+
61
+		// Allocate IPv6 Port mappings
62
+		// If the container has no IPv6 address, allow proxying host IPv6 traffic to it
63
+		// by setting up the binding with the IPv4 interface if the userland proxy is enabled
64
+		// This change was added to keep backward compatibility
65
+		containerIP := containerIPv6
66
+		if ulPxyEnabled && (containerIPv6 == nil) {
67
+			containerIP = containerIPv4
68
+		}
69
+		if ok := n.validatePortBindingIPv6(&bIPv6, containerIP, defHostIP); ok {
70
+			if err := n.allocatePort(&bIPv6, ulPxyEnabled); err != nil {
71
+				// On allocation failure, release previously allocated ports. On cleanup error, just log a warning message
72
+				if cuErr := n.releasePortsInternal(bs); cuErr != nil {
73
+					log.G(context.TODO()).Warnf("allocation failure for %v, failed to clear previously allocated ipv6 port bindings: %v", bIPv6, cuErr)
74
+				}
75
+				return nil, err
76
+			}
77
+			bs = append(bs, bIPv6)
78
+		}
79
+	}
80
+	return bs, nil
81
+}
82
+
83
+// validatePortBindingIPv4 validates the port binding, populates the missing Host IP field and returns true
84
+// if this is a valid IPv4 binding, else returns false
85
+func (n *bridgeNetwork) validatePortBindingIPv4(bnd *types.PortBinding, containerIPv4, defHostIP net.IP) bool {
86
+	// Return early if there is a valid Host IP, but its not a IPv4 address
87
+	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() == nil {
88
+		return false
89
+	}
90
+	// Adjust the host address in the operational binding
91
+	if len(bnd.HostIP) == 0 {
92
+		// Return early if the default binding address is an IPv6 address
93
+		if defHostIP.To4() == nil {
94
+			return false
95
+		}
96
+		bnd.HostIP = defHostIP
97
+	}
98
+	bnd.IP = containerIPv4
99
+	return true
100
+}
101
+
102
+// validatePortBindingIPv6 validates the port binding, populates the missing Host IP field and returns true
103
+// if this is a valid IPv6 binding, else returns false
104
+func (n *bridgeNetwork) validatePortBindingIPv6(bnd *types.PortBinding, containerIP, defHostIP net.IP) bool {
105
+	// Return early if there is no container endpoint
106
+	if containerIP == nil {
107
+		return false
108
+	}
109
+	// Return early if there is a valid Host IP, which is a IPv4 address
110
+	if len(bnd.HostIP) > 0 && bnd.HostIP.To4() != nil {
111
+		return false
112
+	}
113
+
114
+	// Setup a binding to  "::" if Host IP is empty and the default binding IP is 0.0.0.0
115
+	if len(bnd.HostIP) == 0 {
116
+		if defHostIP.Equal(net.IPv4zero) {
117
+			bnd.HostIP = net.IPv6zero
118
+			// If the default binding IP is an IPv6 address, use it
119
+		} else if defHostIP.To4() == nil {
120
+			bnd.HostIP = defHostIP
121
+			// Return false if default binding ip is an IPv4 address
122
+		} else {
123
+			return false
124
+		}
125
+	}
126
+	bnd.IP = containerIP
127
+	return true
128
+}
129
+
130
+func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, ulPxyEnabled bool) error {
131
+	var (
132
+		host net.Addr
133
+		err  error
134
+	)
135
+
136
+	// Adjust HostPortEnd if this is not a range.
137
+	if bnd.HostPortEnd == 0 {
138
+		bnd.HostPortEnd = bnd.HostPort
139
+	}
140
+
141
+	// Construct the container side transport address
142
+	container, err := bnd.ContainerAddr()
143
+	if err != nil {
144
+		return err
145
+	}
146
+
147
+	portmapper := n.portMapper
148
+
149
+	if bnd.HostIP.To4() == nil {
150
+		portmapper = n.portMapperV6
151
+	}
152
+
153
+	// Try up to maxAllocatePortAttempts times to get a port that's not already allocated.
154
+	for i := 0; i < maxAllocatePortAttempts; i++ {
155
+		if host, err = portmapper.MapRange(container, bnd.HostIP, int(bnd.HostPort), int(bnd.HostPortEnd), ulPxyEnabled); err == nil {
156
+			break
157
+		}
158
+		// There is no point in immediately retrying to map an explicitly chosen port.
159
+		if bnd.HostPort != 0 {
160
+			log.G(context.TODO()).Warnf("Failed to allocate and map port %d-%d: %s", bnd.HostPort, bnd.HostPortEnd, err)
161
+			break
162
+		}
163
+		log.G(context.TODO()).Warnf("Failed to allocate and map port: %s, retry: %d", err, i+1)
164
+	}
165
+	if err != nil {
166
+		return err
167
+	}
168
+
169
+	// Save the host port (regardless it was or not specified in the binding)
170
+	switch netAddr := host.(type) {
171
+	case *net.TCPAddr:
172
+		bnd.HostPort = uint16(host.(*net.TCPAddr).Port)
173
+		return nil
174
+	case *net.UDPAddr:
175
+		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
176
+		return nil
177
+	case *sctp.SCTPAddr:
178
+		bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
179
+		return nil
180
+	default:
181
+		// For completeness
182
+		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
183
+	}
184
+}
185
+
186
+func (n *bridgeNetwork) releasePorts(ep *bridgeEndpoint) error {
187
+	return n.releasePortsInternal(ep.portMapping)
188
+}
189
+
190
+func (n *bridgeNetwork) releasePortsInternal(bindings []types.PortBinding) error {
191
+	var errorBuf bytes.Buffer
192
+
193
+	// Attempt to release all port bindings, do not stop on failure
194
+	for _, m := range bindings {
195
+		if err := n.releasePort(m); err != nil {
196
+			errorBuf.WriteString(fmt.Sprintf("\ncould not release %v because of %v", m, err))
197
+		}
198
+	}
199
+
200
+	if errorBuf.Len() != 0 {
201
+		return errors.New(errorBuf.String())
202
+	}
203
+	return nil
204
+}
205
+
206
+func (n *bridgeNetwork) releasePort(bnd types.PortBinding) error {
207
+	// Construct the host side transport address
208
+	host, err := bnd.HostAddr()
209
+	if err != nil {
210
+		return err
211
+	}
212
+
213
+	portmapper := n.portMapper
214
+
215
+	if bnd.HostIP.To4() == nil {
216
+		portmapper = n.portMapperV6
217
+	}
218
+
219
+	return portmapper.Unmap(host)
220
+}
221
+
222
+var (
223
+	v6ListenableCached bool
224
+	v6ListenableOnce   sync.Once
225
+)
226
+
227
+// IsV6Listenable returns true when `[::1]:0` is listenable.
228
+// IsV6Listenable returns false mostly when the kernel was booted with `ipv6.disable=1` option.
229
+func IsV6Listenable() bool {
230
+	v6ListenableOnce.Do(func() {
231
+		ln, err := net.Listen("tcp6", "[::1]:0")
232
+		if err != nil {
233
+			// When the kernel was booted with `ipv6.disable=1`,
234
+			// we get err "listen tcp6 [::1]:0: socket: address family not supported by protocol"
235
+			// https://github.com/moby/moby/issues/42288
236
+			log.G(context.TODO()).Debugf("port_mapping: v6Listenable=false (%v)", err)
237
+		} else {
238
+			v6ListenableCached = true
239
+			ln.Close()
240
+		}
241
+	})
242
+	return v6ListenableCached
243
+}
0 244
new file mode 100644
... ...
@@ -0,0 +1,173 @@
0
+package bridge
1
+
2
+import (
3
+	"testing"
4
+
5
+	"github.com/docker/docker/internal/testutils/netnsutils"
6
+	"github.com/docker/docker/libnetwork/netlabel"
7
+	"github.com/docker/docker/libnetwork/ns"
8
+	"github.com/docker/docker/libnetwork/types"
9
+)
10
+
11
+func TestPortMappingConfig(t *testing.T) {
12
+	defer netnsutils.SetupTestOSContext(t)()
13
+	d := newDriver()
14
+
15
+	config := &configuration{
16
+		EnableIPTables: true,
17
+	}
18
+	genericOption := make(map[string]interface{})
19
+	genericOption[netlabel.GenericData] = config
20
+
21
+	if err := d.configure(genericOption); err != nil {
22
+		t.Fatalf("Failed to setup driver config: %v", err)
23
+	}
24
+
25
+	binding1 := types.PortBinding{Proto: types.UDP, Port: uint16(400), HostPort: uint16(54000)}
26
+	binding2 := types.PortBinding{Proto: types.TCP, Port: uint16(500), HostPort: uint16(65000)}
27
+	binding3 := types.PortBinding{Proto: types.SCTP, Port: uint16(300), HostPort: uint16(65000)}
28
+	portBindings := []types.PortBinding{binding1, binding2, binding3}
29
+
30
+	sbOptions := make(map[string]interface{})
31
+	sbOptions[netlabel.PortMap] = portBindings
32
+
33
+	netConfig := &networkConfiguration{
34
+		BridgeName: DefaultBridgeName,
35
+	}
36
+	netOptions := make(map[string]interface{})
37
+	netOptions[netlabel.GenericData] = netConfig
38
+
39
+	ipdList := getIPv4Data(t, "")
40
+	err := d.CreateNetwork("dummy", netOptions, nil, ipdList, nil)
41
+	if err != nil {
42
+		t.Fatalf("Failed to create bridge: %v", err)
43
+	}
44
+
45
+	te := newTestEndpoint(ipdList[0].Pool, 11)
46
+	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
47
+	if err != nil {
48
+		t.Fatalf("Failed to create the endpoint: %s", err.Error())
49
+	}
50
+
51
+	if err = d.Join("dummy", "ep1", "sbox", te, sbOptions); err != nil {
52
+		t.Fatalf("Failed to join the endpoint: %v", err)
53
+	}
54
+
55
+	if err = d.ProgramExternalConnectivity("dummy", "ep1", sbOptions); err != nil {
56
+		t.Fatalf("Failed to program external connectivity: %v", err)
57
+	}
58
+
59
+	network, ok := d.networks["dummy"]
60
+	if !ok {
61
+		t.Fatalf("Cannot find network %s inside driver", "dummy")
62
+	}
63
+	ep := network.endpoints["ep1"]
64
+	if len(ep.portMapping) != 3 {
65
+		t.Fatalf("Failed to store the port bindings into the sandbox info. Found: %v", ep.portMapping)
66
+	}
67
+	if ep.portMapping[0].Proto != binding1.Proto || ep.portMapping[0].Port != binding1.Port ||
68
+		ep.portMapping[1].Proto != binding2.Proto || ep.portMapping[1].Port != binding2.Port ||
69
+		ep.portMapping[2].Proto != binding3.Proto || ep.portMapping[2].Port != binding3.Port {
70
+		t.Fatal("bridgeEndpoint has incorrect port mapping values")
71
+	}
72
+	if ep.portMapping[0].HostIP == nil || ep.portMapping[0].HostPort == 0 ||
73
+		ep.portMapping[1].HostIP == nil || ep.portMapping[1].HostPort == 0 ||
74
+		ep.portMapping[2].HostIP == nil || ep.portMapping[2].HostPort == 0 {
75
+		t.Fatal("operational port mapping data not found on bridgeEndpoint")
76
+	}
77
+
78
+	// release host mapped ports
79
+	err = d.Leave("dummy", "ep1")
80
+	if err != nil {
81
+		t.Fatal(err)
82
+	}
83
+
84
+	err = d.RevokeExternalConnectivity("dummy", "ep1")
85
+	if err != nil {
86
+		t.Fatal(err)
87
+	}
88
+}
89
+
90
+func TestPortMappingV6Config(t *testing.T) {
91
+	defer netnsutils.SetupTestOSContext(t)()
92
+	if err := loopbackUp(); err != nil {
93
+		t.Fatalf("Could not bring loopback iface up: %v", err)
94
+	}
95
+
96
+	d := newDriver()
97
+
98
+	config := &configuration{
99
+		EnableIPTables:  true,
100
+		EnableIP6Tables: true,
101
+	}
102
+	genericOption := make(map[string]interface{})
103
+	genericOption[netlabel.GenericData] = config
104
+
105
+	if err := d.configure(genericOption); err != nil {
106
+		t.Fatalf("Failed to setup driver config: %v", err)
107
+	}
108
+
109
+	portBindings := []types.PortBinding{
110
+		{Proto: types.UDP, Port: uint16(400), HostPort: uint16(54000)},
111
+		{Proto: types.TCP, Port: uint16(500), HostPort: uint16(65000)},
112
+		{Proto: types.SCTP, Port: uint16(500), HostPort: uint16(65000)},
113
+	}
114
+
115
+	sbOptions := make(map[string]interface{})
116
+	sbOptions[netlabel.PortMap] = portBindings
117
+	netConfig := &networkConfiguration{
118
+		BridgeName: DefaultBridgeName,
119
+		EnableIPv6: true,
120
+	}
121
+	netOptions := make(map[string]interface{})
122
+	netOptions[netlabel.GenericData] = netConfig
123
+
124
+	ipdList := getIPv4Data(t, "")
125
+	err := d.CreateNetwork("dummy", netOptions, nil, ipdList, nil)
126
+	if err != nil {
127
+		t.Fatalf("Failed to create bridge: %v", err)
128
+	}
129
+
130
+	te := newTestEndpoint(ipdList[0].Pool, 11)
131
+	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
132
+	if err != nil {
133
+		t.Fatalf("Failed to create the endpoint: %s", err.Error())
134
+	}
135
+
136
+	if err = d.Join("dummy", "ep1", "sbox", te, sbOptions); err != nil {
137
+		t.Fatalf("Failed to join the endpoint: %v", err)
138
+	}
139
+
140
+	if err = d.ProgramExternalConnectivity("dummy", "ep1", sbOptions); err != nil {
141
+		t.Fatalf("Failed to program external connectivity: %v", err)
142
+	}
143
+
144
+	network, ok := d.networks["dummy"]
145
+	if !ok {
146
+		t.Fatalf("Cannot find network %s inside driver", "dummy")
147
+	}
148
+	ep := network.endpoints["ep1"]
149
+	if len(ep.portMapping) != 6 {
150
+		t.Fatalf("Failed to store the port bindings into the sandbox info. Found: %v", ep.portMapping)
151
+	}
152
+
153
+	// release host mapped ports
154
+	err = d.Leave("dummy", "ep1")
155
+	if err != nil {
156
+		t.Fatal(err)
157
+	}
158
+
159
+	err = d.RevokeExternalConnectivity("dummy", "ep1")
160
+	if err != nil {
161
+		t.Fatal(err)
162
+	}
163
+}
164
+
165
+func loopbackUp() error {
166
+	nlHandle := ns.NlHandle()
167
+	iface, err := nlHandle.LinkByName("lo")
168
+	if err != nil {
169
+		return err
170
+	}
171
+	return nlHandle.LinkSetUp(iface)
172
+}
0 173
deleted file mode 100644
... ...
@@ -1,175 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"testing"
7
-
8
-	"github.com/docker/docker/internal/testutils/netnsutils"
9
-	"github.com/docker/docker/libnetwork/netlabel"
10
-	"github.com/docker/docker/libnetwork/ns"
11
-	"github.com/docker/docker/libnetwork/types"
12
-)
13
-
14
-func TestPortMappingConfig(t *testing.T) {
15
-	defer netnsutils.SetupTestOSContext(t)()
16
-	d := newDriver()
17
-
18
-	config := &configuration{
19
-		EnableIPTables: true,
20
-	}
21
-	genericOption := make(map[string]interface{})
22
-	genericOption[netlabel.GenericData] = config
23
-
24
-	if err := d.configure(genericOption); err != nil {
25
-		t.Fatalf("Failed to setup driver config: %v", err)
26
-	}
27
-
28
-	binding1 := types.PortBinding{Proto: types.UDP, Port: uint16(400), HostPort: uint16(54000)}
29
-	binding2 := types.PortBinding{Proto: types.TCP, Port: uint16(500), HostPort: uint16(65000)}
30
-	binding3 := types.PortBinding{Proto: types.SCTP, Port: uint16(300), HostPort: uint16(65000)}
31
-	portBindings := []types.PortBinding{binding1, binding2, binding3}
32
-
33
-	sbOptions := make(map[string]interface{})
34
-	sbOptions[netlabel.PortMap] = portBindings
35
-
36
-	netConfig := &networkConfiguration{
37
-		BridgeName: DefaultBridgeName,
38
-	}
39
-	netOptions := make(map[string]interface{})
40
-	netOptions[netlabel.GenericData] = netConfig
41
-
42
-	ipdList := getIPv4Data(t, "")
43
-	err := d.CreateNetwork("dummy", netOptions, nil, ipdList, nil)
44
-	if err != nil {
45
-		t.Fatalf("Failed to create bridge: %v", err)
46
-	}
47
-
48
-	te := newTestEndpoint(ipdList[0].Pool, 11)
49
-	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
50
-	if err != nil {
51
-		t.Fatalf("Failed to create the endpoint: %s", err.Error())
52
-	}
53
-
54
-	if err = d.Join("dummy", "ep1", "sbox", te, sbOptions); err != nil {
55
-		t.Fatalf("Failed to join the endpoint: %v", err)
56
-	}
57
-
58
-	if err = d.ProgramExternalConnectivity("dummy", "ep1", sbOptions); err != nil {
59
-		t.Fatalf("Failed to program external connectivity: %v", err)
60
-	}
61
-
62
-	network, ok := d.networks["dummy"]
63
-	if !ok {
64
-		t.Fatalf("Cannot find network %s inside driver", "dummy")
65
-	}
66
-	ep := network.endpoints["ep1"]
67
-	if len(ep.portMapping) != 3 {
68
-		t.Fatalf("Failed to store the port bindings into the sandbox info. Found: %v", ep.portMapping)
69
-	}
70
-	if ep.portMapping[0].Proto != binding1.Proto || ep.portMapping[0].Port != binding1.Port ||
71
-		ep.portMapping[1].Proto != binding2.Proto || ep.portMapping[1].Port != binding2.Port ||
72
-		ep.portMapping[2].Proto != binding3.Proto || ep.portMapping[2].Port != binding3.Port {
73
-		t.Fatal("bridgeEndpoint has incorrect port mapping values")
74
-	}
75
-	if ep.portMapping[0].HostIP == nil || ep.portMapping[0].HostPort == 0 ||
76
-		ep.portMapping[1].HostIP == nil || ep.portMapping[1].HostPort == 0 ||
77
-		ep.portMapping[2].HostIP == nil || ep.portMapping[2].HostPort == 0 {
78
-		t.Fatal("operational port mapping data not found on bridgeEndpoint")
79
-	}
80
-
81
-	// release host mapped ports
82
-	err = d.Leave("dummy", "ep1")
83
-	if err != nil {
84
-		t.Fatal(err)
85
-	}
86
-
87
-	err = d.RevokeExternalConnectivity("dummy", "ep1")
88
-	if err != nil {
89
-		t.Fatal(err)
90
-	}
91
-}
92
-
93
-func TestPortMappingV6Config(t *testing.T) {
94
-	defer netnsutils.SetupTestOSContext(t)()
95
-	if err := loopbackUp(); err != nil {
96
-		t.Fatalf("Could not bring loopback iface up: %v", err)
97
-	}
98
-
99
-	d := newDriver()
100
-
101
-	config := &configuration{
102
-		EnableIPTables:  true,
103
-		EnableIP6Tables: true,
104
-	}
105
-	genericOption := make(map[string]interface{})
106
-	genericOption[netlabel.GenericData] = config
107
-
108
-	if err := d.configure(genericOption); err != nil {
109
-		t.Fatalf("Failed to setup driver config: %v", err)
110
-	}
111
-
112
-	portBindings := []types.PortBinding{
113
-		{Proto: types.UDP, Port: uint16(400), HostPort: uint16(54000)},
114
-		{Proto: types.TCP, Port: uint16(500), HostPort: uint16(65000)},
115
-		{Proto: types.SCTP, Port: uint16(500), HostPort: uint16(65000)},
116
-	}
117
-
118
-	sbOptions := make(map[string]interface{})
119
-	sbOptions[netlabel.PortMap] = portBindings
120
-	netConfig := &networkConfiguration{
121
-		BridgeName: DefaultBridgeName,
122
-		EnableIPv6: true,
123
-	}
124
-	netOptions := make(map[string]interface{})
125
-	netOptions[netlabel.GenericData] = netConfig
126
-
127
-	ipdList := getIPv4Data(t, "")
128
-	err := d.CreateNetwork("dummy", netOptions, nil, ipdList, nil)
129
-	if err != nil {
130
-		t.Fatalf("Failed to create bridge: %v", err)
131
-	}
132
-
133
-	te := newTestEndpoint(ipdList[0].Pool, 11)
134
-	err = d.CreateEndpoint("dummy", "ep1", te.Interface(), nil)
135
-	if err != nil {
136
-		t.Fatalf("Failed to create the endpoint: %s", err.Error())
137
-	}
138
-
139
-	if err = d.Join("dummy", "ep1", "sbox", te, sbOptions); err != nil {
140
-		t.Fatalf("Failed to join the endpoint: %v", err)
141
-	}
142
-
143
-	if err = d.ProgramExternalConnectivity("dummy", "ep1", sbOptions); err != nil {
144
-		t.Fatalf("Failed to program external connectivity: %v", err)
145
-	}
146
-
147
-	network, ok := d.networks["dummy"]
148
-	if !ok {
149
-		t.Fatalf("Cannot find network %s inside driver", "dummy")
150
-	}
151
-	ep := network.endpoints["ep1"]
152
-	if len(ep.portMapping) != 6 {
153
-		t.Fatalf("Failed to store the port bindings into the sandbox info. Found: %v", ep.portMapping)
154
-	}
155
-
156
-	// release host mapped ports
157
-	err = d.Leave("dummy", "ep1")
158
-	if err != nil {
159
-		t.Fatal(err)
160
-	}
161
-
162
-	err = d.RevokeExternalConnectivity("dummy", "ep1")
163
-	if err != nil {
164
-		t.Fatal(err)
165
-	}
166
-}
167
-
168
-func loopbackUp() error {
169
-	nlHandle := ns.NlHandle()
170
-	iface, err := nlHandle.LinkByName("lo")
171
-	if err != nil {
172
-		return err
173
-	}
174
-	return nlHandle.LinkSetUp(iface)
175
-}
176 1
deleted file mode 100644
... ...
@@ -1,81 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"context"
7
-	"fmt"
8
-	"os"
9
-	"path/filepath"
10
-
11
-	"github.com/containerd/containerd/log"
12
-	"github.com/docker/docker/libnetwork/netutils"
13
-	"github.com/vishvananda/netlink"
14
-)
15
-
16
-// SetupDevice create a new bridge interface/
17
-func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
18
-	// We only attempt to create the bridge when the requested device name is
19
-	// the default one. The default bridge name can be overridden with the
20
-	// DOCKER_TEST_CREATE_DEFAULT_BRIDGE env var. It should be used only for
21
-	// test purpose.
22
-	var defaultBridgeName string
23
-	if defaultBridgeName = os.Getenv("DOCKER_TEST_CREATE_DEFAULT_BRIDGE"); defaultBridgeName == "" {
24
-		defaultBridgeName = DefaultBridgeName
25
-	}
26
-	if config.BridgeName != defaultBridgeName && config.DefaultBridge {
27
-		return NonDefaultBridgeExistError(config.BridgeName)
28
-	}
29
-
30
-	// Set the bridgeInterface netlink.Bridge.
31
-	i.Link = &netlink.Bridge{
32
-		LinkAttrs: netlink.LinkAttrs{
33
-			Name: config.BridgeName,
34
-		},
35
-	}
36
-
37
-	// Set the bridge's MAC address. Requires kernel version 3.3 or up.
38
-	hwAddr := netutils.GenerateRandomMAC()
39
-	i.Link.Attrs().HardwareAddr = hwAddr
40
-	log.G(context.TODO()).Debugf("Setting bridge mac address to %s", hwAddr)
41
-
42
-	if err := i.nlh.LinkAdd(i.Link); err != nil {
43
-		log.G(context.TODO()).WithError(err).Errorf("Failed to create bridge %s via netlink", config.BridgeName)
44
-		return err
45
-	}
46
-
47
-	return nil
48
-}
49
-
50
-func setupDefaultSysctl(config *networkConfiguration, i *bridgeInterface) error {
51
-	// Disable IPv6 router advertisements originating on the bridge
52
-	sysPath := filepath.Join("/proc/sys/net/ipv6/conf/", config.BridgeName, "accept_ra")
53
-	if _, err := os.Stat(sysPath); err != nil {
54
-		log.G(context.TODO()).
55
-			WithField("bridge", config.BridgeName).
56
-			WithField("syspath", sysPath).
57
-			Info("failed to read ipv6 net.ipv6.conf.<bridge>.accept_ra")
58
-		return nil
59
-	}
60
-	if err := os.WriteFile(sysPath, []byte{'0', '\n'}, 0o644); err != nil {
61
-		log.G(context.TODO()).WithError(err).Warn("unable to disable IPv6 router advertisement")
62
-	}
63
-	return nil
64
-}
65
-
66
-// SetupDeviceUp ups the given bridge interface.
67
-func setupDeviceUp(config *networkConfiguration, i *bridgeInterface) error {
68
-	err := i.nlh.LinkSetUp(i.Link)
69
-	if err != nil {
70
-		return fmt.Errorf("Failed to set link up for %s: %v", config.BridgeName, err)
71
-	}
72
-
73
-	// Attempt to update the bridge interface to refresh the flags status,
74
-	// ignoring any failure to do so.
75
-	if lnk, err := i.nlh.LinkByName(config.BridgeName); err == nil {
76
-		i.Link = lnk
77
-	} else {
78
-		log.G(context.TODO()).Warnf("Failed to retrieve link for interface (%s): %v", config.BridgeName, err)
79
-	}
80
-	return nil
81
-}
82 1
new file mode 100644
... ...
@@ -0,0 +1,79 @@
0
+package bridge
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+	"os"
6
+	"path/filepath"
7
+
8
+	"github.com/containerd/containerd/log"
9
+	"github.com/docker/docker/libnetwork/netutils"
10
+	"github.com/vishvananda/netlink"
11
+)
12
+
13
+// SetupDevice create a new bridge interface/
14
+func setupDevice(config *networkConfiguration, i *bridgeInterface) error {
15
+	// We only attempt to create the bridge when the requested device name is
16
+	// the default one. The default bridge name can be overridden with the
17
+	// DOCKER_TEST_CREATE_DEFAULT_BRIDGE env var. It should be used only for
18
+	// test purpose.
19
+	var defaultBridgeName string
20
+	if defaultBridgeName = os.Getenv("DOCKER_TEST_CREATE_DEFAULT_BRIDGE"); defaultBridgeName == "" {
21
+		defaultBridgeName = DefaultBridgeName
22
+	}
23
+	if config.BridgeName != defaultBridgeName && config.DefaultBridge {
24
+		return NonDefaultBridgeExistError(config.BridgeName)
25
+	}
26
+
27
+	// Set the bridgeInterface netlink.Bridge.
28
+	i.Link = &netlink.Bridge{
29
+		LinkAttrs: netlink.LinkAttrs{
30
+			Name: config.BridgeName,
31
+		},
32
+	}
33
+
34
+	// Set the bridge's MAC address. Requires kernel version 3.3 or up.
35
+	hwAddr := netutils.GenerateRandomMAC()
36
+	i.Link.Attrs().HardwareAddr = hwAddr
37
+	log.G(context.TODO()).Debugf("Setting bridge mac address to %s", hwAddr)
38
+
39
+	if err := i.nlh.LinkAdd(i.Link); err != nil {
40
+		log.G(context.TODO()).WithError(err).Errorf("Failed to create bridge %s via netlink", config.BridgeName)
41
+		return err
42
+	}
43
+
44
+	return nil
45
+}
46
+
47
+func setupDefaultSysctl(config *networkConfiguration, i *bridgeInterface) error {
48
+	// Disable IPv6 router advertisements originating on the bridge
49
+	sysPath := filepath.Join("/proc/sys/net/ipv6/conf/", config.BridgeName, "accept_ra")
50
+	if _, err := os.Stat(sysPath); err != nil {
51
+		log.G(context.TODO()).
52
+			WithField("bridge", config.BridgeName).
53
+			WithField("syspath", sysPath).
54
+			Info("failed to read ipv6 net.ipv6.conf.<bridge>.accept_ra")
55
+		return nil
56
+	}
57
+	if err := os.WriteFile(sysPath, []byte{'0', '\n'}, 0o644); err != nil {
58
+		log.G(context.TODO()).WithError(err).Warn("unable to disable IPv6 router advertisement")
59
+	}
60
+	return nil
61
+}
62
+
63
+// SetupDeviceUp ups the given bridge interface.
64
+func setupDeviceUp(config *networkConfiguration, i *bridgeInterface) error {
65
+	err := i.nlh.LinkSetUp(i.Link)
66
+	if err != nil {
67
+		return fmt.Errorf("Failed to set link up for %s: %v", config.BridgeName, err)
68
+	}
69
+
70
+	// Attempt to update the bridge interface to refresh the flags status,
71
+	// ignoring any failure to do so.
72
+	if lnk, err := i.nlh.LinkByName(config.BridgeName); err == nil {
73
+		i.Link = lnk
74
+	} else {
75
+		log.G(context.TODO()).Warnf("Failed to retrieve link for interface (%s): %v", config.BridgeName, err)
76
+	}
77
+	return nil
78
+}
0 79
new file mode 100644
... ...
@@ -0,0 +1,94 @@
0
+package bridge
1
+
2
+import (
3
+	"bytes"
4
+	"net"
5
+	"testing"
6
+
7
+	"github.com/docker/docker/internal/testutils/netnsutils"
8
+	"github.com/docker/docker/libnetwork/netutils"
9
+	"github.com/vishvananda/netlink"
10
+)
11
+
12
+func TestSetupNewBridge(t *testing.T) {
13
+	defer netnsutils.SetupTestOSContext(t)()
14
+
15
+	nh, err := netlink.NewHandle()
16
+	if err != nil {
17
+		t.Fatal(err)
18
+	}
19
+	defer nh.Close()
20
+
21
+	config := &networkConfiguration{BridgeName: DefaultBridgeName}
22
+	br := &bridgeInterface{nlh: nh}
23
+
24
+	if err := setupDevice(config, br); err != nil {
25
+		t.Fatalf("Bridge creation failed: %v", err)
26
+	}
27
+	if br.Link == nil {
28
+		t.Fatal("bridgeInterface link is nil (expected valid link)")
29
+	}
30
+	if _, err := nh.LinkByName(DefaultBridgeName); err != nil {
31
+		t.Fatalf("Failed to retrieve bridge device: %v", err)
32
+	}
33
+	if br.Link.Attrs().Flags&net.FlagUp == net.FlagUp {
34
+		t.Fatal("bridgeInterface should be created down")
35
+	}
36
+}
37
+
38
+func TestSetupNewNonDefaultBridge(t *testing.T) {
39
+	defer netnsutils.SetupTestOSContext(t)()
40
+
41
+	nh, err := netlink.NewHandle()
42
+	if err != nil {
43
+		t.Fatal(err)
44
+	}
45
+	defer nh.Close()
46
+
47
+	config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true}
48
+	br := &bridgeInterface{nlh: nh}
49
+
50
+	err = setupDevice(config, br)
51
+	if err == nil {
52
+		t.Fatal(`Expected bridge creation failure with "non default name", succeeded`)
53
+	}
54
+
55
+	if _, ok := err.(NonDefaultBridgeExistError); !ok {
56
+		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
57
+	}
58
+}
59
+
60
+func TestSetupDeviceUp(t *testing.T) {
61
+	defer netnsutils.SetupTestOSContext(t)()
62
+
63
+	nh, err := netlink.NewHandle()
64
+	if err != nil {
65
+		t.Fatal(err)
66
+	}
67
+	defer nh.Close()
68
+
69
+	config := &networkConfiguration{BridgeName: DefaultBridgeName}
70
+	br := &bridgeInterface{nlh: nh}
71
+
72
+	if err := setupDevice(config, br); err != nil {
73
+		t.Fatalf("Bridge creation failed: %v", err)
74
+	}
75
+	if err := setupDeviceUp(config, br); err != nil {
76
+		t.Fatalf("Failed to up bridge device: %v", err)
77
+	}
78
+
79
+	lnk, _ := nh.LinkByName(DefaultBridgeName)
80
+	if lnk.Attrs().Flags&net.FlagUp != net.FlagUp {
81
+		t.Fatal("bridgeInterface should be up")
82
+	}
83
+}
84
+
85
+func TestGenerateRandomMAC(t *testing.T) {
86
+	defer netnsutils.SetupTestOSContext(t)()
87
+
88
+	mac1 := netutils.GenerateRandomMAC()
89
+	mac2 := netutils.GenerateRandomMAC()
90
+	if bytes.Equal(mac1, mac2) {
91
+		t.Fatalf("Generated twice the same MAC address %v", mac1)
92
+	}
93
+}
0 94
deleted file mode 100644
... ...
@@ -1,96 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"bytes"
7
-	"net"
8
-	"testing"
9
-
10
-	"github.com/docker/docker/internal/testutils/netnsutils"
11
-	"github.com/docker/docker/libnetwork/netutils"
12
-	"github.com/vishvananda/netlink"
13
-)
14
-
15
-func TestSetupNewBridge(t *testing.T) {
16
-	defer netnsutils.SetupTestOSContext(t)()
17
-
18
-	nh, err := netlink.NewHandle()
19
-	if err != nil {
20
-		t.Fatal(err)
21
-	}
22
-	defer nh.Close()
23
-
24
-	config := &networkConfiguration{BridgeName: DefaultBridgeName}
25
-	br := &bridgeInterface{nlh: nh}
26
-
27
-	if err := setupDevice(config, br); err != nil {
28
-		t.Fatalf("Bridge creation failed: %v", err)
29
-	}
30
-	if br.Link == nil {
31
-		t.Fatal("bridgeInterface link is nil (expected valid link)")
32
-	}
33
-	if _, err := nh.LinkByName(DefaultBridgeName); err != nil {
34
-		t.Fatalf("Failed to retrieve bridge device: %v", err)
35
-	}
36
-	if br.Link.Attrs().Flags&net.FlagUp == net.FlagUp {
37
-		t.Fatal("bridgeInterface should be created down")
38
-	}
39
-}
40
-
41
-func TestSetupNewNonDefaultBridge(t *testing.T) {
42
-	defer netnsutils.SetupTestOSContext(t)()
43
-
44
-	nh, err := netlink.NewHandle()
45
-	if err != nil {
46
-		t.Fatal(err)
47
-	}
48
-	defer nh.Close()
49
-
50
-	config := &networkConfiguration{BridgeName: "test0", DefaultBridge: true}
51
-	br := &bridgeInterface{nlh: nh}
52
-
53
-	err = setupDevice(config, br)
54
-	if err == nil {
55
-		t.Fatal(`Expected bridge creation failure with "non default name", succeeded`)
56
-	}
57
-
58
-	if _, ok := err.(NonDefaultBridgeExistError); !ok {
59
-		t.Fatalf("Did not fail with expected error. Actual error: %v", err)
60
-	}
61
-}
62
-
63
-func TestSetupDeviceUp(t *testing.T) {
64
-	defer netnsutils.SetupTestOSContext(t)()
65
-
66
-	nh, err := netlink.NewHandle()
67
-	if err != nil {
68
-		t.Fatal(err)
69
-	}
70
-	defer nh.Close()
71
-
72
-	config := &networkConfiguration{BridgeName: DefaultBridgeName}
73
-	br := &bridgeInterface{nlh: nh}
74
-
75
-	if err := setupDevice(config, br); err != nil {
76
-		t.Fatalf("Bridge creation failed: %v", err)
77
-	}
78
-	if err := setupDeviceUp(config, br); err != nil {
79
-		t.Fatalf("Failed to up bridge device: %v", err)
80
-	}
81
-
82
-	lnk, _ := nh.LinkByName(DefaultBridgeName)
83
-	if lnk.Attrs().Flags&net.FlagUp != net.FlagUp {
84
-		t.Fatal("bridgeInterface should be up")
85
-	}
86
-}
87
-
88
-func TestGenerateRandomMAC(t *testing.T) {
89
-	defer netnsutils.SetupTestOSContext(t)()
90
-
91
-	mac1 := netutils.GenerateRandomMAC()
92
-	mac2 := netutils.GenerateRandomMAC()
93
-	if bytes.Equal(mac1, mac2) {
94
-		t.Fatalf("Generated twice the same MAC address %v", mac1)
95
-	}
96
-}
97 1
deleted file mode 100644
... ...
@@ -1,470 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"context"
7
-	"errors"
8
-	"fmt"
9
-	"net"
10
-
11
-	"github.com/containerd/containerd/log"
12
-	"github.com/docker/docker/libnetwork/iptables"
13
-	"github.com/docker/docker/libnetwork/types"
14
-	"github.com/vishvananda/netlink"
15
-)
16
-
17
-// DockerChain: DOCKER iptable chain name
18
-const (
19
-	DockerChain = "DOCKER"
20
-
21
-	// Isolation between bridge networks is achieved in two stages by means
22
-	// of the following two chains in the filter table. The first chain matches
23
-	// on the source interface being a bridge network's bridge and the
24
-	// destination being a different interface. A positive match leads to the
25
-	// second isolation chain. No match returns to the parent chain. The second
26
-	// isolation chain matches on destination interface being a bridge network's
27
-	// bridge. A positive match identifies a packet originated from one bridge
28
-	// network's bridge destined to another bridge network's bridge and will
29
-	// result in the packet being dropped. No match returns to the parent chain.
30
-
31
-	IsolationChain1 = "DOCKER-ISOLATION-STAGE-1"
32
-	IsolationChain2 = "DOCKER-ISOLATION-STAGE-2"
33
-)
34
-
35
-func setupIPChains(config configuration, version iptables.IPVersion) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
36
-	// Sanity check.
37
-	if !config.EnableIPTables {
38
-		return nil, nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled")
39
-	}
40
-
41
-	hairpinMode := !config.EnableUserlandProxy
42
-
43
-	iptable := iptables.GetIptable(version)
44
-
45
-	natChain, err := iptable.NewChain(DockerChain, iptables.Nat, hairpinMode)
46
-	if err != nil {
47
-		return nil, nil, nil, nil, fmt.Errorf("failed to create NAT chain %s: %v", DockerChain, err)
48
-	}
49
-	defer func() {
50
-		if err != nil {
51
-			if err := iptable.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
52
-				log.G(context.TODO()).Warnf("failed on removing iptables NAT chain %s on cleanup: %v", DockerChain, err)
53
-			}
54
-		}
55
-	}()
56
-
57
-	filterChain, err := iptable.NewChain(DockerChain, iptables.Filter, false)
58
-	if err != nil {
59
-		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER chain %s: %v", DockerChain, err)
60
-	}
61
-	defer func() {
62
-		if err != nil {
63
-			if err := iptable.RemoveExistingChain(DockerChain, iptables.Filter); err != nil {
64
-				log.G(context.TODO()).Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", DockerChain, err)
65
-			}
66
-		}
67
-	}()
68
-
69
-	isolationChain1, err := iptable.NewChain(IsolationChain1, iptables.Filter, false)
70
-	if err != nil {
71
-		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
72
-	}
73
-	defer func() {
74
-		if err != nil {
75
-			if err := iptable.RemoveExistingChain(IsolationChain1, iptables.Filter); err != nil {
76
-				log.G(context.TODO()).Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain1, err)
77
-			}
78
-		}
79
-	}()
80
-
81
-	isolationChain2, err := iptable.NewChain(IsolationChain2, iptables.Filter, false)
82
-	if err != nil {
83
-		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
84
-	}
85
-	defer func() {
86
-		if err != nil {
87
-			if err := iptable.RemoveExistingChain(IsolationChain2, iptables.Filter); err != nil {
88
-				log.G(context.TODO()).Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain2, err)
89
-			}
90
-		}
91
-	}()
92
-
93
-	if err := iptable.AddReturnRule(IsolationChain1); err != nil {
94
-		return nil, nil, nil, nil, err
95
-	}
96
-
97
-	if err := iptable.AddReturnRule(IsolationChain2); err != nil {
98
-		return nil, nil, nil, nil, err
99
-	}
100
-
101
-	return natChain, filterChain, isolationChain1, isolationChain2, nil
102
-}
103
-
104
-func (n *bridgeNetwork) setupIP4Tables(config *networkConfiguration, i *bridgeInterface) error {
105
-	d := n.driver
106
-	d.Lock()
107
-	driverConfig := d.config
108
-	d.Unlock()
109
-
110
-	// Sanity check.
111
-	if !driverConfig.EnableIPTables {
112
-		return errors.New("Cannot program chains, EnableIPTable is disabled")
113
-	}
114
-
115
-	maskedAddrv4 := &net.IPNet{
116
-		IP:   i.bridgeIPv4.IP.Mask(i.bridgeIPv4.Mask),
117
-		Mask: i.bridgeIPv4.Mask,
118
-	}
119
-	return n.setupIPTables(iptables.IPv4, maskedAddrv4, config, i)
120
-}
121
-
122
-func (n *bridgeNetwork) setupIP6Tables(config *networkConfiguration, i *bridgeInterface) error {
123
-	d := n.driver
124
-	d.Lock()
125
-	driverConfig := d.config
126
-	d.Unlock()
127
-
128
-	// Sanity check.
129
-	if !driverConfig.EnableIP6Tables {
130
-		return errors.New("Cannot program chains, EnableIP6Tables is disabled")
131
-	}
132
-
133
-	maskedAddrv6 := &net.IPNet{
134
-		IP:   i.bridgeIPv6.IP.Mask(i.bridgeIPv6.Mask),
135
-		Mask: i.bridgeIPv6.Mask,
136
-	}
137
-
138
-	return n.setupIPTables(iptables.IPv6, maskedAddrv6, config, i)
139
-}
140
-
141
-func (n *bridgeNetwork) setupIPTables(ipVersion iptables.IPVersion, maskedAddr *net.IPNet, config *networkConfiguration, i *bridgeInterface) error {
142
-	var err error
143
-
144
-	d := n.driver
145
-	d.Lock()
146
-	driverConfig := d.config
147
-	d.Unlock()
148
-
149
-	// Pickup this configuration option from driver
150
-	hairpinMode := !driverConfig.EnableUserlandProxy
151
-
152
-	iptable := iptables.GetIptable(ipVersion)
153
-
154
-	if config.Internal {
155
-		if err = setupInternalNetworkRules(config.BridgeName, maskedAddr, config.EnableICC, true); err != nil {
156
-			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
157
-		}
158
-		n.registerIptCleanFunc(func() error {
159
-			return setupInternalNetworkRules(config.BridgeName, maskedAddr, config.EnableICC, false)
160
-		})
161
-	} else {
162
-		if err = setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddr, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
163
-			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
164
-		}
165
-		n.registerIptCleanFunc(func() error {
166
-			return setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddr, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
167
-		})
168
-		natChain, filterChain, _, _, err := n.getDriverChains(ipVersion)
169
-		if err != nil {
170
-			return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
171
-		}
172
-
173
-		err = iptable.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
174
-		if err != nil {
175
-			return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
176
-		}
177
-
178
-		err = iptable.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
179
-		if err != nil {
180
-			return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
181
-		}
182
-
183
-		n.registerIptCleanFunc(func() error {
184
-			return iptable.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
185
-		})
186
-
187
-		if ipVersion == iptables.IPv4 {
188
-			n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName())
189
-		} else {
190
-			n.portMapperV6.SetIptablesChain(natChain, n.getNetworkBridgeName())
191
-		}
192
-	}
193
-
194
-	d.Lock()
195
-	err = iptable.EnsureJumpRule("FORWARD", IsolationChain1)
196
-	d.Unlock()
197
-	return err
198
-}
199
-
200
-type iptRule struct {
201
-	table   iptables.Table
202
-	chain   string
203
-	preArgs []string
204
-	args    []string
205
-}
206
-
207
-func setupIPTablesInternal(hostIP net.IP, bridgeIface string, addr *net.IPNet, icc, ipmasq, hairpin, enable bool) error {
208
-	var (
209
-		address   = addr.String()
210
-		skipDNAT  = iptRule{table: iptables.Nat, chain: DockerChain, preArgs: []string{"-t", "nat"}, args: []string{"-i", bridgeIface, "-j", "RETURN"}}
211
-		outRule   = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}}
212
-		natArgs   []string
213
-		hpNatArgs []string
214
-	)
215
-	// if hostIP is set use this address as the src-ip during SNAT
216
-	if hostIP != nil {
217
-		hostAddr := hostIP.String()
218
-		natArgs = []string{"-s", address, "!", "-o", bridgeIface, "-j", "SNAT", "--to-source", hostAddr}
219
-		hpNatArgs = []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "SNAT", "--to-source", hostAddr}
220
-		// Else use MASQUERADE which picks the src-ip based on NH from the route table
221
-	} else {
222
-		natArgs = []string{"-s", address, "!", "-o", bridgeIface, "-j", "MASQUERADE"}
223
-		hpNatArgs = []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "MASQUERADE"}
224
-	}
225
-
226
-	natRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: natArgs}
227
-	hpNatRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: hpNatArgs}
228
-
229
-	ipVer := iptables.IPv4
230
-	if addr.IP.To4() == nil {
231
-		ipVer = iptables.IPv6
232
-	}
233
-
234
-	// Set NAT.
235
-	if ipmasq {
236
-		if err := programChainRule(ipVer, natRule, "NAT", enable); err != nil {
237
-			return err
238
-		}
239
-	}
240
-
241
-	if ipmasq && !hairpin {
242
-		if err := programChainRule(ipVer, skipDNAT, "SKIP DNAT", enable); err != nil {
243
-			return err
244
-		}
245
-	}
246
-
247
-	// In hairpin mode, masquerade traffic from localhost. If hairpin is disabled or if we're tearing down
248
-	// that bridge, make sure the iptables rule isn't lying around.
249
-	if err := programChainRule(ipVer, hpNatRule, "MASQ LOCAL HOST", enable && hairpin); err != nil {
250
-		return err
251
-	}
252
-
253
-	// Set Inter Container Communication.
254
-	if err := setIcc(ipVer, bridgeIface, icc, enable); err != nil {
255
-		return err
256
-	}
257
-
258
-	// Set Accept on all non-intercontainer outgoing packets.
259
-	return programChainRule(ipVer, outRule, "ACCEPT NON_ICC OUTGOING", enable)
260
-}
261
-
262
-func programChainRule(version iptables.IPVersion, rule iptRule, ruleDescr string, insert bool) error {
263
-	iptable := iptables.GetIptable(version)
264
-
265
-	var (
266
-		prefix    []string
267
-		operation string
268
-		condition bool
269
-		doesExist = iptable.Exists(rule.table, rule.chain, rule.args...)
270
-	)
271
-
272
-	if insert {
273
-		condition = !doesExist
274
-		prefix = []string{"-I", rule.chain}
275
-		operation = "enable"
276
-	} else {
277
-		condition = doesExist
278
-		prefix = []string{"-D", rule.chain}
279
-		operation = "disable"
280
-	}
281
-	if rule.preArgs != nil {
282
-		prefix = append(rule.preArgs, prefix...)
283
-	}
284
-
285
-	if condition {
286
-		if err := iptable.RawCombinedOutput(append(prefix, rule.args...)...); err != nil {
287
-			return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error())
288
-		}
289
-	}
290
-
291
-	return nil
292
-}
293
-
294
-func setIcc(version iptables.IPVersion, bridgeIface string, iccEnable, insert bool) error {
295
-	iptable := iptables.GetIptable(version)
296
-	var (
297
-		table      = iptables.Filter
298
-		chain      = "FORWARD"
299
-		args       = []string{"-i", bridgeIface, "-o", bridgeIface, "-j"}
300
-		acceptArgs = append(args, "ACCEPT")
301
-		dropArgs   = append(args, "DROP")
302
-	)
303
-
304
-	if insert {
305
-		if !iccEnable {
306
-			iptable.Raw(append([]string{"-D", chain}, acceptArgs...)...)
307
-
308
-			if !iptable.Exists(table, chain, dropArgs...) {
309
-				if err := iptable.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil {
310
-					return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error())
311
-				}
312
-			}
313
-		} else {
314
-			iptable.Raw(append([]string{"-D", chain}, dropArgs...)...)
315
-
316
-			if !iptable.Exists(table, chain, acceptArgs...) {
317
-				if err := iptable.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil {
318
-					return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error())
319
-				}
320
-			}
321
-		}
322
-	} else {
323
-		// Remove any ICC rule.
324
-		if !iccEnable {
325
-			if iptable.Exists(table, chain, dropArgs...) {
326
-				iptable.Raw(append([]string{"-D", chain}, dropArgs...)...)
327
-			}
328
-		} else {
329
-			if iptable.Exists(table, chain, acceptArgs...) {
330
-				iptable.Raw(append([]string{"-D", chain}, acceptArgs...)...)
331
-			}
332
-		}
333
-	}
334
-
335
-	return nil
336
-}
337
-
338
-// Control Inter Network Communication. Install[Remove] only if it is [not] present.
339
-func setINC(version iptables.IPVersion, iface string, enable bool) error {
340
-	iptable := iptables.GetIptable(version)
341
-	var (
342
-		action    = iptables.Insert
343
-		actionMsg = "add"
344
-		chains    = []string{IsolationChain1, IsolationChain2}
345
-		rules     = [][]string{
346
-			{"-i", iface, "!", "-o", iface, "-j", IsolationChain2},
347
-			{"-o", iface, "-j", "DROP"},
348
-		}
349
-	)
350
-
351
-	if !enable {
352
-		action = iptables.Delete
353
-		actionMsg = "remove"
354
-	}
355
-
356
-	for i, chain := range chains {
357
-		if err := iptable.ProgramRule(iptables.Filter, chain, action, rules[i]); err != nil {
358
-			msg := fmt.Sprintf("unable to %s inter-network communication rule: %v", actionMsg, err)
359
-			if enable {
360
-				if i == 1 {
361
-					// Rollback the rule installed on first chain
362
-					if err2 := iptable.ProgramRule(iptables.Filter, chains[0], iptables.Delete, rules[0]); err2 != nil {
363
-						log.G(context.TODO()).Warnf("Failed to rollback iptables rule after failure (%v): %v", err, err2)
364
-					}
365
-				}
366
-				return fmt.Errorf(msg)
367
-			}
368
-			log.G(context.TODO()).Warn(msg)
369
-		}
370
-	}
371
-
372
-	return nil
373
-}
374
-
375
-// Obsolete chain from previous docker versions
376
-const oldIsolationChain = "DOCKER-ISOLATION"
377
-
378
-func removeIPChains(version iptables.IPVersion) {
379
-	ipt := iptables.GetIptable(version)
380
-
381
-	// Remove obsolete rules from default chains
382
-	ipt.ProgramRule(iptables.Filter, "FORWARD", iptables.Delete, []string{"-j", oldIsolationChain})
383
-
384
-	// Remove chains
385
-	for _, chainInfo := range []iptables.ChainInfo{
386
-		{Name: DockerChain, Table: iptables.Nat, IPVersion: version},
387
-		{Name: DockerChain, Table: iptables.Filter, IPVersion: version},
388
-		{Name: IsolationChain1, Table: iptables.Filter, IPVersion: version},
389
-		{Name: IsolationChain2, Table: iptables.Filter, IPVersion: version},
390
-		{Name: oldIsolationChain, Table: iptables.Filter, IPVersion: version},
391
-	} {
392
-		if err := chainInfo.Remove(); err != nil {
393
-			log.G(context.TODO()).Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
394
-		}
395
-	}
396
-}
397
-
398
-func setupInternalNetworkRules(bridgeIface string, addr *net.IPNet, icc, insert bool) error {
399
-	var version iptables.IPVersion
400
-	var inDropRule, outDropRule iptRule
401
-
402
-	if addr.IP.To4() != nil {
403
-		version = iptables.IPv4
404
-		inDropRule = iptRule{
405
-			table: iptables.Filter,
406
-			chain: IsolationChain1,
407
-			args:  []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"},
408
-		}
409
-		outDropRule = iptRule{
410
-			table: iptables.Filter,
411
-			chain: IsolationChain1,
412
-			args:  []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"},
413
-		}
414
-	} else {
415
-		version = iptables.IPv6
416
-		inDropRule = iptRule{
417
-			table: iptables.Filter,
418
-			chain: IsolationChain1,
419
-			args:  []string{"-i", bridgeIface, "!", "-o", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"},
420
-		}
421
-		outDropRule = iptRule{
422
-			table: iptables.Filter,
423
-			chain: IsolationChain1,
424
-			args:  []string{"!", "-i", bridgeIface, "-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"},
425
-		}
426
-	}
427
-
428
-	if err := programChainRule(version, inDropRule, "DROP INCOMING", insert); err != nil {
429
-		return err
430
-	}
431
-	if err := programChainRule(version, outDropRule, "DROP OUTGOING", insert); err != nil {
432
-		return err
433
-	}
434
-
435
-	// Set Inter Container Communication.
436
-	return setIcc(version, bridgeIface, icc, insert)
437
-}
438
-
439
-// clearConntrackEntries flushes conntrack entries matching endpoint IP address
440
-// or matching one of the exposed UDP port.
441
-// In the first case, this could happen if packets were received by the host
442
-// between userland proxy startup and iptables setup.
443
-// In the latter case, this could happen if packets were received whereas there
444
-// were nowhere to route them, as netfilter creates entries in such case.
445
-// This is required because iptables NAT rules are evaluated by netfilter only
446
-// when creating a new conntrack entry. When Docker latter adds NAT rules,
447
-// netfilter ignore them for any packet matching a pre-existing conntrack entry.
448
-// As such, we need to flush all those conntrack entries to make sure NAT rules
449
-// are correctly applied to all packets.
450
-// See: #8795, #44688 & #44742.
451
-func clearConntrackEntries(nlh *netlink.Handle, ep *bridgeEndpoint) {
452
-	var ipv4List []net.IP
453
-	var ipv6List []net.IP
454
-	var udpPorts []uint16
455
-
456
-	if ep.addr != nil {
457
-		ipv4List = append(ipv4List, ep.addr.IP)
458
-	}
459
-	if ep.addrv6 != nil {
460
-		ipv6List = append(ipv6List, ep.addrv6.IP)
461
-	}
462
-	for _, pb := range ep.portMapping {
463
-		if pb.Proto == types.UDP {
464
-			udpPorts = append(udpPorts, pb.HostPort)
465
-		}
466
-	}
467
-
468
-	iptables.DeleteConntrackEntries(nlh, ipv4List, ipv6List)
469
-	iptables.DeleteConntrackEntriesByPort(nlh, types.UDP, udpPorts)
470
-}
471 1
new file mode 100644
... ...
@@ -0,0 +1,468 @@
0
+package bridge
1
+
2
+import (
3
+	"context"
4
+	"errors"
5
+	"fmt"
6
+	"net"
7
+
8
+	"github.com/containerd/containerd/log"
9
+	"github.com/docker/docker/libnetwork/iptables"
10
+	"github.com/docker/docker/libnetwork/types"
11
+	"github.com/vishvananda/netlink"
12
+)
13
+
14
+// DockerChain: DOCKER iptable chain name
15
+const (
16
+	DockerChain = "DOCKER"
17
+
18
+	// Isolation between bridge networks is achieved in two stages by means
19
+	// of the following two chains in the filter table. The first chain matches
20
+	// on the source interface being a bridge network's bridge and the
21
+	// destination being a different interface. A positive match leads to the
22
+	// second isolation chain. No match returns to the parent chain. The second
23
+	// isolation chain matches on destination interface being a bridge network's
24
+	// bridge. A positive match identifies a packet originated from one bridge
25
+	// network's bridge destined to another bridge network's bridge and will
26
+	// result in the packet being dropped. No match returns to the parent chain.
27
+
28
+	IsolationChain1 = "DOCKER-ISOLATION-STAGE-1"
29
+	IsolationChain2 = "DOCKER-ISOLATION-STAGE-2"
30
+)
31
+
32
+func setupIPChains(config configuration, version iptables.IPVersion) (*iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, *iptables.ChainInfo, error) {
33
+	// Sanity check.
34
+	if !config.EnableIPTables {
35
+		return nil, nil, nil, nil, errors.New("cannot create new chains, EnableIPTable is disabled")
36
+	}
37
+
38
+	hairpinMode := !config.EnableUserlandProxy
39
+
40
+	iptable := iptables.GetIptable(version)
41
+
42
+	natChain, err := iptable.NewChain(DockerChain, iptables.Nat, hairpinMode)
43
+	if err != nil {
44
+		return nil, nil, nil, nil, fmt.Errorf("failed to create NAT chain %s: %v", DockerChain, err)
45
+	}
46
+	defer func() {
47
+		if err != nil {
48
+			if err := iptable.RemoveExistingChain(DockerChain, iptables.Nat); err != nil {
49
+				log.G(context.TODO()).Warnf("failed on removing iptables NAT chain %s on cleanup: %v", DockerChain, err)
50
+			}
51
+		}
52
+	}()
53
+
54
+	filterChain, err := iptable.NewChain(DockerChain, iptables.Filter, false)
55
+	if err != nil {
56
+		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER chain %s: %v", DockerChain, err)
57
+	}
58
+	defer func() {
59
+		if err != nil {
60
+			if err := iptable.RemoveExistingChain(DockerChain, iptables.Filter); err != nil {
61
+				log.G(context.TODO()).Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", DockerChain, err)
62
+			}
63
+		}
64
+	}()
65
+
66
+	isolationChain1, err := iptable.NewChain(IsolationChain1, iptables.Filter, false)
67
+	if err != nil {
68
+		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
69
+	}
70
+	defer func() {
71
+		if err != nil {
72
+			if err := iptable.RemoveExistingChain(IsolationChain1, iptables.Filter); err != nil {
73
+				log.G(context.TODO()).Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain1, err)
74
+			}
75
+		}
76
+	}()
77
+
78
+	isolationChain2, err := iptable.NewChain(IsolationChain2, iptables.Filter, false)
79
+	if err != nil {
80
+		return nil, nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err)
81
+	}
82
+	defer func() {
83
+		if err != nil {
84
+			if err := iptable.RemoveExistingChain(IsolationChain2, iptables.Filter); err != nil {
85
+				log.G(context.TODO()).Warnf("failed on removing iptables FILTER chain %s on cleanup: %v", IsolationChain2, err)
86
+			}
87
+		}
88
+	}()
89
+
90
+	if err := iptable.AddReturnRule(IsolationChain1); err != nil {
91
+		return nil, nil, nil, nil, err
92
+	}
93
+
94
+	if err := iptable.AddReturnRule(IsolationChain2); err != nil {
95
+		return nil, nil, nil, nil, err
96
+	}
97
+
98
+	return natChain, filterChain, isolationChain1, isolationChain2, nil
99
+}
100
+
101
+func (n *bridgeNetwork) setupIP4Tables(config *networkConfiguration, i *bridgeInterface) error {
102
+	d := n.driver
103
+	d.Lock()
104
+	driverConfig := d.config
105
+	d.Unlock()
106
+
107
+	// Sanity check.
108
+	if !driverConfig.EnableIPTables {
109
+		return errors.New("Cannot program chains, EnableIPTable is disabled")
110
+	}
111
+
112
+	maskedAddrv4 := &net.IPNet{
113
+		IP:   i.bridgeIPv4.IP.Mask(i.bridgeIPv4.Mask),
114
+		Mask: i.bridgeIPv4.Mask,
115
+	}
116
+	return n.setupIPTables(iptables.IPv4, maskedAddrv4, config, i)
117
+}
118
+
119
+func (n *bridgeNetwork) setupIP6Tables(config *networkConfiguration, i *bridgeInterface) error {
120
+	d := n.driver
121
+	d.Lock()
122
+	driverConfig := d.config
123
+	d.Unlock()
124
+
125
+	// Sanity check.
126
+	if !driverConfig.EnableIP6Tables {
127
+		return errors.New("Cannot program chains, EnableIP6Tables is disabled")
128
+	}
129
+
130
+	maskedAddrv6 := &net.IPNet{
131
+		IP:   i.bridgeIPv6.IP.Mask(i.bridgeIPv6.Mask),
132
+		Mask: i.bridgeIPv6.Mask,
133
+	}
134
+
135
+	return n.setupIPTables(iptables.IPv6, maskedAddrv6, config, i)
136
+}
137
+
138
+func (n *bridgeNetwork) setupIPTables(ipVersion iptables.IPVersion, maskedAddr *net.IPNet, config *networkConfiguration, i *bridgeInterface) error {
139
+	var err error
140
+
141
+	d := n.driver
142
+	d.Lock()
143
+	driverConfig := d.config
144
+	d.Unlock()
145
+
146
+	// Pickup this configuration option from driver
147
+	hairpinMode := !driverConfig.EnableUserlandProxy
148
+
149
+	iptable := iptables.GetIptable(ipVersion)
150
+
151
+	if config.Internal {
152
+		if err = setupInternalNetworkRules(config.BridgeName, maskedAddr, config.EnableICC, true); err != nil {
153
+			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
154
+		}
155
+		n.registerIptCleanFunc(func() error {
156
+			return setupInternalNetworkRules(config.BridgeName, maskedAddr, config.EnableICC, false)
157
+		})
158
+	} else {
159
+		if err = setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddr, config.EnableICC, config.EnableIPMasquerade, hairpinMode, true); err != nil {
160
+			return fmt.Errorf("Failed to Setup IP tables: %s", err.Error())
161
+		}
162
+		n.registerIptCleanFunc(func() error {
163
+			return setupIPTablesInternal(config.HostIP, config.BridgeName, maskedAddr, config.EnableICC, config.EnableIPMasquerade, hairpinMode, false)
164
+		})
165
+		natChain, filterChain, _, _, err := n.getDriverChains(ipVersion)
166
+		if err != nil {
167
+			return fmt.Errorf("Failed to setup IP tables, cannot acquire chain info %s", err.Error())
168
+		}
169
+
170
+		err = iptable.ProgramChain(natChain, config.BridgeName, hairpinMode, true)
171
+		if err != nil {
172
+			return fmt.Errorf("Failed to program NAT chain: %s", err.Error())
173
+		}
174
+
175
+		err = iptable.ProgramChain(filterChain, config.BridgeName, hairpinMode, true)
176
+		if err != nil {
177
+			return fmt.Errorf("Failed to program FILTER chain: %s", err.Error())
178
+		}
179
+
180
+		n.registerIptCleanFunc(func() error {
181
+			return iptable.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
182
+		})
183
+
184
+		if ipVersion == iptables.IPv4 {
185
+			n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName())
186
+		} else {
187
+			n.portMapperV6.SetIptablesChain(natChain, n.getNetworkBridgeName())
188
+		}
189
+	}
190
+
191
+	d.Lock()
192
+	err = iptable.EnsureJumpRule("FORWARD", IsolationChain1)
193
+	d.Unlock()
194
+	return err
195
+}
196
+
197
+type iptRule struct {
198
+	table   iptables.Table
199
+	chain   string
200
+	preArgs []string
201
+	args    []string
202
+}
203
+
204
+func setupIPTablesInternal(hostIP net.IP, bridgeIface string, addr *net.IPNet, icc, ipmasq, hairpin, enable bool) error {
205
+	var (
206
+		address   = addr.String()
207
+		skipDNAT  = iptRule{table: iptables.Nat, chain: DockerChain, preArgs: []string{"-t", "nat"}, args: []string{"-i", bridgeIface, "-j", "RETURN"}}
208
+		outRule   = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}}
209
+		natArgs   []string
210
+		hpNatArgs []string
211
+	)
212
+	// if hostIP is set use this address as the src-ip during SNAT
213
+	if hostIP != nil {
214
+		hostAddr := hostIP.String()
215
+		natArgs = []string{"-s", address, "!", "-o", bridgeIface, "-j", "SNAT", "--to-source", hostAddr}
216
+		hpNatArgs = []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "SNAT", "--to-source", hostAddr}
217
+		// Else use MASQUERADE which picks the src-ip based on NH from the route table
218
+	} else {
219
+		natArgs = []string{"-s", address, "!", "-o", bridgeIface, "-j", "MASQUERADE"}
220
+		hpNatArgs = []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "MASQUERADE"}
221
+	}
222
+
223
+	natRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: natArgs}
224
+	hpNatRule := iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: hpNatArgs}
225
+
226
+	ipVer := iptables.IPv4
227
+	if addr.IP.To4() == nil {
228
+		ipVer = iptables.IPv6
229
+	}
230
+
231
+	// Set NAT.
232
+	if ipmasq {
233
+		if err := programChainRule(ipVer, natRule, "NAT", enable); err != nil {
234
+			return err
235
+		}
236
+	}
237
+
238
+	if ipmasq && !hairpin {
239
+		if err := programChainRule(ipVer, skipDNAT, "SKIP DNAT", enable); err != nil {
240
+			return err
241
+		}
242
+	}
243
+
244
+	// In hairpin mode, masquerade traffic from localhost. If hairpin is disabled or if we're tearing down
245
+	// that bridge, make sure the iptables rule isn't lying around.
246
+	if err := programChainRule(ipVer, hpNatRule, "MASQ LOCAL HOST", enable && hairpin); err != nil {
247
+		return err
248
+	}
249
+
250
+	// Set Inter Container Communication.
251
+	if err := setIcc(ipVer, bridgeIface, icc, enable); err != nil {
252
+		return err
253
+	}
254
+
255
+	// Set Accept on all non-intercontainer outgoing packets.
256
+	return programChainRule(ipVer, outRule, "ACCEPT NON_ICC OUTGOING", enable)
257
+}
258
+
259
+func programChainRule(version iptables.IPVersion, rule iptRule, ruleDescr string, insert bool) error {
260
+	iptable := iptables.GetIptable(version)
261
+
262
+	var (
263
+		prefix    []string
264
+		operation string
265
+		condition bool
266
+		doesExist = iptable.Exists(rule.table, rule.chain, rule.args...)
267
+	)
268
+
269
+	if insert {
270
+		condition = !doesExist
271
+		prefix = []string{"-I", rule.chain}
272
+		operation = "enable"
273
+	} else {
274
+		condition = doesExist
275
+		prefix = []string{"-D", rule.chain}
276
+		operation = "disable"
277
+	}
278
+	if rule.preArgs != nil {
279
+		prefix = append(rule.preArgs, prefix...)
280
+	}
281
+
282
+	if condition {
283
+		if err := iptable.RawCombinedOutput(append(prefix, rule.args...)...); err != nil {
284
+			return fmt.Errorf("Unable to %s %s rule: %s", operation, ruleDescr, err.Error())
285
+		}
286
+	}
287
+
288
+	return nil
289
+}
290
+
291
+func setIcc(version iptables.IPVersion, bridgeIface string, iccEnable, insert bool) error {
292
+	iptable := iptables.GetIptable(version)
293
+	var (
294
+		table      = iptables.Filter
295
+		chain      = "FORWARD"
296
+		args       = []string{"-i", bridgeIface, "-o", bridgeIface, "-j"}
297
+		acceptArgs = append(args, "ACCEPT")
298
+		dropArgs   = append(args, "DROP")
299
+	)
300
+
301
+	if insert {
302
+		if !iccEnable {
303
+			iptable.Raw(append([]string{"-D", chain}, acceptArgs...)...)
304
+
305
+			if !iptable.Exists(table, chain, dropArgs...) {
306
+				if err := iptable.RawCombinedOutput(append([]string{"-A", chain}, dropArgs...)...); err != nil {
307
+					return fmt.Errorf("Unable to prevent intercontainer communication: %s", err.Error())
308
+				}
309
+			}
310
+		} else {
311
+			iptable.Raw(append([]string{"-D", chain}, dropArgs...)...)
312
+
313
+			if !iptable.Exists(table, chain, acceptArgs...) {
314
+				if err := iptable.RawCombinedOutput(append([]string{"-I", chain}, acceptArgs...)...); err != nil {
315
+					return fmt.Errorf("Unable to allow intercontainer communication: %s", err.Error())
316
+				}
317
+			}
318
+		}
319
+	} else {
320
+		// Remove any ICC rule.
321
+		if !iccEnable {
322
+			if iptable.Exists(table, chain, dropArgs...) {
323
+				iptable.Raw(append([]string{"-D", chain}, dropArgs...)...)
324
+			}
325
+		} else {
326
+			if iptable.Exists(table, chain, acceptArgs...) {
327
+				iptable.Raw(append([]string{"-D", chain}, acceptArgs...)...)
328
+			}
329
+		}
330
+	}
331
+
332
+	return nil
333
+}
334
+
335
+// Control Inter Network Communication. Install[Remove] only if it is [not] present.
336
+func setINC(version iptables.IPVersion, iface string, enable bool) error {
337
+	iptable := iptables.GetIptable(version)
338
+	var (
339
+		action    = iptables.Insert
340
+		actionMsg = "add"
341
+		chains    = []string{IsolationChain1, IsolationChain2}
342
+		rules     = [][]string{
343
+			{"-i", iface, "!", "-o", iface, "-j", IsolationChain2},
344
+			{"-o", iface, "-j", "DROP"},
345
+		}
346
+	)
347
+
348
+	if !enable {
349
+		action = iptables.Delete
350
+		actionMsg = "remove"
351
+	}
352
+
353
+	for i, chain := range chains {
354
+		if err := iptable.ProgramRule(iptables.Filter, chain, action, rules[i]); err != nil {
355
+			msg := fmt.Sprintf("unable to %s inter-network communication rule: %v", actionMsg, err)
356
+			if enable {
357
+				if i == 1 {
358
+					// Rollback the rule installed on first chain
359
+					if err2 := iptable.ProgramRule(iptables.Filter, chains[0], iptables.Delete, rules[0]); err2 != nil {
360
+						log.G(context.TODO()).Warnf("Failed to rollback iptables rule after failure (%v): %v", err, err2)
361
+					}
362
+				}
363
+				return fmt.Errorf(msg)
364
+			}
365
+			log.G(context.TODO()).Warn(msg)
366
+		}
367
+	}
368
+
369
+	return nil
370
+}
371
+
372
+// Obsolete chain from previous docker versions
373
+const oldIsolationChain = "DOCKER-ISOLATION"
374
+
375
+func removeIPChains(version iptables.IPVersion) {
376
+	ipt := iptables.GetIptable(version)
377
+
378
+	// Remove obsolete rules from default chains
379
+	ipt.ProgramRule(iptables.Filter, "FORWARD", iptables.Delete, []string{"-j", oldIsolationChain})
380
+
381
+	// Remove chains
382
+	for _, chainInfo := range []iptables.ChainInfo{
383
+		{Name: DockerChain, Table: iptables.Nat, IPVersion: version},
384
+		{Name: DockerChain, Table: iptables.Filter, IPVersion: version},
385
+		{Name: IsolationChain1, Table: iptables.Filter, IPVersion: version},
386
+		{Name: IsolationChain2, Table: iptables.Filter, IPVersion: version},
387
+		{Name: oldIsolationChain, Table: iptables.Filter, IPVersion: version},
388
+	} {
389
+		if err := chainInfo.Remove(); err != nil {
390
+			log.G(context.TODO()).Warnf("Failed to remove existing iptables entries in table %s chain %s : %v", chainInfo.Table, chainInfo.Name, err)
391
+		}
392
+	}
393
+}
394
+
395
+func setupInternalNetworkRules(bridgeIface string, addr *net.IPNet, icc, insert bool) error {
396
+	var version iptables.IPVersion
397
+	var inDropRule, outDropRule iptRule
398
+
399
+	if addr.IP.To4() != nil {
400
+		version = iptables.IPv4
401
+		inDropRule = iptRule{
402
+			table: iptables.Filter,
403
+			chain: IsolationChain1,
404
+			args:  []string{"-i", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"},
405
+		}
406
+		outDropRule = iptRule{
407
+			table: iptables.Filter,
408
+			chain: IsolationChain1,
409
+			args:  []string{"-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"},
410
+		}
411
+	} else {
412
+		version = iptables.IPv6
413
+		inDropRule = iptRule{
414
+			table: iptables.Filter,
415
+			chain: IsolationChain1,
416
+			args:  []string{"-i", bridgeIface, "!", "-o", bridgeIface, "!", "-d", addr.String(), "-j", "DROP"},
417
+		}
418
+		outDropRule = iptRule{
419
+			table: iptables.Filter,
420
+			chain: IsolationChain1,
421
+			args:  []string{"!", "-i", bridgeIface, "-o", bridgeIface, "!", "-s", addr.String(), "-j", "DROP"},
422
+		}
423
+	}
424
+
425
+	if err := programChainRule(version, inDropRule, "DROP INCOMING", insert); err != nil {
426
+		return err
427
+	}
428
+	if err := programChainRule(version, outDropRule, "DROP OUTGOING", insert); err != nil {
429
+		return err
430
+	}
431
+
432
+	// Set Inter Container Communication.
433
+	return setIcc(version, bridgeIface, icc, insert)
434
+}
435
+
436
+// clearConntrackEntries flushes conntrack entries matching endpoint IP address
437
+// or matching one of the exposed UDP port.
438
+// In the first case, this could happen if packets were received by the host
439
+// between userland proxy startup and iptables setup.
440
+// In the latter case, this could happen if packets were received whereas there
441
+// were nowhere to route them, as netfilter creates entries in such case.
442
+// This is required because iptables NAT rules are evaluated by netfilter only
443
+// when creating a new conntrack entry. When Docker latter adds NAT rules,
444
+// netfilter ignore them for any packet matching a pre-existing conntrack entry.
445
+// As such, we need to flush all those conntrack entries to make sure NAT rules
446
+// are correctly applied to all packets.
447
+// See: #8795, #44688 & #44742.
448
+func clearConntrackEntries(nlh *netlink.Handle, ep *bridgeEndpoint) {
449
+	var ipv4List []net.IP
450
+	var ipv6List []net.IP
451
+	var udpPorts []uint16
452
+
453
+	if ep.addr != nil {
454
+		ipv4List = append(ipv4List, ep.addr.IP)
455
+	}
456
+	if ep.addrv6 != nil {
457
+		ipv6List = append(ipv6List, ep.addrv6.IP)
458
+	}
459
+	for _, pb := range ep.portMapping {
460
+		if pb.Proto == types.UDP {
461
+			udpPorts = append(udpPorts, pb.HostPort)
462
+		}
463
+	}
464
+
465
+	iptables.DeleteConntrackEntries(nlh, ipv4List, ipv6List)
466
+	iptables.DeleteConntrackEntriesByPort(nlh, types.UDP, udpPorts)
467
+}
0 468
new file mode 100644
... ...
@@ -0,0 +1,141 @@
0
+package bridge
1
+
2
+import (
3
+	"net"
4
+	"testing"
5
+
6
+	"github.com/docker/docker/internal/testutils/netnsutils"
7
+	"github.com/docker/docker/libnetwork/iptables"
8
+	"github.com/docker/docker/libnetwork/portmapper"
9
+	"github.com/vishvananda/netlink"
10
+)
11
+
12
+const (
13
+	iptablesTestBridgeIP = "192.168.42.1"
14
+)
15
+
16
+func TestProgramIPTable(t *testing.T) {
17
+	// Create a test bridge with a basic bridge configuration (name + IPv4).
18
+	defer netnsutils.SetupTestOSContext(t)()
19
+
20
+	nh, err := netlink.NewHandle()
21
+	if err != nil {
22
+		t.Fatal(err)
23
+	}
24
+
25
+	createTestBridge(getBasicTestConfig(), &bridgeInterface{nlh: nh}, t)
26
+
27
+	// Store various iptables chain rules we care for.
28
+	rules := []struct {
29
+		rule  iptRule
30
+		descr string
31
+	}{
32
+		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-d", "127.1.2.3", "-i", "lo", "-o", "lo", "-j", "DROP"}}, "Test Loopback"},
33
+		{iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", iptablesTestBridgeIP, "!", "-o", DefaultBridgeName, "-j", "MASQUERADE"}}, "NAT Test"},
34
+		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", DefaultBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}, "Test ACCEPT INCOMING"},
35
+		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test ACCEPT NON_ICC OUTGOING"},
36
+		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test enable ICC"},
37
+		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "DROP"}}, "Test disable ICC"},
38
+	}
39
+
40
+	// Assert the chain rules' insertion and removal.
41
+	for _, c := range rules {
42
+		assertIPTableChainProgramming(c.rule, c.descr, t)
43
+	}
44
+}
45
+
46
+func TestSetupIPChains(t *testing.T) {
47
+	// Create a test bridge with a basic bridge configuration (name + IPv4).
48
+	defer netnsutils.SetupTestOSContext(t)()
49
+
50
+	nh, err := netlink.NewHandle()
51
+	if err != nil {
52
+		t.Fatal(err)
53
+	}
54
+
55
+	driverconfig := configuration{
56
+		EnableIPTables: true,
57
+	}
58
+	d := &driver{
59
+		config: driverconfig,
60
+	}
61
+	assertChainConfig(d, t)
62
+
63
+	config := getBasicTestConfig()
64
+	br := &bridgeInterface{nlh: nh}
65
+	createTestBridge(config, br, t)
66
+
67
+	assertBridgeConfig(config, br, d, t)
68
+
69
+	config.EnableIPMasquerade = true
70
+	assertBridgeConfig(config, br, d, t)
71
+
72
+	config.EnableICC = true
73
+	assertBridgeConfig(config, br, d, t)
74
+
75
+	config.EnableIPMasquerade = false
76
+	assertBridgeConfig(config, br, d, t)
77
+}
78
+
79
+func getBasicTestConfig() *networkConfiguration {
80
+	config := &networkConfiguration{
81
+		BridgeName:  DefaultBridgeName,
82
+		AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)},
83
+	}
84
+	return config
85
+}
86
+
87
+func createTestBridge(config *networkConfiguration, br *bridgeInterface, t *testing.T) {
88
+	if err := setupDevice(config, br); err != nil {
89
+		t.Fatalf("Failed to create the testing Bridge: %s", err.Error())
90
+	}
91
+	if err := setupBridgeIPv4(config, br); err != nil {
92
+		t.Fatalf("Failed to bring up the testing Bridge: %s", err.Error())
93
+	}
94
+}
95
+
96
+// Assert base function which pushes iptables chain rules on insertion and removal.
97
+func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) {
98
+	// Add
99
+	if err := programChainRule(iptables.IPv4, rule, descr, true); err != nil {
100
+		t.Fatalf("Failed to program iptable rule %s: %s", descr, err.Error())
101
+	}
102
+
103
+	iptable := iptables.GetIptable(iptables.IPv4)
104
+	if iptable.Exists(rule.table, rule.chain, rule.args...) == false {
105
+		t.Fatalf("Failed to effectively program iptable rule: %s", descr)
106
+	}
107
+
108
+	// Remove
109
+	if err := programChainRule(iptables.IPv4, rule, descr, false); err != nil {
110
+		t.Fatalf("Failed to remove iptable rule %s: %s", descr, err.Error())
111
+	}
112
+	if iptable.Exists(rule.table, rule.chain, rule.args...) == true {
113
+		t.Fatalf("Failed to effectively remove iptable rule: %s", descr)
114
+	}
115
+}
116
+
117
+// Assert function which create chains.
118
+func assertChainConfig(d *driver, t *testing.T) {
119
+	var err error
120
+
121
+	d.natChain, d.filterChain, d.isolationChain1, d.isolationChain2, err = setupIPChains(d.config, iptables.IPv4)
122
+	if err != nil {
123
+		t.Fatal(err)
124
+	}
125
+}
126
+
127
+// Assert function which pushes chains based on bridge config parameters.
128
+func assertBridgeConfig(config *networkConfiguration, br *bridgeInterface, d *driver, t *testing.T) {
129
+	nw := bridgeNetwork{
130
+		portMapper: portmapper.New(""),
131
+		config:     config,
132
+	}
133
+	nw.driver = d
134
+
135
+	// Attempt programming of ip tables.
136
+	err := nw.setupIP4Tables(config, br)
137
+	if err != nil {
138
+		t.Fatalf("%v", err)
139
+	}
140
+}
0 141
deleted file mode 100644
... ...
@@ -1,143 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"net"
7
-	"testing"
8
-
9
-	"github.com/docker/docker/internal/testutils/netnsutils"
10
-	"github.com/docker/docker/libnetwork/iptables"
11
-	"github.com/docker/docker/libnetwork/portmapper"
12
-	"github.com/vishvananda/netlink"
13
-)
14
-
15
-const (
16
-	iptablesTestBridgeIP = "192.168.42.1"
17
-)
18
-
19
-func TestProgramIPTable(t *testing.T) {
20
-	// Create a test bridge with a basic bridge configuration (name + IPv4).
21
-	defer netnsutils.SetupTestOSContext(t)()
22
-
23
-	nh, err := netlink.NewHandle()
24
-	if err != nil {
25
-		t.Fatal(err)
26
-	}
27
-
28
-	createTestBridge(getBasicTestConfig(), &bridgeInterface{nlh: nh}, t)
29
-
30
-	// Store various iptables chain rules we care for.
31
-	rules := []struct {
32
-		rule  iptRule
33
-		descr string
34
-	}{
35
-		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-d", "127.1.2.3", "-i", "lo", "-o", "lo", "-j", "DROP"}}, "Test Loopback"},
36
-		{iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-s", iptablesTestBridgeIP, "!", "-o", DefaultBridgeName, "-j", "MASQUERADE"}}, "NAT Test"},
37
-		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", DefaultBridgeName, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}, "Test ACCEPT INCOMING"},
38
-		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "!", "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test ACCEPT NON_ICC OUTGOING"},
39
-		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "ACCEPT"}}, "Test enable ICC"},
40
-		{iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", DefaultBridgeName, "-o", DefaultBridgeName, "-j", "DROP"}}, "Test disable ICC"},
41
-	}
42
-
43
-	// Assert the chain rules' insertion and removal.
44
-	for _, c := range rules {
45
-		assertIPTableChainProgramming(c.rule, c.descr, t)
46
-	}
47
-}
48
-
49
-func TestSetupIPChains(t *testing.T) {
50
-	// Create a test bridge with a basic bridge configuration (name + IPv4).
51
-	defer netnsutils.SetupTestOSContext(t)()
52
-
53
-	nh, err := netlink.NewHandle()
54
-	if err != nil {
55
-		t.Fatal(err)
56
-	}
57
-
58
-	driverconfig := configuration{
59
-		EnableIPTables: true,
60
-	}
61
-	d := &driver{
62
-		config: driverconfig,
63
-	}
64
-	assertChainConfig(d, t)
65
-
66
-	config := getBasicTestConfig()
67
-	br := &bridgeInterface{nlh: nh}
68
-	createTestBridge(config, br, t)
69
-
70
-	assertBridgeConfig(config, br, d, t)
71
-
72
-	config.EnableIPMasquerade = true
73
-	assertBridgeConfig(config, br, d, t)
74
-
75
-	config.EnableICC = true
76
-	assertBridgeConfig(config, br, d, t)
77
-
78
-	config.EnableIPMasquerade = false
79
-	assertBridgeConfig(config, br, d, t)
80
-}
81
-
82
-func getBasicTestConfig() *networkConfiguration {
83
-	config := &networkConfiguration{
84
-		BridgeName:  DefaultBridgeName,
85
-		AddressIPv4: &net.IPNet{IP: net.ParseIP(iptablesTestBridgeIP), Mask: net.CIDRMask(16, 32)},
86
-	}
87
-	return config
88
-}
89
-
90
-func createTestBridge(config *networkConfiguration, br *bridgeInterface, t *testing.T) {
91
-	if err := setupDevice(config, br); err != nil {
92
-		t.Fatalf("Failed to create the testing Bridge: %s", err.Error())
93
-	}
94
-	if err := setupBridgeIPv4(config, br); err != nil {
95
-		t.Fatalf("Failed to bring up the testing Bridge: %s", err.Error())
96
-	}
97
-}
98
-
99
-// Assert base function which pushes iptables chain rules on insertion and removal.
100
-func assertIPTableChainProgramming(rule iptRule, descr string, t *testing.T) {
101
-	// Add
102
-	if err := programChainRule(iptables.IPv4, rule, descr, true); err != nil {
103
-		t.Fatalf("Failed to program iptable rule %s: %s", descr, err.Error())
104
-	}
105
-
106
-	iptable := iptables.GetIptable(iptables.IPv4)
107
-	if iptable.Exists(rule.table, rule.chain, rule.args...) == false {
108
-		t.Fatalf("Failed to effectively program iptable rule: %s", descr)
109
-	}
110
-
111
-	// Remove
112
-	if err := programChainRule(iptables.IPv4, rule, descr, false); err != nil {
113
-		t.Fatalf("Failed to remove iptable rule %s: %s", descr, err.Error())
114
-	}
115
-	if iptable.Exists(rule.table, rule.chain, rule.args...) == true {
116
-		t.Fatalf("Failed to effectively remove iptable rule: %s", descr)
117
-	}
118
-}
119
-
120
-// Assert function which create chains.
121
-func assertChainConfig(d *driver, t *testing.T) {
122
-	var err error
123
-
124
-	d.natChain, d.filterChain, d.isolationChain1, d.isolationChain2, err = setupIPChains(d.config, iptables.IPv4)
125
-	if err != nil {
126
-		t.Fatal(err)
127
-	}
128
-}
129
-
130
-// Assert function which pushes chains based on bridge config parameters.
131
-func assertBridgeConfig(config *networkConfiguration, br *bridgeInterface, d *driver, t *testing.T) {
132
-	nw := bridgeNetwork{
133
-		portMapper: portmapper.New(""),
134
-		config:     config,
135
-	}
136
-	nw.driver = d
137
-
138
-	// Attempt programming of ip tables.
139
-	err := nw.setupIP4Tables(config, br)
140
-	if err != nil {
141
-		t.Fatalf("%v", err)
142
-	}
143
-}
144 1
deleted file mode 100644
... ...
@@ -1,85 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"context"
7
-	"errors"
8
-	"fmt"
9
-	"net"
10
-	"os"
11
-	"path/filepath"
12
-
13
-	"github.com/containerd/containerd/log"
14
-	"github.com/docker/docker/libnetwork/types"
15
-	"github.com/vishvananda/netlink"
16
-)
17
-
18
-func selectIPv4Address(addresses []netlink.Addr, selector *net.IPNet) (netlink.Addr, error) {
19
-	if len(addresses) == 0 {
20
-		return netlink.Addr{}, errors.New("unable to select an address as the address pool is empty")
21
-	}
22
-	if selector != nil {
23
-		for _, addr := range addresses {
24
-			if selector.Contains(addr.IP) {
25
-				return addr, nil
26
-			}
27
-		}
28
-	}
29
-	return addresses[0], nil
30
-}
31
-
32
-func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
33
-	if !config.InhibitIPv4 {
34
-		addrv4List, _, err := i.addresses()
35
-		if err != nil {
36
-			return fmt.Errorf("failed to retrieve bridge interface addresses: %v", err)
37
-		}
38
-
39
-		addrv4, _ := selectIPv4Address(addrv4List, config.AddressIPv4)
40
-
41
-		if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
42
-			if addrv4.IPNet != nil {
43
-				if err := i.nlh.AddrDel(i.Link, &addrv4); err != nil {
44
-					return fmt.Errorf("failed to remove current ip address from bridge: %v", err)
45
-				}
46
-			}
47
-			log.G(context.TODO()).Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4)
48
-			if err := i.nlh.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
49
-				return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err}
50
-			}
51
-		}
52
-	}
53
-
54
-	// Store bridge network and default gateway
55
-	i.bridgeIPv4 = config.AddressIPv4
56
-	i.gatewayIPv4 = config.AddressIPv4.IP
57
-
58
-	return nil
59
-}
60
-
61
-func setupGatewayIPv4(config *networkConfiguration, i *bridgeInterface) error {
62
-	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
63
-		return &ErrInvalidGateway{}
64
-	}
65
-
66
-	// Store requested default gateway
67
-	i.gatewayIPv4 = config.DefaultGatewayIPv4
68
-
69
-	return nil
70
-}
71
-
72
-func setupLoopbackAddressesRouting(config *networkConfiguration, i *bridgeInterface) error {
73
-	sysPath := filepath.Join("/proc/sys/net/ipv4/conf", config.BridgeName, "route_localnet")
74
-	ipv4LoRoutingData, err := os.ReadFile(sysPath)
75
-	if err != nil {
76
-		return fmt.Errorf("Cannot read IPv4 local routing setup: %v", err)
77
-	}
78
-	// Enable loopback addresses routing only if it isn't already enabled
79
-	if ipv4LoRoutingData[0] != '1' {
80
-		if err := os.WriteFile(sysPath, []byte{'1', '\n'}, 0o644); err != nil {
81
-			return fmt.Errorf("Unable to enable local routing for hairpin mode: %v", err)
82
-		}
83
-	}
84
-	return nil
85
-}
86 1
new file mode 100644
... ...
@@ -0,0 +1,83 @@
0
+package bridge
1
+
2
+import (
3
+	"context"
4
+	"errors"
5
+	"fmt"
6
+	"net"
7
+	"os"
8
+	"path/filepath"
9
+
10
+	"github.com/containerd/containerd/log"
11
+	"github.com/docker/docker/libnetwork/types"
12
+	"github.com/vishvananda/netlink"
13
+)
14
+
15
+func selectIPv4Address(addresses []netlink.Addr, selector *net.IPNet) (netlink.Addr, error) {
16
+	if len(addresses) == 0 {
17
+		return netlink.Addr{}, errors.New("unable to select an address as the address pool is empty")
18
+	}
19
+	if selector != nil {
20
+		for _, addr := range addresses {
21
+			if selector.Contains(addr.IP) {
22
+				return addr, nil
23
+			}
24
+		}
25
+	}
26
+	return addresses[0], nil
27
+}
28
+
29
+func setupBridgeIPv4(config *networkConfiguration, i *bridgeInterface) error {
30
+	if !config.InhibitIPv4 {
31
+		addrv4List, _, err := i.addresses()
32
+		if err != nil {
33
+			return fmt.Errorf("failed to retrieve bridge interface addresses: %v", err)
34
+		}
35
+
36
+		addrv4, _ := selectIPv4Address(addrv4List, config.AddressIPv4)
37
+
38
+		if !types.CompareIPNet(addrv4.IPNet, config.AddressIPv4) {
39
+			if addrv4.IPNet != nil {
40
+				if err := i.nlh.AddrDel(i.Link, &addrv4); err != nil {
41
+					return fmt.Errorf("failed to remove current ip address from bridge: %v", err)
42
+				}
43
+			}
44
+			log.G(context.TODO()).Debugf("Assigning address to bridge interface %s: %s", config.BridgeName, config.AddressIPv4)
45
+			if err := i.nlh.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
46
+				return &IPv4AddrAddError{IP: config.AddressIPv4, Err: err}
47
+			}
48
+		}
49
+	}
50
+
51
+	// Store bridge network and default gateway
52
+	i.bridgeIPv4 = config.AddressIPv4
53
+	i.gatewayIPv4 = config.AddressIPv4.IP
54
+
55
+	return nil
56
+}
57
+
58
+func setupGatewayIPv4(config *networkConfiguration, i *bridgeInterface) error {
59
+	if !i.bridgeIPv4.Contains(config.DefaultGatewayIPv4) {
60
+		return &ErrInvalidGateway{}
61
+	}
62
+
63
+	// Store requested default gateway
64
+	i.gatewayIPv4 = config.DefaultGatewayIPv4
65
+
66
+	return nil
67
+}
68
+
69
+func setupLoopbackAddressesRouting(config *networkConfiguration, i *bridgeInterface) error {
70
+	sysPath := filepath.Join("/proc/sys/net/ipv4/conf", config.BridgeName, "route_localnet")
71
+	ipv4LoRoutingData, err := os.ReadFile(sysPath)
72
+	if err != nil {
73
+		return fmt.Errorf("Cannot read IPv4 local routing setup: %v", err)
74
+	}
75
+	// Enable loopback addresses routing only if it isn't already enabled
76
+	if ipv4LoRoutingData[0] != '1' {
77
+		if err := os.WriteFile(sysPath, []byte{'1', '\n'}, 0o644); err != nil {
78
+			return fmt.Errorf("Unable to enable local routing for hairpin mode: %v", err)
79
+		}
80
+	}
81
+	return nil
82
+}
0 83
new file mode 100644
... ...
@@ -0,0 +1,88 @@
0
+package bridge
1
+
2
+import (
3
+	"net"
4
+	"testing"
5
+
6
+	"github.com/docker/docker/internal/testutils/netnsutils"
7
+	"github.com/vishvananda/netlink"
8
+)
9
+
10
+func setupTestInterface(t *testing.T, nh *netlink.Handle) (*networkConfiguration, *bridgeInterface) {
11
+	config := &networkConfiguration{
12
+		BridgeName: DefaultBridgeName,
13
+	}
14
+	br := &bridgeInterface{nlh: nh}
15
+
16
+	if err := setupDevice(config, br); err != nil {
17
+		t.Fatalf("Bridge creation failed: %v", err)
18
+	}
19
+	return config, br
20
+}
21
+
22
+func TestSetupBridgeIPv4Fixed(t *testing.T) {
23
+	defer netnsutils.SetupTestOSContext(t)()
24
+
25
+	ip, netw, err := net.ParseCIDR("192.168.1.1/24")
26
+	if err != nil {
27
+		t.Fatalf("Failed to parse bridge IPv4: %v", err)
28
+	}
29
+
30
+	nh, err := netlink.NewHandle()
31
+	if err != nil {
32
+		t.Fatal(err)
33
+	}
34
+	defer nh.Close()
35
+
36
+	config, br := setupTestInterface(t, nh)
37
+	config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask}
38
+	if err := setupBridgeIPv4(config, br); err != nil {
39
+		t.Fatalf("Failed to setup bridge IPv4: %v", err)
40
+	}
41
+
42
+	addrsv4, err := nh.AddrList(br.Link, netlink.FAMILY_V4)
43
+	if err != nil {
44
+		t.Fatalf("Failed to list device IPv4 addresses: %v", err)
45
+	}
46
+
47
+	var found bool
48
+	for _, addr := range addrsv4 {
49
+		if config.AddressIPv4.String() == addr.IPNet.String() {
50
+			found = true
51
+			break
52
+		}
53
+	}
54
+
55
+	if !found {
56
+		t.Fatalf("Bridge device does not have requested IPv4 address %v", config.AddressIPv4)
57
+	}
58
+}
59
+
60
+func TestSetupGatewayIPv4(t *testing.T) {
61
+	defer netnsutils.SetupTestOSContext(t)()
62
+
63
+	nh, err := netlink.NewHandle()
64
+	if err != nil {
65
+		t.Fatal(err)
66
+	}
67
+	defer nh.Close()
68
+
69
+	ip, nw, _ := net.ParseCIDR("192.168.0.24/16")
70
+	nw.IP = ip
71
+	gw := net.ParseIP("192.168.2.254")
72
+
73
+	config := &networkConfiguration{
74
+		BridgeName:         DefaultBridgeName,
75
+		DefaultGatewayIPv4: gw,
76
+	}
77
+
78
+	br := &bridgeInterface{bridgeIPv4: nw, nlh: nh}
79
+
80
+	if err := setupGatewayIPv4(config, br); err != nil {
81
+		t.Fatalf("Set Default Gateway failed: %v", err)
82
+	}
83
+
84
+	if !gw.Equal(br.gatewayIPv4) {
85
+		t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv4)
86
+	}
87
+}
0 88
deleted file mode 100644
... ...
@@ -1,90 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"net"
7
-	"testing"
8
-
9
-	"github.com/docker/docker/internal/testutils/netnsutils"
10
-	"github.com/vishvananda/netlink"
11
-)
12
-
13
-func setupTestInterface(t *testing.T, nh *netlink.Handle) (*networkConfiguration, *bridgeInterface) {
14
-	config := &networkConfiguration{
15
-		BridgeName: DefaultBridgeName,
16
-	}
17
-	br := &bridgeInterface{nlh: nh}
18
-
19
-	if err := setupDevice(config, br); err != nil {
20
-		t.Fatalf("Bridge creation failed: %v", err)
21
-	}
22
-	return config, br
23
-}
24
-
25
-func TestSetupBridgeIPv4Fixed(t *testing.T) {
26
-	defer netnsutils.SetupTestOSContext(t)()
27
-
28
-	ip, netw, err := net.ParseCIDR("192.168.1.1/24")
29
-	if err != nil {
30
-		t.Fatalf("Failed to parse bridge IPv4: %v", err)
31
-	}
32
-
33
-	nh, err := netlink.NewHandle()
34
-	if err != nil {
35
-		t.Fatal(err)
36
-	}
37
-	defer nh.Close()
38
-
39
-	config, br := setupTestInterface(t, nh)
40
-	config.AddressIPv4 = &net.IPNet{IP: ip, Mask: netw.Mask}
41
-	if err := setupBridgeIPv4(config, br); err != nil {
42
-		t.Fatalf("Failed to setup bridge IPv4: %v", err)
43
-	}
44
-
45
-	addrsv4, err := nh.AddrList(br.Link, netlink.FAMILY_V4)
46
-	if err != nil {
47
-		t.Fatalf("Failed to list device IPv4 addresses: %v", err)
48
-	}
49
-
50
-	var found bool
51
-	for _, addr := range addrsv4 {
52
-		if config.AddressIPv4.String() == addr.IPNet.String() {
53
-			found = true
54
-			break
55
-		}
56
-	}
57
-
58
-	if !found {
59
-		t.Fatalf("Bridge device does not have requested IPv4 address %v", config.AddressIPv4)
60
-	}
61
-}
62
-
63
-func TestSetupGatewayIPv4(t *testing.T) {
64
-	defer netnsutils.SetupTestOSContext(t)()
65
-
66
-	nh, err := netlink.NewHandle()
67
-	if err != nil {
68
-		t.Fatal(err)
69
-	}
70
-	defer nh.Close()
71
-
72
-	ip, nw, _ := net.ParseCIDR("192.168.0.24/16")
73
-	nw.IP = ip
74
-	gw := net.ParseIP("192.168.2.254")
75
-
76
-	config := &networkConfiguration{
77
-		BridgeName:         DefaultBridgeName,
78
-		DefaultGatewayIPv4: gw,
79
-	}
80
-
81
-	br := &bridgeInterface{bridgeIPv4: nw, nlh: nh}
82
-
83
-	if err := setupGatewayIPv4(config, br); err != nil {
84
-		t.Fatalf("Set Default Gateway failed: %v", err)
85
-	}
86
-
87
-	if !gw.Equal(br.gatewayIPv4) {
88
-		t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv4)
89
-	}
90
-}
91 1
deleted file mode 100644
... ...
@@ -1,111 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"context"
7
-	"fmt"
8
-	"net"
9
-	"os"
10
-
11
-	"github.com/containerd/containerd/log"
12
-	"github.com/vishvananda/netlink"
13
-)
14
-
15
-// bridgeIPv6 is the default, link-local IPv6 address for the bridge (fe80::1/64)
16
-var bridgeIPv6 = &net.IPNet{IP: net.ParseIP("fe80::1"), Mask: net.CIDRMask(64, 128)}
17
-
18
-const (
19
-	ipv6ForwardConfPerm    = 0o644
20
-	ipv6ForwardConfDefault = "/proc/sys/net/ipv6/conf/default/forwarding"
21
-	ipv6ForwardConfAll     = "/proc/sys/net/ipv6/conf/all/forwarding"
22
-)
23
-
24
-func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
25
-	procFile := "/proc/sys/net/ipv6/conf/" + config.BridgeName + "/disable_ipv6"
26
-	ipv6BridgeData, err := os.ReadFile(procFile)
27
-	if err != nil {
28
-		return fmt.Errorf("Cannot read IPv6 setup for bridge %v: %v", config.BridgeName, err)
29
-	}
30
-	// Enable IPv6 on the bridge only if it isn't already enabled
31
-	if ipv6BridgeData[0] != '0' {
32
-		if err := os.WriteFile(procFile, []byte{'0', '\n'}, ipv6ForwardConfPerm); err != nil {
33
-			return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
34
-		}
35
-	}
36
-
37
-	// Store bridge network and default gateway
38
-	i.bridgeIPv6 = bridgeIPv6
39
-	i.gatewayIPv6 = i.bridgeIPv6.IP
40
-
41
-	if err := i.programIPv6Address(); err != nil {
42
-		return err
43
-	}
44
-
45
-	if config.AddressIPv6 == nil {
46
-		return nil
47
-	}
48
-
49
-	// Store the user specified bridge network and network gateway and program it
50
-	i.bridgeIPv6 = config.AddressIPv6
51
-	i.gatewayIPv6 = config.AddressIPv6.IP
52
-
53
-	if err := i.programIPv6Address(); err != nil {
54
-		return err
55
-	}
56
-
57
-	// Setting route to global IPv6 subnet
58
-	log.G(context.TODO()).Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
59
-	err = i.nlh.RouteAdd(&netlink.Route{
60
-		Scope:     netlink.SCOPE_UNIVERSE,
61
-		LinkIndex: i.Link.Attrs().Index,
62
-		Dst:       config.AddressIPv6,
63
-	})
64
-	if err != nil && !os.IsExist(err) {
65
-		log.G(context.TODO()).Errorf("Could not add route to IPv6 network %s via device %s: %s", config.AddressIPv6.String(), config.BridgeName, err)
66
-	}
67
-
68
-	return nil
69
-}
70
-
71
-func setupGatewayIPv6(config *networkConfiguration, i *bridgeInterface) error {
72
-	if config.AddressIPv6 == nil {
73
-		return &ErrInvalidContainerSubnet{}
74
-	}
75
-	if !config.AddressIPv6.Contains(config.DefaultGatewayIPv6) {
76
-		return &ErrInvalidGateway{}
77
-	}
78
-
79
-	// Store requested default gateway
80
-	i.gatewayIPv6 = config.DefaultGatewayIPv6
81
-
82
-	return nil
83
-}
84
-
85
-func setupIPv6Forwarding(config *networkConfiguration, i *bridgeInterface) error {
86
-	// Get current IPv6 default forwarding setup
87
-	ipv6ForwardDataDefault, err := os.ReadFile(ipv6ForwardConfDefault)
88
-	if err != nil {
89
-		return fmt.Errorf("Cannot read IPv6 default forwarding setup: %v", err)
90
-	}
91
-	// Enable IPv6 default forwarding only if it is not already enabled
92
-	if ipv6ForwardDataDefault[0] != '1' {
93
-		if err := os.WriteFile(ipv6ForwardConfDefault, []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
94
-			log.G(context.TODO()).Warnf("Unable to enable IPv6 default forwarding: %v", err)
95
-		}
96
-	}
97
-
98
-	// Get current IPv6 all forwarding setup
99
-	ipv6ForwardDataAll, err := os.ReadFile(ipv6ForwardConfAll)
100
-	if err != nil {
101
-		return fmt.Errorf("Cannot read IPv6 all forwarding setup: %v", err)
102
-	}
103
-	// Enable IPv6 all forwarding only if it is not already enabled
104
-	if ipv6ForwardDataAll[0] != '1' {
105
-		if err := os.WriteFile(ipv6ForwardConfAll, []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
106
-			log.G(context.TODO()).Warnf("Unable to enable IPv6 all forwarding: %v", err)
107
-		}
108
-	}
109
-
110
-	return nil
111
-}
112 1
new file mode 100644
... ...
@@ -0,0 +1,109 @@
0
+package bridge
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+	"net"
6
+	"os"
7
+
8
+	"github.com/containerd/containerd/log"
9
+	"github.com/vishvananda/netlink"
10
+)
11
+
12
+// bridgeIPv6 is the default, link-local IPv6 address for the bridge (fe80::1/64)
13
+var bridgeIPv6 = &net.IPNet{IP: net.ParseIP("fe80::1"), Mask: net.CIDRMask(64, 128)}
14
+
15
+const (
16
+	ipv6ForwardConfPerm    = 0o644
17
+	ipv6ForwardConfDefault = "/proc/sys/net/ipv6/conf/default/forwarding"
18
+	ipv6ForwardConfAll     = "/proc/sys/net/ipv6/conf/all/forwarding"
19
+)
20
+
21
+func setupBridgeIPv6(config *networkConfiguration, i *bridgeInterface) error {
22
+	procFile := "/proc/sys/net/ipv6/conf/" + config.BridgeName + "/disable_ipv6"
23
+	ipv6BridgeData, err := os.ReadFile(procFile)
24
+	if err != nil {
25
+		return fmt.Errorf("Cannot read IPv6 setup for bridge %v: %v", config.BridgeName, err)
26
+	}
27
+	// Enable IPv6 on the bridge only if it isn't already enabled
28
+	if ipv6BridgeData[0] != '0' {
29
+		if err := os.WriteFile(procFile, []byte{'0', '\n'}, ipv6ForwardConfPerm); err != nil {
30
+			return fmt.Errorf("Unable to enable IPv6 addresses on bridge: %v", err)
31
+		}
32
+	}
33
+
34
+	// Store bridge network and default gateway
35
+	i.bridgeIPv6 = bridgeIPv6
36
+	i.gatewayIPv6 = i.bridgeIPv6.IP
37
+
38
+	if err := i.programIPv6Address(); err != nil {
39
+		return err
40
+	}
41
+
42
+	if config.AddressIPv6 == nil {
43
+		return nil
44
+	}
45
+
46
+	// Store the user specified bridge network and network gateway and program it
47
+	i.bridgeIPv6 = config.AddressIPv6
48
+	i.gatewayIPv6 = config.AddressIPv6.IP
49
+
50
+	if err := i.programIPv6Address(); err != nil {
51
+		return err
52
+	}
53
+
54
+	// Setting route to global IPv6 subnet
55
+	log.G(context.TODO()).Debugf("Adding route to IPv6 network %s via device %s", config.AddressIPv6.String(), config.BridgeName)
56
+	err = i.nlh.RouteAdd(&netlink.Route{
57
+		Scope:     netlink.SCOPE_UNIVERSE,
58
+		LinkIndex: i.Link.Attrs().Index,
59
+		Dst:       config.AddressIPv6,
60
+	})
61
+	if err != nil && !os.IsExist(err) {
62
+		log.G(context.TODO()).Errorf("Could not add route to IPv6 network %s via device %s: %s", config.AddressIPv6.String(), config.BridgeName, err)
63
+	}
64
+
65
+	return nil
66
+}
67
+
68
+func setupGatewayIPv6(config *networkConfiguration, i *bridgeInterface) error {
69
+	if config.AddressIPv6 == nil {
70
+		return &ErrInvalidContainerSubnet{}
71
+	}
72
+	if !config.AddressIPv6.Contains(config.DefaultGatewayIPv6) {
73
+		return &ErrInvalidGateway{}
74
+	}
75
+
76
+	// Store requested default gateway
77
+	i.gatewayIPv6 = config.DefaultGatewayIPv6
78
+
79
+	return nil
80
+}
81
+
82
+func setupIPv6Forwarding(config *networkConfiguration, i *bridgeInterface) error {
83
+	// Get current IPv6 default forwarding setup
84
+	ipv6ForwardDataDefault, err := os.ReadFile(ipv6ForwardConfDefault)
85
+	if err != nil {
86
+		return fmt.Errorf("Cannot read IPv6 default forwarding setup: %v", err)
87
+	}
88
+	// Enable IPv6 default forwarding only if it is not already enabled
89
+	if ipv6ForwardDataDefault[0] != '1' {
90
+		if err := os.WriteFile(ipv6ForwardConfDefault, []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
91
+			log.G(context.TODO()).Warnf("Unable to enable IPv6 default forwarding: %v", err)
92
+		}
93
+	}
94
+
95
+	// Get current IPv6 all forwarding setup
96
+	ipv6ForwardDataAll, err := os.ReadFile(ipv6ForwardConfAll)
97
+	if err != nil {
98
+		return fmt.Errorf("Cannot read IPv6 all forwarding setup: %v", err)
99
+	}
100
+	// Enable IPv6 all forwarding only if it is not already enabled
101
+	if ipv6ForwardDataAll[0] != '1' {
102
+		if err := os.WriteFile(ipv6ForwardConfAll, []byte{'1', '\n'}, ipv6ForwardConfPerm); err != nil {
103
+			log.G(context.TODO()).Warnf("Unable to enable IPv6 all forwarding: %v", err)
104
+		}
105
+	}
106
+
107
+	return nil
108
+}
0 109
new file mode 100644
... ...
@@ -0,0 +1,82 @@
0
+package bridge
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"net"
6
+	"os"
7
+	"testing"
8
+
9
+	"github.com/docker/docker/internal/testutils/netnsutils"
10
+	"github.com/vishvananda/netlink"
11
+)
12
+
13
+func TestSetupIPv6(t *testing.T) {
14
+	defer netnsutils.SetupTestOSContext(t)()
15
+
16
+	nh, err := netlink.NewHandle()
17
+	if err != nil {
18
+		t.Fatal(err)
19
+	}
20
+	defer nh.Close()
21
+
22
+	config, br := setupTestInterface(t, nh)
23
+	if err := setupBridgeIPv6(config, br); err != nil {
24
+		t.Fatalf("Failed to setup bridge IPv6: %v", err)
25
+	}
26
+
27
+	procSetting, err := os.ReadFile(fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", config.BridgeName))
28
+	if err != nil {
29
+		t.Fatalf("Failed to read disable_ipv6 kernel setting: %v", err)
30
+	}
31
+
32
+	if expected := []byte("0\n"); !bytes.Equal(expected, procSetting) {
33
+		t.Fatalf("Invalid kernel setting disable_ipv6: expected %q, got %q", string(expected), string(procSetting))
34
+	}
35
+
36
+	addrsv6, err := nh.AddrList(br.Link, netlink.FAMILY_V6)
37
+	if err != nil {
38
+		t.Fatalf("Failed to list device IPv6 addresses: %v", err)
39
+	}
40
+
41
+	var found bool
42
+	for _, addr := range addrsv6 {
43
+		if bridgeIPv6.String() == addr.IPNet.String() {
44
+			found = true
45
+			break
46
+		}
47
+	}
48
+
49
+	if !found {
50
+		t.Fatalf("Bridge device does not have requested IPv6 address %v", bridgeIPv6)
51
+	}
52
+}
53
+
54
+func TestSetupGatewayIPv6(t *testing.T) {
55
+	defer netnsutils.SetupTestOSContext(t)()
56
+
57
+	_, nw, _ := net.ParseCIDR("2001:db8:ea9:9abc:ffff::/80")
58
+	gw := net.ParseIP("2001:db8:ea9:9abc:ffff::254")
59
+
60
+	config := &networkConfiguration{
61
+		BridgeName:         DefaultBridgeName,
62
+		AddressIPv6:        nw,
63
+		DefaultGatewayIPv6: gw,
64
+	}
65
+
66
+	nh, err := netlink.NewHandle()
67
+	if err != nil {
68
+		t.Fatal(err)
69
+	}
70
+	defer nh.Close()
71
+
72
+	br := &bridgeInterface{nlh: nh}
73
+
74
+	if err := setupGatewayIPv6(config, br); err != nil {
75
+		t.Fatalf("Set Default Gateway failed: %v", err)
76
+	}
77
+
78
+	if !gw.Equal(br.gatewayIPv6) {
79
+		t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv6)
80
+	}
81
+}
0 82
deleted file mode 100644
... ...
@@ -1,84 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"bytes"
7
-	"fmt"
8
-	"net"
9
-	"os"
10
-	"testing"
11
-
12
-	"github.com/docker/docker/internal/testutils/netnsutils"
13
-	"github.com/vishvananda/netlink"
14
-)
15
-
16
-func TestSetupIPv6(t *testing.T) {
17
-	defer netnsutils.SetupTestOSContext(t)()
18
-
19
-	nh, err := netlink.NewHandle()
20
-	if err != nil {
21
-		t.Fatal(err)
22
-	}
23
-	defer nh.Close()
24
-
25
-	config, br := setupTestInterface(t, nh)
26
-	if err := setupBridgeIPv6(config, br); err != nil {
27
-		t.Fatalf("Failed to setup bridge IPv6: %v", err)
28
-	}
29
-
30
-	procSetting, err := os.ReadFile(fmt.Sprintf("/proc/sys/net/ipv6/conf/%s/disable_ipv6", config.BridgeName))
31
-	if err != nil {
32
-		t.Fatalf("Failed to read disable_ipv6 kernel setting: %v", err)
33
-	}
34
-
35
-	if expected := []byte("0\n"); !bytes.Equal(expected, procSetting) {
36
-		t.Fatalf("Invalid kernel setting disable_ipv6: expected %q, got %q", string(expected), string(procSetting))
37
-	}
38
-
39
-	addrsv6, err := nh.AddrList(br.Link, netlink.FAMILY_V6)
40
-	if err != nil {
41
-		t.Fatalf("Failed to list device IPv6 addresses: %v", err)
42
-	}
43
-
44
-	var found bool
45
-	for _, addr := range addrsv6 {
46
-		if bridgeIPv6.String() == addr.IPNet.String() {
47
-			found = true
48
-			break
49
-		}
50
-	}
51
-
52
-	if !found {
53
-		t.Fatalf("Bridge device does not have requested IPv6 address %v", bridgeIPv6)
54
-	}
55
-}
56
-
57
-func TestSetupGatewayIPv6(t *testing.T) {
58
-	defer netnsutils.SetupTestOSContext(t)()
59
-
60
-	_, nw, _ := net.ParseCIDR("2001:db8:ea9:9abc:ffff::/80")
61
-	gw := net.ParseIP("2001:db8:ea9:9abc:ffff::254")
62
-
63
-	config := &networkConfiguration{
64
-		BridgeName:         DefaultBridgeName,
65
-		AddressIPv6:        nw,
66
-		DefaultGatewayIPv6: gw,
67
-	}
68
-
69
-	nh, err := netlink.NewHandle()
70
-	if err != nil {
71
-		t.Fatal(err)
72
-	}
73
-	defer nh.Close()
74
-
75
-	br := &bridgeInterface{nlh: nh}
76
-
77
-	if err := setupGatewayIPv6(config, br); err != nil {
78
-		t.Fatalf("Set Default Gateway failed: %v", err)
79
-	}
80
-
81
-	if !gw.Equal(br.gatewayIPv6) {
82
-		t.Fatalf("Set Default Gateway failed. Expected %v, Found %v", gw, br.gatewayIPv6)
83
-	}
84
-}
85 1
deleted file mode 100644
... ...
@@ -1,77 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"context"
7
-	"fmt"
8
-	"strings"
9
-
10
-	"github.com/containerd/containerd/log"
11
-	"github.com/docker/docker/libnetwork/ns"
12
-	"github.com/docker/docker/libnetwork/types"
13
-	"github.com/vishvananda/netlink"
14
-)
15
-
16
-func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) error {
17
-	// Fetch a slice of IPv4 addresses and a slice of IPv6 addresses from the bridge.
18
-	addrsv4, addrsv6, err := i.addresses()
19
-	if err != nil {
20
-		return fmt.Errorf("Failed to verify ip addresses: %v", err)
21
-	}
22
-
23
-	addrv4, _ := selectIPv4Address(addrsv4, config.AddressIPv4)
24
-
25
-	// Verify that the bridge does have an IPv4 address.
26
-	if addrv4.IPNet == nil {
27
-		return &ErrNoIPAddr{}
28
-	}
29
-
30
-	// Verify that the bridge IPv4 address matches the requested configuration.
31
-	if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
32
-		return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP}
33
-	}
34
-
35
-	// Verify that one of the bridge IPv6 addresses matches the requested
36
-	// configuration.
37
-	if config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
38
-		return (*IPv6AddrNoMatchError)(bridgeIPv6)
39
-	}
40
-
41
-	// Release any residual IPv6 address that might be there because of older daemon instances
42
-	for _, addrv6 := range addrsv6 {
43
-		addrv6 := addrv6
44
-		if addrv6.IP.IsGlobalUnicast() && !types.CompareIPNet(addrv6.IPNet, i.bridgeIPv6) {
45
-			if err := i.nlh.AddrDel(i.Link, &addrv6); err != nil {
46
-				log.G(context.TODO()).Warnf("Failed to remove residual IPv6 address %s from bridge: %v", addrv6.IPNet, err)
47
-			}
48
-		}
49
-	}
50
-
51
-	return nil
52
-}
53
-
54
-func findIPv6Address(addr netlink.Addr, addresses []netlink.Addr) bool {
55
-	for _, addrv6 := range addresses {
56
-		if addrv6.String() == addr.String() {
57
-			return true
58
-		}
59
-	}
60
-	return false
61
-}
62
-
63
-func bridgeInterfaceExists(name string) (bool, error) {
64
-	nlh := ns.NlHandle()
65
-	link, err := nlh.LinkByName(name)
66
-	if err != nil {
67
-		if strings.Contains(err.Error(), "Link not found") {
68
-			return false, nil
69
-		}
70
-		return false, fmt.Errorf("failed to check bridge interface existence: %v", err)
71
-	}
72
-
73
-	if link.Type() == "bridge" {
74
-		return true, nil
75
-	}
76
-	return false, fmt.Errorf("existing interface %s is not a bridge", name)
77
-}
78 1
new file mode 100644
... ...
@@ -0,0 +1,75 @@
0
+package bridge
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+	"strings"
6
+
7
+	"github.com/containerd/containerd/log"
8
+	"github.com/docker/docker/libnetwork/ns"
9
+	"github.com/docker/docker/libnetwork/types"
10
+	"github.com/vishvananda/netlink"
11
+)
12
+
13
+func setupVerifyAndReconcile(config *networkConfiguration, i *bridgeInterface) error {
14
+	// Fetch a slice of IPv4 addresses and a slice of IPv6 addresses from the bridge.
15
+	addrsv4, addrsv6, err := i.addresses()
16
+	if err != nil {
17
+		return fmt.Errorf("Failed to verify ip addresses: %v", err)
18
+	}
19
+
20
+	addrv4, _ := selectIPv4Address(addrsv4, config.AddressIPv4)
21
+
22
+	// Verify that the bridge does have an IPv4 address.
23
+	if addrv4.IPNet == nil {
24
+		return &ErrNoIPAddr{}
25
+	}
26
+
27
+	// Verify that the bridge IPv4 address matches the requested configuration.
28
+	if config.AddressIPv4 != nil && !addrv4.IP.Equal(config.AddressIPv4.IP) {
29
+		return &IPv4AddrNoMatchError{IP: addrv4.IP, CfgIP: config.AddressIPv4.IP}
30
+	}
31
+
32
+	// Verify that one of the bridge IPv6 addresses matches the requested
33
+	// configuration.
34
+	if config.EnableIPv6 && !findIPv6Address(netlink.Addr{IPNet: bridgeIPv6}, addrsv6) {
35
+		return (*IPv6AddrNoMatchError)(bridgeIPv6)
36
+	}
37
+
38
+	// Release any residual IPv6 address that might be there because of older daemon instances
39
+	for _, addrv6 := range addrsv6 {
40
+		addrv6 := addrv6
41
+		if addrv6.IP.IsGlobalUnicast() && !types.CompareIPNet(addrv6.IPNet, i.bridgeIPv6) {
42
+			if err := i.nlh.AddrDel(i.Link, &addrv6); err != nil {
43
+				log.G(context.TODO()).Warnf("Failed to remove residual IPv6 address %s from bridge: %v", addrv6.IPNet, err)
44
+			}
45
+		}
46
+	}
47
+
48
+	return nil
49
+}
50
+
51
+func findIPv6Address(addr netlink.Addr, addresses []netlink.Addr) bool {
52
+	for _, addrv6 := range addresses {
53
+		if addrv6.String() == addr.String() {
54
+			return true
55
+		}
56
+	}
57
+	return false
58
+}
59
+
60
+func bridgeInterfaceExists(name string) (bool, error) {
61
+	nlh := ns.NlHandle()
62
+	link, err := nlh.LinkByName(name)
63
+	if err != nil {
64
+		if strings.Contains(err.Error(), "Link not found") {
65
+			return false, nil
66
+		}
67
+		return false, fmt.Errorf("failed to check bridge interface existence: %v", err)
68
+	}
69
+
70
+	if link.Type() == "bridge" {
71
+		return true, nil
72
+	}
73
+	return false, fmt.Errorf("existing interface %s is not a bridge", name)
74
+}
0 75
new file mode 100644
... ...
@@ -0,0 +1,114 @@
0
+package bridge
1
+
2
+import (
3
+	"net"
4
+	"testing"
5
+
6
+	"github.com/docker/docker/internal/testutils/netnsutils"
7
+	"github.com/vishvananda/netlink"
8
+)
9
+
10
+func setupVerifyTest(t *testing.T) *bridgeInterface {
11
+	nh, err := netlink.NewHandle()
12
+	if err != nil {
13
+		t.Fatal(err)
14
+	}
15
+	inf := &bridgeInterface{nlh: nh}
16
+
17
+	br := netlink.Bridge{}
18
+	br.LinkAttrs.Name = "default0"
19
+	if err := nh.LinkAdd(&br); err == nil {
20
+		inf.Link = &br
21
+	} else {
22
+		t.Fatalf("Failed to create bridge interface: %v", err)
23
+	}
24
+
25
+	return inf
26
+}
27
+
28
+func TestSetupVerify(t *testing.T) {
29
+	defer netnsutils.SetupTestOSContext(t)()
30
+
31
+	addrv4 := net.IPv4(192, 168, 1, 1)
32
+	inf := setupVerifyTest(t)
33
+	config := &networkConfiguration{}
34
+	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
35
+
36
+	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
37
+		t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
38
+	}
39
+
40
+	if err := setupVerifyAndReconcile(config, inf); err != nil {
41
+		t.Fatalf("Address verification failed: %v", err)
42
+	}
43
+}
44
+
45
+func TestSetupVerifyBad(t *testing.T) {
46
+	defer netnsutils.SetupTestOSContext(t)()
47
+
48
+	addrv4 := net.IPv4(192, 168, 1, 1)
49
+	inf := setupVerifyTest(t)
50
+	config := &networkConfiguration{}
51
+	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
52
+
53
+	ipnet := &net.IPNet{IP: net.IPv4(192, 168, 1, 2), Mask: addrv4.DefaultMask()}
54
+	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: ipnet}); err != nil {
55
+		t.Fatalf("Failed to assign IPv4 %s to interface: %v", ipnet, err)
56
+	}
57
+
58
+	if err := setupVerifyAndReconcile(config, inf); err == nil {
59
+		t.Fatal("Address verification was expected to fail")
60
+	}
61
+}
62
+
63
+func TestSetupVerifyMissing(t *testing.T) {
64
+	defer netnsutils.SetupTestOSContext(t)()
65
+
66
+	addrv4 := net.IPv4(192, 168, 1, 1)
67
+	inf := setupVerifyTest(t)
68
+	config := &networkConfiguration{}
69
+	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
70
+
71
+	if err := setupVerifyAndReconcile(config, inf); err == nil {
72
+		t.Fatal("Address verification was expected to fail")
73
+	}
74
+}
75
+
76
+func TestSetupVerifyIPv6(t *testing.T) {
77
+	defer netnsutils.SetupTestOSContext(t)()
78
+
79
+	addrv4 := net.IPv4(192, 168, 1, 1)
80
+	inf := setupVerifyTest(t)
81
+	config := &networkConfiguration{}
82
+	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
83
+	config.EnableIPv6 = true
84
+
85
+	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
86
+		t.Fatalf("Failed to assign IPv6 %s to interface: %v", bridgeIPv6, err)
87
+	}
88
+	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
89
+		t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
90
+	}
91
+
92
+	if err := setupVerifyAndReconcile(config, inf); err != nil {
93
+		t.Fatalf("Address verification failed: %v", err)
94
+	}
95
+}
96
+
97
+func TestSetupVerifyIPv6Missing(t *testing.T) {
98
+	defer netnsutils.SetupTestOSContext(t)()
99
+
100
+	addrv4 := net.IPv4(192, 168, 1, 1)
101
+	inf := setupVerifyTest(t)
102
+	config := &networkConfiguration{}
103
+	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
104
+	config.EnableIPv6 = true
105
+
106
+	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
107
+		t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
108
+	}
109
+
110
+	if err := setupVerifyAndReconcile(config, inf); err == nil {
111
+		t.Fatal("Address verification was expected to fail")
112
+	}
113
+}
0 114
deleted file mode 100644
... ...
@@ -1,116 +0,0 @@
1
-//go:build linux
2
-
3
-package bridge
4
-
5
-import (
6
-	"net"
7
-	"testing"
8
-
9
-	"github.com/docker/docker/internal/testutils/netnsutils"
10
-	"github.com/vishvananda/netlink"
11
-)
12
-
13
-func setupVerifyTest(t *testing.T) *bridgeInterface {
14
-	nh, err := netlink.NewHandle()
15
-	if err != nil {
16
-		t.Fatal(err)
17
-	}
18
-	inf := &bridgeInterface{nlh: nh}
19
-
20
-	br := netlink.Bridge{}
21
-	br.LinkAttrs.Name = "default0"
22
-	if err := nh.LinkAdd(&br); err == nil {
23
-		inf.Link = &br
24
-	} else {
25
-		t.Fatalf("Failed to create bridge interface: %v", err)
26
-	}
27
-
28
-	return inf
29
-}
30
-
31
-func TestSetupVerify(t *testing.T) {
32
-	defer netnsutils.SetupTestOSContext(t)()
33
-
34
-	addrv4 := net.IPv4(192, 168, 1, 1)
35
-	inf := setupVerifyTest(t)
36
-	config := &networkConfiguration{}
37
-	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
38
-
39
-	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
40
-		t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
41
-	}
42
-
43
-	if err := setupVerifyAndReconcile(config, inf); err != nil {
44
-		t.Fatalf("Address verification failed: %v", err)
45
-	}
46
-}
47
-
48
-func TestSetupVerifyBad(t *testing.T) {
49
-	defer netnsutils.SetupTestOSContext(t)()
50
-
51
-	addrv4 := net.IPv4(192, 168, 1, 1)
52
-	inf := setupVerifyTest(t)
53
-	config := &networkConfiguration{}
54
-	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
55
-
56
-	ipnet := &net.IPNet{IP: net.IPv4(192, 168, 1, 2), Mask: addrv4.DefaultMask()}
57
-	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: ipnet}); err != nil {
58
-		t.Fatalf("Failed to assign IPv4 %s to interface: %v", ipnet, err)
59
-	}
60
-
61
-	if err := setupVerifyAndReconcile(config, inf); err == nil {
62
-		t.Fatal("Address verification was expected to fail")
63
-	}
64
-}
65
-
66
-func TestSetupVerifyMissing(t *testing.T) {
67
-	defer netnsutils.SetupTestOSContext(t)()
68
-
69
-	addrv4 := net.IPv4(192, 168, 1, 1)
70
-	inf := setupVerifyTest(t)
71
-	config := &networkConfiguration{}
72
-	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
73
-
74
-	if err := setupVerifyAndReconcile(config, inf); err == nil {
75
-		t.Fatal("Address verification was expected to fail")
76
-	}
77
-}
78
-
79
-func TestSetupVerifyIPv6(t *testing.T) {
80
-	defer netnsutils.SetupTestOSContext(t)()
81
-
82
-	addrv4 := net.IPv4(192, 168, 1, 1)
83
-	inf := setupVerifyTest(t)
84
-	config := &networkConfiguration{}
85
-	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
86
-	config.EnableIPv6 = true
87
-
88
-	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: bridgeIPv6}); err != nil {
89
-		t.Fatalf("Failed to assign IPv6 %s to interface: %v", bridgeIPv6, err)
90
-	}
91
-	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
92
-		t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
93
-	}
94
-
95
-	if err := setupVerifyAndReconcile(config, inf); err != nil {
96
-		t.Fatalf("Address verification failed: %v", err)
97
-	}
98
-}
99
-
100
-func TestSetupVerifyIPv6Missing(t *testing.T) {
101
-	defer netnsutils.SetupTestOSContext(t)()
102
-
103
-	addrv4 := net.IPv4(192, 168, 1, 1)
104
-	inf := setupVerifyTest(t)
105
-	config := &networkConfiguration{}
106
-	config.AddressIPv4 = &net.IPNet{IP: addrv4, Mask: addrv4.DefaultMask()}
107
-	config.EnableIPv6 = true
108
-
109
-	if err := netlink.AddrAdd(inf.Link, &netlink.Addr{IPNet: config.AddressIPv4}); err != nil {
110
-		t.Fatalf("Failed to assign IPv4 %s to interface: %v", config.AddressIPv4, err)
111
-	}
112
-
113
-	if err := setupVerifyAndReconcile(config, inf); err == nil {
114
-		t.Fatal("Address verification was expected to fail")
115
-	}
116
-}