Skip to content

tpunetd 协议

本页中的所有地址、符号和线缆字符串都适用于 libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64 wheel 中的 libtpu.so(ELF 64-bit LSB, x86-64, ~745 MB, BuildID md5 89edbbe81c5b328a958fe628a9f2207d)。其他版本会不同。

摘要

tpunetd 是驻留在主机上的控制守护进程,拥有 Cloud TPU VM 或 superpod 主机上的物理 TPU 芯片。用户进程从不直接接触这些芯片;相反,libtpu.so 链接了完整的客户端桩 — superpod::tpunetd_client — 它通过本地 gRPC 通道连接到守护进程,并经由守护进程驱动芯片生命周期。本页记录的是 libtpu.so 内观察到的客户端桩:它链接的四个 gRPC 服务、请求/响应消息形状、Unix-socket / TCP 端点发现,以及客户端在作业启动时如何连接到(或拒绝连接到)守护进程。该 wheel 中包含守护进程二进制文件;这里的每一条结论都只来自链接进来的客户端侧单元,其中携带了 gRPC 桩、四个 proto FileDescriptorProto blob、验证器,以及 TpunetdControl / SessionMaster 机制。

如果你用过 gRPC 生成的 C++ 桩,这个表面会很熟悉:每个服务一个 Stub 类,每个 RPC 一个由 BlockingUnaryCall 支撑的方法,外加一个 async 内部类 ClientUnaryReactor 变体;一个接受 shared_ptr<grpc::ChannelInterface>NewStub 工厂;以及一个很薄的手写包装器(TpunetdControl),它把内部 SessionData 结构体封送进 proto 请求。需要先记住的两个意外点是:(1) 默认情况下,libtpu 不是与守护进程自己的 SessionControl 服务通信,而是与位于不同 package(libtpu.tpunetd)下、包含 8 个方法的 VBARControl shim 通信;(2) 四个服务中的两个 — TpuNetworkSessionWorkerTpuNetworkSessionBarrier — 是客户端进程之间的点对点服务,并且libtpu 自身提供服务, 不是由 tpunetd 提供。

使用这个桩的 bootstrap 会合(CreateTpuNetworkInterfaceInitMaybeInitSessionMaster 启动序列及其相对于 Megascale 的位置)由 bootstrap/tpunetd-relationship.md 负责;本页负责 RPC 表面、消息分类和端点发现,不重新推导启动序列。

对于重新实现,契约是:

  • 四个 gRPC 服务及其线缆前缀 — 精确的服务路径、各自的方法集合,以及它们所在的 package。
  • 请求/响应消息形状 — 从链接的 FileDescriptorProto 字符串以及被改编的桩方法签名中恢复(每个 RPC 的 Request/Response 类型对)。
  • 端点发现和通道构造 — Unix-socket 默认路径、--vbar_control_service_url 覆盖、明文 (InsecureChannelCredentials) gRPC,以及连接重试循环。
  • 默认与绕过分支 — libtpu 何时选择 VBARControl 而非 SessionControl::Stub,以及何时改为安装 no-op 桩。
客户端命名空间superpod::tpunetd_client(774 个 mangled-symbol 命中,nm | rg -c '8superpod14tpunetd_client'
守护进程命名空间superpod::tpunetd(720 个 mangled-symbol 命中,nm | rg -c '8superpod7tpunetd'
源路径前缀platforms/deepsea/software/superpod/routing/
本地端点(默认)/var/google/services/tpunetd/user.socket (UDS)
传输明文 gRPC (grpc::InsecureChannelCredentials)
通道构造函数superpod::tpunetd_client::ConnectToGrpcEndpoint (0x1ffcef60)
实现选择工厂superpod::routing::CreateTpuNetworkInterface (0x1fba1100)
默认客户端桩libtpu::tpunetd::grpc::VBARControl::Stub
绕过客户端桩superpod::tpunetd::grpc_gen::SessionControl::Stub (NewStub 0x1ffcdd20)
服务 / 方法4 个服务 / 21 个 RPC

服务表面概览

四个 gRPC 服务被链接进 libtpu.so。它们可以按谁托管服务器、谁发起调用清晰划分。下面的每个线缆前缀都是从反编译的 .rodata 字符串表中逐字提取的;方法数量与 IDA 数据库中存在的逐方法桩函数匹配。

服务线缆前缀方法数服务器由 libtpu 发起
SessionControl/superpod.tpunetd.SessionControl/7tpunetd 守护进程仅当 --bypass_vbar_control_service=true
VBARControl/libtpu.tpunetd.VBARControl/8tpunetd 守护进程(shim)默认路径
TpuNetworkSessionWorker/superpod.tpunetd_client.TpuNetworkSessionWorker/4对等 libtpu 进程session master → workers
TpuNetworkSessionBarrier/superpod.tpunetd_client.proto.TpuNetworkSessionBarrier/2对等 libtpu 进程barrier fan-out

怪异点 — SessionControlVBARControl 暴露几乎相同的方法名,但位于不同的 proto packagesuperpod.tpunetdlibtpu.tpunetd),因此拥有不同且不可互换的消息类型superpod.tpunetd.StartSessionRequestlibtpu.tpunetd.StartSessionRequest 是不同的描述符。把它们作为别名处理的重新实现会针对错误的 FileDescriptorProto 进行序列化。线缆路径中的 package 前缀就是判别器。

注意 — tpunetd 守护进程的 SessionControl proto 还声明了 ~20 个 ICI-fabric / routing-controller RPC(CreateNetwork, SetRoutingTable, SetGtcConfiguration, PerformReset, …)。这些存在于描述符中,但从不由 libtpu 发起 — 它们属于权限更高的 superpod-routing 控制器平面。为完整起见,它们被编入下面的“仅守护进程 RPC 表面”, 而不是作为客户端契约的一部分。


端点发现和通道构造

目的

在可以发起任何 RPC 之前,客户端必须解析一个端点 URL 并向其打开 gRPC 通道。端点要么是 Unix domain socket(本地守护进程链路),要么是 TCP 地址(对等 fanout);通道始终是明文的。

入口点

text
TpunetdClient::Init (decl, throws "Must run TpunetdClient::Init first")
  └─ ConnectToTpunetd                          ── default-vs-bypass + NoOp branch
       └─ ConnectToGrpcEndpoint (0x1ffcef60)    ── CreateChannel + retry loop
            ├─ grpc::InsecureChannelCredentials
            ├─ grpc::CreateChannel(url, creds)
            └─ Channel::GetState(true) until READY or deadline
```text

### 算法

```c
// superpod::tpunetd_client::ConnectToGrpcEndpoint  (0x1ffcef60)
// args: (string_view url, absl::Duration deadline)
function ConnectToGrpcEndpoint(url, deadline):
    creds   = grpc::InsecureChannelCredentials()   // line 67 — plaintext, no TLS
    channel = grpc::CreateChannel(url, creds)       // line 70
    end     = absl::Now() + deadline
    loop:
        state = channel.GetState(/*try_to_connect=*/true)
        if state == 2:                              // line 104 — GRPC_CHANNEL_READY
            return channel
        if absl::Now() >= end:
            return Error("Failed to connect to " + url)   // rodata "Failed to connect to "
        WaitForStateChange(state, short_deadline)   // spin until next transition

端点选择

通道打开所用的 URL 在 ConnectToTpunetd 中按以下顺序解析:

  1. Options URL 字段,如果嵌入运行时提供了该字段。
  2. FLAGS_vbar_control_service_url — absl flag --vbar_control_service_url=<url>;TPU-driver env-var token 是 kVbarControlServiceUrl.
  3. 当该 flag 未设置时,回退到 Unix-socket 默认值/var/google/services/tpunetd/user.socket。 这个精确字符串在 .rodata 中出现一次(已在反编译输出中确认)。

连接日志行是 "Connecting to vbar control service at "(后接解析后的 URL),已在二进制中逐字确认。

通道之上选择的桩

通道进入 READY 后,会准确包装两个守护进程桩之一:

c
// inside ConnectToTpunetd
if process_owns_chips == false:
    install NoOpControl                         // rodata "process_owns_chips is false, using NoOpControl"
    return OK                                   // never opens a channel at all
else:
    channel = ConnectToGrpcEndpoint(url, retry_timeout)
    if FLAGS_bypass_vbar_control_service:       // default = false
        stub = superpod::tpunetd::grpc_gen::SessionControl::NewStub(channel)   // 0x1ffcdd20
        wrap into TpunetdControl
    else:
        stub = libtpu::tpunetd::grpc::VBARControl::NewStub(channel)
        wrap into VbarControl proxy
```text

> **陷阱 —** 当 `Options.process_owns_chips == false` 时,永远不会打开通道。客户端会安装 `NoOpControl`,其每个方法都会记录
> `"NoOpControl::<Op> is called; skipping tpunetd call"` 并返回 OK。
> 总是拨打 socket 的重新实现会在合法不拥有芯片的 chip-less / sidecar 进程上挂住。

### 激活门(实现选择工厂)

是否使用 `tpunetd` 完全由上一层决定,即位于 `0x1fba1100` 的
`superpod::routing::CreateTpuNetworkInterface(const tpu::TpuTopology&,
bool)`。分支如下:

```c
// superpod::routing::CreateTpuNetworkInterface  (0x1fba1100)
function CreateTpuNetworkInterface(topology, process_owns_chips):
    if FLAGS_enable_tpunetd_client                          // default false
       && binary_search(kTpunetdSupportedTpuVersions, topology.tpu_type):
        log("Running in Cloud, using TpunetdClient")
        return TpunetdClient::Create(topology, tpu_type, Options)   // kTpunetd impl
    else:
        log("tpunetd either not supported or disabled, falling back to Slice Builder")
        return SliceBuilder-backed impl                     // accel_ssw::deepsea::slice_builder::*

kTpunetdSupportedTpuVersions.rodata 中位于 0xb8ec184 的已排序 tpu::TpuType 数组 — 它是 superpod::routing::CreateTpuNetworkFactory 的 static-local,但在这里被引用。它正好包含两个条目 {4, 5}(字节 04 00 00 00 05 00 00 00, 结束哨兵位于 0xb8ec18c);查找是在这些 4 字节 TpuType 值上进行的 lower_bound 风格二分搜索。因此 tpunetd 严格是 Cloud / production-superpod 路径;其他一切都会回退到进程内 SliceBuilder 家族及其自己的 /accel_ssw.deepsea.slice_builder.SliceBuilderWorkerService/* RPC。.rodata 中的 BorglessTpunetd token 是在没有 Borg 作业管理器的 Cloud TPU VM 上使用的本地主机变体。两个激活日志字符串都已逐字确认。完整启动序列见 bootstrap/tpunetd-relationship.md.


服务 1 — SessionControl(守护进程,7 个方法)

目的

完整守护进程上的面向用户的芯片 session 生命周期。仅当 --bypass_vbar_control_service=true 时才直接使用。“session”是对一组由 asic_sw::proto::ChipLocation 标识的芯片进行独占(或共享)控制的权利。

编码

text
Wire prefix : /superpod.tpunetd.SessionControl/
Package     : superpod.tpunetd
Stub class  : superpod::tpunetd::grpc_gen::SessionControl::Stub
NewStub     : 0x1ffcdd20   (takes shared_ptr<grpc::ChannelInterface>, StubOptions)
Ctor        : 0x1ffcdd60
```text

全部七个方法都遵循标准生成桩签名
`Stub::<Op>(grpc::ClientContext*, const <Op>Request&, <Op>Response*)`,
并带有一个包含 `ClientUnaryReactor` 的 `async` 内部类变体。请求和响应类型对从逐方法的 mangled 符号中恢复。

| RPC | 请求 | 响应 | 桩地址 |
|---|---|---|---|
| `StartSession` | `superpod.tpunetd.StartSessionRequest` | `…StartSessionResponse` | `0x1ffce0e0` |
| `StopSession` | `…StopSessionRequest` | `…StopSessionResponse` | `0x1ffce2c0` |
| `StatSession` | `…StatSessionRequest` | `…StatSessionResponse` | `0x1ffce4a0` |
| `CheckSessionHealth` | `…CheckSessionHealthRequest` | `…CheckSessionHealthResponse` | `0x1ffce6a0` |
| `GetChipCoordinates` | `…GetChipCoordinatesRequest` | `…GetChipCoordinatesResponse` | `0x1ffceaa0` |
| `GetCoreDump` | `…GetCoreDumpRequest` | `…GetCoreDumpResponse` | `0x1ffce8a0` |
| `GrantSessionPermission` | `…GrantSessionPermissionRequest` | `…GrantSessionPermissionResponse` | `0x1ffcdf00` |

### 客户端包装器

`superpod::tpunetd_client::TpunetdControl` 是手写类,它包装 `SessionControl` 桩,并把内部 `SessionData`
结构体转换为 proto 请求。已确认的入口点:

| 包装器方法 | 地址 |
|---|---|
| `TpunetdControl::StartSession(const SessionData&)` | `0x1ffcb660` |
| `TpunetdControl::StopSession(const SessionData&)` | `0x1ffcbc80` |
| `TpunetdControl::StatSession` | `0x1ffcc2a0` |
| `TpunetdControl::CheckSessionHealth` | `0x1ffcc9a0` |
| `TpunetdControl::GetCoreDump` | `0x1ffcd040` |
| `TpunetdControl::GetChipCoordinates` | `0x1ffcd7c0` |

每个包装器都从全局常量 `superpod::tpunetd_client::kSessionControlTimeout`(mangled
`_ZN8superpod14tpunetd_client22kSessionControlTimeoutE`,类型
`absl::Duration`)设置 `grpc::ClientContext` deadline。所有包装器中的 deadline 计算完全相同:
`now = absl::Now(); deadline = now + kSessionControlTimeout;`
然后是 `absl::ToChronoTime` → `grpc::Timepoint2Timespec` →
`context.set_deadline`。

---

## 服务 2 — VBARControl(libtpu↔守护进程 shim,8 个方法,默认)

### 目的

这是**默认**路径。当 `--bypass_vbar_control_service` 为 false(默认)时,libtpu 不直接调用 `SessionControl`;它通过一个 Virtual-BAR shim,由该 shim 经由
`tpunetd` 中介 BAR-register 操作,而不是让用户进程直接接触芯片。方法集合镜像了 `SessionControl` 的六个芯片 session 调用,并额外包含两个方法:
`GetHostMetrics` 和 `TPUBackendConnectionTest`。它**不**暴露 `GrantSessionPermission`(该授权是守护进程内部 /
控制器关注点)。

### 编码

```text
Wire prefix : /libtpu.tpunetd.VBARControl/
Package     : libtpu.tpunetd                         (note: NOT superpod.tpunetd)
Stub class  : libtpu::tpunetd::grpc::VBARControl::Stub
NewStub     : 0x1ffd2360   (Stub ctor at 0x1ffd23a0)
Source proto: learning/45eac/tfrc/tpunetd/proto/vbar_control.proto  (TFRC team)
RPC请求响应桩地址
StartSessionlibtpu.tpunetd.StartSessionRequest…StartSessionResponse0x1ffd2580
StopSession…StopSessionRequest…StopSessionResponse0x1ffd2760
StatSession…StatSessionRequest…StatSessionResponse0x1ffd2940
CheckSessionHealth…CheckSessionHealthRequest…CheckSessionHealthResponse0x1ffd2b20
GetChipCoordinates…GetChipCoordinatesRequest…GetChipCoordinatesResponse0x1ffd3120
GetCoreDump…GetCoreDumpRequest…GetCoreDumpResponse0x1ffd2d20
GetHostMetrics…GetHostMetricsRequest…GetHostMetricsResponse0x1ffd3320
TPUBackendConnectionTest…TPUBackendConnectionTestRequest…TPUBackendConnectionTestResponse0x1ffd2f20

全部八个桩函数及其 async / ClientUnaryReactor 变体都作为不同的反编译函数存在;请求和响应类型名直接从 mangled 签名读取(例如 …Stub::StartSession(grpc::ClientContext*, const StartSessionRequest&, StartSessionResponse*))。

libtpu.tpunetd package 中的额外消息

除了请求/响应对之外,VBAR proto 还声明了用于复用 BAR poke 的 envelope 机制:

消息 / 枚举作用
libtpu.tpunetd.Status携带嵌套 Status.StatusCode 枚举的 status 包装器
libtpu.tpunetd.VBARRequestTypeoneof-tag 枚举,用于选择 envelope 携带哪一种 VBAR poke
libtpu.tpunetd.VBARRequestInput跨 poke 类型的请求 envelope union

注意 — TPUBackendConnectionTestTPU_BACKEND_CONNECTION_TEST env var 控制。VBARRequestType / VBARRequestInput oneof envelope 在线缆上的序列化无法仅从客户端单元恢复 — 复现它需要解码 protodesc_cold 字段 ID 或守护进程二进制。对于需要逐字节精确 VBAR poke framing 的重新实现者,标记为 LOW。


服务 3 — TpuNetworkSessionWorker(点对点,4 个方法)

目的

这是主机间 fanout 通道。一个 slice 中的一个节点运行 session-master 角色;其余节点运行 session-worker 角色。master 通过 TCP gRPC 联系每个 worker,以进行 heartbeat、session info 和 core-dump 收集。这是栈中唯一一个客户端主机彼此通信的部分;tpunetd 不知道它的存在 — 它把 worker 列表交给 master 后就退出这个流程。

编码

text
Wire prefix : /superpod.tpunetd_client.TpuNetworkSessionWorker/
Package     : superpod.tpunetd_client
Transport   : gRPC over TCP (peer hosts)  /  in-process loopback (local node)
```text

| RPC | 请求 | 响应 |
|---|---|---|
| `CheckHeartbeat` | `superpod.tpunetd_client.CheckHeartbeatRequest` | `…CheckHeartbeatResponse` |
| `GetSessionInfo` | `…GetSessionInfoRequest` | `…GetSessionInfoResponse` |
| `UpdateSessionInfo` | `…UpdateSessionInfoRequest` | `…UpdateSessionInfoResponse` |
| `CollectCoreDump` | `…CollectCoreDumpRequest` | `…CollectCoreDumpResponse` |

### 桩实现

两个桩类型实现相同表面:

- **`SessionWorkerStubRpc`**(`CheckHeartbeat` 位于 `0x1ffcb1a0`)— 通过内部 `TpuNetworkSessionWorker::StubInterface*` 进行的真实
  gRPC。
- **`SessionWorkerStubLocal`**(`CheckHeartbeat` 位于 `0x1ff920e0`)— 相同表面,但通过 `FakeServerContext` 循环调用,使 master 能在没有实际 TCP 往返的情况下调用自己的 worker 进程。

peer 列表**不是由客户端自身发现的**。它由调用方以 `flat_hash_map<string worker_name,
SessionWorkerStubFactory>` 的形式提供给 `SessionMaster::Create`;每个条目的工厂闭包都会产出一个 `unique_ptr&lt;SessionWorkerStub&gt;`,可能是 RPC 变体或本地变体。peer 地址的权威来源是 Megascale coordinator(`MEGASCALE_COORDINATOR_ADDRESS`)。见
[`fleet-metadata/overview.md`](fleet-metadata/overview.md).

### UpdateSessionInfoRequest 字段模式

从二进制中逐字确认的验证器错误文本中恢复(`session_worker_validation.cc`):

| 字段 | 类型 | 规则 |
|---|---|---|
| `in_session` | bool | 必需(`"in_session must be specified"`) |
| `session_id` | string | 当且仅当 `in_session == true` 时必需(`"session_id must be present iff in_session is true"`) |
| `failure_type` | enum | 当且仅当 `in_session == true` 时必须不存在;值 `SLICE_FAILURE_UNKNOWN` 被拒绝 |

`failure_type` 枚举与 SliceBuilder 代码路径共享
(`accel_ssw::deepsea::slice_builder::SliceFailureType`)。

### Heartbeat 行为

`SessionMaster::CheckSessionHeartbeat()`(`0x1ffa6180`)驱动扫描:

```c
// SessionMaster::CheckSessionHeartbeat  (0x1ffa6180)
function CheckSessionHeartbeat():
    lock(heartbeat_mutex)                         // SessionMaster offset +104
    ExecuteOnAllWorkers([](name, stub){            // fans CheckHeartbeat to all peers
        return stub->CheckHeartbeat(req, resp, deadline)
    })
    for worker in results:
        if any chip has chip_id == 0:              // vector<asic_sw::proto::ChipLocation>
            log("Session is failing due to the following chips having zero as chip id")
            transition SessionState -> kFailing (=3)   // HandleFailingSession on ThreadPool
            return
    reschedule self at now + heartbeat_interval    // ThreadPool::ScheduleAt; interval at offset 0

heartbeat_interval 位于 SessionMaster 偏移 0(由 Options.heartbeat_interval 设置);heartbeat 扫描的逐调用 deadline 是用户提供的绝对 absl::Time,而不是一元守护进程调用使用的 kSessionControlTimeout 时长。


服务 4 — TpuNetworkSessionBarrier(点对点,2 个方法)

目的

用于同步一个 slice 中各主机的点对点 rendezvous barrier。与 TpuNetworkSessionWorker 一样,服务器侧由每个 libtpu 进程自身托管 — 符号表中的 WithCallbackMethod_Notify / WithCallbackMethod_WaitForReady 模板实例化就是进程内服务器。tpunetd 不参与。

编码

text
Wire prefix : /superpod.tpunetd_client.proto.TpuNetworkSessionBarrier/
Package     : superpod.tpunetd_client.proto      (note the extra .proto sub-namespace)
Client class: BroadcastBarrier  (tpunetd_client/lib/broadcast_barrier.cc)
```text

| RPC | 请求 | 响应 |
|---|---|---|
| `Notify` | `superpod.tpunetd_client.proto.NotifyRequest`(barrier_id string + chip_locations) | `…NotifyResponse`(仅 status) |
| `WaitForReady` | `…WaitForReadyRequest`(barrier_id string) | `…WaitForReadyResponse`(仅 status) |

### 算法

```c
// BroadcastBarrier  (Init 0x1ff9bac0, BroadcastNotification 0x1ff9c320)
function Init(absl::Duration):
    for each known peer worker:                 // peer count at this+104, peer array at this+96
        build one std::function<absl::Status()>  // 32 B closure each; vector sized 32 * num_workers

function BroadcastNotification(barrier_id, deadline):
    materialize vector<grpc::ClientContext>(num_peers)   // 400 B each; alloc = 400 * num_peers
    counter = absl::BlockingCounter(num_peers)
    for peer in peers:                          // parallel fan-out
        log("Notifying " + peer + " with barrier id " + barrier_id)
        async Notify(peer, {barrier_id, chip_locations}) -> counter.DecrementCount()
    counter.Wait()

function BroadcastWaitForReady(barrier_id, deadline):
    // symmetric parallel fan-out of WaitForReady

function SyncWithTimeout(barrier_id, timeout):
    BroadcastNotification(barrier_id, now + timeout)   // fire-and-forget per peer
    BroadcastWaitForReady(barrier_id, now + timeout)   // blocks until every peer notified AND waiting

SyncWithTimeout 是面向用户的 collective rendezvous 点:Notify 对每个 peer 都是即发即忘;WaitForReady 会阻塞,直到每个 peer 都已经通知了相同的 barrier_id,并且自身也在等待它。当 process_owns_chips == false 时,NoopBarrierlib/noop_barrier.h)会替代它。


SessionData — 每个守护进程请求携带的内容

superpod::tpunetd_client::SessionControlInterface::SessionDataTpunetdControl 封送进每个 Start/Stop/Stat/ CheckHealth/GetCoreDump/GetChipCoordinates 请求的内部结构体。布局从反编译调用点恢复(偏移以字节计):

偏移类型含义
+0vector<DriverInterface*>::begin逐芯片 driver 指针数组(起点)
+8vector<DriverInterface*>::enddrivers vector 末尾 — 用作 for-loop 边界
+24superpod::routing::proto::Topology附加到 session 的 topology proto
+104NetworkContextIdnetwork identity,当且仅当 +144 == 1 处的 flag 为真时复制进请求
+144boolhas_network_context — 控制是否复制 +104

[+0, +8) 数组中的每个 driver 都在 vtable 偏移 +56 处暴露一个虚函数,返回 asic_sw::ChipLocation;libtpu 对每个 driver 调用它,并把结果追加到请求的 repeated ChipLocation chip_locations

怪异点 — tpunetd 从不自行发现芯片。每个 session RPC 都携带用户进程的完整本地 ChipLocation 集合, 由客户端从其 driver vector 公布。期望守护进程枚举芯片的重新实现会得到空的 chip_locations,以及一个不拥有任何东西的 session。


CoreDump 收集

Two distinct paths produce core dumps:

text
direct (daemon):
  TpunetdControl::GetCoreDump(SessionData, CoreDumpType, Duration)
    -> /superpod.tpunetd.SessionControl/GetCoreDump
    CoreDumpType ∈ { CORE_DUMP_UNKNOWN, CORE_DUMP_CHIP_DUMP, CORE_DUMP_ICI_DUMP }

peer fanout (master collects from all workers):
  SessionMaster::ExecuteOnAllWorkers([](name, stub){
      return stub->CollectCoreDump(req, resp, deadline); })
    -> /superpod.tpunetd_client.TpuNetworkSessionWorker/CollectCoreDump
    writes through accel_ssw::deepsea::CoreDumpUploader (CoreDumpUploaderInterface)
    which can also reach logmanagerd at
      /var/google/services/logmanagerd/remote_coredump.socket
```text

---

## 仅守护进程 RPC 表面(已声明,从不由 libtpu 发起)

`superpod.tpunetd` proto 描述符声明了一个很大的 ICI-fabric /
routing-controller 表面,它被链接进来(作为描述符字节),但客户端从不调用。这些属于同样会与 `tpunetd` 通信的 superpod-routing 控制器平面。下面按轴列出而非穷尽列出,使重新实现者无需 30 行转储也能了解守护进程的完整方法空间:

| 轴 | RPC(在描述符中声明) |
|---|---|
| Network lifecycle | `CreateNetwork`, `DeleteNetwork`, `ListNetworks`, `UpdateTopology`, `GetLocalTopology` |
| ICI data links | `ConfigureIci`, `EnableIciDataLink`, `WaitForDataLinkUp`, `ResetIciNetwork`, `UpdateIciNetworkConfiguration` |
| Routing | `SetRoutingTable` (+ `RoutingTableMap`) |
| Coordinates / IDs | `SetChipCoordinates`, `SetGlobalChipId` |
| Global time counter (GTC) | `SetGtcConfiguration`, `ClearGlobalGtc`, `WaitForGtcReset` |
| Reset / driver | `PerformReset`, `RestartDriver` |

这些确认 `tpunetd` 拥有主机上的 ICI-link 配置、routing-table
安装和 global-time 同步 — 但它们都不是 libtpu 客户端契约的一部分。它们产生的 chip-coordinate 输出会被 libtpu 通过 `GetChipCoordinates` 读回,并流入
[fleet-metadata](fleet-metadata/overview.md) 和 Megascale topology
exchange。

---

## Proto 文件清单

四个 `FileDescriptorProto` blob 支撑四个服务;另外三个 routing proto 提供共享消息类型。文件名作为带长度前缀的字符串在 proto pool(`protodesc_cold` ELF section)中可见。

| Proto 路径 | Package | 服务 |
|---|---|---|
| `…/superpod/routing/tpunetd/proto/tpunetd.proto` | `superpod.tpunetd` | SessionControl |
| `…/superpod/routing/tpunetd/proto/common.proto` | `superpod.tpunetd` | (仅消息) |
| `…/superpod/routing/tpunetd_client/proto/session_worker.proto` | `superpod.tpunetd_client` | TpuNetworkSessionWorker |
| `…/superpod/routing/tpunetd_client/proto/session_barrier.proto` | `superpod.tpunetd_client.proto` | TpuNetworkSessionBarrier |
| `…/superpod/routing/tpunetd_client/proto/common.proto` | `superpod.tpunetd_client` | (仅消息) |
| `learning/45eac/tfrc/tpunetd/proto/vbar_control.proto` | `libtpu.tpunetd` | VBARControl |

共享 routing proto:`common/proto/topology.proto`
(`superpod.routing.proto`)、`common/proto/chip_coordinate.proto`、
`common/proto/tpu_type.proto`(`TpuType` 枚举,dense `0..10`,名称在运行时通过
`proto2::internal::NameOfDenseEnum<&TpuType_descriptor,0,10>` 获取),以及
`common/proto/ici_network_config.proto`.

> **陷阱 —** 每个描述符文件名字符串开头的数字是 protobuf 内部长度前缀字节,**不是**字段号。这里没有恢复每个请求/响应的数值型**字段 ID**;
> 它们需要解码压缩的 `protodesc_cold` 条目或守护进程二进制。任何逐字节精确的线缆重新实现都必须执行该解码 —
> 本页中的消息*形状*足以命名字段,但不足以分配它们的 tag number。(字段编号置信度 LOW;消息名称和 RPC 表面 CERTAIN。)

---

## 安全性和可观测性说明

- **本地链路没有传输安全性。** 通道使用
  `grpc::InsecureChannelCredentials()` 构建(已在
  `ConnectToGrpcEndpoint` 第 67 行确认)。认证如果存在,也是在守护进程侧 —
  可能是 Unix socket 上的 `SO_PEERCRED` 或文件系统权限 — 并且**无法从客户端单元观察到**。连接到该 socket 的第三方客户端将面对守护进程强制执行的任何机制,而这个二进制没有揭示其细节(LOW)。
- **Telemetry。** `IciSessionMonitorImpl` 通过 `tsl::monitoring` 把 session-health、
  state-transition latency、broadcast latency、notification latency,以及
  missed-health-check 计数记录到 `/tpu/…`
  树下的 TF streamz counters 中。`tpu_type` label 值通过
  `NameOfDenseEnum<&TpuType_descriptor,0,10>`.

---

## 交叉引用

- [Megascale 概览](overview.md) — tpunetd 在 multi-host / DCN 栈中的位置
- [bootstrap/tpunetd 关系](bootstrap/tpunetd-relationship.md) — *使用*这个桩的启动序列;tpunetd → MegaScaleTransport 顺序
- [bootstrap/概览](bootstrap/overview.md) — 整体 job-bringup rendezvous
- [fleet-metadata/概览](fleet-metadata/overview.md) — 通过这个表面交换的 peer-address / chip-coordinate metadata
- [错误聚合器](error-aggregator.md) — session-failure 信号(kFailing、zero-chip-id)呈现给 runtime 的位置
- [ICI Topology Discovery](../ici/topology-discovery.md) — 守护进程的 superpod-controller 表面驱动的 ICI-fabric 配置