package libnetwork import ( "encoding/json" "net" "github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/types" ) // EndpointInfo provides an interface to retrieve network resources bound to the endpoint. type EndpointInfo interface { // Iface returns InterfaceInfo, go interface that can be used // to get more information on the interface which was assigned to // the endpoint by the driver. This can be used after the // endpoint has been created. Iface() InterfaceInfo // Gateway returns the IPv4 gateway assigned by the driver. // This will only return a valid value if a container has joined the endpoint. Gateway() net.IP // GatewayIPv6 returns the IPv6 gateway assigned by the driver. // This will only return a valid value if a container has joined the endpoint. GatewayIPv6() net.IP // Sandbox returns the attached sandbox if there, nil otherwise. Sandbox() Sandbox } // InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint. type InterfaceInfo interface { // MacAddress returns the MAC address assigned to the endpoint. MacAddress() net.HardwareAddr // Address returns the IPv4 address assigned to the endpoint. Address() *net.IPNet // AddressIPv6 returns the IPv6 address assigned to the endpoint. AddressIPv6() *net.IPNet } type endpointInterface struct { mac net.HardwareAddr addr *net.IPNet addrv6 *net.IPNet srcName string dstPrefix string routes []*net.IPNet poolID string } func (epi *endpointInterface) MarshalJSON() ([]byte, error) { epMap := make(map[string]interface{}) if epi.mac != nil { epMap["mac"] = epi.mac.String() } if epi.addr != nil { epMap["addr"] = epi.addr.String() } if epi.addrv6 != nil { epMap["addrv6"] = epi.addrv6.String() } epMap["srcName"] = epi.srcName epMap["dstPrefix"] = epi.dstPrefix var routes []string for _, route := range epi.routes { routes = append(routes, route.String()) } epMap["routes"] = routes epMap["poolID"] = epi.poolID return json.Marshal(epMap) } func (epi *endpointInterface) UnmarshalJSON(b []byte) error { var ( err error epMap map[string]interface{} ) if err = json.Unmarshal(b, &epMap); err != nil { return err } if v, ok := epMap["mac"]; ok { if epi.mac, err = net.ParseMAC(v.(string)); err != nil { return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string)) } } if v, ok := epMap["addr"]; ok { if epi.addr, err = types.ParseCIDR(v.(string)); err != nil { return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err) } } if v, ok := epMap["addrv6"]; ok { if epi.addrv6, err = types.ParseCIDR(v.(string)); err != nil { return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err) } } epi.srcName = epMap["srcName"].(string) epi.dstPrefix = epMap["dstPrefix"].(string) rb, _ := json.Marshal(epMap["routes"]) var routes []string json.Unmarshal(rb, &routes) epi.routes = make([]*net.IPNet, 0) for _, route := range routes { ip, ipr, err := net.ParseCIDR(route) if err == nil { ipr.IP = ip epi.routes = append(epi.routes, ipr) } } epi.poolID = epMap["poolID"].(string) return nil } type endpointJoinInfo struct { gw net.IP gw6 net.IP StaticRoutes []*types.StaticRoute } func (ep *endpoint) Info() EndpointInfo { return ep } func (ep *endpoint) DriverInfo() (map[string]interface{}, error) { ep.Lock() network := ep.network epid := ep.id ep.Unlock() network.Lock() driver := network.driver nid := network.id network.Unlock() return driver.EndpointOperInfo(nid, epid) } func (ep *endpoint) Iface() InterfaceInfo { ep.Lock() defer ep.Unlock() if ep.iface != nil { return ep.iface } return nil } func (ep *endpoint) Interface() driverapi.InterfaceInfo { ep.Lock() defer ep.Unlock() if ep.iface != nil { return ep.iface } return nil } func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error { if epi.mac != nil { return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac) } if mac == nil { return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface") } epi.mac = types.GetMacCopy(mac) return nil } func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error { if address.IP == nil { return types.BadRequestErrorf("tried to set nil IP address to endpoint interface") } if address.IP.To4() == nil { return setAddress(&epi.addrv6, address) } return setAddress(&epi.addr, address) } func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error { if *ifaceAddr != nil { return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address) } *ifaceAddr = types.GetIPNetCopy(address) return nil } func (epi *endpointInterface) MacAddress() net.HardwareAddr { return types.GetMacCopy(epi.mac) } func (epi *endpointInterface) Address() *net.IPNet { return types.GetIPNetCopy(epi.addr) } func (epi *endpointInterface) AddressIPv6() *net.IPNet { return types.GetIPNetCopy(epi.addrv6) } func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error { epi.srcName = srcName epi.dstPrefix = dstPrefix return nil } func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo { ep.Lock() defer ep.Unlock() if ep.iface != nil { return ep.iface } return nil } func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error { ep.Lock() defer ep.Unlock() r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop} if routeType == types.NEXTHOP { // If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface). ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r) } else { // If the route doesn't specify a next-hop, it must be a connected route, bound to an interface. ep.iface.routes = append(ep.iface.routes, r.Destination) } return nil } func (ep *endpoint) Sandbox() Sandbox { cnt, ok := ep.getSandbox() if !ok { return nil } return cnt } func (ep *endpoint) Gateway() net.IP { ep.Lock() defer ep.Unlock() if ep.joinInfo == nil { return net.IP{} } return types.GetIPCopy(ep.joinInfo.gw) } func (ep *endpoint) GatewayIPv6() net.IP { ep.Lock() defer ep.Unlock() if ep.joinInfo == nil { return net.IP{} } return types.GetIPCopy(ep.joinInfo.gw6) } func (ep *endpoint) SetGateway(gw net.IP) error { ep.Lock() defer ep.Unlock() ep.joinInfo.gw = types.GetIPCopy(gw) return nil } func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error { ep.Lock() defer ep.Unlock() ep.joinInfo.gw6 = types.GetIPCopy(gw6) return nil }