Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

policy: ImplementAsAppendAction #1637

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
995 changes: 518 additions & 477 deletions api/gobgp.pb.go

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions api/gobgp.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1056,6 +1056,12 @@ message LocalPrefAction {
uint32 value = 1;
}

message AsAppendAction {
uint32 asn = 1;
uint32 repeat = 2;
bool use_right_most = 3;
}

message Actions {
RouteAction route_action = 1;
CommunityAction community = 2;
Expand All @@ -1065,6 +1071,7 @@ message Actions {
NexthopAction nexthop = 6;
LocalPrefAction local_pref = 7;
CommunityAction large_community = 8;
AsAppendAction as_append = 9;
}

message Statement {
Expand Down
35 changes: 35 additions & 0 deletions api/grpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1690,6 +1690,23 @@ func toStatementApi(s *config.Statement) *Statement {
UseLeftMost: useleft,
}
}(),
AsAppend: func() *AsAppendAction {
if len(s.Actions.BgpActions.SetAsPathAppend.As) == 0 {
return nil
}
var asn uint64
useright := false
if s.Actions.BgpActions.SetAsPathAppend.As != "first-as" {
asn, _ = strconv.ParseUint(s.Actions.BgpActions.SetAsPathAppend.As, 10, 32)
} else {
useright = true
}
return &AsAppendAction{
Asn: uint32(asn),
Repeat: uint32(s.Actions.BgpActions.SetAsPathAppend.RepeatN),
UseRightMost: useright,
}
}(),
ExtCommunity: func() *CommunityAction {
if len(s.Actions.BgpActions.SetExtCommunity.SetExtCommunityMethod.CommunitiesList) == 0 {
return nil
Expand Down Expand Up @@ -1960,6 +1977,21 @@ func NewAsPathPrependActionFromApiStruct(a *AsPrependAction) (*table.AsPathPrepe
})
}

func NewAsPathAppendActionFromApiStruct(a *AsAppendAction) (*table.AsPathAppendAction, error) {
if a == nil {
return nil, nil
}
return table.NewAsPathAppendAction(config.SetAsPathAppend{
RepeatN: uint8(a.Repeat),
As: func() string {
if a.UseRightMost {
return "first-as"
}
return fmt.Sprintf("%d", a.Asn)
}(),
})
}

func NewNexthopActionFromApiStruct(a *NexthopAction) (*table.NexthopAction, error) {
if a == nil {
return nil, nil
Expand Down Expand Up @@ -2047,6 +2079,9 @@ func NewStatementFromApiStruct(a *Statement) (*table.Statement, error) {
func() (table.Action, error) {
return NewAsPathPrependActionFromApiStruct(a.Actions.AsPrepend)
},
func() (table.Action, error) {
return NewAsPathAppendActionFromApiStruct(a.Actions.AsAppend)
},
func() (table.Action, error) {
return NewNexthopActionFromApiStruct(a.Actions.Nexthop)
},
Expand Down
34 changes: 34 additions & 0 deletions config/bgp_configs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4949,6 +4949,33 @@ func (lhs *SetLargeCommunity) Equal(rhs *SetLargeCommunity) bool {
return true
}

// struct for container gobgp:set-as-path-append.
// action to append the specified AS number to the AS-path a
// specified number of times.
type SetAsPathAppend struct {
// original -> gobgp:repeat-n
// number of times to append the specified AS number.
RepeatN uint8 `mapstructure:"repeat-n" json:"repeat-n,omitempty"`
// original -> gobgp:as
// gobgp:as's original type is union.
// autonomous system number or 'first-as' which means
// the rightmost as number in the AS-path to be appendded.
As string `mapstructure:"as" json:"as,omitempty"`
}

func (lhs *SetAsPathAppend) Equal(rhs *SetAsPathAppend) bool {
if lhs == nil || rhs == nil {
return false
}
if lhs.RepeatN != rhs.RepeatN {
return false
}
if lhs.As != rhs.As {
return false
}
return true
}

// struct for container bgp-pol:set-ext-community-method.
// Option to set communities using an inline list or
// reference to an existing defined set.
Expand Down Expand Up @@ -5134,6 +5161,10 @@ type BgpActions struct {
// set the med metric attribute in the route
// update.
SetMed BgpSetMedType `mapstructure:"set-med" json:"set-med,omitempty"`
// original -> gobgp:set-as-path-append
// action to append the specified AS number to the AS-path a
// specified number of times.
SetAsPathAppend SetAsPathAppend `mapstructure:"set-as-path-append" json:"set-as-path-append,omitempty"`
// original -> gobgp:set-large-community
SetLargeCommunity SetLargeCommunity `mapstructure:"set-large-community" json:"set-large-community,omitempty"`
}
Expand Down Expand Up @@ -5163,6 +5194,9 @@ func (lhs *BgpActions) Equal(rhs *BgpActions) bool {
if lhs.SetMed != rhs.SetMed {
return false
}
if !lhs.SetAsPathAppend.Equal(&(rhs.SetAsPathAppend)) {
return false
}
if !lhs.SetLargeCommunity.Equal(&(rhs.SetLargeCommunity)) {
return false
}
Expand Down
2 changes: 1 addition & 1 deletion docs/sources/cli-command-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ If you want to remove one element(extended community) of ExtCommunitySet, to spe
# mod a condition to a statement
% gobgp policy statement <statement name> { add | del | set } condition { { prefix | neighbor | as-path | community | ext-community | large-community } <set name> [{ any | all | invert }] | as-path-length <len> { eq | ge | le } | rpki { valid | invalid | not-found } }
# mod an action to a statement
% gobgp policy statement <statement name> { add | del | set } action { reject | accept | { community | ext-community | large-community } { add | remove | replace } <value>... | med { add | sub | set } <value> | local-pref <value> | as-prepend { <asn> | last-as } <repeat-value> }
% gobgp policy statement <statement name> { add | del | set } action { reject | accept | { community | ext-community | large-community } { add | remove | replace } <value>... | med { add | sub | set } <value> | local-pref <value> | as-prepend { <asn> | last-as } <repeat-value> | as-append { <asn> | first-as } <repeat-value> }
# show all statements
% gobgp policy statement
# show a specific statement
Expand Down
3 changes: 3 additions & 0 deletions docs/sources/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
[policy-definitions.statements.actions.bgp-actions.set-as-path-prepend]
as = "last-as"
repeat-n = 5
[policy-definitions.statements.actions.bgp-actions.set-as-path-append]
as = "12345"
repeat-n = 5
[policy-definitions.statements.actions]
route-disposition = "accept-route"
[[policy-definitions.statements]]
Expand Down
11 changes: 11 additions & 0 deletions docs/sources/policy.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ Actions are categorized into attributes below:
- set next-hop
- set local-pref
- prepend AS number in the AS_PATH attribute
- append AS number in the AS_PATH attribute

When **ALL** conditions in the statement are `true`, the action(s) in the
statement are executed.
Expand Down Expand Up @@ -617,6 +618,13 @@ evaluate routes from neighbors, if matched, action will be applied.
| as | AS number to prepend. You can use "last-as" to prepend the leftmost AS number in the aspath attribute.| "65100" |
| repeat-n | repeat count to prepend AS | 5 |

- policy-definitions.statements.actions.bgp-actions.set-as-path-append

| Element | Description | Example |
|----------|-------------------------------------------------------------------------------------------------------|---------|
| as | AS number to append. You can use "first-as" to append the rightmost AS number in the aspath attribute.| "65100" |
| repeat-n | repeat count to append AS | 5 |

#### Execution condition of Action

Action statement is executed when the result of each Condition, including
Expand Down Expand Up @@ -750,6 +758,9 @@ evaluate routes from neighbors, if matched, action will be applied.
[policy-definitions.statements.actions.bgp-actions.set-as-path-prepend]
as = "65005"
repeat-n = 5
[policy-definitions.statements.actions.bgp-actions.set-as-path-append]
as = "first-as"
repeat-n = 1
[policy-definitions.statements.actions.bgp-actions.set-community]
options = "ADD"
[policy-definitions.statements.actions.bgp-actions.set-community.set-community-method]
Expand Down
1 change: 1 addition & 0 deletions gobgp/cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ var actionOpts struct {
CommunityAction string `long:"community" description:"specifying a community action of policy"`
MedAction string `long:"med" description:"specifying a med action of policy"`
AsPathPrependAction string `long:"as-prepend" description:"specifying a as-prepend action of policy"`
AsPathAppendAction string `long:"as-append" description:"specifying a as-append action of policy"`
NexthopAction string `long:"next-hop" description:"specifying a next-hop action of policy"`
}

Expand Down
14 changes: 13 additions & 1 deletion gobgp/cmd/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,8 @@ func printStatement(indent int, s *table.Statement) {
fmt.Println(ind, "LocalPref: ", t.String())
case *table.AsPathPrependAction:
fmt.Println(ind, "ASPathPrepend: ", t.String())
case *table.AsPathAppendAction:
fmt.Println(ind, "ASPathAppend: ", t.String())
case *table.NexthopAction:
fmt.Println(ind, "Nexthop: ", t.String())
}
Expand Down Expand Up @@ -664,7 +666,7 @@ func modAction(name, op string, args []string) error {
}
usage := fmt.Sprintf("usage: gobgp policy statement %s %s action", name, op)
if len(args) < 1 {
return fmt.Errorf("%s { reject | accept | community | ext-community | large-community | med | local-pref | as-prepend | next-hop }", usage)
return fmt.Errorf("%s { reject | accept | community | ext-community | large-community | med | local-pref | as-prepend | as-append | next-hop }", usage)
}
typ := args[0]
args = args[1:]
Expand Down Expand Up @@ -755,6 +757,16 @@ func modAction(name, op string, args []string) error {
return err
}
stmt.Actions.BgpActions.SetAsPathPrepend.RepeatN = uint8(repeat)
case "as-append":
if len(args) < 2 {
return fmt.Errorf("%s as-append { <asn> | first-as } <repeat-value>", usage)
}
stmt.Actions.BgpActions.SetAsPathAppend.As = args[0]
repeat, err := strconv.ParseUint(args[1], 10, 8)
if err != nil {
return err
}
stmt.Actions.BgpActions.SetAsPathAppend.RepeatN = uint8(repeat)
case "next-hop":
if len(args) != 1 {
return fmt.Errorf("%s next-hop { <value> | self }", usage)
Expand Down
41 changes: 27 additions & 14 deletions table/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,18 @@ func (path *Path) IsEOR() bool {
return false
}

func cloneAsPath(asAttr *bgp.PathAttributeAsPath) *bgp.PathAttributeAsPath {
func cloneAsPathValue(asAttr *bgp.PathAttributeAsPath) []bgp.AsPathParamInterface {
if asAttr == nil {
return []bgp.AsPathParamInterface{}
}
newASparams := make([]bgp.AsPathParamInterface, len(asAttr.Value))
for i, param := range asAttr.Value {
asList := param.GetAS()
as := make([]uint32, len(asList))
copy(as, asList)
newASparams[i] = bgp.NewAs4PathParam(param.GetType(), as)
}
return bgp.NewPathAttributeAsPath(newASparams)
return newASparams
}

func UpdatePathAttrs(global *config.Global, peer *config.Neighbor, info *PeerInfo, original *Path) *Path {
Expand Down Expand Up @@ -755,37 +758,47 @@ func (path *Path) PrependAsn(asn uint32, repeat uint8, confed bool) {
segType = bgp.BGP_ASPATH_ATTR_TYPE_SEQ
}

original := path.GetAsPath()
values := cloneAsPathValue(path.GetAsPath())

asns := make([]uint32, repeat)
for i := range asns {
asns[i] = asn
}

var asPath *bgp.PathAttributeAsPath
if original == nil {
asPath = bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{})
} else {
asPath = cloneAsPath(original)
}

if len(asPath.Value) > 0 {
param := asPath.Value[0]
if len(values) > 0 {
param := values[0]
asList := param.GetAS()
if param.GetType() == segType {
if int(repeat)+len(asList) > 255 {
repeat = uint8(255 - len(asList))
}
newAsList := append(asns[:int(repeat)], asList...)
asPath.Value[0] = bgp.NewAs4PathParam(segType, newAsList)
values[0] = bgp.NewAs4PathParam(segType, newAsList)
asns = asns[int(repeat):]
}
}

if len(asns) > 0 {
p := bgp.NewAs4PathParam(segType, asns)
asPath.Value = append([]bgp.AsPathParamInterface{p}, asPath.Value...)
values = append([]bgp.AsPathParamInterface{p}, values...)
}

asPath := bgp.NewPathAttributeAsPath(values)
path.setPathAttr(asPath)
}

func (path *Path) AppendAsn(asn uint32, repeat uint8) {
values := cloneAsPathValue(path.GetAsPath())

asns := make([]uint32, repeat)
for i := range asns {
asns[i] = asn
}

p := bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, asns)
values = append(values, []bgp.AsPathParamInterface{p}...)

asPath := bgp.NewPathAttributeAsPath(values)
path.setPathAttr(asPath)
}

Expand Down
Loading