#!/usr/bin/env bash
# scripts/dc-dc-mtu-geneve-budget.sh --underlay-mtu <MEASURED_MTU>
#
# Phase-0 gate calculator (tooling gap register item #7): turns D-101's
# ("Tenant/MTU sub-policy", folded in from D-102) prose arithmetic into a
# runnable check, per `runbooks/dc-dc-phase0-vcloud-prep.md` Step 3. Mutates
# NOTHING -- read-only arithmetic against an operator-supplied, MEASURED
# input; safe to re-run any number of times.
#
# The underlay MTU is NEVER inferred or defaulted -- it must be measured this
# session on the real interface(s) VR1 will use (Step 3's own check:
# `ip -o link show | awk '{print $2, $0}' | grep -i mtu`) and passed
# explicitly via --underlay-mtu. There is no --underlay-mtu default on
# purpose (hard rule 2: no inferred value for anything that varies by real
# hardware).
#
# D-101 arithmetic quoted verbatim (docs/design-decisions.md, "Tenant/MTU
# sub-policy" bullet under D-101, folded in from D-102):
#   "An IPv6 outer header adds 20 bytes over IPv4 (40 vs 20); geneve-over-v6
#   overhead is about 40 (IPv6) + 8 (UDP) + 8 (Geneve base) = 56 bytes,
#   before nested-virt and options... Recommendation: raise the vcloud
#   underlay to jumbo (9000) end-to-end so tenant MTU stays 1500 and
#   amphora/geneve fit; if the underlying is pinned at 1500, tenant MTU
#   drops to about 1444 (v6-geneve) and MUST be set consistently across ovn
#   geneve, tenant-network MTU, and amphora."
#
# This script implements exactly that: >=9000 underlay -> jumbo, tenant MTU
# stays 1500 (no reduction). Below jumbo -> tenant_mtu = underlay_mtu - 56,
# matching the doc's own worked example exactly (1500 - 56 = 1444).
#
# One extra, clearly-separated sanity floor NOT itself part of D-101's own
# arithmetic: IPv6 requires every link to carry at least a 1280-byte MTU
# (RFC 8200 Section 5) -- if the computed tenant MTU falls below 1280, the
# verdict is FAIL rather than a silent PASS, since a v6-geneve tenant network
# below the IPv6 minimum link MTU is not viable regardless of what D-101
# itself says about the 56-byte overhead.
#
# Output: a human-readable computation + verdict, and a single
# `MTU-BUDGET: ...` summary line at the end suitable for pasting verbatim
# into a changelog entry or the as-executed log (Step 3's "decision to
# record").
#
# Usage: dc-dc-mtu-geneve-budget.sh --underlay-mtu <bytes> [--jumbo-threshold N]
#   --underlay-mtu N       REQUIRED. The measured host L2 MTU (bytes),
#                          Step 3's `ip -o link show` output. No default.
#   --jumbo-threshold N    OPTIONAL. Override the jumbo cutoff (default 9000,
#                          D-101's own recommended jumbo value). Only for
#                          exploring alternate policy; do not use to dodge a
#                          real measurement.
#   -h|--help              this help.
#
# Exit: 0 PASS (jumbo, or a viable reduced tenant MTU) | 1 FAIL/HOLD (computed
# tenant MTU below the IPv6 minimum link MTU) | 2 usage error (missing/bad
# --underlay-mtu). ASCII + LF.
set -uo pipefail
shopt -s inherit_errexit 2>/dev/null || true

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# D-101's own stated geneve-over-v6 overhead: 40 (IPv6 outer header) + 8 (UDP)
# + 8 (Geneve base) = 56 bytes "before nested-virt and options" -- this is
# fixed protocol-header arithmetic from the ADOPTED decision text, not a
# per-host measured value, so it is a constant here (not an argument).
readonly GENEVE_OVER_V6_OVERHEAD=56
# RFC 8200 Section 5: IPv6 requires every link to support at least a
# 1280-byte MTU. Independent of D-101; a defensive sanity floor.
readonly IPV6_MIN_LINK_MTU=1280
readonly DEFAULT_JUMBO_THRESHOLD=9000

usage() { sed -n '2,49p' "$HERE/$(basename "${BASH_SOURCE[0]}")" | sed 's/^# \{0,1\}//'; }

UNDERLAY_MTU=""
JUMBO_THRESHOLD="$DEFAULT_JUMBO_THRESHOLD"

while [ $# -gt 0 ]; do
  case "$1" in
    --underlay-mtu)
      UNDERLAY_MTU="${2:-}"; shift 2 ;;
    --underlay-mtu=*)
      UNDERLAY_MTU="${1#*=}"; shift ;;
    --jumbo-threshold)
      JUMBO_THRESHOLD="${2:-}"; shift 2 ;;
    --jumbo-threshold=*)
      JUMBO_THRESHOLD="${1#*=}"; shift ;;
    -h|--help)
      usage; exit 0 ;;
    *)
      echo "FAIL: unknown argument: $1" >&2
      echo "      run with --help for usage" >&2
      exit 2 ;;
  esac
done

is_pos_int() { [[ "$1" =~ ^[0-9]+$ ]] && [ "$1" -gt 0 ]; }

if [ -z "$UNDERLAY_MTU" ]; then
  echo "FAIL: --underlay-mtu is REQUIRED (no default -- measure it this session:" >&2
  echo "      ip -o link show | awk '{print \$2, \$0}' | grep -i mtu)" >&2
  exit 2
fi
if ! is_pos_int "$UNDERLAY_MTU"; then
  echo "FAIL: --underlay-mtu must be a positive integer (bytes); got '$UNDERLAY_MTU'" >&2
  exit 2
fi
if ! is_pos_int "$JUMBO_THRESHOLD"; then
  echo "FAIL: --jumbo-threshold must be a positive integer (bytes); got '$JUMBO_THRESHOLD'" >&2
  exit 2
fi

echo "=== dc-dc-mtu-geneve-budget: D-101 MTU / geneve-over-v6 budget ==="
echo "  measured underlay MTU (--underlay-mtu): $UNDERLAY_MTU"
echo "  jumbo threshold: $JUMBO_THRESHOLD"
echo "  geneve-over-v6 overhead (D-101: 40 IPv6 + 8 UDP + 8 Geneve base): $GENEVE_OVER_V6_OVERHEAD bytes"
echo

VERDICT=""
SUMMARY=""

if [ "$UNDERLAY_MTU" -ge "$JUMBO_THRESHOLD" ]; then
  TENANT_MTU=1500
  echo "  Underlay is jumbo (>= $JUMBO_THRESHOLD)."
  echo "  Per D-101: tenant MTU stays 1500; geneve/amphora headroom is generous."
  echo "  Recorded decision: underlay_mtu = $UNDERLAY_MTU (jumbo); tenant MTU = 1500 (unchanged)."
  VERDICT="PASS"
  SUMMARY="MTU-BUDGET: underlay=$UNDERLAY_MTU jumbo=yes tenant_mtu=1500 verdict=PASS"
else
  TENANT_MTU=$((UNDERLAY_MTU - GENEVE_OVER_V6_OVERHEAD))
  echo "  Underlay is NOT jumbo (< $JUMBO_THRESHOLD)."
  echo "  Per D-101: tenant_mtu = underlay_mtu - $GENEVE_OVER_V6_OVERHEAD = $UNDERLAY_MTU - $GENEVE_OVER_V6_OVERHEAD = $TENANT_MTU"
  if [ "$UNDERLAY_MTU" -eq 1500 ]; then
    echo "  (This is D-101's own worked example: 1500 - 56 = 1444.)"
  fi
  if [ "$TENANT_MTU" -lt "$IPV6_MIN_LINK_MTU" ]; then
    echo
    echo "  HOLD: computed tenant MTU ($TENANT_MTU) is BELOW the IPv6 minimum"
    echo "  link MTU ($IPV6_MIN_LINK_MTU, RFC 8200 Sec 5) -- this underlay MTU"
    echo "  cannot carry a viable v6-geneve tenant network at all. Raising the"
    echo "  underlay toward jumbo (or at minimum above $((IPV6_MIN_LINK_MTU + GENEVE_OVER_V6_OVERHEAD))) is required before proceeding."
    VERDICT="FAIL"
    SUMMARY="MTU-BUDGET: underlay=$UNDERLAY_MTU jumbo=no tenant_mtu=$TENANT_MTU verdict=FAIL (below IPv6 min link MTU $IPV6_MIN_LINK_MTU)"
  else
    echo
    echo "  Recorded decision: underlay_mtu = $UNDERLAY_MTU; tenant MTU = $TENANT_MTU (v6-geneve),"
    echo "  MUST be set consistently across ovn geneve, tenant-network MTU, and amphora"
    echo "  (propagation happens in later stages per Step 3 -- this only records the decision)."
    VERDICT="PASS"
    SUMMARY="MTU-BUDGET: underlay=$UNDERLAY_MTU jumbo=no tenant_mtu=$TENANT_MTU verdict=PASS"
  fi
fi

echo
echo "VERDICT: $VERDICT"
echo "$SUMMARY"

[ "$VERDICT" = "PASS" ] && exit 0 || exit 1
