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