diff options
-rw-r--r-- | api/gobgp.pb.go | 49 | ||||
-rw-r--r-- | api/gobgp.proto | 17 | ||||
-rw-r--r-- | gobgp/common.go | 19 | ||||
-rw-r--r-- | gobgp/neighbor.go | 12 | ||||
-rw-r--r-- | gobgp/policy.go | 280 | ||||
-rw-r--r-- | policy/policy.go | 111 | ||||
-rw-r--r-- | server/grpc_server.go | 22 | ||||
-rw-r--r-- | server/server.go | 166 |
8 files changed, 591 insertions, 85 deletions
diff --git a/api/gobgp.pb.go b/api/gobgp.pb.go index 32ace22d..060aaa68 100644 --- a/api/gobgp.pb.go +++ b/api/gobgp.pb.go @@ -38,7 +38,9 @@ It has these top-level messages: NeighborSet AsPathLength AsPathSet + CommunitySet Conditions + CommunityAction Actions Statement PolicyDefinition @@ -70,7 +72,8 @@ const ( Resource_POLICY_PREFIX Resource = 4 Resource_POLICY_NEIGHBOR Resource = 5 Resource_POLICY_ASPATH Resource = 6 - Resource_POLICY_ROUTEPOLICY Resource = 7 + Resource_POLICY_COMMUNITY Resource = 7 + Resource_POLICY_ROUTEPOLICY Resource = 8 ) var Resource_name = map[int32]string{ @@ -81,7 +84,8 @@ var Resource_name = map[int32]string{ 4: "POLICY_PREFIX", 5: "POLICY_NEIGHBOR", 6: "POLICY_ASPATH", - 7: "POLICY_ROUTEPOLICY", + 7: "POLICY_COMMUNITY", + 8: "POLICY_ROUTEPOLICY", } var Resource_value = map[string]int32{ "GLOBAL": 0, @@ -91,7 +95,8 @@ var Resource_value = map[string]int32{ "POLICY_PREFIX": 4, "POLICY_NEIGHBOR": 5, "POLICY_ASPATH": 6, - "POLICY_ROUTEPOLICY": 7, + "POLICY_COMMUNITY": 7, + "POLICY_ROUTEPOLICY": 8, } func (x Resource) String() string { @@ -1007,12 +1012,22 @@ func (m *AsPathSet) Reset() { *m = AsPathSet{} } func (m *AsPathSet) String() string { return proto.CompactTextString(m) } func (*AsPathSet) ProtoMessage() {} +type CommunitySet struct { + CommunitySetName string `protobuf:"bytes,1,opt,name=community_set_name" json:"community_set_name,omitempty"` + CommunityMembers []string `protobuf:"bytes,2,rep,name=community_members" json:"community_members,omitempty"` +} + +func (m *CommunitySet) Reset() { *m = CommunitySet{} } +func (m *CommunitySet) String() string { return proto.CompactTextString(m) } +func (*CommunitySet) ProtoMessage() {} + type Conditions struct { MatchPrefixSet *PrefixSet `protobuf:"bytes,1,opt,name=match_prefix_set" json:"match_prefix_set,omitempty"` MatchNeighborSet *NeighborSet `protobuf:"bytes,2,opt,name=match_neighbor_set" json:"match_neighbor_set,omitempty"` MatchAsPathLength *AsPathLength `protobuf:"bytes,3,opt,name=match_as_path_length" json:"match_as_path_length,omitempty"` MatchAsPathSet *AsPathSet `protobuf:"bytes,4,opt,name=match_as_path_set" json:"match_as_path_set,omitempty"` - MatchSetOptions string `protobuf:"bytes,5,opt,name=match_set_options" json:"match_set_options,omitempty"` + MatchCommunitySet *CommunitySet `protobuf:"bytes,5,opt,name=match_community_set" json:"match_community_set,omitempty"` + MatchSetOptions string `protobuf:"bytes,6,opt,name=match_set_options" json:"match_set_options,omitempty"` } func (m *Conditions) Reset() { *m = Conditions{} } @@ -1047,14 +1062,38 @@ func (m *Conditions) GetMatchAsPathSet() *AsPathSet { return nil } +func (m *Conditions) GetMatchCommunitySet() *CommunitySet { + if m != nil { + return m.MatchCommunitySet + } + return nil +} + +type CommunityAction struct { + Communities []string `protobuf:"bytes,1,rep,name=communities" json:"communities,omitempty"` + Options string `protobuf:"bytes,2,opt,name=options" json:"options,omitempty"` +} + +func (m *CommunityAction) Reset() { *m = CommunityAction{} } +func (m *CommunityAction) String() string { return proto.CompactTextString(m) } +func (*CommunityAction) ProtoMessage() {} + type Actions struct { - RouteAction string `protobuf:"bytes,1,opt,name=route_action" json:"route_action,omitempty"` + RouteAction string `protobuf:"bytes,1,opt,name=route_action" json:"route_action,omitempty"` + Community *CommunityAction `protobuf:"bytes,2,opt,name=community" json:"community,omitempty"` } func (m *Actions) Reset() { *m = Actions{} } func (m *Actions) String() string { return proto.CompactTextString(m) } func (*Actions) ProtoMessage() {} +func (m *Actions) GetCommunity() *CommunityAction { + if m != nil { + return m.Community + } + return nil +} + type Statement struct { StatementNeme string `protobuf:"bytes,1,opt,name=statement_neme" json:"statement_neme,omitempty"` Conditions *Conditions `protobuf:"bytes,2,opt,name=conditions" json:"conditions,omitempty"` diff --git a/api/gobgp.proto b/api/gobgp.proto index e61c2243..b4beb1c2 100644 --- a/api/gobgp.proto +++ b/api/gobgp.proto @@ -76,7 +76,8 @@ enum Resource { POLICY_PREFIX = 4; POLICY_NEIGHBOR = 5; POLICY_ASPATH = 6; - POLICY_ROUTEPOLICY = 7; + POLICY_COMMUNITY = 7; + POLICY_ROUTEPOLICY = 8; } enum Operation { @@ -379,16 +380,28 @@ message AsPathSet { repeated string as_path_members = 2; } +message CommunitySet { + string community_set_name = 1; + repeated string community_members = 2; +} + message Conditions { PrefixSet match_prefix_set = 1; NeighborSet match_neighbor_set = 2; AsPathLength match_as_path_length = 3; AsPathSet match_as_path_set = 4; - string match_set_options = 5; + CommunitySet match_community_set = 5; + string match_set_options = 6; +} + +message CommunityAction { + repeated string communities = 1; + string options = 2; } message Actions { string route_action = 1; + CommunityAction community = 2; } message Statement { diff --git a/gobgp/common.go b/gobgp/common.go index 1d47ea1e..d7d9e2c4 100644 --- a/gobgp/common.go +++ b/gobgp/common.go @@ -46,6 +46,7 @@ const ( CMD_DISABLE = "disable" CMD_PREFIX = "prefix" CMD_ASPATH = "aspath" + CMD_COMMUNITY = "community" CMD_ROUTEPOLICY = "routepolicy" CMD_CONDITIONS = "conditions" CMD_ACTIONS = "actions" @@ -65,12 +66,14 @@ var conditionOpts struct { Prefix string `long:"prefix" description:"specifying a prefix set name of policy"` Neighbor string `long:"neighbor" description:"specifying a neighbor set name of policy"` AsPath string `long:"aspath" description:"specifying an as set name of policy"` + Community string `long:"community" description:"specifying a community set name of policy"` AsPathLength string `long:"aspath-len" description:"specifying an as path length of policy (<operator>,<numeric>)"` Option string `long:"option" description:"specifying an option of policy (any | all | invert)"` } var actionOpts struct { - RouteAction string `long:"route-action" description:"specifying a route action of policy (accept | reject)"` + RouteAction string `long:"route-action" description:"specifying a route action of policy (accept | reject)"` + CommunityAction string `long:"community" description:"specifying a community action of policy"` } func formatTimedelta(d int64) string { @@ -213,6 +216,20 @@ func (a aspaths) Less(i, j int) bool { return a[i].AsPathSetName < a[j].AsPathSetName } +type communities []*api.CommunitySet + +func (c communities) Len() int { + return len(c) +} + +func (c communities) Swap(i, j int) { + c[i], c[j] = c[j], c[i] +} + +func (c communities) Less(i, j int) bool { + return c[i].CommunitySetName < c[j].CommunitySetName +} + type policyDefinitions []*api.PolicyDefinition func (p policyDefinitions) Len() int { diff --git a/gobgp/neighbor.go b/gobgp/neighbor.go index ed060fd2..8d311f9b 100644 --- a/gobgp/neighbor.go +++ b/gobgp/neighbor.go @@ -535,18 +535,6 @@ func showNeighborPolicy(remoteIP net.IP) error { return nil } -func parseRouteAction(rType string) (string, error) { - routeActionUpper := strings.ToUpper(rType) - var routeAction string - switch routeActionUpper { - case policy.ROUTE_ACCEPT, policy.ROUTE_REJECT: - routeAction = routeActionUpper - default: - return "", fmt.Errorf("invalid route action: %s\nPlease enter the accept or reject", rType) - } - return routeAction, nil -} - func parsePolicy(pNames string) []*api.PolicyDefinition { pList := strings.Split(pNames, ",") policyList := make([]*api.PolicyDefinition, 0, len(pList)) diff --git a/gobgp/policy.go b/gobgp/policy.go index 1939a12d..1c76edbd 100644 --- a/gobgp/policy.go +++ b/gobgp/policy.go @@ -24,10 +24,10 @@ import ( "golang.org/x/net/context" "io" "net" + "regexp" "sort" "strconv" "strings" - "regexp" ) func formatPolicyPrefix(prefixSetList []*api.PrefixSet) (string, string) { @@ -195,6 +195,8 @@ func modPolicy(resource api.Resource, op api.Operation, data interface{}) error co.MatchNeighborSet = data.(*api.NeighborSet) case api.Resource_POLICY_ASPATH: co.MatchAsPathSet = data.(*api.AsPathSet) + case api.Resource_POLICY_COMMUNITY: + co.MatchCommunitySet = data.(*api.CommunitySet) } pd.StatementList = []*api.Statement{{Conditions: co}} } else { @@ -443,7 +445,6 @@ func formatPolicyAsPath(asPathSetList []*api.AsPathSet) string { return format } - func showPolicyAsPaths() error { arg := &api.PolicyArguments{ Resource: api.Resource_POLICY_ASPATH, @@ -576,6 +577,171 @@ func modPolicyAsPath(modtype string, eArgs []string) error { return nil } +func formatPolicyCommunity(CommunitySetList []*api.CommunitySet) string { + maxNameLen := len("Name") + maxCommunityLen := len("Community") + for _, cs := range CommunitySetList { + if len(cs.CommunitySetName) > maxNameLen { + maxNameLen = len(cs.CommunitySetName) + } + for _, m := range cs.CommunityMembers { + if len(m) > maxCommunityLen { + maxCommunityLen = len(m) + } + } + } + format := "%-" + fmt.Sprint(maxNameLen) + "s %-" + fmt.Sprint(maxCommunityLen) + "s\n" + return format +} + +func showPolicyCommunities() error { + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_COMMUNITY, + } + stream, e := client.GetPolicyRoutePolicies(context.Background(), arg) + if e != nil { + return e + } + m := communities{} + for { + a, e := stream.Recv() + if e == io.EOF { + break + } else if e != nil { + return e + } + m = append(m, a.StatementList[0].Conditions.MatchCommunitySet) + } + if globalOpts.Json { + j, _ := json.Marshal(m) + fmt.Println(string(j)) + return nil + } + if globalOpts.Quiet { + for _, c := range m { + fmt.Println(c.CommunitySetName) + } + return nil + } + sort.Sort(m) + + format := formatPolicyCommunity(m) + fmt.Printf(format, "Name", "Community") + for _, cs := range m { + for i, m := range cs.CommunityMembers { + if i == 0 { + fmt.Printf(format, cs.CommunitySetName, m) + } else { + fmt.Printf(format, "", m) + } + } + } + return nil +} + +func showPolicyCommunity(args []string) error { + arg := &api.PolicyArguments{ + Resource: api.Resource_POLICY_COMMUNITY, + Name: args[0], + } + pd, e := client.GetPolicyRoutePolicy(context.Background(), arg) + if e != nil { + return e + } + cs := pd.StatementList[0].Conditions.GetMatchCommunitySet() + if globalOpts.Json { + j, _ := json.Marshal(cs) + fmt.Println(string(j)) + return nil + } + if globalOpts.Quiet { + for _, c := range cs.CommunityMembers { + fmt.Println(c) + } + return nil + } + format := formatPolicyCommunity([]*api.CommunitySet{cs}) + fmt.Printf(format, "Name", "Community") + for i, m := range cs.CommunityMembers { + if i == 0 { + fmt.Printf(format, cs.CommunitySetName, m) + } else { + fmt.Printf(format, "", m) + } + } + return nil +} + +func checkCommunityFormat(comStr string) bool { + // community regexp + regUint, _ := regexp.Compile("^([0-9]+)$") + regString, _ := regexp.Compile("([0-9]+):([0-9]+)") + regWellKnown, _ := regexp.Compile("^(" + + policy.COMMUNITY_INTERNET + "|" + + policy.COMMUNITY_NO_EXPORT + "|" + + policy.COMMUNITY_NO_ADVERTISE + "|" + + policy.COMMUNITY_NO_EXPORT_SUBCONFED + ")$") + if regUint.MatchString(comStr) || regString.MatchString(comStr) || regWellKnown.MatchString(comStr) { + return true + } + return false +} + +func parseCommunitySet(eArgs []string) (*api.CommunitySet, error) { + if !checkCommunityFormat(eArgs[1]) { + if _, err := regexp.Compile(eArgs[1]); err != nil { + return nil, fmt.Errorf("invalid community: %s\nplease enter community format", eArgs[1]) + } + } + communitySet := &api.CommunitySet{ + CommunitySetName: eArgs[0], + CommunityMembers: []string{eArgs[1]}, + } + return communitySet, nil +} + +func modPolicyCommunity(modtype string, eArgs []string) error { + communitySet := &api.CommunitySet{} + var e error + var operation api.Operation + + switch modtype { + case CMD_ADD: + if len(eArgs) < 2 { + return fmt.Errorf("usage: policy community add <community set name> <community>") + } + if communitySet, e = parseCommunitySet(eArgs); e != nil { + return e + } + operation = api.Operation_ADD + case CMD_DEL: + if len(eArgs) == 0 { + return fmt.Errorf("usage: policy community add <community set name> [<community>]") + } else if len(eArgs) == 1 { + communitySet = &api.CommunitySet{ + CommunitySetName: eArgs[0], + CommunityMembers: nil, + } + } else { + if communitySet, e = parseCommunitySet(eArgs); e != nil { + return e + } + } + operation = api.Operation_DEL + case CMD_ALL: + if len(eArgs) > 0 { + return fmt.Errorf("Argument can not be entered: %s", eArgs[0:]) + } + operation = api.Operation_DEL_ALL + default: + return fmt.Errorf("invalid modType %s", modtype) + } + if e = modPolicy(api.Resource_POLICY_COMMUNITY, operation, communitySet); e != nil { + return e + } + return nil +} + func showPolicyStatement(head string, pd *api.PolicyDefinition) { for _, st := range pd.StatementList { fmt.Printf("%s StatementName %s:\n", head, st.StatementNeme) @@ -624,10 +790,31 @@ func showPolicyStatement(head string, pd *api.PolicyDefinition) { } else { fmt.Print("\n") } + communitySet := st.Conditions.MatchCommunitySet + fmt.Printf("%s CommunitySet: %s ", head, communitySet.CommunitySetName) + if len(communitySet.CommunityMembers) != 0 { + nameFormat := "%-" + fmt.Sprint(len(communitySet.CommunitySetName)+2) + "s" + for i, community := range communitySet.CommunityMembers { + if i != 0 { + fmt.Printf("%s ", head) + fmt.Printf(nameFormat, "") + } + fmt.Println(community) + } + } else { + fmt.Print("\n") + } asPathLentgh := st.Conditions.MatchAsPathLength fmt.Printf("%s AsPathLength: %s %s\n", head, asPathLentgh.Operator, asPathLentgh.Value) fmt.Printf("%s MatchOption: %s\n", head, st.Conditions.MatchSetOptions) fmt.Printf("%s Actions:\n", head) + + communityAction := st.Actions.Community.Options + if len(st.Actions.Community.Communities) != 0 || st.Actions.Community.Options == "NULL" { + communities := strings.Join(st.Actions.Community.Communities, ",") + communityAction = fmt.Sprintf("%s[%s]", st.Actions.Community.Options, communities) + } + fmt.Printf("%s Community: %s\n", head, communityAction) fmt.Printf("%s %s\n", head, st.Actions.RouteAction) } @@ -717,6 +904,11 @@ func parseConditions() (*api.Conditions, error) { AsPathSetName: conditionOpts.AsPath, } } + if conditionOpts.Community != "" { + conditions.MatchCommunitySet = &api.CommunitySet{ + CommunitySetName: conditionOpts.Community, + } + } if conditionOpts.AsPathLength != "" { asPathLen := conditionOpts.AsPathLength idx := strings.Index(asPathLen, ",") @@ -748,6 +940,64 @@ func parseConditions() (*api.Conditions, error) { return conditions, nil } +func parseRouteAction(rType string) (string, error) { + routeActionUpper := strings.ToUpper(rType) + var routeAction string + switch routeActionUpper { + case policy.ROUTE_ACCEPT, policy.ROUTE_REJECT: + routeAction = routeActionUpper + default: + return "", fmt.Errorf("invalid route action: %s\nPlease enter the accept or reject", rType) + } + return routeAction, nil +} + +func parseCommunityAction(communityStr string) (*api.CommunityAction, error) { + regStr, _ := regexp.Compile("^(.*)\\[(.*)\\]$") + var communities, option string + communityList := make([]string, 0) + if regStr.MatchString(communityStr) { + group := regStr.FindStringSubmatch(communityStr) + option = group[1] + communities = group[2] + + // check options + communityActionTypes := policy.COMMUNITY_ACTION_ADD + "|" + + policy.COMMUNITY_ACTION_REPLACE + "|" + + policy.COMMUNITY_ACTION_REMOVE + "|" + + policy.COMMUNITY_ACTION_NULL + regOption, _ := regexp.Compile(fmt.Sprintf("^(%s)$", communityActionTypes)) + if !regOption.MatchString(option) { + e := fmt.Sprintf("invalid Option: %s\n", option) + e += fmt.Sprintf("please enter the (%s)", communityActionTypes) + return nil, fmt.Errorf("%s", e) + } + // check the relationship between the community and the option + if option == "NULL" && communities != "" { + e := "invalid relationship between community and option\n" + e += "When the option is NULL, community should not be input" + return nil, fmt.Errorf("%s", e) + } else if !(communities == "" && option == "NULL") { + // check communities + communityList = strings.Split(communities, ",") + for _, community := range communityList { + if !checkCommunityFormat(community) { + return nil, fmt.Errorf("invalid Community %s:", community) + } + } + } + } else { + e := fmt.Sprintf("invalid format: %s\n", communityStr) + e += "please enter the <option>[<comunity>,<comunity>,...]" + return nil, fmt.Errorf("%s", e) + } + communityAction := &api.CommunityAction{ + Communities: communityList, + Options: option, + } + return communityAction, nil +} + func parseActions() (*api.Actions, error) { actions := &api.Actions{} if actionOpts.RouteAction != "" { @@ -757,6 +1007,14 @@ func parseActions() (*api.Actions, error) { } actions.RouteAction = routeAction } + if actionOpts.CommunityAction != "" { + community, e := parseCommunityAction(actionOpts.CommunityAction) + if e != nil { + return nil, e + } + + actions.Community = community + } return actions, nil } @@ -772,18 +1030,18 @@ func modPolicyRoutePolicy(modtype string, eArgs []string) error { if len(eArgs) != 2 { return fmt.Errorf("usage: gobgp policy routepoilcy add <route policy name> <statement name>") } - stmt := &api.Statement{} + stmt := &api.Statement{ + StatementNeme: eArgs[1], + } conditions, err := parseConditions() if err != nil { return err } - stmt.Conditions = conditions - actions, err := parseActions() if err != nil { return err } - stmt.StatementNeme = eArgs[1] + stmt.Conditions = conditions stmt.Actions = actions pd.StatementList = []*api.Statement{stmt} @@ -828,10 +1086,12 @@ func NewPolicyAddCmd(v string, mod func(string, []string) error) *cobra.Command if v == CMD_ROUTEPOLICY { policyAddCmd.Flags().StringVarP(&conditionOpts.Prefix, "c-prefix", "", "", "a prefix set name of policy condition") policyAddCmd.Flags().StringVarP(&conditionOpts.Neighbor, "c-neighbor", "", "", "a neighbor set name of policy condition") - policyAddCmd.Flags().StringVarP(&conditionOpts.Neighbor, "c-aspath", "", "", "as set name of policy condition") + policyAddCmd.Flags().StringVarP(&conditionOpts.AsPath, "c-aspath", "", "", "an as path set name of policy condition") + policyAddCmd.Flags().StringVarP(&conditionOpts.Community, "c-community", "", "", "a community set name of policy condition") policyAddCmd.Flags().StringVarP(&conditionOpts.AsPathLength, "c-aslen", "", "", "an as path length of policy condition (<operator>,<numeric>)") policyAddCmd.Flags().StringVarP(&conditionOpts.Option, "c-option", "", "", "an option of policy condition") policyAddCmd.Flags().StringVarP(&actionOpts.RouteAction, "a-route", "", "", "a route action of policy action (accept | reject)") + policyAddCmd.Flags().StringVarP(&actionOpts.CommunityAction, "a-community", "", "", "a community of policy action") } return policyAddCmd @@ -866,7 +1126,7 @@ func NewPolicyCmd() *cobra.Command { Use: CMD_POLICY, } - for _, v := range []string{CMD_PREFIX, CMD_NEIGHBOR, CMD_ASPATH, CMD_ROUTEPOLICY} { + for _, v := range []string{CMD_PREFIX, CMD_NEIGHBOR, CMD_ASPATH, CMD_COMMUNITY, CMD_ROUTEPOLICY} { var showAll func() error var showOne func([]string) error var mod func(string, []string) error @@ -883,6 +1143,10 @@ func NewPolicyCmd() *cobra.Command { showAll = showPolicyAsPaths showOne = showPolicyAsPath mod = modPolicyAsPath + case CMD_COMMUNITY: + showAll = showPolicyCommunities + showOne = showPolicyCommunity + mod = modPolicyCommunity case CMD_ROUTEPOLICY: showAll = showPolicyRoutePolicies showOne = showPolicyRoutePolicy diff --git a/policy/policy.go b/policy/policy.go index 27dc3c53..942aa70f 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -353,9 +353,9 @@ func (c *AsPathLengthCondition) evaluate(path table.Path) bool { if result { log.WithFields(log.Fields{ - "Topic": "Policy", + "Topic": "Policy", "Condition": "aspath length", - "Reason": c.Operator, + "Reason": c.Operator, }).Debug("condition matched") } @@ -473,10 +473,10 @@ func (c *AsPathCondition) evaluate(path table.Path) bool { if matched { log.WithFields(log.Fields{ - "Topic": "Policy", + "Topic": "Policy", "Condition": "aspath length", - "ASN": member.asn, - "Position": member.postiion, + "ASN": member.asn, + "Position": member.postiion, }).Debug("condition matched") return true } @@ -665,7 +665,7 @@ func (c *CommunityCondition) evaluate(path table.Path) bool { if matched { log.WithFields(log.Fields{ - "Topic": "Policy", + "Topic": "Policy", "Condition": "Community", "Community": makeStr(communities[idx]), }).Debug("condition matched") @@ -729,7 +729,7 @@ func NewCommunityAction(action config.SetCommunity) *CommunityAction { m := &CommunityAction{} - if len(action.Communities) == 0 && action.Options != COMMUNITY_ACTION_NULL{ + if len(action.Communities) == 0 && action.Options != COMMUNITY_ACTION_NULL { return nil } @@ -1009,6 +1009,29 @@ func IndexOfAsPathSet(conAsPathSetList []config.AsPathSet, reqAsPathSet config.A return idxAsPathSet, idxAsPath } +// find index CommunitySet of request from CommunitySet of configuration file. +// Return the idxCommunitySet of the location where the name of CommunitySet matches, +// and idxCommunity of the location where element of CommunitySet matches +func IndexOfCommunitySet(conCommunitySetList []config.CommunitySet, reqCommunitySet config.CommunitySet) (int, int) { + idxCommunitySet := -1 + idxCommunity := -1 + for i, conCommunitySet := range conCommunitySetList { + if conCommunitySet.CommunitySetName == reqCommunitySet.CommunitySetName { + idxCommunitySet = i + if len(reqCommunitySet.CommunityMembers) == 0 { + return idxCommunitySet, idxCommunity + } + for j, conCommunity := range conCommunitySet.CommunityMembers { + if conCommunity == reqCommunitySet.CommunityMembers[0] { + idxCommunity = j + return idxCommunitySet, idxCommunity + } + } + } + } + return idxCommunitySet, idxCommunity +} + // find index PolicyDefinition of request from PolicyDefinition of configuration file. // Return the idxPolicyDefinition of the location where the name of PolicyDefinition matches, // and idxStatement of the location where Statement of PolicyDefinition matches @@ -1138,6 +1161,30 @@ func AsPathSetToConfigStruct(reqAsPathSet *api.AsPathSet) (bool, config.AsPathSe return isAsPathSetSet, asPathSet } +func CommunitySetToApiStruct(cs config.CommunitySet) *api.CommunitySet { + resCommunityMembers := make([]string, 0) + for _, m := range cs.CommunityMembers { + resCommunityMembers = append(resCommunityMembers, m) + } + resCommunitySet := &api.CommunitySet{ + CommunitySetName: cs.CommunitySetName, + CommunityMembers: resCommunityMembers, + } + return resCommunitySet +} + +func CommunitySetToConfigStruct(reqCommunitySet *api.CommunitySet) (bool, config.CommunitySet) { + isCommunitySet := true + if len(reqCommunitySet.CommunityMembers) == 0 { + isCommunitySet = false + } + communitySet := config.CommunitySet{ + CommunitySetName: reqCommunitySet.CommunitySetName, + CommunityMembers: reqCommunitySet.CommunityMembers, + } + return isCommunitySet, communitySet +} + func AsPathLengthToApiStruct(asPathLength config.AsPathLength) *api.AsPathLength { value := "" if asPathLength.Operator != "" { @@ -1172,6 +1219,9 @@ func ConditionsToConfigStruct(reqConditions *api.Conditions) config.Conditions { if reqConditions.MatchAsPathSet != nil { conditions.BgpConditions.MatchAsPathSet = reqConditions.MatchAsPathSet.AsPathSetName } + if reqConditions.MatchCommunitySet != nil { + conditions.BgpConditions.MatchCommunitySet = reqConditions.MatchCommunitySet.CommunitySetName + } if reqConditions.MatchAsPathLength != nil { conditions.BgpConditions.AsPathLength = AsPathLengthToConfigStruct(reqConditions.MatchAsPathLength) @@ -1189,8 +1239,28 @@ func ConditionsToConfigStruct(reqConditions *api.Conditions) config.Conditions { return conditions } +func ActionsToApiStruct(conActions config.Actions) *api.Actions { + action := ROUTE_REJECT + if conActions.AcceptRoute { + action = ROUTE_ACCEPT + } + communityAction := &api.CommunityAction{ + Communities: conActions.BgpActions.SetCommunity.Communities, + Options: conActions.BgpActions.SetCommunity.Options, + } + resActions := &api.Actions{ + RouteAction: action, + Community: communityAction, + } + return resActions +} + func ActionsToConfigStruct(reqActions *api.Actions) config.Actions { actions := config.Actions{} + if reqActions.Community != nil { + actions.BgpActions.SetCommunity.Communities = reqActions.Community.Communities + actions.BgpActions.SetCommunity.Options = reqActions.Community.Options + } switch reqActions.RouteAction { case ROUTE_ACCEPT: actions.AcceptRoute = true @@ -1202,13 +1272,9 @@ func ActionsToConfigStruct(reqActions *api.Actions) config.Actions { func StatementToConfigStruct(reqStatement *api.Statement) config.Statement { statement := config.Statement{ - Name: reqStatement.StatementNeme, - } - if reqStatement.Conditions != nil { - statement.Conditions = ConditionsToConfigStruct(reqStatement.Conditions) - } - if reqStatement.Actions != nil { - statement.Actions = ActionsToConfigStruct(reqStatement.Actions) + Name: reqStatement.StatementNeme, + Conditions: ConditionsToConfigStruct(reqStatement.Conditions), + Actions: ActionsToConfigStruct(reqStatement.Actions), } return statement } @@ -1231,6 +1297,7 @@ func PolicyDefinitionToApiStruct(pd config.PolicyDefinition, df config.DefinedSe conPrefixSetList := df.PrefixSetList conNeighborSetList := df.NeighborSetList conAsPathSetList := df.BgpDefinedSets.AsPathSetList + conCommunitySetList := df.BgpDefinedSets.CommunitySetList resStatementList := make([]*api.Statement, 0) for _, st := range pd.StatementList { conditions := st.Conditions @@ -1245,13 +1312,18 @@ func PolicyDefinitionToApiStruct(pd config.PolicyDefinition, df config.DefinedSe asPathSet := &api.AsPathSet{ AsPathSetName: conditions.BgpConditions.MatchAsPathSet, } + communitySet := &api.CommunitySet{ + CommunitySetName: conditions.BgpConditions.MatchCommunitySet, + } // consider later whether treatment of here need _, conPrefixSet := PrefixSetToConfigStruct(prefixSet) _, conNeighborSet := NeighborSetToConfigStruct(neighborSet) _, conAsPathSet := AsPathSetToConfigStruct(asPathSet) + _, conCommunitySet := CommunitySetToConfigStruct(communitySet) idxPrefixSet, _ := IndexOfPrefixSet(conPrefixSetList, conPrefixSet) idxNeighborSet, _ := IndexOfNeighborSet(conNeighborSetList, conNeighborSet) idxAsPathSet, _ := IndexOfAsPathSet(conAsPathSetList, conAsPathSet) + idxCommunitySet, _ := IndexOfCommunitySet(conCommunitySetList, conCommunitySet) if idxPrefixSet != -1 { prefixSet = PrefixSetToApiStruct(conPrefixSetList[idxPrefixSet]) } @@ -1261,19 +1333,18 @@ func PolicyDefinitionToApiStruct(pd config.PolicyDefinition, df config.DefinedSe if idxAsPathSet != -1 { asPathSet = AsPathSetToApiStruct(conAsPathSetList[idxAsPathSet]) } + if idxCommunitySet != -1 { + communitySet = CommunitySetToApiStruct(conCommunitySetList[idxCommunitySet]) + } resConditions := &api.Conditions{ MatchPrefixSet: prefixSet, MatchNeighborSet: neighborSet, MatchAsPathSet: asPathSet, + MatchCommunitySet: communitySet, MatchAsPathLength: AsPathLengthToApiStruct(st.Conditions.BgpConditions.AsPathLength), MatchSetOptions: MatchSetOptionToString(conditions.MatchSetOptions), } - resActions := &api.Actions{ - RouteAction: ROUTE_REJECT, - } - if actions.AcceptRoute { - resActions.RouteAction = ROUTE_ACCEPT - } + resActions := ActionsToApiStruct(actions) resStatement := &api.Statement{ StatementNeme: st.Name, Conditions: resConditions, diff --git a/server/grpc_server.go b/server/grpc_server.go index 8f2ca497..ef850dbf 100644 --- a/server/grpc_server.go +++ b/server/grpc_server.go @@ -68,6 +68,11 @@ const ( REQ_POLICY_ROUTEPOLICY_ADD REQ_POLICY_ROUTEPOLICY_DELETE REQ_POLICY_ROUTEPOLICIES_DELETE + REQ_POLICY_COMMUNITY + REQ_POLICY_COMMUNITIES + REQ_POLICY_COMMUNITY_ADD + REQ_POLICY_COMMUNITY_DELETE + REQ_POLICY_COMMUNITIES_DELETE ) const GRPC_PORT = 8080 @@ -389,6 +394,17 @@ func (s *Server) modPolicy(arg *api.PolicyArguments, stream interface{}) error { default: return fmt.Errorf("unsupported operation: %s", arg.Operation) } + case api.Resource_POLICY_COMMUNITY: + switch arg.Operation { + case api.Operation_ADD: + reqType = REQ_POLICY_COMMUNITY_ADD + case api.Operation_DEL: + reqType = REQ_POLICY_COMMUNITY_DELETE + case api.Operation_DEL_ALL: + reqType = REQ_POLICY_COMMUNITIES_DELETE + default: + return fmt.Errorf("unsupported operation: %s", arg.Operation) + } case api.Resource_POLICY_ROUTEPOLICY: switch arg.Operation { case api.Operation_ADD: @@ -400,6 +416,8 @@ func (s *Server) modPolicy(arg *api.PolicyArguments, stream interface{}) error { default: return fmt.Errorf("unsupported operation: %s", arg.Operation) } + default: + return fmt.Errorf("unsupported resource type: %v", arg.Resource) } req := NewGrpcRequest(reqType, "", rf, arg.PolicyDefinition) s.bgpServerCh <- req @@ -428,6 +446,8 @@ func (s *Server) GetPolicyRoutePolicies(arg *api.PolicyArguments, stream api.Grp reqType = REQ_POLICY_NEIGHBORS case api.Resource_POLICY_ASPATH: reqType = REQ_POLICY_ASPATHS + case api.Resource_POLICY_COMMUNITY: + reqType = REQ_POLICY_COMMUNITIES case api.Resource_POLICY_ROUTEPOLICY: reqType = REQ_POLICY_ROUTEPOLICIES default: @@ -457,6 +477,8 @@ func (s *Server) GetPolicyRoutePolicy(ctx context.Context, arg *api.PolicyArgume reqType = REQ_POLICY_NEIGHBOR case api.Resource_POLICY_ASPATH: reqType = REQ_POLICY_ASPATH + case api.Resource_POLICY_COMMUNITY: + reqType = REQ_POLICY_COMMUNITY case api.Resource_POLICY_ROUTEPOLICY: reqType = REQ_POLICY_ROUTEPOLICY default: diff --git a/server/server.go b/server/server.go index 78cd5c8f..9a300a98 100644 --- a/server/server.go +++ b/server/server.go @@ -1048,20 +1048,25 @@ func (server *BgpServer) handleGrpc(grpcReq *GrpcRequest) []*SenderMsg { grpcReq.ResponseCh <- &GrpcResponse{} close(grpcReq.ResponseCh) - case REQ_POLICY_PREFIXES, REQ_POLICY_NEIGHBORS, REQ_POLICY_ASPATHS, REQ_POLICY_ROUTEPOLICIES: + case REQ_POLICY_PREFIXES, REQ_POLICY_NEIGHBORS, REQ_POLICY_ASPATHS, + REQ_POLICY_COMMUNITIES, REQ_POLICY_ROUTEPOLICIES: server.handleGrpcShowPolicies(grpcReq) - case REQ_POLICY_PREFIX, REQ_POLICY_NEIGHBOR, REQ_POLICY_ASPATH, REQ_POLICY_ROUTEPOLICY: + case REQ_POLICY_PREFIX, REQ_POLICY_NEIGHBOR, REQ_POLICY_ASPATH, + REQ_POLICY_COMMUNITY, REQ_POLICY_ROUTEPOLICY: server.handleGrpcShowPolicy(grpcReq) - case REQ_POLICY_PREFIX_ADD, REQ_POLICY_NEIGHBOR_ADD, REQ_POLICY_ASPATH_ADD, REQ_POLICY_ROUTEPOLICY_ADD: + case REQ_POLICY_PREFIX_ADD, REQ_POLICY_NEIGHBOR_ADD, REQ_POLICY_ASPATH_ADD, + REQ_POLICY_COMMUNITY_ADD, REQ_POLICY_ROUTEPOLICY_ADD: server.handleGrpcAddPolicy(grpcReq) - case REQ_POLICY_PREFIX_DELETE, REQ_POLICY_NEIGHBOR_DELETE, REQ_POLICY_ASPATH_DELETE, REQ_POLICY_ROUTEPOLICY_DELETE: + case REQ_POLICY_PREFIX_DELETE, REQ_POLICY_NEIGHBOR_DELETE, REQ_POLICY_ASPATH_DELETE, + REQ_POLICY_COMMUNITY_DELETE, REQ_POLICY_ROUTEPOLICY_DELETE: server.handleGrpcDelPolicy(grpcReq) - case REQ_POLICY_PREFIXES_DELETE, REQ_POLICY_NEIGHBORS_DELETE, REQ_POLICY_ASPATHS_DELETE, REQ_POLICY_ROUTEPOLICIES_DELETE: + case REQ_POLICY_PREFIXES_DELETE, REQ_POLICY_NEIGHBORS_DELETE, REQ_POLICY_ASPATHS_DELETE, + REQ_POLICY_COMMUNITIES_DELETE, REQ_POLICY_ROUTEPOLICIES_DELETE: server.handleGrpcDelPolicies(grpcReq) default: - errmsg := "Unknown request type" + errmsg := fmt.Errorf("Unknown request type: %v", grpcReq.RequestType) result := &GrpcResponse{ - ResponseErr: fmt.Errorf(errmsg), + ResponseErr: errmsg, } grpcReq.ResponseCh <- result close(grpcReq.ResponseCh) @@ -1120,6 +1125,22 @@ func (server *BgpServer) handleGrpcShowPolicies(grpcReq *GrpcRequest) { result.ResponseErr = fmt.Errorf("Policy aspath doesn't exist.") grpcReq.ResponseCh <- result } + case REQ_POLICY_COMMUNITIES: + info := server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySetList + if len(info) > 0 { + for _, cs := range info { + resCommunitySet := policy.CommunitySetToApiStruct(cs) + pd := &api.PolicyDefinition{} + pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchCommunitySet: resCommunitySet}}} + result = &GrpcResponse{ + Data: pd, + } + grpcReq.ResponseCh <- result + } + } else { + result.ResponseErr = fmt.Errorf("Policy community doesn't exist.") + grpcReq.ResponseCh <- result + } case REQ_POLICY_ROUTEPOLICIES: info := server.routingPolicy.PolicyDefinitionList df := server.routingPolicy.DefinedSets @@ -1197,6 +1218,24 @@ func (server *BgpServer) handleGrpcShowPolicy(grpcReq *GrpcRequest) { } else { result.ResponseErr = fmt.Errorf("policy aspath that has %v doesn't exist.", name) } + case REQ_POLICY_COMMUNITY: + info := server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySetList + resCommunitySet := &api.CommunitySet{} + for _, cs := range info { + if cs.CommunitySetName == name { + resCommunitySet = policy.CommunitySetToApiStruct(cs) + break + } + } + if len(resCommunitySet.CommunityMembers) > 0 { + pd := &api.PolicyDefinition{} + pd.StatementList = []*api.Statement{{Conditions: &api.Conditions{MatchCommunitySet: resCommunitySet}}} + result = &GrpcResponse{ + Data: pd, + } + } else { + result.ResponseErr = fmt.Errorf("policy community that has %v doesn't exist.", name) + } case REQ_POLICY_ROUTEPOLICY: log.Error("IN RoutePolicy") info := server.routingPolicy.PolicyDefinitionList @@ -1208,7 +1247,7 @@ func (server *BgpServer) handleGrpcShowPolicy(grpcReq *GrpcRequest) { break } } - log.Error("IN RoutePolicy: ",len(resPolicyDefinition.StatementList)) + log.Error("IN RoutePolicy: ", len(resPolicyDefinition.StatementList)) if len(resPolicyDefinition.StatementList) > 0 { result = &GrpcResponse{ Data: resPolicyDefinition, @@ -1241,7 +1280,7 @@ func (server *BgpServer) handleGrpcAddPolicy(grpcReq *GrpcRequest) { } else { if idxPrefix == -1 { conPrefixSetList[idxPrefixSet].PrefixList = - append(conPrefixSetList[idxPrefixSet].PrefixList, prefixSet.PrefixList[0]) + append(conPrefixSetList[idxPrefixSet].PrefixList, prefixSet.PrefixList[0]) } } server.routingPolicy.DefinedSets.PrefixSetList = conPrefixSetList @@ -1262,7 +1301,7 @@ func (server *BgpServer) handleGrpcAddPolicy(grpcReq *GrpcRequest) { } else { if idxNeighbor == -1 { conNeighborSetList[idxNeighborSet].NeighborInfoList = - append(conNeighborSetList[idxNeighborSet].NeighborInfoList, neighborSet.NeighborInfoList[0]) + append(conNeighborSetList[idxNeighborSet].NeighborInfoList, neighborSet.NeighborInfoList[0]) } } server.routingPolicy.DefinedSets.NeighborSetList = conNeighborSetList @@ -1287,6 +1326,27 @@ func (server *BgpServer) handleGrpcAddPolicy(grpcReq *GrpcRequest) { } } server.routingPolicy.DefinedSets.BgpDefinedSets.AsPathSetList = conAsPathSetList + case REQ_POLICY_COMMUNITY_ADD: + reqCommunitySet := grpcReq.Data.(*api.PolicyDefinition).StatementList[0].Conditions.MatchCommunitySet + conCommunitySetList := server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySetList + isReqCommunitySet, communitySet := policy.CommunitySetToConfigStruct(reqCommunitySet) + if !isReqCommunitySet { + result.ResponseErr = fmt.Errorf("doesn't reqest of policy community.") + grpcReq.ResponseCh <- result + close(grpcReq.ResponseCh) + } + // If the same NeighborSet is not set, add NeighborSet of request to the end. + // If only name of the NeighborSet is same, overwrite with NeighborSet of request + idxCommunitySet, idxCommunity := policy.IndexOfCommunitySet(conCommunitySetList, communitySet) + if idxCommunitySet == -1 { + conCommunitySetList = append(conCommunitySetList, communitySet) + } else { + if idxCommunity == -1 { + conCommunitySetList[idxCommunitySet].CommunityMembers = + append(conCommunitySetList[idxCommunitySet].CommunityMembers, communitySet.CommunityMembers[0]) + } + } + server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySetList = conCommunitySetList case REQ_POLICY_ROUTEPOLICY_ADD: reqPolicy := grpcReq.Data.(*api.PolicyDefinition) reqConditions := reqPolicy.StatementList[0].Conditions @@ -1300,32 +1360,33 @@ func (server *BgpServer) handleGrpcAddPolicy(grpcReq *GrpcRequest) { statement := policyDef.StatementList[0] if idxStatement == -1 { conPolicyList[idxPolicy].StatementList = - append(conPolicyList[idxPolicy].StatementList, statement) + append(conPolicyList[idxPolicy].StatementList, statement) } else { conStatement := &conPolicyList[idxPolicy].StatementList[idxStatement] - if reqConditions != nil { - if reqConditions.MatchPrefixSet != nil { - conStatement.Conditions.MatchPrefixSet = statement.Conditions.MatchPrefixSet - } - if reqConditions.MatchNeighborSet != nil { - conStatement.Conditions.MatchNeighborSet = statement.Conditions.MatchNeighborSet - } - if reqConditions.MatchSetOptions != "" { - conStatement.Conditions.MatchSetOptions = statement.Conditions.MatchSetOptions - } - if reqConditions.MatchAsPathSet != nil { - conStatement.Conditions.BgpConditions.MatchAsPathSet = statement.Conditions.BgpConditions.MatchAsPathSet - } - if reqConditions.MatchAsPathLength != nil { - conStatement.Conditions.BgpConditions.AsPathLength = statement.Conditions.BgpConditions.AsPathLength - } + if reqConditions.MatchPrefixSet != nil { + conStatement.Conditions.MatchPrefixSet = statement.Conditions.MatchPrefixSet } - if reqActions != nil { - if reqActions.RouteAction != "" { - conStatement.Actions.AcceptRoute = statement.Actions.AcceptRoute - conStatement.Actions.RejectRoute = statement.Actions.RejectRoute - } - conStatement.Actions = statement.Actions + if reqConditions.MatchNeighborSet != nil { + conStatement.Conditions.MatchNeighborSet = statement.Conditions.MatchNeighborSet + } + if reqConditions.MatchSetOptions != "" { + conStatement.Conditions.MatchSetOptions = statement.Conditions.MatchSetOptions + } + if reqConditions.MatchAsPathSet != nil { + conStatement.Conditions.BgpConditions.MatchAsPathSet = statement.Conditions.BgpConditions.MatchAsPathSet + } + if reqConditions.MatchCommunitySet != nil { + conStatement.Conditions.BgpConditions.MatchCommunitySet = statement.Conditions.BgpConditions.MatchCommunitySet + } + if reqConditions.MatchAsPathLength != nil { + conStatement.Conditions.BgpConditions.AsPathLength = statement.Conditions.BgpConditions.AsPathLength + } + if reqActions.RouteAction != "" { + conStatement.Actions.AcceptRoute = statement.Actions.AcceptRoute + conStatement.Actions.RejectRoute = statement.Actions.RejectRoute + } + if reqActions.Community != nil { + conStatement.Actions.BgpActions.SetCommunity = statement.Actions.BgpActions.SetCommunity } } } @@ -1357,7 +1418,7 @@ func (server *BgpServer) handleGrpcDelPolicy(grpcReq *GrpcRequest) { prefix.Address, prefix.Masklength, prefix.MasklengthRange) } else { conPrefixSetList[idxPrefixSet].PrefixList = - append(conPrefixSetList[idxPrefixSet].PrefixList[:idxPrefix], conPrefixSetList[idxPrefixSet].PrefixList[idxPrefix+1:]...) + append(conPrefixSetList[idxPrefixSet].PrefixList[:idxPrefix], conPrefixSetList[idxPrefixSet].PrefixList[idxPrefix+1:]...) } } } else { @@ -1392,8 +1453,8 @@ func (server *BgpServer) handleGrpcDelPolicy(grpcReq *GrpcRequest) { neighborSet.NeighborInfoList[0].Address) } else { conNeighborSetList[idxNeighborSet].NeighborInfoList = - append(conNeighborSetList[idxNeighborSet].NeighborInfoList[:idxNeighbor], - conNeighborSetList[idxNeighborSet].NeighborInfoList[idxNeighbor+1:]...) + append(conNeighborSetList[idxNeighborSet].NeighborInfoList[:idxNeighbor], + conNeighborSetList[idxNeighborSet].NeighborInfoList[idxNeighbor+1:]...) } } } else { @@ -1441,6 +1502,35 @@ func (server *BgpServer) handleGrpcDelPolicy(grpcReq *GrpcRequest) { } } server.routingPolicy.DefinedSets.BgpDefinedSets.AsPathSetList = conAsPathSetList + case REQ_POLICY_COMMUNITY_DELETE: + reqCommunitySet := grpcReq.Data.(*api.PolicyDefinition).StatementList[0].Conditions.MatchCommunitySet + conCommunitySetList := server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySetList + isReqCommunitySet, CommunitySet := policy.CommunitySetToConfigStruct(reqCommunitySet) + // If only name of the NeighborSet is same, delete all of the elements of the NeighborSet. + // If the same element NeighborSet, delete the it's element from NeighborSet. + idxCommunitySet, idxCommunity := policy.IndexOfCommunitySet(conCommunitySetList, CommunitySet) + if isReqCommunitySet { + if idxCommunitySet == -1 { + result.ResponseErr = fmt.Errorf("Policy aspath that has %v %v doesn't exist.", CommunitySet.CommunitySetName, + CommunitySet.CommunityMembers[0]) + } else { + if idxCommunity == -1 { + result.ResponseErr = fmt.Errorf("Policy aspath that has %v %v doesn't exist.", CommunitySet.CommunitySetName, + CommunitySet.CommunityMembers[0]) + } else { + conCommunitySetList[idxCommunitySet].CommunityMembers = + append(conCommunitySetList[idxCommunitySet].CommunityMembers[:idxCommunity], + conCommunitySetList[idxCommunitySet].CommunityMembers[idxCommunity+1:]...) + } + } + } else { + if idxCommunitySet == -1 { + result.ResponseErr = fmt.Errorf("Policy aspath %v doesn't exist.", CommunitySet.CommunitySetName) + } else { + conCommunitySetList = append(conCommunitySetList[:idxCommunitySet], conCommunitySetList[idxCommunitySet+1:]...) + } + } + server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySetList = conCommunitySetList case REQ_POLICY_ROUTEPOLICY_DELETE: reqPolicy := grpcReq.Data.(*api.PolicyDefinition) conPolicyList := server.routingPolicy.PolicyDefinitionList @@ -1455,7 +1545,7 @@ func (server *BgpServer) handleGrpcDelPolicy(grpcReq *GrpcRequest) { result.ResponseErr = fmt.Errorf("Policy Statment that has %v doesn't exist.", policyDef.StatementList[0].Name) } else { conPolicyList[idxPolicy].StatementList = - append(conPolicyList[idxPolicy].StatementList[:idxStatement], conPolicyList[idxPolicy].StatementList[idxStatement+1:]...) + append(conPolicyList[idxPolicy].StatementList[:idxStatement], conPolicyList[idxPolicy].StatementList[idxStatement+1:]...) } } } else { @@ -1488,6 +1578,8 @@ func (server *BgpServer) handleGrpcDelPolicies(grpcReq *GrpcRequest) { server.routingPolicy.DefinedSets.NeighborSetList = make([]config.NeighborSet, 0) case REQ_POLICY_ASPATHS_DELETE: server.routingPolicy.DefinedSets.BgpDefinedSets.AsPathSetList = make([]config.AsPathSet, 0) + case REQ_POLICY_COMMUNITIES_DELETE: + server.routingPolicy.DefinedSets.BgpDefinedSets.CommunitySetList = make([]config.CommunitySet, 0) case REQ_POLICY_ROUTEPOLICIES_DELETE: server.routingPolicy.PolicyDefinitionList = make([]config.PolicyDefinition, 0) } |