diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-08-03 05:52:31 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2016-08-03 05:52:31 +0900 |
commit | 0082b4889e35883d9f0aeb07c3d6827b3f129e1b (patch) | |
tree | 6ecf9abb12783056973fead3b7362e85466ced5b | |
parent | 6f3d90f80cb40723f0f391041e88d24d1b2b0de1 (diff) |
move policyMutex to policy/
It's more logical.
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | server/fsm.go | 2 | ||||
-rw-r--r-- | server/server.go | 492 | ||||
-rw-r--r-- | server/server_test.go | 2 | ||||
-rw-r--r-- | table/policy.go | 469 |
4 files changed, 514 insertions, 451 deletions
diff --git a/server/fsm.go b/server/fsm.go index 780a2b32..5ac3e6a2 100644 --- a/server/fsm.go +++ b/server/fsm.go @@ -657,7 +657,6 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { if err == nil { fmsg.PathList = table.ProcessMessage(m, h.fsm.peerInfo, fmsg.timestamp) id := h.fsm.pConf.Config.NeighborAddress - policyMutex.RLock() for _, path := range fmsg.PathList { if path.IsEOR() { continue @@ -666,7 +665,6 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { path.Filter(id, table.POLICY_DIRECTION_IN) } } - policyMutex.RUnlock() } else { fmsg.MsgData = err } diff --git a/server/server.go b/server/server.go index d8351180..1954d124 100644 --- a/server/server.go +++ b/server/server.go @@ -1,4 +1,4 @@ -// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation. +// Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,7 +21,6 @@ import ( "net" "os" "strconv" - "sync" "time" log "github.com/Sirupsen/logrus" @@ -33,8 +32,6 @@ import ( "github.com/satori/go.uuid" ) -var policyMutex sync.RWMutex - type TCPListener struct { l *net.TCPListener ch chan struct{} @@ -925,41 +922,11 @@ func (s *BgpServer) UpdatePolicy(policy config.RoutingPolicy) (err error) { }).Info("call set policy") ap[peer.ID()] = peer.fsm.pConf.ApplyPolicy } - err = s.setPolicy(&policy, ap) + err = s.policy.Reset(&policy, ap) } return err } -func (s *BgpServer) setPolicy(rp *config.RoutingPolicy, ap map[string]config.ApplyPolicy) error { - policyMutex.Lock() - defer policyMutex.Unlock() - - if rp != nil { - if err := s.policy.Reload(*rp); err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - }).Errorf("failed to create routing policy: %s", err) - return err - } - } - - for id, c := range ap { - for _, dir := range []table.PolicyDirection{table.POLICY_DIRECTION_IN, table.POLICY_DIRECTION_IMPORT, table.POLICY_DIRECTION_EXPORT} { - ps, def, err := s.policy.GetAssignmentFromConfig(dir, c) - if err != nil { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Dir": dir, - }).Errorf("failed to get policy info: %s", err) - continue - } - s.policy.SetDefaultPolicy(id, dir, def) - s.policy.SetPolicy(id, dir, ps) - } - } - return nil -} - // EVPN MAC MOBILITY HANDLING // // We don't have multihoming function now, so ignore @@ -1188,7 +1155,7 @@ func (s *BgpServer) Start(c *config.Global) (err error) { rfs, _ := config.AfiSafis(c.AfiSafis).ToRfList() s.globalRib = table.NewTableManager(rfs, c.MplsLabelRange.MinLabel, c.MplsLabelRange.MaxLabel) - if err = s.setPolicy(&config.RoutingPolicy{}, map[string]config.ApplyPolicy{}); err != nil { + if err = s.policy.Reset(&config.RoutingPolicy{}, map[string]config.ApplyPolicy{}); err != nil { return } s.bgpConfig.Global = *c @@ -1689,7 +1656,7 @@ func (server *BgpServer) addNeighbor(c *config.Neighbor) error { }).Infof("Add a peer configuration for:%s", addr) peer := NewPeer(&server.bgpConfig.Global, c, server.globalRib, server.policy) - server.setPolicy(nil, map[string]config.ApplyPolicy{peer.ID(): c.ApplyPolicy}) + server.policy.Reset(nil, map[string]config.ApplyPolicy{peer.ID(): c.ApplyPolicy}) if peer.isRouteServerClient() { pathList := make([]*table.Path, 0) rfList := peer.configuredRFlist() @@ -1801,7 +1768,7 @@ func (s *BgpServer) UpdateNeighbor(c *config.Neighbor) (policyUpdated bool, err "Topic": "Peer", "Key": addr, }).Info("Update ApplyPolicy") - s.setPolicy(nil, map[string]config.ApplyPolicy{peer.ID(): c.ApplyPolicy}) + s.policy.Reset(nil, map[string]config.ApplyPolicy{peer.ID(): c.ApplyPolicy}) peer.fsm.pConf.ApplyPolicy = c.ApplyPolicy policyUpdated = true } @@ -1976,42 +1943,11 @@ func (s *BgpServer) GetDefinedSet(typ table.DefinedType) (sets *config.DefinedSe defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - set, ok := s.policy.DefinedSetMap[typ] - if !ok { - err = fmt.Errorf("invalid defined-set type: %d", typ) - return - } - sets = &config.DefinedSets{ - PrefixSets: make([]config.PrefixSet, 0), - NeighborSets: make([]config.NeighborSet, 0), - BgpDefinedSets: config.BgpDefinedSets{ - CommunitySets: make([]config.CommunitySet, 0), - ExtCommunitySets: make([]config.ExtCommunitySet, 0), - AsPathSets: make([]config.AsPathSet, 0), - }, - } - for _, s := range set { - switch s.(type) { - case *table.PrefixSet: - sets.PrefixSets = append(sets.PrefixSets, *s.(*table.PrefixSet).ToConfig()) - case *table.NeighborSet: - sets.NeighborSets = append(sets.NeighborSets, *s.(*table.NeighborSet).ToConfig()) - case *table.CommunitySet: - sets.BgpDefinedSets.CommunitySets = append(sets.BgpDefinedSets.CommunitySets, *s.(*table.CommunitySet).ToConfig()) - case *table.ExtCommunitySet: - sets.BgpDefinedSets.ExtCommunitySets = append(sets.BgpDefinedSets.ExtCommunitySets, *s.(*table.ExtCommunitySet).ToConfig()) - case *table.AsPathSet: - sets.BgpDefinedSets.AsPathSets = append(sets.BgpDefinedSets.AsPathSets, *s.(*table.AsPathSet).ToConfig()) - } - } + sets, err = s.policy.GetDefinedSet(typ) } - return sets, nil + return sets, err } func (s *BgpServer) AddDefinedSet(a table.DefinedSet) (err error) { @@ -2019,21 +1955,9 @@ func (s *BgpServer) AddDefinedSet(a table.DefinedSet) (err error) { defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - if m, ok := s.policy.DefinedSetMap[a.Type()]; !ok { - err = fmt.Errorf("invalid defined-set type: %d", a.Type()) - } else { - if d, ok := m[a.Name()]; ok { - err = d.Append(a) - } else { - m[a.Name()] = a - } - } + err = s.policy.AddDefinedSet(a) } return err } @@ -2043,30 +1967,9 @@ func (s *BgpServer) DeleteDefinedSet(a table.DefinedSet, all bool) (err error) { defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - if m, ok := s.policy.DefinedSetMap[a.Type()]; !ok { - err = fmt.Errorf("invalid defined-set type: %d", a.Type()) - } else { - d, ok := m[a.Name()] - if !ok { - err = fmt.Errorf("not found defined-set: %s", a.Name()) - return - } - if all { - if s.policy.InUse(d) { - err = fmt.Errorf("can't delete. defined-set %s is in use", a.Name()) - } else { - delete(m, a.Name()) - } - } else { - err = d.Remove(a) - } - } + err = s.policy.DeleteDefinedSet(a, all) } return err } @@ -2076,21 +1979,9 @@ func (s *BgpServer) ReplaceDefinedSet(a table.DefinedSet) (err error) { defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - if m, ok := s.policy.DefinedSetMap[a.Type()]; !ok { - err = fmt.Errorf("invalid defined-set type: %d", a.Type()) - } else { - if d, ok := m[a.Name()]; !ok { - err = fmt.Errorf("not found defined-set: %s", a.Name()) - } else { - err = d.Replace(a) - } - } + err = s.policy.ReplaceDefinedSet(a) } return err } @@ -2100,16 +1991,9 @@ func (s *BgpServer) GetStatement() (l []*config.Statement) { defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - l = make([]*config.Statement, 0, len(s.policy.StatementMap)) - for _, st := range s.policy.StatementMap { - l = append(l, st.ToConfig()) - } + l = s.policy.GetStatement() } return l } @@ -2119,24 +2003,9 @@ func (s *BgpServer) AddStatement(st *table.Statement) (err error) { defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - for _, c := range st.Conditions { - if err = s.policy.ValidateCondition(c); err != nil { - return - } - } - m := s.policy.StatementMap - name := st.Name - if d, ok := m[name]; ok { - err = d.Add(st) - } else { - m[name] = st - } + err = s.policy.AddStatement(st) } return err } @@ -2146,27 +2015,9 @@ func (s *BgpServer) DeleteStatement(st *table.Statement, all bool) (err error) { defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - m := s.policy.StatementMap - name := st.Name - if d, ok := m[name]; ok { - if all { - if s.policy.StatementInUse(d) { - err = fmt.Errorf("can't delete. statement %s is in use", name) - } else { - delete(m, name) - } - } else { - err = d.Remove(st) - } - } else { - err = fmt.Errorf("not found statement: %s", name) - } + err = s.policy.DeleteStatement(st, all) } return err } @@ -2176,19 +2027,9 @@ func (s *BgpServer) ReplaceStatement(st *table.Statement) (err error) { defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - m := s.policy.StatementMap - name := st.Name - if d, ok := m[name]; ok { - err = d.Replace(st) - } else { - err = fmt.Errorf("not found statement: %s", name) - } + err = s.policy.ReplaceStatement(st) } return err } @@ -2198,79 +2039,21 @@ func (s *BgpServer) GetPolicy() (l []*config.PolicyDefinition) { defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - l := make([]*config.PolicyDefinition, 0, len(s.policy.PolicyMap)) - for _, p := range s.policy.PolicyMap { - l = append(l, p.ToConfig()) - } + l = s.policy.GetAllPolicy() } return l } -func (s *BgpServer) policyInUse(x *table.Policy) bool { - for _, peer := range s.neighborMap { - for _, dir := range []table.PolicyDirection{table.POLICY_DIRECTION_IN, table.POLICY_DIRECTION_EXPORT, table.POLICY_DIRECTION_EXPORT} { - for _, y := range s.policy.GetPolicy(peer.ID(), dir) { - if x.Name == y.Name { - return true - } - } - } - } - for _, dir := range []table.PolicyDirection{table.POLICY_DIRECTION_EXPORT, table.POLICY_DIRECTION_EXPORT} { - for _, y := range s.policy.GetPolicy(table.GLOBAL_RIB_NAME, dir) { - if x.Name == y.Name { - return true - } - } - } - return false -} - func (s *BgpServer) AddPolicy(x *table.Policy, refer bool) (err error) { ch := make(chan struct{}) defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() - - for _, st := range x.Statements { - for _, c := range st.Conditions { - if err = s.policy.ValidateCondition(c); err != nil { - return - } - } - } + defer close(ch) - pMap := s.policy.PolicyMap - sMap := s.policy.StatementMap - name := x.Name - y, ok := pMap[name] - if refer { - err = x.FillUp(sMap) - } else { - for _, st := range x.Statements { - if _, ok := sMap[st.Name]; ok { - err = fmt.Errorf("statement %s already defined", st.Name) - return - } - sMap[st.Name] = st - } - } - if ok { - err = y.Add(x) - } else { - pMap[name] = x - } + err = s.policy.AddPolicy(x, refer) } return err } @@ -2280,44 +2063,16 @@ func (s *BgpServer) DeletePolicy(x *table.Policy, all, preserve bool) (err error defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) - pMap := s.policy.PolicyMap - sMap := s.policy.StatementMap - name := x.Name - y, ok := pMap[name] - if !ok { - err = fmt.Errorf("not found policy: %s", name) - return - } - if all { - if s.policyInUse(y) { - err = fmt.Errorf("can't delete. policy %s is in use", name) - return - } - log.WithFields(log.Fields{ - "Topic": "Policy", - "Key": name, - }).Debug("delete policy") - delete(pMap, name) - } else { - err = y.Remove(x) - } - if err == nil && !preserve { - for _, st := range y.Statements { - if !s.policy.StatementInUse(st) { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Key": st.Name, - }).Debug("delete unused statement") - delete(sMap, st.Name) - } - } + l := make([]string, 0, len(s.neighborMap)+1) + for _, peer := range s.neighborMap { + l = append(l, peer.ID()) } + l = append(l, table.GLOBAL_RIB_NAME) + + err = s.policy.DeletePolicy(x, all, preserve, l) + } return err } @@ -2327,54 +2082,9 @@ func (s *BgpServer) ReplacePolicy(x *table.Policy, refer, preserve bool) (err er defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() - - for _, st := range x.Statements { - for _, c := range st.Conditions { - if err = s.policy.ValidateCondition(c); err != nil { - return - } - } - } - - pMap := s.policy.PolicyMap - sMap := s.policy.StatementMap - name := x.Name - y, ok := pMap[name] - if !ok { - err = fmt.Errorf("not found policy: %s", name) - return - } - if refer { - if err = x.FillUp(sMap); err != nil { - return - } - } else { - for _, st := range x.Statements { - if _, ok := sMap[st.Name]; ok { - err = fmt.Errorf("statement %s already defined", st.Name) - return - } - sMap[st.Name] = st - } - } + defer close(ch) - err = y.Replace(x) - if err == nil && !preserve { - for _, st := range y.Statements { - if !s.policy.StatementInUse(st) { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Key": st.Name, - }).Debug("delete unused statement") - delete(sMap, st.Name) - } - } - } + err = s.policy.ReplacePolicy(x, refer, preserve) } return err } @@ -2403,24 +2113,14 @@ func (s *BgpServer) GetPolicyAssignment(name string, dir table.PolicyDirection) defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) var id string id, err = s.toPolicyInfo(name, dir) if err != nil { rt = table.ROUTE_TYPE_NONE } else { - rt = s.policy.GetDefaultPolicy(id, dir) - - ps := s.policy.GetPolicy(id, dir) - l = make([]*config.PolicyDefinition, 0, len(ps)) - for _, p := range ps { - l = append(l, p.ToConfig()) - } + rt, l, err = s.policy.GetPolicyAssignment(id, dir) } } return rt, l, err @@ -2431,51 +2131,14 @@ func (s *BgpServer) AddPolicyAssignment(name string, dir table.PolicyDirection, defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) var id string id, err = s.toPolicyInfo(name, dir) if err != nil { return } - - ps := make([]*table.Policy, 0, len(policies)) - seen := make(map[string]bool) - for _, x := range policies { - p, ok := s.policy.PolicyMap[x.Name] - if !ok { - err = fmt.Errorf("not found policy %s", x.Name) - return - } - if seen[x.Name] { - err = fmt.Errorf("duplicated policy %s", x.Name) - return - } - seen[x.Name] = true - ps = append(ps, p) - } - cur := s.policy.GetPolicy(id, dir) - if cur == nil { - err = s.policy.SetPolicy(id, dir, ps) - } else { - seen = make(map[string]bool) - ps = append(cur, ps...) - for _, x := range ps { - if seen[x.Name] { - err = fmt.Errorf("duplicated policy %s", x.Name) - return - } - seen[x.Name] = true - } - err = s.policy.SetPolicy(id, dir, ps) - } - if err == nil && def != table.ROUTE_TYPE_NONE { - err = s.policy.SetDefaultPolicy(id, dir, def) - } + err = s.policy.AddPolicyAssignment(id, dir, policies, def) } return err } @@ -2485,57 +2148,14 @@ func (s *BgpServer) DeletePolicyAssignment(name string, dir table.PolicyDirectio defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) var id string id, err = s.toPolicyInfo(name, dir) if err != nil { return } - - ps := make([]*table.Policy, 0, len(policies)) - seen := make(map[string]bool) - for _, x := range policies { - p, ok := s.policy.PolicyMap[x.Name] - if !ok { - err = fmt.Errorf("not found policy %s", x.Name) - return - } - if seen[x.Name] { - err = fmt.Errorf("duplicated policy %s", x.Name) - return - } - seen[x.Name] = true - ps = append(ps, p) - } - cur := s.policy.GetPolicy(id, dir) - - if all { - err = s.policy.SetPolicy(id, dir, nil) - if err != nil { - return - } - err = s.policy.SetDefaultPolicy(id, dir, table.ROUTE_TYPE_NONE) - } else { - n := make([]*table.Policy, 0, len(cur)-len(ps)) - for _, y := range cur { - found := false - for _, x := range ps { - if x.Name == y.Name { - found = true - break - } - } - if !found { - n = append(n, y) - } - } - err = s.policy.SetPolicy(id, dir, n) - } + err = s.policy.DeletePolicyAssignment(id, dir, policies, all) } return err } @@ -2545,38 +2165,14 @@ func (s *BgpServer) ReplacePolicyAssignment(name string, dir table.PolicyDirecti defer func() { <-ch }() s.mgmtCh <- func() { - policyMutex.Lock() - defer func() { - policyMutex.Unlock() - close(ch) - }() + defer close(ch) var id string id, err = s.toPolicyInfo(name, dir) if err != nil { return } - - ps := make([]*table.Policy, 0, len(policies)) - seen := make(map[string]bool) - for _, x := range policies { - p, ok := s.policy.PolicyMap[x.Name] - if !ok { - err = fmt.Errorf("not found policy %s", x.Name) - return - } - if seen[x.Name] { - err = fmt.Errorf("duplicated policy %s", x.Name) - return - } - seen[x.Name] = true - ps = append(ps, p) - } - s.policy.GetPolicy(id, dir) - err = s.policy.SetPolicy(id, dir, ps) - if err == nil && def != table.ROUTE_TYPE_NONE { - err = s.policy.SetDefaultPolicy(id, dir, def) - } + err = s.policy.ReplacePolicyAssignment(id, dir, policies, def) } return err } diff --git a/server/server_test.go b/server/server_test.go index 57fcfaf1..c3553932 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -49,6 +49,6 @@ func TestModPolicyAssign(t *testing.T) { []*config.PolicyDefinition{&config.PolicyDefinition{Name: "p1"}}, false) assert.Nil(err) - ps := s.policy.GetPolicy(table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT) + _, ps, _ := s.GetPolicyAssignment("", table.POLICY_DIRECTION_IMPORT) assert.Equal(len(ps), 2) } diff --git a/table/policy.go b/table/policy.go index 94773346..c6da5471 100644 --- a/table/policy.go +++ b/table/policy.go @@ -23,6 +23,7 @@ import ( "regexp" "strconv" "strings" + "sync" log "github.com/Sirupsen/logrus" "github.com/armon/go-radix" @@ -2198,9 +2199,13 @@ type RoutingPolicy struct { PolicyMap map[string]*Policy StatementMap map[string]*Statement AssignmentMap map[string]*Assignment + mu sync.RWMutex } func (r *RoutingPolicy) ApplyPolicy(id string, dir PolicyDirection, before *Path, options *PolicyOptions) *Path { + r.mu.RLock() + defer r.mu.RUnlock() + if before == nil { return nil } @@ -2516,6 +2521,470 @@ func (r *RoutingPolicy) Reload(c config.RoutingPolicy) error { return nil } +func (r *RoutingPolicy) GetDefinedSet(typ DefinedType) (*config.DefinedSets, error) { + r.mu.RLock() + defer r.mu.RUnlock() + + set, ok := r.DefinedSetMap[typ] + if !ok { + return nil, fmt.Errorf("invalid defined-set type: %d", typ) + } + sets := &config.DefinedSets{ + PrefixSets: make([]config.PrefixSet, 0), + NeighborSets: make([]config.NeighborSet, 0), + BgpDefinedSets: config.BgpDefinedSets{ + CommunitySets: make([]config.CommunitySet, 0), + ExtCommunitySets: make([]config.ExtCommunitySet, 0), + AsPathSets: make([]config.AsPathSet, 0), + }, + } + for _, s := range set { + switch s.(type) { + case *PrefixSet: + sets.PrefixSets = append(sets.PrefixSets, *s.(*PrefixSet).ToConfig()) + case *NeighborSet: + sets.NeighborSets = append(sets.NeighborSets, *s.(*NeighborSet).ToConfig()) + case *CommunitySet: + sets.BgpDefinedSets.CommunitySets = append(sets.BgpDefinedSets.CommunitySets, *s.(*CommunitySet).ToConfig()) + case *ExtCommunitySet: + sets.BgpDefinedSets.ExtCommunitySets = append(sets.BgpDefinedSets.ExtCommunitySets, *s.(*ExtCommunitySet).ToConfig()) + case *AsPathSet: + sets.BgpDefinedSets.AsPathSets = append(sets.BgpDefinedSets.AsPathSets, *s.(*AsPathSet).ToConfig()) + } + } + return sets, nil +} + +func (r *RoutingPolicy) AddDefinedSet(s DefinedSet) error { + r.mu.Lock() + defer r.mu.Unlock() + + if m, ok := r.DefinedSetMap[s.Type()]; !ok { + return fmt.Errorf("invalid defined-set type: %d", s.Type()) + } else { + if d, ok := m[s.Name()]; ok { + if err := d.Append(s); err != nil { + return err + } + } else { + m[s.Name()] = s + } + } + return nil +} + +func (r *RoutingPolicy) DeleteDefinedSet(a DefinedSet, all bool) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + if m, ok := r.DefinedSetMap[a.Type()]; !ok { + err = fmt.Errorf("invalid defined-set type: %d", a.Type()) + } else { + d, ok := m[a.Name()] + if !ok { + return fmt.Errorf("not found defined-set: %s", a.Name()) + } + if all { + if r.InUse(d) { + err = fmt.Errorf("can't delete. defined-set %s is in use", a.Name()) + } else { + delete(m, a.Name()) + } + } else { + err = d.Remove(a) + } + } + return err +} + +func (r *RoutingPolicy) ReplaceDefinedSet(a DefinedSet) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + if m, ok := r.DefinedSetMap[a.Type()]; !ok { + err = fmt.Errorf("invalid defined-set type: %d", a.Type()) + } else { + if d, ok := m[a.Name()]; !ok { + err = fmt.Errorf("not found defined-set: %s", a.Name()) + } else { + err = d.Replace(a) + } + } + return err +} + +func (r *RoutingPolicy) GetStatement() []*config.Statement { + r.mu.RLock() + defer r.mu.RUnlock() + + l := make([]*config.Statement, 0, len(r.StatementMap)) + for _, st := range r.StatementMap { + l = append(l, st.ToConfig()) + } + return l +} + +func (r *RoutingPolicy) AddStatement(st *Statement) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + for _, c := range st.Conditions { + if err = r.ValidateCondition(c); err != nil { + return + } + } + m := r.StatementMap + name := st.Name + if d, ok := m[name]; ok { + err = d.Add(st) + } else { + m[name] = st + } + + return err +} + +func (r *RoutingPolicy) DeleteStatement(st *Statement, all bool) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + m := r.StatementMap + name := st.Name + if d, ok := m[name]; ok { + if all { + if r.StatementInUse(d) { + err = fmt.Errorf("can't delete. statement %s is in use", name) + } else { + delete(m, name) + } + } else { + err = d.Remove(st) + } + } else { + err = fmt.Errorf("not found statement: %s", name) + } + return err +} + +func (r *RoutingPolicy) ReplaceStatement(st *Statement) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + m := r.StatementMap + name := st.Name + if d, ok := m[name]; ok { + err = d.Replace(st) + } else { + err = fmt.Errorf("not found statement: %s", name) + } + return err +} + +func (r *RoutingPolicy) GetAllPolicy() []*config.PolicyDefinition { + r.mu.RLock() + defer r.mu.RUnlock() + + l := make([]*config.PolicyDefinition, 0, len(r.PolicyMap)) + for _, p := range r.PolicyMap { + l = append(l, p.ToConfig()) + } + return l +} + +func (r *RoutingPolicy) AddPolicy(x *Policy, refer bool) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + for _, st := range x.Statements { + for _, c := range st.Conditions { + if err = r.ValidateCondition(c); err != nil { + return + } + } + } + + pMap := r.PolicyMap + sMap := r.StatementMap + name := x.Name + y, ok := pMap[name] + if refer { + err = x.FillUp(sMap) + } else { + for _, st := range x.Statements { + if _, ok := sMap[st.Name]; ok { + err = fmt.Errorf("statement %s already defined", st.Name) + return + } + sMap[st.Name] = st + } + } + if ok { + err = y.Add(x) + } else { + pMap[name] = x + } + + return err +} + +func (r *RoutingPolicy) DeletePolicy(x *Policy, all, preserve bool, activeId []string) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + pMap := r.PolicyMap + sMap := r.StatementMap + name := x.Name + y, ok := pMap[name] + if !ok { + err = fmt.Errorf("not found policy: %s", name) + return + } + inUse := func(ids []string) bool { + for _, id := range ids { + for _, dir := range []PolicyDirection{POLICY_DIRECTION_IN, POLICY_DIRECTION_EXPORT, POLICY_DIRECTION_EXPORT} { + for _, y := range r.GetPolicy(id, dir) { + if x.Name == y.Name { + return true + } + } + } + } + return false + } + + if all { + if inUse(activeId) { + err = fmt.Errorf("can't delete. policy %s is in use", name) + return + } + log.WithFields(log.Fields{ + "Topic": "Policy", + "Key": name, + }).Debug("delete policy") + delete(pMap, name) + } else { + err = y.Remove(x) + } + if err == nil && !preserve { + for _, st := range y.Statements { + if !r.StatementInUse(st) { + log.WithFields(log.Fields{ + "Topic": "Policy", + "Key": st.Name, + }).Debug("delete unused statement") + delete(sMap, st.Name) + } + } + } + return err +} + +func (r *RoutingPolicy) ReplacePolicy(x *Policy, refer, preserve bool) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + for _, st := range x.Statements { + for _, c := range st.Conditions { + if err = r.ValidateCondition(c); err != nil { + return + } + } + } + + pMap := r.PolicyMap + sMap := r.StatementMap + name := x.Name + y, ok := pMap[name] + if !ok { + err = fmt.Errorf("not found policy: %s", name) + return + } + if refer { + if err = x.FillUp(sMap); err != nil { + return + } + } else { + for _, st := range x.Statements { + if _, ok := sMap[st.Name]; ok { + err = fmt.Errorf("statement %s already defined", st.Name) + return + } + sMap[st.Name] = st + } + } + + err = y.Replace(x) + if err == nil && !preserve { + for _, st := range y.Statements { + if !r.StatementInUse(st) { + log.WithFields(log.Fields{ + "Topic": "Policy", + "Key": st.Name, + }).Debug("delete unused statement") + delete(sMap, st.Name) + } + } + } + return err +} + +func (r *RoutingPolicy) GetPolicyAssignment(id string, dir PolicyDirection) (RouteType, []*config.PolicyDefinition, error) { + r.mu.RLock() + defer r.mu.RUnlock() + + rt := r.GetDefaultPolicy(id, dir) + + ps := r.GetPolicy(id, dir) + l := make([]*config.PolicyDefinition, 0, len(ps)) + for _, p := range ps { + l = append(l, p.ToConfig()) + } + return rt, l, nil +} + +func (r *RoutingPolicy) AddPolicyAssignment(id string, dir PolicyDirection, policies []*config.PolicyDefinition, def RouteType) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + ps := make([]*Policy, 0, len(policies)) + seen := make(map[string]bool) + for _, x := range policies { + p, ok := r.PolicyMap[x.Name] + if !ok { + err = fmt.Errorf("not found policy %s", x.Name) + return + } + if seen[x.Name] { + err = fmt.Errorf("duplicated policy %s", x.Name) + return + } + seen[x.Name] = true + ps = append(ps, p) + } + cur := r.GetPolicy(id, dir) + if cur == nil { + err = r.SetPolicy(id, dir, ps) + } else { + seen = make(map[string]bool) + ps = append(cur, ps...) + for _, x := range ps { + if seen[x.Name] { + err = fmt.Errorf("duplicated policy %s", x.Name) + return + } + seen[x.Name] = true + } + err = r.SetPolicy(id, dir, ps) + } + if err == nil && def != ROUTE_TYPE_NONE { + err = r.SetDefaultPolicy(id, dir, def) + } + return err +} + +func (r *RoutingPolicy) DeletePolicyAssignment(id string, dir PolicyDirection, policies []*config.PolicyDefinition, all bool) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + ps := make([]*Policy, 0, len(policies)) + seen := make(map[string]bool) + for _, x := range policies { + p, ok := r.PolicyMap[x.Name] + if !ok { + err = fmt.Errorf("not found policy %s", x.Name) + return + } + if seen[x.Name] { + err = fmt.Errorf("duplicated policy %s", x.Name) + return + } + seen[x.Name] = true + ps = append(ps, p) + } + cur := r.GetPolicy(id, dir) + + if all { + err = r.SetPolicy(id, dir, nil) + if err != nil { + return + } + err = r.SetDefaultPolicy(id, dir, ROUTE_TYPE_NONE) + } else { + n := make([]*Policy, 0, len(cur)-len(ps)) + for _, y := range cur { + found := false + for _, x := range ps { + if x.Name == y.Name { + found = true + break + } + } + if !found { + n = append(n, y) + } + } + err = r.SetPolicy(id, dir, n) + } + return err +} + +func (r *RoutingPolicy) ReplacePolicyAssignment(id string, dir PolicyDirection, policies []*config.PolicyDefinition, def RouteType) (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + ps := make([]*Policy, 0, len(policies)) + seen := make(map[string]bool) + for _, x := range policies { + p, ok := r.PolicyMap[x.Name] + if !ok { + err = fmt.Errorf("not found policy %s", x.Name) + return + } + if seen[x.Name] { + err = fmt.Errorf("duplicated policy %s", x.Name) + return + } + seen[x.Name] = true + ps = append(ps, p) + } + r.GetPolicy(id, dir) + err = r.SetPolicy(id, dir, ps) + if err == nil && def != ROUTE_TYPE_NONE { + err = r.SetDefaultPolicy(id, dir, def) + } + return err +} + +func (r *RoutingPolicy) Reset(rp *config.RoutingPolicy, ap map[string]config.ApplyPolicy) error { + r.mu.Lock() + defer r.mu.Unlock() + + if rp != nil { + if err := r.Reload(*rp); err != nil { + log.WithFields(log.Fields{ + "Topic": "Policy", + }).Errorf("failed to create routing policy: %s", err) + return err + } + } + + for id, c := range ap { + for _, dir := range []PolicyDirection{POLICY_DIRECTION_IN, POLICY_DIRECTION_IMPORT, POLICY_DIRECTION_EXPORT} { + ps, def, err := r.GetAssignmentFromConfig(dir, c) + if err != nil { + log.WithFields(log.Fields{ + "Topic": "Policy", + "Dir": dir, + }).Errorf("failed to get policy info: %s", err) + continue + } + r.SetDefaultPolicy(id, dir, def) + r.SetPolicy(id, dir, ps) + } + } + return nil +} + func NewRoutingPolicy() *RoutingPolicy { return &RoutingPolicy{ DefinedSetMap: make(map[DefinedType]map[string]DefinedSet), |