go.ligato.io/vpp-agent/v3@v3.5.0/proto/ligato/vpp/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 vpp_interfaces 16 17 import ( 18 "strconv" 19 "strings" 20 21 "go.ligato.io/vpp-agent/v3/pkg/models" 22 "go.ligato.io/vpp-agent/v3/proto/ligato/netalloc" 23 ) 24 25 // ModuleName is the module name used for models. 26 const ModuleName = "vpp" 27 28 var ( 29 ModelInterface = models.Register(&Interface{}, models.Spec{ 30 Module: ModuleName, 31 Version: "v2", 32 Type: "interfaces", 33 }) 34 35 ModelSpan = models.Register(&Span{}, models.Spec{ 36 Module: ModuleName, 37 Version: "v2", 38 Type: "span", 39 }, models.WithNameTemplate("{{.InterfaceFrom}}/to/{{.InterfaceTo}}")) 40 ) 41 42 // InterfaceKey returns the key used in NB DB to store the configuration of the 43 // given vpp interface. 44 func InterfaceKey(name string) string { 45 return models.Key(&Interface{ 46 Name: name, 47 }) 48 } 49 50 // SpanKey returns the key used in NB DB to store the configuration of the 51 // given vpp span. 52 func SpanKey(ifaceFrom, ifaceTo string) string { 53 return models.Key(&Span{ 54 InterfaceFrom: ifaceFrom, 55 InterfaceTo: ifaceTo, 56 }) 57 } 58 59 /* Interface State */ 60 const ( 61 // StatePrefix is a key prefix used in NB DB to store interface states. 62 StatePrefix = "vpp/status/v2/interface/" 63 ) 64 65 /* Interface Error */ 66 const ( 67 // ErrorPrefix is a key prefix used in NB DB to store interface errors. 68 ErrorPrefix = "vpp/status/v2/interface/error/" 69 ) 70 71 /* Interface Address (derived) */ 72 const ( 73 addressKeyPrefix = "vpp/interface/{iface}/address/" 74 75 // addressKeyTemplate is a template for (derived) key representing assigned 76 // IP addresses to an interface. 77 addressKeyTemplate = addressKeyPrefix + "{address-source}/{address}" 78 ) 79 80 /* Interface VRF (derived) */ 81 const ( 82 // vrfTKeyTemplatePrefix is a prefix of the template used to construct 83 // key representing assignment of an interface into a VRF table. 84 // The prefix includes the source interface name, but not details about the 85 // target VRF. 86 vrfTKeyTemplatePrefix = "vpp/interface/{iface}/vrf/" 87 88 // vrfKeyTemplate is a template for (derived) key representing assignment 89 // of a VPP interface into a VRF table. 90 vrfKeyTemplate = vrfTKeyTemplatePrefix + "{vrf}/ip-version/{ip-version}" 91 92 // inheritedVrfKeyTemplate is a template for (derived) key representing 93 // assignment of an (unnumbered) VPP interface into a VRF table, ID of which 94 // is given by the configuration of a referenced (numbered) interface. 95 inheritedVrfKeyTemplate = vrfTKeyTemplatePrefix + "from-interface/{from-iface}" 96 97 vrfIPv4 = "v4" 98 vrfIPv6 = "v6" 99 vrfBoth = "both" 100 ) 101 102 /* Unnumbered interface (derived) */ 103 const ( 104 // UnnumberedKeyPrefix is used as a common prefix for keys derived from 105 // interfaces to represent unnumbered interfaces. 106 UnnumberedKeyPrefix = "vpp/interface/unnumbered/" 107 ) 108 109 /* Bond interface enslavement (derived) */ 110 const ( 111 // BondedInterfacePrefix is used as a common prefix for keys derived from 112 // interfaces to represent interface slaves for bond interface. 113 BondedInterfacePrefix = "vpp/bond/{bond}/interface/{iface}/" 114 ) 115 116 /* DHCP (client - derived, lease - notification) */ 117 const ( 118 // IP6NDKeyPrefix is used as a common prefix for keys derived from 119 // interfaces to represent enabled IP6 ND. 120 IP6NDKeyPrefix = "vpp/interface/ip6nd/" 121 ) 122 123 /* DHCP (client - derived, lease - notification) */ 124 const ( 125 // DHCPClientKeyPrefix is used as a common prefix for keys derived from 126 // interfaces to represent enabled DHCP clients. 127 DHCPClientKeyPrefix = "vpp/interface/dhcp-client/" 128 129 // DHCPLeaseKeyPrefix is used as a common prefix for keys representing 130 // notifications with DHCP leases. 131 DHCPLeaseKeyPrefix = "vpp/interface/dhcp-lease/" 132 ) 133 134 /* Interface Link State */ 135 136 const ( 137 // interface link states as described in the keys 138 linkUpState = "UP" 139 linkDownState = "DOWN" 140 141 // linkStateKeyTemplate is a template for keys representing 142 // the link state of VPP interfaces (up/down). 143 linkStateKeyTemplate = "vpp/interface/{ifName}/link-state/{linkState}" 144 ) 145 146 /* Interface Rx-placement (derived) */ 147 const ( 148 // rxPlacementKeyTemplate is a template for (derived) key representing 149 // rx-placement configured for a given interface queue. 150 rxPlacementKeyTemplate = "vpp/interface/{iface}/rx-placement/queue/{queue}" 151 ) 152 153 /* Interface Rx-modes (derived) */ 154 const ( 155 // rxModeKeyTemplate is a template for (derived) key representing 156 // rx-mode configuration for all queues of a given interface. 157 rxModesKeyTemplate = "vpp/interface/{iface}/rx-modes" 158 ) 159 160 /* Interface with IP address (derived, property) */ 161 const ( 162 // interfaceWithIPKeyTemplate is a template for keys derived from all interfaces 163 // but created only after at least one IP address is assigned. 164 interfaceWithIPKeyTemplate = "vpp/interface/{iface}/has-IP-address" 165 ) 166 167 const ( 168 // InvalidKeyPart is used in key for parts which are invalid 169 InvalidKeyPart = "<invalid>" 170 ) 171 172 /* Interface Error */ 173 174 // InterfaceErrorKey returns the key used in NB DB to store the interface errors. 175 func InterfaceErrorKey(iface string) string { 176 if iface == "" { 177 iface = InvalidKeyPart 178 } 179 return ErrorPrefix + iface 180 } 181 182 /* Interface State */ 183 184 // InterfaceStateKey returns the key used in NB DB to store the state data of the 185 // given vpp interface. 186 func InterfaceStateKey(iface string) string { 187 if iface == "" { 188 iface = InvalidKeyPart 189 } 190 return StatePrefix + iface 191 } 192 193 /* Interface Address (derived) */ 194 195 // InterfaceAddressPrefix returns longest-common prefix of keys representing 196 // assigned IP addresses to a specific VPP interface. 197 func InterfaceAddressPrefix(iface string) string { 198 if iface == "" { 199 iface = InvalidKeyPart 200 } 201 return strings.Replace(addressKeyPrefix, "{iface}", iface, 1) 202 } 203 204 // InterfaceAddressKey returns key representing IP address assigned to VPP interface. 205 func InterfaceAddressKey(iface string, address string, source netalloc.IPAddressSource) string { 206 if iface == "" { 207 iface = InvalidKeyPart 208 } 209 210 src := source.String() 211 if src == "" { 212 src = InvalidKeyPart 213 } 214 if strings.HasPrefix(address, netalloc.AllocRefPrefix) { 215 src = netalloc.IPAddressSource_ALLOC_REF.String() 216 } 217 src = strings.ToLower(src) 218 219 // construct key without validating the IP address 220 key := strings.Replace(addressKeyTemplate, "{iface}", iface, 1) 221 key = strings.Replace(key, "{address-source}", src, 1) 222 key = strings.Replace(key, "{address}", address, 1) 223 return key 224 } 225 226 // ParseInterfaceAddressKey parses interface address from key derived 227 // from interface by InterfaceAddressKey(). 228 func ParseInterfaceAddressKey(key string) (iface, address string, source netalloc.IPAddressSource, invalidKey, isAddrKey bool) { 229 parts := strings.Split(key, "/") 230 if len(parts) < 4 || parts[0] != "vpp" || parts[1] != "interface" { 231 return 232 } 233 234 addrIdx := -1 235 for idx, part := range parts { 236 if part == "address" { 237 addrIdx = idx 238 break 239 } 240 } 241 if addrIdx == -1 { 242 return 243 } 244 isAddrKey = true 245 246 // parse interface name 247 iface = strings.Join(parts[2:addrIdx], "/") 248 if iface == "" { 249 iface = InvalidKeyPart 250 invalidKey = true 251 } 252 253 // parse address type 254 if addrIdx == len(parts)-1 { 255 invalidKey = true 256 return 257 } 258 259 // parse address source 260 src := strings.ToUpper(parts[addrIdx+1]) 261 srcInt, validSrc := netalloc.IPAddressSource_value[src] 262 if !validSrc { 263 invalidKey = true 264 return 265 } 266 source = netalloc.IPAddressSource(srcInt) 267 268 // return address as is (not parsed - this is done by the netalloc plugin) 269 address = strings.Join(parts[addrIdx+2:], "/") 270 if address == "" { 271 invalidKey = true 272 } 273 return 274 } 275 276 /* Interface VRF (derived) */ 277 278 // InterfaceVrfKeyPrefix returns prefix of the key representing assignment 279 // of the given interface into unspecified VRF table. 280 func InterfaceVrfKeyPrefix(iface string) string { 281 return strings.Replace(vrfTKeyTemplatePrefix, "{iface}", iface, 1) 282 } 283 284 // InterfaceVrfKey returns key representing assignment of the given interface 285 // into the given VRF. 286 func InterfaceVrfKey(iface string, vrf int, ipv4, ipv6 bool) string { 287 if iface == "" { 288 iface = InvalidKeyPart 289 } 290 ipVer := InvalidKeyPart 291 if ipv4 && ipv6 { 292 ipVer = vrfBoth 293 } else if ipv4 { 294 ipVer = vrfIPv4 295 } else if ipv6 { 296 ipVer = vrfIPv6 297 } 298 299 vrfTableID := InvalidKeyPart 300 if vrf >= 0 { 301 vrfTableID = strconv.Itoa(vrf) 302 } 303 304 key := strings.Replace(vrfKeyTemplate, "{iface}", iface, 1) 305 key = strings.Replace(key, "{vrf}", vrfTableID, 1) 306 key = strings.Replace(key, "{ip-version}", ipVer, 1) 307 return key 308 } 309 310 // ParseInterfaceVrfKey parses details from key derived from interface by 311 // InterfaceVrfKey(). 312 func ParseInterfaceVrfKey(key string) (iface string, vrf int, ipv4, ipv6, isIfaceVrfKey bool) { 313 parts := strings.Split(key, "/") 314 if len(parts) < 7 || parts[0] != "vpp" || parts[1] != "interface" { 315 return 316 } 317 318 vrfIdx := -1 319 ipVerIdx := -1 320 for idx, part := range parts { 321 if part == "vrf" { 322 vrfIdx = idx 323 } 324 if part == "ip-version" { 325 ipVerIdx = idx 326 } 327 } 328 if vrfIdx == -1 || ipVerIdx != len(parts)-2 { 329 return 330 } 331 isIfaceVrfKey = true 332 333 // parse interface name 334 iface = strings.Join(parts[2:vrfIdx], "/") 335 if iface == "" { 336 iface = InvalidKeyPart 337 } 338 339 // parse VRF table ID 340 var err error 341 vrf, err = strconv.Atoi(parts[vrfIdx+1]) 342 if err != nil { 343 vrf = -1 344 } 345 346 // parse IP version 347 switch parts[ipVerIdx+1] { 348 case vrfBoth: 349 ipv4 = true 350 ipv6 = true 351 case vrfIPv4: 352 ipv4 = true 353 case vrfIPv6: 354 ipv6 = true 355 } 356 return 357 } 358 359 // InterfaceInheritedVrfKey returns key representing assignment of the given 360 // interface into a VRF inherited from another interface. 361 // Used by unnumbered interfaces. 362 func InterfaceInheritedVrfKey(iface string, fromIface string) string { 363 if iface == "" { 364 iface = InvalidKeyPart 365 } 366 if fromIface == "" { 367 fromIface = InvalidKeyPart 368 } 369 key := strings.Replace(inheritedVrfKeyTemplate, "{iface}", iface, 1) 370 key = strings.Replace(key, "{from-iface}", fromIface, 1) 371 return key 372 } 373 374 // ParseInterfaceInheritedVrfKey parses details from key derived from interface by 375 // InterfaceInheritedVrfKey(). 376 func ParseInterfaceInheritedVrfKey(key string) (iface, fromIface string, isIfaceInherVrfKey bool) { 377 parts := strings.Split(key, "/") 378 if len(parts) < 6 || parts[0] != "vpp" || parts[1] != "interface" { 379 return 380 } 381 382 vrfIdx := -1 383 for idx, part := range parts { 384 if part == "vrf" { 385 vrfIdx = idx 386 break 387 } 388 } 389 if vrfIdx == -1 || vrfIdx+2 >= len(parts) || parts[vrfIdx+1] != "from-interface" { 390 return 391 } 392 isIfaceInherVrfKey = true 393 394 // parse interface name 395 iface = strings.Join(parts[2:vrfIdx], "/") 396 if iface == "" { 397 iface = InvalidKeyPart 398 } 399 400 // parse from-interface name 401 fromIface = strings.Join(parts[vrfIdx+2:], "/") 402 if fromIface == "" { 403 fromIface = InvalidKeyPart 404 } 405 return 406 } 407 408 /* Unnumbered interface (derived) */ 409 410 // UnnumberedKey returns key representing unnumbered interface. 411 func UnnumberedKey(iface string) string { 412 if iface == "" { 413 iface = InvalidKeyPart 414 } 415 return UnnumberedKeyPrefix + iface 416 } 417 418 // ParseNameFromUnnumberedKey returns suffix of the key. 419 func ParseNameFromUnnumberedKey(key string) (iface string, isUnnumberedKey bool) { 420 suffix := strings.TrimPrefix(key, UnnumberedKeyPrefix) 421 if suffix != key && suffix != "" { 422 return suffix, true 423 } 424 return 425 } 426 427 /* Bond slave interface (derived) */ 428 429 // BondedInterfaceKey returns a key with bond and slave interface set 430 func BondedInterfaceKey(bondIf, slaveIf string) string { 431 if bondIf == "" { 432 bondIf = InvalidKeyPart 433 } 434 if slaveIf == "" { 435 slaveIf = InvalidKeyPart 436 } 437 key := strings.Replace(BondedInterfacePrefix, "{bond}", bondIf, 1) 438 key = strings.Replace(key, "{iface}", slaveIf, 1) 439 return key 440 } 441 442 // ParseBondedInterfaceKey returns names of interfaces of the key. 443 func ParseBondedInterfaceKey(key string) (bondIf, slaveIf string, isBondSlaveInterfaceKey bool) { 444 keyComps := strings.Split(key, "/") 445 if len(keyComps) >= 5 && keyComps[0] == "vpp" && keyComps[1] == "bond" && keyComps[3] == "interface" { 446 slaveIf = strings.Join(keyComps[4:], "/") 447 return keyComps[2], slaveIf, true 448 } 449 return "", "", false 450 } 451 452 // IP6NDKey returns a (derived) key used to represent enabled IP6 ND. 453 func IP6NDKey(iface string) string { 454 if iface == "" { 455 iface = InvalidKeyPart 456 } 457 return IP6NDKeyPrefix + iface 458 } 459 460 // ParseNameFromIP6NDKey returns suffix of the key. 461 func ParseNameFromIP6NDKey(key string) (iface string, isIP6NDKey bool) { 462 if suffix := strings.TrimPrefix(key, IP6NDKeyPrefix); suffix != key && suffix != "" { 463 return suffix, true 464 } 465 return 466 } 467 468 /* DHCP (client - derived, lease - notification) */ 469 470 // DHCPClientKey returns a (derived) key used to represent enabled DHCP lease. 471 func DHCPClientKey(iface string) string { 472 if iface == "" { 473 iface = InvalidKeyPart 474 } 475 return DHCPClientKeyPrefix + iface 476 } 477 478 // ParseNameFromDHCPClientKey returns suffix of the key. 479 func ParseNameFromDHCPClientKey(key string) (iface string, isDHCPClientKey bool) { 480 if suffix := strings.TrimPrefix(key, DHCPClientKeyPrefix); suffix != key && suffix != "" { 481 return suffix, true 482 } 483 return 484 } 485 486 // DHCPLeaseKey returns a key used to represent DHCP lease for the given interface. 487 func DHCPLeaseKey(iface string) string { 488 if iface == "" { 489 iface = InvalidKeyPart 490 } 491 return DHCPLeaseKeyPrefix + iface 492 } 493 494 // ParseNameFromDHCPLeaseKey returns suffix of the key. 495 func ParseNameFromDHCPLeaseKey(key string) (iface string, isDHCPLeaseKey bool) { 496 if suffix := strings.TrimPrefix(key, DHCPLeaseKeyPrefix); suffix != key && suffix != "" { 497 return suffix, true 498 } 499 return 500 } 501 502 /* Link State (notification) */ 503 504 // LinkStateKey returns key representing link state of a VPP interface. 505 func LinkStateKey(ifaceName string, linkIsUp bool) string { 506 if ifaceName == "" { 507 ifaceName = InvalidKeyPart 508 } 509 linkState := linkDownState 510 if linkIsUp { 511 linkState = linkUpState 512 } 513 key := strings.Replace(linkStateKeyTemplate, "{ifName}", ifaceName, 1) 514 key = strings.Replace(key, "{linkState}", linkState, 1) 515 return key 516 } 517 518 // ParseLinkStateKey parses key representing link state of a VPP interface. 519 func ParseLinkStateKey(key string) (ifaceName string, isLinkUp bool, isLinkStateKey bool) { 520 if suffix := strings.TrimPrefix(key, "vpp/interface/"); suffix != key { 521 parts := strings.Split(suffix, "/") 522 linkState := -1 523 for i, part := range parts { 524 if part == "link-state" { 525 linkState = i 526 } 527 } 528 if linkState != len(parts)-2 { 529 return 530 } 531 532 switch parts[len(parts)-1] { 533 case linkDownState: 534 case linkUpState: 535 isLinkUp = true 536 default: 537 return 538 } 539 540 // beware: interface name may contain forward slashes 541 ifaceName = strings.Join(parts[:linkState], "/") 542 if ifaceName == InvalidKeyPart { 543 isLinkUp = false 544 ifaceName = "" 545 return 546 } 547 isLinkStateKey = true 548 } 549 return 550 } 551 552 /* Interface with IP address (derived property) */ 553 554 // InterfaceWithIPKey returns key derived from every VPP interface but created only 555 // after at least one IP address was assigned to it. 556 func InterfaceWithIPKey(ifaceName string) string { 557 if ifaceName == "" { 558 ifaceName = InvalidKeyPart 559 } 560 return strings.Replace(interfaceWithIPKeyTemplate, "{iface}", ifaceName, 1) 561 } 562 563 // ParseInterfaceWithIPKey parses key derived from every VPP interface but created only 564 // after at least one IP address was assigned to it 565 func ParseInterfaceWithIPKey(key string) (ifaceName string, isInterfaceWithIPKey bool) { 566 if suffix := strings.TrimPrefix(key, "vpp/interface/"); suffix != key { 567 if prefix := strings.TrimSuffix(suffix, "/has-IP-address"); prefix != suffix { 568 if prefix != InvalidKeyPart { 569 ifaceName = prefix 570 isInterfaceWithIPKey = true 571 } 572 } 573 } 574 return 575 } 576 577 /* Rx placement (derived) */ 578 579 // RxPlacementKey returns a key representing rx-placement configured for a given 580 // interface queue. 581 func RxPlacementKey(ifaceName string, queue uint32) string { 582 if ifaceName == "" { 583 ifaceName = InvalidKeyPart 584 } 585 key := strings.Replace(rxPlacementKeyTemplate, "{iface}", ifaceName, 1) 586 key = strings.Replace(key, "{queue}", strconv.Itoa(int(queue)), 1) 587 return key 588 } 589 590 // ParseRxPlacementKey parses key representing rx-placement configured for a given 591 // interface queue. 592 func ParseRxPlacementKey(key string) (ifaceName string, queue uint32, isRxPlacementKey bool) { 593 if suffix := strings.TrimPrefix(key, "vpp/interface/"); suffix != key { 594 parts := strings.Split(suffix, "/") 595 rxPlacement := -1 596 for i, part := range parts { 597 if part == "rx-placement" { 598 rxPlacement = i 599 } 600 } 601 if rxPlacement != len(parts)-3 { 602 return 603 } 604 605 if parts[len(parts)-2] != "queue" { 606 return 607 } 608 609 queueID, err := strconv.Atoi(parts[len(parts)-1]) 610 if err != nil || queueID < 0 { 611 return 612 } 613 614 // beware: interface name may contain forward slashes 615 ifaceName = strings.Join(parts[:rxPlacement], "/") 616 if ifaceName == InvalidKeyPart { 617 ifaceName = "" 618 return 619 } 620 621 queue = uint32(queueID) 622 isRxPlacementKey = true 623 } 624 return 625 } 626 627 /* Rx modes (derived) */ 628 629 // RxModesKey returns a key representing rx-mode configuration for all queues 630 // of a given interface. 631 func RxModesKey(ifaceName string) string { 632 if ifaceName == "" { 633 ifaceName = InvalidKeyPart 634 } 635 return strings.Replace(rxModesKeyTemplate, "{iface}", ifaceName, 1) 636 } 637 638 // ParseRxModesKey parses key representing rx-mode configuration for all queues 639 // of a given interface. 640 func ParseRxModesKey(key string) (ifaceName string, isRxModesKey bool) { 641 if suffix := strings.TrimPrefix(key, "vpp/interface/"); suffix != key { 642 parts := strings.Split(suffix, "/") 643 if len(parts) == 0 || parts[len(parts)-1] != "rx-modes" { 644 return 645 } 646 647 // beware: interface name may contain forward slashes 648 ifaceName = strings.Join(parts[:len(parts)-1], "/") 649 if ifaceName == InvalidKeyPart { 650 ifaceName = "" 651 return 652 } 653 654 isRxModesKey = true 655 } 656 return 657 }