Skip to content

Commit a4509bd

Browse files
committed
Added support for "routeserver_info_types=Route Server,NSP" in ini-files,
that will consider ingother network types for routeserver, while trying to keep the default behavior (until now)
1 parent cc7a06e commit a4509bd

File tree

7 files changed

+163
-14
lines changed

7 files changed

+163
-14
lines changed

Readme.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,13 @@ Setting wildcard to enableAll will configure all neighbors from the Exchange, no
293293
good for configuration testing, benchmarking, and history ...! Be sure to set the _-myasn_ parameter on start, so that
294294
neighbor statements for your network will be omitted.
295295

296+
### routeserver info types
297+
298+
Some IXs have the network type set to "NSP", in which case the route servers are not recognized despite a correct ASN. This allows you to override the info types with a comma-separated list for the IX. For example:
299+
300+
- routeserver_info_types=NSP,Route Server
301+
302+
296303
#### additional configuration
297304

298305
You can use this code to generate peer-group configuration or anything else you want to add before the single peer

inireader/iniread.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ package inireader
33
import (
44
"bufio"
55
"fmt"
6-
"github.com/ipcjk/ixgen/ixtypes"
76
"io"
87
"log"
98
"regexp"
109
"strconv"
1110
"strings"
11+
12+
"github.com/ipcjk/ixgen/ixtypes"
1213
)
1314

1415
var splitBy = `\s+`
@@ -28,6 +29,7 @@ var PossibleOptions = map[string]bool{
2829
"routeserver_prefixes6": true,
2930
"rs_asn": true,
3031
"wildcard_prefix_filter": true,
32+
"routeserver_info_types": true,
3133
}
3234

3335
const (
@@ -103,6 +105,9 @@ func ReadPeeringConfig(r io.Reader) ixtypes.IXs {
103105
if ix.Options[currentHead]["peer_group"] != "" {
104106
ix.PeeringGroups[string(ix.Options[currentHead]["peer_group"])] = true
105107
}
108+
if ix.Options[currentHead]["routeserver_info_types"] != "" {
109+
ix.PeeringGroups[string(ix.Options[currentHead]["routeserver_info_types"])] = true
110+
}
106111
} else if line != "" && whichSection == peers {
107112
Peer := ParsePeerLine(line, lineNum)
108113
if Peer.Active == true {

inireader_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package main
22

33
import (
4+
"testing"
5+
46
"github.com/ipcjk/ixgen/inireader"
57
"github.com/ipcjk/ixgen/ixtypes"
6-
"testing"
78
)
89

910
func TestParsePeerFunction(t *testing.T) {
@@ -62,6 +63,7 @@ func TestExchangeOption(t *testing.T) {
6263
inireader.ParseOptionLine("routeserver_prefixes6=400", ixConfig, "testIX")
6364
inireader.ParseOptionLine("rs_asn=6695", ixConfig, "testIX")
6465
inireader.ParseOptionLine("wildcard_prefix_filter=1", ixConfig, "testIX")
66+
inireader.ParseOptionLine("routeserver_info_types=Route Server,NSP", ixConfig, "testIX")
6567

6668
/* Check that we covered all cases from inireader */
6769
for k := range inireader.PossibleOptions {
@@ -103,4 +105,8 @@ func TestExchangeOption(t *testing.T) {
103105
if ixConfig["testIX"]["wildcard_prefix_filter"] != "1" {
104106
t.Error("Prefix filter options for wildcards peers is not set")
105107
}
108+
109+
if ixConfig["testIX"]["routeserver_info_types"] != "Route Server,NSP" {
110+
t.Error("Routeserver info types are wrong")
111+
}
106112
}

ixworkers/ixworkers.go

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"strconv"
66
"sync"
77

8+
"strings"
9+
810
"github.com/ipcjk/ixgen/bgpqworkers"
911
"github.com/ipcjk/ixgen/ixtypes"
1012
"github.com/ipcjk/ixgen/peeringdb"
@@ -18,6 +20,16 @@ func isTrue(value string) bool {
1820
return false
1921
}
2022

23+
/* helper function to check if a string slice contains a value */
24+
func contains(slice []string, value string) bool {
25+
for _, item := range slice {
26+
if item == value {
27+
return true
28+
}
29+
}
30+
return false
31+
}
32+
2133
func WorkerMergePeerConfiguration(exchanges ixtypes.IXs, apiServiceURL string, apiKey string, exchangeOnly string, myASN int64, prefixFactor float64) ixtypes.IXs {
2234
var wg sync.WaitGroup
2335
peerDB := peeringdb.Peeringdb(apiServiceURL, apiKey)
@@ -54,6 +66,16 @@ func WorkerMergePeerConfiguration(exchanges ixtypes.IXs, apiServiceURL string, a
5466
return
5567
}
5668

69+
/* Parse routeserver_info_types from config into a map for fast lookup */
70+
rsInfoTypesMap := make(map[string]bool)
71+
rsInfoTypesMap["Route Server"] = true // default
72+
73+
if rsInfoTypes, rsInfoTypesOk := exchanges[i].Options[exchanges[i].IxName]["routeserver_info_types"]; rsInfoTypesOk && string(rsInfoTypes) != "" {
74+
for _, rsInfoType := range strings.Split(string(rsInfoTypes), ",") {
75+
rsInfoTypesMap[strings.TrimSpace(rsInfoType)] = true
76+
}
77+
}
78+
5779
/* peering DB api change, pull asns into a local query list,
5880
respect other threads if necessary */
5981
for _, peer := range myPeers.Data {
@@ -129,7 +151,38 @@ func WorkerMergePeerConfiguration(exchanges ixtypes.IXs, apiServiceURL string, a
129151
continue
130152
}
131153

132-
if peerDbNetwork.InfoType == "Route Server" {
154+
/* Check both info_type (legacy) and info_types (array) for configured route server types */
155+
isRouteServerType := false
156+
hasRouteServerType := false
157+
158+
// Check InfoTypes array
159+
for _, infoType := range peerDbNetwork.InfoTypes {
160+
if rsInfoTypesMap[infoType] {
161+
isRouteServerType = true
162+
if infoType == "Route Server" {
163+
hasRouteServerType = true
164+
}
165+
}
166+
}
167+
168+
// Check legacy InfoType string
169+
if rsInfoTypesMap[peerDbNetwork.InfoType] {
170+
isRouteServerType = true
171+
if peerDbNetwork.InfoType == "Route Server" {
172+
hasRouteServerType = true
173+
}
174+
}
175+
176+
// Legacy behavior: if "Route Server" type found and rs_asn configured, validate ASN match
177+
if hasRouteServerType && rsnOk && peerASN != string(rsnASN) {
178+
log.Printf("Ignoring route-server advertised from ASN %s, but IX ASN shall be %s\n", peerASN, rsnASN)
179+
continue
180+
}
181+
182+
// Set as route server only if type matches AND rs_asn matches (if configured)
183+
isRouteServer := isRouteServerType && (!rsnOk || peerASN == string(rsnASN))
184+
185+
if isRouteServer {
133186
rgroup, rgOk := exchanges[i].Options[exchanges[i].IxName]["routeserver_group"]
134187
rgroup6, rg6Ok := exchanges[i].Options[exchanges[i].IxName]["routeserver_group6"]
135188
infoprefixes4, rprefixOk := exchanges[i].Options[exchanges[i].IxName]["routeserver_prefixes"]
@@ -184,11 +237,10 @@ func WorkerMergePeerConfiguration(exchanges ixtypes.IXs, apiServiceURL string, a
184237
rsPeer.InfoPrefixes6 = int64(prefixFactor * float64(rsPeer.InfoPrefixes6))
185238
}
186239

187-
if rsAuto && rsnOk && peerASN != string(rsnASN) {
188-
log.Printf("Ignoring route-server advertised from ASN %s, but IX ASN shall be %s\n", peerASN, rsnASN)
189-
} else if rsAuto {
240+
if rsAuto {
190241
exchanges[i].PeersReady = append(exchanges[i].PeersReady, rsPeer)
191242
}
243+
// continue to the next peer
192244
continue
193245
}
194246
_, ok := exchanges[i].PeersINI[exchanges[i].IxName][peerASN]

peergen_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import (
44
"bufio"
55
"bytes"
66
"encoding/json"
7-
"github.com/ipcjk/ixgen/ixtypes"
8-
"github.com/ipcjk/ixgen/peergen"
97
"html/template"
108
"io"
119
"log"
1210
"net"
1311
"strings"
1412
"testing"
13+
14+
"github.com/ipcjk/ixgen/ixtypes"
15+
"github.com/ipcjk/ixgen/peergen"
1516
)
1617

1718
func TestExtremeNetworksIX(t *testing.T) {

peeringdb/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ type NetData struct {
105105
InfoScope string `json:"info_scope"`
106106
InfoTraffic string `json:"info_traffic"`
107107
InfoType string `json:"info_type"`
108+
InfoTypes []string `json:"info_types"`
108109
InfoUnicast bool `json:"info_unicast"`
109110
IrrAsSet string `json:"irr_as_set"`
110111
LookingGlass string `json:"looking_glass"`

peeringdb_test.go

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package main
22

33
import (
4-
"github.com/ipcjk/ixgen/libapiserver"
5-
"github.com/ipcjk/ixgen/peeringdb"
64
"net/http"
75
"os"
6+
"strconv"
87
"testing"
8+
9+
"github.com/ipcjk/ixgen/libapiserver"
10+
"github.com/ipcjk/ixgen/peeringdb"
911
)
1012

1113
var apiserverDbTest *libapiserver.Apiserver
@@ -161,11 +163,69 @@ func TestGetPeersOnIX(t *testing.T) {
161163

162164
}
163165

164-
func mini(a int, b int) int {
165-
if a <= b {
166-
return a
166+
func TestGetRouteServersOnIX(t *testing.T) {
167+
peerDB := peeringdb.Peeringdb("http://"+apiserverDbTest.AddrPort+"/api", apikey)
168+
ix, err := peerDB.SearchIXByIxName("DE-CIX Frankfurt")
169+
170+
if err != nil {
171+
t.Errorf("Cant search by the IxName: %s", err)
172+
}
173+
174+
if ix.Data[0].Name != "DE-CIX Frankfurt" {
175+
t.Error("Cant find the DE-CIX Frankfurt, something wrong the data-set!")
176+
}
177+
178+
// Route Server ASN for DE-CIX Frankfurt is 6695
179+
var decixRsAsn int64 = 6695
180+
181+
// get all peers on DE-CIX Frankfurt
182+
myPeers, err := peerDB.GetPeersOnIX(ix.Data[0].Name, strconv.FormatInt(ix.Data[0].ID, 10), false)
183+
if err != nil {
184+
t.Errorf("Cant query the API for peers on IX: %s", err)
185+
}
186+
187+
if len(myPeers.Data) == 0 {
188+
t.Error("No peers found for DE-CIX Frankfurt")
189+
}
190+
191+
for _, peer := range myPeers.Data {
192+
// check if the peer is a route server
193+
if peer.Asn == decixRsAsn {
194+
// Get NetData to access InfoType, InfoTypes, and prefix information
195+
netData, err := peerDB.GetNetworkByAsN(peer.Asn)
196+
if err != nil {
197+
t.Errorf("Cant get network data for ASN %d: %s", peer.Asn, err)
198+
continue
199+
}
200+
201+
if len(netData.Data) == 0 {
202+
t.Errorf("No network data found for ASN %d", peer.Asn)
203+
continue
204+
}
205+
206+
/* Check both info_type (legacy) and info_types (array) for Route Server on DE-CIX Frankfurt
207+
maybe need convert this into a function to avoid code duplication*/
208+
var isLegacyRouteServer bool = false
209+
var isArrayRouteServer bool = false
210+
if netData.Data[0].InfoType == "Route Server" {
211+
isLegacyRouteServer = true
212+
}
213+
if contains(netData.Data[0].InfoTypes, "Route Server") {
214+
isArrayRouteServer = true
215+
}
216+
if !isLegacyRouteServer {
217+
t.Logf("Expected Route Server for DE-CIX Frankfurt is not a Route Server: %s", peer.Name)
218+
}
219+
if !isArrayRouteServer {
220+
t.Logf("Array Field is not a possible Route Server for DE-CIX Frankfurt: %s", peer.Name)
221+
}
222+
223+
if !isLegacyRouteServer && !isArrayRouteServer {
224+
t.Logf("Expected Route Server for DE-CIX Frankfurt is not a Route Server: %s", peer.Name)
225+
}
226+
227+
}
167228
}
168-
return b
169229
}
170230

171231
func TestSplitASN(t *testing.T) {
@@ -184,6 +244,13 @@ func TestSplitASN(t *testing.T) {
184244

185245
}
186246

247+
func mini(a int, b int) int {
248+
if a <= b {
249+
return a
250+
}
251+
return b
252+
}
253+
187254
func TestGetASNsbyList(t *testing.T) {
188255
asnList := []string{"196922", "3356"}
189256

@@ -204,3 +271,13 @@ func TestGetASNsbyList(t *testing.T) {
204271
}
205272

206273
}
274+
275+
/* helper function to check if a string slice contains a value */
276+
func contains(slice []string, value string) bool {
277+
for _, item := range slice {
278+
if item == value {
279+
return true
280+
}
281+
}
282+
return false
283+
}

0 commit comments

Comments
 (0)