Skip to content

Commit

Permalink
mup: add Source Address to Type 1 ST Route
Browse files Browse the repository at this point in the history
This patch adds Source Address to Type 1 ST Route as defined in draft-mpmz-bess-mup-safi-03.
See https://datatracker.ietf.org/doc/html/draft-mpmz-bess-mup-safi-03#section-3.1.3
  • Loading branch information
higebu committed Dec 15, 2023
1 parent 7ddcd29 commit 270ee41
Show file tree
Hide file tree
Showing 12 changed files with 849 additions and 715 deletions.
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

0 comments on commit 270ee41

Please sign in to comment.