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

Import IPv4/6 routes from VRF tables to the Global RIB as EVPN IP Prefix #2856

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
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,20 @@ jobs:
sudo pip3 install -r test/pip-requires.txt
PYTHONPATH=test python3 test/scenario_test/vrf_neighbor_test2.py --gobgp-image gobgp -x -s

vrf-neighbor3:
name: vrf-neighbor3
runs-on: ubuntu-22.04
needs: build
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
- name: test
run: |
docker load < artifact/gobgp.tar
sudo apt-get install python3-setuptools
sudo pip3 install -r test/pip-requires.txt
PYTHONPATH=test python3 test/scenario_test/vrf_neighbor_test3.py --gobgp-image gobgp -x -s

rtc:
name: rtc
runs-on: ubuntu-22.04
Expand Down
2 changes: 1 addition & 1 deletion api/attribute.pb.go

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

2 changes: 1 addition & 1 deletion api/capability.pb.go

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

786 changes: 409 additions & 377 deletions api/gobgp.pb.go

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions api/gobgp.proto
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,9 @@ message Vrf {
// or FourOctetAsSpecificExtended.
repeated google.protobuf.Any export_rt = 4;
uint32 id = 5;
bool import_as_evpn_ipprefix = 6;
string routers_mac = 7;
uint32 ethernet_tag = 8;
}

message DefaultRouteDistance {
Expand Down
11 changes: 8 additions & 3 deletions cmd/gobgp/neighbor.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ var (
columnWidthTEID = 10
columnWidthQFI = 10
columnWidthEndpoint = 20
columnWidthAttrs = 20
)

func updateColumnWidth(nlri, nexthop, aspath, label, teid, qfi, endpoint string) {
func updateColumnWidth(nlri, nexthop, aspath, label, teid, qfi, endpoint, attrs string) {
if prefixLen := len(nlri); columnWidthPrefix < prefixLen {
columnWidthPrefix = prefixLen
}
Expand All @@ -69,6 +70,10 @@ func updateColumnWidth(nlri, nexthop, aspath, label, teid, qfi, endpoint string)
if columnWidthEndpoint < len(endpoint) {
columnWidthEndpoint = len(endpoint)
}
if columnWidthAttrs < len(attrs) {
columnWidthAttrs = len(attrs)
}

}

func getNeighbors(address string, enableAdv bool) ([]*api.Peer, error) {
Expand Down Expand Up @@ -660,7 +665,7 @@ func makeShowRouteArgs(p *api.Path, idx int, now time.Time, showAge, showBest, s
}
}

updateColumnWidth(nlri.String(), nexthop, aspathstr, label, teid, qfi, endpoint)
updateColumnWidth(nlri.String(), nexthop, aspathstr, label, teid, qfi, endpoint, pattrstr)

return args
}
Expand Down Expand Up @@ -699,7 +704,7 @@ func showRoute(dsts []*api.Destination, showAge, showBest, showLabel, showMUP, s
format += "%-10s "
}
headers = append(headers, "Attrs")
format += "%-s"
format += fmt.Sprintf("%%-%ds ", columnWidthAttrs)

if showSendMaxFiltered {
headers = append(headers, "Filtered")
Expand Down
57 changes: 43 additions & 14 deletions cmd/gobgp/vrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"encoding/json"
"fmt"
"io"
"net"
"sort"
"strconv"
"strings"
Expand Down Expand Up @@ -53,7 +54,7 @@ func getVrfs() ([]*api.Vrf, error) {
}

func showVrfs() error {
maxLens := []int{20, 20, 20, 20, 5}
maxLens := []int{20, 20, 20, 20, 20, 5, 20, 5}
vrfs, err := getVrfs()
if err != nil {
return err
Expand Down Expand Up @@ -98,19 +99,19 @@ func showVrfs() error {
if err != nil {
return err
}
lines = append(lines, []string{name, rdStr, importRts, exportRts, fmt.Sprintf("%d", v.Id)})
lines = append(lines, []string{name, rdStr, importRts, exportRts, v.RoutersMac, fmt.Sprintf("%d", v.Id), fmt.Sprintf("%v", v.ImportAsEvpnIpprefix), fmt.Sprintf("%d", v.EthernetTag)})

for i, v := range []int{len(name), len(rdStr), len(importRts), len(exportRts)} {
for i, v := range []int{len(name), len(rdStr), len(importRts), len(exportRts), len(v.RoutersMac)} {
if v > maxLens[i] {
maxLens[i] = v + 4
}
}

}
format := fmt.Sprintf(" %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds\n", maxLens[0], maxLens[1], maxLens[2], maxLens[3], maxLens[4])
fmt.Printf(format, "Name", "RD", "Import RT", "Export RT", "ID")
format := fmt.Sprintf(" %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds %%-%ds\n", maxLens[0], maxLens[1], maxLens[2], maxLens[3], maxLens[4], maxLens[5], maxLens[6], maxLens[7])
fmt.Printf(format, "Name", "RD", "Import RT", "Export RT", "Router's MAC", "ID", "Import as EVPN", "Ethernet Tag")
for _, l := range lines {
fmt.Printf(format, l[0], l[1], l[2], l[3], l[4])
fmt.Printf(format, l[0], l[1], l[2], l[3], l[4], l[5], l[6], l[7])
}
return nil
}
Expand All @@ -123,9 +124,13 @@ func modVrf(typ string, args []string) error {
switch typ {
case cmdAdd:
a, err := extractReserved(args, map[string]int{
"rd": paramSingle,
"rt": paramList,
"id": paramSingle})
"rd": paramSingle,
"rt": paramList,
"id": paramSingle,
"import-as-evpn": paramFlag,
"routers-mac": paramSingle,
"ethernet-tag": paramSingle,
})
if err != nil || len(a[""]) != 1 || len(a["rd"]) != 1 || len(a["rt"]) < 2 {
//lint:ignore ST1005 cli example
return fmt.Errorf("usage: gobgp vrf add <vrf name> [ id <id> ] rd <rd> rt { import | export | both } <rt>...")
Expand Down Expand Up @@ -172,13 +177,37 @@ func modVrf(typ string, args []string) error {
irt, _ := apiutil.MarshalRTs(importRt)
ert, _ := apiutil.MarshalRTs(exportRt)

var etag uint64
if len(a["ethernet-tag"]) > 0 {
etag, err = strconv.ParseUint(a["ethernet-tag"][0], 10, 32)
if err != nil {
return err
}
}

importAsEVPN := false
if _, ok := a["import-as-evpn"]; ok {
importAsEVPN = true
}

routersMac := ""
if mac, ok := a["routers-mac"]; ok {
if _, err := net.ParseMAC(mac[0]); err != nil {
return fmt.Errorf("invalid router's mac: %q", mac[0])
}
routersMac = mac[0]
}

_, err = client.AddVrf(ctx, &api.AddVrfRequest{
Vrf: &api.Vrf{
Name: name,
Rd: v,
ImportRt: irt,
ExportRt: ert,
Id: uint32(id),
Name: name,
Rd: v,
ImportRt: irt,
ExportRt: ert,
Id: uint32(id),
ImportAsEvpnIpprefix: importAsEVPN,
RoutersMac: routersMac,
EthernetTag: uint32(etag),
},
})
return err
Expand Down
9 changes: 9 additions & 0 deletions docs/sources/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@
# are preferred than both-rt-list.
both-rt-list = ["65000:100"]

[[vrfs]]
[vrfs.config]
name = "vrf2"
rd = "65000:200"
both-rt-list = ["65000:200"]
import-as-evpn-ipprefix = true
routers-mac = "ca:fe:00:00:be:ef"
ethernet-tag = 100

[[mrt-dump]]
[mrt-dump.config]
dump-type = "updates"
Expand Down
64 changes: 55 additions & 9 deletions internal/pkg/table/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -1115,11 +1115,18 @@ func (lhs *Path) Compare(rhs *Path) int {

func (v *Vrf) ToGlobalPath(path *Path) error {
nlri := path.GetNlri()
addRoutersMacAttr := false
switch rf := path.GetRouteFamily(); rf {
case bgp.RF_IPv4_UC:
n := nlri.(*bgp.IPAddrPrefix)
pathIdentifier := path.GetNlri().PathIdentifier()
path.OriginInfo().nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(v.MplsLabel), v.Rd)
if v.ImportToGlobalAsEvpnType5 {
esi, _ := bgp.ParseEthernetSegmentIdentifier([]string{"single-homed"})
path.OriginInfo().nlri = bgp.NewEVPNIPPrefixRoute(v.Rd, esi, v.EthernetTag, n.Length, n.Prefix.String(), "0.0.0.0", 0)
addRoutersMacAttr = true
} else {
path.OriginInfo().nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(v.MplsLabel), v.Rd)
}
path.GetNlri().SetPathIdentifier(pathIdentifier)
case bgp.RF_FS_IPv4_UC:
n := nlri.(*bgp.FlowSpecIPv4Unicast)
Expand All @@ -1129,7 +1136,13 @@ func (v *Vrf) ToGlobalPath(path *Path) error {
case bgp.RF_IPv6_UC:
n := nlri.(*bgp.IPv6AddrPrefix)
pathIdentifier := path.GetNlri().PathIdentifier()
path.OriginInfo().nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(v.MplsLabel), v.Rd)
if v.ImportToGlobalAsEvpnType5 {
esi, _ := bgp.ParseEthernetSegmentIdentifier([]string{"single-homed"})
path.OriginInfo().nlri = bgp.NewEVPNIPPrefixRoute(v.Rd, esi, v.EthernetTag, n.Length, n.Prefix.String(), "0.0.0.0", 0)
addRoutersMacAttr = true
} else {
path.OriginInfo().nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(v.MplsLabel), v.Rd)
}
path.GetNlri().SetPathIdentifier(pathIdentifier)
case bgp.RF_FS_IPv6_UC:
n := nlri.(*bgp.FlowSpecIPv6Unicast)
Expand Down Expand Up @@ -1159,23 +1172,41 @@ func (v *Vrf) ToGlobalPath(path *Path) error {
default:
return fmt.Errorf("unsupported route family for vrf: %s", rf)
}
path.SetExtCommunities(v.ExportRt, false)
extCommunity := v.ExportRt
if addRoutersMacAttr {
extCommunity = append(extCommunity, bgp.NewRoutersMacExtended(v.RoutersMac))
}
path.SetExtCommunities(extCommunity, false)

return nil
}

func (p *Path) ToGlobal(vrf *Vrf) *Path {
nlri := p.GetNlri()
nh := p.GetNexthop()
pathId := nlri.PathIdentifier()
addRoutersMacAttr := false
switch rf := p.GetRouteFamily(); rf {
case bgp.RF_IPv4_UC:
n := nlri.(*bgp.IPAddrPrefix)
nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(vrf.MplsLabel), vrf.Rd)
nlri.SetPathIdentifier(pathId)
if vrf.ImportToGlobalAsEvpnType5 {
esi, _ := bgp.ParseEthernetSegmentIdentifier([]string{"single-homed"})
nlri = bgp.NewEVPNIPPrefixRoute(vrf.Rd, esi, vrf.EthernetTag, n.Length, n.Prefix.String(), "0.0.0.0", 0)
addRoutersMacAttr = true
} else {
nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(vrf.MplsLabel), vrf.Rd)
nlri.SetPathIdentifier(pathId)
}
case bgp.RF_IPv6_UC:
n := nlri.(*bgp.IPv6AddrPrefix)
nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(vrf.MplsLabel), vrf.Rd)
nlri.SetPathIdentifier(pathId)
if vrf.ImportToGlobalAsEvpnType5 {
esi, _ := bgp.ParseEthernetSegmentIdentifier([]string{"single-homed"})
nlri = bgp.NewEVPNIPPrefixRoute(vrf.Rd, esi, vrf.EthernetTag, n.Length, n.Prefix.String(), "0.0.0.0", 0)
addRoutersMacAttr = true
} else {
nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(vrf.MplsLabel), vrf.Rd)
nlri.SetPathIdentifier(pathId)
}
case bgp.RF_EVPN:
n := nlri.(*bgp.EVPNNLRI)
switch n.RouteType {
Expand Down Expand Up @@ -1222,9 +1253,15 @@ func (p *Path) ToGlobal(vrf *Vrf) *Path {
return p
}
path := NewPath(p.OriginInfo().source, nlri, p.IsWithdraw, p.GetPathAttrs(), p.GetTimestamp(), false)
path.SetExtCommunities(vrf.ExportRt, false)

path.delPathAttr(bgp.BGP_ATTR_TYPE_NEXT_HOP)
path.setPathAttr(bgp.NewPathAttributeMpReachNLRI(nh.String(), []bgp.AddrPrefixInterface{nlri}))

extCommunities := vrf.ExportRt
if addRoutersMacAttr {
extCommunities = append(extCommunities, bgp.NewRoutersMacExtended(vrf.RoutersMac))
}
path.SetExtCommunities(extCommunities, false)
return path
}

Expand Down Expand Up @@ -1258,12 +1295,21 @@ func (p *Path) ToLocal() *Path {
nlri = bgp.NewFlowSpecIPv6Unicast(n.FlowSpecNLRI.Value)
nlri.SetPathLocalIdentifier(localPathId)
nlri.SetPathIdentifier(pathId)
case bgp.RF_EVPN:
n := nlri.(*bgp.EVPNNLRI)
v, ok := n.RouteTypeData.(*bgp.EVPNIPPrefixRoute)
if !ok {
return p
}
nlri = bgp.NewIPAddrPrefix(v.IPPrefixLength, v.IPPrefix.String())
nlri.SetPathLocalIdentifier(localPathId)
nlri.SetPathIdentifier(pathId)
default:
return p
}
path := NewPath(p.OriginInfo().source, nlri, p.IsWithdraw, p.GetPathAttrs(), p.GetTimestamp(), false)
switch f {
case bgp.RF_IPv4_VPN, bgp.RF_IPv6_VPN:
case bgp.RF_IPv4_VPN, bgp.RF_IPv6_VPN, bgp.RF_EVPN:
path.delPathAttr(bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES)
case bgp.RF_FS_IPv4_VPN, bgp.RF_FS_IPv6_VPN:
extcomms := path.GetExtCommunities()
Expand Down
Loading
Loading