github.com/geofffranks/garden-linux@v0.0.0-20160715111146-26c893169cfa/network/bridgemgr/mgr.go (about)

     1  package bridgemgr
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"strings"
     8  	"sync"
     9  
    10  	"code.cloudfoundry.org/garden-linux/network/subnets"
    11  )
    12  
    13  type Builder interface {
    14  	Create(name string, ip net.IP, subnet *net.IPNet) (intf *net.Interface, err error)
    15  	Destroy(name string) error
    16  }
    17  
    18  type Lister interface {
    19  	List() ([]string, error)
    20  }
    21  
    22  //go:generate counterfeiter -o fake_bridge_manager/FakeBridgeManager.go . BridgeManager
    23  type BridgeManager interface {
    24  	// Reserve reserves a bridge name for a subnet.
    25  	// if this is the first call of 'reserve' for a subnet created a new, unique bridge name
    26  	Reserve(subnet *net.IPNet, containerId string) (string, error)
    27  
    28  	// Rereserves adds a container to the list of reservations for a particular bridge name.
    29  	Rereserve(bridgeName string, subnet *net.IPNet, containerId string) error
    30  
    31  	// Release releases a reservation made by a particular container.
    32  	// If this is the last reservation, the passed destroyers Destroy method is called.
    33  	Release(bridgeName string, containerId string) error
    34  
    35  	// Prune deletes all bridges starting with prefix, that are unknown.
    36  	Prune() error
    37  }
    38  
    39  type mgr struct {
    40  	prefix  string
    41  	names   BridgeNameGenerator
    42  	builder Builder
    43  	lister  Lister
    44  
    45  	mu           sync.Mutex
    46  	owners       map[string][]string // bridgeName -> []containerId
    47  	bridgeSubnet map[string]string   // bridgeName -> subnet
    48  	subnetBridge map[string]string   // subnet -> bridgeName
    49  }
    50  
    51  func New(prefix string, builder Builder, lister Lister) BridgeManager {
    52  	return &mgr{
    53  		prefix:  prefix,
    54  		names:   NewBridgeNameGenerator(prefix),
    55  		builder: builder,
    56  		lister:  lister,
    57  
    58  		owners:       make(map[string][]string),
    59  		bridgeSubnet: make(map[string]string),
    60  		subnetBridge: make(map[string]string),
    61  	}
    62  }
    63  
    64  func (m *mgr) Reserve(subnet *net.IPNet, containerId string) (string, error) {
    65  	m.mu.Lock()
    66  	defer m.mu.Unlock()
    67  
    68  	name, present := m.subnetBridge[subnet.String()]
    69  
    70  	if !present {
    71  		name = m.names.Generate()
    72  		if _, err := m.builder.Create(name, subnets.GatewayIP(subnet), subnet); err != nil {
    73  			return "", err
    74  		}
    75  		m.subnetBridge[subnet.String()] = name
    76  		m.bridgeSubnet[name] = subnet.String()
    77  	}
    78  
    79  	m.owners[name] = append(m.owners[name], containerId)
    80  
    81  	return name, nil
    82  }
    83  
    84  func (m *mgr) Release(bridgeName string, containerId string) error {
    85  	m.mu.Lock()
    86  	m.owners[bridgeName] = remove(m.owners[bridgeName], containerId)
    87  
    88  	shouldDelete := false
    89  	if len(m.owners[bridgeName]) == 0 {
    90  		delete(m.owners, bridgeName)
    91  		delete(m.subnetBridge, m.bridgeSubnet[bridgeName])
    92  		delete(m.bridgeSubnet, bridgeName)
    93  		shouldDelete = true
    94  	}
    95  
    96  	m.mu.Unlock()
    97  
    98  	if shouldDelete {
    99  		return m.builder.Destroy(bridgeName)
   100  	}
   101  
   102  	return nil
   103  }
   104  
   105  func (m *mgr) Rereserve(bridgeName string, subnet *net.IPNet, containerId string) error {
   106  	m.mu.Lock()
   107  	defer m.mu.Unlock()
   108  
   109  	if bridgeName == "" {
   110  		return errors.New("bridgemgr: re-reserving bridge: bridge name must not be empty")
   111  	}
   112  
   113  	if sn, present := m.bridgeSubnet[bridgeName]; present && sn != subnet.String() {
   114  		return fmt.Errorf("bridgemgr: reacquired bridge name '%s' has already been acquired for subnet %s", bridgeName, sn)
   115  	}
   116  
   117  	m.subnetBridge[subnet.String()] = bridgeName
   118  	m.owners[bridgeName] = append(m.owners[bridgeName], containerId)
   119  	m.bridgeSubnet[bridgeName] = subnet.String()
   120  
   121  	return nil
   122  }
   123  
   124  func (m *mgr) Prune() error {
   125  	list, err := m.lister.List()
   126  	if err != nil {
   127  		return fmt.Errorf("bridgemgr: pruning bridges: %v", err)
   128  	}
   129  
   130  	for _, b := range list {
   131  		if !strings.HasPrefix(b, m.prefix) {
   132  			continue
   133  		}
   134  
   135  		if !m.isReserved(b) {
   136  			m.builder.Destroy(b)
   137  		}
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  func (m *mgr) isReserved(r string) bool {
   144  	_, ok := m.bridgeSubnet[r]
   145  	return ok
   146  }
   147  
   148  func remove(a []string, b string) []string {
   149  	for i, j := range a {
   150  		if j == b {
   151  			return append(a[:i], a[i+1:]...)
   152  		}
   153  	}
   154  
   155  	return a
   156  }