blob: 68d445eb547e2759858a1ba4e4a4a1d2a458315f [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//go:build !build_with_native_toolchain
package netstack
import (
"context"
"fmt"
"time"
"go.fuchsia.dev/fuchsia/src/lib/component"
syslog "go.fuchsia.dev/fuchsia/src/lib/syslog/go"
"fidl/fuchsia/diagnostics/persist"
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
persistenceTagName = "persist"
// The amount of time to wait after requesting persistence before doing so
// again.
persistPeriod = 12 * time.Minute
)
var tags = []string{
"counters",
"fidl",
"memstats",
"nics",
"routes",
"runtime",
"sockets",
}
// startPersistClient attempts to start the persistence polling client. Fatal
// startup errors will cause this function to panic; any other failures will be
// logged as warnings.
func startPersistClient(ctx context.Context, componentCtx *component.Context, clock tcpip.Clock) {
_ = syslog.InfoTf(persistenceTagName, "starting persistence client")
persistServerEnd, persistClientEnd, err := persist.NewDataPersistenceWithCtxInterfaceRequest()
if err != nil {
_ = syslog.FatalTf(persistenceTagName, "failed to create channel: %s", err)
}
if err := componentCtx.ConnectToProtocolAtPath(
"fuchsia.diagnostics.persist.DataPersistence-netstack", persistServerEnd); err != nil {
_ = syslog.WarnTf(persistenceTagName, "couldn't connect to persistence service: %s", err)
return
}
runPersistClient(persistClientEnd, ctx, clock)
}
func runPersistClient(persistClientEnd *persist.DataPersistenceWithCtxInterface, ctx context.Context, clock tcpip.Clock) {
_ = syslog.InfoTf(persistenceTagName, "starting persistence polling routine")
// Request immediately, then wait for the timer.
if err := makePersistenceRequest(persistClientEnd, ctx, 0*time.Second); err != nil {
_ = syslog.WarnTf(persistenceTagName, "aborting persistence routine startup: %s", err)
return
}
var timer tcpip.Timer
timer = clock.AfterFunc(persistPeriod, func() {
select {
case <-ctx.Done():
_ = syslog.InfoTf(persistenceTagName, "stopping persistence polling routine")
default:
if err := makePersistenceRequest(persistClientEnd, ctx, 5*time.Second); err != nil {
_ = syslog.WarnTf(persistenceTagName, "stopping persistence routine: %s", err)
return
}
timer.Reset(persistPeriod)
}
})
}
func makePersistenceRequest(persistClientEnd *persist.DataPersistenceWithCtxInterface, ctx context.Context, delay time.Duration) error {
_ = syslog.DebugTf(persistenceTagName, "requesting persistence for netstack")
for _, tag := range tags {
result, err := persistClientEnd.Persist(ctx, tag)
if err != nil {
return fmt.Errorf("failed to request persistence: %w", err)
}
if want := persist.PersistResultQueued; result != want {
_ = syslog.WarnTf(persistenceTagName, "unexpected persist result; expected %s got %s", want, result)
}
// TODO(https://fxbug.dev/42080432): Remove once multi-tag persistence is working
time.Sleep(delay)
}
return nil
}