windows.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. // +build windows
  2. // Shim for the Host Network Service (HNS) to manage networking for
  3. // Windows Server containers and Hyper-V containers. This module
  4. // is a basic libnetwork driver that passes all the calls to HNS
  5. // It implements the 4 networking modes supported by HNS L2Bridge,
  6. // L2Tunnel, NAT and Transparent(DHCP)
  7. //
  8. // The network are stored in memory and docker daemon ensures discovering
  9. // and loading these networks on startup
  10. package windows
  11. import (
  12. "encoding/json"
  13. "fmt"
  14. "net"
  15. "strconv"
  16. "strings"
  17. "sync"
  18. "github.com/Microsoft/hcsshim"
  19. "github.com/Sirupsen/logrus"
  20. "github.com/docker/libnetwork/datastore"
  21. "github.com/docker/libnetwork/discoverapi"
  22. "github.com/docker/libnetwork/driverapi"
  23. "github.com/docker/libnetwork/netlabel"
  24. "github.com/docker/libnetwork/types"
  25. )
  26. // networkConfiguration for network specific configuration
  27. type networkConfiguration struct {
  28. ID string
  29. Type string
  30. Name string
  31. HnsID string
  32. RDID string
  33. VLAN uint
  34. VSID uint
  35. DNSServers string
  36. DNSSuffix string
  37. SourceMac string
  38. NetworkAdapterName string
  39. dbIndex uint64
  40. dbExists bool
  41. }
  42. // endpointConfiguration represents the user specified configuration for the sandbox endpoint
  43. type endpointOption struct {
  44. MacAddress net.HardwareAddr
  45. QosPolicies []types.QosPolicy
  46. DNSServers []string
  47. DisableDNS bool
  48. DisableICC bool
  49. }
  50. type endpointConnectivity struct {
  51. PortBindings []types.PortBinding
  52. ExposedPorts []types.TransportPort
  53. }
  54. type hnsEndpoint struct {
  55. id string
  56. nid string
  57. profileID string
  58. Type string
  59. macAddress net.HardwareAddr
  60. epOption *endpointOption // User specified parameters
  61. epConnectivity *endpointConnectivity // User specified parameters
  62. portMapping []types.PortBinding // Operation port bindings
  63. addr *net.IPNet
  64. gateway net.IP
  65. dbIndex uint64
  66. dbExists bool
  67. }
  68. type hnsNetwork struct {
  69. id string
  70. created bool
  71. config *networkConfiguration
  72. endpoints map[string]*hnsEndpoint // key: endpoint id
  73. driver *driver // The network's driver
  74. sync.Mutex
  75. }
  76. type driver struct {
  77. name string
  78. networks map[string]*hnsNetwork
  79. store datastore.DataStore
  80. sync.Mutex
  81. }
  82. const (
  83. errNotFound = "HNS failed with error : The object identifier does not represent a valid object. "
  84. )
  85. // IsBuiltinWindowsDriver vaidates if network-type is a builtin local-scoped driver
  86. func IsBuiltinLocalDriver(networkType string) bool {
  87. if "l2bridge" == networkType || "l2tunnel" == networkType || "nat" == networkType || "ics" == networkType || "transparent" == networkType {
  88. return true
  89. }
  90. return false
  91. }
  92. // New constructs a new bridge driver
  93. func newDriver(networkType string) *driver {
  94. return &driver{name: networkType, networks: map[string]*hnsNetwork{}}
  95. }
  96. // GetInit returns an initializer for the given network type
  97. func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error {
  98. return func(dc driverapi.DriverCallback, config map[string]interface{}) error {
  99. if !IsBuiltinLocalDriver(networkType) {
  100. return types.BadRequestErrorf("Network type not supported: %s", networkType)
  101. }
  102. d := newDriver(networkType)
  103. err := d.initStore(config)
  104. if err != nil {
  105. return err
  106. }
  107. return dc.RegisterDriver(networkType, d, driverapi.Capability{
  108. DataScope: datastore.LocalScope,
  109. ConnectivityScope: datastore.LocalScope,
  110. })
  111. }
  112. }
  113. func (d *driver) getNetwork(id string) (*hnsNetwork, error) {
  114. d.Lock()
  115. defer d.Unlock()
  116. if nw, ok := d.networks[id]; ok {
  117. return nw, nil
  118. }
  119. return nil, types.NotFoundErrorf("network not found: %s", id)
  120. }
  121. func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) {
  122. n.Lock()
  123. defer n.Unlock()
  124. if ep, ok := n.endpoints[eid]; ok {
  125. return ep, nil
  126. }
  127. return nil, types.NotFoundErrorf("Endpoint not found: %s", eid)
  128. }
  129. func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) {
  130. config := &networkConfiguration{Type: d.name}
  131. for label, value := range genericOptions {
  132. switch label {
  133. case NetworkName:
  134. config.Name = value
  135. case HNSID:
  136. config.HnsID = value
  137. case RoutingDomain:
  138. config.RDID = value
  139. case Interface:
  140. config.NetworkAdapterName = value
  141. case DNSSuffix:
  142. config.DNSSuffix = value
  143. case DNSServers:
  144. config.DNSServers = value
  145. case VLAN:
  146. vlan, err := strconv.ParseUint(value, 10, 32)
  147. if err != nil {
  148. return nil, err
  149. }
  150. config.VLAN = uint(vlan)
  151. case VSID:
  152. vsid, err := strconv.ParseUint(value, 10, 32)
  153. if err != nil {
  154. return nil, err
  155. }
  156. config.VSID = uint(vsid)
  157. }
  158. }
  159. config.ID = id
  160. config.Type = d.name
  161. return config, nil
  162. }
  163. func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
  164. if len(ipamV6Data) > 0 {
  165. return types.ForbiddenErrorf("windowsshim driver doesn't support v6 subnets")
  166. }
  167. if len(ipamV4Data) == 0 {
  168. return types.BadRequestErrorf("network %s requires ipv4 configuration", id)
  169. }
  170. return nil
  171. }
  172. func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
  173. }
  174. func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
  175. return "", nil
  176. }
  177. func (d *driver) createNetwork(config *networkConfiguration) error {
  178. network := &hnsNetwork{
  179. id: config.ID,
  180. endpoints: make(map[string]*hnsEndpoint),
  181. config: config,
  182. driver: d,
  183. }
  184. d.Lock()
  185. d.networks[config.ID] = network
  186. d.Unlock()
  187. return nil
  188. }
  189. // Create a new network
  190. func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
  191. if _, err := d.getNetwork(id); err == nil {
  192. return types.ForbiddenErrorf("network %s exists", id)
  193. }
  194. genData, ok := option[netlabel.GenericData].(map[string]string)
  195. if !ok {
  196. return fmt.Errorf("Unknown generic data option")
  197. }
  198. // Parse and validate the config. It should not conflict with existing networks' config
  199. config, err := d.parseNetworkOptions(id, genData)
  200. if err != nil {
  201. return err
  202. }
  203. err = config.processIPAM(id, ipV4Data, ipV6Data)
  204. if err != nil {
  205. return err
  206. }
  207. err = d.createNetwork(config)
  208. if err != nil {
  209. return err
  210. }
  211. // A non blank hnsid indicates that the network was discovered
  212. // from HNS. No need to call HNS if this network was discovered
  213. // from HNS
  214. if config.HnsID == "" {
  215. subnets := []hcsshim.Subnet{}
  216. for _, ipData := range ipV4Data {
  217. subnet := hcsshim.Subnet{
  218. AddressPrefix: ipData.Pool.String(),
  219. }
  220. if ipData.Gateway != nil {
  221. subnet.GatewayAddress = ipData.Gateway.IP.String()
  222. }
  223. subnets = append(subnets, subnet)
  224. }
  225. network := &hcsshim.HNSNetwork{
  226. Name: config.Name,
  227. Type: d.name,
  228. Subnets: subnets,
  229. DNSServerList: config.DNSServers,
  230. DNSSuffix: config.DNSSuffix,
  231. SourceMac: config.SourceMac,
  232. NetworkAdapterName: config.NetworkAdapterName,
  233. }
  234. if config.VLAN != 0 {
  235. vlanPolicy, err := json.Marshal(hcsshim.VlanPolicy{
  236. Type: "VLAN",
  237. VLAN: config.VLAN,
  238. })
  239. if err != nil {
  240. return err
  241. }
  242. network.Policies = append(network.Policies, vlanPolicy)
  243. }
  244. if config.VSID != 0 {
  245. vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{
  246. Type: "VSID",
  247. VSID: config.VSID,
  248. })
  249. if err != nil {
  250. return err
  251. }
  252. network.Policies = append(network.Policies, vsidPolicy)
  253. }
  254. if network.Name == "" {
  255. network.Name = id
  256. }
  257. configurationb, err := json.Marshal(network)
  258. if err != nil {
  259. return err
  260. }
  261. configuration := string(configurationb)
  262. logrus.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets)
  263. hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
  264. if err != nil {
  265. return err
  266. }
  267. config.HnsID = hnsresponse.Id
  268. genData[HNSID] = config.HnsID
  269. }
  270. n, err := d.getNetwork(id)
  271. n.created = true
  272. return d.storeUpdate(config)
  273. }
  274. func (d *driver) DeleteNetwork(nid string) error {
  275. n, err := d.getNetwork(nid)
  276. if err != nil {
  277. return types.InternalMaskableErrorf("%s", err)
  278. }
  279. n.Lock()
  280. config := n.config
  281. n.Unlock()
  282. if n.created {
  283. _, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "")
  284. if err != nil && err.Error() != errNotFound {
  285. return types.ForbiddenErrorf(err.Error())
  286. }
  287. }
  288. d.Lock()
  289. delete(d.networks, nid)
  290. d.Unlock()
  291. // delele endpoints belong to this network
  292. for _, ep := range n.endpoints {
  293. if err := d.storeDelete(ep); err != nil {
  294. logrus.Warnf("Failed to remove bridge endpoint %s from store: %v", ep.id[0:7], err)
  295. }
  296. }
  297. return d.storeDelete(config)
  298. }
  299. func convertQosPolicies(qosPolicies []types.QosPolicy) ([]json.RawMessage, error) {
  300. var qps []json.RawMessage
  301. // Enumerate through the qos policies specified by the user and convert
  302. // them into the internal structure matching the JSON blob that can be
  303. // understood by the HCS.
  304. for _, elem := range qosPolicies {
  305. encodedPolicy, err := json.Marshal(hcsshim.QosPolicy{
  306. Type: "QOS",
  307. MaximumOutgoingBandwidthInBytes: elem.MaxEgressBandwidth,
  308. })
  309. if err != nil {
  310. return nil, err
  311. }
  312. qps = append(qps, encodedPolicy)
  313. }
  314. return qps, nil
  315. }
  316. func convertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) {
  317. var pbs []json.RawMessage
  318. // Enumerate through the port bindings specified by the user and convert
  319. // them into the internal structure matching the JSON blob that can be
  320. // understood by the HCS.
  321. for _, elem := range portBindings {
  322. proto := strings.ToUpper(elem.Proto.String())
  323. if proto != "TCP" && proto != "UDP" {
  324. return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String())
  325. }
  326. if elem.HostPort != elem.HostPortEnd {
  327. return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings")
  328. }
  329. if len(elem.HostIP) != 0 {
  330. return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings")
  331. }
  332. encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{
  333. Type: "NAT",
  334. ExternalPort: elem.HostPort,
  335. InternalPort: elem.Port,
  336. Protocol: elem.Proto.String(),
  337. })
  338. if err != nil {
  339. return nil, err
  340. }
  341. pbs = append(pbs, encodedPolicy)
  342. }
  343. return pbs, nil
  344. }
  345. func parsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) {
  346. var bindings []types.PortBinding
  347. hcsPolicy := &hcsshim.NatPolicy{}
  348. for _, elem := range policies {
  349. if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" {
  350. continue
  351. }
  352. binding := types.PortBinding{
  353. HostPort: hcsPolicy.ExternalPort,
  354. HostPortEnd: hcsPolicy.ExternalPort,
  355. Port: hcsPolicy.InternalPort,
  356. Proto: types.ParseProtocol(hcsPolicy.Protocol),
  357. HostIP: net.IPv4(0, 0, 0, 0),
  358. }
  359. bindings = append(bindings, binding)
  360. }
  361. return bindings, nil
  362. }
  363. func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) {
  364. if epOptions == nil {
  365. return nil, nil
  366. }
  367. ec := &endpointOption{}
  368. if opt, ok := epOptions[netlabel.MacAddress]; ok {
  369. if mac, ok := opt.(net.HardwareAddr); ok {
  370. ec.MacAddress = mac
  371. } else {
  372. return nil, fmt.Errorf("Invalid endpoint configuration")
  373. }
  374. }
  375. if opt, ok := epOptions[QosPolicies]; ok {
  376. if policies, ok := opt.([]types.QosPolicy); ok {
  377. ec.QosPolicies = policies
  378. } else {
  379. return nil, fmt.Errorf("Invalid endpoint configuration")
  380. }
  381. }
  382. if opt, ok := epOptions[netlabel.DNSServers]; ok {
  383. if dns, ok := opt.([]string); ok {
  384. ec.DNSServers = dns
  385. } else {
  386. return nil, fmt.Errorf("Invalid endpoint configuration")
  387. }
  388. }
  389. if opt, ok := epOptions[DisableICC]; ok {
  390. if disableICC, ok := opt.(bool); ok {
  391. ec.DisableICC = disableICC
  392. } else {
  393. return nil, fmt.Errorf("Invalid endpoint configuration")
  394. }
  395. }
  396. if opt, ok := epOptions[DisableDNS]; ok {
  397. if disableDNS, ok := opt.(bool); ok {
  398. ec.DisableDNS = disableDNS
  399. } else {
  400. return nil, fmt.Errorf("Invalid endpoint configuration")
  401. }
  402. }
  403. return ec, nil
  404. }
  405. func parseEndpointConnectivity(epOptions map[string]interface{}) (*endpointConnectivity, error) {
  406. if epOptions == nil {
  407. return nil, nil
  408. }
  409. ec := &endpointConnectivity{}
  410. if opt, ok := epOptions[netlabel.PortMap]; ok {
  411. if bs, ok := opt.([]types.PortBinding); ok {
  412. ec.PortBindings = bs
  413. } else {
  414. return nil, fmt.Errorf("Invalid endpoint configuration")
  415. }
  416. }
  417. if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
  418. if ports, ok := opt.([]types.TransportPort); ok {
  419. ec.ExposedPorts = ports
  420. } else {
  421. return nil, fmt.Errorf("Invalid endpoint configuration")
  422. }
  423. }
  424. return ec, nil
  425. }
  426. func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
  427. n, err := d.getNetwork(nid)
  428. if err != nil {
  429. return err
  430. }
  431. // Check if endpoint id is good and retrieve corresponding endpoint
  432. ep, err := n.getEndpoint(eid)
  433. if err == nil && ep != nil {
  434. return driverapi.ErrEndpointExists(eid)
  435. }
  436. endpointStruct := &hcsshim.HNSEndpoint{
  437. VirtualNetwork: n.config.HnsID,
  438. }
  439. epOption, err := parseEndpointOptions(epOptions)
  440. epConnectivity, err := parseEndpointConnectivity(epOptions)
  441. macAddress := ifInfo.MacAddress()
  442. // Use the macaddress if it was provided
  443. if macAddress != nil {
  444. endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1)
  445. }
  446. endpointStruct.Policies, err = convertPortBindings(epConnectivity.PortBindings)
  447. if err != nil {
  448. return err
  449. }
  450. qosPolicies, err := convertQosPolicies(epOption.QosPolicies)
  451. if err != nil {
  452. return err
  453. }
  454. endpointStruct.Policies = append(endpointStruct.Policies, qosPolicies...)
  455. if ifInfo.Address() != nil {
  456. endpointStruct.IPAddress = ifInfo.Address().IP
  457. }
  458. endpointStruct.DNSServerList = strings.Join(epOption.DNSServers, ",")
  459. if n.driver.name == "nat" && !epOption.DisableDNS {
  460. endpointStruct.EnableInternalDNS = true
  461. }
  462. endpointStruct.DisableICC = epOption.DisableICC
  463. configurationb, err := json.Marshal(endpointStruct)
  464. if err != nil {
  465. return err
  466. }
  467. hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb))
  468. if err != nil {
  469. return err
  470. }
  471. mac, err := net.ParseMAC(hnsresponse.MacAddress)
  472. if err != nil {
  473. return err
  474. }
  475. // TODO For now the ip mask is not in the info generated by HNS
  476. endpoint := &hnsEndpoint{
  477. id: eid,
  478. nid: n.id,
  479. Type: d.name,
  480. addr: &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
  481. macAddress: mac,
  482. }
  483. if hnsresponse.GatewayAddress != "" {
  484. endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress)
  485. }
  486. endpoint.profileID = hnsresponse.Id
  487. endpoint.epConnectivity = epConnectivity
  488. endpoint.epOption = epOption
  489. endpoint.portMapping, err = parsePortBindingPolicies(hnsresponse.Policies)
  490. if err != nil {
  491. hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "")
  492. return err
  493. }
  494. n.Lock()
  495. n.endpoints[eid] = endpoint
  496. n.Unlock()
  497. if ifInfo.Address() == nil {
  498. ifInfo.SetIPAddress(endpoint.addr)
  499. }
  500. if macAddress == nil {
  501. ifInfo.SetMacAddress(endpoint.macAddress)
  502. }
  503. if err = d.storeUpdate(endpoint); err != nil {
  504. return fmt.Errorf("failed to save endpoint %s to store: %v", endpoint.id[0:7], err)
  505. }
  506. return nil
  507. }
  508. func (d *driver) DeleteEndpoint(nid, eid string) error {
  509. n, err := d.getNetwork(nid)
  510. if err != nil {
  511. return types.InternalMaskableErrorf("%s", err)
  512. }
  513. ep, err := n.getEndpoint(eid)
  514. if err != nil {
  515. return err
  516. }
  517. n.Lock()
  518. delete(n.endpoints, eid)
  519. n.Unlock()
  520. _, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "")
  521. if err != nil && err.Error() != errNotFound {
  522. return err
  523. }
  524. if err := d.storeDelete(ep); err != nil {
  525. logrus.Warnf("Failed to remove bridge endpoint %s from store: %v", ep.id[0:7], err)
  526. }
  527. return nil
  528. }
  529. func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
  530. network, err := d.getNetwork(nid)
  531. if err != nil {
  532. return nil, err
  533. }
  534. ep, err := network.getEndpoint(eid)
  535. if err != nil {
  536. return nil, err
  537. }
  538. data := make(map[string]interface{}, 1)
  539. if network.driver.name == "nat" {
  540. data["AllowUnqualifiedDNSQuery"] = true
  541. }
  542. data["hnsid"] = ep.profileID
  543. if ep.epConnectivity.ExposedPorts != nil {
  544. // Return a copy of the config data
  545. epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts))
  546. for _, tp := range ep.epConnectivity.ExposedPorts {
  547. epc = append(epc, tp.GetCopy())
  548. }
  549. data[netlabel.ExposedPorts] = epc
  550. }
  551. if ep.portMapping != nil {
  552. // Return a copy of the operational data
  553. pmc := make([]types.PortBinding, 0, len(ep.portMapping))
  554. for _, pm := range ep.portMapping {
  555. pmc = append(pmc, pm.GetCopy())
  556. }
  557. data[netlabel.PortMap] = pmc
  558. }
  559. if len(ep.macAddress) != 0 {
  560. data[netlabel.MacAddress] = ep.macAddress
  561. }
  562. return data, nil
  563. }
  564. // Join method is invoked when a Sandbox is attached to an endpoint.
  565. func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
  566. network, err := d.getNetwork(nid)
  567. if err != nil {
  568. return err
  569. }
  570. // Ensure that the endpoint exists
  571. endpoint, err := network.getEndpoint(eid)
  572. if err != nil {
  573. return err
  574. }
  575. err = jinfo.SetGateway(endpoint.gateway)
  576. if err != nil {
  577. return err
  578. }
  579. // This is just a stub for now
  580. jinfo.DisableGatewayService()
  581. return nil
  582. }
  583. // Leave method is invoked when a Sandbox detaches from an endpoint.
  584. func (d *driver) Leave(nid, eid string) error {
  585. network, err := d.getNetwork(nid)
  586. if err != nil {
  587. return types.InternalMaskableErrorf("%s", err)
  588. }
  589. // Ensure that the endpoint exists
  590. _, err = network.getEndpoint(eid)
  591. if err != nil {
  592. return err
  593. }
  594. // This is just a stub for now
  595. return nil
  596. }
  597. func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
  598. return nil
  599. }
  600. func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
  601. return nil
  602. }
  603. func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
  604. return nil, types.NotImplementedErrorf("not implemented")
  605. }
  606. func (d *driver) NetworkFree(id string) error {
  607. return types.NotImplementedErrorf("not implemented")
  608. }
  609. func (d *driver) Type() string {
  610. return d.name
  611. }
  612. func (d *driver) IsBuiltIn() bool {
  613. return true
  614. }
  615. // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
  616. func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
  617. return nil
  618. }
  619. // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
  620. func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
  621. return nil
  622. }