github.com/osrg/gobgp/v3@v3.30.0/internal/pkg/table/policy.go (about) 1 // Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation. 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 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package table 17 18 import ( 19 "encoding/json" 20 "fmt" 21 "net" 22 "reflect" 23 "regexp" 24 "sort" 25 "strconv" 26 "strings" 27 "sync" 28 29 "github.com/k-sone/critbitgo" 30 api "github.com/osrg/gobgp/v3/api" 31 "github.com/osrg/gobgp/v3/pkg/config/oc" 32 "github.com/osrg/gobgp/v3/pkg/log" 33 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 34 ) 35 36 type PolicyOptions struct { 37 Info *PeerInfo 38 OldNextHop net.IP 39 Validate func(*Path) *Validation 40 } 41 42 type DefinedType int 43 44 const ( 45 DEFINED_TYPE_PREFIX DefinedType = iota 46 DEFINED_TYPE_NEIGHBOR 47 DEFINED_TYPE_TAG 48 DEFINED_TYPE_AS_PATH 49 DEFINED_TYPE_COMMUNITY 50 DEFINED_TYPE_EXT_COMMUNITY 51 DEFINED_TYPE_LARGE_COMMUNITY 52 DEFINED_TYPE_NEXT_HOP 53 ) 54 55 type RouteType int 56 57 const ( 58 ROUTE_TYPE_NONE RouteType = iota 59 ROUTE_TYPE_ACCEPT 60 ROUTE_TYPE_REJECT 61 ) 62 63 func (t RouteType) String() string { 64 switch t { 65 case ROUTE_TYPE_NONE: 66 return "continue" 67 case ROUTE_TYPE_ACCEPT: 68 return "accept" 69 case ROUTE_TYPE_REJECT: 70 return "reject" 71 } 72 return fmt.Sprintf("unknown(%d)", t) 73 } 74 75 type PolicyDirection int 76 77 const ( 78 POLICY_DIRECTION_NONE PolicyDirection = iota 79 POLICY_DIRECTION_IMPORT 80 POLICY_DIRECTION_EXPORT 81 ) 82 83 func (d PolicyDirection) String() string { 84 switch d { 85 case POLICY_DIRECTION_IMPORT: 86 return "import" 87 case POLICY_DIRECTION_EXPORT: 88 return "export" 89 } 90 return fmt.Sprintf("unknown(%d)", d) 91 } 92 93 type MatchOption int 94 95 const ( 96 MATCH_OPTION_ANY MatchOption = iota 97 MATCH_OPTION_ALL 98 MATCH_OPTION_INVERT 99 ) 100 101 func (o MatchOption) String() string { 102 switch o { 103 case MATCH_OPTION_ANY: 104 return "any" 105 case MATCH_OPTION_ALL: 106 return "all" 107 case MATCH_OPTION_INVERT: 108 return "invert" 109 default: 110 return fmt.Sprintf("MatchOption(%d)", o) 111 } 112 } 113 114 func (o MatchOption) ConvertToMatchSetOptionsRestrictedType() oc.MatchSetOptionsRestrictedType { 115 switch o { 116 case MATCH_OPTION_ANY: 117 return oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY 118 case MATCH_OPTION_INVERT: 119 return oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT 120 } 121 return "unknown" 122 } 123 124 type MedActionType int 125 126 const ( 127 MED_ACTION_MOD MedActionType = iota 128 MED_ACTION_REPLACE 129 ) 130 131 var CommunityOptionNameMap = map[oc.BgpSetCommunityOptionType]string{ 132 oc.BGP_SET_COMMUNITY_OPTION_TYPE_ADD: "add", 133 oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE: "remove", 134 oc.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE: "replace", 135 } 136 137 var CommunityOptionValueMap = map[string]oc.BgpSetCommunityOptionType{ 138 CommunityOptionNameMap[oc.BGP_SET_COMMUNITY_OPTION_TYPE_ADD]: oc.BGP_SET_COMMUNITY_OPTION_TYPE_ADD, 139 CommunityOptionNameMap[oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE]: oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE, 140 CommunityOptionNameMap[oc.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE]: oc.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE, 141 } 142 143 type ConditionType int 144 145 const ( 146 CONDITION_PREFIX ConditionType = iota 147 CONDITION_NEIGHBOR 148 CONDITION_AS_PATH 149 CONDITION_COMMUNITY 150 CONDITION_EXT_COMMUNITY 151 CONDITION_AS_PATH_LENGTH 152 CONDITION_RPKI 153 CONDITION_ROUTE_TYPE 154 CONDITION_LARGE_COMMUNITY 155 CONDITION_NEXT_HOP 156 CONDITION_AFI_SAFI_IN 157 CONDITION_COMMUNITY_COUNT 158 CONDITION_ORIGIN 159 ) 160 161 type ActionType int 162 163 const ( 164 ACTION_ROUTING ActionType = iota 165 ACTION_COMMUNITY 166 ACTION_EXT_COMMUNITY 167 ACTION_MED 168 ACTION_AS_PATH_PREPEND 169 ACTION_NEXTHOP 170 ACTION_LOCAL_PREF 171 ACTION_LARGE_COMMUNITY 172 ACTION_ORIGIN 173 ) 174 175 func NewMatchOption(c interface{}) (MatchOption, error) { 176 switch t := c.(type) { 177 case oc.MatchSetOptionsType: 178 t = t.DefaultAsNeeded() 179 switch t { 180 case oc.MATCH_SET_OPTIONS_TYPE_ANY: 181 return MATCH_OPTION_ANY, nil 182 case oc.MATCH_SET_OPTIONS_TYPE_ALL: 183 return MATCH_OPTION_ALL, nil 184 case oc.MATCH_SET_OPTIONS_TYPE_INVERT: 185 return MATCH_OPTION_INVERT, nil 186 } 187 case oc.MatchSetOptionsRestrictedType: 188 t = t.DefaultAsNeeded() 189 switch t { 190 case oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_ANY: 191 return MATCH_OPTION_ANY, nil 192 case oc.MATCH_SET_OPTIONS_RESTRICTED_TYPE_INVERT: 193 return MATCH_OPTION_INVERT, nil 194 } 195 } 196 return MATCH_OPTION_ANY, fmt.Errorf("invalid argument to create match option: %v", c) 197 } 198 199 type AttributeComparison int 200 201 const ( 202 // "== comparison" 203 ATTRIBUTE_EQ AttributeComparison = iota 204 // ">= comparison" 205 ATTRIBUTE_GE 206 // "<= comparison" 207 ATTRIBUTE_LE 208 ) 209 210 func (c AttributeComparison) String() string { 211 switch c { 212 case ATTRIBUTE_EQ: 213 return "=" 214 case ATTRIBUTE_GE: 215 return ">=" 216 case ATTRIBUTE_LE: 217 return "<=" 218 } 219 return "?" 220 } 221 222 const ( 223 ASPATH_REGEXP_MAGIC = "(^|[,{}() ]|$)" 224 ) 225 226 type DefinedSet interface { 227 Type() DefinedType 228 Name() string 229 Append(DefinedSet) error 230 Remove(DefinedSet) error 231 Replace(DefinedSet) error 232 String() string 233 List() []string 234 } 235 236 type DefinedSetMap map[DefinedType]map[string]DefinedSet 237 238 type DefinedSetList []DefinedSet 239 240 func (l DefinedSetList) Len() int { 241 return len(l) 242 } 243 244 func (l DefinedSetList) Swap(i, j int) { 245 l[i], l[j] = l[j], l[i] 246 } 247 248 func (l DefinedSetList) Less(i, j int) bool { 249 if l[i].Type() != l[j].Type() { 250 return l[i].Type() < l[j].Type() 251 } 252 return l[i].Name() < l[j].Name() 253 } 254 255 type Prefix struct { 256 Prefix *net.IPNet 257 AddressFamily bgp.RouteFamily 258 MasklengthRangeMax uint8 259 MasklengthRangeMin uint8 260 } 261 262 func (p *Prefix) Match(path *Path) bool { 263 rf := path.GetRouteFamily() 264 if rf != p.AddressFamily { 265 return false 266 } 267 268 var pAddr net.IP 269 var pMasklen uint8 270 switch rf { 271 case bgp.RF_IPv4_UC: 272 pAddr = path.GetNlri().(*bgp.IPAddrPrefix).Prefix 273 pMasklen = path.GetNlri().(*bgp.IPAddrPrefix).Length 274 case bgp.RF_IPv6_UC: 275 pAddr = path.GetNlri().(*bgp.IPv6AddrPrefix).Prefix 276 pMasklen = path.GetNlri().(*bgp.IPv6AddrPrefix).Length 277 default: 278 return false 279 } 280 281 return (p.MasklengthRangeMin <= pMasklen && pMasklen <= p.MasklengthRangeMax) && p.Prefix.Contains(pAddr) 282 } 283 284 func (lhs *Prefix) Equal(rhs *Prefix) bool { 285 if lhs == rhs { 286 return true 287 } 288 if rhs == nil { 289 return false 290 } 291 return lhs.Prefix.String() == rhs.Prefix.String() && lhs.MasklengthRangeMin == rhs.MasklengthRangeMin && lhs.MasklengthRangeMax == rhs.MasklengthRangeMax 292 } 293 294 func (p *Prefix) PrefixString() string { 295 isZeros := func(p net.IP) bool { 296 for i := 0; i < len(p); i++ { 297 if p[i] != 0 { 298 return false 299 } 300 } 301 return true 302 } 303 304 ip := p.Prefix.IP 305 if p.AddressFamily == bgp.RF_IPv6_UC && isZeros(ip[0:10]) && ip[10] == 0xff && ip[11] == 0xff { 306 m, _ := p.Prefix.Mask.Size() 307 return fmt.Sprintf("::FFFF:%s/%d", ip.To16(), m) 308 } 309 return p.Prefix.String() 310 } 311 312 var _regexpPrefixRange = regexp.MustCompile(`(\d+)\.\.(\d+)`) 313 314 func NewPrefix(c oc.Prefix) (*Prefix, error) { 315 _, prefix, err := net.ParseCIDR(c.IpPrefix) 316 if err != nil { 317 return nil, err 318 } 319 320 rf := bgp.RF_IPv4_UC 321 if strings.Contains(c.IpPrefix, ":") { 322 rf = bgp.RF_IPv6_UC 323 } 324 p := &Prefix{ 325 Prefix: prefix, 326 AddressFamily: rf, 327 } 328 maskRange := c.MasklengthRange 329 330 if maskRange == "" { 331 l, _ := prefix.Mask.Size() 332 maskLength := uint8(l) 333 p.MasklengthRangeMax = maskLength 334 p.MasklengthRangeMin = maskLength 335 return p, nil 336 } 337 338 elems := _regexpPrefixRange.FindStringSubmatch(maskRange) 339 if len(elems) != 3 { 340 return nil, fmt.Errorf("mask length range format is invalid") 341 } 342 343 // we've already checked the range is sane by regexp 344 min, _ := strconv.ParseUint(elems[1], 10, 8) 345 max, _ := strconv.ParseUint(elems[2], 10, 8) 346 p.MasklengthRangeMin = uint8(min) 347 p.MasklengthRangeMax = uint8(max) 348 return p, nil 349 } 350 351 type PrefixSet struct { 352 name string 353 tree *critbitgo.Net 354 family bgp.RouteFamily 355 } 356 357 func (s *PrefixSet) Name() string { 358 return s.name 359 } 360 361 func (s *PrefixSet) Type() DefinedType { 362 return DEFINED_TYPE_PREFIX 363 } 364 365 func (lhs *PrefixSet) Append(arg DefinedSet) error { 366 rhs, ok := arg.(*PrefixSet) 367 if !ok { 368 return fmt.Errorf("type cast failed") 369 } 370 371 if rhs.tree.Size() == 0 { 372 // if try to append an empty set, then return directly 373 return nil 374 } else if lhs.tree.Size() != 0 && rhs.family != lhs.family { 375 return fmt.Errorf("can't append different family") 376 } 377 rhs.tree.Walk(nil, func(r *net.IPNet, v interface{}) bool { 378 w, ok, _ := lhs.tree.Get(r) 379 if ok { 380 rp := v.([]*Prefix) 381 lp := w.([]*Prefix) 382 lhs.tree.Add(r, append(lp, rp...)) 383 } else { 384 lhs.tree.Add(r, v) 385 } 386 return true 387 }) 388 lhs.family = rhs.family 389 return nil 390 } 391 392 func (lhs *PrefixSet) Remove(arg DefinedSet) error { 393 rhs, ok := arg.(*PrefixSet) 394 if !ok { 395 return fmt.Errorf("type cast failed") 396 } 397 rhs.tree.Walk(nil, func(r *net.IPNet, v interface{}) bool { 398 w, ok, _ := lhs.tree.Get(r) 399 if !ok { 400 return true 401 } 402 rp := v.([]*Prefix) 403 lp := w.([]*Prefix) 404 new := make([]*Prefix, 0, len(lp)) 405 for _, lp := range lp { 406 delete := false 407 for _, rp := range rp { 408 if lp.Equal(rp) { 409 delete = true 410 break 411 } 412 } 413 if !delete { 414 new = append(new, lp) 415 } 416 } 417 if len(new) == 0 { 418 lhs.tree.Delete(r) 419 } else { 420 lhs.tree.Add(r, new) 421 } 422 return true 423 }) 424 return nil 425 } 426 427 func (lhs *PrefixSet) Replace(arg DefinedSet) error { 428 rhs, ok := arg.(*PrefixSet) 429 if !ok { 430 return fmt.Errorf("type cast failed") 431 } 432 lhs.tree = rhs.tree 433 lhs.family = rhs.family 434 return nil 435 } 436 437 func (s *PrefixSet) List() []string { 438 var list []string 439 s.tree.Walk(nil, func(_ *net.IPNet, v interface{}) bool { 440 ps := v.([]*Prefix) 441 for _, p := range ps { 442 list = append(list, fmt.Sprintf("%s %d..%d", p.PrefixString(), p.MasklengthRangeMin, p.MasklengthRangeMax)) 443 } 444 return true 445 }) 446 return list 447 } 448 449 func (s *PrefixSet) ToConfig() *oc.PrefixSet { 450 list := make([]oc.Prefix, 0, s.tree.Size()) 451 s.tree.Walk(nil, func(_ *net.IPNet, v interface{}) bool { 452 ps := v.([]*Prefix) 453 for _, p := range ps { 454 list = append(list, oc.Prefix{IpPrefix: p.PrefixString(), MasklengthRange: fmt.Sprintf("%d..%d", p.MasklengthRangeMin, p.MasklengthRangeMax)}) 455 } 456 return true 457 }) 458 return &oc.PrefixSet{ 459 PrefixSetName: s.name, 460 PrefixList: list, 461 } 462 } 463 464 func (s *PrefixSet) String() string { 465 return strings.Join(s.List(), "\n") 466 } 467 468 func (s *PrefixSet) MarshalJSON() ([]byte, error) { 469 return json.Marshal(s.ToConfig()) 470 } 471 472 func NewPrefixSetFromApiStruct(name string, prefixes []*Prefix) (*PrefixSet, error) { 473 if name == "" { 474 return nil, fmt.Errorf("empty prefix set name") 475 } 476 tree := critbitgo.NewNet() 477 var family bgp.RouteFamily 478 for i, x := range prefixes { 479 if i == 0 { 480 family = x.AddressFamily 481 } else if family != x.AddressFamily { 482 return nil, fmt.Errorf("multiple families") 483 } 484 d, ok, _ := tree.Get(x.Prefix) 485 if ok { 486 ps := d.([]*Prefix) 487 tree.Add(x.Prefix, append(ps, x)) 488 } else { 489 tree.Add(x.Prefix, []*Prefix{x}) 490 } 491 } 492 return &PrefixSet{ 493 name: name, 494 tree: tree, 495 family: family, 496 }, nil 497 } 498 499 func NewPrefixSet(c oc.PrefixSet) (*PrefixSet, error) { 500 name := c.PrefixSetName 501 if name == "" { 502 if len(c.PrefixList) == 0 { 503 return nil, nil 504 } 505 return nil, fmt.Errorf("empty prefix set name") 506 } 507 tree := critbitgo.NewNet() 508 var family bgp.RouteFamily 509 for i, x := range c.PrefixList { 510 y, err := NewPrefix(x) 511 if err != nil { 512 return nil, err 513 } 514 if i == 0 { 515 family = y.AddressFamily 516 } else if family != y.AddressFamily { 517 return nil, fmt.Errorf("multiple families") 518 } 519 d, ok, _ := tree.Get(y.Prefix) 520 if ok { 521 ps := d.([]*Prefix) 522 tree.Add(y.Prefix, append(ps, y)) 523 } else { 524 tree.Add(y.Prefix, []*Prefix{y}) 525 } 526 } 527 return &PrefixSet{ 528 name: name, 529 tree: tree, 530 family: family, 531 }, nil 532 } 533 534 type NextHopSet struct { 535 list []net.IPNet 536 } 537 538 func (s *NextHopSet) Name() string { 539 return "NextHopSet: NO NAME" 540 } 541 542 func (s *NextHopSet) Type() DefinedType { 543 return DEFINED_TYPE_NEXT_HOP 544 } 545 546 func (lhs *NextHopSet) Append(arg DefinedSet) error { 547 rhs, ok := arg.(*NextHopSet) 548 if !ok { 549 return fmt.Errorf("type cast failed") 550 } 551 lhs.list = append(lhs.list, rhs.list...) 552 return nil 553 } 554 555 func (lhs *NextHopSet) Remove(arg DefinedSet) error { 556 rhs, ok := arg.(*NextHopSet) 557 if !ok { 558 return fmt.Errorf("type cast failed") 559 } 560 ps := make([]net.IPNet, 0, len(lhs.list)) 561 for _, x := range lhs.list { 562 found := false 563 for _, y := range rhs.list { 564 if x.String() == y.String() { 565 found = true 566 break 567 } 568 } 569 if !found { 570 ps = append(ps, x) 571 } 572 } 573 lhs.list = ps 574 return nil 575 } 576 577 func (lhs *NextHopSet) Replace(arg DefinedSet) error { 578 rhs, ok := arg.(*NextHopSet) 579 if !ok { 580 return fmt.Errorf("type cast failed") 581 } 582 lhs.list = rhs.list 583 return nil 584 } 585 586 func (s *NextHopSet) List() []string { 587 list := make([]string, 0, len(s.list)) 588 for _, n := range s.list { 589 list = append(list, n.String()) 590 } 591 return list 592 } 593 594 func (s *NextHopSet) ToConfig() []string { 595 return s.List() 596 } 597 598 func (s *NextHopSet) String() string { 599 return "[ " + strings.Join(s.List(), ", ") + " ]" 600 } 601 602 func (s *NextHopSet) MarshalJSON() ([]byte, error) { 603 return json.Marshal(s.ToConfig()) 604 } 605 606 func NewNextHopSetFromApiStruct(name string, list []net.IPNet) (*NextHopSet, error) { 607 return &NextHopSet{ 608 list: list, 609 }, nil 610 } 611 612 func NewNextHopSet(c []string) (*NextHopSet, error) { 613 list := make([]net.IPNet, 0, len(c)) 614 for _, x := range c { 615 _, cidr, err := net.ParseCIDR(x) 616 if err != nil { 617 addr := net.ParseIP(x) 618 if addr == nil { 619 return nil, fmt.Errorf("invalid address or prefix: %s", x) 620 } 621 mask := net.CIDRMask(32, 32) 622 if addr.To4() == nil { 623 mask = net.CIDRMask(128, 128) 624 } 625 cidr = &net.IPNet{ 626 IP: addr, 627 Mask: mask, 628 } 629 } 630 list = append(list, *cidr) 631 } 632 return &NextHopSet{ 633 list: list, 634 }, nil 635 } 636 637 type NeighborSet struct { 638 name string 639 list []net.IPNet 640 } 641 642 func (s *NeighborSet) Name() string { 643 return s.name 644 } 645 646 func (s *NeighborSet) Type() DefinedType { 647 return DEFINED_TYPE_NEIGHBOR 648 } 649 650 func (lhs *NeighborSet) Append(arg DefinedSet) error { 651 rhs, ok := arg.(*NeighborSet) 652 if !ok { 653 return fmt.Errorf("type cast failed") 654 } 655 lhs.list = append(lhs.list, rhs.list...) 656 return nil 657 } 658 659 func (lhs *NeighborSet) Remove(arg DefinedSet) error { 660 rhs, ok := arg.(*NeighborSet) 661 if !ok { 662 return fmt.Errorf("type cast failed") 663 } 664 ps := make([]net.IPNet, 0, len(lhs.list)) 665 for _, x := range lhs.list { 666 found := false 667 for _, y := range rhs.list { 668 if x.String() == y.String() { 669 found = true 670 break 671 } 672 } 673 if !found { 674 ps = append(ps, x) 675 } 676 } 677 lhs.list = ps 678 return nil 679 } 680 681 func (lhs *NeighborSet) Replace(arg DefinedSet) error { 682 rhs, ok := arg.(*NeighborSet) 683 if !ok { 684 return fmt.Errorf("type cast failed") 685 } 686 lhs.list = rhs.list 687 return nil 688 } 689 690 func (s *NeighborSet) List() []string { 691 list := make([]string, 0, len(s.list)) 692 for _, n := range s.list { 693 list = append(list, n.String()) 694 } 695 return list 696 } 697 698 func (s *NeighborSet) ToConfig() *oc.NeighborSet { 699 return &oc.NeighborSet{ 700 NeighborSetName: s.name, 701 NeighborInfoList: s.List(), 702 } 703 } 704 705 func (s *NeighborSet) String() string { 706 return strings.Join(s.List(), "\n") 707 } 708 709 func (s *NeighborSet) MarshalJSON() ([]byte, error) { 710 return json.Marshal(s.ToConfig()) 711 } 712 713 func NewNeighborSetFromApiStruct(name string, list []net.IPNet) (*NeighborSet, error) { 714 return &NeighborSet{ 715 name: name, 716 list: list, 717 }, nil 718 } 719 720 func NewNeighborSet(c oc.NeighborSet) (*NeighborSet, error) { 721 name := c.NeighborSetName 722 if name == "" { 723 if len(c.NeighborInfoList) == 0 { 724 return nil, nil 725 } 726 return nil, fmt.Errorf("empty neighbor set name") 727 } 728 list := make([]net.IPNet, 0, len(c.NeighborInfoList)) 729 for _, x := range c.NeighborInfoList { 730 _, cidr, err := net.ParseCIDR(x) 731 if err != nil { 732 addr := net.ParseIP(x) 733 if addr == nil { 734 return nil, fmt.Errorf("invalid address or prefix: %s", x) 735 } 736 mask := net.CIDRMask(32, 32) 737 if addr.To4() == nil { 738 mask = net.CIDRMask(128, 128) 739 } 740 cidr = &net.IPNet{ 741 IP: addr, 742 Mask: mask, 743 } 744 } 745 list = append(list, *cidr) 746 } 747 return &NeighborSet{ 748 name: name, 749 list: list, 750 }, nil 751 } 752 753 type singleAsPathMatchMode int 754 755 const ( 756 INCLUDE singleAsPathMatchMode = iota 757 LEFT_MOST 758 ORIGIN 759 ONLY 760 ) 761 762 type singleAsPathMatch struct { 763 asn uint32 764 mode singleAsPathMatchMode 765 } 766 767 func (lhs *singleAsPathMatch) Equal(rhs *singleAsPathMatch) bool { 768 return lhs.asn == rhs.asn && lhs.mode == rhs.mode 769 } 770 771 func (lhs *singleAsPathMatch) String() string { 772 switch lhs.mode { 773 case INCLUDE: 774 return fmt.Sprintf("_%d_", lhs.asn) 775 case LEFT_MOST: 776 return fmt.Sprintf("^%d_", lhs.asn) 777 case ORIGIN: 778 return fmt.Sprintf("_%d$", lhs.asn) 779 case ONLY: 780 return fmt.Sprintf("^%d$", lhs.asn) 781 } 782 return "" 783 } 784 785 func (m *singleAsPathMatch) Match(aspath []uint32) bool { 786 if len(aspath) == 0 { 787 return false 788 } 789 switch m.mode { 790 case INCLUDE: 791 for _, asn := range aspath { 792 if m.asn == asn { 793 return true 794 } 795 } 796 case LEFT_MOST: 797 if m.asn == aspath[0] { 798 return true 799 } 800 case ORIGIN: 801 if m.asn == aspath[len(aspath)-1] { 802 return true 803 } 804 case ONLY: 805 if len(aspath) == 1 && m.asn == aspath[0] { 806 return true 807 } 808 } 809 return false 810 } 811 812 var ( 813 _regexpLeftMostRe = regexp.MustCompile(`^\^([0-9]+)_$`) 814 _regexpOriginRe = regexp.MustCompile(`^_([0-9]+)\$$`) 815 _regexpIncludeRe = regexp.MustCompile("^_([0-9]+)_$") 816 _regexpOnlyRe = regexp.MustCompile(`^\^([0-9]+)\$$`) 817 ) 818 819 func NewSingleAsPathMatch(arg string) *singleAsPathMatch { 820 switch { 821 case _regexpLeftMostRe.MatchString(arg): 822 asn, _ := strconv.ParseUint(_regexpLeftMostRe.FindStringSubmatch(arg)[1], 10, 32) 823 return &singleAsPathMatch{ 824 asn: uint32(asn), 825 mode: LEFT_MOST, 826 } 827 case _regexpOriginRe.MatchString(arg): 828 asn, _ := strconv.ParseUint(_regexpOriginRe.FindStringSubmatch(arg)[1], 10, 32) 829 return &singleAsPathMatch{ 830 asn: uint32(asn), 831 mode: ORIGIN, 832 } 833 case _regexpIncludeRe.MatchString(arg): 834 asn, _ := strconv.ParseUint(_regexpIncludeRe.FindStringSubmatch(arg)[1], 10, 32) 835 return &singleAsPathMatch{ 836 asn: uint32(asn), 837 mode: INCLUDE, 838 } 839 case _regexpOnlyRe.MatchString(arg): 840 asn, _ := strconv.ParseUint(_regexpOnlyRe.FindStringSubmatch(arg)[1], 10, 32) 841 return &singleAsPathMatch{ 842 asn: uint32(asn), 843 mode: ONLY, 844 } 845 } 846 return nil 847 } 848 849 type AsPathSet struct { 850 typ DefinedType 851 name string 852 list []*regexp.Regexp 853 singleList []*singleAsPathMatch 854 } 855 856 func (s *AsPathSet) Name() string { 857 return s.name 858 } 859 860 func (s *AsPathSet) Type() DefinedType { 861 return s.typ 862 } 863 864 func (lhs *AsPathSet) Append(arg DefinedSet) error { 865 if lhs.Type() != arg.Type() { 866 return fmt.Errorf("can't append to different type of defined-set") 867 } 868 lhs.list = append(lhs.list, arg.(*AsPathSet).list...) 869 lhs.singleList = append(lhs.singleList, arg.(*AsPathSet).singleList...) 870 return nil 871 } 872 873 func (lhs *AsPathSet) Remove(arg DefinedSet) error { 874 if lhs.Type() != arg.Type() { 875 return fmt.Errorf("can't append to different type of defined-set") 876 } 877 newList := make([]*regexp.Regexp, 0, len(lhs.list)) 878 for _, x := range lhs.list { 879 found := false 880 for _, y := range arg.(*AsPathSet).list { 881 if x.String() == y.String() { 882 found = true 883 break 884 } 885 } 886 if !found { 887 newList = append(newList, x) 888 } 889 } 890 lhs.list = newList 891 newSingleList := make([]*singleAsPathMatch, 0, len(lhs.singleList)) 892 for _, x := range lhs.singleList { 893 found := false 894 for _, y := range arg.(*AsPathSet).singleList { 895 if x.Equal(y) { 896 found = true 897 break 898 } 899 } 900 if !found { 901 newSingleList = append(newSingleList, x) 902 } 903 } 904 lhs.singleList = newSingleList 905 return nil 906 } 907 908 func (lhs *AsPathSet) Replace(arg DefinedSet) error { 909 rhs, ok := arg.(*AsPathSet) 910 if !ok { 911 return fmt.Errorf("type cast failed") 912 } 913 lhs.list = rhs.list 914 lhs.singleList = rhs.singleList 915 return nil 916 } 917 918 func (s *AsPathSet) List() []string { 919 list := make([]string, 0, len(s.list)+len(s.singleList)) 920 for _, exp := range s.singleList { 921 list = append(list, exp.String()) 922 } 923 for _, exp := range s.list { 924 list = append(list, exp.String()) 925 } 926 return list 927 } 928 929 func (s *AsPathSet) ToConfig() *oc.AsPathSet { 930 return &oc.AsPathSet{ 931 AsPathSetName: s.name, 932 AsPathList: s.List(), 933 } 934 } 935 936 func (s *AsPathSet) String() string { 937 return strings.Join(s.List(), "\n") 938 } 939 940 func (s *AsPathSet) MarshalJSON() ([]byte, error) { 941 return json.Marshal(s.ToConfig()) 942 } 943 944 func NewAsPathSet(c oc.AsPathSet) (*AsPathSet, error) { 945 name := c.AsPathSetName 946 if name == "" { 947 if len(c.AsPathList) == 0 { 948 return nil, nil 949 } 950 return nil, fmt.Errorf("empty as-path set name") 951 } 952 list := make([]*regexp.Regexp, 0, len(c.AsPathList)) 953 singleList := make([]*singleAsPathMatch, 0, len(c.AsPathList)) 954 for _, x := range c.AsPathList { 955 if s := NewSingleAsPathMatch(x); s != nil { 956 singleList = append(singleList, s) 957 } else { 958 exp, err := regexp.Compile(strings.Replace(x, "_", ASPATH_REGEXP_MAGIC, -1)) 959 if err != nil { 960 return nil, fmt.Errorf("invalid regular expression: %s", x) 961 } 962 list = append(list, exp) 963 } 964 } 965 return &AsPathSet{ 966 typ: DEFINED_TYPE_AS_PATH, 967 name: name, 968 list: list, 969 singleList: singleList, 970 }, nil 971 } 972 973 type regExpSet struct { 974 typ DefinedType 975 name string 976 list []*regexp.Regexp 977 } 978 979 func (s *regExpSet) Name() string { 980 return s.name 981 } 982 983 func (s *regExpSet) Type() DefinedType { 984 return s.typ 985 } 986 987 func (lhs *regExpSet) Append(arg DefinedSet) error { 988 if lhs.Type() != arg.Type() { 989 return fmt.Errorf("can't append to different type of defined-set") 990 } 991 var list []*regexp.Regexp 992 switch lhs.Type() { 993 case DEFINED_TYPE_AS_PATH: 994 list = arg.(*AsPathSet).list 995 case DEFINED_TYPE_COMMUNITY: 996 list = arg.(*CommunitySet).list 997 case DEFINED_TYPE_EXT_COMMUNITY: 998 list = arg.(*ExtCommunitySet).list 999 case DEFINED_TYPE_LARGE_COMMUNITY: 1000 list = arg.(*LargeCommunitySet).list 1001 default: 1002 return fmt.Errorf("invalid defined-set type: %d", lhs.Type()) 1003 } 1004 lhs.list = append(lhs.list, list...) 1005 return nil 1006 } 1007 1008 func (lhs *regExpSet) Remove(arg DefinedSet) error { 1009 if lhs.Type() != arg.Type() { 1010 return fmt.Errorf("can't append to different type of defined-set") 1011 } 1012 var list []*regexp.Regexp 1013 switch lhs.Type() { 1014 case DEFINED_TYPE_AS_PATH: 1015 list = arg.(*AsPathSet).list 1016 case DEFINED_TYPE_COMMUNITY: 1017 list = arg.(*CommunitySet).list 1018 case DEFINED_TYPE_EXT_COMMUNITY: 1019 list = arg.(*ExtCommunitySet).list 1020 case DEFINED_TYPE_LARGE_COMMUNITY: 1021 list = arg.(*LargeCommunitySet).list 1022 default: 1023 return fmt.Errorf("invalid defined-set type: %d", lhs.Type()) 1024 } 1025 ps := make([]*regexp.Regexp, 0, len(lhs.list)) 1026 for _, x := range lhs.list { 1027 found := false 1028 for _, y := range list { 1029 if x.String() == y.String() { 1030 found = true 1031 break 1032 } 1033 } 1034 if !found { 1035 ps = append(ps, x) 1036 } 1037 } 1038 lhs.list = ps 1039 return nil 1040 } 1041 1042 func (lhs *regExpSet) Replace(arg DefinedSet) error { 1043 switch c := arg.(type) { 1044 case *CommunitySet: 1045 lhs.list = c.list 1046 case *ExtCommunitySet: 1047 lhs.list = c.list 1048 case *LargeCommunitySet: 1049 lhs.list = c.list 1050 default: 1051 return fmt.Errorf("type cast failed") 1052 } 1053 return nil 1054 } 1055 1056 type CommunitySet struct { 1057 regExpSet 1058 } 1059 1060 func (s *CommunitySet) List() []string { 1061 list := make([]string, 0, len(s.list)) 1062 for _, exp := range s.list { 1063 list = append(list, exp.String()) 1064 } 1065 return list 1066 } 1067 1068 func (s *CommunitySet) ToConfig() *oc.CommunitySet { 1069 return &oc.CommunitySet{ 1070 CommunitySetName: s.name, 1071 CommunityList: s.List(), 1072 } 1073 } 1074 1075 func (s *CommunitySet) String() string { 1076 return strings.Join(s.List(), "\n") 1077 } 1078 1079 func (s *CommunitySet) MarshalJSON() ([]byte, error) { 1080 return json.Marshal(s.ToConfig()) 1081 } 1082 1083 var _regexpCommunity = regexp.MustCompile(`(\d+):(\d+)`) 1084 1085 func ParseCommunity(arg string) (uint32, error) { 1086 i, err := strconv.ParseUint(arg, 10, 32) 1087 if err == nil { 1088 return uint32(i), nil 1089 } 1090 1091 elems := _regexpCommunity.FindStringSubmatch(arg) 1092 if len(elems) == 3 { 1093 fst, _ := strconv.ParseUint(elems[1], 10, 16) 1094 snd, _ := strconv.ParseUint(elems[2], 10, 16) 1095 return uint32(fst<<16 | snd), nil 1096 } 1097 for i, v := range bgp.WellKnownCommunityNameMap { 1098 if arg == v { 1099 return uint32(i), nil 1100 } 1101 } 1102 return 0, fmt.Errorf("failed to parse %s as community", arg) 1103 } 1104 1105 func ParseExtCommunity(arg string) (bgp.ExtendedCommunityInterface, error) { 1106 var subtype bgp.ExtendedCommunityAttrSubType 1107 var value string 1108 elems := strings.SplitN(arg, ":", 2) 1109 1110 isValidationState := func(s string) bool { 1111 s = strings.ToLower(s) 1112 r := s == bgp.VALIDATION_STATE_VALID.String() 1113 r = r || s == bgp.VALIDATION_STATE_NOT_FOUND.String() 1114 return r || s == bgp.VALIDATION_STATE_INVALID.String() 1115 } 1116 if len(elems) < 2 && (len(elems) < 1 && !isValidationState(elems[0])) { 1117 return nil, fmt.Errorf("invalid ext-community (rt|soo|encap|lb):<value> | valid | not-found | invalid") 1118 } 1119 if isValidationState(elems[0]) { 1120 subtype = bgp.EC_SUBTYPE_ORIGIN_VALIDATION 1121 value = elems[0] 1122 } else { 1123 switch strings.ToLower(elems[0]) { 1124 case "rt": 1125 subtype = bgp.EC_SUBTYPE_ROUTE_TARGET 1126 case "soo": 1127 subtype = bgp.EC_SUBTYPE_ROUTE_ORIGIN 1128 case "encap": 1129 subtype = bgp.EC_SUBTYPE_ENCAPSULATION 1130 case "lb": 1131 subtype = bgp.EC_SUBTYPE_LINK_BANDWIDTH 1132 default: 1133 return nil, fmt.Errorf("invalid ext-community (rt|soo|encap|lb):<value> | valid | not-found | invalid") 1134 } 1135 value = elems[1] 1136 } 1137 return bgp.ParseExtendedCommunity(subtype, value) 1138 } 1139 1140 var _regexpCommunity2 = regexp.MustCompile(`^(\d+.)*\d+:\d+$`) 1141 1142 func ParseCommunityRegexp(arg string) (*regexp.Regexp, error) { 1143 i, err := strconv.ParseUint(arg, 10, 32) 1144 if err == nil { 1145 return regexp.Compile(fmt.Sprintf("^%d:%d$", i>>16, i&0x0000ffff)) 1146 } 1147 1148 if _regexpCommunity2.MatchString(arg) { 1149 return regexp.Compile(fmt.Sprintf("^%s$", arg)) 1150 } 1151 1152 for i, v := range bgp.WellKnownCommunityNameMap { 1153 if strings.Replace(strings.ToLower(arg), "_", "-", -1) == v { 1154 return regexp.Compile(fmt.Sprintf("^%d:%d$", i>>16, i&0x0000ffff)) 1155 } 1156 } 1157 1158 return regexp.Compile(arg) 1159 } 1160 1161 func ParseExtCommunityRegexp(arg string) (bgp.ExtendedCommunityAttrSubType, *regexp.Regexp, error) { 1162 var subtype bgp.ExtendedCommunityAttrSubType 1163 elems := strings.SplitN(arg, ":", 2) 1164 if len(elems) < 2 { 1165 return subtype, nil, fmt.Errorf("invalid ext-community format([rt|soo|encap|lb]:<value>)") 1166 } 1167 switch strings.ToLower(elems[0]) { 1168 case "rt": 1169 subtype = bgp.EC_SUBTYPE_ROUTE_TARGET 1170 case "soo": 1171 subtype = bgp.EC_SUBTYPE_ROUTE_ORIGIN 1172 case "encap": 1173 subtype = bgp.EC_SUBTYPE_ENCAPSULATION 1174 case "lb": 1175 subtype = bgp.EC_SUBTYPE_LINK_BANDWIDTH 1176 default: 1177 return subtype, nil, fmt.Errorf("unknown ext-community subtype. rt, soo, encap, lb is supported") 1178 } 1179 exp, err := ParseCommunityRegexp(elems[1]) 1180 return subtype, exp, err 1181 } 1182 1183 func NewCommunitySet(c oc.CommunitySet) (*CommunitySet, error) { 1184 name := c.CommunitySetName 1185 if name == "" { 1186 if len(c.CommunityList) == 0 { 1187 return nil, nil 1188 } 1189 return nil, fmt.Errorf("empty community set name") 1190 } 1191 list := make([]*regexp.Regexp, 0, len(c.CommunityList)) 1192 for _, x := range c.CommunityList { 1193 exp, err := ParseCommunityRegexp(x) 1194 if err != nil { 1195 return nil, err 1196 } 1197 list = append(list, exp) 1198 } 1199 return &CommunitySet{ 1200 regExpSet: regExpSet{ 1201 typ: DEFINED_TYPE_COMMUNITY, 1202 name: name, 1203 list: list, 1204 }, 1205 }, nil 1206 } 1207 1208 type ExtCommunitySet struct { 1209 regExpSet 1210 subtypeList []bgp.ExtendedCommunityAttrSubType 1211 } 1212 1213 func (s *ExtCommunitySet) List() []string { 1214 list := make([]string, 0, len(s.list)) 1215 f := func(idx int, arg string) string { 1216 switch s.subtypeList[idx] { 1217 case bgp.EC_SUBTYPE_ROUTE_TARGET: 1218 return fmt.Sprintf("rt:%s", arg) 1219 case bgp.EC_SUBTYPE_ROUTE_ORIGIN: 1220 return fmt.Sprintf("soo:%s", arg) 1221 case bgp.EC_SUBTYPE_ENCAPSULATION: 1222 return fmt.Sprintf("encap:%s", arg) 1223 case bgp.EC_SUBTYPE_ORIGIN_VALIDATION: 1224 return arg 1225 case bgp.EC_SUBTYPE_LINK_BANDWIDTH: 1226 return fmt.Sprintf("lb:%s", arg) 1227 default: 1228 return fmt.Sprintf("%d:%s", s.subtypeList[idx], arg) 1229 } 1230 } 1231 for idx, exp := range s.list { 1232 list = append(list, f(idx, exp.String())) 1233 } 1234 return list 1235 } 1236 1237 func (s *ExtCommunitySet) ToConfig() *oc.ExtCommunitySet { 1238 return &oc.ExtCommunitySet{ 1239 ExtCommunitySetName: s.name, 1240 ExtCommunityList: s.List(), 1241 } 1242 } 1243 1244 func (s *ExtCommunitySet) String() string { 1245 return strings.Join(s.List(), "\n") 1246 } 1247 1248 func (s *ExtCommunitySet) MarshalJSON() ([]byte, error) { 1249 return json.Marshal(s.ToConfig()) 1250 } 1251 1252 func NewExtCommunitySet(c oc.ExtCommunitySet) (*ExtCommunitySet, error) { 1253 name := c.ExtCommunitySetName 1254 if name == "" { 1255 if len(c.ExtCommunityList) == 0 { 1256 return nil, nil 1257 } 1258 return nil, fmt.Errorf("empty ext-community set name") 1259 } 1260 list := make([]*regexp.Regexp, 0, len(c.ExtCommunityList)) 1261 subtypeList := make([]bgp.ExtendedCommunityAttrSubType, 0, len(c.ExtCommunityList)) 1262 for _, x := range c.ExtCommunityList { 1263 subtype, exp, err := ParseExtCommunityRegexp(x) 1264 if err != nil { 1265 return nil, err 1266 } 1267 list = append(list, exp) 1268 subtypeList = append(subtypeList, subtype) 1269 } 1270 return &ExtCommunitySet{ 1271 regExpSet: regExpSet{ 1272 typ: DEFINED_TYPE_EXT_COMMUNITY, 1273 name: name, 1274 list: list, 1275 }, 1276 subtypeList: subtypeList, 1277 }, nil 1278 } 1279 1280 func (s *ExtCommunitySet) Append(arg DefinedSet) error { 1281 err := s.regExpSet.Append(arg) 1282 if err != nil { 1283 return err 1284 } 1285 sList := arg.(*ExtCommunitySet).subtypeList 1286 s.subtypeList = append(s.subtypeList, sList...) 1287 return nil 1288 } 1289 1290 type LargeCommunitySet struct { 1291 regExpSet 1292 } 1293 1294 func (s *LargeCommunitySet) List() []string { 1295 list := make([]string, 0, len(s.list)) 1296 for _, exp := range s.list { 1297 list = append(list, exp.String()) 1298 } 1299 return list 1300 } 1301 1302 func (s *LargeCommunitySet) ToConfig() *oc.LargeCommunitySet { 1303 return &oc.LargeCommunitySet{ 1304 LargeCommunitySetName: s.name, 1305 LargeCommunityList: s.List(), 1306 } 1307 } 1308 1309 func (s *LargeCommunitySet) String() string { 1310 return strings.Join(s.List(), "\n") 1311 } 1312 1313 func (s *LargeCommunitySet) MarshalJSON() ([]byte, error) { 1314 return json.Marshal(s.ToConfig()) 1315 } 1316 1317 var _regexpCommunityLarge = regexp.MustCompile(`\d+:\d+:\d+`) 1318 1319 func ParseLargeCommunityRegexp(arg string) (*regexp.Regexp, error) { 1320 if _regexpCommunityLarge.MatchString(arg) { 1321 return regexp.Compile(fmt.Sprintf("^%s$", arg)) 1322 } 1323 exp, err := regexp.Compile(arg) 1324 if err != nil { 1325 return nil, fmt.Errorf("invalid large-community format: %v", err) 1326 } 1327 1328 return exp, nil 1329 } 1330 1331 func NewLargeCommunitySet(c oc.LargeCommunitySet) (*LargeCommunitySet, error) { 1332 name := c.LargeCommunitySetName 1333 if name == "" { 1334 if len(c.LargeCommunityList) == 0 { 1335 return nil, nil 1336 } 1337 return nil, fmt.Errorf("empty large community set name") 1338 } 1339 list := make([]*regexp.Regexp, 0, len(c.LargeCommunityList)) 1340 for _, x := range c.LargeCommunityList { 1341 exp, err := ParseLargeCommunityRegexp(x) 1342 if err != nil { 1343 return nil, err 1344 } 1345 list = append(list, exp) 1346 } 1347 return &LargeCommunitySet{ 1348 regExpSet: regExpSet{ 1349 typ: DEFINED_TYPE_LARGE_COMMUNITY, 1350 name: name, 1351 list: list, 1352 }, 1353 }, nil 1354 } 1355 1356 type Condition interface { 1357 Name() string 1358 Type() ConditionType 1359 Evaluate(*Path, *PolicyOptions) bool 1360 Set() DefinedSet 1361 } 1362 1363 type NextHopCondition struct { 1364 set *NextHopSet 1365 } 1366 1367 func (c *NextHopCondition) Type() ConditionType { 1368 return CONDITION_NEXT_HOP 1369 } 1370 1371 func (c *NextHopCondition) Set() DefinedSet { 1372 return c.set 1373 } 1374 1375 func (c *NextHopCondition) Name() string { return "" } 1376 1377 func (c *NextHopCondition) String() string { 1378 return c.set.String() 1379 } 1380 1381 // compare next-hop ipaddress of this condition and source address of path 1382 // and, subsequent comparisons are skipped if that matches the conditions. 1383 // If NextHopSet's length is zero, return true. 1384 func (c *NextHopCondition) Evaluate(path *Path, options *PolicyOptions) bool { 1385 if len(c.set.list) == 0 { 1386 return true 1387 } 1388 1389 nexthop := path.GetNexthop() 1390 1391 // In cases where we advertise routes from iBGP to eBGP, we want to filter 1392 // on the "original" nexthop. The current paths' nexthop has already been 1393 // set and is ready to be advertised as per: 1394 // https://tools.ietf.org/html/rfc4271#section-5.1.3 1395 if options != nil && options.OldNextHop != nil && 1396 !options.OldNextHop.IsUnspecified() && !options.OldNextHop.Equal(nexthop) { 1397 nexthop = options.OldNextHop 1398 } 1399 1400 if nexthop == nil { 1401 return false 1402 } 1403 1404 for _, n := range c.set.list { 1405 if n.Contains(nexthop) { 1406 return true 1407 } 1408 } 1409 1410 return false 1411 } 1412 1413 func NewNextHopCondition(c []string) (*NextHopCondition, error) { 1414 if len(c) == 0 { 1415 return nil, nil 1416 } 1417 1418 list, err := NewNextHopSet(c) 1419 if err != nil { 1420 return nil, nil 1421 } 1422 1423 return &NextHopCondition{ 1424 set: list, 1425 }, nil 1426 } 1427 1428 type PrefixCondition struct { 1429 set *PrefixSet 1430 option MatchOption 1431 } 1432 1433 func (c *PrefixCondition) Type() ConditionType { 1434 return CONDITION_PREFIX 1435 } 1436 1437 func (c *PrefixCondition) Set() DefinedSet { 1438 return c.set 1439 } 1440 1441 func (c *PrefixCondition) Option() MatchOption { 1442 return c.option 1443 } 1444 1445 // compare prefixes in this condition and nlri of path and 1446 // subsequent comparison is skipped if that matches the conditions. 1447 // If PrefixList's length is zero, return true. 1448 func (c *PrefixCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 1449 pathAfi, _ := bgp.RouteFamilyToAfiSafi(path.GetRouteFamily()) 1450 cAfi, _ := bgp.RouteFamilyToAfiSafi(c.set.family) 1451 1452 if cAfi != pathAfi { 1453 return false 1454 } 1455 1456 r := nlriToIPNet(path.GetNlri()) 1457 if r == nil { 1458 return false 1459 } 1460 ones, _ := r.Mask.Size() 1461 masklen := uint8(ones) 1462 result := false 1463 if _, ps, _ := c.set.tree.Match(r); ps != nil { 1464 for _, p := range ps.([]*Prefix) { 1465 if p.MasklengthRangeMin <= masklen && masklen <= p.MasklengthRangeMax { 1466 result = true 1467 break 1468 } 1469 } 1470 } 1471 1472 if c.option == MATCH_OPTION_INVERT { 1473 result = !result 1474 } 1475 1476 return result 1477 } 1478 1479 func (c *PrefixCondition) Name() string { return c.set.name } 1480 1481 func NewPrefixCondition(c oc.MatchPrefixSet) (*PrefixCondition, error) { 1482 if c.PrefixSet == "" { 1483 return nil, nil 1484 } 1485 o, err := NewMatchOption(c.MatchSetOptions) 1486 if err != nil { 1487 return nil, err 1488 } 1489 return &PrefixCondition{ 1490 set: &PrefixSet{ 1491 name: c.PrefixSet, 1492 }, 1493 option: o, 1494 }, nil 1495 } 1496 1497 type NeighborCondition struct { 1498 set *NeighborSet 1499 option MatchOption 1500 } 1501 1502 func (c *NeighborCondition) Type() ConditionType { 1503 return CONDITION_NEIGHBOR 1504 } 1505 1506 func (c *NeighborCondition) Set() DefinedSet { 1507 return c.set 1508 } 1509 1510 func (c *NeighborCondition) Option() MatchOption { 1511 return c.option 1512 } 1513 1514 // compare neighbor ipaddress of this condition and source address of path 1515 // and, subsequent comparisons are skipped if that matches the conditions. 1516 // If NeighborList's length is zero, return true. 1517 func (c *NeighborCondition) Evaluate(path *Path, options *PolicyOptions) bool { 1518 if len(c.set.list) == 0 { 1519 return true 1520 } 1521 1522 neighbor := path.GetSource().Address 1523 if options != nil && options.Info != nil && options.Info.Address != nil { 1524 neighbor = options.Info.Address 1525 } 1526 1527 if neighbor == nil { 1528 return false 1529 } 1530 result := false 1531 for _, n := range c.set.list { 1532 if n.Contains(neighbor) { 1533 result = true 1534 break 1535 } 1536 } 1537 1538 if c.option == MATCH_OPTION_INVERT { 1539 result = !result 1540 } 1541 1542 return result 1543 } 1544 1545 func (c *NeighborCondition) Name() string { return c.set.name } 1546 1547 func NewNeighborCondition(c oc.MatchNeighborSet) (*NeighborCondition, error) { 1548 if c.NeighborSet == "" { 1549 return nil, nil 1550 } 1551 o, err := NewMatchOption(c.MatchSetOptions) 1552 if err != nil { 1553 return nil, err 1554 } 1555 return &NeighborCondition{ 1556 set: &NeighborSet{ 1557 name: c.NeighborSet, 1558 }, 1559 option: o, 1560 }, nil 1561 } 1562 1563 type AsPathCondition struct { 1564 set *AsPathSet 1565 option MatchOption 1566 } 1567 1568 func (c *AsPathCondition) Type() ConditionType { 1569 return CONDITION_AS_PATH 1570 } 1571 1572 func (c *AsPathCondition) Set() DefinedSet { 1573 return c.set 1574 } 1575 1576 func (c *AsPathCondition) Option() MatchOption { 1577 return c.option 1578 } 1579 1580 func (c *AsPathCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 1581 if len(c.set.singleList) > 0 { 1582 aspath := path.GetAsSeqList() 1583 for _, m := range c.set.singleList { 1584 result := m.Match(aspath) 1585 if c.option == MATCH_OPTION_ALL && !result { 1586 return false 1587 } 1588 if c.option == MATCH_OPTION_ANY && result { 1589 return true 1590 } 1591 if c.option == MATCH_OPTION_INVERT && result { 1592 return false 1593 } 1594 } 1595 } 1596 if len(c.set.list) > 0 { 1597 aspath := path.GetAsString() 1598 for _, r := range c.set.list { 1599 result := r.MatchString(aspath) 1600 if c.option == MATCH_OPTION_ALL && !result { 1601 return false 1602 } 1603 if c.option == MATCH_OPTION_ANY && result { 1604 return true 1605 } 1606 if c.option == MATCH_OPTION_INVERT && result { 1607 return false 1608 } 1609 } 1610 } 1611 if c.option == MATCH_OPTION_ANY { 1612 return false 1613 } 1614 return true 1615 } 1616 1617 func (c *AsPathCondition) Name() string { return c.set.name } 1618 1619 func NewAsPathCondition(c oc.MatchAsPathSet) (*AsPathCondition, error) { 1620 if c.AsPathSet == "" { 1621 return nil, nil 1622 } 1623 o, err := NewMatchOption(c.MatchSetOptions) 1624 if err != nil { 1625 return nil, err 1626 } 1627 return &AsPathCondition{ 1628 set: &AsPathSet{ 1629 name: c.AsPathSet, 1630 }, 1631 option: o, 1632 }, nil 1633 } 1634 1635 type CommunityCondition struct { 1636 set *CommunitySet 1637 option MatchOption 1638 } 1639 1640 func (c *CommunityCondition) Type() ConditionType { 1641 return CONDITION_COMMUNITY 1642 } 1643 1644 func (c *CommunityCondition) Set() DefinedSet { 1645 return c.set 1646 } 1647 1648 func (c *CommunityCondition) Option() MatchOption { 1649 return c.option 1650 } 1651 1652 func (c *CommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 1653 cs := path.GetCommunities() 1654 result := false 1655 for _, x := range c.set.list { 1656 result = false 1657 for _, y := range cs { 1658 if x.MatchString(fmt.Sprintf("%d:%d", y>>16, y&0x0000ffff)) { 1659 result = true 1660 break 1661 } 1662 } 1663 if c.option == MATCH_OPTION_ALL && !result { 1664 break 1665 } 1666 if (c.option == MATCH_OPTION_ANY || c.option == MATCH_OPTION_INVERT) && result { 1667 break 1668 } 1669 } 1670 if c.option == MATCH_OPTION_INVERT { 1671 result = !result 1672 } 1673 return result 1674 } 1675 1676 func (c *CommunityCondition) Name() string { return c.set.name } 1677 1678 func NewCommunityCondition(c oc.MatchCommunitySet) (*CommunityCondition, error) { 1679 if c.CommunitySet == "" { 1680 return nil, nil 1681 } 1682 o, err := NewMatchOption(c.MatchSetOptions) 1683 if err != nil { 1684 return nil, err 1685 } 1686 return &CommunityCondition{ 1687 set: &CommunitySet{ 1688 regExpSet: regExpSet{ 1689 name: c.CommunitySet, 1690 }, 1691 }, 1692 option: o, 1693 }, nil 1694 } 1695 1696 type ExtCommunityCondition struct { 1697 set *ExtCommunitySet 1698 option MatchOption 1699 } 1700 1701 func (c *ExtCommunityCondition) Type() ConditionType { 1702 return CONDITION_EXT_COMMUNITY 1703 } 1704 1705 func (c *ExtCommunityCondition) Set() DefinedSet { 1706 return c.set 1707 } 1708 1709 func (c *ExtCommunityCondition) Option() MatchOption { 1710 return c.option 1711 } 1712 1713 func (c *ExtCommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 1714 es := path.GetExtCommunities() 1715 result := false 1716 for _, x := range es { 1717 result = false 1718 typ, subtype := x.GetTypes() 1719 // match only with transitive community. see RFC7153 1720 if typ >= 0x3f { 1721 continue 1722 } 1723 var xStr string 1724 for idx, y := range c.set.list { 1725 if subtype == c.set.subtypeList[idx] { 1726 if len(xStr) == 0 { 1727 // caching x.String() saves a lot of resources when matching against 1728 // a lot of conditions, link hundreds of RTs. 1729 xStr = x.String() 1730 } 1731 if y.MatchString(xStr) { 1732 result = true 1733 break 1734 } 1735 } 1736 } 1737 if c.option == MATCH_OPTION_ALL && !result { 1738 break 1739 } 1740 if c.option == MATCH_OPTION_ANY && result { 1741 break 1742 } 1743 } 1744 if c.option == MATCH_OPTION_INVERT { 1745 result = !result 1746 } 1747 return result 1748 } 1749 1750 func (c *ExtCommunityCondition) Name() string { return c.set.name } 1751 1752 func NewExtCommunityCondition(c oc.MatchExtCommunitySet) (*ExtCommunityCondition, error) { 1753 if c.ExtCommunitySet == "" { 1754 return nil, nil 1755 } 1756 o, err := NewMatchOption(c.MatchSetOptions) 1757 if err != nil { 1758 return nil, err 1759 } 1760 return &ExtCommunityCondition{ 1761 set: &ExtCommunitySet{ 1762 regExpSet: regExpSet{ 1763 name: c.ExtCommunitySet, 1764 }, 1765 }, 1766 option: o, 1767 }, nil 1768 } 1769 1770 type LargeCommunityCondition struct { 1771 set *LargeCommunitySet 1772 option MatchOption 1773 } 1774 1775 func (c *LargeCommunityCondition) Type() ConditionType { 1776 return CONDITION_LARGE_COMMUNITY 1777 } 1778 1779 func (c *LargeCommunityCondition) Set() DefinedSet { 1780 return c.set 1781 } 1782 1783 func (c *LargeCommunityCondition) Option() MatchOption { 1784 return c.option 1785 } 1786 1787 func (c *LargeCommunityCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 1788 result := false 1789 cs := path.GetLargeCommunities() 1790 for _, x := range c.set.list { 1791 result = false 1792 for _, y := range cs { 1793 if x.MatchString(y.String()) { 1794 result = true 1795 break 1796 } 1797 } 1798 if c.option == MATCH_OPTION_ALL && !result { 1799 break 1800 } 1801 if (c.option == MATCH_OPTION_ANY || c.option == MATCH_OPTION_INVERT) && result { 1802 break 1803 } 1804 } 1805 if c.option == MATCH_OPTION_INVERT { 1806 result = !result 1807 } 1808 return result 1809 } 1810 1811 func (c *LargeCommunityCondition) Name() string { return c.set.name } 1812 1813 func NewLargeCommunityCondition(c oc.MatchLargeCommunitySet) (*LargeCommunityCondition, error) { 1814 if c.LargeCommunitySet == "" { 1815 return nil, nil 1816 } 1817 o, err := NewMatchOption(c.MatchSetOptions) 1818 if err != nil { 1819 return nil, err 1820 } 1821 return &LargeCommunityCondition{ 1822 set: &LargeCommunitySet{ 1823 regExpSet: regExpSet{ 1824 name: c.LargeCommunitySet, 1825 }, 1826 }, 1827 option: o, 1828 }, nil 1829 } 1830 1831 type CommunityCountCondition struct { 1832 count uint32 1833 operator AttributeComparison 1834 } 1835 1836 func (c *CommunityCountCondition) Type() ConditionType { 1837 return CONDITION_COMMUNITY_COUNT 1838 } 1839 1840 // Evaluate compares the number of communities in the message's community 1841 // attributes with the one in condition. 1842 func (c *CommunityCountCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 1843 count := uint32(len(path.GetCommunities())) 1844 switch c.operator { 1845 case ATTRIBUTE_EQ: 1846 return count == c.count 1847 case ATTRIBUTE_GE: 1848 return count >= c.count 1849 case ATTRIBUTE_LE: 1850 return count <= c.count 1851 default: 1852 return false 1853 } 1854 } 1855 1856 func (c *CommunityCountCondition) Set() DefinedSet { 1857 return nil 1858 } 1859 1860 func (c *CommunityCountCondition) Name() string { return "" } 1861 1862 func (c *CommunityCountCondition) String() string { 1863 return fmt.Sprintf("%s%d", c.operator, c.count) 1864 } 1865 1866 func NewCommunityCountCondition(c oc.CommunityCount) (*CommunityCountCondition, error) { 1867 if c.Value == 0 && c.Operator == "" { 1868 return nil, nil 1869 } 1870 var op AttributeComparison 1871 if i := c.Operator.ToInt(); i < 0 { 1872 return nil, fmt.Errorf("invalid community count operator: %s", c.Operator) 1873 } else { 1874 // take mod 3 because we have extended openconfig attribute-comparison 1875 // for simple configuration. see oc.AttributeComparison definition 1876 op = AttributeComparison(i % 3) 1877 } 1878 return &CommunityCountCondition{ 1879 count: c.Value, 1880 operator: op, 1881 }, nil 1882 } 1883 1884 type AsPathLengthCondition struct { 1885 length uint32 1886 operator AttributeComparison 1887 } 1888 1889 func (c *AsPathLengthCondition) Type() ConditionType { 1890 return CONDITION_AS_PATH_LENGTH 1891 } 1892 1893 // compare AS_PATH length in the message's AS_PATH attribute with 1894 // the one in condition. 1895 func (c *AsPathLengthCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 1896 length := uint32(path.GetAsPathLen()) 1897 switch c.operator { 1898 case ATTRIBUTE_EQ: 1899 return length == c.length 1900 case ATTRIBUTE_GE: 1901 return length >= c.length 1902 case ATTRIBUTE_LE: 1903 return length <= c.length 1904 default: 1905 return false 1906 } 1907 } 1908 1909 func (c *AsPathLengthCondition) Set() DefinedSet { 1910 return nil 1911 } 1912 1913 func (c *AsPathLengthCondition) Name() string { return "" } 1914 1915 func (c *AsPathLengthCondition) String() string { 1916 return fmt.Sprintf("%s%d", c.operator, c.length) 1917 } 1918 1919 func NewAsPathLengthCondition(c oc.AsPathLength) (*AsPathLengthCondition, error) { 1920 if c.Value == 0 && c.Operator == "" { 1921 return nil, nil 1922 } 1923 var op AttributeComparison 1924 if i := c.Operator.ToInt(); i < 0 { 1925 return nil, fmt.Errorf("invalid as path length operator: %s", c.Operator) 1926 } else { 1927 // take mod 3 because we have extended openconfig attribute-comparison 1928 // for simple configuration. see oc.AttributeComparison definition 1929 op = AttributeComparison(i % 3) 1930 } 1931 return &AsPathLengthCondition{ 1932 length: c.Value, 1933 operator: op, 1934 }, nil 1935 } 1936 1937 type RpkiValidationCondition struct { 1938 result oc.RpkiValidationResultType 1939 } 1940 1941 func (c *RpkiValidationCondition) Type() ConditionType { 1942 return CONDITION_RPKI 1943 } 1944 1945 func (c *RpkiValidationCondition) Evaluate(path *Path, options *PolicyOptions) bool { 1946 if options != nil && options.Validate != nil { 1947 return c.result == options.Validate(path).Status 1948 } 1949 return false 1950 } 1951 1952 func (c *RpkiValidationCondition) Set() DefinedSet { 1953 return nil 1954 } 1955 1956 func (c *RpkiValidationCondition) Name() string { return "" } 1957 1958 func (c *RpkiValidationCondition) String() string { 1959 return string(c.result) 1960 } 1961 1962 func NewRpkiValidationCondition(c oc.RpkiValidationResultType) (*RpkiValidationCondition, error) { 1963 if c == oc.RpkiValidationResultType("") || c == oc.RPKI_VALIDATION_RESULT_TYPE_NONE { 1964 return nil, nil 1965 } 1966 return &RpkiValidationCondition{ 1967 result: c, 1968 }, nil 1969 } 1970 1971 type RouteTypeCondition struct { 1972 typ oc.RouteType 1973 } 1974 1975 func (c *RouteTypeCondition) Type() ConditionType { 1976 return CONDITION_ROUTE_TYPE 1977 } 1978 1979 func (c *RouteTypeCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 1980 switch c.typ { 1981 case oc.ROUTE_TYPE_LOCAL: 1982 return path.IsLocal() 1983 case oc.ROUTE_TYPE_INTERNAL: 1984 return !path.IsLocal() && path.IsIBGP() 1985 case oc.ROUTE_TYPE_EXTERNAL: 1986 return !path.IsLocal() && !path.IsIBGP() 1987 } 1988 return false 1989 } 1990 1991 func (c *RouteTypeCondition) Set() DefinedSet { 1992 return nil 1993 } 1994 1995 func (c *RouteTypeCondition) Name() string { return "" } 1996 1997 func (c *RouteTypeCondition) String() string { 1998 return string(c.typ) 1999 } 2000 2001 func NewRouteTypeCondition(c oc.RouteType) (*RouteTypeCondition, error) { 2002 if string(c) == "" || c == oc.ROUTE_TYPE_NONE { 2003 return nil, nil 2004 } 2005 if err := c.Validate(); err != nil { 2006 return nil, err 2007 } 2008 return &RouteTypeCondition{ 2009 typ: c, 2010 }, nil 2011 } 2012 2013 type OriginCondition struct { 2014 origin oc.BgpOriginAttrType 2015 } 2016 2017 func (c *OriginCondition) Type() ConditionType { 2018 return CONDITION_ORIGIN 2019 } 2020 2021 func (c *OriginCondition) Set() DefinedSet { 2022 return nil 2023 } 2024 2025 // compare if origin matches the one in the condition. 2026 func (c *OriginCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 2027 originInt, err := path.GetOrigin() 2028 if err != nil { 2029 return false 2030 } 2031 return int(originInt) == c.origin.ToInt() 2032 } 2033 2034 func (c *OriginCondition) Name() string { return "" } 2035 2036 func NewOriginCondition(origin oc.BgpOriginAttrType) (*OriginCondition, error) { 2037 if origin.ToInt() == -1 { 2038 return nil, nil 2039 } 2040 return &OriginCondition{ 2041 origin: origin, 2042 }, nil 2043 } 2044 2045 type AfiSafiInCondition struct { 2046 routeFamilies []bgp.RouteFamily 2047 } 2048 2049 func (c *AfiSafiInCondition) Type() ConditionType { 2050 return CONDITION_AFI_SAFI_IN 2051 } 2052 2053 func (c *AfiSafiInCondition) Evaluate(path *Path, _ *PolicyOptions) bool { 2054 for _, rf := range c.routeFamilies { 2055 if path.GetRouteFamily() == rf { 2056 return true 2057 } 2058 } 2059 return false 2060 } 2061 2062 func (c *AfiSafiInCondition) Set() DefinedSet { 2063 return nil 2064 } 2065 2066 func (c *AfiSafiInCondition) Name() string { return "" } 2067 2068 func (c *AfiSafiInCondition) String() string { 2069 tmp := make([]string, 0, len(c.routeFamilies)) 2070 for _, afiSafi := range c.routeFamilies { 2071 tmp = append(tmp, afiSafi.String()) 2072 } 2073 return strings.Join(tmp, " ") 2074 } 2075 2076 func NewAfiSafiInCondition(afiSafInConfig []oc.AfiSafiType) (*AfiSafiInCondition, error) { 2077 if afiSafInConfig == nil { 2078 return nil, nil 2079 } 2080 2081 routeFamilies := make([]bgp.RouteFamily, 0, len(afiSafInConfig)) 2082 for _, afiSafiValue := range afiSafInConfig { 2083 if err := afiSafiValue.Validate(); err != nil { 2084 return nil, err 2085 } 2086 rf, err := bgp.GetRouteFamily(string(afiSafiValue)) 2087 if err != nil { 2088 return nil, err 2089 } 2090 routeFamilies = append(routeFamilies, rf) 2091 } 2092 return &AfiSafiInCondition{ 2093 routeFamilies: routeFamilies, 2094 }, nil 2095 } 2096 2097 type Action interface { 2098 Type() ActionType 2099 Apply(*Path, *PolicyOptions) (*Path, error) 2100 String() string 2101 } 2102 2103 type RoutingAction struct { 2104 AcceptRoute bool 2105 } 2106 2107 func (a *RoutingAction) Type() ActionType { 2108 return ACTION_ROUTING 2109 } 2110 2111 func (a *RoutingAction) Apply(path *Path, _ *PolicyOptions) (*Path, error) { 2112 if a.AcceptRoute { 2113 return path, nil 2114 } 2115 return nil, nil 2116 } 2117 2118 func (a *RoutingAction) String() string { 2119 action := "reject" 2120 if a.AcceptRoute { 2121 action = "accept" 2122 } 2123 return action 2124 } 2125 2126 func NewRoutingAction(c oc.RouteDisposition) (*RoutingAction, error) { 2127 var accept bool 2128 switch c { 2129 case oc.RouteDisposition(""), oc.ROUTE_DISPOSITION_NONE: 2130 return nil, nil 2131 case oc.ROUTE_DISPOSITION_ACCEPT_ROUTE: 2132 accept = true 2133 case oc.ROUTE_DISPOSITION_REJECT_ROUTE: 2134 accept = false 2135 default: 2136 return nil, fmt.Errorf("invalid route disposition") 2137 } 2138 return &RoutingAction{ 2139 AcceptRoute: accept, 2140 }, nil 2141 } 2142 2143 type CommunityAction struct { 2144 action oc.BgpSetCommunityOptionType 2145 list []uint32 2146 removeList []*regexp.Regexp 2147 } 2148 2149 func RegexpRemoveCommunities(path *Path, exps []*regexp.Regexp) { 2150 comms := path.GetCommunities() 2151 newComms := make([]uint32, 0, len(comms)) 2152 for _, comm := range comms { 2153 c := fmt.Sprintf("%d:%d", comm>>16, comm&0x0000ffff) 2154 match := false 2155 for _, exp := range exps { 2156 if exp.MatchString(c) { 2157 match = true 2158 break 2159 } 2160 } 2161 if !match { 2162 newComms = append(newComms, comm) 2163 } 2164 } 2165 path.SetCommunities(newComms, true) 2166 } 2167 2168 func RegexpRemoveExtCommunities(path *Path, exps []*regexp.Regexp, subtypes []bgp.ExtendedCommunityAttrSubType) { 2169 comms := path.GetExtCommunities() 2170 newComms := make([]bgp.ExtendedCommunityInterface, 0, len(comms)) 2171 for _, comm := range comms { 2172 match := false 2173 typ, subtype := comm.GetTypes() 2174 // match only with transitive community. see RFC7153 2175 if typ >= 0x3f { 2176 continue 2177 } 2178 for idx, exp := range exps { 2179 if subtype == subtypes[idx] && exp.MatchString(comm.String()) { 2180 match = true 2181 break 2182 } 2183 } 2184 if !match { 2185 newComms = append(newComms, comm) 2186 } 2187 } 2188 path.SetExtCommunities(newComms, true) 2189 } 2190 2191 func RegexpRemoveLargeCommunities(path *Path, exps []*regexp.Regexp) { 2192 comms := path.GetLargeCommunities() 2193 newComms := make([]*bgp.LargeCommunity, 0, len(comms)) 2194 for _, comm := range comms { 2195 c := comm.String() 2196 match := false 2197 for _, exp := range exps { 2198 if exp.MatchString(c) { 2199 match = true 2200 break 2201 } 2202 } 2203 if !match { 2204 newComms = append(newComms, comm) 2205 } 2206 } 2207 path.SetLargeCommunities(newComms, true) 2208 } 2209 2210 func (a *CommunityAction) Type() ActionType { 2211 return ACTION_COMMUNITY 2212 } 2213 2214 func (a *CommunityAction) Apply(path *Path, _ *PolicyOptions) (*Path, error) { 2215 switch a.action { 2216 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_ADD: 2217 path.SetCommunities(a.list, false) 2218 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE: 2219 RegexpRemoveCommunities(path, a.removeList) 2220 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE: 2221 path.SetCommunities(a.list, true) 2222 } 2223 return path, nil 2224 } 2225 2226 func (a *CommunityAction) ToConfig() *oc.SetCommunity { 2227 cs := make([]string, 0, len(a.list)+len(a.removeList)) 2228 for _, comm := range a.list { 2229 c := fmt.Sprintf("%d:%d", comm>>16, comm&0x0000ffff) 2230 cs = append(cs, c) 2231 } 2232 for _, exp := range a.removeList { 2233 cs = append(cs, exp.String()) 2234 } 2235 return &oc.SetCommunity{ 2236 Options: string(a.action), 2237 SetCommunityMethod: oc.SetCommunityMethod{CommunitiesList: cs}, 2238 } 2239 } 2240 2241 func (a *CommunityAction) MarshalJSON() ([]byte, error) { 2242 return json.Marshal(a.ToConfig()) 2243 } 2244 2245 // TODO: this is not efficient use of regexp, probably slow 2246 var _regexpCommunityReplaceString = regexp.MustCompile(`[\^\$]`) 2247 2248 func (a *CommunityAction) String() string { 2249 list := a.ToConfig().SetCommunityMethod.CommunitiesList 2250 l := _regexpCommunityReplaceString.ReplaceAllString(strings.Join(list, ", "), "") 2251 return fmt.Sprintf("%s[%s]", a.action, l) 2252 } 2253 2254 func NewCommunityAction(c oc.SetCommunity) (*CommunityAction, error) { 2255 a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)] 2256 if !ok { 2257 if len(c.SetCommunityMethod.CommunitiesList) == 0 { 2258 return nil, nil 2259 } 2260 return nil, fmt.Errorf("invalid option name: %s", c.Options) 2261 } 2262 var list []uint32 2263 var removeList []*regexp.Regexp 2264 if a == oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { 2265 removeList = make([]*regexp.Regexp, 0, len(c.SetCommunityMethod.CommunitiesList)) 2266 } else { 2267 list = make([]uint32, 0, len(c.SetCommunityMethod.CommunitiesList)) 2268 } 2269 for _, x := range c.SetCommunityMethod.CommunitiesList { 2270 if a == oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { 2271 exp, err := ParseCommunityRegexp(x) 2272 if err != nil { 2273 return nil, err 2274 } 2275 removeList = append(removeList, exp) 2276 } else { 2277 comm, err := ParseCommunity(x) 2278 if err != nil { 2279 return nil, err 2280 } 2281 list = append(list, comm) 2282 } 2283 } 2284 return &CommunityAction{ 2285 action: a, 2286 list: list, 2287 removeList: removeList, 2288 }, nil 2289 } 2290 2291 type ExtCommunityAction struct { 2292 action oc.BgpSetCommunityOptionType 2293 list []bgp.ExtendedCommunityInterface 2294 removeList []*regexp.Regexp 2295 subtypeList []bgp.ExtendedCommunityAttrSubType 2296 } 2297 2298 func (a *ExtCommunityAction) Type() ActionType { 2299 return ACTION_EXT_COMMUNITY 2300 } 2301 2302 func (a *ExtCommunityAction) Apply(path *Path, _ *PolicyOptions) (*Path, error) { 2303 switch a.action { 2304 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_ADD: 2305 path.SetExtCommunities(a.list, false) 2306 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE: 2307 RegexpRemoveExtCommunities(path, a.removeList, a.subtypeList) 2308 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE: 2309 path.SetExtCommunities(a.list, true) 2310 } 2311 return path, nil 2312 } 2313 2314 func (a *ExtCommunityAction) ToConfig() *oc.SetExtCommunity { 2315 cs := make([]string, 0, len(a.list)+len(a.removeList)) 2316 f := func(idx int, arg string) string { 2317 switch a.subtypeList[idx] { 2318 case bgp.EC_SUBTYPE_ROUTE_TARGET: 2319 return fmt.Sprintf("rt:%s", arg) 2320 case bgp.EC_SUBTYPE_ROUTE_ORIGIN: 2321 return fmt.Sprintf("soo:%s", arg) 2322 case bgp.EC_SUBTYPE_ENCAPSULATION: 2323 return fmt.Sprintf("encap:%s", arg) 2324 case bgp.EC_SUBTYPE_LINK_BANDWIDTH: 2325 return fmt.Sprintf("lb:%s", arg) 2326 case bgp.EC_SUBTYPE_ORIGIN_VALIDATION: 2327 return arg 2328 default: 2329 return fmt.Sprintf("%d:%s", a.subtypeList[idx], arg) 2330 } 2331 } 2332 for idx, c := range a.list { 2333 cs = append(cs, f(idx, c.String())) 2334 } 2335 for idx, exp := range a.removeList { 2336 cs = append(cs, f(idx, exp.String())) 2337 } 2338 return &oc.SetExtCommunity{ 2339 Options: string(a.action), 2340 SetExtCommunityMethod: oc.SetExtCommunityMethod{ 2341 CommunitiesList: cs, 2342 }, 2343 } 2344 } 2345 2346 func (a *ExtCommunityAction) String() string { 2347 list := a.ToConfig().SetExtCommunityMethod.CommunitiesList 2348 l := _regexpCommunityReplaceString.ReplaceAllString(strings.Join(list, ", "), "") 2349 return fmt.Sprintf("%s[%s]", a.action, l) 2350 } 2351 2352 func (a *ExtCommunityAction) MarshalJSON() ([]byte, error) { 2353 return json.Marshal(a.ToConfig()) 2354 } 2355 2356 func NewExtCommunityAction(c oc.SetExtCommunity) (*ExtCommunityAction, error) { 2357 a, ok := CommunityOptionValueMap[strings.ToLower(c.Options)] 2358 if !ok { 2359 if len(c.SetExtCommunityMethod.CommunitiesList) == 0 { 2360 return nil, nil 2361 } 2362 return nil, fmt.Errorf("invalid option name: %s", c.Options) 2363 } 2364 var list []bgp.ExtendedCommunityInterface 2365 var removeList []*regexp.Regexp 2366 subtypeList := make([]bgp.ExtendedCommunityAttrSubType, 0, len(c.SetExtCommunityMethod.CommunitiesList)) 2367 if a == oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { 2368 removeList = make([]*regexp.Regexp, 0, len(c.SetExtCommunityMethod.CommunitiesList)) 2369 } else { 2370 list = make([]bgp.ExtendedCommunityInterface, 0, len(c.SetExtCommunityMethod.CommunitiesList)) 2371 } 2372 for _, x := range c.SetExtCommunityMethod.CommunitiesList { 2373 if a == oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { 2374 subtype, exp, err := ParseExtCommunityRegexp(x) 2375 if err != nil { 2376 return nil, err 2377 } 2378 removeList = append(removeList, exp) 2379 subtypeList = append(subtypeList, subtype) 2380 } else { 2381 comm, err := ParseExtCommunity(x) 2382 if err != nil { 2383 return nil, err 2384 } 2385 list = append(list, comm) 2386 _, subtype := comm.GetTypes() 2387 subtypeList = append(subtypeList, subtype) 2388 } 2389 } 2390 return &ExtCommunityAction{ 2391 action: a, 2392 list: list, 2393 removeList: removeList, 2394 subtypeList: subtypeList, 2395 }, nil 2396 } 2397 2398 type LargeCommunityAction struct { 2399 action oc.BgpSetCommunityOptionType 2400 list []*bgp.LargeCommunity 2401 removeList []*regexp.Regexp 2402 } 2403 2404 func (a *LargeCommunityAction) Type() ActionType { 2405 return ACTION_LARGE_COMMUNITY 2406 } 2407 2408 func (a *LargeCommunityAction) Apply(path *Path, _ *PolicyOptions) (*Path, error) { 2409 switch a.action { 2410 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_ADD: 2411 path.SetLargeCommunities(a.list, false) 2412 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE: 2413 RegexpRemoveLargeCommunities(path, a.removeList) 2414 case oc.BGP_SET_COMMUNITY_OPTION_TYPE_REPLACE: 2415 path.SetLargeCommunities(a.list, true) 2416 } 2417 return path, nil 2418 } 2419 2420 func (a *LargeCommunityAction) ToConfig() *oc.SetLargeCommunity { 2421 cs := make([]string, 0, len(a.list)+len(a.removeList)) 2422 for _, comm := range a.list { 2423 cs = append(cs, comm.String()) 2424 } 2425 for _, exp := range a.removeList { 2426 cs = append(cs, exp.String()) 2427 } 2428 return &oc.SetLargeCommunity{ 2429 SetLargeCommunityMethod: oc.SetLargeCommunityMethod{CommunitiesList: cs}, 2430 Options: oc.BgpSetCommunityOptionType(a.action), 2431 } 2432 } 2433 2434 func (a *LargeCommunityAction) String() string { 2435 list := a.ToConfig().SetLargeCommunityMethod.CommunitiesList 2436 l := _regexpCommunityReplaceString.ReplaceAllString(strings.Join(list, ", "), "") 2437 return fmt.Sprintf("%s[%s]", a.action, l) 2438 } 2439 2440 func (a *LargeCommunityAction) MarshalJSON() ([]byte, error) { 2441 return json.Marshal(a.ToConfig()) 2442 } 2443 2444 func NewLargeCommunityAction(c oc.SetLargeCommunity) (*LargeCommunityAction, error) { 2445 a, ok := CommunityOptionValueMap[strings.ToLower(string(c.Options))] 2446 if !ok { 2447 if len(c.SetLargeCommunityMethod.CommunitiesList) == 0 { 2448 return nil, nil 2449 } 2450 return nil, fmt.Errorf("invalid option name: %s", c.Options) 2451 } 2452 var list []*bgp.LargeCommunity 2453 var removeList []*regexp.Regexp 2454 if a == oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { 2455 removeList = make([]*regexp.Regexp, 0, len(c.SetLargeCommunityMethod.CommunitiesList)) 2456 } else { 2457 list = make([]*bgp.LargeCommunity, 0, len(c.SetLargeCommunityMethod.CommunitiesList)) 2458 } 2459 for _, x := range c.SetLargeCommunityMethod.CommunitiesList { 2460 if a == oc.BGP_SET_COMMUNITY_OPTION_TYPE_REMOVE { 2461 exp, err := ParseLargeCommunityRegexp(x) 2462 if err != nil { 2463 return nil, err 2464 } 2465 removeList = append(removeList, exp) 2466 } else { 2467 comm, err := bgp.ParseLargeCommunity(x) 2468 if err != nil { 2469 return nil, err 2470 } 2471 list = append(list, comm) 2472 } 2473 } 2474 return &LargeCommunityAction{ 2475 action: a, 2476 list: list, 2477 removeList: removeList, 2478 }, nil 2479 2480 } 2481 2482 type MedAction struct { 2483 value int64 2484 action MedActionType 2485 } 2486 2487 func (a *MedAction) Type() ActionType { 2488 return ACTION_MED 2489 } 2490 2491 func (a *MedAction) Apply(path *Path, _ *PolicyOptions) (*Path, error) { 2492 var err error 2493 switch a.action { 2494 case MED_ACTION_MOD: 2495 err = path.SetMed(a.value, false) 2496 case MED_ACTION_REPLACE: 2497 err = path.SetMed(a.value, true) 2498 } 2499 if err != nil { 2500 return path, err 2501 } 2502 return path, nil 2503 } 2504 2505 func (a *MedAction) ToConfig() oc.BgpSetMedType { 2506 if a.action == MED_ACTION_MOD && a.value > 0 { 2507 return oc.BgpSetMedType(fmt.Sprintf("+%d", a.value)) 2508 } 2509 return oc.BgpSetMedType(fmt.Sprintf("%d", a.value)) 2510 } 2511 2512 func (a *MedAction) String() string { 2513 return string(a.ToConfig()) 2514 } 2515 2516 func (a *MedAction) MarshalJSON() ([]byte, error) { 2517 return json.Marshal(a.ToConfig()) 2518 } 2519 2520 var _regexpParseMedAction = regexp.MustCompile(`^(\+|\-)?(\d+)$`) 2521 2522 func NewMedAction(c oc.BgpSetMedType) (*MedAction, error) { 2523 if string(c) == "" { 2524 return nil, nil 2525 } 2526 2527 elems := _regexpParseMedAction.FindStringSubmatch(string(c)) 2528 if len(elems) != 3 { 2529 return nil, fmt.Errorf("invalid med action format") 2530 } 2531 action := MED_ACTION_REPLACE 2532 switch elems[1] { 2533 case "+", "-": 2534 action = MED_ACTION_MOD 2535 } 2536 value, _ := strconv.ParseInt(string(c), 10, 64) 2537 return &MedAction{ 2538 value: value, 2539 action: action, 2540 }, nil 2541 } 2542 2543 func NewMedActionFromApiStruct(action MedActionType, value int64) *MedAction { 2544 return &MedAction{action: action, value: value} 2545 } 2546 2547 type LocalPrefAction struct { 2548 value uint32 2549 } 2550 2551 func (a *LocalPrefAction) Type() ActionType { 2552 return ACTION_LOCAL_PREF 2553 } 2554 2555 func (a *LocalPrefAction) Apply(path *Path, _ *PolicyOptions) (*Path, error) { 2556 path.setPathAttr(bgp.NewPathAttributeLocalPref(a.value)) 2557 return path, nil 2558 } 2559 2560 func (a *LocalPrefAction) ToConfig() uint32 { 2561 return a.value 2562 } 2563 2564 func (a *LocalPrefAction) String() string { 2565 return fmt.Sprintf("%d", a.value) 2566 } 2567 2568 func (a *LocalPrefAction) MarshalJSON() ([]byte, error) { 2569 return json.Marshal(a.ToConfig()) 2570 } 2571 2572 func NewLocalPrefAction(value uint32) (*LocalPrefAction, error) { 2573 if value == 0 { 2574 return nil, nil 2575 } 2576 return &LocalPrefAction{ 2577 value: value, 2578 }, nil 2579 } 2580 2581 type OriginAction struct { 2582 value oc.BgpOriginAttrType 2583 } 2584 2585 func (a *OriginAction) Type() ActionType { 2586 return ACTION_ORIGIN 2587 } 2588 2589 func (a *OriginAction) Apply(path *Path, _ *PolicyOptions) (*Path, error) { 2590 originInt := a.value.ToInt() 2591 if originInt == -1 { 2592 return nil, fmt.Errorf("internal error: got invalid value for origin action") 2593 } 2594 path.setPathAttr(bgp.NewPathAttributeOrigin(uint8(originInt))) 2595 return path, nil 2596 } 2597 2598 func (a *OriginAction) ToConfig() oc.BgpOriginAttrType { 2599 return a.value 2600 } 2601 2602 func (a *OriginAction) String() string { 2603 return fmt.Sprintf("%q", a.value) 2604 } 2605 2606 func (a *OriginAction) MarshalJSON() ([]byte, error) { 2607 return json.Marshal(a.ToConfig()) 2608 } 2609 2610 func NewOriginAction(value oc.BgpOriginAttrType) (*OriginAction, error) { 2611 if value.ToInt() == -1 { 2612 return nil, nil 2613 } 2614 return &OriginAction{ 2615 value: value, 2616 }, nil 2617 } 2618 2619 type AsPathPrependAction struct { 2620 asn uint32 2621 useLeftMost bool 2622 repeat uint8 2623 } 2624 2625 func (a *AsPathPrependAction) Type() ActionType { 2626 return ACTION_AS_PATH_PREPEND 2627 } 2628 2629 func (a *AsPathPrependAction) Apply(path *Path, option *PolicyOptions) (*Path, error) { 2630 var asn uint32 2631 if a.useLeftMost { 2632 aspath := path.GetAsSeqList() 2633 if len(aspath) == 0 { 2634 return path, nil 2635 } 2636 asn = aspath[0] 2637 if asn == 0 { 2638 return path, nil 2639 } 2640 } else { 2641 asn = a.asn 2642 } 2643 2644 confed := option != nil && option.Info != nil && option.Info.Confederation 2645 path.PrependAsn(asn, a.repeat, confed) 2646 2647 return path, nil 2648 } 2649 2650 func (a *AsPathPrependAction) ToConfig() *oc.SetAsPathPrepend { 2651 return &oc.SetAsPathPrepend{ 2652 RepeatN: uint8(a.repeat), 2653 As: func() string { 2654 if a.useLeftMost { 2655 return "last-as" 2656 } 2657 return fmt.Sprintf("%d", a.asn) 2658 }(), 2659 } 2660 } 2661 2662 func (a *AsPathPrependAction) String() string { 2663 c := a.ToConfig() 2664 return fmt.Sprintf("prepend %s %d times", c.As, c.RepeatN) 2665 } 2666 2667 func (a *AsPathPrependAction) MarshalJSON() ([]byte, error) { 2668 return json.Marshal(a.ToConfig()) 2669 } 2670 2671 // NewAsPathPrependAction creates AsPathPrependAction object. 2672 // If ASN cannot be parsed, nil will be returned. 2673 func NewAsPathPrependAction(action oc.SetAsPathPrepend) (*AsPathPrependAction, error) { 2674 a := &AsPathPrependAction{ 2675 repeat: action.RepeatN, 2676 } 2677 switch action.As { 2678 case "": 2679 if a.repeat == 0 { 2680 return nil, nil 2681 } 2682 return nil, fmt.Errorf("specify as to prepend") 2683 case "last-as": 2684 a.useLeftMost = true 2685 default: 2686 asn, err := strconv.ParseUint(action.As, 10, 32) 2687 if err != nil { 2688 return nil, fmt.Errorf("AS number string invalid") 2689 } 2690 a.asn = uint32(asn) 2691 } 2692 return a, nil 2693 } 2694 2695 type NexthopAction struct { 2696 value net.IP 2697 self bool 2698 peerAddress bool 2699 unchanged bool 2700 } 2701 2702 func (a *NexthopAction) Type() ActionType { 2703 return ACTION_NEXTHOP 2704 } 2705 2706 func (a *NexthopAction) Apply(path *Path, options *PolicyOptions) (*Path, error) { 2707 switch { 2708 case a.self: 2709 if options != nil && options.Info != nil && options.Info.LocalAddress != nil { 2710 path.SetNexthop(options.Info.LocalAddress) 2711 } 2712 return path, nil 2713 case a.peerAddress: 2714 if options != nil && options.Info != nil && options.Info.Address != nil { 2715 path.SetNexthop(options.Info.Address) 2716 } 2717 return path, nil 2718 case a.unchanged: 2719 if options != nil && options.OldNextHop != nil { 2720 path.SetNexthop(options.OldNextHop) 2721 } 2722 return path, nil 2723 } 2724 path.SetNexthop(a.value) 2725 return path, nil 2726 } 2727 2728 func (a *NexthopAction) ToConfig() oc.BgpNextHopType { 2729 switch { 2730 case a.self: 2731 return oc.BgpNextHopType("self") 2732 case a.peerAddress: 2733 return oc.BgpNextHopType("peer-address") 2734 case a.unchanged: 2735 return oc.BgpNextHopType("unchanged") 2736 } 2737 return oc.BgpNextHopType(a.value.String()) 2738 } 2739 2740 func (a *NexthopAction) String() string { 2741 return string(a.ToConfig()) 2742 } 2743 2744 func (a *NexthopAction) MarshalJSON() ([]byte, error) { 2745 return json.Marshal(a.ToConfig()) 2746 } 2747 2748 func NewNexthopAction(c oc.BgpNextHopType) (*NexthopAction, error) { 2749 switch strings.ToLower(string(c)) { 2750 case "": 2751 return nil, nil 2752 case "self": 2753 return &NexthopAction{ 2754 self: true, 2755 }, nil 2756 case "peer-address": 2757 return &NexthopAction{ 2758 peerAddress: true, 2759 }, nil 2760 case "unchanged": 2761 return &NexthopAction{ 2762 unchanged: true, 2763 }, nil 2764 } 2765 addr := net.ParseIP(string(c)) 2766 if addr == nil { 2767 return nil, fmt.Errorf("invalid ip address format: %s", string(c)) 2768 } 2769 return &NexthopAction{ 2770 value: addr, 2771 }, nil 2772 } 2773 2774 type Statement struct { 2775 Name string 2776 Conditions []Condition 2777 RouteAction Action 2778 ModActions []Action 2779 } 2780 2781 // evaluate each condition in the statement according to MatchSetOptions 2782 func (s *Statement) Evaluate(p *Path, options *PolicyOptions) bool { 2783 for _, c := range s.Conditions { 2784 if !c.Evaluate(p, options) { 2785 return false 2786 } 2787 } 2788 return true 2789 } 2790 2791 func (s *Statement) Apply(logger log.Logger, path *Path, options *PolicyOptions) (RouteType, *Path) { 2792 result := s.Evaluate(path, options) 2793 if result { 2794 if len(s.ModActions) != 0 { 2795 // apply all modification actions 2796 path = path.Clone(path.IsWithdraw) 2797 for _, action := range s.ModActions { 2798 var err error 2799 path, err = action.Apply(path, options) 2800 if err != nil { 2801 logger.Warn("action failed", 2802 log.Fields{ 2803 "Topic": "policy", 2804 "Error": err}) 2805 } 2806 } 2807 } 2808 //Routing action 2809 if s.RouteAction == nil || reflect.ValueOf(s.RouteAction).IsNil() { 2810 return ROUTE_TYPE_NONE, path 2811 } 2812 p, _ := s.RouteAction.Apply(path, options) 2813 if p == nil { 2814 return ROUTE_TYPE_REJECT, path 2815 } 2816 return ROUTE_TYPE_ACCEPT, path 2817 } 2818 return ROUTE_TYPE_NONE, path 2819 } 2820 2821 func (s *Statement) ToConfig() *oc.Statement { 2822 return &oc.Statement{ 2823 Name: s.Name, 2824 Conditions: func() oc.Conditions { 2825 cond := oc.Conditions{} 2826 for _, c := range s.Conditions { 2827 switch v := c.(type) { 2828 case *PrefixCondition: 2829 cond.MatchPrefixSet = oc.MatchPrefixSet{PrefixSet: v.set.Name(), MatchSetOptions: v.option.ConvertToMatchSetOptionsRestrictedType()} 2830 case *NeighborCondition: 2831 cond.MatchNeighborSet = oc.MatchNeighborSet{NeighborSet: v.set.Name(), MatchSetOptions: v.option.ConvertToMatchSetOptionsRestrictedType()} 2832 case *CommunityCountCondition: 2833 cond.BgpConditions.CommunityCount = oc.CommunityCount{Operator: oc.IntToAttributeComparisonMap[int(v.operator)], Value: v.count} 2834 case *AsPathLengthCondition: 2835 cond.BgpConditions.AsPathLength = oc.AsPathLength{Operator: oc.IntToAttributeComparisonMap[int(v.operator)], Value: v.length} 2836 case *AsPathCondition: 2837 cond.BgpConditions.MatchAsPathSet = oc.MatchAsPathSet{AsPathSet: v.set.Name(), MatchSetOptions: oc.IntToMatchSetOptionsTypeMap[int(v.option)]} 2838 case *CommunityCondition: 2839 cond.BgpConditions.MatchCommunitySet = oc.MatchCommunitySet{CommunitySet: v.set.Name(), MatchSetOptions: oc.IntToMatchSetOptionsTypeMap[int(v.option)]} 2840 case *ExtCommunityCondition: 2841 cond.BgpConditions.MatchExtCommunitySet = oc.MatchExtCommunitySet{ExtCommunitySet: v.set.Name(), MatchSetOptions: oc.IntToMatchSetOptionsTypeMap[int(v.option)]} 2842 case *LargeCommunityCondition: 2843 cond.BgpConditions.MatchLargeCommunitySet = oc.MatchLargeCommunitySet{LargeCommunitySet: v.set.Name(), MatchSetOptions: oc.IntToMatchSetOptionsTypeMap[int(v.option)]} 2844 case *NextHopCondition: 2845 cond.BgpConditions.NextHopInList = v.set.List() 2846 case *RpkiValidationCondition: 2847 cond.BgpConditions.RpkiValidationResult = v.result 2848 case *RouteTypeCondition: 2849 cond.BgpConditions.RouteType = v.typ 2850 case *OriginCondition: 2851 cond.BgpConditions.OriginEq = v.origin 2852 case *AfiSafiInCondition: 2853 res := make([]oc.AfiSafiType, 0, len(v.routeFamilies)) 2854 for _, rf := range v.routeFamilies { 2855 res = append(res, oc.AfiSafiType(rf.String())) 2856 } 2857 cond.BgpConditions.AfiSafiInList = res 2858 } 2859 } 2860 return cond 2861 }(), 2862 Actions: func() oc.Actions { 2863 act := oc.Actions{} 2864 if s.RouteAction != nil && !reflect.ValueOf(s.RouteAction).IsNil() { 2865 a := s.RouteAction.(*RoutingAction) 2866 if a.AcceptRoute { 2867 act.RouteDisposition = oc.ROUTE_DISPOSITION_ACCEPT_ROUTE 2868 } else { 2869 act.RouteDisposition = oc.ROUTE_DISPOSITION_REJECT_ROUTE 2870 } 2871 } else { 2872 act.RouteDisposition = oc.ROUTE_DISPOSITION_NONE 2873 } 2874 for _, a := range s.ModActions { 2875 switch v := a.(type) { 2876 case *AsPathPrependAction: 2877 act.BgpActions.SetAsPathPrepend = *v.ToConfig() 2878 case *CommunityAction: 2879 act.BgpActions.SetCommunity = *v.ToConfig() 2880 case *ExtCommunityAction: 2881 act.BgpActions.SetExtCommunity = *v.ToConfig() 2882 case *LargeCommunityAction: 2883 act.BgpActions.SetLargeCommunity = *v.ToConfig() 2884 case *MedAction: 2885 act.BgpActions.SetMed = v.ToConfig() 2886 case *LocalPrefAction: 2887 act.BgpActions.SetLocalPref = v.ToConfig() 2888 case *NexthopAction: 2889 act.BgpActions.SetNextHop = v.ToConfig() 2890 case *OriginAction: 2891 act.BgpActions.SetRouteOrigin = v.ToConfig() 2892 } 2893 } 2894 return act 2895 }(), 2896 } 2897 } 2898 2899 func (s *Statement) MarshalJSON() ([]byte, error) { 2900 return json.Marshal(s.ToConfig()) 2901 } 2902 2903 type opType int 2904 2905 const ( 2906 ADD opType = iota 2907 REMOVE 2908 REPLACE 2909 ) 2910 2911 func (lhs *Statement) mod(op opType, rhs *Statement) error { 2912 cs := make([]Condition, len(lhs.Conditions)) 2913 copy(cs, lhs.Conditions) 2914 ra := lhs.RouteAction 2915 as := make([]Action, len(lhs.ModActions)) 2916 copy(as, lhs.ModActions) 2917 for _, x := range rhs.Conditions { 2918 var c Condition 2919 i := 0 2920 for idx, y := range lhs.Conditions { 2921 if x.Type() == y.Type() { 2922 c = y 2923 i = idx 2924 break 2925 } 2926 } 2927 switch op { 2928 case ADD: 2929 if c != nil { 2930 return fmt.Errorf("condition %d is already set", x.Type()) 2931 } 2932 if cs == nil { 2933 cs = make([]Condition, 0, len(rhs.Conditions)) 2934 } 2935 cs = append(cs, x) 2936 case REMOVE: 2937 if c == nil { 2938 return fmt.Errorf("condition %d is not set", x.Type()) 2939 } 2940 cs = append(cs[:i], cs[i+1:]...) 2941 if len(cs) == 0 { 2942 cs = nil 2943 } 2944 case REPLACE: 2945 if c == nil { 2946 return fmt.Errorf("condition %d is not set", x.Type()) 2947 } 2948 cs[i] = x 2949 } 2950 } 2951 if rhs.RouteAction != nil && !reflect.ValueOf(rhs.RouteAction).IsNil() { 2952 switch op { 2953 case ADD: 2954 if lhs.RouteAction != nil && !reflect.ValueOf(lhs.RouteAction).IsNil() { 2955 return fmt.Errorf("route action is already set") 2956 } 2957 ra = rhs.RouteAction 2958 case REMOVE: 2959 if lhs.RouteAction == nil || reflect.ValueOf(lhs.RouteAction).IsNil() { 2960 return fmt.Errorf("route action is not set") 2961 } 2962 ra = nil 2963 case REPLACE: 2964 if lhs.RouteAction == nil || reflect.ValueOf(lhs.RouteAction).IsNil() { 2965 return fmt.Errorf("route action is not set") 2966 } 2967 ra = rhs.RouteAction 2968 } 2969 } 2970 for _, x := range rhs.ModActions { 2971 var a Action 2972 i := 0 2973 for idx, y := range lhs.ModActions { 2974 if x.Type() == y.Type() { 2975 a = y 2976 i = idx 2977 break 2978 } 2979 } 2980 switch op { 2981 case ADD: 2982 if a != nil { 2983 return fmt.Errorf("action %d is already set", x.Type()) 2984 } 2985 if as == nil { 2986 as = make([]Action, 0, len(rhs.ModActions)) 2987 } 2988 as = append(as, x) 2989 case REMOVE: 2990 if a == nil { 2991 return fmt.Errorf("action %d is not set", x.Type()) 2992 } 2993 as = append(as[:i], as[i+1:]...) 2994 if len(as) == 0 { 2995 as = nil 2996 } 2997 case REPLACE: 2998 if a == nil { 2999 return fmt.Errorf("action %d is not set", x.Type()) 3000 } 3001 as[i] = x 3002 } 3003 } 3004 lhs.Conditions = cs 3005 lhs.RouteAction = ra 3006 lhs.ModActions = as 3007 return nil 3008 } 3009 3010 func (lhs *Statement) Add(rhs *Statement) error { 3011 return lhs.mod(ADD, rhs) 3012 } 3013 3014 func (lhs *Statement) Remove(rhs *Statement) error { 3015 return lhs.mod(REMOVE, rhs) 3016 } 3017 3018 func (lhs *Statement) Replace(rhs *Statement) error { 3019 return lhs.mod(REPLACE, rhs) 3020 } 3021 3022 func NewStatement(c oc.Statement) (*Statement, error) { 3023 if c.Name == "" { 3024 return nil, fmt.Errorf("empty statement name") 3025 } 3026 var ra Action 3027 var as []Action 3028 var cs []Condition 3029 var err error 3030 cfs := []func() (Condition, error){ 3031 func() (Condition, error) { 3032 return NewPrefixCondition(c.Conditions.MatchPrefixSet) 3033 }, 3034 func() (Condition, error) { 3035 return NewNeighborCondition(c.Conditions.MatchNeighborSet) 3036 }, 3037 func() (Condition, error) { 3038 return NewCommunityCountCondition(c.Conditions.BgpConditions.CommunityCount) 3039 }, 3040 func() (Condition, error) { 3041 return NewAsPathLengthCondition(c.Conditions.BgpConditions.AsPathLength) 3042 }, 3043 func() (Condition, error) { 3044 return NewRpkiValidationCondition(c.Conditions.BgpConditions.RpkiValidationResult) 3045 }, 3046 func() (Condition, error) { 3047 return NewRouteTypeCondition(c.Conditions.BgpConditions.RouteType) 3048 }, 3049 func() (Condition, error) { 3050 return NewOriginCondition(c.Conditions.BgpConditions.OriginEq) 3051 }, 3052 func() (Condition, error) { 3053 return NewAsPathCondition(c.Conditions.BgpConditions.MatchAsPathSet) 3054 }, 3055 func() (Condition, error) { 3056 return NewCommunityCondition(c.Conditions.BgpConditions.MatchCommunitySet) 3057 }, 3058 func() (Condition, error) { 3059 return NewExtCommunityCondition(c.Conditions.BgpConditions.MatchExtCommunitySet) 3060 }, 3061 func() (Condition, error) { 3062 return NewLargeCommunityCondition(c.Conditions.BgpConditions.MatchLargeCommunitySet) 3063 }, 3064 func() (Condition, error) { 3065 return NewNextHopCondition(c.Conditions.BgpConditions.NextHopInList) 3066 }, 3067 func() (Condition, error) { 3068 return NewAfiSafiInCondition(c.Conditions.BgpConditions.AfiSafiInList) 3069 }, 3070 } 3071 cs = make([]Condition, 0, len(cfs)) 3072 for _, f := range cfs { 3073 c, err := f() 3074 if err != nil { 3075 return nil, err 3076 } 3077 if !reflect.ValueOf(c).IsNil() { 3078 cs = append(cs, c) 3079 } 3080 } 3081 ra, err = NewRoutingAction(c.Actions.RouteDisposition) 3082 if err != nil { 3083 return nil, err 3084 } 3085 afs := []func() (Action, error){ 3086 func() (Action, error) { 3087 return NewCommunityAction(c.Actions.BgpActions.SetCommunity) 3088 }, 3089 func() (Action, error) { 3090 return NewExtCommunityAction(c.Actions.BgpActions.SetExtCommunity) 3091 }, 3092 func() (Action, error) { 3093 return NewLargeCommunityAction(c.Actions.BgpActions.SetLargeCommunity) 3094 }, 3095 func() (Action, error) { 3096 return NewMedAction(c.Actions.BgpActions.SetMed) 3097 }, 3098 func() (Action, error) { 3099 return NewLocalPrefAction(c.Actions.BgpActions.SetLocalPref) 3100 }, 3101 func() (Action, error) { 3102 return NewAsPathPrependAction(c.Actions.BgpActions.SetAsPathPrepend) 3103 }, 3104 func() (Action, error) { 3105 return NewNexthopAction(c.Actions.BgpActions.SetNextHop) 3106 }, 3107 func() (Action, error) { 3108 return NewOriginAction(c.Actions.BgpActions.SetRouteOrigin) 3109 }, 3110 } 3111 as = make([]Action, 0, len(afs)) 3112 for _, f := range afs { 3113 a, err := f() 3114 if err != nil { 3115 return nil, err 3116 } 3117 if !reflect.ValueOf(a).IsNil() { 3118 as = append(as, a) 3119 } 3120 } 3121 return &Statement{ 3122 Name: c.Name, 3123 Conditions: cs, 3124 RouteAction: ra, 3125 ModActions: as, 3126 }, nil 3127 } 3128 3129 type Policy struct { 3130 Name string 3131 Statements []*Statement 3132 } 3133 3134 // Compare path with a policy's condition in stored order in the policy. 3135 // If a condition match, then this function stops evaluation and 3136 // subsequent conditions are skipped. 3137 func (p *Policy) Apply(logger log.Logger, path *Path, options *PolicyOptions) (RouteType, *Path) { 3138 for _, stmt := range p.Statements { 3139 var result RouteType 3140 result, path = stmt.Apply(logger, path, options) 3141 if result != ROUTE_TYPE_NONE { 3142 return result, path 3143 } 3144 } 3145 return ROUTE_TYPE_NONE, path 3146 } 3147 3148 func (p *Policy) ToConfig() *oc.PolicyDefinition { 3149 ss := make([]oc.Statement, 0, len(p.Statements)) 3150 for _, s := range p.Statements { 3151 ss = append(ss, *s.ToConfig()) 3152 } 3153 return &oc.PolicyDefinition{ 3154 Name: p.Name, 3155 Statements: ss, 3156 } 3157 } 3158 3159 func (p *Policy) FillUp(m map[string]*Statement) error { 3160 stmts := make([]*Statement, 0, len(p.Statements)) 3161 for _, x := range p.Statements { 3162 y, ok := m[x.Name] 3163 if !ok { 3164 return fmt.Errorf("not found statement %s", x.Name) 3165 } 3166 stmts = append(stmts, y) 3167 } 3168 p.Statements = stmts 3169 return nil 3170 } 3171 3172 func (lhs *Policy) Add(rhs *Policy) error { 3173 lhs.Statements = append(lhs.Statements, rhs.Statements...) 3174 return nil 3175 } 3176 3177 func (lhs *Policy) Remove(rhs *Policy) error { 3178 stmts := make([]*Statement, 0, len(lhs.Statements)) 3179 for _, x := range lhs.Statements { 3180 found := false 3181 for _, y := range rhs.Statements { 3182 if x.Name == y.Name { 3183 found = true 3184 break 3185 } 3186 } 3187 if !found { 3188 stmts = append(stmts, x) 3189 } 3190 } 3191 lhs.Statements = stmts 3192 return nil 3193 } 3194 3195 func (lhs *Policy) Replace(rhs *Policy) error { 3196 lhs.Statements = rhs.Statements 3197 return nil 3198 } 3199 3200 func (p *Policy) MarshalJSON() ([]byte, error) { 3201 return json.Marshal(p.ToConfig()) 3202 } 3203 3204 func NewPolicy(c oc.PolicyDefinition) (*Policy, error) { 3205 if c.Name == "" { 3206 return nil, fmt.Errorf("empty policy name") 3207 } 3208 var st []*Statement 3209 stmts := c.Statements 3210 if len(stmts) != 0 { 3211 st = make([]*Statement, 0, len(stmts)) 3212 for idx, stmt := range stmts { 3213 if stmt.Name == "" { 3214 stmt.Name = fmt.Sprintf("%s_stmt%d", c.Name, idx) 3215 } 3216 s, err := NewStatement(stmt) 3217 if err != nil { 3218 return nil, err 3219 } 3220 st = append(st, s) 3221 } 3222 } 3223 return &Policy{ 3224 Name: c.Name, 3225 Statements: st, 3226 }, nil 3227 } 3228 3229 type Policies []*Policy 3230 3231 func (p Policies) Len() int { 3232 return len(p) 3233 } 3234 3235 func (p Policies) Swap(i, j int) { 3236 p[i], p[j] = p[j], p[i] 3237 } 3238 3239 func (p Policies) Less(i, j int) bool { 3240 return p[i].Name < p[j].Name 3241 } 3242 3243 type Assignment struct { 3244 importPolicies []*Policy 3245 defaultImportPolicy RouteType 3246 exportPolicies []*Policy 3247 defaultExportPolicy RouteType 3248 } 3249 3250 type RoutingPolicy struct { 3251 definedSetMap DefinedSetMap 3252 policyMap map[string]*Policy 3253 statementMap map[string]*Statement 3254 assignmentMap map[string]*Assignment 3255 mu sync.RWMutex 3256 logger log.Logger 3257 } 3258 3259 func (r *RoutingPolicy) ApplyPolicy(id string, dir PolicyDirection, before *Path, options *PolicyOptions) *Path { 3260 if before == nil { 3261 return nil 3262 } 3263 3264 if before.IsWithdraw { 3265 return before 3266 } 3267 result := ROUTE_TYPE_NONE 3268 after := before 3269 3270 r.mu.RLock() 3271 defer r.mu.RUnlock() 3272 3273 for _, p := range r.getPolicy(id, dir) { 3274 result, after = p.Apply(r.logger, after, options) 3275 if result != ROUTE_TYPE_NONE { 3276 break 3277 } 3278 } 3279 if result == ROUTE_TYPE_NONE { 3280 result = r.getDefaultPolicy(id, dir) 3281 } 3282 switch result { 3283 case ROUTE_TYPE_ACCEPT: 3284 return after 3285 default: 3286 return nil 3287 } 3288 } 3289 3290 func (r *RoutingPolicy) getPolicy(id string, dir PolicyDirection) []*Policy { 3291 a, ok := r.assignmentMap[id] 3292 if !ok { 3293 return nil 3294 } 3295 switch dir { 3296 case POLICY_DIRECTION_IMPORT: 3297 return a.importPolicies 3298 case POLICY_DIRECTION_EXPORT: 3299 return a.exportPolicies 3300 default: 3301 return nil 3302 } 3303 } 3304 3305 func (r *RoutingPolicy) getDefaultPolicy(id string, dir PolicyDirection) RouteType { 3306 a, ok := r.assignmentMap[id] 3307 if !ok { 3308 return ROUTE_TYPE_NONE 3309 } 3310 switch dir { 3311 case POLICY_DIRECTION_IMPORT: 3312 return a.defaultImportPolicy 3313 case POLICY_DIRECTION_EXPORT: 3314 return a.defaultExportPolicy 3315 default: 3316 return ROUTE_TYPE_NONE 3317 } 3318 3319 } 3320 3321 func (r *RoutingPolicy) setPolicy(id string, dir PolicyDirection, policies []*Policy) error { 3322 a, ok := r.assignmentMap[id] 3323 if !ok { 3324 a = &Assignment{} 3325 } 3326 switch dir { 3327 case POLICY_DIRECTION_IMPORT: 3328 a.importPolicies = policies 3329 case POLICY_DIRECTION_EXPORT: 3330 a.exportPolicies = policies 3331 } 3332 r.assignmentMap[id] = a 3333 return nil 3334 } 3335 3336 func (r *RoutingPolicy) setDefaultPolicy(id string, dir PolicyDirection, typ RouteType) error { 3337 a, ok := r.assignmentMap[id] 3338 if !ok { 3339 a = &Assignment{} 3340 } 3341 switch dir { 3342 case POLICY_DIRECTION_IMPORT: 3343 a.defaultImportPolicy = typ 3344 case POLICY_DIRECTION_EXPORT: 3345 a.defaultExportPolicy = typ 3346 } 3347 r.assignmentMap[id] = a 3348 return nil 3349 } 3350 3351 func (r *RoutingPolicy) getAssignmentFromConfig(dir PolicyDirection, a oc.ApplyPolicy) ([]*Policy, RouteType, error) { 3352 var names []string 3353 var cdef oc.DefaultPolicyType 3354 def := ROUTE_TYPE_ACCEPT 3355 c := a.Config 3356 switch dir { 3357 case POLICY_DIRECTION_IMPORT: 3358 names = c.ImportPolicyList 3359 cdef = c.DefaultImportPolicy 3360 case POLICY_DIRECTION_EXPORT: 3361 names = c.ExportPolicyList 3362 cdef = c.DefaultExportPolicy 3363 default: 3364 return nil, def, fmt.Errorf("invalid policy direction") 3365 } 3366 if cdef == oc.DEFAULT_POLICY_TYPE_REJECT_ROUTE { 3367 def = ROUTE_TYPE_REJECT 3368 } 3369 ps := make([]*Policy, 0, len(names)) 3370 seen := make(map[string]bool) 3371 for _, name := range names { 3372 p, ok := r.policyMap[name] 3373 if !ok { 3374 return nil, def, fmt.Errorf("not found policy %s", name) 3375 } 3376 if seen[name] { 3377 return nil, def, fmt.Errorf("duplicated policy %s", name) 3378 } 3379 seen[name] = true 3380 ps = append(ps, p) 3381 } 3382 return ps, def, nil 3383 } 3384 3385 func (r *RoutingPolicy) validateCondition(v Condition) (err error) { 3386 switch v.Type() { 3387 case CONDITION_PREFIX: 3388 m := r.definedSetMap[DEFINED_TYPE_PREFIX] 3389 if i, ok := m[v.Name()]; !ok { 3390 return fmt.Errorf("not found prefix set %s", v.Name()) 3391 } else { 3392 c := v.(*PrefixCondition) 3393 c.set = i.(*PrefixSet) 3394 } 3395 case CONDITION_NEIGHBOR: 3396 m := r.definedSetMap[DEFINED_TYPE_NEIGHBOR] 3397 if i, ok := m[v.Name()]; !ok { 3398 return fmt.Errorf("not found neighbor set %s", v.Name()) 3399 } else { 3400 c := v.(*NeighborCondition) 3401 c.set = i.(*NeighborSet) 3402 } 3403 case CONDITION_AS_PATH: 3404 m := r.definedSetMap[DEFINED_TYPE_AS_PATH] 3405 if i, ok := m[v.Name()]; !ok { 3406 return fmt.Errorf("not found as path set %s", v.Name()) 3407 } else { 3408 c := v.(*AsPathCondition) 3409 c.set = i.(*AsPathSet) 3410 } 3411 case CONDITION_COMMUNITY: 3412 m := r.definedSetMap[DEFINED_TYPE_COMMUNITY] 3413 if i, ok := m[v.Name()]; !ok { 3414 return fmt.Errorf("not found community set %s", v.Name()) 3415 } else { 3416 c := v.(*CommunityCondition) 3417 c.set = i.(*CommunitySet) 3418 } 3419 case CONDITION_EXT_COMMUNITY: 3420 m := r.definedSetMap[DEFINED_TYPE_EXT_COMMUNITY] 3421 if i, ok := m[v.Name()]; !ok { 3422 return fmt.Errorf("not found ext-community set %s", v.Name()) 3423 } else { 3424 c := v.(*ExtCommunityCondition) 3425 c.set = i.(*ExtCommunitySet) 3426 } 3427 case CONDITION_LARGE_COMMUNITY: 3428 m := r.definedSetMap[DEFINED_TYPE_LARGE_COMMUNITY] 3429 if i, ok := m[v.Name()]; !ok { 3430 return fmt.Errorf("not found large-community set %s", v.Name()) 3431 } else { 3432 c := v.(*LargeCommunityCondition) 3433 c.set = i.(*LargeCommunitySet) 3434 } 3435 case CONDITION_NEXT_HOP: 3436 case CONDITION_AFI_SAFI_IN: 3437 case CONDITION_AS_PATH_LENGTH: 3438 case CONDITION_RPKI: 3439 } 3440 return nil 3441 } 3442 3443 func (r *RoutingPolicy) inUse(d DefinedSet) bool { 3444 name := d.Name() 3445 for _, p := range r.policyMap { 3446 for _, s := range p.Statements { 3447 for _, c := range s.Conditions { 3448 if c.Set() != nil && c.Set().Name() == name { 3449 return true 3450 } 3451 } 3452 } 3453 } 3454 return false 3455 } 3456 3457 func (r *RoutingPolicy) statementInUse(x *Statement) bool { 3458 for _, p := range r.policyMap { 3459 for _, y := range p.Statements { 3460 if x.Name == y.Name { 3461 return true 3462 } 3463 } 3464 } 3465 return false 3466 } 3467 3468 func (r *RoutingPolicy) reload(c oc.RoutingPolicy) error { 3469 dmap := make(map[DefinedType]map[string]DefinedSet) 3470 dmap[DEFINED_TYPE_PREFIX] = make(map[string]DefinedSet) 3471 d := c.DefinedSets 3472 for _, x := range d.PrefixSets { 3473 y, err := NewPrefixSet(x) 3474 if err != nil { 3475 return err 3476 } 3477 if y == nil { 3478 return fmt.Errorf("empty prefix set") 3479 } 3480 dmap[DEFINED_TYPE_PREFIX][y.Name()] = y 3481 } 3482 dmap[DEFINED_TYPE_NEIGHBOR] = make(map[string]DefinedSet) 3483 for _, x := range d.NeighborSets { 3484 y, err := NewNeighborSet(x) 3485 if err != nil { 3486 return err 3487 } 3488 if y == nil { 3489 return fmt.Errorf("empty neighbor set") 3490 } 3491 dmap[DEFINED_TYPE_NEIGHBOR][y.Name()] = y 3492 } 3493 // dmap[DEFINED_TYPE_TAG] = make(map[string]DefinedSet) 3494 // for _, x := range c.DefinedSets.TagSets{ 3495 // y, err := NewTagSet(x) 3496 // if err != nil { 3497 // return nil, err 3498 // } 3499 // dmap[DEFINED_TYPE_TAG][y.Name()] = y 3500 // } 3501 bd := c.DefinedSets.BgpDefinedSets 3502 dmap[DEFINED_TYPE_AS_PATH] = make(map[string]DefinedSet) 3503 for _, x := range bd.AsPathSets { 3504 y, err := NewAsPathSet(x) 3505 if err != nil { 3506 return err 3507 } 3508 if y == nil { 3509 return fmt.Errorf("empty as path set") 3510 } 3511 dmap[DEFINED_TYPE_AS_PATH][y.Name()] = y 3512 } 3513 dmap[DEFINED_TYPE_COMMUNITY] = make(map[string]DefinedSet) 3514 for _, x := range bd.CommunitySets { 3515 y, err := NewCommunitySet(x) 3516 if err != nil { 3517 return err 3518 } 3519 if y == nil { 3520 return fmt.Errorf("empty community set") 3521 } 3522 dmap[DEFINED_TYPE_COMMUNITY][y.Name()] = y 3523 } 3524 dmap[DEFINED_TYPE_EXT_COMMUNITY] = make(map[string]DefinedSet) 3525 for _, x := range bd.ExtCommunitySets { 3526 y, err := NewExtCommunitySet(x) 3527 if err != nil { 3528 return err 3529 } 3530 if y == nil { 3531 return fmt.Errorf("empty ext-community set") 3532 } 3533 dmap[DEFINED_TYPE_EXT_COMMUNITY][y.Name()] = y 3534 } 3535 dmap[DEFINED_TYPE_LARGE_COMMUNITY] = make(map[string]DefinedSet) 3536 for _, x := range bd.LargeCommunitySets { 3537 y, err := NewLargeCommunitySet(x) 3538 if err != nil { 3539 return err 3540 } 3541 if y == nil { 3542 return fmt.Errorf("empty large-community set") 3543 } 3544 dmap[DEFINED_TYPE_LARGE_COMMUNITY][y.Name()] = y 3545 } 3546 3547 pmap := make(map[string]*Policy) 3548 smap := make(map[string]*Statement) 3549 for _, x := range c.PolicyDefinitions { 3550 y, err := NewPolicy(x) 3551 if err != nil { 3552 return err 3553 } 3554 if _, ok := pmap[y.Name]; ok { 3555 return fmt.Errorf("duplicated policy name. policy name must be unique") 3556 } 3557 pmap[y.Name] = y 3558 for _, s := range y.Statements { 3559 _, ok := smap[s.Name] 3560 if ok { 3561 return fmt.Errorf("duplicated statement name. statement name must be unique") 3562 } 3563 smap[s.Name] = s 3564 } 3565 } 3566 3567 // hacky 3568 oldMap := r.definedSetMap 3569 r.definedSetMap = dmap 3570 for _, y := range pmap { 3571 for _, s := range y.Statements { 3572 for _, c := range s.Conditions { 3573 if err := r.validateCondition(c); err != nil { 3574 r.definedSetMap = oldMap 3575 return err 3576 } 3577 } 3578 } 3579 } 3580 3581 r.definedSetMap = dmap 3582 r.policyMap = pmap 3583 r.statementMap = smap 3584 r.assignmentMap = make(map[string]*Assignment) 3585 // allow all routes coming in and going out by default 3586 r.setDefaultPolicy(GLOBAL_RIB_NAME, POLICY_DIRECTION_IMPORT, ROUTE_TYPE_ACCEPT) 3587 r.setDefaultPolicy(GLOBAL_RIB_NAME, POLICY_DIRECTION_EXPORT, ROUTE_TYPE_ACCEPT) 3588 return nil 3589 } 3590 3591 func (r *RoutingPolicy) GetDefinedSet(typ DefinedType, name string) (*oc.DefinedSets, error) { 3592 dl, err := func() (DefinedSetList, error) { 3593 r.mu.RLock() 3594 defer r.mu.RUnlock() 3595 3596 set, ok := r.definedSetMap[typ] 3597 if !ok { 3598 return nil, fmt.Errorf("invalid defined-set type: %d", typ) 3599 } 3600 3601 var dl DefinedSetList 3602 for _, s := range set { 3603 dl = append(dl, s) 3604 } 3605 return dl, nil 3606 }() 3607 if err != nil { 3608 return nil, err 3609 } 3610 3611 sort.Sort(dl) 3612 3613 sets := &oc.DefinedSets{ 3614 PrefixSets: make([]oc.PrefixSet, 0), 3615 NeighborSets: make([]oc.NeighborSet, 0), 3616 BgpDefinedSets: oc.BgpDefinedSets{ 3617 CommunitySets: make([]oc.CommunitySet, 0), 3618 ExtCommunitySets: make([]oc.ExtCommunitySet, 0), 3619 LargeCommunitySets: make([]oc.LargeCommunitySet, 0), 3620 AsPathSets: make([]oc.AsPathSet, 0), 3621 }, 3622 } 3623 for _, s := range dl { 3624 if name != "" && s.Name() != name { 3625 continue 3626 } 3627 switch v := s.(type) { 3628 case *PrefixSet: 3629 sets.PrefixSets = append(sets.PrefixSets, *v.ToConfig()) 3630 case *NeighborSet: 3631 sets.NeighborSets = append(sets.NeighborSets, *v.ToConfig()) 3632 case *CommunitySet: 3633 sets.BgpDefinedSets.CommunitySets = append(sets.BgpDefinedSets.CommunitySets, *v.ToConfig()) 3634 case *ExtCommunitySet: 3635 sets.BgpDefinedSets.ExtCommunitySets = append(sets.BgpDefinedSets.ExtCommunitySets, *v.ToConfig()) 3636 case *LargeCommunitySet: 3637 sets.BgpDefinedSets.LargeCommunitySets = append(sets.BgpDefinedSets.LargeCommunitySets, *v.ToConfig()) 3638 case *AsPathSet: 3639 sets.BgpDefinedSets.AsPathSets = append(sets.BgpDefinedSets.AsPathSets, *v.ToConfig()) 3640 } 3641 } 3642 return sets, nil 3643 } 3644 3645 func (r *RoutingPolicy) AddDefinedSet(s DefinedSet, replace bool) error { 3646 r.mu.Lock() 3647 defer r.mu.Unlock() 3648 3649 if m, ok := r.definedSetMap[s.Type()]; !ok { 3650 return fmt.Errorf("invalid defined-set type: %d", s.Type()) 3651 } else { 3652 if d, ok := m[s.Name()]; ok && !replace { 3653 if err := d.Append(s); err != nil { 3654 return err 3655 } 3656 } else { 3657 m[s.Name()] = s 3658 } 3659 } 3660 return nil 3661 } 3662 3663 func (r *RoutingPolicy) DeleteDefinedSet(a DefinedSet, all bool) (err error) { 3664 r.mu.Lock() 3665 defer r.mu.Unlock() 3666 3667 if m, ok := r.definedSetMap[a.Type()]; !ok { 3668 err = fmt.Errorf("invalid defined-set type: %d", a.Type()) 3669 } else { 3670 d, ok := m[a.Name()] 3671 if !ok { 3672 return fmt.Errorf("not found defined-set: %s", a.Name()) 3673 } 3674 if all { 3675 if r.inUse(d) { 3676 err = fmt.Errorf("can't delete. defined-set %s is in use", a.Name()) 3677 } else { 3678 delete(m, a.Name()) 3679 } 3680 } else { 3681 err = d.Remove(a) 3682 } 3683 } 3684 return err 3685 } 3686 3687 func (r *RoutingPolicy) GetStatement(name string) []*oc.Statement { 3688 r.mu.RLock() 3689 defer r.mu.RUnlock() 3690 3691 l := make([]*oc.Statement, 0, len(r.statementMap)) 3692 for _, st := range r.statementMap { 3693 if name != "" && name != st.Name { 3694 continue 3695 } 3696 l = append(l, st.ToConfig()) 3697 } 3698 return l 3699 } 3700 3701 func (r *RoutingPolicy) AddStatement(st *Statement) (err error) { 3702 r.mu.Lock() 3703 defer r.mu.Unlock() 3704 3705 for _, c := range st.Conditions { 3706 if err = r.validateCondition(c); err != nil { 3707 return 3708 } 3709 } 3710 m := r.statementMap 3711 name := st.Name 3712 if d, ok := m[name]; ok { 3713 err = d.Add(st) 3714 } else { 3715 m[name] = st 3716 } 3717 3718 return err 3719 } 3720 3721 func (r *RoutingPolicy) DeleteStatement(st *Statement, all bool) (err error) { 3722 r.mu.Lock() 3723 defer r.mu.Unlock() 3724 3725 m := r.statementMap 3726 name := st.Name 3727 if d, ok := m[name]; ok { 3728 if all { 3729 if r.statementInUse(d) { 3730 err = fmt.Errorf("can't delete. statement %s is in use", name) 3731 } else { 3732 delete(m, name) 3733 } 3734 } else { 3735 err = d.Remove(st) 3736 } 3737 } else { 3738 err = fmt.Errorf("not found statement: %s", name) 3739 } 3740 return err 3741 } 3742 3743 func (r *RoutingPolicy) GetPolicy(name string) []*oc.PolicyDefinition { 3744 ps := func() Policies { 3745 r.mu.RLock() 3746 defer r.mu.RUnlock() 3747 3748 var ps Policies 3749 for _, p := range r.policyMap { 3750 if name != "" && name != p.Name { 3751 continue 3752 } 3753 ps = append(ps, p) 3754 } 3755 return ps 3756 }() 3757 3758 sort.Sort(ps) 3759 3760 l := make([]*oc.PolicyDefinition, 0, len(ps)) 3761 for _, p := range ps { 3762 l = append(l, p.ToConfig()) 3763 } 3764 return l 3765 } 3766 3767 func (r *RoutingPolicy) AddPolicy(x *Policy, refer bool) (err error) { 3768 r.mu.Lock() 3769 defer r.mu.Unlock() 3770 3771 for _, st := range x.Statements { 3772 for _, c := range st.Conditions { 3773 if err = r.validateCondition(c); err != nil { 3774 return 3775 } 3776 } 3777 } 3778 3779 pMap := r.policyMap 3780 sMap := r.statementMap 3781 name := x.Name 3782 y, ok := pMap[name] 3783 if refer { 3784 err = x.FillUp(sMap) 3785 } else { 3786 for _, st := range x.Statements { 3787 if _, ok := sMap[st.Name]; ok { 3788 err = fmt.Errorf("statement %s already defined", st.Name) 3789 return 3790 } 3791 sMap[st.Name] = st 3792 } 3793 } 3794 if ok { 3795 err = y.Add(x) 3796 } else { 3797 pMap[name] = x 3798 } 3799 3800 return err 3801 } 3802 3803 func (r *RoutingPolicy) DeletePolicy(x *Policy, all, preserve bool, activeId []string) (err error) { 3804 r.mu.Lock() 3805 defer r.mu.Unlock() 3806 3807 pMap := r.policyMap 3808 sMap := r.statementMap 3809 name := x.Name 3810 y, ok := pMap[name] 3811 if !ok { 3812 err = fmt.Errorf("not found policy: %s", name) 3813 return 3814 } 3815 inUse := func(ids []string) bool { 3816 for _, id := range ids { 3817 for _, dir := range []PolicyDirection{POLICY_DIRECTION_EXPORT, POLICY_DIRECTION_EXPORT} { 3818 for _, y := range r.getPolicy(id, dir) { 3819 if x.Name == y.Name { 3820 return true 3821 } 3822 } 3823 } 3824 } 3825 return false 3826 } 3827 3828 if all { 3829 if inUse(activeId) { 3830 err = fmt.Errorf("can't delete. policy %s is in use", name) 3831 return 3832 } 3833 r.logger.Debug("delete policy", 3834 log.Fields{ 3835 "Topic": "Policy", 3836 "Key": name}) 3837 delete(pMap, name) 3838 } else { 3839 err = y.Remove(x) 3840 } 3841 if err == nil && !preserve { 3842 for _, st := range y.Statements { 3843 if !r.statementInUse(st) { 3844 r.logger.Debug("delete unused statement", 3845 log.Fields{ 3846 "Topic": "Policy", 3847 "Key": st.Name}) 3848 delete(sMap, st.Name) 3849 } 3850 } 3851 } 3852 return err 3853 } 3854 3855 func (r *RoutingPolicy) GetPolicyAssignment(id string, dir PolicyDirection) (RouteType, []*Policy, error) { 3856 r.mu.RLock() 3857 defer r.mu.RUnlock() 3858 3859 rt := r.getDefaultPolicy(id, dir) 3860 l := make([]*Policy, 0) 3861 l = append(l, r.getPolicy(id, dir)...) 3862 return rt, l, nil 3863 } 3864 3865 func (r *RoutingPolicy) AddPolicyAssignment(id string, dir PolicyDirection, policies []*oc.PolicyDefinition, def RouteType) (err error) { 3866 r.mu.Lock() 3867 defer r.mu.Unlock() 3868 3869 ps := make([]*Policy, 0, len(policies)) 3870 seen := make(map[string]bool) 3871 for _, x := range policies { 3872 p, ok := r.policyMap[x.Name] 3873 if !ok { 3874 err = fmt.Errorf("not found policy %s", x.Name) 3875 return 3876 } 3877 if seen[x.Name] { 3878 err = fmt.Errorf("duplicated policy %s", x.Name) 3879 return 3880 } 3881 seen[x.Name] = true 3882 ps = append(ps, p) 3883 } 3884 cur := r.getPolicy(id, dir) 3885 if cur == nil { 3886 err = r.setPolicy(id, dir, ps) 3887 } else { 3888 seen = make(map[string]bool) 3889 ps = append(cur, ps...) 3890 for _, x := range ps { 3891 if seen[x.Name] { 3892 err = fmt.Errorf("duplicated policy %s", x.Name) 3893 return 3894 } 3895 seen[x.Name] = true 3896 } 3897 err = r.setPolicy(id, dir, ps) 3898 } 3899 if err == nil && def != ROUTE_TYPE_NONE { 3900 err = r.setDefaultPolicy(id, dir, def) 3901 } 3902 return err 3903 } 3904 3905 func (r *RoutingPolicy) DeletePolicyAssignment(id string, dir PolicyDirection, policies []*oc.PolicyDefinition, all bool) (err error) { 3906 r.mu.Lock() 3907 defer r.mu.Unlock() 3908 3909 ps := make([]*Policy, 0, len(policies)) 3910 seen := make(map[string]bool) 3911 for _, x := range policies { 3912 p, ok := r.policyMap[x.Name] 3913 if !ok { 3914 err = fmt.Errorf("not found policy %s", x.Name) 3915 return 3916 } 3917 if seen[x.Name] { 3918 err = fmt.Errorf("duplicated policy %s", x.Name) 3919 return 3920 } 3921 seen[x.Name] = true 3922 ps = append(ps, p) 3923 } 3924 cur := r.getPolicy(id, dir) 3925 3926 if all { 3927 err = r.setPolicy(id, dir, nil) 3928 if err != nil { 3929 return 3930 } 3931 err = r.setDefaultPolicy(id, dir, ROUTE_TYPE_NONE) 3932 } else { 3933 l := len(cur) - len(ps) 3934 if l < 0 { 3935 // try to remove more than the assigned policies... 3936 l = len(cur) 3937 } 3938 n := make([]*Policy, 0, l) 3939 for _, y := range cur { 3940 found := false 3941 for _, x := range ps { 3942 if x.Name == y.Name { 3943 found = true 3944 break 3945 } 3946 } 3947 if !found { 3948 n = append(n, y) 3949 } 3950 } 3951 err = r.setPolicy(id, dir, n) 3952 } 3953 return err 3954 } 3955 3956 func (r *RoutingPolicy) SetPolicyAssignment(id string, dir PolicyDirection, policies []*oc.PolicyDefinition, def RouteType) (err error) { 3957 r.mu.Lock() 3958 defer r.mu.Unlock() 3959 3960 ps := make([]*Policy, 0, len(policies)) 3961 seen := make(map[string]bool) 3962 for _, x := range policies { 3963 p, ok := r.policyMap[x.Name] 3964 if !ok { 3965 err = fmt.Errorf("not found policy %s", x.Name) 3966 return 3967 } 3968 if seen[x.Name] { 3969 err = fmt.Errorf("duplicated policy %s", x.Name) 3970 return 3971 } 3972 seen[x.Name] = true 3973 ps = append(ps, p) 3974 } 3975 r.getPolicy(id, dir) 3976 err = r.setPolicy(id, dir, ps) 3977 if err == nil && def != ROUTE_TYPE_NONE { 3978 err = r.setDefaultPolicy(id, dir, def) 3979 } 3980 return err 3981 } 3982 3983 func (r *RoutingPolicy) Initialize() error { 3984 r.mu.Lock() 3985 defer r.mu.Unlock() 3986 3987 if err := r.reload(oc.RoutingPolicy{}); err != nil { 3988 r.logger.Error("failed to create routing policy", 3989 log.Fields{ 3990 "Topic": "Policy", 3991 "Error": err}) 3992 return err 3993 } 3994 return nil 3995 } 3996 3997 func (r *RoutingPolicy) setPeerPolicy(id string, c oc.ApplyPolicy) { 3998 for _, dir := range []PolicyDirection{POLICY_DIRECTION_IMPORT, POLICY_DIRECTION_EXPORT} { 3999 ps, def, err := r.getAssignmentFromConfig(dir, c) 4000 if err != nil { 4001 r.logger.Error("failed to get policy info", 4002 log.Fields{ 4003 "Topic": "Policy", 4004 "Dir": dir, 4005 "Error": err}) 4006 continue 4007 } 4008 r.setDefaultPolicy(id, dir, def) 4009 r.setPolicy(id, dir, ps) 4010 } 4011 } 4012 4013 func (r *RoutingPolicy) SetPeerPolicy(peerId string, c oc.ApplyPolicy) error { 4014 r.mu.Lock() 4015 defer r.mu.Unlock() 4016 4017 r.setPeerPolicy(peerId, c) 4018 return nil 4019 } 4020 4021 func (r *RoutingPolicy) Reset(rp *oc.RoutingPolicy, ap map[string]oc.ApplyPolicy) error { 4022 if rp == nil { 4023 return fmt.Errorf("routing Policy is nil in call to Reset") 4024 } 4025 4026 r.mu.Lock() 4027 defer r.mu.Unlock() 4028 4029 if err := r.reload(*rp); err != nil { 4030 r.logger.Error("failed to create routing policy", 4031 log.Fields{ 4032 "Topic": "Policy", 4033 "Error": err}) 4034 return err 4035 } 4036 4037 for id, c := range ap { 4038 r.setPeerPolicy(id, c) 4039 } 4040 return nil 4041 } 4042 4043 func NewRoutingPolicy(logger log.Logger) *RoutingPolicy { 4044 return &RoutingPolicy{ 4045 definedSetMap: make(map[DefinedType]map[string]DefinedSet), 4046 policyMap: make(map[string]*Policy), 4047 statementMap: make(map[string]*Statement), 4048 assignmentMap: make(map[string]*Assignment), 4049 logger: logger, 4050 } 4051 } 4052 4053 func CanImportToVrf(v *Vrf, path *Path) bool { 4054 f := func(arg []bgp.ExtendedCommunityInterface) []string { 4055 ret := make([]string, 0, len(arg)) 4056 for _, a := range arg { 4057 ret = append(ret, fmt.Sprintf("RT:%s", a.String())) 4058 } 4059 return ret 4060 } 4061 set, _ := NewExtCommunitySet(oc.ExtCommunitySet{ 4062 ExtCommunitySetName: v.Name, 4063 ExtCommunityList: f(v.ImportRt), 4064 }) 4065 matchSet := oc.MatchExtCommunitySet{ 4066 ExtCommunitySet: v.Name, 4067 MatchSetOptions: oc.MATCH_SET_OPTIONS_TYPE_ANY, 4068 } 4069 c, _ := NewExtCommunityCondition(matchSet) 4070 c.set = set 4071 return c.Evaluate(path, nil) 4072 } 4073 4074 type PolicyAssignment struct { 4075 Name string 4076 Type PolicyDirection 4077 Policies []*Policy 4078 Default RouteType 4079 } 4080 4081 var _regexpMedActionType = regexp.MustCompile(`([+-]?)(\d+)`) 4082 4083 func toStatementApi(s *oc.Statement) *api.Statement { 4084 cs := &api.Conditions{} 4085 o, _ := NewMatchOption(s.Conditions.MatchPrefixSet.MatchSetOptions) 4086 if s.Conditions.MatchPrefixSet.PrefixSet != "" { 4087 cs.PrefixSet = &api.MatchSet{ 4088 Type: api.MatchSet_Type(o), 4089 Name: s.Conditions.MatchPrefixSet.PrefixSet, 4090 } 4091 } 4092 if s.Conditions.MatchNeighborSet.NeighborSet != "" { 4093 o, _ := NewMatchOption(s.Conditions.MatchNeighborSet.MatchSetOptions) 4094 cs.NeighborSet = &api.MatchSet{ 4095 Type: api.MatchSet_Type(o), 4096 Name: s.Conditions.MatchNeighborSet.NeighborSet, 4097 } 4098 } 4099 if s.Conditions.BgpConditions.CommunityCount.Operator != "" { 4100 cs.CommunityCount = &api.CommunityCount{ 4101 Count: s.Conditions.BgpConditions.CommunityCount.Value, 4102 Type: api.CommunityCount_Type(s.Conditions.BgpConditions.CommunityCount.Operator.ToInt()), 4103 } 4104 } 4105 if s.Conditions.BgpConditions.OriginEq.ToInt() != -1 { 4106 switch s.Actions.BgpActions.SetRouteOrigin { 4107 case oc.BGP_ORIGIN_ATTR_TYPE_IGP: 4108 cs.Origin = api.RouteOriginType_ORIGIN_IGP 4109 case oc.BGP_ORIGIN_ATTR_TYPE_EGP: 4110 cs.Origin = api.RouteOriginType_ORIGIN_EGP 4111 case oc.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE: 4112 cs.Origin = api.RouteOriginType_ORIGIN_INCOMPLETE 4113 } 4114 } 4115 if s.Conditions.BgpConditions.AsPathLength.Operator != "" { 4116 cs.AsPathLength = &api.AsPathLength{ 4117 Length: s.Conditions.BgpConditions.AsPathLength.Value, 4118 Type: api.AsPathLength_Type(s.Conditions.BgpConditions.AsPathLength.Operator.ToInt()), 4119 } 4120 } 4121 if s.Conditions.BgpConditions.MatchAsPathSet.AsPathSet != "" { 4122 cs.AsPathSet = &api.MatchSet{ 4123 Type: api.MatchSet_Type(s.Conditions.BgpConditions.MatchAsPathSet.MatchSetOptions.ToInt()), 4124 Name: s.Conditions.BgpConditions.MatchAsPathSet.AsPathSet, 4125 } 4126 } 4127 if s.Conditions.BgpConditions.MatchCommunitySet.CommunitySet != "" { 4128 cs.CommunitySet = &api.MatchSet{ 4129 Type: api.MatchSet_Type(s.Conditions.BgpConditions.MatchCommunitySet.MatchSetOptions.ToInt()), 4130 Name: s.Conditions.BgpConditions.MatchCommunitySet.CommunitySet, 4131 } 4132 } 4133 if s.Conditions.BgpConditions.MatchExtCommunitySet.ExtCommunitySet != "" { 4134 cs.ExtCommunitySet = &api.MatchSet{ 4135 Type: api.MatchSet_Type(s.Conditions.BgpConditions.MatchExtCommunitySet.MatchSetOptions.ToInt()), 4136 Name: s.Conditions.BgpConditions.MatchExtCommunitySet.ExtCommunitySet, 4137 } 4138 } 4139 if s.Conditions.BgpConditions.MatchLargeCommunitySet.LargeCommunitySet != "" { 4140 cs.LargeCommunitySet = &api.MatchSet{ 4141 Type: api.MatchSet_Type(s.Conditions.BgpConditions.MatchLargeCommunitySet.MatchSetOptions.ToInt()), 4142 Name: s.Conditions.BgpConditions.MatchLargeCommunitySet.LargeCommunitySet, 4143 } 4144 } 4145 if s.Conditions.BgpConditions.RouteType != "" { 4146 cs.RouteType = api.Conditions_RouteType(s.Conditions.BgpConditions.RouteType.ToInt()) 4147 } 4148 if len(s.Conditions.BgpConditions.NextHopInList) > 0 { 4149 cs.NextHopInList = s.Conditions.BgpConditions.NextHopInList 4150 } 4151 if s.Conditions.BgpConditions.AfiSafiInList != nil { 4152 afiSafiIn := make([]*api.Family, 0) 4153 for _, afiSafiType := range s.Conditions.BgpConditions.AfiSafiInList { 4154 if mapped, ok := bgp.AddressFamilyValueMap[string(afiSafiType)]; ok { 4155 afi, safi := bgp.RouteFamilyToAfiSafi(mapped) 4156 afiSafiIn = append(afiSafiIn, &api.Family{Afi: api.Family_Afi(afi), Safi: api.Family_Safi(safi)}) 4157 } 4158 } 4159 cs.AfiSafiIn = afiSafiIn 4160 } 4161 cs.RpkiResult = int32(s.Conditions.BgpConditions.RpkiValidationResult.ToInt()) 4162 as := &api.Actions{ 4163 RouteAction: func() api.RouteAction { 4164 switch s.Actions.RouteDisposition { 4165 case oc.ROUTE_DISPOSITION_ACCEPT_ROUTE: 4166 return api.RouteAction_ACCEPT 4167 case oc.ROUTE_DISPOSITION_REJECT_ROUTE: 4168 return api.RouteAction_REJECT 4169 } 4170 return api.RouteAction_NONE 4171 }(), 4172 Community: func() *api.CommunityAction { 4173 if len(s.Actions.BgpActions.SetCommunity.SetCommunityMethod.CommunitiesList) == 0 { 4174 return nil 4175 } 4176 return &api.CommunityAction{ 4177 Type: api.CommunityAction_Type(oc.BgpSetCommunityOptionTypeToIntMap[oc.BgpSetCommunityOptionType(s.Actions.BgpActions.SetCommunity.Options)]), 4178 Communities: s.Actions.BgpActions.SetCommunity.SetCommunityMethod.CommunitiesList} 4179 }(), 4180 Med: func() *api.MedAction { 4181 medStr := strings.TrimSpace(string(s.Actions.BgpActions.SetMed)) 4182 if len(medStr) == 0 { 4183 return nil 4184 } 4185 matches := _regexpMedActionType.FindStringSubmatch(medStr) 4186 if len(matches) == 0 { 4187 return nil 4188 } 4189 action := api.MedAction_REPLACE 4190 switch matches[1] { 4191 case "+", "-": 4192 action = api.MedAction_MOD 4193 } 4194 value, err := strconv.ParseInt(matches[1]+matches[2], 10, 64) 4195 if err != nil { 4196 return nil 4197 } 4198 return &api.MedAction{ 4199 Value: value, 4200 Type: action, 4201 } 4202 }(), 4203 AsPrepend: func() *api.AsPrependAction { 4204 if len(s.Actions.BgpActions.SetAsPathPrepend.As) == 0 { 4205 return nil 4206 } 4207 var asn uint64 4208 useleft := false 4209 if s.Actions.BgpActions.SetAsPathPrepend.As != "last-as" { 4210 asn, _ = strconv.ParseUint(s.Actions.BgpActions.SetAsPathPrepend.As, 10, 32) 4211 } else { 4212 useleft = true 4213 } 4214 return &api.AsPrependAction{ 4215 Asn: uint32(asn), 4216 Repeat: uint32(s.Actions.BgpActions.SetAsPathPrepend.RepeatN), 4217 UseLeftMost: useleft, 4218 } 4219 }(), 4220 ExtCommunity: func() *api.CommunityAction { 4221 if len(s.Actions.BgpActions.SetExtCommunity.SetExtCommunityMethod.CommunitiesList) == 0 { 4222 return nil 4223 } 4224 return &api.CommunityAction{ 4225 Type: api.CommunityAction_Type(oc.BgpSetCommunityOptionTypeToIntMap[oc.BgpSetCommunityOptionType(s.Actions.BgpActions.SetExtCommunity.Options)]), 4226 Communities: s.Actions.BgpActions.SetExtCommunity.SetExtCommunityMethod.CommunitiesList, 4227 } 4228 }(), 4229 LargeCommunity: func() *api.CommunityAction { 4230 if len(s.Actions.BgpActions.SetLargeCommunity.SetLargeCommunityMethod.CommunitiesList) == 0 { 4231 return nil 4232 } 4233 return &api.CommunityAction{ 4234 Type: api.CommunityAction_Type(oc.BgpSetCommunityOptionTypeToIntMap[oc.BgpSetCommunityOptionType(s.Actions.BgpActions.SetLargeCommunity.Options)]), 4235 Communities: s.Actions.BgpActions.SetLargeCommunity.SetLargeCommunityMethod.CommunitiesList, 4236 } 4237 }(), 4238 Nexthop: func() *api.NexthopAction { 4239 if len(string(s.Actions.BgpActions.SetNextHop)) == 0 { 4240 return nil 4241 } 4242 4243 switch string(s.Actions.BgpActions.SetNextHop) { 4244 case "self": 4245 return &api.NexthopAction{ 4246 Self: true, 4247 } 4248 case "peer-address": 4249 return &api.NexthopAction{ 4250 PeerAddress: true, 4251 } 4252 case "unchanged": 4253 return &api.NexthopAction{ 4254 Unchanged: true, 4255 } 4256 } 4257 return &api.NexthopAction{ 4258 Address: string(s.Actions.BgpActions.SetNextHop), 4259 } 4260 }(), 4261 LocalPref: func() *api.LocalPrefAction { 4262 if s.Actions.BgpActions.SetLocalPref == 0 { 4263 return nil 4264 } 4265 return &api.LocalPrefAction{Value: s.Actions.BgpActions.SetLocalPref} 4266 }(), 4267 OriginAction: func() *api.OriginAction { 4268 if s.Actions.BgpActions.SetRouteOrigin.ToInt() == -1 { 4269 return nil 4270 } 4271 var apiOrigin api.RouteOriginType 4272 switch s.Actions.BgpActions.SetRouteOrigin { 4273 case oc.BGP_ORIGIN_ATTR_TYPE_IGP: 4274 apiOrigin = api.RouteOriginType_ORIGIN_IGP 4275 case oc.BGP_ORIGIN_ATTR_TYPE_EGP: 4276 apiOrigin = api.RouteOriginType_ORIGIN_EGP 4277 case oc.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE: 4278 apiOrigin = api.RouteOriginType_ORIGIN_INCOMPLETE 4279 default: 4280 return nil 4281 } 4282 return &api.OriginAction{Origin: apiOrigin} 4283 }(), 4284 } 4285 return &api.Statement{ 4286 Name: s.Name, 4287 Conditions: cs, 4288 Actions: as, 4289 } 4290 } 4291 4292 func NewAPIPolicyFromTableStruct(p *Policy) *api.Policy { 4293 return ToPolicyApi(p.ToConfig()) 4294 } 4295 4296 func ToPolicyApi(p *oc.PolicyDefinition) *api.Policy { 4297 return &api.Policy{ 4298 Name: p.Name, 4299 Statements: func() []*api.Statement { 4300 l := make([]*api.Statement, 0) 4301 for _, s := range p.Statements { 4302 l = append(l, toStatementApi(&s)) 4303 } 4304 return l 4305 }(), 4306 } 4307 } 4308 4309 func NewAPIPolicyAssignmentFromTableStruct(t *PolicyAssignment) *api.PolicyAssignment { 4310 return &api.PolicyAssignment{ 4311 Direction: func() api.PolicyDirection { 4312 switch t.Type { 4313 case POLICY_DIRECTION_IMPORT: 4314 return api.PolicyDirection_IMPORT 4315 case POLICY_DIRECTION_EXPORT: 4316 return api.PolicyDirection_EXPORT 4317 } 4318 return api.PolicyDirection_UNKNOWN 4319 }(), 4320 DefaultAction: func() api.RouteAction { 4321 switch t.Default { 4322 case ROUTE_TYPE_ACCEPT: 4323 return api.RouteAction_ACCEPT 4324 case ROUTE_TYPE_REJECT: 4325 return api.RouteAction_REJECT 4326 } 4327 return api.RouteAction_NONE 4328 }(), 4329 Name: t.Name, 4330 Policies: func() []*api.Policy { 4331 l := make([]*api.Policy, 0) 4332 for _, p := range t.Policies { 4333 l = append(l, NewAPIPolicyFromTableStruct(p)) 4334 } 4335 return l 4336 }(), 4337 } 4338 } 4339 4340 func NewAPIRoutingPolicyFromConfigStruct(c *oc.RoutingPolicy) (*api.RoutingPolicy, error) { 4341 definedSets, err := oc.NewAPIDefinedSetsFromConfigStruct(&c.DefinedSets) 4342 if err != nil { 4343 return nil, err 4344 } 4345 policies := make([]*api.Policy, 0, len(c.PolicyDefinitions)) 4346 for _, policy := range c.PolicyDefinitions { 4347 policies = append(policies, ToPolicyApi(&policy)) 4348 } 4349 4350 return &api.RoutingPolicy{ 4351 DefinedSets: definedSets, 4352 Policies: policies, 4353 }, nil 4354 }