Repository: moby/moby
File: daemon/libnetwork/drivers/bridge/bridge_linux.go (Go)

Code before:
func (d *driver) handleFirewalldReload() {
	if !d.config.EnableIPTables && !d.config.EnableIP6Tables {
		return
	}

	d.Lock()
	nids := make([]string, 0, len(d.networks))
	for _, nw := range d.networks {
		nids = append(nids, nw.id)
	}
	d.Unlock()

	for _, nid := range nids {
		d.handleFirewalldReloadNw(nid)
	}
}

func (d *driver) handleFirewalldReloadNw(nid string) {
	d.Lock()
	defer d.Unlock()

	if !d.config.EnableIPTables && !d.config.EnableIP6Tables {
		return
	}

	// Make sure the network isn't being deleted, and ProgramExternalConnectivity
	// isn't modifying iptables rules, while restoring the rules.
	d.configNetwork.Lock()
	defer d.configNetwork.Unlock()

	nw, ok := d.networks[nid]
	if !ok {
		// Network deleted since the reload started, not an error.
		return
	}

	if err := nw.firewallerNetwork.ReapplyNetworkLevelRules(context.TODO()); err != nil {
		log.G(context.Background()).WithFields(log.Fields{
			"nid":   nw.id,
			"error": err,
		}).Error("Failed to re-create packet filter on firewalld reload")
	}

	// Re-add legacy links - only added during ProgramExternalConnectivity, but legacy
	// links are default-bridge-only, and it's not possible to connect a container to
	// the default bridge and a user-defined network. So, the default bridge is always
	// the gateway and, if there are legacy links configured they need to be set up.
	if !nw.config.EnableICC {
		for _, ep := range nw.endpoints {
			if err := d.link(nw, ep, true); err != nil {
				log.G(context.Background()).WithFields(log.Fields{

Review comment (suggestion):
FWIW there's other places where we acquite a lock for `configNetwork`, but don't hold a lock for `networks` (`mu`), or at least not for the whole duration;
https://github.com/moby/moby/blob/cf15d5bbc62d58eec714afe0d54d9470fadf25f5/daemon/libnetwork/drivers/bridge/bridge_linux.go#L758-L766
https://github.com/moby/moby/blob/cf15d5bbc62d58eec714afe0d54d9470fadf25f5/daemon/libnetwork/drivers/bridge/bridge_linux.go#L725-L730

Code after:

func (d *driver) handleFirewalldReload() {
	if !d.config.EnableIPTables && !d.config.EnableIP6Tables {
		return
	}

	d.mu.Lock()
	nids := make([]string, 0, len(d.networks))
	for _, nw := range d.networks {
		nids = append(nids, nw.id)
	}
	d.mu.Unlock()

	for _, nid := range nids {
		d.handleFirewalldReloadNw(nid)
	}
}

func (d *driver) handleFirewalldReloadNw(nid string) {
	// Make sure the network isn't being deleted, and ProgramExternalConnectivity
	// isn't modifying iptables rules, while restoring the rules.
	d.configNetwork.Lock()
	defer d.configNetwork.Unlock()

	d.mu.Lock()
	defer d.mu.Unlock()

	if !d.config.EnableIPTables && !d.config.EnableIP6Tables {
		return
	}

	nw, ok := d.networks[nid]
	if !ok {
		// Network deleted since the reload started, not an error.
		return
	}

	if err := nw.firewallerNetwork.ReapplyNetworkLevelRules(context.TODO()); err != nil {
		log.G(context.Background()).WithFields(log.Fields{
			"nid":   nw.id,
			"error": err,
		}).Error("Failed to re-create packet filter on firewalld reload")
	}

	// Re-add legacy links - only added during ProgramExternalConnectivity, but legacy
	// links are default-bridge-only, and it's not possible to connect a container to
	// the default bridge and a user-defined network. So, the default bridge is always
	// the gateway and, if there are legacy links configured they need to be set up.
	if !nw.config.EnableICC {
		for _, ep := range nw.endpoints {
			if err := d.link(nw, ep, true); err != nil {