diff options
-rw-r--r-- | api/grpc_server.go | 5 | ||||
-rw-r--r-- | config/bgp_configs.go | 61 | ||||
-rw-r--r-- | config/default.go | 33 | ||||
-rw-r--r-- | docs/sources/policy.md | 86 | ||||
-rw-r--r-- | gobgp/cmd/policy.go | 4 | ||||
-rw-r--r-- | table/policy.go | 27 | ||||
-rw-r--r-- | table/policy_test.go | 54 | ||||
-rw-r--r-- | test/scenario_test/route_server_policy_test.py | 100 | ||||
-rw-r--r-- | test/scenario_test/route_server_softreset_test.py | 2 | ||||
-rw-r--r-- | tools/config/example_toml.go | 5 | ||||
-rw-r--r-- | tools/pyang_plugins/bgpyang2golang.py | 32 |
11 files changed, 281 insertions, 128 deletions
diff --git a/api/grpc_server.go b/api/grpc_server.go index 78a53d0b..6445c003 100644 --- a/api/grpc_server.go +++ b/api/grpc_server.go @@ -1230,9 +1230,10 @@ func toStatementApi(s *config.Statement) *Statement { cs.RpkiResult = int32(s.Conditions.BgpConditions.RpkiValidationResult.ToInt()) as := &Actions{ RouteAction: func() RouteAction { - if s.Actions.RouteDisposition.AcceptRoute { + switch s.Actions.RouteDisposition { + case config.ROUTE_DISPOSITION_ACCEPT_ROUTE: return RouteAction_ACCEPT - } else if s.Actions.RouteDisposition.RejectRoute { + case config.ROUTE_DISPOSITION_REJECT_ROUTE: return RouteAction_REJECT } return RouteAction_NONE diff --git a/config/bgp_configs.go b/config/bgp_configs.go index 300d9058..742f80dd 100644 --- a/config/bgp_configs.go +++ b/config/bgp_configs.go @@ -581,6 +581,42 @@ func (v AttributeComparison) Validate() error { return nil } +// typedef for identity rpol:route-disposition +type RouteDisposition string + +const ( + ROUTE_DISPOSITION_NONE RouteDisposition = "none" + ROUTE_DISPOSITION_ACCEPT_ROUTE RouteDisposition = "accept-route" + ROUTE_DISPOSITION_REJECT_ROUTE RouteDisposition = "reject-route" +) + +var RouteDispositionToIntMap = map[RouteDisposition]int{ + ROUTE_DISPOSITION_NONE: 0, + ROUTE_DISPOSITION_ACCEPT_ROUTE: 1, + ROUTE_DISPOSITION_REJECT_ROUTE: 2, +} + +func (v RouteDisposition) ToInt() int { + i, ok := RouteDispositionToIntMap[v] + if !ok { + return -1 + } + return i +} + +var IntToRouteDispositionMap = map[int]RouteDisposition{ + 0: ROUTE_DISPOSITION_NONE, + 1: ROUTE_DISPOSITION_ACCEPT_ROUTE, + 2: ROUTE_DISPOSITION_REJECT_ROUTE, +} + +func (v RouteDisposition) Validate() error { + if _, ok := RouteDispositionToIntMap[v]; !ok { + return fmt.Errorf("invalid RouteDisposition: %s", v) + } + return nil +} + // typedef for identity rpol:route-type type RouteType string @@ -4011,29 +4047,6 @@ func (lhs *IgpActions) Equal(rhs *IgpActions) bool { return true } -//struct for container rpol:route-disposition -type RouteDisposition struct { - // original -> rpol:accept-route - //rpol:accept-route's original type is empty - AcceptRoute bool `mapstructure:"accept-route" json:"accept-route,omitempty"` - // original -> rpol:reject-route - //rpol:reject-route's original type is empty - RejectRoute bool `mapstructure:"reject-route" json:"reject-route,omitempty"` -} - -func (lhs *RouteDisposition) Equal(rhs *RouteDisposition) bool { - if lhs == nil || rhs == nil { - return false - } - if lhs.AcceptRoute != rhs.AcceptRoute { - return false - } - if lhs.RejectRoute != rhs.RejectRoute { - return false - } - return true -} - //struct for container rpol:actions type Actions struct { // original -> rpol:route-disposition @@ -4048,7 +4061,7 @@ func (lhs *Actions) Equal(rhs *Actions) bool { if lhs == nil || rhs == nil { return false } - if !lhs.RouteDisposition.Equal(&(rhs.RouteDisposition)) { + if lhs.RouteDisposition != rhs.RouteDisposition { return false } if !lhs.IgpActions.Equal(&(rhs.IgpActions)) { diff --git a/config/default.go b/config/default.go index 05fe2db8..fc15f046 100644 --- a/config/default.go +++ b/config/default.go @@ -216,6 +216,23 @@ func SetDefaultConfigValues(b *BgpConfigSet) error { return setDefaultConfigValuesWithViper(nil, b) } +func setDefaultPolicyConfigValuesWithViper(v *viper.Viper, p *PolicyDefinition) error { + stmts, err := extractArray(v.Get("policy.statements")) + if err != nil { + return err + } + for i, _ := range p.Statements { + vv := viper.New() + if len(stmts) > i { + vv.Set("statement", stmts[i]) + } + if !vv.IsSet("statement.actions.route-disposition") { + p.Statements[i].Actions.RouteDisposition = ROUTE_DISPOSITION_NONE + } + } + return nil +} + func setDefaultConfigValuesWithViper(v *viper.Viper, b *BgpConfigSet) error { if v == nil { v = viper.New() @@ -258,5 +275,21 @@ func setDefaultConfigValuesWithViper(v *viper.Viper, b *BgpConfigSet) error { } } + list, err = extractArray(v.Get("policy-definitions")) + if err != nil { + return err + } + + for idx, p := range b.PolicyDefinitions { + vv := viper.New() + if len(list) > idx { + vv.Set("policy", list[idx]) + } + if err := setDefaultPolicyConfigValuesWithViper(vv, &p); err != nil { + return err + } + b.PolicyDefinitions[idx] = p + } + return nil } diff --git a/docs/sources/policy.md b/docs/sources/policy.md index e9d4b8be..0d7f5a05 100644 --- a/docs/sources/policy.md +++ b/docs/sources/policy.md @@ -493,8 +493,8 @@ policy-definitions consists of condition and action. Condition part is used to e [policy-definitions.statements.conditions.bgp-conditions.as-path-length] operator = "eq" value = 2 - [policy-definitions.statements.actions.route-disposition] - accept-route = true + [policy-definitions.statements.actions] + route-disposition = "accept-route" [policy-definitions.statements.actions.bgp-actions] set-med = "-200" [policy-definitions.statements.actions.bgp-actions.set-as-path-prepend] @@ -562,11 +562,11 @@ policy-definitions consists of condition and action. Condition part is used to e | operator | operator to compare the length of AS number in AS_PATH attribute. <br> "eq","ge","le" can be used. <br> "eq" means that length of AS number is equal to Value element <br> "ge" means that length of AS number is equal or greater than the Value element <br> "le" means that length of AS number is equal or smaller than the Value element| "eq" | | value | value used to compare with the length of AS number in AS_PATH attribute | 2 | - - policy-definitions.statements.actions.route-disposition + - policy-definitions.statements.actions - | Element | Description | Example | - |--------------|-----------------------------------------------------------------------------------|---------| - | accept-route | action to accept the route if matches conditions. If true, this route is accepted | true | + | Element | Description | Example | + |-------------------|---------------------------------------------------------------------------------------------------------------|----------------| + | route-disposition | stop following policy/statement evaluation and accept/reject the route:<br> "accept-route" or "reject-route" | "accept-route" | - policy-definitions.statements.actions.bgp-actions @@ -618,8 +618,8 @@ policy-definitions consists of condition and action. Condition part is used to e prefix-set = "ps1" [policy-definitions.statements.conditions.match-neighbor-set] neighbor-set = "ns1" - [policy-definitions.statements.actions.route-disposition] - reject-route = true + [policy-definitions.statements.actions] + route-disposition = "reject-route" ``` - example 2 @@ -636,8 +636,8 @@ policy-definitions consists of condition and action. Condition part is used to e prefix-set = "ps1" [policy-definitions.statements.conditions.match-neighbor-set] neighbor-set = "ns1" - [policy-definitions.statements.actions.route-disposition] - reject-route = true + [policy-definitions.statements.actions] + route-disposition = "reject-route" # second statement - (2) [[policy-definitions.statements]] name = "statement2" @@ -645,8 +645,8 @@ policy-definitions consists of condition and action. Condition part is used to e prefix-set = "ps2" [policy-definitions.statements.conditions.match-neighbor-set] neighbor-set = "ns2" - [policy-definitions.statements.actions.route-disposition] - reject-route = true + [policy-definitions.statements.actions] + route-disposition = "reject-route" ``` - if a route matches the condition inside the first statement(1), GoBGP applies its action and quits the policy evaluation. @@ -665,8 +665,8 @@ policy-definitions consists of condition and action. Condition part is used to e prefix-set = "ps1" [policy-definitions.statements.conditions.match-neighbor-set] neighbor-set = "ns1" - [policy-definitions.statements.actions.route-disposition] - reject-route = true + [policy-definitions.statements.actions] + route-disposition = "reject-route" # second policy [[policy-definitions]] name = "policy2" @@ -676,8 +676,8 @@ policy-definitions consists of condition and action. Condition part is used to e prefix-set = "ps2" [policy-definitions.statements.conditions.match-neighbor-set] neighbor-set = "ns2" - [policy-definitions.statements.actions.route-disposition] - reject-route = true + [policy-definitions.statements.actions] + route-disposition = "reject-route" ``` - example 4 @@ -710,8 +710,8 @@ policy-definitions consists of condition and action. Condition part is used to e [policy-definitions.statements.conditions.bgp-conditions.as-path-length] operator = "eq" value = 2 - [policy-definitions.statements.actions.route-disposition] - accept-route = true + [policy-definitions.statements.actions] + route-disposition = "accept-route" [policy-definitions.statements.actions.bgp-actions] set-med = "-200" set-next-hop = "10.0.0.1" @@ -725,6 +725,42 @@ policy-definitions consists of condition and action. Condition part is used to e communities-list = ["65100:20"] ``` + - example 5 + - example of multiple statement + + ```toml + # example 5 + [[policy-definitions]] + name = "policy1" + [[policy-definitions.statements]] + # statement without route-disposition continues to the next statement + [policy-definitions.statements.actions.bgp-actions] + set-med = "+100" + [[policy-definitions.statements]] + # if matched with "ps1", reject the route and stop evaluating + # following statements + [policy-definitions.statements.conditions.match-prefix-set] + prefix-set = "ps1" + [policy-definitions.statements.actions] + route-disposition = "reject-route" + [[policy-definitions.statements]] + # if matched with "ps2", accept the route and stop evaluating + # following statements + [policy-definitions.statements.conditions.match-prefix-set] + prefix-set = "ps2" + [policy-definitions.statements.actions] + route-disposition = "accept-route" + [[policy-definitions.statements]] + # since this is the last statement, if the route matched with "ps3", + # add 10 to MED value and continue to the next policy if exists. + # If not, default-policy is applied. + [policy-definitions.statements.conditions.match-prefix-set] + prefix-set = "ps3" + [policy-definitions.statements.actions.bgp-actions] + set-med = "+10" + ``` + + --- @@ -749,8 +785,8 @@ default-export-policy = "accept-route" |-------------------------|---------------------------------------------------------------------------------------------|----------------| | import-policy | policy-definitions.name for Import policy | "policy1" | | export-policy | policy-definitions.name for Export policy | "policy2" | -| default-import-policy | action when the route doesn't match any policy:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | -| default-export-policy | action when the route doesn't match any policy:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | +| default-import-policy | action when the route doesn't match any policy or none of the matched policy specifies `route-disposition`:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | +| default-export-policy | action when the route doesn't match any policy or none of the matched policy specifies `route-disposition`:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | #### <a name="rs-attachment"> 4.2. Attach policy to route-server-client @@ -785,9 +821,9 @@ The apply-policy has 6 elements. | import-policy | policy-definitions.name for Import policy | "policy1" | | export-policy | policy-definitions.name for Export policy | "policy2" | | in-policy | policy-definitions.name for In policy | "policy3" | -| default-import-policy | action when the route doesn't match any policy:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | -| default-export-policy | action when the route doesn't match any policy:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | -| default-in-policy | action when the route doesn't match any policy:<br> "accept-route" or "reject-route". default is "accept-route" | "reject-route" | +| default-import-policy | action when the route doesn't match any policy or none of the matched policy specifies `route-disposition`:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | +| default-export-policy | action when the route doesn't match any policy or none of the matched policy specifies `route-disposition`:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | +| default-in-policy | action when the route doesn't match any policy or none of the matched policy specifies `route-disposition`:<br> "accept-route" or "reject-route". default is "accept-route" | "accept-route" | @@ -847,8 +883,8 @@ define an import policy for neighbor 10.0.255.2 that drops [policy-definitions.statements.conditions.match-neighbor-set] neighbor-set = "ns1" match-set-options = "any" - [policy-definitions.statements.actions.route-disposition] - reject-route = true + [policy-definitions.statements.actions] + route-disposition = "reject-route" ``` Neighbor 10.0.255.2 has pd2 policy. The pd2 policy consists of ps2 prefix match and ns1 neighbor match. The ps2 specifies 10.33.0.0 and 10.50.0.0 address. The ps2 specifies the mask with **MASK** keyword. **masklength-range** keyword can specify the range of mask length like ```masklength-range 24..26```. The *ns1* specifies neighbor 10.0.255.1. diff --git a/gobgp/cmd/policy.go b/gobgp/cmd/policy.go index aa614d50..8ef136d8 100644 --- a/gobgp/cmd/policy.go +++ b/gobgp/cmd/policy.go @@ -669,9 +669,9 @@ func modAction(name, op string, args []string) error { args = args[1:] switch typ { case "reject": - stmt.Actions.RouteDisposition = config.RouteDisposition{RejectRoute: true} + stmt.Actions.RouteDisposition = config.ROUTE_DISPOSITION_REJECT_ROUTE case "accept": - stmt.Actions.RouteDisposition = config.RouteDisposition{AcceptRoute: true} + stmt.Actions.RouteDisposition = config.ROUTE_DISPOSITION_ACCEPT_ROUTE case "community": if len(args) < 1 { return fmt.Errorf("%s community { add | remove | replace } <value>...", usage) diff --git a/table/policy.go b/table/policy.go index 1d055b57..994ff4d8 100644 --- a/table/policy.go +++ b/table/policy.go @@ -1725,14 +1725,16 @@ func (a *RoutingAction) String() string { } func NewRoutingAction(c config.RouteDisposition) (*RoutingAction, error) { - if c.AcceptRoute == c.RejectRoute && c.AcceptRoute { - return nil, fmt.Errorf("invalid route disposition") - } else if !c.AcceptRoute && !c.RejectRoute { + var accept bool + switch c { + case config.RouteDisposition(""), config.ROUTE_DISPOSITION_NONE: return nil, nil - } - accept := false - if c.AcceptRoute && !c.RejectRoute { + case config.ROUTE_DISPOSITION_ACCEPT_ROUTE: accept = true + case config.ROUTE_DISPOSITION_REJECT_ROUTE: + accept = false + default: + return nil, fmt.Errorf("invalid route disposition") } return &RoutingAction{ AcceptRoute: accept, @@ -2341,11 +2343,6 @@ func (s *Statement) Apply(path *Path, options *PolicyOptions) (RouteType, *Path) } //Routing action if s.RouteAction == nil || reflect.ValueOf(s.RouteAction).IsNil() { - log.WithFields(log.Fields{ - "Topic": "Policy", - "Path": path, - "PolicyName": s.Name, - }).Warn("route action is nil") return ROUTE_TYPE_NONE, path } p := s.RouteAction.Apply(path, options) @@ -2399,7 +2396,13 @@ func (s *Statement) ToConfig() *config.Statement { act := config.Actions{} if s.RouteAction != nil && !reflect.ValueOf(s.RouteAction).IsNil() { a := s.RouteAction.(*RoutingAction) - act.RouteDisposition = config.RouteDisposition{AcceptRoute: a.AcceptRoute, RejectRoute: !a.AcceptRoute} + if a.AcceptRoute { + act.RouteDisposition = config.ROUTE_DISPOSITION_ACCEPT_ROUTE + } else { + act.RouteDisposition = config.ROUTE_DISPOSITION_REJECT_ROUTE + } + } else { + act.RouteDisposition = config.ROUTE_DISPOSITION_NONE } for _, a := range s.ModActions { switch a.(type) { diff --git a/table/policy_test.go b/table/policy_test.go index c3a04433..6897a227 100644 --- a/table/policy_test.go +++ b/table/policy_test.go @@ -2728,11 +2728,12 @@ func createStatement(name, psname, nsname string, accept bool) config.Statement NeighborSet: nsname, }, } + rd := config.ROUTE_DISPOSITION_REJECT_ROUTE + if accept { + rd = config.ROUTE_DISPOSITION_ACCEPT_ROUTE + } a := config.Actions{ - RouteDisposition: config.RouteDisposition{ - AcceptRoute: accept, - RejectRoute: !accept, - }, + RouteDisposition: rd, } s := config.Statement{ Name: name, @@ -2940,3 +2941,48 @@ func TestLargeCommunityMatchAction(t *testing.T) { assert.Equal(t, m.Evaluate(p, nil), true) } + +func TestMultipleStatementPolicy(t *testing.T) { + r := NewRoutingPolicy() + rp := config.RoutingPolicy{ + PolicyDefinitions: []config.PolicyDefinition{config.PolicyDefinition{ + Name: "p1", + Statements: []config.Statement{ + config.Statement{ + Actions: config.Actions{ + BgpActions: config.BgpActions{ + SetMed: "+100", + }, + }, + }, + config.Statement{ + Actions: config.Actions{ + BgpActions: config.BgpActions{ + SetLocalPref: 100, + }, + }, + }, + }, + }, + }, + } + err := r.reload(rp) + assert.Nil(t, err) + + nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0") + + origin := bgp.NewPathAttributeOrigin(0) + aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65001})} + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") + pattrs := []bgp.PathAttributeInterface{origin, aspath, nexthop} + + path := NewPath(nil, nlri, false, pattrs, time.Now(), false) + + pType, newPath := r.policyMap["p1"].Apply(path, nil) + assert.Equal(t, ROUTE_TYPE_NONE, pType) + med, _ := newPath.GetMed() + assert.Equal(t, med, uint32(100)) + localPref, _ := newPath.GetLocalPref() + assert.Equal(t, localPref, uint32(100)) +} diff --git a/test/scenario_test/route_server_policy_test.py b/test/scenario_test/route_server_policy_test.py index 6bf02eb0..7188f43c 100644 --- a/test/scenario_test/route_server_policy_test.py +++ b/test/scenario_test/route_server_policy_test.py @@ -114,7 +114,7 @@ class ImportPolicy(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -180,7 +180,7 @@ class ExportPolicy(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -266,7 +266,7 @@ class ImportPolicyUpdate(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -313,7 +313,7 @@ class ImportPolicyUpdate(object): st0 = {'name': 'st0', 'conditions': {'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -393,7 +393,7 @@ class ExportPolicyUpdate(object): st0 = {'name': 'st0', 'conditions': {'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -440,7 +440,7 @@ class ExportPolicyUpdate(object): st0 = {'name': 'st0', 'conditions': {'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -536,7 +536,7 @@ class ImportPolicyIPV6(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -605,7 +605,7 @@ class ExportPolicyIPV6(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -687,7 +687,7 @@ class ImportPolicyIPV6Update(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -731,7 +731,7 @@ class ImportPolicyIPV6Update(object): 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, 'actions': { - 'route-disposition': {'reject-route': True}}} + 'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -808,7 +808,7 @@ class ExportPolicyIPv6Update(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -851,7 +851,7 @@ class ExportPolicyIPv6Update(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -902,7 +902,7 @@ class ImportPolicyAsPathLengthCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'as-path-length': {'operator': 'ge', 'value': 10}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -962,7 +962,7 @@ class ImportPolicyAsPathCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'match-as-path-set': {'as-path-set': 'as0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -1014,7 +1014,7 @@ class ImportPolicyAsPathAnyCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'match-as-path-set': {'as-path-set': 'as0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -1066,7 +1066,7 @@ class ImportPolicyAsPathOriginCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'match-as-path-set': {'as-path-set': 'as0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -1118,7 +1118,7 @@ class ImportPolicyAsPathOnlyCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'match-as-path-set': {'as-path-set': 'as0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -1172,7 +1172,7 @@ class ImportPolicyAsPathMismatchCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'match-community-set': {'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -1232,7 +1232,7 @@ class ImportPolicyCommunityCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'match-community-set': {'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -1285,7 +1285,7 @@ class ImportPolicyCommunityRegexp(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'match-community-set': {'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -1346,7 +1346,7 @@ class ImportPolicyCommunityAction(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions': {'match-community-set': {'community-set': 'cs0', 'match-set-options': 'any'}}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-community': {'options': 'add', 'set-community-method': {'communities-list': ['65100:20']}}}}} @@ -1420,7 +1420,7 @@ class ImportPolicyCommunityReplace(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-community': {'options': 'REPLACE', 'set-community-method': {'communities-list': ['65100:20']}}}}} @@ -1486,7 +1486,7 @@ class ImportPolicyCommunityRemove(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-community': {'options': 'REMOVE', 'set-community-method': {'communities-list': ['65100:10', '65100:20']}}}}} @@ -1570,7 +1570,7 @@ class ImportPolicyCommunityNull(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-community': {'options': 'REPLACE', 'set-community-method': {'communities-list': []}}}}} @@ -1644,7 +1644,7 @@ class ExportPolicyCommunityAdd(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-community': {'options': 'add', 'set-community-method': {'communities-list': ['65100:20']}}}}} @@ -1717,7 +1717,7 @@ class ExportPolicyCommunityReplace(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-community': {'options': 'REPLACE', 'set-community-method': {'communities-list': ['65100:20']}}}}} @@ -1790,7 +1790,7 @@ class ExportPolicyCommunityRemove(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-community': {'options': 'REMOVE', 'set-community-method': {'communities-list': ['65100:20', '65100:30']}}}}} @@ -1866,7 +1866,7 @@ class ExportPolicyCommunityNull(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-community': {'options': 'REPLACE', 'set-community-method': {'communities-list': []}}}}} @@ -1944,7 +1944,7 @@ class ImportPolicyMedReplace(object): q1 = env.q1 q2 = env.q2 st0 = {'name': 'st0', - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-med': '100'}}} policy = {'name': 'policy0', @@ -2005,7 +2005,7 @@ class ImportPolicyMedAdd(object): q1 = env.q1 q2 = env.q2 st0 = {'name': 'st0', - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-med': '+100'}}} policy = {'name': 'policy0', @@ -2066,7 +2066,7 @@ class ImportPolicyMedSub(object): q1 = env.q1 q2 = env.q2 st0 = {'name': 'st0', - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-med': '-100'}}} policy = {'name': 'policy0', @@ -2127,7 +2127,7 @@ class ExportPolicyMedReplace(object): q1 = env.q1 q2 = env.q2 st0 = {'name': 'st0', - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-med': '100'}}} policy = {'name': 'policy0', @@ -2188,7 +2188,7 @@ class ExportPolicyMedAdd(object): q1 = env.q1 q2 = env.q2 st0 = {'name': 'st0', - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-med': '+100'}}} policy = {'name': 'policy0', @@ -2249,7 +2249,7 @@ class ExportPolicyMedSub(object): q1 = env.q1 q2 = env.q2 st0 = {'name': 'st0', - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-med': '-100'}}} policy = {'name': 'policy0', @@ -2314,7 +2314,7 @@ class InPolicyReject(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -2373,7 +2373,7 @@ class InPolicyAccept(object): st0 = {'name': 'st0', 'conditions':{'bgp-conditions':{'match-community-set':{'community-set': 'cs0'}}}, - 'actions':{'route-disposition': {'accept-route': True}}} + 'actions':{'route-disposition': 'accept-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -2448,7 +2448,7 @@ class InPolicyUpdate(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -2496,7 +2496,7 @@ class InPolicyUpdate(object): st0 = {'name': 'st0', 'conditions': {'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -2556,7 +2556,7 @@ class ExportPolicyAsPathPrepend(object): st0 = {'name': 'st0', 'conditions': {'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-as-path-prepend': {'repeat-n': 5, 'as': "65005"}}}} policy = {'name': 'policy0', @@ -2643,7 +2643,7 @@ class ImportPolicyAsPathPrependLastAS(object): st0 = {'name': 'st0', 'conditions': {'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-as-path-prepend': {'repeat-n': 5, 'as': "last-as"}}}} policy = {'name': 'policy0', @@ -2720,7 +2720,7 @@ class ExportPolicyAsPathPrependLastAS(object): st0 = {'name': 'st0', 'conditions': {'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}}, - 'actions': {'route-disposition': {'accept-route': True}, + 'actions': {'route-disposition': 'accept-route', 'bgp-actions': {'set-as-path-prepend': {'repeat-n': 5, 'as': "last-as"}}}} policy = {'name': 'policy0', @@ -2795,7 +2795,7 @@ class ImportPolicyExCommunityOriginCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions':{'match-ext-community-set':{'ext-community-set': 'es0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -2846,7 +2846,7 @@ class ImportPolicyExCommunityTargetCondition(object): st0 = {'name': 'st0', 'conditions': {'bgp-conditions':{'match-ext-community-set':{'ext-community-set': 'es0'}}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -2899,7 +2899,7 @@ class InPolicyPrefixCondition(object): st0 = {'name': 'st0', 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -2971,7 +2971,7 @@ class ImportPolicyExCommunityAdd(object): } }, 'actions': { - 'route-disposition': {'accept-route': True}, + 'route-disposition': 'accept-route', 'bgp-actions': { 'set-ext-community': { 'options': 'add', @@ -3051,7 +3051,7 @@ class ImportPolicyExCommunityAdd2(object): } }, 'actions': { - 'route-disposition': {'accept-route': True}, + 'route-disposition': 'accept-route', 'bgp-actions': { 'set-ext-community': { 'options': 'add', @@ -3136,7 +3136,7 @@ class ImportPolicyExCommunityMultipleAdd(object): } }, 'actions': { - 'route-disposition': {'accept-route': True}, + 'route-disposition': 'accept-route', 'bgp-actions': { 'set-ext-community': { 'options': 'add', @@ -3221,7 +3221,7 @@ class ExportPolicyExCommunityAdd(object): } }, 'actions': { - 'route-disposition': {'accept-route': True}, + 'route-disposition': 'accept-route', 'bgp-actions': { 'set-ext-community': { 'options': 'add', @@ -3318,7 +3318,7 @@ class InPolicyUpdate2(object): 'conditions': { 'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} @@ -3367,7 +3367,7 @@ class InPolicyUpdate2(object): st0 = {'name': 'st0', 'conditions': {'match-prefix-set': {'prefix-set': ps0['prefix-set-name']}, 'match-neighbor-set': {'neighbor-set': ns0['neighbor-set-name']}}, - 'actions': {'route-disposition': {'reject-route': True}}} + 'actions': {'route-disposition': 'reject-route'}} policy = {'name': 'policy0', 'statements': [st0]} diff --git a/test/scenario_test/route_server_softreset_test.py b/test/scenario_test/route_server_softreset_test.py index 05e39ba2..63388fd5 100644 --- a/test/scenario_test/route_server_softreset_test.py +++ b/test/scenario_test/route_server_softreset_test.py @@ -80,7 +80,7 @@ class GoBGPTestBase(unittest.TestCase): g1.set_prefix_set(ps0) st0 = {'conditions': {'match-prefix-set': {'prefix-set': 'ps0'}}, - 'actions': {'route-disposition': {'accept-route': True}}} + 'actions': {'route-disposition': 'accept-route'}} pol0 = {'name': 'pol0', 'statements': [st0]} diff --git a/tools/config/example_toml.go b/tools/config/example_toml.go index 11ab2939..62e6b8f6 100644 --- a/tools/config/example_toml.go +++ b/tools/config/example_toml.go @@ -156,10 +156,7 @@ func policy() config.RoutingPolicy { }, }, Actions: config.Actions{ - RouteDisposition: config.RouteDisposition{ - AcceptRoute: false, - RejectRoute: true, - }, + RouteDisposition: "reject-route", BgpActions: config.BgpActions{ SetCommunity: config.SetCommunity{ SetCommunityMethod: config.SetCommunityMethod{ diff --git a/tools/pyang_plugins/bgpyang2golang.py b/tools/pyang_plugins/bgpyang2golang.py index f6ea1a86..a7a59866 100644 --- a/tools/pyang_plugins/bgpyang2golang.py +++ b/tools/pyang_plugins/bgpyang2golang.py @@ -18,6 +18,7 @@ import optparse import StringIO import sys from pyang import plugin +from collections import namedtuple _COPYRIGHT_NOTICE = """ // DO NOT EDIT @@ -207,6 +208,9 @@ def emit_class_def(ctx, yang_statement, struct_name, prefix): if is_case(child): continue + if is_choice(child) and is_enum_choice(child): + emit_type_name = val_name_go + # case leaflist if is_leaflist(child): type_obj = child.search_one('type') @@ -239,7 +243,7 @@ def emit_class_def(ctx, yang_statement, struct_name, prefix): emit_type_name = '[]'+t.golang_name # case container - elif is_container(child) or is_choice(child): + elif is_container(child) or (is_choice(child) and not is_enum_choice(child)): key = child_prefix+':'+container_or_list_name t = ctx.golang_struct_names[key] val_name_go = t.golang_name @@ -380,7 +384,7 @@ def visit_children(ctx, module, children): t = c.search_one('type') # define container embeded enums - if is_leaf(c) and c.search_one('type').arg == 'enumeration': + def define_enum(c): prefix = module.i_prefix c.path = get_path(c) c.golang_name = convert_to_golang(c.arg) @@ -389,12 +393,17 @@ def visit_children(ctx, module, children): else: ctx.golang_typedef_map[prefix] = {c.arg: c} - if is_list(c) or is_container(c) or is_choice(c): + if is_leaf(c) and c.search_one('type').arg == 'enumeration': + define_enum(c) + elif is_list(c) or is_container(c) or is_choice(c): c.golang_name = convert_to_golang(c.uniq_name) if is_choice(c): picks = pickup_choice(c) c.i_children = picks + if is_enum_choice(c): + define_enum(c) + continue if ctx.golang_struct_names.get(prefix+':'+c.uniq_name): ext_c = ctx.golang_struct_names.get(prefix+':'+c.uniq_name) @@ -504,6 +513,12 @@ def emit_enum(prefix, name, stmt, substmts): const_prefix = convert_const_prefix(type_name_org) print >> o, 'const (' m = {} + + if is_choice(stmt) and is_enum_choice(stmt): + n = namedtuple('Statement', ['arg']) + n.arg = 'none' + substmts = [n] + substmts + for sub in substmts: enum_name = '%s_%s' % (const_prefix, convert_const_prefix(sub.arg)) m[sub.arg.lower()] = enum_name @@ -580,7 +595,9 @@ def emit_typedef(ctx, module): t = stmt.search_one('type') o = StringIO.StringIO() - if t.arg == 'enumeration': + if not t and is_choice(stmt): + emit_enum(prefix, type_name_org, stmt, stmt.i_children) + elif t.arg == 'enumeration': emit_enum(prefix, type_name_org, stmt, t.substmts) elif t.arg == 'union': print >> o, '// typedef for typedef %s:%s'\ @@ -642,6 +659,13 @@ def is_case(s): def is_choice(s): return s.keyword in ['choice'] +def is_enum_choice(s): + return all(e.search_one('type').arg in _type_enum_case for e in s.i_children) + +_type_enum_case = [ + 'empty', +] + def is_builtin_type(t): return t.arg in _type_builtin |