package ipvlan import ( "encoding/json" "fmt" "github.com/Sirupsen/logrus" "github.com/docker/libkv/store/boltdb" "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/discoverapi" "github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/types" ) const ipvlanPrefix = "ipvlan" // prefix used for persistent driver storage // networkConfiguration for this driver's network specific configuration type configuration struct { ID string Mtu int dbIndex uint64 dbExists bool Internal bool HostIface string IpvlanMode string CreatedSlaveLink bool Ipv4Subnets []*ipv4Subnet Ipv6Subnets []*ipv6Subnet } type ipv4Subnet struct { SubnetIP string GwIP string } type ipv6Subnet struct { SubnetIP string GwIP string } // initStore drivers are responsible for caching their own persistent state func (d *driver) initStore(option map[string]interface{}) error { if data, ok := option[netlabel.LocalKVClient]; ok { var err error dsc, ok := data.(discoverapi.DatastoreConfigData) if !ok { return types.InternalErrorf("incorrect data in datastore configuration: %v", data) } d.store, err = datastore.NewDataStoreFromConfig(dsc) if err != nil { return types.InternalErrorf("ipvlan driver failed to initialize data store: %v", err) } return d.populateNetworks() } return nil } // populateNetworks is invoked at driver init to recreate persistently stored networks func (d *driver) populateNetworks() error { kvol, err := d.store.List(datastore.Key(ipvlanPrefix), &configuration{}) if err != nil && err != datastore.ErrKeyNotFound && err != boltdb.ErrBoltBucketNotFound { return fmt.Errorf("failed to get ipvlan network configurations from store: %v", err) } // If empty it simply means no ipvlan networks have been created yet if err == datastore.ErrKeyNotFound { return nil } for _, kvo := range kvol { config := kvo.(*configuration) if err = d.createNetwork(config); err != nil { logrus.Warnf("could not create ipvlan network for id %s from persistent state", config.ID) } } return nil } // storeUpdate used to update persistent ipvlan network records as they are created func (d *driver) storeUpdate(kvObject datastore.KVObject) error { if d.store == nil { logrus.Warnf("ipvlan store not initialized. kv object %s is not added to the store", datastore.Key(kvObject.Key()...)) return nil } if err := d.store.PutObjectAtomic(kvObject); err != nil { return fmt.Errorf("failed to update ipvlan store for object type %T: %v", kvObject, err) } return nil } // storeDelete used to delete ipvlan network records from persistent cache as they are deleted func (d *driver) storeDelete(kvObject datastore.KVObject) error { if d.store == nil { logrus.Debugf("ipvlan store not initialized. kv object %s is not deleted from store", datastore.Key(kvObject.Key()...)) return nil } retry: if err := d.store.DeleteObjectAtomic(kvObject); err != nil { if err == datastore.ErrKeyModified { if err := d.store.GetObject(datastore.Key(kvObject.Key()...), kvObject); err != nil { return fmt.Errorf("could not update the kvobject to latest when trying to delete: %v", err) } goto retry } return err } return nil } func (config *configuration) MarshalJSON() ([]byte, error) { nMap := make(map[string]interface{}) nMap["ID"] = config.ID nMap["Mtu"] = config.Mtu nMap["HostIface"] = config.HostIface nMap["IpvlanMode"] = config.IpvlanMode nMap["CreatedSubIface"] = config.CreatedSlaveLink if len(config.Ipv4Subnets) > 0 { iis, err := json.Marshal(config.Ipv4Subnets) if err != nil { return nil, err } nMap["Ipv4Subnets"] = string(iis) } if len(config.Ipv6Subnets) > 0 { iis, err := json.Marshal(config.Ipv6Subnets) if err != nil { return nil, err } nMap["Ipv6Subnets"] = string(iis) } return json.Marshal(nMap) } func (config *configuration) UnmarshalJSON(b []byte) error { var ( err error nMap map[string]interface{} ) if err = json.Unmarshal(b, &nMap); err != nil { return err } config.ID = nMap["ID"].(string) config.Mtu = int(nMap["Mtu"].(float64)) config.HostIface = nMap["HostIface"].(string) config.IpvlanMode = nMap["IpvlanMode"].(string) config.CreatedSlaveLink = nMap["CreatedSubIface"].(bool) if v, ok := nMap["Ipv4Subnets"]; ok { if err := json.Unmarshal([]byte(v.(string)), &config.Ipv4Subnets); err != nil { return err } } if v, ok := nMap["Ipv6Subnets"]; ok { if err := json.Unmarshal([]byte(v.(string)), &config.Ipv6Subnets); err != nil { return err } } return nil } func (config *configuration) Key() []string { return []string{ipvlanPrefix, config.ID} } func (config *configuration) KeyPrefix() []string { return []string{ipvlanPrefix} } func (config *configuration) Value() []byte { b, err := json.Marshal(config) if err != nil { return nil } return b } func (config *configuration) SetValue(value []byte) error { return json.Unmarshal(value, config) } func (config *configuration) Index() uint64 { return config.dbIndex } func (config *configuration) SetIndex(index uint64) { config.dbIndex = index config.dbExists = true } func (config *configuration) Exists() bool { return config.dbExists } func (config *configuration) Skip() bool { return false } func (config *configuration) New() datastore.KVObject { return &configuration{} } func (config *configuration) CopyTo(o datastore.KVObject) error { dstNcfg := o.(*configuration) *dstNcfg = *config return nil } func (config *configuration) DataScope() string { return datastore.LocalScope }