github.com/osrg/gobgp/v3@v3.30.0/internal/pkg/table/policy.go (about)

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