Skip to content

Ask whether a source can reach a destination, and if not, which hop drops it.

POST
/v1/projects/{projectId}/network/reachability-analyses
Code sample: Shell / cURL
curl --request POST \
--url https://stratum.example.com/v1/projects/example/network/reachability-analyses \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "source": { "kind": "instance-nic", "id": "example", "address": "example" }, "destination": { "kind": "instance-nic", "id": "example", "address": "example" }, "protocol": "tcp", "port": 1 }'

Evaluates a packet through the modelled OVN pipeline and returns the hop-by-hop path with a verdict: reachable with the path, or blocked naming the exact rule — the ACL and its priority, the routing policy, a missing route, an absent NAT, an unbound port.

The pipeline is modelled in the order OVN runs it, because that ordering is where the bugs behind this endpoint lived: a load balancer attached to a switch rewrites the destination before the router stage evaluates any routing policy, so a policy keyed on the pre-rewrite address is looking at an address that no longer exists. Routing-policy priorities are 1000 + prefix length, so a peering route to a /16 sits at 1016 and does outrank the 0.0.0.0/0 catch-all at 1000 — “the catch-all outranked it” is a tempting wrong answer.

The return path is evaluated too, whenever the forward path completed. A forward path that is open and a reply that cannot get home is not a reachable path peering routes are required in BOTH VPCs, and reporting one-way wiring as reachable is the most dangerous wrong answer this endpoint could give.

What it does not do

This is configuration analysis, not a packet. It reads the OVN northbound database; it is blind to a dataplane that does not match its configuration — a chassis with zero geneve tunnels, a dead ovn-controller, a stale flow table. Every non-blocked verdict therefore carries the dataplane_not_verified caveat, and GET /v1/admin/network/ovn/doctor is the surface that checks the substrate’s own health.

Connection tracking is not modelled either, so allow-related return traffic and a load balancer’s reverse translation are assumed rather than proven; both are stated as caveats rather than left implicit.

A path the analyzer cannot model answers undetermined with the reason, never a guess. Answers 200 for every verdict, including blocked: a closed path is a successful analysis, and using 4xx for it would stop a caller telling “the path is shut” from “the request was wrong”.

Vocabulary

The answer is in the resources you configure — security group, route table, internet gateway, floating IP — and never in the substrate that implements them. A block also carries fault: configuration means it is yours to fix, platform means Stratum’s own configuration caused it and changing yours will not help.

The operator view of the same analysis, with the OVN objects, rule priorities and match expressions, is POST /v1/admin/network/ovn/reachability-analyses. One pipeline model backs both, so they cannot disagree about a path.

Nothing is stored. The analysis is computed inline from current state, like the IAM policy simulator.

projectId
required
string
/^p-[a-z0-9-]+$/
Media typeapplication/json
object
source
required

Names a source or destination before resolution. id is required for every kind that names a Stratum resource; address is required for address and optional elsewhere, where it selects which of a NIC’s addresses the question is about.

object
kind
required
string
Allowed values: instance-nic load-balancer floating-ip internet vpn-client-cidr peered-vpc service-endpoint address
id

The Stratum resource id (nic-…, lb-…, fip-…, pcx-…, cvpn-…, vpce-…).

string
address
string format: ipv4
destination
required

Names a source or destination before resolution. id is required for every kind that names a Stratum resource; address is required for address and optional elsewhere, where it selects which of a NIC’s addresses the question is about.

object
kind
required
string
Allowed values: instance-nic load-balancer floating-ip internet vpn-client-cidr peered-vpc service-endpoint address
id

The Stratum resource id (nic-…, lb-…, fip-…, pcx-…, cvpn-…, vpce-…).

string
address
string format: ipv4
protocol
required
string
Allowed values: tcp udp icmp
port

Destination port. Required for tcp and udp, ignored for icmp. Security-group rules are per-port, so a tcp verdict without a port would be a verdict about a packet nobody sends.

integer
>= 1 <= 65535

The analysis.

Media typeapplication/json

A reachability analysis in tenant vocabulary. The same pipeline model backs this and the operator view at /v1/admin/network/ovn/reachability-analyses; only the projection differs, so the two can never disagree about a path.

object
query
required

The resolved question.

object
verdict
required

undetermined is not a soft form of either other value. A path the analyzer could not model, rendered as reachable, talks an operator out of investigating a real outage; rendered as blocked, it sends them hunting for a rule that does not exist.

string
Allowed values: reachable blocked undetermined
reason

The KIND of block, so a caller can branch without parsing prose. The specific offending object is on the blocking hop.

flow_log_capture is split from acl_deny because the repair differs: the priority-501 capture ACL is the only band matching an explicit port name rather than a port group, so on a port with no security group there is no default-deny beneath it and the capture becomes that port’s entire policy. Reporting it as a generic ACL denial sends an operator looking for a security-group rule on a port that has no security group at all.

no_return_route likewise: the forward path is open and the reply has nowhere to go. Per routes are required in BOTH VPCs.

string
Allowed values: acl_deny sg_default_deny flow_log_capture no_route no_return_route missing_nat port_unbound peering_inactive endpoint_unresolved
fault

Whose problem the block is.

platform means Stratum’s own configuration caused it and changing yours will not help — the case this exists for is, where a platform capture rule black-holed a load-balancer port and any tenant told “dropped by an ACL” would have audited security groups that were perfectly correct.

string
Allowed values: configuration platform
summary
required

The one sentence. Names the resource, the rule that acted, and — when the cause is the platform — says so outright.

string
forward
required
object
direction
required
string
Allowed values: forward return
verdict
required

undetermined is not a soft form of either other value. A path the analyzer could not model, rendered as reachable, talks an operator out of investigating a real outage; rendered as blocked, it sends them hunting for a rule that does not exist.

string
Allowed values: reachable blocked undetermined
hops
required
Array<object>
object
sequence
required
integer
component
required

A Stratum resource, never an OVN row. platform is used for a step that has no tenant-facing construct (a platform service rewrite, an internal guard), so the path has no unexplained gaps.

object
type
required
string
Allowed values: network-interface security-group route-table internet-gateway nat-gateway vpc-peering load-balancer floating-ip subnet vpc service-endpoint client-vpn-endpoint internet address platform
id
string
action
required
string
Allowed values: forward allow drop reroute dnat snat deliver
detail
required

One line, in the vocabulary you configure in.

string
blockingHop

Index into hops of the hop that dropped the packet.

integer
return
object
direction
required
string
Allowed values: forward return
verdict
required

undetermined is not a soft form of either other value. A path the analyzer could not model, rendered as reachable, talks an operator out of investigating a real outage; rendered as blocked, it sends them hunting for a rule that does not exist.

string
Allowed values: reachable blocked undetermined
hops
required
Array<object>
object
sequence
required
integer
component
required

A Stratum resource, never an OVN row. platform is used for a step that has no tenant-facing construct (a platform service rewrite, an internal guard), so the path has no unexplained gaps.

object
type
required
string
Allowed values: network-interface security-group route-table internet-gateway nat-gateway vpc-peering load-balancer floating-ip subnet vpc service-endpoint client-vpn-endpoint internet address platform
id
string
action
required
string
Allowed values: forward allow drop reroute dnat snat deliver
detail
required

One line, in the vocabulary you configure in.

string
blockingHop

Index into hops of the hop that dropped the packet.

integer
caveats
Array<string>
Allowed values: dataplane_not_verified conntrack_not_modeled stateful_lb_not_modeled
undetermined
Array<string>

Example

{
"verdict": "reachable",
"reason": "acl_deny",
"fault": "configuration",
"summary": "Blocked: network interface nic-abc cannot reach network interface nic-def over tcp/3306 — security group sg-web has no inbound rule admitting this traffic.",
"forward": {
"direction": "forward",
"verdict": "reachable",
"hops": [
{
"component": {
"type": "network-interface"
},
"action": "forward"
}
]
},
"return": {
"direction": "forward",
"verdict": "reachable",
"hops": [
{
"component": {
"type": "network-interface"
},
"action": "forward"
}
]
},
"caveats": [
"dataplane_not_verified"
]
}

Bad request.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
>= 400 <= 599
detail
string
instance
string format: uri-reference
requestId
required
string
code
required
string
issues

The findings of a rejected IAM policy document (custom and resource policies).

Array<object>

One finding of a rejected IAM policy document. A rejection lists every finding, so the author fixes the document in one round trip.

object
code
required

The finding, e.g. INVALID_DOCUMENT, UNKNOWN_ACTION, ACTION_NOT_APPLICABLE.

string
statement
required

Index of the statement at fault; -1 for the document as a whole.

integer
>= -1
detail
required
string
action

The offending action, where one is at fault (ACTION_NOT_APPLICABLE).

string
errors

Field errors, for codes that carry them: each problem at its field (see FieldError). Documented on the responses that set it, e.g. approveNodeJoin’s INVALID_INPUT and JOIN_APPROVAL_REFUSED. Absent otherwise.

Array<object>

One field’s problem, the stage-2 installer API’s shape. field is the field’s path, message what is wrong with it.

object
field
required

The field’s path, e.g. links[0].interface, disks[1].confirm, mgmt.address or role; empty for the whole request.

string
message
required
string
details

Structured facts about the refusal, for codes that carry them. The shape is fixed per code and documented on the response that answers it, e.g. IMAGE_POOL_MISMATCH (see ImagePoolMismatchDetails) and IMAGE_IN_USE. Absent for codes that carry none.

object
key
additional properties
any

Example

{
"issues": [
{
"code": "ACTION_NOT_APPLICABLE",
"action": "compute:CreateVpc"
}
]
}

Authenticated but not authorized.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
>= 400 <= 599
detail
string
instance
string format: uri-reference
requestId
required
string
code
required
string
issues

The findings of a rejected IAM policy document (custom and resource policies).

Array<object>

One finding of a rejected IAM policy document. A rejection lists every finding, so the author fixes the document in one round trip.

object
code
required

The finding, e.g. INVALID_DOCUMENT, UNKNOWN_ACTION, ACTION_NOT_APPLICABLE.

string
statement
required

Index of the statement at fault; -1 for the document as a whole.

integer
>= -1
detail
required
string
action

The offending action, where one is at fault (ACTION_NOT_APPLICABLE).

string
errors

Field errors, for codes that carry them: each problem at its field (see FieldError). Documented on the responses that set it, e.g. approveNodeJoin’s INVALID_INPUT and JOIN_APPROVAL_REFUSED. Absent otherwise.

Array<object>

One field’s problem, the stage-2 installer API’s shape. field is the field’s path, message what is wrong with it.

object
field
required

The field’s path, e.g. links[0].interface, disks[1].confirm, mgmt.address or role; empty for the whole request.

string
message
required
string
details

Structured facts about the refusal, for codes that carry them. The shape is fixed per code and documented on the response that answers it, e.g. IMAGE_POOL_MISMATCH (see ImagePoolMismatchDetails) and IMAGE_IN_USE. Absent for codes that carry none.

object
key
additional properties
any

Example

{
"issues": [
{
"code": "ACTION_NOT_APPLICABLE",
"action": "compute:CreateVpc"
}
]
}

Resource not found.

Media typeapplication/problem+json
object
type
required
string format: uri
title
required
string
status
required
integer
>= 400 <= 599
detail
string
instance
string format: uri-reference
requestId
required
string
code
required
string
issues

The findings of a rejected IAM policy document (custom and resource policies).

Array<object>

One finding of a rejected IAM policy document. A rejection lists every finding, so the author fixes the document in one round trip.

object
code
required

The finding, e.g. INVALID_DOCUMENT, UNKNOWN_ACTION, ACTION_NOT_APPLICABLE.

string
statement
required

Index of the statement at fault; -1 for the document as a whole.

integer
>= -1
detail
required
string
action

The offending action, where one is at fault (ACTION_NOT_APPLICABLE).

string
errors

Field errors, for codes that carry them: each problem at its field (see FieldError). Documented on the responses that set it, e.g. approveNodeJoin’s INVALID_INPUT and JOIN_APPROVAL_REFUSED. Absent otherwise.

Array<object>

One field’s problem, the stage-2 installer API’s shape. field is the field’s path, message what is wrong with it.

object
field
required

The field’s path, e.g. links[0].interface, disks[1].confirm, mgmt.address or role; empty for the whole request.

string
message
required
string
details

Structured facts about the refusal, for codes that carry them. The shape is fixed per code and documented on the response that answers it, e.g. IMAGE_POOL_MISMATCH (see ImagePoolMismatchDetails) and IMAGE_IN_USE. Absent for codes that carry none.

object
key
additional properties
any

Example

{
"issues": [
{
"code": "ACTION_NOT_APPLICABLE",
"action": "compute:CreateVpc"
}
]
}