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

mup: add Source Address to Type 1 ST Route #2753

Merged
merged 1 commit into from
Dec 15, 2023
Merged
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
1,251 changes: 636 additions & 615 deletions api/attribute.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions api/attribute.proto
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,8 @@ message MUPType1SessionTransformedRoute {
uint32 qfi = 5;
uint32 endpoint_address_length = 6;
string endpoint_address = 7;
uint32 source_address_length = 8;
string source_address = 9;
}

message MUPType2SessionTransformedRoute {
Expand Down
4 changes: 2 additions & 2 deletions api/gobgp.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions api/gobgp_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions cmd/gobgp/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -1152,7 +1152,7 @@ func parseTeid(s string) (teid netip.Addr, err error) {

func parseMUPType1SessionTransformedRouteArgs(args []string, afi uint16) (bgp.AddrPrefixInterface, *bgp.PathAttributePrefixSID, []string, error) {
// Format:
// <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint>
// <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint> [source <source>]
req := 5
if len(args) < req {
return nil, nil, nil, fmt.Errorf("%d args required at least, but got %d", req, len(args))
Expand All @@ -1163,6 +1163,7 @@ func parseMUPType1SessionTransformedRouteArgs(args []string, afi uint16) (bgp.Ad
"teid": paramSingle,
"qfi": paramSingle,
"endpoint": paramSingle,
"source": paramSingle,
})
if err != nil {
return nil, nil, nil, err
Expand Down Expand Up @@ -1209,6 +1210,14 @@ func parseMUPType1SessionTransformedRouteArgs(args []string, afi uint16) (bgp.Ad
EndpointAddressLength: uint8(ea.BitLen()),
EndpointAddress: ea,
}
if len(m["source"]) > 0 {
sa, err := netip.ParseAddr(m["source"][0])
if err != nil {
return nil, nil, nil, err
}
r.SourceAddressLength = uint8(sa.BitLen())
r.SourceAddress = &sa
}
return bgp.NewMUPNLRI(afi, bgp.MUP_ARCH_TYPE_UNDEFINED, bgp.MUP_ROUTE_TYPE_TYPE_1_SESSION_TRANSFORMED, r), nil, extcomms, nil
}

Expand Down Expand Up @@ -2166,7 +2175,7 @@ usage: %s rib %s { a-d <A-D> | macadv <MACADV> | multicast <MULTICAST> | esi <ES
usage: %s rib %s { isd <ISD> | dsd <DSD> | t1st <T1ST> | t2st <T2ST> } -a mup-ipv4
<ISD> : <ip prefix> rd <rd> prefix <prefix> locator-node-length <locator-node-length> function-length <function-length> behavior <behavior> [rt <rt>...]
<DSD> : <ip address> rd <rd> prefix <prefix> locator-node-length <locator-node-length> function-length <function-length> behavior <behavior> [rt <rt>...] [mup <segment identifier>]
<T1ST> : <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint>
<T1ST> : <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint> [source <source>]
<T2ST> : <endpoint address> rd <rd> [rt <rt>...] endpoint-address-length <endpoint-address-length> teid <teid> [mup <segment identifier>]`,
err,
cmdstr,
Expand All @@ -2176,7 +2185,7 @@ usage: %s rib %s { isd <ISD> | dsd <DSD> | t1st <T1ST> | t2st <T2ST> } -a mup-ip
usage: %s rib %s { isd <ISD> | dsd <DSD> | t1st <T1ST> | t2st <T2ST> } -a mup-ipv6
<ISD> : <ip prefix> rd <rd> prefix <prefix> locator-node-length <locator-node-length> function-length <function-length> behavior <behavior> [rt <rt>...]
<DSD> : <ip address> rd <rd> prefix <prefix> locator-node-length <locator-node-length> function-length <function-length> behavior <behavior> [rt <rt>...] [mup <segment identifier>]
<T1ST> : <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint>
<T1ST> : <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint> [source <source>]
<T2ST> : <endpoint address> rd <rd> [rt <rt>...] endpoint-address-length <endpoint-address-length> teid <teid> [mup <segment identifier>]`,
err,
cmdstr,
Expand Down
10 changes: 5 additions & 5 deletions docs/sources/srv6_mup.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# BGP Extensions for the Mobile User Plane (MUP) SAFI

This feature is implementation of [the Internet-Draft, BGP Extensions for the Mobile User Plane (MUP) SAFI](https://datatracker.ietf.org/doc/html/draft-mpmz-bess-mup-safi-01).
This feature is implementation of [the Internet-Draft, BGP Extensions for the Mobile User Plane (MUP) SAFI](https://datatracker.ietf.org/doc/html/draft-mpmz-bess-mup-safi-03).

## Contents

Expand Down Expand Up @@ -83,16 +83,16 @@ $ gobgp global rib -a ipv6-mup

```shell
# Add a route
gobgp global rib add -a ipv4-mup t1st <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint>
gobgp global rib add -a ipv6-mup t1st <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint>
gobgp global rib add -a ipv4-mup t1st <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint> [source <source>]
gobgp global rib add -a ipv6-mup t1st <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint> [source <source>]

# Show routes
gobgp global rib -a ipv4-mup
gobgp global rib -a ipv6-mup

# Delete a route
gobgp global rib del -a ipv4-mup t1st <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint>
gobgp global rib del -a ipv6-mup t1st <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint>
gobgp global rib del -a ipv4-mup t1st <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint> [source <source>]
gobgp global rib del -a ipv6-mup t1st <ip prefix> rd <rd> [rt <rt>...] teid <teid> qfi <qfi> endpoint <endpoint> [source <source>]
```

The format of the TEID: hexadecimal (beginning with '0x'), decimal (uint32), or IPv4.
Expand Down
3 changes: 1 addition & 2 deletions internal/pkg/table/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,6 @@ func (path *Path) GetAsList() []uint32 {

func (path *Path) GetAsSeqList() []uint32 {
return path.getAsListOfSpecificType(true, false)

}

func (path *Path) getAsListOfSpecificType(getAsSeq, getAsSet bool) []uint32 {
Expand Down Expand Up @@ -1164,7 +1163,7 @@ func (p *Path) ToGlobal(vrf *Vrf) *Path {
nlri = bgp.NewMUPDirectSegmentDiscoveryRoute(vrf.Rd, old.Address)
case bgp.MUP_ROUTE_TYPE_TYPE_1_SESSION_TRANSFORMED:
old := n.RouteTypeData.(*bgp.MUPType1SessionTransformedRoute)
nlri = bgp.NewMUPType1SessionTransformedRoute(vrf.Rd, old.Prefix, old.TEID, old.QFI, old.EndpointAddress)
nlri = bgp.NewMUPType1SessionTransformedRoute(vrf.Rd, old.Prefix, old.TEID, old.QFI, old.EndpointAddress, old.SourceAddress)
case bgp.MUP_ROUTE_TYPE_TYPE_2_SESSION_TRANSFORMED:
old := n.RouteTypeData.(*bgp.MUPType2SessionTransformedRoute)
nlri = bgp.NewMUPType2SessionTransformedRoute(vrf.Rd, old.EndpointAddressLength, old.EndpointAddress, old.TEID)
Expand Down
18 changes: 17 additions & 1 deletion pkg/apiutil/attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -1352,13 +1352,21 @@ func MarshalNLRI(value bgp.AddrPrefixInterface) (*apb.Any, error) {
if err != nil {
return nil, err
}
var sal uint32
var sa string
if r.SourceAddressLength > 0 && r.SourceAddress != nil {
sal = uint32(r.SourceAddressLength)
sa = r.SourceAddress.String()
}
nlri = &api.MUPType1SessionTransformedRoute{
Rd: rd,
Prefix: r.Prefix.String(),
Teid: binary.BigEndian.Uint32(r.TEID.AsSlice()),
Qfi: uint32(r.QFI),
EndpointAddressLength: uint32(r.EndpointAddressLength),
EndpointAddress: r.EndpointAddress.String(),
SourceAddressLength: sal,
SourceAddress: sa,
}
case *bgp.MUPType2SessionTransformedRoute:
rd, err := MarshalRD(r.RD)
Expand Down Expand Up @@ -1581,7 +1589,15 @@ func UnmarshalNLRI(rf bgp.RouteFamily, an *apb.Any) (bgp.AddrPrefixInterface, er
if !ok {
return nil, fmt.Errorf("invalid teid: %x", v.Teid)
}
nlri = bgp.NewMUPType1SessionTransformedRoute(rd, prefix, teid, uint8(v.Qfi), ea)
var sa *netip.Addr
if v.SourceAddressLength > 0 && v.SourceAddress != "" {
a, err := netip.ParseAddr(v.SourceAddress)
if err != nil {
return nil, err
}
sa = &a
}
nlri = bgp.NewMUPType1SessionTransformedRoute(rd, prefix, teid, uint8(v.Qfi), ea, sa)
case *api.MUPType2SessionTransformedRoute:
rd, err := UnmarshalRD(v.Rd)
if err != nil {
Expand Down
90 changes: 56 additions & 34 deletions pkg/apiutil/attribute_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1294,47 +1294,69 @@ func Test_MpReachNLRIAttribute_MUPDirectSegmentDiscoveryRoute(t *testing.T) {

func Test_MpReachNLRIAttribute_MUPType1SessionTransformedRoute(t *testing.T) {
assert := assert.New(t)

nlris := make([]*apb.Any, 0, 1)
rd, err := apb.New(&api.RouteDistinguisherTwoOctetASN{
Admin: 65000,
Assigned: 100,
})
assert.Nil(err)
a, err := apb.New(&api.MUPType1SessionTransformedRoute{
Rd: rd,
Prefix: "192.168.100.1/32",
Teid: 12345,
Qfi: 9,
EndpointAddressLength: 32,
EndpointAddress: "10.0.0.1",
})
assert.Nil(err)
nlris = append(nlris, a)

input := &api.MpReachNLRIAttribute{
Family: &api.Family{
Afi: api.Family_AFI_IP,
Safi: api.Family_SAFI_MUP,
tests := []struct {
name string
in *api.MUPType1SessionTransformedRoute
}{
{
name: "IPv4",
in: &api.MUPType1SessionTransformedRoute{
Rd: rd,
Prefix: "192.168.100.1/32",
Teid: 12345,
Qfi: 9,
EndpointAddressLength: 32,
EndpointAddress: "10.0.0.1",
},
},
{
name: "IPv4_with_SourceAddress",
in: &api.MUPType1SessionTransformedRoute{
Rd: rd,
Prefix: "192.168.100.1/32",
Teid: 12345,
Qfi: 9,
EndpointAddressLength: 32,
EndpointAddress: "10.0.0.1",
SourceAddressLength: 32,
SourceAddress: "10.0.0.2",
},
},
NextHops: []string{"0.0.0.0"},
Nlris: nlris,
}

a, err = apb.New(input)
assert.Nil(err)
n, err := UnmarshalAttribute(a)
assert.Nil(err)

output, _ := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
assert.Equal(input.Family.Afi, output.Family.Afi)
assert.Equal(input.Family.Safi, output.Family.Safi)
assert.Equal(input.NextHops, output.NextHops)
assert.Equal(1, len(output.Nlris))
for idx, inputNLRI := range input.Nlris {
outputNLRI := output.Nlris[idx]
assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
assert.Equal(inputNLRI.Value, outputNLRI.Value)
for _, tt := range tests {
a, err := apb.New(tt.in)
assert.Nil(err)
nlris := []*apb.Any{a}

input := &api.MpReachNLRIAttribute{
Family: &api.Family{
Afi: api.Family_AFI_IP,
Safi: api.Family_SAFI_MUP,
},
NextHops: []string{"0.0.0.0"},
Nlris: nlris,
}

a, err = apb.New(input)
assert.Nil(err)
n, err := UnmarshalAttribute(a)
assert.Nil(err)

output, _ := NewMpReachNLRIAttributeFromNative(n.(*bgp.PathAttributeMpReachNLRI))
assert.Equal(input.Family.Afi, output.Family.Afi)
assert.Equal(input.Family.Safi, output.Family.Safi)
assert.Equal(input.NextHops, output.NextHops)
assert.Equal(1, len(output.Nlris))
for idx, inputNLRI := range input.Nlris {
outputNLRI := output.Nlris[idx]
assert.Equal(inputNLRI.TypeUrl, outputNLRI.TypeUrl)
assert.Equal(inputNLRI.Value, outputNLRI.Value)
}
}
}

Expand Down
46 changes: 38 additions & 8 deletions pkg/packet/bgp/mup.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,29 +444,36 @@ func (r *MUPDirectSegmentDiscoveryRoute) rd() RouteDistinguisherInterface {
}

// MUPType1SessionTransformedRoute3GPP5G represents 3GPP 5G specific Type 1 Session Transformed (ST) Route as described in
// https://datatracker.ietf.org/doc/html/draft-mpmz-bess-mup-safi-00#section-3.1.3
// https://datatracker.ietf.org/doc/html/draft-mpmz-bess-mup-safi-03#section-3.1.3
type MUPType1SessionTransformedRoute struct {
RD RouteDistinguisherInterface
Prefix netip.Prefix
TEID netip.Addr
QFI uint8
EndpointAddressLength uint8
EndpointAddress netip.Addr
SourceAddressLength uint8
SourceAddress *netip.Addr
}

func NewMUPType1SessionTransformedRoute(rd RouteDistinguisherInterface, prefix netip.Prefix, teid netip.Addr, qfi uint8, ea netip.Addr) *MUPNLRI {
func NewMUPType1SessionTransformedRoute(rd RouteDistinguisherInterface, prefix netip.Prefix, teid netip.Addr, qfi uint8, ea netip.Addr, sa *netip.Addr) *MUPNLRI {
afi := uint16(AFI_IP)
if prefix.Addr().Is6() {
afi = uint16(AFI_IP6)
}
return NewMUPNLRI(afi, MUP_ARCH_TYPE_3GPP_5G, MUP_ROUTE_TYPE_TYPE_1_SESSION_TRANSFORMED, &MUPType1SessionTransformedRoute{
r := &MUPType1SessionTransformedRoute{
RD: rd,
Prefix: prefix,
TEID: teid,
QFI: qfi,
EndpointAddressLength: uint8(ea.BitLen()),
EndpointAddress: ea,
})
}
if sa != nil {
r.SourceAddressLength = uint8(sa.BitLen())
r.SourceAddress = sa
}
return NewMUPNLRI(afi, MUP_ARCH_TYPE_3GPP_5G, MUP_ROUTE_TYPE_TYPE_1_SESSION_TRANSFORMED, r)
}

func (r *MUPType1SessionTransformedRoute) DecodeFromBytes(data []byte, afi uint16) error {
Expand Down Expand Up @@ -519,6 +526,16 @@ func (r *MUPType1SessionTransformedRoute) DecodeFromBytes(data []byte, afi uint1
} else {
return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid Endpoint Address length: %d", r.EndpointAddressLength))
}
p += int(r.EndpointAddressLength / 8)
r.SourceAddressLength = data[p]
p += 1
if r.SourceAddressLength == 32 || r.SourceAddressLength == 128 {
sa, ok := netip.AddrFromSlice(data[p : p+int(r.SourceAddressLength/8)])
if !ok {
return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid Source Address: %x", data[p:p+int(r.SourceAddressLength/8)]))
}
r.SourceAddress = &sa
}
return nil
}

Expand All @@ -540,6 +557,10 @@ func (r *MUPType1SessionTransformedRoute) Serialize() ([]byte, error) {
buf = append(buf, r.QFI)
buf = append(buf, r.EndpointAddressLength)
buf = append(buf, r.EndpointAddress.AsSlice()...)
buf = append(buf, r.SourceAddressLength)
if r.SourceAddressLength > 0 {
buf = append(buf, r.SourceAddress.AsSlice()...)
}
return buf, nil
}

Expand All @@ -552,8 +573,12 @@ func (r *MUPType1SessionTransformedRoute) AFI() uint16 {

func (r *MUPType1SessionTransformedRoute) Len() int {
// RD(8) + PrefixLength(1) + Prefix(variable)
// + TEID(4) + QFI(1) + EndpointAddressLength(1) + EndpointAddress(4 or 16)
return 15 + (r.Prefix.Bits()+7)/8 + int(r.EndpointAddressLength/8)
// + TEID(4) + QFI(1) + EndpointAddressLength(1) + EndpointAddress(4 or 16) + SourceAddressLength(1) + SourceAddress(4 or 16)
l := 16 + (r.Prefix.Bits()+7)/8 + int(r.EndpointAddressLength/8)
if r.SourceAddressLength > 0 {
l += int(r.SourceAddressLength / 8)
}
return l
}

func (r *MUPType1SessionTransformedRoute) String() string {
Expand All @@ -564,19 +589,24 @@ func (r *MUPType1SessionTransformedRoute) String() string {
}

func (r *MUPType1SessionTransformedRoute) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
d := struct {
RD RouteDistinguisherInterface `json:"rd"`
Prefix string `json:"prefix"`
TEID string `json:"teid"`
QFI uint8 `json:"qfi"`
EndpointAddress string `json:"endpoint_address"`
SourceAddress string `json:"source_address"`
}{
RD: r.RD,
Prefix: r.Prefix.String(),
TEID: r.TEID.String(),
QFI: r.QFI,
EndpointAddress: r.EndpointAddress.String(),
})
}
if r.SourceAddress != nil {
d.SourceAddress = r.SourceAddress.String()
}
return json.Marshal(d)
}

func (r *MUPType1SessionTransformedRoute) rd() RouteDistinguisherInterface {
Expand Down
Loading
Loading