go.ligato.io/vpp-agent/v3@v3.5.0/proto/ligato/linux/interfaces/models.go (about) 1 // Copyright (c) 2017 Cisco and/or its affiliates. 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 15 package linux_interfaces 16 17 import ( 18 "strings" 19 20 "go.ligato.io/vpp-agent/v3/pkg/models" 21 "go.ligato.io/vpp-agent/v3/proto/ligato/netalloc" 22 ) 23 24 // ModuleName is the module name used for models. 25 const ModuleName = "linux.interfaces" 26 27 var ( 28 ModelInterface = models.Register(&Interface{}, models.Spec{ 29 Module: ModuleName, 30 Version: "v2", 31 Type: "interface", 32 }) 33 ) 34 35 // InterfaceKey returns the key used in ETCD to store configuration of a particular Linux interface. 36 func InterfaceKey(name string) string { 37 return models.Key(&Interface{ 38 Name: name, 39 }) 40 } 41 42 const ( 43 /* Interface host-name (default ns only, notifications) */ 44 45 // InterfaceHostNameKeyPrefix is the common prefix of all keys representing 46 // existing Linux interfaces in the default namespace (referenced by host names). 47 InterfaceHostNameKeyPrefix = "linux/interface/host-name/" 48 49 interfaceHostNameWithAddrKeyTmpl = InterfaceHostNameKeyPrefix + "{host-name}/address/{address}" 50 interfaceHostNameWithVrfKeyTmpl = InterfaceHostNameKeyPrefix + "{host-name}/vrf-host-name/{vrf-host-name}" 51 52 /* Interface State (derived) */ 53 54 // InterfaceStateKeyPrefix is used as a common prefix for keys derived from 55 // interfaces to represent the interface admin state (up/down). 56 InterfaceStateKeyPrefix = "linux/interface/state/" 57 58 // interfaceStateKeyTemplate is a template for (derived) key representing interface 59 // admin state (up/down). 60 interfaceStateKeyTemplate = InterfaceStateKeyPrefix + "{ifName}/{ifState}" 61 62 // interface admin state as printed in derived keys. 63 interfaceUpState = "UP" 64 interfaceDownState = "DOWN" 65 66 /* Interface Address (derived) */ 67 68 // interfaceAddressKeyPrefix is used as a common prefix for keys derived from 69 // interfaces to represent assigned IP addresses. 70 interfaceAddrKeyPrefix = "linux/interface/{iface}/address/" 71 72 // interfaceAddrKeyTmpl is a template for (derived) key representing IP address 73 // (incl. mask) assigned to a Linux interface (referenced by the logical name). 74 interfaceAddrKeyTmpl = interfaceAddrKeyPrefix + "{address-source}/{address}" 75 76 /* Interface VRF (derived) */ 77 78 // interfaceVrfKeyTmpl is a template for (derived) key representing assignment 79 // of a Linux interface into a VRF. 80 interfaceVrfKeyTmpl = "linux/interface/{iface}/vrf/{vrf}" 81 ) 82 83 const ( 84 // InvalidKeyPart is used in key for parts which are invalid 85 InvalidKeyPart = "<invalid>" 86 ) 87 88 /* Interface host-name (default ns only, notifications) */ 89 90 // InterfaceHostNameKey returns key representing Linux interface host name. 91 func InterfaceHostNameKey(hostName string) string { 92 return InterfaceHostNameKeyPrefix + hostName 93 } 94 95 // InterfaceHostNameWithAddrKey returns key representing assignment of an IP address 96 // to a Linux interface referenced by its host name. 97 // If address is empty, the function returns key prefix matching any IP address. 98 func InterfaceHostNameWithAddrKey(hostName, address string) string { 99 if hostName == "" { 100 hostName = InvalidKeyPart 101 } 102 tmpl := interfaceHostNameWithAddrKeyTmpl 103 key := strings.Replace(tmpl, "{host-name}", hostName, 1) 104 key = strings.Replace(key, "{address}", address, 1) 105 return key 106 } 107 108 // InterfaceHostNameWithVrfKey returns key representing association between Linux 109 // interface and Linux VRF, both referenced by host names. 110 // If vrf is empty, the function returns key prefix matching any VRF. 111 func InterfaceHostNameWithVrfKey(hostName, vrf string) string { 112 if hostName == "" { 113 hostName = InvalidKeyPart 114 } 115 tmpl := interfaceHostNameWithVrfKeyTmpl 116 key := strings.Replace(tmpl, "{host-name}", hostName, 1) 117 key = strings.Replace(key, "{vrf-host-name}", vrf, 1) 118 return key 119 } 120 121 /* Interface State (derived) */ 122 123 // InterfaceStateKey returns key representing admin state of a Linux interface. 124 func InterfaceStateKey(ifName string, ifIsUp bool) string { 125 ifState := interfaceDownState 126 if ifIsUp { 127 ifState = interfaceUpState 128 } 129 key := strings.Replace(interfaceStateKeyTemplate, "{ifName}", ifName, 1) 130 key = strings.Replace(key, "{ifState}", ifState, 1) 131 return key 132 } 133 134 // ParseInterfaceStateKey parses interface name and state from key derived 135 // from interface by InterfaceStateKey(). 136 func ParseInterfaceStateKey(key string) (ifName string, ifIsUp bool, isStateKey bool) { 137 if strings.HasPrefix(key, InterfaceStateKeyPrefix) { 138 keySuffix := strings.TrimPrefix(key, InterfaceStateKeyPrefix) 139 keyComps := strings.Split(keySuffix, "/") 140 if len(keyComps) != 2 { 141 return "", false, false 142 } 143 ifName = keyComps[0] 144 isStateKey = true 145 if keyComps[1] == interfaceUpState { 146 ifIsUp = true 147 } 148 return 149 } 150 return "", false, false 151 } 152 153 /* Interface Address (derived) */ 154 155 // InterfaceAddressPrefix returns longest-common prefix of keys representing 156 // assigned IP addresses to a specific Linux interface. 157 func InterfaceAddressPrefix(iface string) string { 158 if iface == "" { 159 iface = InvalidKeyPart 160 } 161 return strings.Replace(interfaceAddrKeyPrefix, "{iface}", iface, 1) 162 } 163 164 // InterfaceAddressKey returns key representing IP address assigned to Linux interface. 165 // With undefined vrf the returned key can be also used as a key prefix, matching derived 166 // interface address key regardless of the VRF to which it belongs. 167 func InterfaceAddressKey(iface, address string, source netalloc.IPAddressSource) string { 168 if iface == "" { 169 iface = InvalidKeyPart 170 } 171 172 src := source.String() 173 if src == "" { 174 src = InvalidKeyPart 175 } 176 if strings.HasPrefix(address, netalloc.AllocRefPrefix) { 177 src = netalloc.IPAddressSource_ALLOC_REF.String() 178 } 179 src = strings.ToLower(src) 180 181 // construct key without validating the IP address 182 tmpl := interfaceAddrKeyTmpl 183 key := strings.Replace(tmpl, "{iface}", iface, 1) 184 key = strings.Replace(key, "{address-source}", src, 1) 185 key = strings.Replace(key, "{address}", address, 1) 186 return key 187 } 188 189 // ParseInterfaceAddressKey parses interface address from key derived 190 // from interface by InterfaceAddressKey(). 191 func ParseInterfaceAddressKey(key string) (iface, address string, source netalloc.IPAddressSource, 192 invalidKey, isAddrKey bool) { 193 parts := strings.Split(key, "/") 194 if len(parts) < 4 || parts[0] != "linux" || parts[1] != "interface" { 195 return 196 } 197 if parts[2] == "state" || parts[2] == "host-name" { 198 return 199 } 200 201 addrIdx := -1 202 for idx, part := range parts { 203 switch part { 204 case "vrf": 205 // avoid collision with InterfaceVrfKey 206 return 207 case "address": 208 addrIdx = idx 209 } 210 } 211 if addrIdx == -1 { 212 return 213 } 214 isAddrKey = true 215 216 // parse interface name 217 iface = strings.Join(parts[2:addrIdx], "/") 218 if iface == "" { 219 iface = InvalidKeyPart 220 invalidKey = true 221 } 222 223 // parse address source 224 src := strings.ToUpper(parts[addrIdx+1]) 225 srcInt, validSrc := netalloc.IPAddressSource_value[src] 226 if !validSrc { 227 invalidKey = true 228 return 229 } 230 source = netalloc.IPAddressSource(srcInt) 231 232 // return address as is (not parsed - this is done by the netalloc plugin) 233 if addrIdx == len(parts)-1 { 234 invalidKey = true 235 return 236 } 237 address = strings.Join(parts[addrIdx+2:], "/") 238 if address == "" { 239 invalidKey = true 240 } 241 return 242 } 243 244 // InterfaceVrfKey returns key representing assignment of a Linux interface into a VRF. 245 func InterfaceVrfKey(iface string, vrf string) string { 246 if iface == "" { 247 iface = InvalidKeyPart 248 } 249 if vrf == "" { 250 vrf = InvalidKeyPart 251 } 252 253 tmpl := interfaceVrfKeyTmpl 254 key := strings.Replace(tmpl, "{iface}", iface, 1) 255 key = strings.Replace(key, "{vrf}", vrf, 1) 256 return key 257 } 258 259 // ParseInterfaceVrfKey parses interface VRF from key derived 260 // from interface by InterfaceVrfKey(). 261 func ParseInterfaceVrfKey(key string) (iface string, vrf string, invalidKey, isVrfKey bool) { 262 parts := strings.Split(key, "/") 263 if len(parts) < 4 || parts[0] != "linux" || parts[1] != "interface" { 264 return 265 } 266 if parts[2] == "state" || parts[2] == "host-name" { 267 return 268 } 269 270 vrfIdx := -1 271 for idx, part := range parts { 272 switch part { 273 case "address": 274 // avoid collision with InterfaceAddressKey 275 return 276 case "vrf": 277 vrfIdx = idx 278 } 279 } 280 if vrfIdx == -1 { 281 return 282 } 283 isVrfKey = true 284 285 // parse interface name 286 iface = strings.Join(parts[2:vrfIdx], "/") 287 if iface == "" { 288 iface = InvalidKeyPart 289 invalidKey = true 290 } 291 292 // parse VRF 293 if vrfIdx == len(parts)-1 { 294 invalidKey = true 295 vrf = InvalidKeyPart 296 return 297 } 298 vrf = parts[vrfIdx+1] 299 return 300 }