{
  "openapi": "3.1.1",
  "info": {
    "title": "Signalhouse MTU, Fragmentation & TCP Throughput Calculator API",
    "version": "1.0.0",
    "summary": "Tunnel overhead, inner MTU and MSS, IPv4/IPv6 fragments and a TCP throughput model.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://signalhousemtucalculator.usefulweb.app"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Tunnel overhead, inner MTU and MSS, IPv4/IPv6 fragments and a TCP throughput model.",
        "description": "Stack encapsulations on a link — PPPoE, MPLS, GRE, IP-in-IP, 6in4, DS-Lite, VXLAN, Geneve, WireGuard and IPsec ESP (approximate) — and get the inner MTU, the TCP MSS for IPv4 and IPv6 and the wire efficiency. Send a packet through it to see the exact IPv4 fragments (offsets, lengths, MF flag), what happens with “Don’t Fragment” and why IPv6 routers answer “Packet Too Big”. A TCP model adds the bandwidth-delay product, the window scale you need and the Mathis loss limit. It is the MTU panel of the Signalhouse Network lab.\n\nMethodology:\n- Each encapsulation subtracts its header bytes from the MTU of the layer below it, from the wire inwards: PPPoE 8, MPLS 4 per label, GRE over IPv4 24 (28 with a key), IPIP and 6in4 20, IP-in-IPv6 40, VXLAN and Geneve 50 over IPv4 or 70 over IPv6 (they carry an inner Ethernet header), WireGuard 60 over IPv4 or 80 over IPv6.\n- IPsec ESP in tunnel mode is computed from the cipher: outer IPv4 20, ESP header 8, IV, padding of the encrypted part to the cipher block (16 bytes for AES-CBC, 4 for AES-GCM) including the 2-byte trailer, and the ICV (12 for HMAC-SHA1-96, 16 for GCM); NAT-T adds a UDP header. Real overhead varies with options, so the figure is labelled approximate.\n- IPv4 fragments carry data in multiples of 8 bytes (the offset field counts 8-byte units); every fragment but the last has MF set (RFC 791). IPv6 packets are only fragmented by the source, each fragment repeats the unfragmentable headers and adds an 8-byte Fragment header (RFC 8200); routers drop oversize packets with “Packet Too Big”.\n- TCP MSS = MTU − 40 (IPv4) or − 60 (IPv6), without TCP options. The TCP estimate is the minimum of the bandwidth, window ÷ RTT and the Mathis et al. model MSS ÷ RTT × √(3/2) ÷ √loss. It models steady-state Reno-style congestion avoidance; CUBIC, BBR, slow start and queueing behave differently.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "signalhouse_mtu_calculator",
        "x-owner-app": "signalhouse",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignalhouseMtuCalculatorInput"
              },
              "examples": {
                "example1": {
                  "summary": "Textbook: a 4000-byte IPv4 datagram over a 1500-byte MTU",
                  "value": {
                    "linkMtu": 1500,
                    "packetSize": 4000,
                    "df": false
                  }
                },
                "example2": {
                  "summary": "WireGuard over a PPPoE DSL line",
                  "value": {
                    "linkMtu": 1500,
                    "layers": [
                      {
                        "layer": "pppoe"
                      },
                      {
                        "layer": "wireguard4"
                      }
                    ],
                    "packetSize": 1500,
                    "df": true
                  }
                },
                "example3": {
                  "summary": "VXLAN over an IPv6 underlay with 1500-byte links",
                  "value": {
                    "linkMtu": 1500,
                    "layers": [
                      {
                        "layer": "vxlan6"
                      }
                    ]
                  }
                },
                "example4": {
                  "summary": "IPsec ESP with NAT traversal (AES-CBC, approximate) and IPv6 inside",
                  "value": {
                    "linkMtu": 1500,
                    "layers": [
                      {
                        "layer": "esp-cbc-natt"
                      }
                    ],
                    "ipVersion": "6",
                    "packetSize": 1500
                  }
                },
                "example5": {
                  "summary": "Long fat network: 1 Gbit/s over 150 ms without window scaling",
                  "value": {
                    "linkMtu": 1500,
                    "bandwidthMbps": 1000,
                    "rttMs": 150,
                    "windowScaling": false,
                    "transferMB": 1000
                  }
                },
                "example6": {
                  "summary": "TCP with 0.1 % loss on a 100 Mbit/s, 80 ms path",
                  "value": {
                    "linkMtu": 1500,
                    "bandwidthMbps": 100,
                    "rttMs": 80,
                    "lossPercent": 0.1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SignalhouseMtuCalculatorResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "SignalhouseMtuCalculatorInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "linkMtu": {
            "title": "Link MTU",
            "description": "MTU of the physical link (Ethernet 1500, jumbo frames 9000).",
            "type": "integer",
            "minimum": 68,
            "maximum": 65535,
            "default": 1500,
            "x-unit": "bytes"
          },
          "layers": {
            "title": "Encapsulations, from the wire inwards",
            "type": "array",
            "maxItems": 8,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "layer": {
                  "title": "Encapsulation",
                  "type": "string",
                  "enum": [
                    "pppoe",
                    "mpls",
                    "gre",
                    "gre-key",
                    "gre6",
                    "ipip",
                    "6in4",
                    "ip6tnl",
                    "vxlan4",
                    "vxlan6",
                    "geneve4",
                    "wireguard4",
                    "wireguard6",
                    "esp-cbc",
                    "esp-cbc-natt",
                    "esp-gcm",
                    "esp-gcm-natt"
                  ],
                  "default": "pppoe"
                }
              },
              "required": []
            },
            "default": []
          },
          "ipVersion": {
            "title": "Inner IP version",
            "type": "string",
            "enum": [
              "4",
              "6"
            ],
            "default": "4"
          },
          "packetSize": {
            "title": "Packet to send (total length)",
            "description": "Optional: an IP packet of this size is checked against the inner MTU and fragmented if needed.",
            "type": "integer",
            "minimum": 20,
            "maximum": 65575,
            "x-unit": "bytes"
          },
          "df": {
            "title": "“Don’t Fragment” set (IPv4)",
            "type": "boolean",
            "default": false
          },
          "ipv4HeaderLength": {
            "title": "IPv4 header length",
            "type": "integer",
            "minimum": 20,
            "maximum": 60,
            "default": 20,
            "x-unit": "bytes"
          },
          "ipv6ExtensionBytes": {
            "title": "IPv6 extension headers before the Fragment header",
            "type": "integer",
            "minimum": 0,
            "maximum": 2000,
            "default": 0,
            "x-unit": "bytes"
          },
          "bandwidthMbps": {
            "title": "TCP model: bandwidth",
            "description": "Fill in bandwidth and round-trip time to add the TCP throughput model.",
            "type": "number",
            "minimum": 0,
            "maximum": 10000000,
            "x-unit": "Mbit/s"
          },
          "rttMs": {
            "title": "TCP model: round-trip time",
            "type": "number",
            "minimum": 0,
            "maximum": 100000,
            "x-unit": "ms"
          },
          "lossPercent": {
            "title": "TCP model: packet loss",
            "type": "number",
            "minimum": 0,
            "maximum": 99,
            "default": 0,
            "x-unit": "%"
          },
          "windowBytes": {
            "title": "TCP model: receive window",
            "description": "Empty: as large as the path needs (with window scaling) or 65,535 bytes (without).",
            "type": "integer",
            "minimum": 1,
            "maximum": 1073725440,
            "x-unit": "bytes"
          },
          "windowScaling": {
            "title": "TCP model: window scaling (RFC 7323) enabled",
            "type": "boolean",
            "default": true
          },
          "transferMB": {
            "title": "TCP model: file size to transfer",
            "type": "number",
            "minimum": 0,
            "x-unit": "MB"
          }
        },
        "required": []
      },
      "SignalhouseMtuCalculatorResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "linkMtu",
              "ipVersion",
              "layers",
              "innerMtu",
              "overheadBytes",
              "mssIPv4",
              "mssIPv6",
              "ethernetEfficiencyPercent",
              "packet",
              "tcp",
              "notes"
            ],
            "properties": {
              "linkMtu": {
                "type": "number"
              },
              "ipVersion": {
                "enum": [
                  4,
                  6
                ]
              },
              "layers": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "id",
                    "label",
                    "overheadBytes",
                    "mtuBefore",
                    "mtuAfter",
                    "approximate",
                    "standard"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "label": {
                      "type": "string"
                    },
                    "overheadBytes": {
                      "type": "number"
                    },
                    "mtuBefore": {
                      "type": "number"
                    },
                    "mtuAfter": {
                      "type": "number"
                    },
                    "approximate": {
                      "type": "boolean"
                    },
                    "standard": {
                      "type": "string"
                    }
                  }
                }
              },
              "innerMtu": {
                "type": "number"
              },
              "overheadBytes": {
                "type": "number"
              },
              "mssIPv4": {
                "type": "number"
              },
              "mssIPv6": {
                "type": "number"
              },
              "ethernetEfficiencyPercent": {
                "type": "number",
                "description": "TCP payload share of the Ethernet wire bytes (MTU + 38 bytes framing)."
              },
              "packet": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "The packet check: size, fits, action (fits, fragmented, dropped), message and the fragments (index, offset in 8-byte units, offset in bytes, data bytes, total length, more-fragments flag)."
              },
              "tcp": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "TCP model: bandwidth-delay product, window, effective window, window scale needed, window limit, Mathis loss limit, estimate, limiting factor, transfer time."
              },
              "notes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}