1// Copyright 2016 VMware, Inc. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package network 16 17import ( 18 "fmt" 19 "net" 20 21 "github.com/vmware/vic/lib/portlayer/exec" 22 "github.com/vmware/vic/pkg/ip" 23 "github.com/vmware/vic/pkg/uid" 24) 25 26type alias struct { 27 Name string 28 Container string 29 30 ep *Endpoint 31} 32 33var badAlias = alias{} 34 35type Endpoint struct { 36 container *Container 37 scope *Scope 38 ip net.IP 39 static bool 40 ports map[Port]interface{} // exposed ports 41 aliases map[string][]alias 42 gw *net.IP 43 subnet *net.IPNet 44} 45 46// scopeName returns the "fully qualified" name of an alias. Aliases are scoped 47// by the container and network scope they are in. 48func (a alias) scopedName() string { 49 // an alias for the container itself is network scoped 50 for _, al := range a.ep.getAliases("") { 51 if a.Name == al.Name { 52 return ScopedAliasName(a.ep.Scope().Name(), "", a.Name) 53 } 54 } 55 56 return ScopedAliasName(a.ep.Scope().Name(), a.ep.Container().Name(), a.Name) 57} 58 59// ScopedAliasName returns the fully qualified name of an alias, scoped to 60// the scope and optionally a container 61func ScopedAliasName(scope string, container string, alias string) string { 62 if container != "" { 63 return fmt.Sprintf("%s:%s:%s", scope, container, alias) 64 } 65 66 return fmt.Sprintf("%s:%s", scope, alias) 67} 68 69func newEndpoint(container *Container, scope *Scope, eip *net.IP, pciSlot *int32) *Endpoint { 70 e := &Endpoint{ 71 container: container, 72 scope: scope, 73 ip: net.IPv4(0, 0, 0, 0), 74 static: false, 75 ports: make(map[Port]interface{}), 76 aliases: make(map[string][]alias), 77 } 78 79 if eip != nil && !ip.IsUnspecifiedIP(*eip) { 80 e.ip = *eip 81 e.static = true 82 } 83 84 return e 85} 86 87func removeEndpointHelper(ep *Endpoint, eps []*Endpoint) []*Endpoint { 88 for i, e := range eps { 89 if ep != e { 90 continue 91 } 92 93 return append(eps[:i], eps[i+1:]...) 94 } 95 96 return eps 97} 98 99func (e *Endpoint) addPort(p Port) error { 100 if _, ok := e.ports[p]; ok { 101 return fmt.Errorf("port %s already exposed", p) 102 } 103 104 e.ports[p] = nil 105 return nil 106} 107 108func (e *Endpoint) IP() net.IP { 109 return e.ip 110} 111 112func (e *Endpoint) Scope() *Scope { 113 return e.scope 114} 115 116func (e *Endpoint) Subnet() *net.IPNet { 117 if e.subnet != nil { 118 return e.subnet 119 } 120 121 return e.Scope().Subnet() 122} 123 124func (e *Endpoint) Container() *Container { 125 return e.container 126} 127 128func (e *Endpoint) ID() uid.UID { 129 return e.container.ID() 130} 131 132func (e *Endpoint) Name() string { 133 return e.container.Name() 134} 135 136func (e *Endpoint) Gateway() net.IP { 137 if e.gw != nil { 138 return *e.gw 139 } 140 141 return e.Scope().Gateway() 142} 143 144func (e *Endpoint) Ports() []Port { 145 ports := make([]Port, len(e.ports)) 146 i := 0 147 for p := range e.ports { 148 ports[i] = p 149 i++ 150 } 151 152 return ports 153} 154 155func (e *Endpoint) addAlias(con, a string) (alias, bool) { 156 if a == "" { 157 return badAlias, false 158 } 159 160 if con == "" { 161 con = e.container.Name() 162 } 163 164 aliases := e.aliases[con] 165 for _, as := range aliases { 166 if as.Name == a { 167 // already present 168 return as, true 169 } 170 } 171 172 na := alias{ 173 Name: a, 174 Container: con, 175 ep: e, 176 } 177 e.aliases[con] = append(aliases, na) 178 return na, false 179} 180 181func (e *Endpoint) getAliases(con string) []alias { 182 if con == "" { 183 con = e.container.Name() 184 } 185 186 return e.aliases[con] 187} 188 189func (e *Endpoint) copy() *Endpoint { 190 other := *e 191 other.aliases = make(map[string][]alias) 192 for k, v := range e.aliases { 193 a := make([]alias, len(v)) 194 copy(a, v) 195 other.aliases[k] = a 196 } 197 other.ports = make(map[Port]interface{}) 198 for p := range e.ports { 199 other.ports[p] = nil 200 } 201 202 return &other 203} 204 205func (e *Endpoint) refresh(h *exec.Handle) error { 206 if !e.scope.isDynamic() { 207 return nil 208 } 209 210 s := e.scope 211 ne := h.ExecConfig.Networks[s.Name()] 212 if ne == nil { 213 return fmt.Errorf("container config does not have info for network scope %s", s.Name()) 214 } 215 216 if ip.IsUnspecifiedSubnet(&ne.Network.Assigned.Gateway) { 217 return fmt.Errorf("updating endpoint for container %s: gateway not present for scope %s", h.ExecConfig.ID, s.name) 218 } 219 220 gw, snet, err := net.ParseCIDR(ne.Network.Assigned.Gateway.String()) 221 if err != nil { 222 return fmt.Errorf("could not parse gateway for container %s: %s", h.ExecConfig.ID, err) 223 } 224 225 e.ip = ne.Assigned.IP 226 e.gw = &gw 227 e.subnet = snet 228 return nil 229} 230