Peering Intelligence and latency
Presence of networks at Equinix exchanges and facilities from PeeringDB, peering lost with a metro, and fibre latency floors.
Purpose#
Peering Intelligence cross-references PeeringDB with the Equinix exchanges and facilities for a list of ASNs. It reports the Equinix metros in which each network is present, the exchanges at which you and a target network can peer, and the peering that is lost if a metro fails.
Data and credentials#
| Source | Data | Access |
|---|---|---|
| PeeringDB | Networks, exchange memberships (netixlan), facility presence (netfac), organizations | Anonymous at about 20 requests per minute, or with an API key |
| Fabric | Metro codes, service profiles | The Fabric client |
The PeeringDB key is separate from the Equinix credentials and is resolved in this order: the argument of peeringIntelligence("key"), then EquinixConfig.peeringDbApiKey, then the PEERINGDB_API_KEY environment variable, then anonymous access.
Two defects, both fixed in 4.0, caused 3.0.0 to return no presence for any network. PeeringDB ignores an asn filter on netfac and returns unrelated rows, so the client now resolves each ASN to its network id and filters on that. The live Fabric metros response has no IBX list, so Equinix facility names are now matched to metros through the live metro codes. Unit tests built from live response shapes cover the fixes. The end-to-end run was not repeated live on 2026-11-11, because PeeringDB throttled anonymous calls.
Presence#
import com.eqixiac.equinix.core.enums.MetroCode;
import com.eqixiac.equinix.core.model.MetroId;
import com.eqixiac.equinix.design.peering.model.MetroPresenceReport;
import com.eqixiac.equinix.design.peering.model.NetworkPresence;
import com.eqixiac.equinix.design.peering.model.PeeringIntelligenceResult;
PeeringIntelligenceResult presence = fabric.peeringIntelligence()
.addAsn(16509, "AWS")
.addAsn(8075, "Microsoft")
.addAsn(15169, "Google")
.addAsn(13335, "Cloudflare")
.analyze();
System.out.println(presence.getPresenceMatrix().toTableString()); // rows: networks, columns: metros
System.out.println(presence.getPresenceMatrix().toDetailedTableString()); // with port capacity and route-server use
List<MetroId> allThree = presence.getPresenceMatrix().metrosWithAllAsns(List.of(16509L, 8075L, 15169L));
MetroPresenceReport ashburn = presence.metroReport(MetroId.of(MetroCode.DC));
System.out.println(ashburn.withIxPeering().size() + " target networks peer at the exchange in DC, "
+ ashburn.totalIxCapacityMbps() / 1000 + " Gbps of port capacity");
NetworkPresence aws = presence.networkPresence(16509);
System.out.println(aws.getPeeringPolicy() + ", " + aws.ixMetroCount() + " metros, route servers: "
+ aws.isRouteServerParticipant());The port capacity in the report is the figure that each network declares in PeeringDB, which says nothing about the traffic on the port.
Peering opportunities#
When the request includes your own ASN, the result lists the Equinix exchanges at which both you and a target network are present.
import com.eqixiac.equinix.design.peering.model.PeeringOpportunity;
PeeringIntelligenceResult mutual = fabric.peeringIntelligence()
.addAsn(16509, "AWS")
.addAsn(13335, "Cloudflare")
.customerAsn(65100L)
.analyze();
for (PeeringOpportunity opportunity : mutual.getPeeringOpportunities()) {
System.out.println(opportunity.getTargetLabel() + " at " + opportunity.getMetro()
+ " (" + opportunity.getIxName() + "): " + opportunity.getComplexity()
+ ", feasibility " + (int) (opportunity.getFeasibility() * 100) + "%");
}Complexity and feasibility are derived from the target's stated peering policy and route-server participation. A target with an open policy that uses the route servers can be reached without a bilateral session. A target with a selective or restrictive policy has to agree to a peering request. The feasibility figure ranks the opportunities and is not an estimate of the probability that a request succeeds.
Resiliency#
import com.eqixiac.equinix.design.peering.model.BlastRadiusReport;
import com.eqixiac.equinix.design.peering.model.FailoverPath;
PeeringIntelligenceResult resilience = fabric.peeringIntelligence()
.addAsn(16509, "AWS")
.addAsn(8075, "Microsoft")
.addAsn(13335, "Cloudflare")
.customerMetros(MetroCode.DC, MetroCode.DA, MetroCode.SG)
.includeResiliency(true)
.analyze();
BlastRadiusReport dc = resilience.getResiliency().blastRadiusFor(MetroId.of(MetroCode.DC));
System.out.println("Losing DC removes " + (int) (dc.getImpactRatio() * 100) + "% of the peering reach: "
+ dc.getLostIxPeeringLabels() + ", severity " + dc.getSeverity());
for (FailoverPath path : resilience.getResiliency().failoverPathsForAsn(16509)) {
System.out.println(path.getFailoverMetro() + " " + path.getIxCapacityMbps() / 1000 + " Gbps, diversity "
+ path.getDiversity().getRating() + ": " + path.getRecommendation());
}
resilience.getResiliency().criticalCorrelations().forEach(c ->
System.out.println(c.getSeverity() + " " + c.getFailureDomain() + ": " + c.getRecommendation()));
Files.writeString(Path.of("peering-report.md"), resilience.toMarkdown());The blast radius is the share of the target networks' reach that depends on one metro, given the metros you are in. A correlated failure is a set of paths that use different metros and share a failure domain. The analysis uses presence data and has no data on physical routes, so two metros that it reports as diverse can share a fibre path that PeeringDB does not describe.
Latency estimates#
SpeedOfLightLatency computes the delay of light in fibre over the great-circle distance between two locations: about 4.9 microseconds per km one way, with a refractive index of 1.467.
| Endpoints | Coordinate source | Precision |
|---|---|---|
| IBX to IBX | Internet Access ibxs(), or the enriched metro registry | Per data center; a same-metro pair gets a real, non-zero figure |
| Metro to metro | Fabric metros() | Metro centroid |
| IBX to metro | Both | Mixed |
| Raw coordinates or kilometres | None | Offline |
import com.eqixiac.equinix.design.geo.SpeedOfLightLatency;
import com.eqixiac.equinix.fabric.model.Metro;
import com.eqixiac.equinix.internetaccess.model.Ibx;
Ibx la4 = internet.ibxs().getByCode("LA4");
Ibx sv5 = internet.ibxs().getByCode("SV5");
Metro dcMetro = fabric.metros().getByMetroCode(MetroCode.DC);
Metro svMetro = fabric.metros().getByMetroCode(MetroCode.SV);
SpeedOfLightLatency roundTrip = SpeedOfLightLatency.roundTrip();
double ibxToIbx = roundTrip.millisBetween(la4, sv5);
double metroToMetro = roundTrip.millisBetween(dcMetro, svMetro);
double km = SpeedOfLightLatency.distanceKm(la4, sv5);
SpeedOfLightLatency routed = SpeedOfLightLatency.builder()
.mode(SpeedOfLightLatency.Mode.ONE_WAY)
.routeFactor(1.4) // 1.0 is the physical floor; real terrestrial routes are longer
.refractiveIndex(1.467)
.build();
double oneWay = routed.millisBetween(la4, sv5);The result is a lower bound that excludes switching, queuing and the extra length of real fibre routes. The measured counterpart is the round-trip avgLatency in metro.getConnectedMetros(). On 2026-11-11 Fabric reported 65.8 ms round trip between SV and DC against a physical floor of 37.6 ms, a ratio of 1.75. The Metro Optimizer fits this ratio from all measured pairs to estimate the unmeasured ones.
For a location without coordinates the calculator throws IllegalArgumentException with the name of the location.