From e9eb34cea8b72e255ffe436531cb267d1092cf06 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Wed, 19 Jan 2022 18:41:19 +0100 Subject: [PATCH 01/47] kata-monitor: improve debug logging Improve debug log formatting of the sandbox cache update process. Move raw and tracing logs from the DEBUG to the TRACE log level. Signed-off-by: Francesco Giudici --- src/runtime/pkg/kata-monitor/cri.go | 15 ++++++++++----- src/runtime/pkg/kata-monitor/metrics.go | 2 +- src/runtime/pkg/kata-monitor/monitor.go | 3 ++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/runtime/pkg/kata-monitor/cri.go b/src/runtime/pkg/kata-monitor/cri.go index f9cbf3c9f..b0cd82a01 100644 --- a/src/runtime/pkg/kata-monitor/cri.go +++ b/src/runtime/pkg/kata-monitor/cri.go @@ -39,7 +39,6 @@ func getAddressAndDialer(endpoint string) (string, func(ctx context.Context, add func getConnection(endPoint string) (*grpc.ClientConn, error) { var conn *grpc.ClientConn - monitorLog.Debugf("connect using endpoint '%s' with '%s' timeout", endPoint, defaultTimeout) addr, dialer, err := getAddressAndDialer(endPoint) if err != nil { return nil, err @@ -51,7 +50,7 @@ func getConnection(endPoint string) (*grpc.ClientConn, error) { errMsg := errors.Wrapf(err, "connect endpoint '%s', make sure you are running as root and the endpoint has been started", endPoint) return nil, errMsg } - monitorLog.Debugf("connected successfully using endpoint: %s", endPoint) + monitorLog.Tracef("connected successfully using endpoint: %s", endPoint) return conn, nil } @@ -132,28 +131,34 @@ func (km *KataMonitor) getSandboxes(sandboxMap map[string]bool) (map[string]bool request := &pb.ListPodSandboxRequest{ Filter: filter, } - monitorLog.Debugf("ListPodSandboxRequest: %v", request) + monitorLog.Tracef("ListPodSandboxRequest: %v", request) r, err := runtimeClient.ListPodSandbox(context.Background(), request) if err != nil { return newMap, err } - monitorLog.Debugf("ListPodSandboxResponse: %v", r) + monitorLog.Tracef("ListPodSandboxResponse: %v", r) for _, pod := range r.Items { // Use the cached data if available if isKata, ok := sandboxMap[pod.Id]; ok { newMap[pod.Id] = isKata + if isKata { + monitorLog.Debugf("KATA POD %s (cached)", pod.Id) + } continue } // Check if a directory associated with the POD ID exist on the kata fs: // if so we know that the POD is a kata one. newMap[pod.Id] = checkSandboxFSExists(pod.Id) + if newMap[pod.Id] { + monitorLog.Debugf("KATA POD %s (new)", pod.Id) + } monitorLog.WithFields(logrus.Fields{ "id": pod.Id, "is kata": newMap[pod.Id], "pod": pod, - }).Debug("") + }).Trace("") } return newMap, nil diff --git a/src/runtime/pkg/kata-monitor/metrics.go b/src/runtime/pkg/kata-monitor/metrics.go index b1788de46..5f5fa3e4c 100644 --- a/src/runtime/pkg/kata-monitor/metrics.go +++ b/src/runtime/pkg/kata-monitor/metrics.go @@ -156,7 +156,7 @@ func (km *KataMonitor) aggregateSandboxMetrics(encoder expfmt.Encoder) error { // used to receive response results := make(chan []*dto.MetricFamily, len(sandboxes)) - monitorLog.WithField("sandbox_count", len(sandboxes)).Debugf("sandboxes count") + monitorLog.WithField("sandboxes count", len(sandboxes)).Debugf("aggregate sandbox metrics") // get metrics from sandbox's shim for _, sandboxID := range sandboxes { diff --git a/src/runtime/pkg/kata-monitor/monitor.go b/src/runtime/pkg/kata-monitor/monitor.go index 6d0003af5..c5c166d94 100644 --- a/src/runtime/pkg/kata-monitor/monitor.go +++ b/src/runtime/pkg/kata-monitor/monitor.go @@ -126,13 +126,14 @@ func (km *KataMonitor) startPodCacheUpdater() { "cache update timer fires in %d secs", podCacheRefreshDelaySeconds) case <-cacheUpdateTimer.C: + monitorLog.Debugf("sync sandbox cache with the container engine") sandboxes, err := km.getSandboxes(km.sandboxCache.getAllSandboxes()) if err != nil { monitorLog.WithError(err).Error("failed to get sandboxes") continue } monitorLog.WithField("count", len(sandboxes)).Info("synced sandbox cache with the container engine") - monitorLog.WithField("sandboxes", sandboxes).Debug("dump sandbox cache") + monitorLog.WithField("sandboxes", sandboxes).Trace("dump sandbox cache") km.sandboxCache.set(sandboxes) } } From e78d80ea0d9f7133b7d8f10a6380f4a5e7eda98e Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Thu, 20 Jan 2022 15:09:27 +0100 Subject: [PATCH 02/47] kata-monitor: silently ignore CHMOD events on the sandboxes fs We currently WARN about unexpected fs events, which includes CHMOD operations (which should be actually expected...). Just ignore all the fs events we don't care about without any warn. We dump all the events with debug log in any case. Signed-off-by: Francesco Giudici --- src/runtime/pkg/kata-monitor/monitor.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/runtime/pkg/kata-monitor/monitor.go b/src/runtime/pkg/kata-monitor/monitor.go index c5c166d94..593a15c88 100644 --- a/src/runtime/pkg/kata-monitor/monitor.go +++ b/src/runtime/pkg/kata-monitor/monitor.go @@ -113,9 +113,6 @@ func (km *KataMonitor) startPodCacheUpdater() { "REMOVE event but pod was missing from the sandbox cache") } monitorLog.WithField("pod", id).Info("sandbox cache: removed pod") - - default: - monitorLog.WithField("event", event).Warn("got unexpected fs event") } // While we process fs events directly to update the sandbox cache we need to sync with the From 7516a8c51b40e5b84b46f1888b2337c50e1acce5 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Tue, 25 Jan 2022 09:33:07 +0100 Subject: [PATCH 03/47] kata-monitor: rework the sandbox cache sync with the container manager Kata-monitor detects started and terminated kata pods by monitoring the vc/sbs fs (this makes sense since we will have to access that path to access the sockets there to get the metrics from the shim). While kata-monitor updates its sandbox cache based on the sbs fs events, it will schedule also a sync with the container manager via the CRI in order to sync the list of sandboxes there. The container manager will be the ultimate source of truth, so we will stick with the response from the container manager, removing the sandboxes not reported from the container manager. May happen anyway that when we check the container manager, the new kata pod is not reported yet, and we will remove it from the kata-monitor pod cache. If we don't get any new kata pod added or removed, we will not check with the container manager again, missing reporting metrics about that kata pod. Let's stick with the sbs fs as the source of truth: we will update the cache just following what happens on the sbs fs. At this point we may have also decided to drop the container manager connection... better instead to keep it in order to get the kube pod metadata from it, i.e., the kube UID, Name and Namespace associated with the sandbox. Every time we get a new sandbox from the sbs fs we will try to retrieve the pod metadata associated with it. Right now we just attach the container manager sandbox id as a label to the exposed metrics, making hard to link the metrics to the running pod in the kubernetes cluster. With kubernetes pod metadata we will be able to add them as labels to map explicitly the metrics to the kubernetes workloads. Fixes: #3550 Signed-off-by: Francesco Giudici --- src/runtime/pkg/kata-monitor/cri.go | 50 +++++++------- src/runtime/pkg/kata-monitor/metrics.go | 2 +- src/runtime/pkg/kata-monitor/monitor.go | 68 ++++++++++++++----- src/runtime/pkg/kata-monitor/sandbox_cache.go | 34 ++++++---- .../pkg/kata-monitor/sandbox_cache_test.go | 10 +-- 5 files changed, 103 insertions(+), 61 deletions(-) diff --git a/src/runtime/pkg/kata-monitor/cri.go b/src/runtime/pkg/kata-monitor/cri.go index b0cd82a01..0e9e06884 100644 --- a/src/runtime/pkg/kata-monitor/cri.go +++ b/src/runtime/pkg/kata-monitor/cri.go @@ -113,15 +113,15 @@ func parseEndpoint(endpoint string) (string, string, error) { } } -// getSandboxes gets ready sandboxes from the container engine and returns an updated sandboxMap -func (km *KataMonitor) getSandboxes(sandboxMap map[string]bool) (map[string]bool, error) { - newMap := make(map[string]bool) +// syncSandboxes gets pods metadata from the container manager and updates the sandbox cache. +func (km *KataMonitor) syncSandboxes(sandboxList []string) ([]string, error) { runtimeClient, runtimeConn, err := getRuntimeClient(km.runtimeEndpoint) if err != nil { - return newMap, err + return sandboxList, err } defer closeConnection(runtimeConn) + // TODO: if len(sandboxList) is 1, better we just runtimeClient.PodSandboxStatus(...) targeting the single sandbox filter := &pb.PodSandboxFilter{ State: &pb.PodSandboxStateValue{ State: pb.PodSandboxState_SANDBOX_READY, @@ -134,32 +134,32 @@ func (km *KataMonitor) getSandboxes(sandboxMap map[string]bool) (map[string]bool monitorLog.Tracef("ListPodSandboxRequest: %v", request) r, err := runtimeClient.ListPodSandbox(context.Background(), request) if err != nil { - return newMap, err + return sandboxList, err } monitorLog.Tracef("ListPodSandboxResponse: %v", r) for _, pod := range r.Items { - // Use the cached data if available - if isKata, ok := sandboxMap[pod.Id]; ok { - newMap[pod.Id] = isKata - if isKata { - monitorLog.Debugf("KATA POD %s (cached)", pod.Id) + for _, sandbox := range sandboxList { + if pod.Id == sandbox { + km.sandboxCache.setMetadata(sandbox, sandboxKubeData{ + uid: pod.Metadata.Uid, + name: pod.Metadata.Name, + namespace: pod.Metadata.Namespace, + }) + + sandboxList = removeFromSandboxList(sandboxList, sandbox) + + monitorLog.WithFields(logrus.Fields{ + "Pod Name": pod.Metadata.Name, + "Pod Namespace": pod.Metadata.Namespace, + "Pod UID": pod.Metadata.Uid, + }).Debugf("Synced KATA POD %s", pod.Id) + + break } - continue } - - // Check if a directory associated with the POD ID exist on the kata fs: - // if so we know that the POD is a kata one. - newMap[pod.Id] = checkSandboxFSExists(pod.Id) - if newMap[pod.Id] { - monitorLog.Debugf("KATA POD %s (new)", pod.Id) - } - monitorLog.WithFields(logrus.Fields{ - "id": pod.Id, - "is kata": newMap[pod.Id], - "pod": pod, - }).Trace("") } - - return newMap, nil + // TODO: here we should mark the sandboxes we failed to retrieve info from: we should try a finite number of times + // to retrieve their metadata: if we fail resign and remove them from the sanbox cache (with a Warning log). + return sandboxList, nil } diff --git a/src/runtime/pkg/kata-monitor/metrics.go b/src/runtime/pkg/kata-monitor/metrics.go index 5f5fa3e4c..d2958441b 100644 --- a/src/runtime/pkg/kata-monitor/metrics.go +++ b/src/runtime/pkg/kata-monitor/metrics.go @@ -141,7 +141,7 @@ func encodeMetricFamily(mfs []*dto.MetricFamily, encoder expfmt.Encoder) error { // aggregateSandboxMetrics will get metrics from one sandbox and do some process func (km *KataMonitor) aggregateSandboxMetrics(encoder expfmt.Encoder) error { // get all kata sandboxes from cache - sandboxes := km.sandboxCache.getKataSandboxes() + sandboxes := km.sandboxCache.getSandboxList() // save running kata pods as a metrics. runningShimCount.Set(float64(len(sandboxes))) diff --git a/src/runtime/pkg/kata-monitor/monitor.go b/src/runtime/pkg/kata-monitor/monitor.go index 593a15c88..caacfb222 100644 --- a/src/runtime/pkg/kata-monitor/monitor.go +++ b/src/runtime/pkg/kata-monitor/monitor.go @@ -53,7 +53,7 @@ func NewKataMonitor(runtimeEndpoint string) (*KataMonitor, error) { runtimeEndpoint: runtimeEndpoint, sandboxCache: &sandboxCache{ Mutex: &sync.Mutex{}, - sandboxes: make(map[string]bool), + sandboxes: make(map[string]sandboxKubeData), }, } @@ -65,6 +65,15 @@ func NewKataMonitor(runtimeEndpoint string) (*KataMonitor, error) { return km, nil } +func removeFromSandboxList(sandboxList []string, sandboxToRemove string) []string { + for i, sandbox := range sandboxList { + if sandbox == sandboxToRemove { + return append(sandboxList[:i], sandboxList[i+1:]...) + } + } + return sandboxList +} + // startPodCacheUpdater will boot a thread to manage sandbox cache func (km *KataMonitor) startPodCacheUpdater() { sbsWatcher, err := fsnotify.NewWatcher() @@ -84,9 +93,24 @@ func (km *KataMonitor) startPodCacheUpdater() { monitorLog.Debugf("started fs monitoring @%s", getSandboxFS()) break } - // we refresh the pod cache once if we get multiple add/delete pod events in a short time (< podCacheRefreshDelaySeconds) + // Initial sync with the kata sandboxes already running + sbsFile, err := os.Open(getSandboxFS()) + if err != nil { + monitorLog.WithError(err).Fatal("cannot open sandboxes fs") + os.Exit(1) + } + sandboxList, err := sbsFile.Readdirnames(0) + if err != nil { + monitorLog.WithError(err).Fatal("cannot read sandboxes fs") + os.Exit(1) + } + monitorLog.Debug("initial sync of sbs directory completed") + monitorLog.Tracef("pod list from sbs: %v", sandboxList) + + // We should get kubernetes metadata from the container manager for each new kata sandbox we detect. + // It may take a while for data to be available, so we always wait podCacheRefreshDelaySeconds before checking. cacheUpdateTimer := time.NewTimer(podCacheRefreshDelaySeconds * time.Second) - cacheUpdateTimerWasSet := false + cacheUpdateTimerIsSet := true for { select { case event, ok := <-sbsWatcher.Events: @@ -99,11 +123,18 @@ func (km *KataMonitor) startPodCacheUpdater() { case fsnotify.Create: splitPath := strings.Split(event.Name, string(os.PathSeparator)) id := splitPath[len(splitPath)-1] - if !km.sandboxCache.putIfNotExists(id, true) { + if !km.sandboxCache.putIfNotExists(id, sandboxKubeData{}) { monitorLog.WithField("pod", id).Warn( "CREATE event but pod already present in the sandbox cache") } + sandboxList = append(sandboxList, id) monitorLog.WithField("pod", id).Info("sandbox cache: added pod") + if !cacheUpdateTimerIsSet { + cacheUpdateTimer.Reset(podCacheRefreshDelaySeconds * time.Second) + cacheUpdateTimerIsSet = true + monitorLog.Debugf( + "cache update timer fires in %d secs", podCacheRefreshDelaySeconds) + } case fsnotify.Remove: splitPath := strings.Split(event.Name, string(os.PathSeparator)) @@ -112,26 +143,27 @@ func (km *KataMonitor) startPodCacheUpdater() { monitorLog.WithField("pod", id).Warn( "REMOVE event but pod was missing from the sandbox cache") } + sandboxList = removeFromSandboxList(sandboxList, id) monitorLog.WithField("pod", id).Info("sandbox cache: removed pod") } - // While we process fs events directly to update the sandbox cache we need to sync with the - // container engine to ensure we are on sync with it: we can get out of sync in environments - // where kata workloads can be started by other processes than the container engine. - cacheUpdateTimerWasSet = cacheUpdateTimer.Reset(podCacheRefreshDelaySeconds * time.Second) - monitorLog.WithField("was reset", cacheUpdateTimerWasSet).Debugf( - "cache update timer fires in %d secs", podCacheRefreshDelaySeconds) - case <-cacheUpdateTimer.C: - monitorLog.Debugf("sync sandbox cache with the container engine") - sandboxes, err := km.getSandboxes(km.sandboxCache.getAllSandboxes()) + cacheUpdateTimerIsSet = false + monitorLog.WithField("pod list", sandboxList).Debugf( + "retrieve pods metadata from the container manager") + sandboxList, err = km.syncSandboxes(sandboxList) if err != nil { - monitorLog.WithError(err).Error("failed to get sandboxes") + monitorLog.WithError(err).Error("failed to get sandboxes metadata") continue } - monitorLog.WithField("count", len(sandboxes)).Info("synced sandbox cache with the container engine") - monitorLog.WithField("sandboxes", sandboxes).Trace("dump sandbox cache") - km.sandboxCache.set(sandboxes) + if len(sandboxList) > 0 { + monitorLog.WithField("sandboxes", sandboxList).Debugf( + "%d sandboxes still miss metadata", len(sandboxList)) + cacheUpdateTimer.Reset(podCacheRefreshDelaySeconds * time.Second) + cacheUpdateTimerIsSet = true + } + + monitorLog.WithField("sandboxes", km.sandboxCache.getSandboxList()).Trace("dump sandbox cache") } } } @@ -155,7 +187,7 @@ func (km *KataMonitor) GetAgentURL(w http.ResponseWriter, r *http.Request) { // ListSandboxes list all sandboxes running in Kata func (km *KataMonitor) ListSandboxes(w http.ResponseWriter, r *http.Request) { - sandboxes := km.sandboxCache.getKataSandboxes() + sandboxes := km.sandboxCache.getSandboxList() for _, s := range sandboxes { w.Write([]byte(fmt.Sprintf("%s\n", s))) } diff --git a/src/runtime/pkg/kata-monitor/sandbox_cache.go b/src/runtime/pkg/kata-monitor/sandbox_cache.go index 98978f193..f4f542b41 100644 --- a/src/runtime/pkg/kata-monitor/sandbox_cache.go +++ b/src/runtime/pkg/kata-monitor/sandbox_cache.go @@ -9,28 +9,31 @@ import ( "sync" ) +type sandboxKubeData struct { + uid string + name string + namespace string +} type sandboxCache struct { *sync.Mutex - // the bool value tracks if the pod is a kata one (true) or not (false) - sandboxes map[string]bool + // the sandboxKubeData links the sandbox id from the container manager to the pod metadata of kubernetes + sandboxes map[string]sandboxKubeData } -func (sc *sandboxCache) getAllSandboxes() map[string]bool { +func (sc *sandboxCache) getSandboxes() map[string]sandboxKubeData { sc.Lock() defer sc.Unlock() return sc.sandboxes } -func (sc *sandboxCache) getKataSandboxes() []string { +func (sc *sandboxCache) getSandboxList() []string { sc.Lock() defer sc.Unlock() - var katasandboxes []string - for id, isKata := range sc.sandboxes { - if isKata { - katasandboxes = append(katasandboxes, id) - } + var sandboxList []string + for id := range sc.sandboxes { + sandboxList = append(sandboxList, id) } - return katasandboxes + return sandboxList } func (sc *sandboxCache) deleteIfExists(id string) bool { @@ -46,7 +49,7 @@ func (sc *sandboxCache) deleteIfExists(id string) bool { return false } -func (sc *sandboxCache) putIfNotExists(id string, value bool) bool { +func (sc *sandboxCache) putIfNotExists(id string, value sandboxKubeData) bool { sc.Lock() defer sc.Unlock() @@ -59,7 +62,14 @@ func (sc *sandboxCache) putIfNotExists(id string, value bool) bool { return false } -func (sc *sandboxCache) set(sandboxes map[string]bool) { +func (sc *sandboxCache) setMetadata(id string, value sandboxKubeData) { + sc.Lock() + defer sc.Unlock() + + sc.sandboxes[id] = value +} + +func (sc *sandboxCache) set(sandboxes map[string]sandboxKubeData) { sc.Lock() defer sc.Unlock() sc.sandboxes = sandboxes diff --git a/src/runtime/pkg/kata-monitor/sandbox_cache_test.go b/src/runtime/pkg/kata-monitor/sandbox_cache_test.go index 43b8c8c99..6dd2e7894 100644 --- a/src/runtime/pkg/kata-monitor/sandbox_cache_test.go +++ b/src/runtime/pkg/kata-monitor/sandbox_cache_test.go @@ -16,24 +16,24 @@ func TestSandboxCache(t *testing.T) { assert := assert.New(t) sc := &sandboxCache{ Mutex: &sync.Mutex{}, - sandboxes: make(map[string]bool), + sandboxes: make(map[string]sandboxKubeData), } - scMap := map[string]bool{"111": true} + scMap := map[string]sandboxKubeData{"111": {"1-2-3", "test-name", "test-namespace"}} sc.set(scMap) - scMap = sc.getAllSandboxes() + scMap = sc.getSandboxes() assert.Equal(1, len(scMap)) // put new item id := "new-id" - b := sc.putIfNotExists(id, true) + b := sc.putIfNotExists(id, sandboxKubeData{}) assert.Equal(true, b) assert.Equal(2, len(scMap)) // put key that alreay exists - b = sc.putIfNotExists(id, true) + b = sc.putIfNotExists(id, sandboxKubeData{}) assert.Equal(false, b) b = sc.deleteIfExists(id) From 834e199eee19c430f519417677dfc7f5f99dc7e7 Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Tue, 25 Jan 2022 11:13:44 +0100 Subject: [PATCH 04/47] kata-monitor: drop unused functions Drop the functions we are not using anymore. Update the tests too. Signed-off-by: Francesco Giudici --- src/runtime/pkg/kata-monitor/sandbox_cache.go | 12 ------------ .../pkg/kata-monitor/sandbox_cache_test.go | 15 +++++---------- src/runtime/pkg/kata-monitor/shim_client.go | 9 --------- 3 files changed, 5 insertions(+), 31 deletions(-) diff --git a/src/runtime/pkg/kata-monitor/sandbox_cache.go b/src/runtime/pkg/kata-monitor/sandbox_cache.go index f4f542b41..4e3e77845 100644 --- a/src/runtime/pkg/kata-monitor/sandbox_cache.go +++ b/src/runtime/pkg/kata-monitor/sandbox_cache.go @@ -20,12 +20,6 @@ type sandboxCache struct { sandboxes map[string]sandboxKubeData } -func (sc *sandboxCache) getSandboxes() map[string]sandboxKubeData { - sc.Lock() - defer sc.Unlock() - return sc.sandboxes -} - func (sc *sandboxCache) getSandboxList() []string { sc.Lock() defer sc.Unlock() @@ -68,9 +62,3 @@ func (sc *sandboxCache) setMetadata(id string, value sandboxKubeData) { sc.sandboxes[id] = value } - -func (sc *sandboxCache) set(sandboxes map[string]sandboxKubeData) { - sc.Lock() - defer sc.Unlock() - sc.sandboxes = sandboxes -} diff --git a/src/runtime/pkg/kata-monitor/sandbox_cache_test.go b/src/runtime/pkg/kata-monitor/sandbox_cache_test.go index 6dd2e7894..4eedf778a 100644 --- a/src/runtime/pkg/kata-monitor/sandbox_cache_test.go +++ b/src/runtime/pkg/kata-monitor/sandbox_cache_test.go @@ -16,21 +16,16 @@ func TestSandboxCache(t *testing.T) { assert := assert.New(t) sc := &sandboxCache{ Mutex: &sync.Mutex{}, - sandboxes: make(map[string]sandboxKubeData), + sandboxes: map[string]sandboxKubeData{"111": {"1-2-3", "test-name", "test-namespace"}}, } - scMap := map[string]sandboxKubeData{"111": {"1-2-3", "test-name", "test-namespace"}} - - sc.set(scMap) - - scMap = sc.getSandboxes() - assert.Equal(1, len(scMap)) + assert.Equal(1, len(sc.getSandboxList())) // put new item id := "new-id" b := sc.putIfNotExists(id, sandboxKubeData{}) assert.Equal(true, b) - assert.Equal(2, len(scMap)) + assert.Equal(2, len(sc.getSandboxList())) // put key that alreay exists b = sc.putIfNotExists(id, sandboxKubeData{}) @@ -38,9 +33,9 @@ func TestSandboxCache(t *testing.T) { b = sc.deleteIfExists(id) assert.Equal(true, b) - assert.Equal(1, len(scMap)) + assert.Equal(1, len(sc.getSandboxList())) b = sc.deleteIfExists(id) assert.Equal(false, b) - assert.Equal(1, len(scMap)) + assert.Equal(1, len(sc.getSandboxList())) } diff --git a/src/runtime/pkg/kata-monitor/shim_client.go b/src/runtime/pkg/kata-monitor/shim_client.go index 31043c847..bdb62d401 100644 --- a/src/runtime/pkg/kata-monitor/shim_client.go +++ b/src/runtime/pkg/kata-monitor/shim_client.go @@ -10,8 +10,6 @@ import ( "io" "net" "net/http" - "os" - "path/filepath" "time" cdshim "github.com/containerd/containerd/runtime/v2/shim" @@ -43,13 +41,6 @@ func getSandboxFS() string { return shim.GetSandboxesStoragePath() } -func checkSandboxFSExists(sandboxID string) bool { - sbsPath := filepath.Join(string(filepath.Separator), getSandboxFS(), sandboxID) - _, err := os.Stat(sbsPath) - - return !os.IsNotExist(err) -} - // BuildShimClient builds and returns an http client for communicating with the provided sandbox func BuildShimClient(sandboxID string, timeout time.Duration) (*http.Client, error) { return buildUnixSocketClient(shim.SocketAddress(sandboxID), timeout) From ab447285badb68ecda94afe4a306fd188d292e0b Mon Sep 17 00:00:00 2001 From: Francesco Giudici Date: Tue, 25 Jan 2022 13:42:39 +0100 Subject: [PATCH 05/47] kata-monitor: add kubernetes pod metadata labels to metrics Add the POD metadata we get from the container manager to the metrics by adding more labels. Fixes: #3551 Signed-off-by: Francesco Giudici --- src/runtime/pkg/kata-monitor/metrics.go | 38 ++++++++++++++----- src/runtime/pkg/kata-monitor/metrics_test.go | 12 +++++- src/runtime/pkg/kata-monitor/sandbox_cache.go | 8 ++++ 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/runtime/pkg/kata-monitor/metrics.go b/src/runtime/pkg/kata-monitor/metrics.go index d2958441b..0216969cb 100644 --- a/src/runtime/pkg/kata-monitor/metrics.go +++ b/src/runtime/pkg/kata-monitor/metrics.go @@ -160,9 +160,13 @@ func (km *KataMonitor) aggregateSandboxMetrics(encoder expfmt.Encoder) error { // get metrics from sandbox's shim for _, sandboxID := range sandboxes { + sandboxMetadata, ok := km.sandboxCache.getMetadata(sandboxID) + if !ok { // likely the sandbox has been just removed + continue + } wg.Add(1) - go func(sandboxID string, results chan<- []*dto.MetricFamily) { - sandboxMetrics, err := getParsedMetrics(sandboxID) + go func(sandboxID string, sandboxMetadata sandboxKubeData, results chan<- []*dto.MetricFamily) { + sandboxMetrics, err := getParsedMetrics(sandboxID, sandboxMetadata) if err != nil { monitorLog.WithError(err).WithField("sandbox_id", sandboxID).Errorf("failed to get metrics for sandbox") } @@ -170,7 +174,7 @@ func (km *KataMonitor) aggregateSandboxMetrics(encoder expfmt.Encoder) error { results <- sandboxMetrics wg.Done() monitorLog.WithField("sandbox_id", sandboxID).Debug("job finished") - }(sandboxID, results) + }(sandboxID, sandboxMetadata, results) monitorLog.WithField("sandbox_id", sandboxID).Debug("job started") } @@ -219,13 +223,13 @@ func (km *KataMonitor) aggregateSandboxMetrics(encoder expfmt.Encoder) error { } -func getParsedMetrics(sandboxID string) ([]*dto.MetricFamily, error) { +func getParsedMetrics(sandboxID string, sandboxMetadata sandboxKubeData) ([]*dto.MetricFamily, error) { body, err := doGet(sandboxID, defaultTimeout, "metrics") if err != nil { return nil, err } - return parsePrometheusMetrics(sandboxID, body) + return parsePrometheusMetrics(sandboxID, sandboxMetadata, body) } // GetSandboxMetrics will get sandbox's metrics from shim @@ -240,7 +244,7 @@ func GetSandboxMetrics(sandboxID string) (string, error) { // parsePrometheusMetrics will decode metrics from Prometheus text format // and return array of *dto.MetricFamily with an ASC order -func parsePrometheusMetrics(sandboxID string, body []byte) ([]*dto.MetricFamily, error) { +func parsePrometheusMetrics(sandboxID string, sandboxMetadata sandboxKubeData, body []byte) ([]*dto.MetricFamily, error) { reader := bytes.NewReader(body) decoder := expfmt.NewDecoder(reader, expfmt.FmtText) @@ -258,10 +262,24 @@ func parsePrometheusMetrics(sandboxID string, body []byte) ([]*dto.MetricFamily, metricList := mf.Metric for j := range metricList { metric := metricList[j] - metric.Label = append(metric.Label, &dto.LabelPair{ - Name: mutils.String2Pointer("sandbox_id"), - Value: mutils.String2Pointer(sandboxID), - }) + metric.Label = append(metric.Label, + &dto.LabelPair{ + Name: mutils.String2Pointer("sandbox_id"), + Value: mutils.String2Pointer(sandboxID), + }, + &dto.LabelPair{ + Name: mutils.String2Pointer("kube_uid"), + Value: mutils.String2Pointer(sandboxMetadata.uid), + }, + &dto.LabelPair{ + Name: mutils.String2Pointer("kube_name"), + Value: mutils.String2Pointer(sandboxMetadata.name), + }, + &dto.LabelPair{ + Name: mutils.String2Pointer("kube_namespace"), + Value: mutils.String2Pointer(sandboxMetadata.namespace), + }, + ) } // Kata shim are using prometheus go client, add a prefix for metric name to avoid confusing diff --git a/src/runtime/pkg/kata-monitor/metrics_test.go b/src/runtime/pkg/kata-monitor/metrics_test.go index 5263d2a93..1055a6d36 100644 --- a/src/runtime/pkg/kata-monitor/metrics_test.go +++ b/src/runtime/pkg/kata-monitor/metrics_test.go @@ -40,9 +40,10 @@ ttt 999 func TestParsePrometheusMetrics(t *testing.T) { assert := assert.New(t) sandboxID := "sandboxID-abc" + sandboxMetadata := sandboxKubeData{"123", "pod-name", "pod-namespace"} // parse metrics - list, err := parsePrometheusMetrics(sandboxID, []byte(shimMetricBody)) + list, err := parsePrometheusMetrics(sandboxID, sandboxMetadata, []byte(shimMetricBody)) assert.Nil(err, "parsePrometheusMetrics should not return error") assert.Equal(4, len(list), "should return 3 metric families") @@ -56,9 +57,16 @@ func TestParsePrometheusMetrics(t *testing.T) { // get the metric m := mf.Metric[0] - assert.Equal(1, len(m.Label), "should have only 1 labels") + assert.Equal(4, len(m.Label), "should have 4 labels") assert.Equal("sandbox_id", *m.Label[0].Name, "label name should be sandbox_id") assert.Equal(sandboxID, *m.Label[0].Value, "label value should be", sandboxID) + assert.Equal("kube_uid", *m.Label[1].Name, "label name should be kube_uid") + assert.Equal(sandboxMetadata.uid, *m.Label[1].Value, "label value should be", sandboxMetadata.uid) + + assert.Equal("kube_name", *m.Label[2].Name, "label name should be kube_name") + assert.Equal(sandboxMetadata.name, *m.Label[2].Value, "label value should be", sandboxMetadata.name) + assert.Equal("kube_namespace", *m.Label[3].Name, "label name should be kube_namespace") + assert.Equal(sandboxMetadata.namespace, *m.Label[3].Value, "label value should be", sandboxMetadata.namespace) summary := m.Summary assert.NotNil(summary, "summary should not be nil") diff --git a/src/runtime/pkg/kata-monitor/sandbox_cache.go b/src/runtime/pkg/kata-monitor/sandbox_cache.go index 4e3e77845..ba98a121f 100644 --- a/src/runtime/pkg/kata-monitor/sandbox_cache.go +++ b/src/runtime/pkg/kata-monitor/sandbox_cache.go @@ -62,3 +62,11 @@ func (sc *sandboxCache) setMetadata(id string, value sandboxKubeData) { sc.sandboxes[id] = value } + +func (sc *sandboxCache) getMetadata(id string) (sandboxKubeData, bool) { + sc.Lock() + defer sc.Unlock() + + metadata, ok := sc.sandboxes[id] + return metadata, ok +} From c1ce67d9050b1a36f88c8349cd9e54dce329f6c5 Mon Sep 17 00:00:00 2001 From: Matt Layher Date: Fri, 4 Feb 2022 20:06:12 -0500 Subject: [PATCH 06/47] runtime: use github.com/mdlayher/vsock@v1.1.0 Fixes #3625 Signed-off-by: Matt Layher --- src/runtime/go.mod | 6 +- src/runtime/go.sum | 24 +- .../github.com/mdlayher/socket/CHANGELOG.md | 36 + .../github.com/mdlayher/socket/LICENSE.md | 9 + .../github.com/mdlayher/socket/README.md | 14 + .../github.com/mdlayher/socket/accept.go | 23 + .../github.com/mdlayher/socket/accept4.go | 15 + .../vendor/github.com/mdlayher/socket/conn.go | 675 ++++++++ .../github.com/mdlayher/socket/conn_linux.go | 88 + .../vendor/github.com/mdlayher/socket/doc.go | 13 + .../vendor/github.com/mdlayher/socket/go.mod | 10 + .../vendor/github.com/mdlayher/socket/go.sum | 13 + .../github.com/mdlayher/socket/netns_linux.go | 150 ++ .../mdlayher/socket/netns_others.go | 14 + .../mdlayher/socket/setbuffer_linux.go | 24 + .../mdlayher/socket/setbuffer_others.go | 16 + .../mdlayher/socket/typ_cloexec_nonblock.go | 12 + .../github.com/mdlayher/socket/typ_none.go | 11 + .../github.com/mdlayher/vsock/CHANGELOG.md | 35 + .../github.com/mdlayher/vsock/LICENSE.md | 5 +- .../github.com/mdlayher/vsock/README.md | 39 +- .../github.com/mdlayher/vsock/conn_linux.go | 83 +- .../vendor/github.com/mdlayher/vsock/doc.go | 50 - .../github.com/mdlayher/vsock/fd_linux.go | 189 --- .../mdlayher/vsock/fd_linux_1.10.go | 63 - .../mdlayher/vsock/fd_linux_1.11.go | 76 - .../mdlayher/vsock/fd_linux_gteq_1.12.go | 112 -- .../vendor/github.com/mdlayher/vsock/go.mod | 7 +- .../vendor/github.com/mdlayher/vsock/go.sum | 23 +- .../mdlayher/vsock/listener_linux.go | 109 +- .../vendor/github.com/mdlayher/vsock/vsock.go | 154 +- .../github.com/mdlayher/vsock/vsock_others.go | 31 +- .../vendor/golang.org/x/net/bpf/asm.go | 41 + .../vendor/golang.org/x/net/bpf/constants.go | 222 +++ .../vendor/golang.org/x/net/bpf/doc.go | 82 + .../golang.org/x/net/bpf/instructions.go | 726 ++++++++ .../vendor/golang.org/x/net/bpf/setter.go | 10 + src/runtime/vendor/golang.org/x/net/bpf/vm.go | 150 ++ .../golang.org/x/net/bpf/vm_instructions.go | 182 ++ .../x/net/http2/client_conn_pool.go | 47 +- .../vendor/golang.org/x/net/http2/errors.go | 12 + .../vendor/golang.org/x/net/http2/frame.go | 62 +- .../golang.org/x/net/http2/hpack/huffman.go | 38 +- .../vendor/golang.org/x/net/http2/pipe.go | 11 + .../vendor/golang.org/x/net/http2/server.go | 111 +- .../golang.org/x/net/http2/transport.go | 1480 ++++++++++------- .../golang.org/x/net/http2/writesched.go | 4 +- .../x/net/http2/writesched_random.go | 6 +- .../vendor/golang.org/x/net/idna/go118.go | 14 + .../golang.org/x/net/idna/idna10.0.0.go | 6 +- .../vendor/golang.org/x/net/idna/idna9.0.0.go | 4 +- .../vendor/golang.org/x/net/idna/pre_go118.go | 12 + .../vendor/golang.org/x/net/idna/punycode.go | 36 +- .../vendor/golang.org/x/sys/unix/README.md | 2 +- .../vendor/golang.org/x/sys/unix/mkall.sh | 2 +- .../vendor/golang.org/x/sys/unix/mkerrors.sh | 5 +- .../golang.org/x/sys/unix/sockcmsg_linux.go | 8 +- .../golang.org/x/sys/unix/syscall_aix.go | 28 +- .../golang.org/x/sys/unix/syscall_bsd.go | 24 +- .../golang.org/x/sys/unix/syscall_darwin.go | 27 +- .../x/sys/unix/syscall_dragonfly.go | 10 +- .../golang.org/x/sys/unix/syscall_freebsd.go | 6 +- .../golang.org/x/sys/unix/syscall_linux.go | 58 +- .../golang.org/x/sys/unix/syscall_netbsd.go | 14 +- .../golang.org/x/sys/unix/syscall_openbsd.go | 6 +- .../golang.org/x/sys/unix/syscall_solaris.go | 28 +- .../x/sys/unix/syscall_zos_s390x.go | 22 +- .../golang.org/x/sys/unix/zerrors_linux.go | 73 +- .../x/sys/unix/zerrors_linux_386.go | 6 +- .../x/sys/unix/zerrors_linux_amd64.go | 6 +- .../x/sys/unix/zerrors_linux_arm.go | 6 +- .../x/sys/unix/zerrors_linux_arm64.go | 6 +- .../x/sys/unix/zerrors_linux_mips.go | 6 +- .../x/sys/unix/zerrors_linux_mips64.go | 6 +- .../x/sys/unix/zerrors_linux_mips64le.go | 6 +- .../x/sys/unix/zerrors_linux_mipsle.go | 6 +- .../x/sys/unix/zerrors_linux_ppc.go | 6 +- .../x/sys/unix/zerrors_linux_ppc64.go | 6 +- .../x/sys/unix/zerrors_linux_ppc64le.go | 6 +- .../x/sys/unix/zerrors_linux_riscv64.go | 6 +- .../x/sys/unix/zerrors_linux_s390x.go | 6 +- .../x/sys/unix/zerrors_linux_sparc64.go | 6 +- .../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 22 +- .../x/sys/unix/zsyscall_aix_ppc64.go | 20 +- .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 20 +- .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 18 +- .../golang.org/x/sys/unix/zsyscall_linux.go | 17 +- .../x/sys/unix/zsyscall_netbsd_386.go | 12 - .../x/sys/unix/zsyscall_netbsd_amd64.go | 12 - .../x/sys/unix/zsyscall_netbsd_arm.go | 12 - .../x/sys/unix/zsyscall_netbsd_arm64.go | 12 - .../x/sys/unix/zsysnum_linux_386.go | 2 + .../x/sys/unix/zsysnum_linux_amd64.go | 2 + .../x/sys/unix/zsysnum_linux_arm.go | 3 + .../x/sys/unix/zsysnum_linux_arm64.go | 2 + .../x/sys/unix/zsysnum_linux_mips.go | 2 + .../x/sys/unix/zsysnum_linux_mips64.go | 2 + .../x/sys/unix/zsysnum_linux_mips64le.go | 2 + .../x/sys/unix/zsysnum_linux_mipsle.go | 2 + .../x/sys/unix/zsysnum_linux_ppc.go | 2 + .../x/sys/unix/zsysnum_linux_ppc64.go | 2 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 2 + .../x/sys/unix/zsysnum_linux_riscv64.go | 2 + .../x/sys/unix/zsysnum_linux_s390x.go | 2 + .../x/sys/unix/zsysnum_linux_sparc64.go | 2 + .../x/sys/unix/ztypes_darwin_amd64.go | 6 +- .../x/sys/unix/ztypes_darwin_arm64.go | 6 +- .../golang.org/x/sys/unix/ztypes_linux.go | 125 +- .../golang.org/x/sys/unix/ztypes_linux_386.go | 2 +- .../x/sys/unix/ztypes_linux_amd64.go | 2 +- .../golang.org/x/sys/unix/ztypes_linux_arm.go | 2 +- .../x/sys/unix/ztypes_linux_arm64.go | 2 +- .../x/sys/unix/ztypes_linux_mips.go | 2 +- .../x/sys/unix/ztypes_linux_mips64.go | 2 +- .../x/sys/unix/ztypes_linux_mips64le.go | 2 +- .../x/sys/unix/ztypes_linux_mipsle.go | 2 +- .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 2 +- .../x/sys/unix/ztypes_linux_ppc64.go | 2 +- .../x/sys/unix/ztypes_linux_ppc64le.go | 2 +- .../x/sys/unix/ztypes_linux_riscv64.go | 2 +- .../x/sys/unix/ztypes_linux_s390x.go | 2 +- .../x/sys/unix/ztypes_linux_sparc64.go | 2 +- .../x/sys/unix/ztypes_openbsd_386.go | 11 +- .../x/sys/unix/ztypes_openbsd_amd64.go | 11 +- .../x/sys/unix/ztypes_openbsd_arm.go | 11 +- .../x/sys/unix/ztypes_openbsd_arm64.go | 11 +- .../x/sys/unix/ztypes_openbsd_mips64.go | 11 +- .../golang.org/x/sys/windows/exec_windows.go | 37 +- .../golang.org/x/sys/windows/mksyscall.go | 2 +- .../golang.org/x/sys/windows/registry/key.go | 9 + .../x/sys/windows/registry/mksyscall.go | 1 + .../x/sys/windows/registry/syscall.go | 1 + .../x/sys/windows/registry/value.go | 1 + .../golang.org/x/sys/windows/service.go | 12 +- .../x/sys/windows/setupapi_windows.go | 1425 ++++++++++++++++ .../x/sys/windows/setupapierrors_windows.go | 100 -- .../x/sys/windows/syscall_windows.go | 21 +- .../golang.org/x/sys/windows/types_windows.go | 60 +- .../x/sys/windows/zsyscall_windows.go | 358 +++- src/runtime/vendor/modules.txt | 11 +- .../pkg/agent/protocols/client/client.go | 2 +- 141 files changed, 6339 insertions(+), 1877 deletions(-) create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/CHANGELOG.md create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/LICENSE.md create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/README.md create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/accept.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/accept4.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/conn.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/conn_linux.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/doc.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/go.mod create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/go.sum create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/netns_linux.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/netns_others.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/setbuffer_linux.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/setbuffer_others.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go create mode 100644 src/runtime/vendor/github.com/mdlayher/socket/typ_none.go create mode 100644 src/runtime/vendor/github.com/mdlayher/vsock/CHANGELOG.md delete mode 100644 src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_1.10.go delete mode 100644 src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_1.11.go delete mode 100644 src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_gteq_1.12.go create mode 100644 src/runtime/vendor/golang.org/x/net/bpf/asm.go create mode 100644 src/runtime/vendor/golang.org/x/net/bpf/constants.go create mode 100644 src/runtime/vendor/golang.org/x/net/bpf/doc.go create mode 100644 src/runtime/vendor/golang.org/x/net/bpf/instructions.go create mode 100644 src/runtime/vendor/golang.org/x/net/bpf/setter.go create mode 100644 src/runtime/vendor/golang.org/x/net/bpf/vm.go create mode 100644 src/runtime/vendor/golang.org/x/net/bpf/vm_instructions.go create mode 100644 src/runtime/vendor/golang.org/x/net/idna/go118.go create mode 100644 src/runtime/vendor/golang.org/x/net/idna/pre_go118.go create mode 100644 src/runtime/vendor/golang.org/x/sys/windows/setupapi_windows.go delete mode 100644 src/runtime/vendor/golang.org/x/sys/windows/setupapierrors_windows.go diff --git a/src/runtime/go.mod b/src/runtime/go.mod index 07d393227..296cae4ea 100644 --- a/src/runtime/go.mod +++ b/src/runtime/go.mod @@ -28,7 +28,7 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/hashicorp/go-multierror v1.0.0 github.com/intel-go/cpuid v0.0.0-20210602155658-5747e5cec0d9 - github.com/mdlayher/vsock v0.0.0-20191108225356-d9c65923cb8f + github.com/mdlayher/vsock v1.1.0 github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/runc v1.0.3 github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 @@ -49,9 +49,9 @@ require ( go.opentelemetry.io/otel/exporters/jaeger v1.0.0 go.opentelemetry.io/otel/sdk v1.0.1 go.opentelemetry.io/otel/trace v1.0.1 - golang.org/x/net v0.0.0-20210825183410-e898025ed96a + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93 - golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 + golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a google.golang.org/appengine v1.6.7 // indirect google.golang.org/grpc v1.41.0 k8s.io/apimachinery v0.22.0 diff --git a/src/runtime/go.sum b/src/runtime/go.sum index 3bc3ba026..3417ff96a 100644 --- a/src/runtime/go.sum +++ b/src/runtime/go.sum @@ -479,8 +479,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= @@ -617,8 +618,10 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5 github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= -github.com/mdlayher/vsock v0.0.0-20191108225356-d9c65923cb8f h1:t9bhAC/9+wqdIb49Jamux+Sxqa7MhkyuTtsHkmVg6tk= -github.com/mdlayher/vsock v0.0.0-20191108225356-d9c65923cb8f/go.mod h1:4GtNxrXX+cNil8xnCdz0zGYemDZDDHSsXbopCRZrRRw= +github.com/mdlayher/socket v0.2.0 h1:EY4YQd6hTAg2tcXF84p5DTHazShE50u5HeBzBaNgjkA= +github.com/mdlayher/socket v0.2.0/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= +github.com/mdlayher/vsock v1.1.0 h1:2k9udP/hUkLUOboGxXMHOk4f0GWWZwS3IuE3Ee/YYfk= +github.com/mdlayher/vsock v1.1.0/go.mod h1:nsVhPsVuBBwAKh6i6PzdNoke6/TNYTjkxoRKAp/+pXs= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= @@ -988,7 +991,6 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1014,8 +1016,9 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw= golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1066,7 +1069,6 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1116,22 +1118,28 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/src/runtime/vendor/github.com/mdlayher/socket/CHANGELOG.md b/src/runtime/vendor/github.com/mdlayher/socket/CHANGELOG.md new file mode 100644 index 000000000..d16ae090b --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/CHANGELOG.md @@ -0,0 +1,36 @@ +# CHANGELOG + +## v0.2.0 + +- [New API] [commit](https://github.com/mdlayher/socket/commit/6e912a68523c45e5fd899239f4b46c402dd856da): + `socket.FileConn` can be used to create a `socket.Conn` from an existing + `os.File`, which may be provided by systemd socket activation or another + external mechanism. +- [API change] [commit](https://github.com/mdlayher/socket/commit/66d61f565188c23fe02b24099ddc856d538bf1a7): + `socket.Conn.Connect` now returns the `unix.Sockaddr` value provided by + `getpeername(2)`, since we have to invoke that system call anyway to verify + that a connection to a remote peer was successfully established. +- [Bug Fix] [commit](https://github.com/mdlayher/socket/commit/b60b2dbe0ac3caff2338446a150083bde8c5c19c): + check the correct error from `unix.GetsockoptInt` in the `socket.Conn.Connect` + method. Thanks @vcabbage! + +## v0.1.2 + +- [Bug Fix]: `socket.Conn.Connect` now properly checks the `SO_ERROR` socket + option value after calling `connect(2)` to verify whether or not a connection + could successfully be established. This means that `Connect` should now report + an error for an `AF_INET` TCP connection refused or `AF_VSOCK` connection + reset by peer. +- [New API]: add `socket.Conn.Getpeername` for use in `Connect`, but also for + use by external callers. + +## v0.1.1 + +- [New API]: `socket.Conn` now has `CloseRead`, `CloseWrite`, and `Shutdown` + methods. +- [Improvement]: internal rework to more robustly handle various errors. + +## v0.1.0 + +- Initial unstable release. Most functionality has been developed and ported +from package [`netlink`](https://github.com/mdlayher/netlink). diff --git a/src/runtime/vendor/github.com/mdlayher/socket/LICENSE.md b/src/runtime/vendor/github.com/mdlayher/socket/LICENSE.md new file mode 100644 index 000000000..3ccdb75b2 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/LICENSE.md @@ -0,0 +1,9 @@ +# MIT License + +Copyright (C) 2021 Matt Layher + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/runtime/vendor/github.com/mdlayher/socket/README.md b/src/runtime/vendor/github.com/mdlayher/socket/README.md new file mode 100644 index 000000000..97ddcd617 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/README.md @@ -0,0 +1,14 @@ +# socket [![Test Status](https://github.com/mdlayher/socket/workflows/Test/badge.svg)](https://github.com/mdlayher/socket/actions) [![Go Reference](https://pkg.go.dev/badge/github.com/mdlayher/socket.svg)](https://pkg.go.dev/github.com/mdlayher/socket) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/socket)](https://goreportcard.com/report/github.com/mdlayher/socket) + +Package `socket` provides a low-level network connection type which integrates +with Go's runtime network poller to provide asynchronous I/O and deadline +support. MIT Licensed. + +This package focuses on UNIX-like operating systems which make use of BSD +sockets system call APIs. It is meant to be used as a foundation for the +creation of operating system-specific socket packages, for socket families such +as Linux's `AF_NETLINK`, `AF_PACKET`, or `AF_VSOCK`. This package should not be +used directly in end user applications. + +Any use of package socket should be guarded by build tags, as one would also +use when importing the `syscall` or `golang.org/x/sys` packages. diff --git a/src/runtime/vendor/github.com/mdlayher/socket/accept.go b/src/runtime/vendor/github.com/mdlayher/socket/accept.go new file mode 100644 index 000000000..47e9d897e --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/accept.go @@ -0,0 +1,23 @@ +//go:build !dragonfly && !freebsd && !illumos && !linux +// +build !dragonfly,!freebsd,!illumos,!linux + +package socket + +import ( + "fmt" + "runtime" + + "golang.org/x/sys/unix" +) + +const sysAccept = "accept" + +// accept wraps accept(2). +func accept(fd, flags int) (int, unix.Sockaddr, error) { + if flags != 0 { + // These operating systems have no support for flags to accept(2). + return 0, nil, fmt.Errorf("socket: Conn.Accept flags are ineffective on %s", runtime.GOOS) + } + + return unix.Accept(fd) +} diff --git a/src/runtime/vendor/github.com/mdlayher/socket/accept4.go b/src/runtime/vendor/github.com/mdlayher/socket/accept4.go new file mode 100644 index 000000000..e1016b206 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/accept4.go @@ -0,0 +1,15 @@ +//go:build dragonfly || freebsd || illumos || linux +// +build dragonfly freebsd illumos linux + +package socket + +import ( + "golang.org/x/sys/unix" +) + +const sysAccept = "accept4" + +// accept wraps accept4(2). +func accept(fd, flags int) (int, unix.Sockaddr, error) { + return unix.Accept4(fd, flags) +} diff --git a/src/runtime/vendor/github.com/mdlayher/socket/conn.go b/src/runtime/vendor/github.com/mdlayher/socket/conn.go new file mode 100644 index 000000000..d5ddcbf4a --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/conn.go @@ -0,0 +1,675 @@ +package socket + +import ( + "os" + "sync/atomic" + "syscall" + "time" + + "golang.org/x/sys/unix" +) + +// A Conn is a low-level network connection which integrates with Go's runtime +// network poller to provide asynchronous I/O and deadline support. +type Conn struct { + // Indicates whether or not Conn.Close has been called. Must be accessed + // atomically. Atomics definitions must come first in the Conn struct. + closed uint32 + + // A unique name for the Conn which is also associated with derived file + // descriptors such as those created by accept(2). + name string + + // Provides access to the underlying file registered with the runtime + // network poller, and arbitrary raw I/O calls. + fd *os.File + rc syscall.RawConn +} + +// A Config contains options for a Conn. +type Config struct { + // NetNS specifies the Linux network namespace the Conn will operate in. + // This option is unsupported on other operating systems. + // + // If set (non-zero), Conn will enter the specified network namespace and an + // error will occur in Socket if the operation fails. + // + // If not set (zero), a best-effort attempt will be made to enter the + // network namespace of the calling thread: this means that any changes made + // to the calling thread's network namespace will also be reflected in Conn. + // If this operation fails (due to lack of permissions or because network + // namespaces are disabled by kernel configuration), Socket will not return + // an error, and the Conn will operate in the default network namespace of + // the process. This enables non-privileged use of Conn in applications + // which do not require elevated privileges. + // + // Entering a network namespace is a privileged operation (root or + // CAP_SYS_ADMIN are required), and most applications should leave this set + // to 0. + NetNS int +} + +// High-level methods which provide convenience over raw system calls. + +// Close closes the underlying file descriptor for the Conn, which also causes +// all in-flight I/O operations to immediately unblock and return errors. Any +// subsequent uses of Conn will result in EBADF. +func (c *Conn) Close() error { + // The caller has expressed an intent to close the socket, so immediately + // increment s.closed to force further calls to result in EBADF before also + // closing the file descriptor to unblock any outstanding operations. + // + // Because other operations simply check for s.closed != 0, we will permit + // double Close, which would increment s.closed beyond 1. + if atomic.AddUint32(&c.closed, 1) != 1 { + // Multiple Close calls. + return nil + } + + return os.NewSyscallError("close", c.fd.Close()) +} + +// CloseRead shuts down the reading side of the Conn. Most callers should just +// use Close. +func (c *Conn) CloseRead() error { return c.Shutdown(unix.SHUT_RD) } + +// CloseWrite shuts down the writing side of the Conn. Most callers should just +// use Close. +func (c *Conn) CloseWrite() error { return c.Shutdown(unix.SHUT_WR) } + +// Read implements io.Reader by reading directly from the underlying file +// descriptor. +func (c *Conn) Read(b []byte) (int, error) { return c.fd.Read(b) } + +// Write implements io.Writer by writing directly to the underlying file +// descriptor. +func (c *Conn) Write(b []byte) (int, error) { return c.fd.Write(b) } + +// SetDeadline sets both the read and write deadlines associated with the Conn. +func (c *Conn) SetDeadline(t time.Time) error { return c.fd.SetDeadline(t) } + +// SetReadDeadline sets the read deadline associated with the Conn. +func (c *Conn) SetReadDeadline(t time.Time) error { return c.fd.SetReadDeadline(t) } + +// SetWriteDeadline sets the write deadline associated with the Conn. +func (c *Conn) SetWriteDeadline(t time.Time) error { return c.fd.SetWriteDeadline(t) } + +// ReadBuffer gets the size of the operating system's receive buffer associated +// with the Conn. +func (c *Conn) ReadBuffer() (int, error) { + return c.GetsockoptInt(unix.SOL_SOCKET, unix.SO_RCVBUF) +} + +// WriteBuffer gets the size of the operating system's transmit buffer +// associated with the Conn. +func (c *Conn) WriteBuffer() (int, error) { + return c.GetsockoptInt(unix.SOL_SOCKET, unix.SO_SNDBUF) +} + +// SetReadBuffer sets the size of the operating system's receive buffer +// associated with the Conn. +// +// When called with elevated privileges on Linux, the SO_RCVBUFFORCE option will +// be used to override operating system limits. Otherwise SO_RCVBUF is used +// (which obeys operating system limits). +func (c *Conn) SetReadBuffer(bytes int) error { return c.setReadBuffer(bytes) } + +// SetWriteBuffer sets the size of the operating system's transmit buffer +// associated with the Conn. +// +// When called with elevated privileges on Linux, the SO_SNDBUFFORCE option will +// be used to override operating system limits. Otherwise SO_SNDBUF is used +// (which obeys operating system limits). +func (c *Conn) SetWriteBuffer(bytes int) error { return c.setWriteBuffer(bytes) } + +// SyscallConn returns a raw network connection. This implements the +// syscall.Conn interface. +// +// SyscallConn is intended for advanced use cases, such as getting and setting +// arbitrary socket options using the socket's file descriptor. If possible, +// those operations should be performed using methods on Conn instead. +// +// Once invoked, it is the caller's responsibility to ensure that operations +// performed using Conn and the syscall.RawConn do not conflict with each other. +func (c *Conn) SyscallConn() (syscall.RawConn, error) { + if atomic.LoadUint32(&c.closed) != 0 { + return nil, os.NewSyscallError("syscallconn", unix.EBADF) + } + + // TODO(mdlayher): mutex or similar to enforce syscall.RawConn contract of + // FD remaining valid for duration of calls? + return c.rc, nil +} + +// Socket wraps the socket(2) system call to produce a Conn. domain, typ, and +// proto are passed directly to socket(2), and name should be a unique name for +// the socket type such as "netlink" or "vsock". +// +// The cfg parameter specifies optional configuration for the Conn. If nil, no +// additional configuration will be applied. +// +// If the operating system supports SOCK_CLOEXEC and SOCK_NONBLOCK, they are +// automatically applied to typ to mirror the standard library's socket flag +// behaviors. +func Socket(domain, typ, proto int, name string, cfg *Config) (*Conn, error) { + if cfg == nil { + cfg = &Config{} + } + + if cfg.NetNS == 0 { + // Non-Linux or no network namespace. + return socket(domain, typ, proto, name) + } + + // Linux only: create Conn in the specified network namespace. + return withNetNS(cfg.NetNS, func() (*Conn, error) { + return socket(domain, typ, proto, name) + }) +} + +// socket is the internal, cross-platform entry point for socket(2). +func socket(domain, typ, proto int, name string) (*Conn, error) { + var ( + fd int + err error + ) + + for { + fd, err = unix.Socket(domain, typ|socketFlags, proto) + switch { + case err == nil: + // Some OSes already set CLOEXEC with typ. + if !flagCLOEXEC { + unix.CloseOnExec(fd) + } + + // No error, prepare the Conn. + return newConn(fd, name) + case !ready(err): + // System call interrupted or not ready, try again. + continue + case err == unix.EINVAL, err == unix.EPROTONOSUPPORT: + // On Linux, SOCK_NONBLOCK and SOCK_CLOEXEC were introduced in + // 2.6.27. On FreeBSD, both flags were introduced in FreeBSD 10. + // EINVAL and EPROTONOSUPPORT check for earlier versions of these + // OSes respectively. + // + // Mirror what the standard library does when creating file + // descriptors: avoid racing a fork/exec with the creation of new + // file descriptors, so that child processes do not inherit socket + // file descriptors unexpectedly. + // + // For a more thorough explanation, see similar work in the Go tree: + // func sysSocket in net/sock_cloexec.go, as well as the detailed + // comment in syscall/exec_unix.go. + syscall.ForkLock.RLock() + fd, err = unix.Socket(domain, typ, proto) + if err != nil { + syscall.ForkLock.RUnlock() + return nil, os.NewSyscallError("socket", err) + } + unix.CloseOnExec(fd) + syscall.ForkLock.RUnlock() + + return newConn(fd, name) + default: + // Unhandled error. + return nil, os.NewSyscallError("socket", err) + } + } +} + +// FileConn returns a copy of the network connection corresponding to the open +// file. It is the caller's responsibility to close the file when finished. +// Closing the Conn does not affect the File, and closing the File does not +// affect the Conn. +func FileConn(f *os.File, name string) (*Conn, error) { + // First we'll try to do fctnl(2) with F_DUPFD_CLOEXEC because we can dup + // the file descriptor and set the flag in one syscall. + fd, err := unix.FcntlInt(f.Fd(), unix.F_DUPFD_CLOEXEC, 0) + switch err { + case nil: + // OK, ready to set up non-blocking I/O. + return newConn(fd, name) + case unix.EINVAL: + // The kernel rejected our fcntl(2), fall back to separate dup(2) and + // setting close on exec. + // + // Mirror what the standard library does when creating file descriptors: + // avoid racing a fork/exec with the creation of new file descriptors, + // so that child processes do not inherit socket file descriptors + // unexpectedly. + syscall.ForkLock.RLock() + fd, err := unix.Dup(fd) + if err != nil { + syscall.ForkLock.RUnlock() + return nil, os.NewSyscallError("dup", err) + } + unix.CloseOnExec(fd) + syscall.ForkLock.RUnlock() + + return newConn(fd, name) + default: + // Any other errors. + return nil, os.NewSyscallError("fcntl", err) + } +} + +// TODO(mdlayher): consider exporting newConn as New? + +// newConn wraps an existing file descriptor to create a Conn. name should be a +// unique name for the socket type such as "netlink" or "vsock". +func newConn(fd int, name string) (*Conn, error) { + // All Conn I/O is nonblocking for integration with Go's runtime network + // poller. Depending on the OS this might already be set but it can't hurt + // to set it again. + if err := unix.SetNonblock(fd, true); err != nil { + return nil, os.NewSyscallError("setnonblock", err) + } + + // os.NewFile registers the non-blocking file descriptor with the runtime + // poller, which is then used for most subsequent operations except those + // that require raw I/O via SyscallConn. + // + // See also: https://golang.org/pkg/os/#NewFile + f := os.NewFile(uintptr(fd), name) + rc, err := f.SyscallConn() + if err != nil { + return nil, err + } + + return &Conn{ + name: name, + fd: f, + rc: rc, + }, nil +} + +// Low-level methods which provide raw system call access. + +// Accept wraps accept(2) or accept4(2) depending on the operating system, but +// returns a Conn for the accepted connection rather than a raw file descriptor. +// +// If the operating system supports accept4(2) (which allows flags), +// SOCK_CLOEXEC and SOCK_NONBLOCK are automatically applied to flags to mirror +// the standard library's socket flag behaviors. +// +// If the operating system only supports accept(2) (which does not allow flags) +// and flags is not zero, an error will be returned. +func (c *Conn) Accept(flags int) (*Conn, unix.Sockaddr, error) { + var ( + nfd int + sa unix.Sockaddr + err error + ) + + doErr := c.read(sysAccept, func(fd int) error { + // Either accept(2) or accept4(2) depending on the OS. + nfd, sa, err = accept(fd, flags|socketFlags) + return err + }) + if doErr != nil { + return nil, nil, doErr + } + if err != nil { + // sysAccept is either "accept" or "accept4" depending on the OS. + return nil, nil, os.NewSyscallError(sysAccept, err) + } + + // Successfully accepted a connection, wrap it in a Conn for use by the + // caller. + ac, err := newConn(nfd, c.name) + if err != nil { + return nil, nil, err + } + + return ac, sa, nil +} + +// Bind wraps bind(2). +func (c *Conn) Bind(sa unix.Sockaddr) error { + const op = "bind" + + var err error + doErr := c.control(op, func(fd int) error { + err = unix.Bind(fd, sa) + return err + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) +} + +// Connect wraps connect(2). In order to verify that the underlying socket is +// connected to a remote peer, Connect calls getpeername(2) and returns the +// unix.Sockaddr from that call. +func (c *Conn) Connect(sa unix.Sockaddr) (unix.Sockaddr, error) { + const op = "connect" + + // TODO(mdlayher): it would seem that trying to connect to unbound vsock + // listeners by calling Connect multiple times results in ECONNRESET for the + // first and nil error for subsequent calls. Do we need to memoize the + // error? Check what the stdlib behavior is. + + var ( + // Track progress between invocations of the write closure. We don't + // have an explicit WaitWrite call like internal/poll does, so we have + // to wait until the runtime calls the closure again to indicate we can + // write. + progress uint32 + + // Capture closure sockaddr and error. + rsa unix.Sockaddr + err error + ) + + doErr := c.write(op, func(fd int) error { + if atomic.AddUint32(&progress, 1) == 1 { + // First call: initiate connect. + return unix.Connect(fd, sa) + } + + // Subsequent calls: the runtime network poller indicates fd is + // writable. Check for errno. + errno, gerr := c.GetsockoptInt(unix.SOL_SOCKET, unix.SO_ERROR) + if gerr != nil { + return gerr + } + if errno != 0 { + // Connection is still not ready or failed. If errno indicates + // the socket is not ready, we will wait for the next write + // event. Otherwise we propagate this errno back to the as a + // permanent error. + uerr := unix.Errno(errno) + err = uerr + return uerr + } + + // According to internal/poll, it's possible for the runtime network + // poller to spuriously wake us and return errno 0 for SO_ERROR. + // Make sure we are actually connected to a peer. + peer, err := c.Getpeername() + if err != nil { + // internal/poll unconditionally goes back to WaitWrite. + // Synthesize an error that will do the same for us. + return unix.EAGAIN + } + + // Connection complete. + rsa = peer + return nil + }) + if doErr != nil { + return nil, doErr + } + + if err == unix.EISCONN { + // TODO(mdlayher): is this block obsolete with the addition of the + // getsockopt SO_ERROR check above? + // + // EISCONN is reported if the socket is already established and should + // not be treated as an error. + // - Darwin reports this for at least TCP sockets + // - Linux reports this for at least AF_VSOCK sockets + return rsa, nil + } + + return rsa, os.NewSyscallError(op, err) +} + +// Getsockname wraps getsockname(2). +func (c *Conn) Getsockname() (unix.Sockaddr, error) { + const op = "getsockname" + + var ( + sa unix.Sockaddr + err error + ) + + doErr := c.control(op, func(fd int) error { + sa, err = unix.Getsockname(fd) + return err + }) + if doErr != nil { + return nil, doErr + } + + return sa, os.NewSyscallError(op, err) +} + +// Getpeername wraps getpeername(2). +func (c *Conn) Getpeername() (unix.Sockaddr, error) { + const op = "getpeername" + + var ( + sa unix.Sockaddr + err error + ) + + doErr := c.control(op, func(fd int) error { + sa, err = unix.Getpeername(fd) + return err + }) + if doErr != nil { + return nil, doErr + } + + return sa, os.NewSyscallError(op, err) +} + +// GetsockoptInt wraps getsockopt(2) for integer values. +func (c *Conn) GetsockoptInt(level, opt int) (int, error) { + const op = "getsockopt" + + var ( + value int + err error + ) + + doErr := c.control(op, func(fd int) error { + value, err = unix.GetsockoptInt(fd, level, opt) + return err + }) + if doErr != nil { + return 0, doErr + } + + return value, os.NewSyscallError(op, err) +} + +// Listen wraps listen(2). +func (c *Conn) Listen(n int) error { + const op = "listen" + + var err error + doErr := c.control(op, func(fd int) error { + err = unix.Listen(fd, n) + return err + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) +} + +// Recvmsg wraps recvmsg(2). +func (c *Conn) Recvmsg(p, oob []byte, flags int) (int, int, int, unix.Sockaddr, error) { + const op = "recvmsg" + + var ( + n, oobn, recvflags int + from unix.Sockaddr + err error + ) + + doErr := c.read(op, func(fd int) error { + n, oobn, recvflags, from, err = unix.Recvmsg(fd, p, oob, flags) + return err + }) + if doErr != nil { + return 0, 0, 0, nil, doErr + } + + return n, oobn, recvflags, from, os.NewSyscallError(op, err) +} + +// Recvfrom wraps recvfrom(2) +func (c *Conn) Recvfrom(p []byte, flags int) (int, unix.Sockaddr, error) { + const op = "recvfrom" + + var ( + n int + addr unix.Sockaddr + err error + ) + + doErr := c.read(op, func(fd int) error { + n, addr, err = unix.Recvfrom(fd, p, flags) + return err + }) + if doErr != nil { + return 0, nil, doErr + } + + return n, addr, os.NewSyscallError(op, err) +} + +// Sendmsg wraps sendmsg(2). +func (c *Conn) Sendmsg(p, oob []byte, to unix.Sockaddr, flags int) error { + const op = "sendmsg" + + var err error + doErr := c.write(op, func(fd int) error { + err = unix.Sendmsg(fd, p, oob, to, flags) + return err + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) +} + +// Sendto wraps sendto(2). +func (c *Conn) Sendto(b []byte, to unix.Sockaddr, flags int) error { + const op = "sendto" + + var err error + doErr := c.write(op, func(fd int) error { + err = unix.Sendto(fd, b, flags, to) + return err + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) +} + +// SetsockoptInt wraps setsockopt(2) for integer values. +func (c *Conn) SetsockoptInt(level, opt, value int) error { + const op = "setsockopt" + + var err error + doErr := c.control(op, func(fd int) error { + err = unix.SetsockoptInt(fd, level, opt, value) + return err + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) +} + +// Shutdown wraps shutdown(2). +func (c *Conn) Shutdown(how int) error { + const op = "shutdown" + + var err error + doErr := c.control(op, func(fd int) error { + err = unix.Shutdown(fd, how) + return err + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) +} + +// Conn low-level read/write/control functions. These functions mirror the +// syscall.RawConn APIs but the input closures return errors rather than +// booleans. Any syscalls invoked within f should return their error to allow +// the Conn to check for readiness with the runtime network poller, or to retry +// operations which may have been interrupted by EINTR or similar. +// +// Note that errors from the input closure functions are not propagated to the +// error return values of read/write/control, and the caller is still +// responsible for error handling. + +// read executes f, a read function, against the associated file descriptor. +// op is used to create an *os.SyscallError if the file descriptor is closed. +func (c *Conn) read(op string, f func(fd int) error) error { + if atomic.LoadUint32(&c.closed) != 0 { + return os.NewSyscallError(op, unix.EBADF) + } + + return c.rc.Read(func(fd uintptr) bool { + return ready(f(int(fd))) + }) +} + +// write executes f, a write function, against the associated file descriptor. +// op is used to create an *os.SyscallError if the file descriptor is closed. +func (c *Conn) write(op string, f func(fd int) error) error { + if atomic.LoadUint32(&c.closed) != 0 { + return os.NewSyscallError(op, unix.EBADF) + } + + return c.rc.Write(func(fd uintptr) bool { + return ready(f(int(fd))) + }) +} + +// control executes f, a control function, against the associated file +// descriptor. op is used to create an *os.SyscallError if the file descriptor +// is closed. +func (c *Conn) control(op string, f func(fd int) error) error { + if atomic.LoadUint32(&c.closed) != 0 { + return os.NewSyscallError(op, unix.EBADF) + } + + return c.rc.Control(func(fd uintptr) { + // Repeatedly attempt the syscall(s) invoked by f until completion is + // indicated by the return value of ready. + for { + if ready(f(int(fd))) { + return + } + } + }) +} + +// ready indicates readiness based on the value of err. +func ready(err error) bool { + // When a socket is in non-blocking mode, we might see a variety of errors: + // - EAGAIN: most common case for a socket read not being ready + // - EINPROGRESS: reported by some sockets when first calling connect + // - EINTR: system call interrupted, more frequently occurs in Go 1.14+ + // because goroutines can be asynchronously preempted + // + // Return false to let the poller wait for readiness. See the source code + // for internal/poll.FD.RawRead for more details. + switch err { + case unix.EAGAIN, unix.EINPROGRESS, unix.EINTR: + // Not ready. + return false + default: + // Ready regardless of whether there was an error or no error. + return true + } +} diff --git a/src/runtime/vendor/github.com/mdlayher/socket/conn_linux.go b/src/runtime/vendor/github.com/mdlayher/socket/conn_linux.go new file mode 100644 index 000000000..275f641c1 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/conn_linux.go @@ -0,0 +1,88 @@ +//go:build linux +// +build linux + +package socket + +import ( + "os" + "unsafe" + + "golang.org/x/net/bpf" + "golang.org/x/sys/unix" +) + +// SetBPF attaches an assembled BPF program to a Conn. +func (c *Conn) SetBPF(filter []bpf.RawInstruction) error { + // We can't point to the first instruction in the array if no instructions + // are present. + if len(filter) == 0 { + return os.NewSyscallError("setsockopt", unix.EINVAL) + } + + prog := unix.SockFprog{ + Len: uint16(len(filter)), + Filter: (*unix.SockFilter)(unsafe.Pointer(&filter[0])), + } + + return c.SetsockoptSockFprog(unix.SOL_SOCKET, unix.SO_ATTACH_FILTER, &prog) +} + +// RemoveBPF removes a BPF filter from a Conn. +func (c *Conn) RemoveBPF() error { + // 0 argument is ignored. + return c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_DETACH_FILTER, 0) +} + +// SetsockoptSockFprog wraps setsockopt(2) for unix.SockFprog values. +func (c *Conn) SetsockoptSockFprog(level, opt int, fprog *unix.SockFprog) error { + const op = "setsockopt" + + var err error + doErr := c.control(op, func(fd int) error { + err = unix.SetsockoptSockFprog(fd, level, opt, fprog) + return err + }) + if doErr != nil { + return doErr + } + + return os.NewSyscallError(op, err) +} + +// GetSockoptTpacketStats wraps getsockopt(2) for getting TpacketStats +func (c *Conn) GetSockoptTpacketStats(level, name int) (*unix.TpacketStats, error) { + const op = "getsockopt" + + var ( + stats *unix.TpacketStats + err error + ) + + doErr := c.control(op, func(fd int) error { + stats, err = unix.GetsockoptTpacketStats(fd, level, name) + return err + }) + if doErr != nil { + return stats, doErr + } + return stats, os.NewSyscallError(op, err) +} + +// GetSockoptTpacketStatsV3 wraps getsockopt(2) for getting TpacketStatsV3 +func (c *Conn) GetSockoptTpacketStatsV3(level, name int) (*unix.TpacketStatsV3, error) { + const op = "getsockopt" + + var ( + stats *unix.TpacketStatsV3 + err error + ) + + doErr := c.control(op, func(fd int) error { + stats, err = unix.GetsockoptTpacketStatsV3(fd, level, name) + return err + }) + if doErr != nil { + return stats, doErr + } + return stats, os.NewSyscallError(op, err) +} diff --git a/src/runtime/vendor/github.com/mdlayher/socket/doc.go b/src/runtime/vendor/github.com/mdlayher/socket/doc.go new file mode 100644 index 000000000..7d4566c90 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/doc.go @@ -0,0 +1,13 @@ +// Package socket provides a low-level network connection type which integrates +// with Go's runtime network poller to provide asynchronous I/O and deadline +// support. +// +// This package focuses on UNIX-like operating systems which make use of BSD +// sockets system call APIs. It is meant to be used as a foundation for the +// creation of operating system-specific socket packages, for socket families +// such as Linux's AF_NETLINK, AF_PACKET, or AF_VSOCK. This package should not +// be used directly in end user applications. +// +// Any use of package socket should be guarded by build tags, as one would also +// use when importing the syscall or golang.org/x/sys packages. +package socket diff --git a/src/runtime/vendor/github.com/mdlayher/socket/go.mod b/src/runtime/vendor/github.com/mdlayher/socket/go.mod new file mode 100644 index 000000000..ead5e027b --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/go.mod @@ -0,0 +1,10 @@ +module github.com/mdlayher/socket + +go 1.17 + +require ( + github.com/google/go-cmp v0.5.6 + golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 +) diff --git a/src/runtime/vendor/github.com/mdlayher/socket/go.sum b/src/runtime/vendor/github.com/mdlayher/socket/go.sum new file mode 100644 index 000000000..8a92791e8 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/go.sum @@ -0,0 +1,13 @@ +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/src/runtime/vendor/github.com/mdlayher/socket/netns_linux.go b/src/runtime/vendor/github.com/mdlayher/socket/netns_linux.go new file mode 100644 index 000000000..b29115ad1 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/netns_linux.go @@ -0,0 +1,150 @@ +//go:build linux +// +build linux + +package socket + +import ( + "errors" + "fmt" + "os" + "runtime" + + "golang.org/x/sync/errgroup" + "golang.org/x/sys/unix" +) + +// errNetNSDisabled is returned when network namespaces are unavailable on +// a given system. +var errNetNSDisabled = errors.New("socket: Linux network namespaces are not enabled on this system") + +// withNetNS invokes fn within the context of the network namespace specified by +// fd, while also managing the logic required to safely do so by manipulating +// thread-local state. +func withNetNS(fd int, fn func() (*Conn, error)) (*Conn, error) { + var ( + eg errgroup.Group + conn *Conn + ) + + eg.Go(func() error { + // Retrieve and store the calling OS thread's network namespace so the + // thread can be reassigned to it after creating a socket in another network + // namespace. + runtime.LockOSThread() + + ns, err := threadNetNS() + if err != nil { + // No thread-local manipulation, unlock. + runtime.UnlockOSThread() + return err + } + defer ns.Close() + + // Beyond this point, the thread's network namespace is poisoned. Do not + // unlock the OS thread until all network namespace manipulation completes + // to avoid returning to the caller with altered thread-local state. + + // Assign the current OS thread the goroutine is locked to to the given + // network namespace. + if err := ns.Set(fd); err != nil { + return err + } + + // Attempt Conn creation and unconditionally restore the original namespace. + c, err := fn() + if nerr := ns.Restore(); nerr != nil { + // Failed to restore original namespace. Return an error and allow the + // runtime to terminate the thread. + if err == nil { + _ = c.Close() + } + + return nerr + } + + // No more thread-local state manipulation; return the new Conn. + runtime.UnlockOSThread() + conn = c + return nil + }) + + if err := eg.Wait(); err != nil { + return nil, err + } + + return conn, nil +} + +// A netNS is a handle that can manipulate network namespaces. +// +// Operations performed on a netNS must use runtime.LockOSThread before +// manipulating any network namespaces. +type netNS struct { + // The handle to a network namespace. + f *os.File + + // Indicates if network namespaces are disabled on this system, and thus + // operations should become a no-op or return errors. + disabled bool +} + +// threadNetNS constructs a netNS using the network namespace of the calling +// thread. If the namespace is not the default namespace, runtime.LockOSThread +// should be invoked first. +func threadNetNS() (*netNS, error) { + return fileNetNS(fmt.Sprintf("/proc/self/task/%d/ns/net", unix.Gettid())) +} + +// fileNetNS opens file and creates a netNS. fileNetNS should only be called +// directly in tests. +func fileNetNS(file string) (*netNS, error) { + f, err := os.Open(file) + switch { + case err == nil: + return &netNS{f: f}, nil + case os.IsNotExist(err): + // Network namespaces are not enabled on this system. Use this signal + // to return errors elsewhere if the caller explicitly asks for a + // network namespace to be set. + return &netNS{disabled: true}, nil + default: + return nil, err + } +} + +// Close releases the handle to a network namespace. +func (n *netNS) Close() error { + return n.do(func() error { return n.f.Close() }) +} + +// FD returns a file descriptor which represents the network namespace. +func (n *netNS) FD() int { + if n.disabled { + // No reasonable file descriptor value in this case, so specify a + // non-existent one. + return -1 + } + + return int(n.f.Fd()) +} + +// Restore restores the original network namespace for the calling thread. +func (n *netNS) Restore() error { + return n.do(func() error { return n.Set(n.FD()) }) +} + +// Set sets a new network namespace for the current thread using fd. +func (n *netNS) Set(fd int) error { + return n.do(func() error { + return os.NewSyscallError("setns", unix.Setns(fd, unix.CLONE_NEWNET)) + }) +} + +// do runs fn if network namespaces are enabled on this system. +func (n *netNS) do(fn func() error) error { + if n.disabled { + return errNetNSDisabled + } + + return fn() +} diff --git a/src/runtime/vendor/github.com/mdlayher/socket/netns_others.go b/src/runtime/vendor/github.com/mdlayher/socket/netns_others.go new file mode 100644 index 000000000..4cceb3d04 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/netns_others.go @@ -0,0 +1,14 @@ +//go:build !linux +// +build !linux + +package socket + +import ( + "fmt" + "runtime" +) + +// withNetNS returns an error on non-Linux systems. +func withNetNS(_ int, _ func() (*Conn, error)) (*Conn, error) { + return nil, fmt.Errorf("socket: Linux network namespace support is not available on %s", runtime.GOOS) +} diff --git a/src/runtime/vendor/github.com/mdlayher/socket/setbuffer_linux.go b/src/runtime/vendor/github.com/mdlayher/socket/setbuffer_linux.go new file mode 100644 index 000000000..0d4aa4417 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/setbuffer_linux.go @@ -0,0 +1,24 @@ +//go:build linux +// +build linux + +package socket + +import "golang.org/x/sys/unix" + +// setReadBuffer wraps the SO_RCVBUF{,FORCE} setsockopt(2) options. +func (c *Conn) setReadBuffer(bytes int) error { + err := c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, bytes) + if err != nil { + err = c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_RCVBUF, bytes) + } + return err +} + +// setWriteBuffer wraps the SO_SNDBUF{,FORCE} setsockopt(2) options. +func (c *Conn) setWriteBuffer(bytes int) error { + err := c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_SNDBUFFORCE, bytes) + if err != nil { + err = c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_SNDBUF, bytes) + } + return err +} diff --git a/src/runtime/vendor/github.com/mdlayher/socket/setbuffer_others.go b/src/runtime/vendor/github.com/mdlayher/socket/setbuffer_others.go new file mode 100644 index 000000000..72b36dbe3 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/setbuffer_others.go @@ -0,0 +1,16 @@ +//go:build !linux +// +build !linux + +package socket + +import "golang.org/x/sys/unix" + +// setReadBuffer wraps the SO_RCVBUF setsockopt(2) option. +func (c *Conn) setReadBuffer(bytes int) error { + return c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_RCVBUF, bytes) +} + +// setWriteBuffer wraps the SO_SNDBUF setsockopt(2) option. +func (c *Conn) setWriteBuffer(bytes int) error { + return c.SetsockoptInt(unix.SOL_SOCKET, unix.SO_SNDBUF, bytes) +} diff --git a/src/runtime/vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go b/src/runtime/vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go new file mode 100644 index 000000000..40e834310 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/typ_cloexec_nonblock.go @@ -0,0 +1,12 @@ +//go:build !darwin +// +build !darwin + +package socket + +import "golang.org/x/sys/unix" + +const ( + // These operating systems support CLOEXEC and NONBLOCK socket options. + flagCLOEXEC = true + socketFlags = unix.SOCK_CLOEXEC | unix.SOCK_NONBLOCK +) diff --git a/src/runtime/vendor/github.com/mdlayher/socket/typ_none.go b/src/runtime/vendor/github.com/mdlayher/socket/typ_none.go new file mode 100644 index 000000000..9bbb1aab5 --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/socket/typ_none.go @@ -0,0 +1,11 @@ +//go:build darwin +// +build darwin + +package socket + +const ( + // These operating systems do not support CLOEXEC and NONBLOCK socket + // options. + flagCLOEXEC = false + socketFlags = 0 +) diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/CHANGELOG.md b/src/runtime/vendor/github.com/mdlayher/vsock/CHANGELOG.md new file mode 100644 index 000000000..61be08d8b --- /dev/null +++ b/src/runtime/vendor/github.com/mdlayher/vsock/CHANGELOG.md @@ -0,0 +1,35 @@ +# CHANGELOG + +## Unreleased + +## v1.1.0 + +- [New API] [commit](https://github.com/mdlayher/vsock/commit/44cd82dc5f7de644436f22236b111ab97fa9a14f): + `vsock.FileListener` can be used to create a `vsock.Listener` from an existing + `os.File`, which may be provided by systemd socket activation or another + external mechanism. + +## v1.0.1 + +- [Bug Fix] [commit](https://github.com/mdlayher/vsock/commit/99a6dccdebad21d1fa5f757d228d677ccb1412dc): + upgrade `github.com/mdlayher/socket` to handle non-blocking `connect(2)` + errors (called in `vsock.Dial`) properly by checking the `SO_ERROR` socket + option. Lock in this behavior with a new test. +- [Improvement] [commit](https://github.com/mdlayher/vsock/commit/375f3bbcc363500daf367ec511638a4655471719): + downgrade the version of `golang.org/x/net` in use to support Go 1.12. We + don't need the latest version for this package. + +## v1.0.0 + +**This is the first release of package vsock that only supports Go 1.12+. +Users on older versions of Go must use an unstable release.** + +- Initial stable commit! +- [API change]: the `vsock.Dial` and `vsock.Listen` constructors now accept an + optional `*vsock.Config` parameter to enable future expansion in v1.x.x + without prompting further breaking API changes. Because `vsock.Config` has no + options as of this release, `nil` may be passed in all call sites to fix + existing code upon upgrading to v1.0.0. +- [New API]: the `vsock.ListenContextID` function can be used to create a + `*vsock.Listener` which is bound to an explicit context ID address, rather + than inferring one automatically as `vsock.Listen` does. diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/LICENSE.md b/src/runtime/vendor/github.com/mdlayher/vsock/LICENSE.md index ffcdf89c9..9fa6774b1 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/LICENSE.md +++ b/src/runtime/vendor/github.com/mdlayher/vsock/LICENSE.md @@ -1,7 +1,6 @@ -MIT License -=========== +# MIT License -Copyright (C) 2017 Matt Layher +Copyright (C) 2017-2022 Matt Layher Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/README.md b/src/runtime/vendor/github.com/mdlayher/vsock/README.md index dd0ffe805..6395502bf 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/README.md +++ b/src/runtime/vendor/github.com/mdlayher/vsock/README.md @@ -1,32 +1,30 @@ -# vsock [![builds.sr.ht status](https://builds.sr.ht/~mdlayher/vsock.svg)](https://builds.sr.ht/~mdlayher/vsock?) [![GoDoc](https://godoc.org/github.com/mdlayher/vsock?status.svg)](https://godoc.org/github.com/mdlayher/vsock) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/vsock)](https://goreportcard.com/report/github.com/mdlayher/vsock) +# vsock [![Test Status](https://github.com/mdlayher/vsock/workflows/Linux%20Test/badge.svg)](https://github.com/mdlayher/vsock/actions) [![Go Reference](https://pkg.go.dev/badge/github.com/mdlayher/vsock.svg)](https://pkg.go.dev/github.com/mdlayher/vsock) [![Go Report Card](https://goreportcard.com/badge/github.com/mdlayher/vsock)](https://goreportcard.com/report/github.com/mdlayher/vsock) Package `vsock` provides access to Linux VM sockets (`AF_VSOCK`) for communication between a hypervisor and its virtual machines. MIT Licensed. For more information about VM sockets, check out my blog about -[Linux VM sockets in Go](https://medium.com/@mdlayher/linux-vm-sockets-in-go-ea11768e9e67). - -## Go version support - -This package supports varying levels of functionality depending on the version -of Go used during compilation. The `Listener` and `Conn` types produced by this -package are backed by non-blocking I/O, in order to integrate with Go's runtime -network poller in Go 1.11+. Additional functionality is available starting in Go -1.12+. The older Go 1.10 is only supported in a blocking-only mode. - -A comprehensive list of functionality for supported Go versions can be found on -[package vsock's GoDoc page](https://godoc.org/github.com/mdlayher/vsock#hdr-Go_version_support). +[Linux VM sockets in Go](https://mdlayher.com/blog/linux-vm-sockets-in-go/). ## Stability -At this time, package `vsock` is in a pre-v1.0.0 state. Changes are being made -which may impact the exported API of this package and others in its ecosystem. +See the [CHANGELOG](./CHANGELOG.md) file for a description of changes between +releases. -**If you depend on this package in your application, please use Go modules when -building your application.** +This package has a stable v1 API and any future breaking changes will prompt +the release of a new major version. Features and bug fixes will continue to +occur in the v1.x.x series. + +In order to reduce the maintenance burden, this package is only supported on +Go 1.12+. Older versions of Go lack critical features and APIs which are +necessary for this package to function correctly. + +**If you depend on this package in your applications, please use Go modules.** ## Requirements +**It's possible these requirements are out of date. PRs are welcome.** + To make use of VM sockets with QEMU and virtio-vsock, you must have: - a Linux hypervisor with kernel 4.8+ @@ -53,10 +51,3 @@ Check out the [QEMU wiki page on virtio-vsock](http://wiki.qemu-project.org/Features/VirtioVsock) for more details. More detail on setting up this environment will be provided in the future. - -## Usage - -To try out VM sockets and see an example of how they work, see -[cmd/vscp](https://github.com/mdlayher/vsock/tree/master/cmd/vscp). -This command shows usage of the `vsock.ListenStream` and `vsock.DialStream` -APIs, and allows users to easily test VM sockets on their systems. diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/conn_linux.go b/src/runtime/vendor/github.com/mdlayher/vsock/conn_linux.go index d9558cd5d..684cf4c98 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/conn_linux.go +++ b/src/runtime/vendor/github.com/mdlayher/vsock/conn_linux.go @@ -1,72 +1,55 @@ -//+build linux +//go:build linux +// +build linux package vsock import ( + "github.com/mdlayher/socket" "golang.org/x/sys/unix" ) -// newConn creates a Conn using a connFD, immediately setting the connFD to -// non-blocking mode for use with the runtime network poller. -func newConn(cfd connFD, local, remote *Addr) (*Conn, error) { - // Note: if any calls fail after this point, cfd.Close should be invoked - // for cleanup because the socket is now non-blocking. - if err := cfd.SetNonblocking(local.fileName()); err != nil { - return nil, err - } - - return &Conn{ - fd: cfd, - local: local, - remote: remote, - }, nil -} - // dial is the entry point for Dial on Linux. -func dial(cid, port uint32) (*Conn, error) { - cfd, err := newConnFD() +func dial(cid, port uint32, _ *Config) (*Conn, error) { + // TODO(mdlayher): Config default nil check and initialize. Pass options to + // socket.Config where necessary. + + c, err := socket.Socket(unix.AF_VSOCK, unix.SOCK_STREAM, 0, "vsock", nil) if err != nil { return nil, err } - return dialLinux(cfd, cid, port) -} - -// dialLinux is the entry point for tests on Linux. -func dialLinux(cfd connFD, cid, port uint32) (c *Conn, err error) { - defer func() { - if err != nil { - // If any system calls fail during setup, the socket must be closed - // to avoid file descriptor leaks. - _ = cfd.EarlyClose() - } - }() - - rsa := &unix.SockaddrVM{ - CID: cid, - Port: port, - } - - if err := cfd.Connect(rsa); err != nil { + sa := &unix.SockaddrVM{CID: cid, Port: port} + rsa, err := c.Connect(sa) + if err != nil { + _ = c.Close() return nil, err } - lsa, err := cfd.Getsockname() + // TODO(mdlayher): getpeername(2) appears to return nil in the GitHub CI + // environment, so in the event of a nil sockaddr, fall back to the previous + // method of synthesizing the remote address. + if rsa == nil { + rsa = sa + } + + lsa, err := c.Getsockname() if err != nil { + _ = c.Close() return nil, err } lsavm := lsa.(*unix.SockaddrVM) + rsavm := rsa.(*unix.SockaddrVM) - local := &Addr{ - ContextID: lsavm.CID, - Port: lsavm.Port, - } - - remote := &Addr{ - ContextID: cid, - Port: port, - } - - return newConn(cfd, local, remote) + return &Conn{ + c: c, + local: &Addr{ + ContextID: lsavm.CID, + Port: lsavm.Port, + }, + remote: &Addr{ + ContextID: rsavm.CID, + Port: rsavm.Port, + }, + }, nil } diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/doc.go b/src/runtime/vendor/github.com/mdlayher/vsock/doc.go index a26534146..e158b1836 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/doc.go +++ b/src/runtime/vendor/github.com/mdlayher/vsock/doc.go @@ -7,54 +7,4 @@ // - *Addr implements net.Addr // - *Conn implements net.Conn // - *Listener implements net.Listener -// -// Go version support -// -// This package supports varying levels of functionality depending on the version -// of Go used during compilation. The Listener and Conn types produced by this -// package are backed by non-blocking I/O, in order to integrate with Go's -// runtime network poller in Go 1.11+. Additional functionality is available -// starting in Go 1.12+. -// -// Go 1.12+ (recommended): -// - *Listener: -// - Accept blocks until a connection is received -// - Close can interrupt Accept and make it return a permanent error -// - SetDeadline can set timeouts which can interrupt Accept and make it return a -// temporary error -// - *Conn: -// - SetDeadline family of methods are fully supported -// - CloseRead and CloseWrite can close the reading or writing sides of a -// Conn, respectively -// - SyscallConn provides access to raw network control/read/write functionality -// -// Go 1.11 (not recommended): -// - *Listener: -// - Accept is non-blocking and should be called in a loop, checking for -// net.Error.Temporary() == true and sleeping for a short period to avoid wasteful -// CPU cycle consumption -// - Close makes Accept return a permanent error on the next loop iteration -// - SetDeadline is not supported and will always return an error -// - *Conn: -// - SetDeadline family of methods are fully supported -// - CloseRead and CloseWrite are not supported and will always return an error -// - SyscallConn is not supported and will always return an error -// -// Go 1.10 (not recommended): -// - *Listener: -// - Accept blocks until a connection is received -// - Close cannot unblock Accept -// - SetDeadline is not supported and will always return an error -// - *Conn: -// - SetDeadline is not supported and will always return an error -// - CloseRead and CloseWrite are not supported and will always return an error -// - SyscallConn is not supported and will always return an error -// -// Stability -// -// At this time, package vsock is in a pre-v1.0.0 state. Changes are being made -// which may impact the exported API of this package and others in its ecosystem. -// -// If you depend on this package in your application, please use Go modules when -// building your application. package vsock diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux.go b/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux.go index 4c593047b..531e53f92 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux.go +++ b/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux.go @@ -2,10 +2,7 @@ package vsock import ( "fmt" - "io" "os" - "syscall" - "time" "golang.org/x/sys/unix" ) @@ -21,192 +18,6 @@ func contextID() (uint32, error) { return unix.IoctlGetUint32(int(f.Fd()), unix.IOCTL_VM_SOCKETS_GET_LOCAL_CID) } -// A listenFD is a type that wraps a file descriptor used to implement -// net.Listener. -type listenFD interface { - io.Closer - EarlyClose() error - Accept4(flags int) (connFD, unix.Sockaddr, error) - Bind(sa unix.Sockaddr) error - Listen(n int) error - Getsockname() (unix.Sockaddr, error) - SetNonblocking(name string) error - SetDeadline(t time.Time) error -} - -var _ listenFD = &sysListenFD{} - -// A sysListenFD is the system call implementation of listenFD. -type sysListenFD struct { - // These fields should never be non-zero at the same time. - fd int // Used in blocking mode. - f *os.File // Used in non-blocking mode. -} - -// newListenFD creates a sysListenFD in its default blocking mode. -func newListenFD() (*sysListenFD, error) { - fd, err := socket() - if err != nil { - return nil, err - } - - return &sysListenFD{ - fd: fd, - }, nil -} - -// Blocking mode methods. - -func (lfd *sysListenFD) Bind(sa unix.Sockaddr) error { return unix.Bind(lfd.fd, sa) } -func (lfd *sysListenFD) Getsockname() (unix.Sockaddr, error) { return unix.Getsockname(lfd.fd) } -func (lfd *sysListenFD) Listen(n int) error { return unix.Listen(lfd.fd, n) } - -func (lfd *sysListenFD) SetNonblocking(name string) error { - return lfd.setNonblocking(name) -} - -// EarlyClose is a blocking version of Close, only used for cleanup before -// entering non-blocking mode. -func (lfd *sysListenFD) EarlyClose() error { return unix.Close(lfd.fd) } - -// Non-blocking mode methods. - -func (lfd *sysListenFD) Accept4(flags int) (connFD, unix.Sockaddr, error) { - // Invoke Go version-specific logic for accept. - newFD, sa, err := lfd.accept4(flags) - if err != nil { - return nil, nil, err - } - - // Create a non-blocking connFD which will be used to implement net.Conn. - cfd := &sysConnFD{fd: newFD} - return cfd, sa, nil -} - -func (lfd *sysListenFD) Close() error { - // In Go 1.12+, *os.File.Close will also close the runtime network poller - // file descriptor, so that net.Listener.Accept can stop blocking. - return lfd.f.Close() -} - -func (lfd *sysListenFD) SetDeadline(t time.Time) error { - // Invoke Go version-specific logic for setDeadline. - return lfd.setDeadline(t) -} - -// A connFD is a type that wraps a file descriptor used to implement net.Conn. -type connFD interface { - io.ReadWriteCloser - EarlyClose() error - Connect(sa unix.Sockaddr) error - Getsockname() (unix.Sockaddr, error) - Shutdown(how int) error - SetNonblocking(name string) error - SetDeadline(t time.Time, typ deadlineType) error - SyscallConn() (syscall.RawConn, error) -} - -var _ connFD = &sysConnFD{} - -// newConnFD creates a sysConnFD in its default blocking mode. -func newConnFD() (*sysConnFD, error) { - fd, err := socket() - if err != nil { - return nil, err - } - - return &sysConnFD{ - fd: fd, - }, nil -} - -// A sysConnFD is the system call implementation of connFD. -type sysConnFD struct { - // These fields should never be non-zero at the same time. - fd int // Used in blocking mode. - f *os.File // Used in non-blocking mode. -} - -// Blocking mode methods. - -func (cfd *sysConnFD) Connect(sa unix.Sockaddr) error { return unix.Connect(cfd.fd, sa) } -func (cfd *sysConnFD) Getsockname() (unix.Sockaddr, error) { return unix.Getsockname(cfd.fd) } - -// EarlyClose is a blocking version of Close, only used for cleanup before -// entering non-blocking mode. -func (cfd *sysConnFD) EarlyClose() error { return unix.Close(cfd.fd) } - -func (cfd *sysConnFD) SetNonblocking(name string) error { - return cfd.setNonblocking(name) -} - -// Non-blocking mode methods. - -func (cfd *sysConnFD) Close() error { - // *os.File.Close will also close the runtime network poller file descriptor, - // so that read/write can stop blocking. - return cfd.f.Close() -} - -func (cfd *sysConnFD) Read(b []byte) (int, error) { return cfd.f.Read(b) } -func (cfd *sysConnFD) Write(b []byte) (int, error) { return cfd.f.Write(b) } - -func (cfd *sysConnFD) Shutdown(how int) error { - switch how { - case unix.SHUT_RD, unix.SHUT_WR: - return cfd.shutdown(how) - default: - panicf("vsock: sysConnFD.Shutdown method invoked with invalid how constant: %d", how) - return nil - } -} - -func (cfd *sysConnFD) SetDeadline(t time.Time, typ deadlineType) error { - return cfd.setDeadline(t, typ) -} - -func (cfd *sysConnFD) SyscallConn() (syscall.RawConn, error) { return cfd.syscallConn() } - -// socket invokes unix.Socket with the correct arguments to produce a vsock -// file descriptor. -func socket() (int, error) { - // "Mirror what the standard library does when creating file - // descriptors: avoid racing a fork/exec with the creation - // of new file descriptors, so that child processes do not - // inherit [socket] file descriptors unexpectedly. - // - // On Linux, SOCK_CLOEXEC was introduced in 2.6.27. OTOH, - // Go supports Linux 2.6.23 and above. If we get EINVAL on - // the first try, it may be that we are running on a kernel - // older than 2.6.27. In that case, take syscall.ForkLock - // and try again without SOCK_CLOEXEC. - // - // For a more thorough explanation, see similar work in the - // Go tree: func sysSocket in net/sock_cloexec.go, as well - // as the detailed comment in syscall/exec_unix.go." - // - // Explanation copied from netlink, courtesy of acln: - // https://github.com/mdlayher/netlink/pull/138. - fd, err := unix.Socket(unix.AF_VSOCK, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0) - switch err { - case nil: - return fd, nil - case unix.EINVAL: - syscall.ForkLock.RLock() - defer syscall.ForkLock.RUnlock() - - fd, err = unix.Socket(unix.AF_VSOCK, unix.SOCK_STREAM, 0) - if err != nil { - return 0, err - } - unix.CloseOnExec(fd) - - return fd, nil - default: - return 0, err - } -} - // isErrno determines if an error a matches UNIX error number. func isErrno(err error, errno int) bool { switch errno { diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_1.10.go b/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_1.10.go deleted file mode 100644 index aa214feb2..000000000 --- a/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_1.10.go +++ /dev/null @@ -1,63 +0,0 @@ -//+build go1.10,!go1.11,linux - -package vsock - -import ( - "fmt" - "os" - "runtime" - "syscall" - "time" - - "golang.org/x/sys/unix" -) - -func (lfd *sysListenFD) accept4(flags int) (int, unix.Sockaddr, error) { - // In Go 1.11, accept on the raw file descriptor directly, because lfd.f - // may be attached to the runtime network poller, forcing this call to block - // even if Close is called. - return unix.Accept4(lfd.fd, flags) -} - -func (lfd *sysListenFD) setNonblocking(name string) error { - // Go 1.10 doesn't support non-blocking I/O. - if err := unix.SetNonblock(lfd.fd, false); err != nil { - return err - } - - lfd.f = os.NewFile(uintptr(lfd.fd), name) - - return nil -} - -func (*sysListenFD) setDeadline(_ time.Time) error { - // Listener deadlines won't work as expected in this version of Go, so - // return an early error. - return fmt.Errorf("vsock: listener deadlines not supported on %s", runtime.Version()) -} - -func (*sysConnFD) shutdown(_ int) error { - // Shutdown functionality is not available in this version on Go. - return fmt.Errorf("vsock: close conn read/write not supported on %s", runtime.Version()) -} - -func (*sysConnFD) syscallConn() (syscall.RawConn, error) { - // SyscallConn functionality is not available in this version on Go. - return nil, fmt.Errorf("vsock: syscall conn not supported on %s", runtime.Version()) -} - -func (cfd *sysConnFD) setNonblocking(name string) error { - // Go 1.10 doesn't support non-blocking I/O. - if err := unix.SetNonblock(cfd.fd, false); err != nil { - return err - } - - cfd.f = os.NewFile(uintptr(cfd.fd), name) - - return nil -} - -func (cfd *sysConnFD) setDeadline(t time.Time, typ deadlineType) error { - // Deadline functionality is not available in this version on Go. - return fmt.Errorf("vsock: connection deadlines not supported on %s", runtime.Version()) -} diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_1.11.go b/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_1.11.go deleted file mode 100644 index 90991a0f5..000000000 --- a/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_1.11.go +++ /dev/null @@ -1,76 +0,0 @@ -//+build go1.11,!go1.12,linux - -package vsock - -import ( - "fmt" - "os" - "runtime" - "syscall" - "time" - - "golang.org/x/sys/unix" -) - -func (lfd *sysListenFD) accept4(flags int) (int, unix.Sockaddr, error) { - // In Go 1.11, accept on the raw file descriptor directly, because lfd.f - // may be attached to the runtime network poller, forcing this call to block - // even if Close is called. - return unix.Accept4(lfd.fd, flags) -} - -func (lfd *sysListenFD) setNonblocking(name string) error { - // From now on, we must perform non-blocking I/O, so that our - // net.Listener.Accept method can be interrupted by closing the socket. - if err := unix.SetNonblock(lfd.fd, true); err != nil { - return err - } - - // Transition from blocking mode to non-blocking mode. - lfd.f = os.NewFile(uintptr(lfd.fd), name) - - return nil -} - -func (*sysListenFD) setDeadline(_ time.Time) error { - // Listener deadlines won't work as expected in this version of Go, so - // return an early error. - return fmt.Errorf("vsock: listener deadlines not supported on %s", runtime.Version()) -} - -func (*sysConnFD) shutdown(_ int) error { - // Shutdown functionality is not available in this version on Go. - return fmt.Errorf("vsock: close conn read/write not supported on %s", runtime.Version()) -} - -func (*sysConnFD) syscallConn() (syscall.RawConn, error) { - // SyscallConn functionality is not available in this version on Go. - return nil, fmt.Errorf("vsock: syscall conn not supported on %s", runtime.Version()) -} - -func (cfd *sysConnFD) setNonblocking(name string) error { - // From now on, we must perform non-blocking I/O, so that our deadline - // methods work, and the connection can be interrupted by net.Conn.Close. - if err := unix.SetNonblock(cfd.fd, true); err != nil { - return err - } - - // Transition from blocking mode to non-blocking mode. - cfd.f = os.NewFile(uintptr(cfd.fd), name) - - return nil -} - -func (cfd *sysConnFD) setDeadline(t time.Time, typ deadlineType) error { - switch typ { - case deadline: - return cfd.f.SetDeadline(t) - case readDeadline: - return cfd.f.SetReadDeadline(t) - case writeDeadline: - return cfd.f.SetWriteDeadline(t) - } - - panicf("vsock: sysConnFD.SetDeadline method invoked with invalid deadline type constant: %d", typ) - return nil -} diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_gteq_1.12.go b/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_gteq_1.12.go deleted file mode 100644 index b90a45e03..000000000 --- a/src/runtime/vendor/github.com/mdlayher/vsock/fd_linux_gteq_1.12.go +++ /dev/null @@ -1,112 +0,0 @@ -//+build go1.12,linux - -package vsock - -import ( - "os" - "syscall" - "time" - - "golang.org/x/sys/unix" -) - -func (lfd *sysListenFD) accept4(flags int) (int, unix.Sockaddr, error) { - // In Go 1.12+, we make use of runtime network poller integration to allow - // net.Listener.Accept to be unblocked by a call to net.Listener.Close. - rc, err := lfd.f.SyscallConn() - if err != nil { - return 0, nil, err - } - - var ( - newFD int - sa unix.Sockaddr - ) - - doErr := rc.Read(func(fd uintptr) bool { - newFD, sa, err = unix.Accept4(int(fd), flags) - - switch err { - case unix.EAGAIN, unix.ECONNABORTED: - // Return false to let the poller wait for readiness. See the - // source code for internal/poll.FD.RawRead for more details. - // - // When the socket is in non-blocking mode, we might see EAGAIN if - // the socket is not ready for reading. - // - // In addition, the network poller's accept implementation also - // deals with ECONNABORTED, in case a socket is closed before it is - // pulled from our listen queue. - return false - default: - // No error or some unrecognized error, treat this Read operation - // as completed. - return true - } - }) - if doErr != nil { - return 0, nil, doErr - } - - return newFD, sa, err -} - -func (lfd *sysListenFD) setDeadline(t time.Time) error { return lfd.f.SetDeadline(t) } - -func (lfd *sysListenFD) setNonblocking(name string) error { - // From now on, we must perform non-blocking I/O, so that our - // net.Listener.Accept method can be interrupted by closing the socket. - if err := unix.SetNonblock(lfd.fd, true); err != nil { - return err - } - - // Transition from blocking mode to non-blocking mode. - lfd.f = os.NewFile(uintptr(lfd.fd), name) - - return nil -} - -func (cfd *sysConnFD) shutdown(how int) error { - rc, err := cfd.f.SyscallConn() - if err != nil { - return err - } - - doErr := rc.Control(func(fd uintptr) { - err = unix.Shutdown(int(fd), how) - }) - if doErr != nil { - return doErr - } - - return err -} - -func (cfd *sysConnFD) syscallConn() (syscall.RawConn, error) { return cfd.f.SyscallConn() } - -func (cfd *sysConnFD) setNonblocking(name string) error { - // From now on, we must perform non-blocking I/O, so that our deadline - // methods work, and the connection can be interrupted by net.Conn.Close. - if err := unix.SetNonblock(cfd.fd, true); err != nil { - return err - } - - // Transition from blocking mode to non-blocking mode. - cfd.f = os.NewFile(uintptr(cfd.fd), name) - - return nil -} - -func (cfd *sysConnFD) setDeadline(t time.Time, typ deadlineType) error { - switch typ { - case deadline: - return cfd.f.SetDeadline(t) - case readDeadline: - return cfd.f.SetReadDeadline(t) - case writeDeadline: - return cfd.f.SetWriteDeadline(t) - } - - panicf("vsock: sysConnFD.SetDeadline method invoked with invalid deadline type constant: %d", typ) - return nil -} diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/go.mod b/src/runtime/vendor/github.com/mdlayher/vsock/go.mod index bf837d952..0beb9b692 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/go.mod +++ b/src/runtime/vendor/github.com/mdlayher/vsock/go.mod @@ -3,7 +3,8 @@ module github.com/mdlayher/vsock go 1.13 require ( - github.com/google/go-cmp v0.3.1 - golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c - golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd + github.com/google/go-cmp v0.5.7 + github.com/mdlayher/socket v0.2.0 + golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c + golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a ) diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/go.sum b/src/runtime/vendor/github.com/mdlayher/vsock/go.sum index 373a00e3b..54e861d3c 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/go.sum +++ b/src/runtime/vendor/github.com/mdlayher/vsock/go.sum @@ -1,16 +1,17 @@ -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/mdlayher/socket v0.2.0 h1:EY4YQd6hTAg2tcXF84p5DTHazShE50u5HeBzBaNgjkA= +github.com/mdlayher/socket v0.2.0/go.mod h1:QLlNPkFR88mRUNQIzRBMfXxwKal8H7u1h3bL1CV+f0E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+wdKBmM9Y9kU7Z83/lw= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c h1:SRpq/kuj/xNci/RdvEs+RSvpfxqvLAzTKuKGlzoGdZQ= -golang.org/x/net v0.0.0-20191108221443-4ba9e2ef068c/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862 h1:rM0ROo5vb9AdYJi1110yjWGMej9ITfKddS89P3Fkhug= -golang.org/x/sys v0.0.0-20190509141414-a5b02f93d862/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd h1:3x5uuvBgE6oaXJjCOvpCC1IpgJogqQ+PqGGU3ZxAgII= -golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE= +golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/listener_linux.go b/src/runtime/vendor/github.com/mdlayher/vsock/listener_linux.go index 2c16a336a..458449ad1 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/listener_linux.go +++ b/src/runtime/vendor/github.com/mdlayher/vsock/listener_linux.go @@ -1,11 +1,14 @@ -//+build linux +//go:build linux +// +build linux package vsock import ( "net" + "os" "time" + "github.com/mdlayher/socket" "golang.org/x/sys/unix" ) @@ -14,93 +17,107 @@ var _ net.Listener = &listener{} // A listener is the net.Listener implementation for connection-oriented // VM sockets. type listener struct { - fd listenFD + c *socket.Conn addr *Addr } // Addr and Close implement the net.Listener interface for listener. func (l *listener) Addr() net.Addr { return l.addr } -func (l *listener) Close() error { return l.fd.Close() } -func (l *listener) SetDeadline(t time.Time) error { return l.fd.SetDeadline(t) } +func (l *listener) Close() error { return l.c.Close() } +func (l *listener) SetDeadline(t time.Time) error { return l.c.SetDeadline(t) } // Accept accepts a single connection from the listener, and sets up // a net.Conn backed by conn. func (l *listener) Accept() (net.Conn, error) { - // Mimic what internal/poll does and close on exec, but leave it up to - // newConn to set non-blocking mode. - // See: https://golang.org/src/internal/poll/sock_cloexec.go. - // - // TODO(mdlayher): acquire syscall.ForkLock.RLock here once the Go 1.11 - // code can be removed and we're fully using the runtime network poller in - // non-blocking mode. - cfd, sa, err := l.fd.Accept4(unix.SOCK_CLOEXEC) + c, rsa, err := l.c.Accept(0) if err != nil { return nil, err } - savm := sa.(*unix.SockaddrVM) + savm := rsa.(*unix.SockaddrVM) remote := &Addr{ ContextID: savm.CID, Port: savm.Port, } - return newConn(cfd, l.addr, remote) + return &Conn{ + c: c, + local: l.addr, + remote: remote, + }, nil } +// name is the socket name passed to package socket. +const name = "vsock" + // listen is the entry point for Listen on Linux. -func listen(cid, port uint32) (*Listener, error) { - lfd, err := newListenFD() +func listen(cid, port uint32, _ *Config) (*Listener, error) { + // TODO(mdlayher): Config default nil check and initialize. Pass options to + // socket.Config where necessary. + + c, err := socket.Socket(unix.AF_VSOCK, unix.SOCK_STREAM, 0, name, nil) if err != nil { return nil, err } - return listenLinux(lfd, cid, port) -} + // Be sure to close the Conn if any of the system calls fail before we + // return the Conn to the caller. -// listenLinux is the entry point for tests on Linux. -func listenLinux(lfd listenFD, cid, port uint32) (l *Listener, err error) { - defer func() { - if err != nil { - // If any system calls fail during setup, the socket must be closed - // to avoid file descriptor leaks. - _ = lfd.EarlyClose() - } - }() - - // Zero-value for "any port" is friendlier in Go than a constant. if port == 0 { port = unix.VMADDR_PORT_ANY } - sa := &unix.SockaddrVM{ - CID: cid, - Port: port, - } - - if err := lfd.Bind(sa); err != nil { + if err := c.Bind(&unix.SockaddrVM{CID: cid, Port: port}); err != nil { + _ = c.Close() return nil, err } - if err := lfd.Listen(unix.SOMAXCONN); err != nil { + if err := c.Listen(unix.SOMAXCONN); err != nil { + _ = c.Close() return nil, err } - lsa, err := lfd.Getsockname() + l, err := newListener(c) + if err != nil { + _ = c.Close() + return nil, err + } + + return l, nil +} + +// fileListener is the entry point for FileListener on Linux. +func fileListener(f *os.File) (*Listener, error) { + c, err := socket.FileConn(f, name) if err != nil { return nil, err } - // Done with blocking mode setup, transition to non-blocking before the - // caller has a chance to start calling things concurrently that might make - // the locking situation tricky. - // - // Note: if any calls fail after this point, lfd.Close should be invoked - // for cleanup because the socket is now non-blocking. - if err := lfd.SetNonblocking("vsock-listen"); err != nil { + l, err := newListener(c) + if err != nil { + _ = c.Close() return nil, err } - lsavm := lsa.(*unix.SockaddrVM) + return l, nil +} + +// newListener creates a Listener from a raw socket.Conn. +func newListener(c *socket.Conn) (*Listener, error) { + lsa, err := c.Getsockname() + if err != nil { + return nil, err + } + + // Now that the library can also accept arbitrary os.Files, we have to + // verify the address family so we don't accidentally create a + // *vsock.Listener backed by TCP or some other socket type. + lsavm, ok := lsa.(*unix.SockaddrVM) + if !ok { + // All errors should wrapped with os.SyscallError. + return nil, os.NewSyscallError("listen", unix.EINVAL) + } + addr := &Addr{ ContextID: lsavm.CID, Port: lsavm.Port, @@ -108,7 +125,7 @@ func listenLinux(lfd listenFD, cid, port uint32) (l *Listener, err error) { return &Listener{ l: &listener{ - fd: lfd, + c: c, addr: addr, }, }, nil diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/vsock.go b/src/runtime/vendor/github.com/mdlayher/vsock/vsock.go index 004263efb..32223982a 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/vsock.go +++ b/src/runtime/vendor/github.com/mdlayher/vsock/vsock.go @@ -9,26 +9,27 @@ import ( "strings" "syscall" "time" + + "github.com/mdlayher/socket" ) const ( // Hypervisor specifies that a socket should communicate with the hypervisor - // process. + // process. Note that this is _not_ the same as a socket owned by a process + // running on the hypervisor. Most users should probably use Host instead. Hypervisor = 0x0 + // Local specifies that a socket should communicate with a matching socket + // on the same machine. This provides an alternative to UNIX sockets or + // similar and may be useful in testing VM sockets applications. + Local = 0x1 + // Host specifies that a socket should communicate with processes other than - // the hypervisor on the host machine. + // the hypervisor on the host machine. This is the correct choice to + // communicate with a process running on a hypervisor using a socket dialed + // from a guest. Host = 0x2 - // cidReserved is a reserved context ID that is no longer in use, - // and cannot be used for socket communications. - cidReserved = 0x1 - - // shutRd and shutWr are arguments for unix.Shutdown, copied here to avoid - // importing x/sys/unix in cross-platform code. - shutRd = 0 // unix.SHUT_RD - shutWr = 1 // unix.SHUT_WR - // Error numbers we recognize, copied here to avoid importing x/sys/unix in // cross-platform code. ebadf = 9 @@ -55,25 +56,47 @@ const ( opWrite = "write" ) +// TODO(mdlayher): plumb through socket.Config.NetNS if it makes sense. + +// Config contains options for a Conn or Listener. +type Config struct{} + // Listen opens a connection-oriented net.Listener for incoming VM sockets -// connections. The port parameter specifies the port for the Listener. +// connections. The port parameter specifies the port for the Listener. Config +// specifies optional configuration for the Listener. If config is nil, a +// default configuration will be used. // -// To allow the server to assign a port automatically, specify 0 for port. -// The address of the server can be retrieved using the Addr method. +// To allow the server to assign a port automatically, specify 0 for port. The +// address of the server can be retrieved using the Addr method. // -// When the Listener is no longer needed, Close must be called to free resources. -func Listen(port uint32) (*Listener, error) { +// Listen automatically infers the appropriate context ID for this machine by +// calling ContextID and passing that value to ListenContextID. Callers with +// advanced use cases (such as using the Local context ID) may wish to use +// ListenContextID directly. +// +// When the Listener is no longer needed, Close must be called to free +// resources. +func Listen(port uint32, cfg *Config) (*Listener, error) { cid, err := ContextID() if err != nil { // No addresses available. return nil, opError(opListen, err, nil, nil) } - l, err := listen(cid, port) + return ListenContextID(cid, port, cfg) +} + +// ListenContextID is the same as Listen, but also accepts an explicit context +// ID parameter. This function is intended for advanced use cases and most +// callers should use Listen instead. +// +// See the documentation of Listen for more details. +func ListenContextID(contextID, port uint32, cfg *Config) (*Listener, error) { + l, err := listen(contextID, port, cfg) if err != nil { // No remote address available. return nil, opError(opListen, err, &Addr{ - ContextID: cid, + ContextID: contextID, Port: port, }, nil) } @@ -81,6 +104,23 @@ func Listen(port uint32) (*Listener, error) { return l, nil } +// FileListener returns a copy of the network listener corresponding to an open +// os.File. It is the caller's responsibility to close the Listener when +// finished. Closing the Listener does not affect the os.File, and closing the +// os.File does not affect the Listener. +// +// This function is intended for advanced use cases and most callers should use +// Listen instead. +func FileListener(f *os.File) (*Listener, error) { + l, err := fileListener(f) + if err != nil { + // No addresses available. + return nil, opError(opListen, err, nil, nil) + } + + return l, nil +} + var _ net.Listener = &Listener{} // A Listener is a VM sockets implementation of a net.Listener. @@ -112,8 +152,6 @@ func (l *Listener) Close() error { // SetDeadline sets the deadline associated with the listener. A zero time value // disables the deadline. -// -// SetDeadline only works with Go 1.12+. func (l *Listener) SetDeadline(t time.Time) error { return l.opError(opSet, l.l.SetDeadline(t)) } @@ -125,8 +163,10 @@ func (l *Listener) opError(op string, err error) error { return opError(op, err, l.Addr(), nil) } -// Dial dials a connection-oriented net.Conn to a VM sockets server. -// The contextID and port parameters specify the address of the server. +// Dial dials a connection-oriented net.Conn to a VM sockets listener. The +// context ID and port parameters specify the address of the listener. Config +// specifies optional configuration for the Conn. If config is nil, a default +// configuration will be used. // // If dialing a connection from the hypervisor to a virtual machine, the VM's // context ID should be specified. @@ -135,9 +175,10 @@ func (l *Listener) opError(op string, err error) error { // communicate with the hypervisor process, or Host should be used to // communicate with other processes on the host machine. // -// When the connection is no longer needed, Close must be called to free resources. -func Dial(contextID, port uint32) (*Conn, error) { - c, err := dial(contextID, port) +// When the connection is no longer needed, Close must be called to free +// resources. +func Dial(contextID, port uint32, cfg *Config) (*Conn, error) { + c, err := dial(contextID, port, cfg) if err != nil { // No local address, but we have a remote address we can return. return nil, opError(opDial, err, nil, &Addr{ @@ -149,35 +190,33 @@ func Dial(contextID, port uint32) (*Conn, error) { return c, nil } -var _ net.Conn = &Conn{} -var _ syscall.Conn = &Conn{} +var ( + _ net.Conn = &Conn{} + _ syscall.Conn = &Conn{} +) // A Conn is a VM sockets implementation of a net.Conn. type Conn struct { - fd connFD + c *socket.Conn local *Addr remote *Addr } // Close closes the connection. func (c *Conn) Close() error { - return c.opError(opClose, c.fd.Close()) + return c.opError(opClose, c.c.Close()) } // CloseRead shuts down the reading side of the VM sockets connection. Most // callers should just use Close. -// -// CloseRead only works with Go 1.12+. func (c *Conn) CloseRead() error { - return c.opError(opClose, c.fd.Shutdown(shutRd)) + return c.opError(opClose, c.c.CloseRead()) } // CloseWrite shuts down the writing side of the VM sockets connection. Most // callers should just use Close. -// -// CloseWrite only works with Go 1.12+. func (c *Conn) CloseWrite() error { - return c.opError(opClose, c.fd.Shutdown(shutWr)) + return c.opError(opClose, c.c.CloseWrite()) } // LocalAddr returns the local network address. The Addr returned is shared by @@ -190,7 +229,7 @@ func (c *Conn) RemoteAddr() net.Addr { return c.remote } // Read implements the net.Conn Read method. func (c *Conn) Read(b []byte) (int, error) { - n, err := c.fd.Read(b) + n, err := c.c.Read(b) if err != nil { return n, c.opError(opRead, err) } @@ -200,7 +239,7 @@ func (c *Conn) Read(b []byte) (int, error) { // Write implements the net.Conn Write method. func (c *Conn) Write(b []byte) (int, error) { - n, err := c.fd.Write(b) + n, err := c.c.Write(b) if err != nil { return n, c.opError(opWrite, err) } @@ -208,35 +247,25 @@ func (c *Conn) Write(b []byte) (int, error) { return n, nil } -// A deadlineType specifies the type of deadline to set for a Conn. -type deadlineType int - -// Possible deadlineType values. -const ( - deadline deadlineType = iota - readDeadline - writeDeadline -) - // SetDeadline implements the net.Conn SetDeadline method. func (c *Conn) SetDeadline(t time.Time) error { - return c.opError(opSet, c.fd.SetDeadline(t, deadline)) + return c.opError(opSet, c.c.SetDeadline(t)) } // SetReadDeadline implements the net.Conn SetReadDeadline method. func (c *Conn) SetReadDeadline(t time.Time) error { - return c.opError(opSet, c.fd.SetDeadline(t, readDeadline)) + return c.opError(opSet, c.c.SetReadDeadline(t)) } // SetWriteDeadline implements the net.Conn SetWriteDeadline method. func (c *Conn) SetWriteDeadline(t time.Time) error { - return c.opError(opSet, c.fd.SetDeadline(t, writeDeadline)) + return c.opError(opSet, c.c.SetWriteDeadline(t)) } // SyscallConn returns a raw network connection. This implements the // syscall.Conn interface. func (c *Conn) SyscallConn() (syscall.RawConn, error) { - rc, err := c.fd.SyscallConn() + rc, err := c.c.SyscallConn() if err != nil { return nil, c.opError(opSyscallConn, err) } @@ -254,14 +283,17 @@ func (c *Conn) opError(op string, err error) error { return opError(op, err, c.local, c.remote) } +// TODO(mdlayher): see if we can port smarter net.OpError with local/remote +// address error logic into socket.Conn's SyscallConn type to avoid the need for +// this wrapper. + var _ syscall.RawConn = &rawConn{} // A rawConn is a syscall.RawConn that wraps an internal syscall.RawConn in order // to produce net.OpError error values. type rawConn struct { - rc syscall.RawConn - local *Addr - remote *Addr + rc syscall.RawConn + local, remote *Addr } // Control implements the syscall.RawConn Control method. @@ -289,8 +321,7 @@ var _ net.Addr = &Addr{} // An Addr is the address of a VM sockets endpoint. type Addr struct { - ContextID uint32 - Port uint32 + ContextID, Port uint32 } // Network returns the address's network name, "vsock". @@ -304,8 +335,8 @@ func (a *Addr) String() string { switch a.ContextID { case Hypervisor: host = fmt.Sprintf("hypervisor(%d)", a.ContextID) - case cidReserved: - host = fmt.Sprintf("reserved(%d)", a.ContextID) + case Local: + host = fmt.Sprintf("local(%d)", a.ContextID) case Host: host = fmt.Sprintf("host(%d)", a.ContextID) default: @@ -338,6 +369,13 @@ func opError(op string, err error, local, remote net.Addr) error { return nil } + // TODO(mdlayher): this entire function is suspect and should probably be + // looked at carefully, especially with Go 1.13+ error wrapping. + // + // Eventually this *net.OpError logic should probably be ported into + // mdlayher/socket because similar checks are necessary to comply with + // nettest.TestConn. + // Unwrap inner errors from error types. // // TODO(mdlayher): errors.Cause or similar in Go 1.13. diff --git a/src/runtime/vendor/github.com/mdlayher/vsock/vsock_others.go b/src/runtime/vendor/github.com/mdlayher/vsock/vsock_others.go index a246de959..a5bd110aa 100644 --- a/src/runtime/vendor/github.com/mdlayher/vsock/vsock_others.go +++ b/src/runtime/vendor/github.com/mdlayher/vsock/vsock_others.go @@ -1,23 +1,23 @@ -//+build !linux +//go:build !linux +// +build !linux package vsock import ( "fmt" "net" + "os" "runtime" - "syscall" "time" ) -var ( - // errUnimplemented is returned by all functions on platforms that - // cannot make use of VM sockets. - errUnimplemented = fmt.Errorf("vsock: not implemented on %s/%s", - runtime.GOOS, runtime.GOARCH) -) +// errUnimplemented is returned by all functions on platforms that +// cannot make use of VM sockets. +var errUnimplemented = fmt.Errorf("vsock: not implemented on %s/%s", + runtime.GOOS, runtime.GOARCH) -func listen(_, _ uint32) (*Listener, error) { return nil, errUnimplemented } +func fileListener(_ *os.File) (*Listener, error) { return nil, errUnimplemented } +func listen(_, _ uint32, _ *Config) (*Listener, error) { return nil, errUnimplemented } type listener struct{} @@ -26,18 +26,7 @@ func (*listener) Addr() net.Addr { return nil } func (*listener) Close() error { return errUnimplemented } func (*listener) SetDeadline(_ time.Time) error { return errUnimplemented } -func dial(_, _ uint32) (*Conn, error) { return nil, errUnimplemented } - -type connFD struct{} - -func (*connFD) LocalAddr() net.Addr { return nil } -func (*connFD) RemoteAddr() net.Addr { return nil } -func (*connFD) SetDeadline(_ time.Time, _ deadlineType) error { return errUnimplemented } -func (*connFD) Read(_ []byte) (int, error) { return 0, errUnimplemented } -func (*connFD) Write(_ []byte) (int, error) { return 0, errUnimplemented } -func (*connFD) Close() error { return errUnimplemented } -func (*connFD) Shutdown(_ int) error { return errUnimplemented } -func (*connFD) SyscallConn() (syscall.RawConn, error) { return nil, errUnimplemented } +func dial(_, _ uint32, _ *Config) (*Conn, error) { return nil, errUnimplemented } func contextID() (uint32, error) { return 0, errUnimplemented } diff --git a/src/runtime/vendor/golang.org/x/net/bpf/asm.go b/src/runtime/vendor/golang.org/x/net/bpf/asm.go new file mode 100644 index 000000000..15e21b181 --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/bpf/asm.go @@ -0,0 +1,41 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +import "fmt" + +// Assemble converts insts into raw instructions suitable for loading +// into a BPF virtual machine. +// +// Currently, no optimization is attempted, the assembled program flow +// is exactly as provided. +func Assemble(insts []Instruction) ([]RawInstruction, error) { + ret := make([]RawInstruction, len(insts)) + var err error + for i, inst := range insts { + ret[i], err = inst.Assemble() + if err != nil { + return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err) + } + } + return ret, nil +} + +// Disassemble attempts to parse raw back into +// Instructions. Unrecognized RawInstructions are assumed to be an +// extension not implemented by this package, and are passed through +// unchanged to the output. The allDecoded value reports whether insts +// contains no RawInstructions. +func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) { + insts = make([]Instruction, len(raw)) + allDecoded = true + for i, r := range raw { + insts[i] = r.Disassemble() + if _, ok := insts[i].(RawInstruction); ok { + allDecoded = false + } + } + return insts, allDecoded +} diff --git a/src/runtime/vendor/golang.org/x/net/bpf/constants.go b/src/runtime/vendor/golang.org/x/net/bpf/constants.go new file mode 100644 index 000000000..12f3ee835 --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/bpf/constants.go @@ -0,0 +1,222 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +// A Register is a register of the BPF virtual machine. +type Register uint16 + +const ( + // RegA is the accumulator register. RegA is always the + // destination register of ALU operations. + RegA Register = iota + // RegX is the indirection register, used by LoadIndirect + // operations. + RegX +) + +// An ALUOp is an arithmetic or logic operation. +type ALUOp uint16 + +// ALU binary operation types. +const ( + ALUOpAdd ALUOp = iota << 4 + ALUOpSub + ALUOpMul + ALUOpDiv + ALUOpOr + ALUOpAnd + ALUOpShiftLeft + ALUOpShiftRight + aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type. + ALUOpMod + ALUOpXor +) + +// A JumpTest is a comparison operator used in conditional jumps. +type JumpTest uint16 + +// Supported operators for conditional jumps. +// K can be RegX for JumpIfX +const ( + // K == A + JumpEqual JumpTest = iota + // K != A + JumpNotEqual + // K > A + JumpGreaterThan + // K < A + JumpLessThan + // K >= A + JumpGreaterOrEqual + // K <= A + JumpLessOrEqual + // K & A != 0 + JumpBitsSet + // K & A == 0 + JumpBitsNotSet +) + +// An Extension is a function call provided by the kernel that +// performs advanced operations that are expensive or impossible +// within the BPF virtual machine. +// +// Extensions are only implemented by the Linux kernel. +// +// TODO: should we prune this list? Some of these extensions seem +// either broken or near-impossible to use correctly, whereas other +// (len, random, ifindex) are quite useful. +type Extension int + +// Extension functions available in the Linux kernel. +const ( + // extOffset is the negative maximum number of instructions used + // to load instructions by overloading the K argument. + extOffset = -0x1000 + // ExtLen returns the length of the packet. + ExtLen Extension = 1 + // ExtProto returns the packet's L3 protocol type. + ExtProto Extension = 0 + // ExtType returns the packet's type (skb->pkt_type in the kernel) + // + // TODO: better documentation. How nice an API do we want to + // provide for these esoteric extensions? + ExtType Extension = 4 + // ExtPayloadOffset returns the offset of the packet payload, or + // the first protocol header that the kernel does not know how to + // parse. + ExtPayloadOffset Extension = 52 + // ExtInterfaceIndex returns the index of the interface on which + // the packet was received. + ExtInterfaceIndex Extension = 8 + // ExtNetlinkAttr returns the netlink attribute of type X at + // offset A. + ExtNetlinkAttr Extension = 12 + // ExtNetlinkAttrNested returns the nested netlink attribute of + // type X at offset A. + ExtNetlinkAttrNested Extension = 16 + // ExtMark returns the packet's mark value. + ExtMark Extension = 20 + // ExtQueue returns the packet's assigned hardware queue. + ExtQueue Extension = 24 + // ExtLinkLayerType returns the packet's hardware address type + // (e.g. Ethernet, Infiniband). + ExtLinkLayerType Extension = 28 + // ExtRXHash returns the packets receive hash. + // + // TODO: figure out what this rxhash actually is. + ExtRXHash Extension = 32 + // ExtCPUID returns the ID of the CPU processing the current + // packet. + ExtCPUID Extension = 36 + // ExtVLANTag returns the packet's VLAN tag. + ExtVLANTag Extension = 44 + // ExtVLANTagPresent returns non-zero if the packet has a VLAN + // tag. + // + // TODO: I think this might be a lie: it reads bit 0x1000 of the + // VLAN header, which changed meaning in recent revisions of the + // spec - this extension may now return meaningless information. + ExtVLANTagPresent Extension = 48 + // ExtVLANProto returns 0x8100 if the frame has a VLAN header, + // 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some + // other value if no VLAN information is present. + ExtVLANProto Extension = 60 + // ExtRand returns a uniformly random uint32. + ExtRand Extension = 56 +) + +// The following gives names to various bit patterns used in opcode construction. + +const ( + opMaskCls uint16 = 0x7 + // opClsLoad masks + opMaskLoadDest = 0x01 + opMaskLoadWidth = 0x18 + opMaskLoadMode = 0xe0 + // opClsALU & opClsJump + opMaskOperand = 0x08 + opMaskOperator = 0xf0 +) + +const ( + // +---------------+-----------------+---+---+---+ + // | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 0 | + // +---------------+-----------------+---+---+---+ + opClsLoadA uint16 = iota + // +---------------+-----------------+---+---+---+ + // | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 1 | + // +---------------+-----------------+---+---+---+ + opClsLoadX + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | + // +---+---+---+---+---+---+---+---+ + opClsStoreA + // +---+---+---+---+---+---+---+---+ + // | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | + // +---+---+---+---+---+---+---+---+ + opClsStoreX + // +---------------+-----------------+---+---+---+ + // | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 | + // +---------------+-----------------+---+---+---+ + opClsALU + // +-----------------------------+---+---+---+---+ + // | TestOperator (4b) | 0 | 1 | 0 | 1 | + // +-----------------------------+---+---+---+---+ + opClsJump + // +---+-------------------------+---+---+---+---+ + // | 0 | 0 | 0 | RetSrc (1b) | 0 | 1 | 1 | 0 | + // +---+-------------------------+---+---+---+---+ + opClsReturn + // +---+-------------------------+---+---+---+---+ + // | 0 | 0 | 0 | TXAorTAX (1b) | 0 | 1 | 1 | 1 | + // +---+-------------------------+---+---+---+---+ + opClsMisc +) + +const ( + opAddrModeImmediate uint16 = iota << 5 + opAddrModeAbsolute + opAddrModeIndirect + opAddrModeScratch + opAddrModePacketLen // actually an extension, not an addressing mode. + opAddrModeMemShift +) + +const ( + opLoadWidth4 uint16 = iota << 3 + opLoadWidth2 + opLoadWidth1 +) + +// Operand for ALU and Jump instructions +type opOperand uint16 + +// Supported operand sources. +const ( + opOperandConstant opOperand = iota << 3 + opOperandX +) + +// An jumpOp is a conditional jump condition. +type jumpOp uint16 + +// Supported jump conditions. +const ( + opJumpAlways jumpOp = iota << 4 + opJumpEqual + opJumpGT + opJumpGE + opJumpSet +) + +const ( + opRetSrcConstant uint16 = iota << 4 + opRetSrcA +) + +const ( + opMiscTAX = 0x00 + opMiscTXA = 0x80 +) diff --git a/src/runtime/vendor/golang.org/x/net/bpf/doc.go b/src/runtime/vendor/golang.org/x/net/bpf/doc.go new file mode 100644 index 000000000..ae62feb53 --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/bpf/doc.go @@ -0,0 +1,82 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + +Package bpf implements marshaling and unmarshaling of programs for the +Berkeley Packet Filter virtual machine, and provides a Go implementation +of the virtual machine. + +BPF's main use is to specify a packet filter for network taps, so that +the kernel doesn't have to expensively copy every packet it sees to +userspace. However, it's been repurposed to other areas where running +user code in-kernel is needed. For example, Linux's seccomp uses BPF +to apply security policies to system calls. For simplicity, this +documentation refers only to packets, but other uses of BPF have their +own data payloads. + +BPF programs run in a restricted virtual machine. It has almost no +access to kernel functions, and while conditional branches are +allowed, they can only jump forwards, to guarantee that there are no +infinite loops. + +The virtual machine + +The BPF VM is an accumulator machine. Its main register, called +register A, is an implicit source and destination in all arithmetic +and logic operations. The machine also has 16 scratch registers for +temporary storage, and an indirection register (register X) for +indirect memory access. All registers are 32 bits wide. + +Each run of a BPF program is given one packet, which is placed in the +VM's read-only "main memory". LoadAbsolute and LoadIndirect +instructions can fetch up to 32 bits at a time into register A for +examination. + +The goal of a BPF program is to produce and return a verdict (uint32), +which tells the kernel what to do with the packet. In the context of +packet filtering, the returned value is the number of bytes of the +packet to forward to userspace, or 0 to ignore the packet. Other +contexts like seccomp define their own return values. + +In order to simplify programs, attempts to read past the end of the +packet terminate the program execution with a verdict of 0 (ignore +packet). This means that the vast majority of BPF programs don't need +to do any explicit bounds checking. + +In addition to the bytes of the packet, some BPF programs have access +to extensions, which are essentially calls to kernel utility +functions. Currently, the only extensions supported by this package +are the Linux packet filter extensions. + +Examples + +This packet filter selects all ARP packets. + + bpf.Assemble([]bpf.Instruction{ + // Load "EtherType" field from the ethernet header. + bpf.LoadAbsolute{Off: 12, Size: 2}, + // Skip over the next instruction if EtherType is not ARP. + bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0806, SkipTrue: 1}, + // Verdict is "send up to 4k of the packet to userspace." + bpf.RetConstant{Val: 4096}, + // Verdict is "ignore packet." + bpf.RetConstant{Val: 0}, + }) + +This packet filter captures a random 1% sample of traffic. + + bpf.Assemble([]bpf.Instruction{ + // Get a 32-bit random number from the Linux kernel. + bpf.LoadExtension{Num: bpf.ExtRand}, + // 1% dice roll? + bpf.JumpIf{Cond: bpf.JumpLessThan, Val: 2^32/100, SkipFalse: 1}, + // Capture. + bpf.RetConstant{Val: 4096}, + // Ignore. + bpf.RetConstant{Val: 0}, + }) + +*/ +package bpf // import "golang.org/x/net/bpf" diff --git a/src/runtime/vendor/golang.org/x/net/bpf/instructions.go b/src/runtime/vendor/golang.org/x/net/bpf/instructions.go new file mode 100644 index 000000000..3cffcaa01 --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/bpf/instructions.go @@ -0,0 +1,726 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +import "fmt" + +// An Instruction is one instruction executed by the BPF virtual +// machine. +type Instruction interface { + // Assemble assembles the Instruction into a RawInstruction. + Assemble() (RawInstruction, error) +} + +// A RawInstruction is a raw BPF virtual machine instruction. +type RawInstruction struct { + // Operation to execute. + Op uint16 + // For conditional jump instructions, the number of instructions + // to skip if the condition is true/false. + Jt uint8 + Jf uint8 + // Constant parameter. The meaning depends on the Op. + K uint32 +} + +// Assemble implements the Instruction Assemble method. +func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil } + +// Disassemble parses ri into an Instruction and returns it. If ri is +// not recognized by this package, ri itself is returned. +func (ri RawInstruction) Disassemble() Instruction { + switch ri.Op & opMaskCls { + case opClsLoadA, opClsLoadX: + reg := Register(ri.Op & opMaskLoadDest) + sz := 0 + switch ri.Op & opMaskLoadWidth { + case opLoadWidth4: + sz = 4 + case opLoadWidth2: + sz = 2 + case opLoadWidth1: + sz = 1 + default: + return ri + } + switch ri.Op & opMaskLoadMode { + case opAddrModeImmediate: + if sz != 4 { + return ri + } + return LoadConstant{Dst: reg, Val: ri.K} + case opAddrModeScratch: + if sz != 4 || ri.K > 15 { + return ri + } + return LoadScratch{Dst: reg, N: int(ri.K)} + case opAddrModeAbsolute: + if ri.K > extOffset+0xffffffff { + return LoadExtension{Num: Extension(-extOffset + ri.K)} + } + return LoadAbsolute{Size: sz, Off: ri.K} + case opAddrModeIndirect: + return LoadIndirect{Size: sz, Off: ri.K} + case opAddrModePacketLen: + if sz != 4 { + return ri + } + return LoadExtension{Num: ExtLen} + case opAddrModeMemShift: + return LoadMemShift{Off: ri.K} + default: + return ri + } + + case opClsStoreA: + if ri.Op != opClsStoreA || ri.K > 15 { + return ri + } + return StoreScratch{Src: RegA, N: int(ri.K)} + + case opClsStoreX: + if ri.Op != opClsStoreX || ri.K > 15 { + return ri + } + return StoreScratch{Src: RegX, N: int(ri.K)} + + case opClsALU: + switch op := ALUOp(ri.Op & opMaskOperator); op { + case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor: + switch operand := opOperand(ri.Op & opMaskOperand); operand { + case opOperandX: + return ALUOpX{Op: op} + case opOperandConstant: + return ALUOpConstant{Op: op, Val: ri.K} + default: + return ri + } + case aluOpNeg: + return NegateA{} + default: + return ri + } + + case opClsJump: + switch op := jumpOp(ri.Op & opMaskOperator); op { + case opJumpAlways: + return Jump{Skip: ri.K} + case opJumpEqual, opJumpGT, opJumpGE, opJumpSet: + cond, skipTrue, skipFalse := jumpOpToTest(op, ri.Jt, ri.Jf) + switch operand := opOperand(ri.Op & opMaskOperand); operand { + case opOperandX: + return JumpIfX{Cond: cond, SkipTrue: skipTrue, SkipFalse: skipFalse} + case opOperandConstant: + return JumpIf{Cond: cond, Val: ri.K, SkipTrue: skipTrue, SkipFalse: skipFalse} + default: + return ri + } + default: + return ri + } + + case opClsReturn: + switch ri.Op { + case opClsReturn | opRetSrcA: + return RetA{} + case opClsReturn | opRetSrcConstant: + return RetConstant{Val: ri.K} + default: + return ri + } + + case opClsMisc: + switch ri.Op { + case opClsMisc | opMiscTAX: + return TAX{} + case opClsMisc | opMiscTXA: + return TXA{} + default: + return ri + } + + default: + panic("unreachable") // switch is exhaustive on the bit pattern + } +} + +func jumpOpToTest(op jumpOp, skipTrue uint8, skipFalse uint8) (JumpTest, uint8, uint8) { + var test JumpTest + + // Decode "fake" jump conditions that don't appear in machine code + // Ensures the Assemble -> Disassemble stage recreates the same instructions + // See https://github.com/golang/go/issues/18470 + if skipTrue == 0 { + switch op { + case opJumpEqual: + test = JumpNotEqual + case opJumpGT: + test = JumpLessOrEqual + case opJumpGE: + test = JumpLessThan + case opJumpSet: + test = JumpBitsNotSet + } + + return test, skipFalse, 0 + } + + switch op { + case opJumpEqual: + test = JumpEqual + case opJumpGT: + test = JumpGreaterThan + case opJumpGE: + test = JumpGreaterOrEqual + case opJumpSet: + test = JumpBitsSet + } + + return test, skipTrue, skipFalse +} + +// LoadConstant loads Val into register Dst. +type LoadConstant struct { + Dst Register + Val uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadConstant) Assemble() (RawInstruction, error) { + return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val) +} + +// String returns the instruction in assembler notation. +func (a LoadConstant) String() string { + switch a.Dst { + case RegA: + return fmt.Sprintf("ld #%d", a.Val) + case RegX: + return fmt.Sprintf("ldx #%d", a.Val) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// LoadScratch loads scratch[N] into register Dst. +type LoadScratch struct { + Dst Register + N int // 0-15 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadScratch) Assemble() (RawInstruction, error) { + if a.N < 0 || a.N > 15 { + return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N) + } + return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N)) +} + +// String returns the instruction in assembler notation. +func (a LoadScratch) String() string { + switch a.Dst { + case RegA: + return fmt.Sprintf("ld M[%d]", a.N) + case RegX: + return fmt.Sprintf("ldx M[%d]", a.N) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// LoadAbsolute loads packet[Off:Off+Size] as an integer value into +// register A. +type LoadAbsolute struct { + Off uint32 + Size int // 1, 2 or 4 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadAbsolute) Assemble() (RawInstruction, error) { + return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off) +} + +// String returns the instruction in assembler notation. +func (a LoadAbsolute) String() string { + switch a.Size { + case 1: // byte + return fmt.Sprintf("ldb [%d]", a.Off) + case 2: // half word + return fmt.Sprintf("ldh [%d]", a.Off) + case 4: // word + if a.Off > extOffset+0xffffffff { + return LoadExtension{Num: Extension(a.Off + 0x1000)}.String() + } + return fmt.Sprintf("ld [%d]", a.Off) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value +// into register A. +type LoadIndirect struct { + Off uint32 + Size int // 1, 2 or 4 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadIndirect) Assemble() (RawInstruction, error) { + return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off) +} + +// String returns the instruction in assembler notation. +func (a LoadIndirect) String() string { + switch a.Size { + case 1: // byte + return fmt.Sprintf("ldb [x + %d]", a.Off) + case 2: // half word + return fmt.Sprintf("ldh [x + %d]", a.Off) + case 4: // word + return fmt.Sprintf("ld [x + %d]", a.Off) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// LoadMemShift multiplies the first 4 bits of the byte at packet[Off] +// by 4 and stores the result in register X. +// +// This instruction is mainly useful to load into X the length of an +// IPv4 packet header in a single instruction, rather than have to do +// the arithmetic on the header's first byte by hand. +type LoadMemShift struct { + Off uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a LoadMemShift) Assemble() (RawInstruction, error) { + return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off) +} + +// String returns the instruction in assembler notation. +func (a LoadMemShift) String() string { + return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off) +} + +// LoadExtension invokes a linux-specific extension and stores the +// result in register A. +type LoadExtension struct { + Num Extension +} + +// Assemble implements the Instruction Assemble method. +func (a LoadExtension) Assemble() (RawInstruction, error) { + if a.Num == ExtLen { + return assembleLoad(RegA, 4, opAddrModePacketLen, 0) + } + return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num)) +} + +// String returns the instruction in assembler notation. +func (a LoadExtension) String() string { + switch a.Num { + case ExtLen: + return "ld #len" + case ExtProto: + return "ld #proto" + case ExtType: + return "ld #type" + case ExtPayloadOffset: + return "ld #poff" + case ExtInterfaceIndex: + return "ld #ifidx" + case ExtNetlinkAttr: + return "ld #nla" + case ExtNetlinkAttrNested: + return "ld #nlan" + case ExtMark: + return "ld #mark" + case ExtQueue: + return "ld #queue" + case ExtLinkLayerType: + return "ld #hatype" + case ExtRXHash: + return "ld #rxhash" + case ExtCPUID: + return "ld #cpu" + case ExtVLANTag: + return "ld #vlan_tci" + case ExtVLANTagPresent: + return "ld #vlan_avail" + case ExtVLANProto: + return "ld #vlan_tpid" + case ExtRand: + return "ld #rand" + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// StoreScratch stores register Src into scratch[N]. +type StoreScratch struct { + Src Register + N int // 0-15 +} + +// Assemble implements the Instruction Assemble method. +func (a StoreScratch) Assemble() (RawInstruction, error) { + if a.N < 0 || a.N > 15 { + return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N) + } + var op uint16 + switch a.Src { + case RegA: + op = opClsStoreA + case RegX: + op = opClsStoreX + default: + return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src) + } + + return RawInstruction{ + Op: op, + K: uint32(a.N), + }, nil +} + +// String returns the instruction in assembler notation. +func (a StoreScratch) String() string { + switch a.Src { + case RegA: + return fmt.Sprintf("st M[%d]", a.N) + case RegX: + return fmt.Sprintf("stx M[%d]", a.N) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// ALUOpConstant executes A = A Val. +type ALUOpConstant struct { + Op ALUOp + Val uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a ALUOpConstant) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsALU | uint16(opOperandConstant) | uint16(a.Op), + K: a.Val, + }, nil +} + +// String returns the instruction in assembler notation. +func (a ALUOpConstant) String() string { + switch a.Op { + case ALUOpAdd: + return fmt.Sprintf("add #%d", a.Val) + case ALUOpSub: + return fmt.Sprintf("sub #%d", a.Val) + case ALUOpMul: + return fmt.Sprintf("mul #%d", a.Val) + case ALUOpDiv: + return fmt.Sprintf("div #%d", a.Val) + case ALUOpMod: + return fmt.Sprintf("mod #%d", a.Val) + case ALUOpAnd: + return fmt.Sprintf("and #%d", a.Val) + case ALUOpOr: + return fmt.Sprintf("or #%d", a.Val) + case ALUOpXor: + return fmt.Sprintf("xor #%d", a.Val) + case ALUOpShiftLeft: + return fmt.Sprintf("lsh #%d", a.Val) + case ALUOpShiftRight: + return fmt.Sprintf("rsh #%d", a.Val) + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// ALUOpX executes A = A X +type ALUOpX struct { + Op ALUOp +} + +// Assemble implements the Instruction Assemble method. +func (a ALUOpX) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsALU | uint16(opOperandX) | uint16(a.Op), + }, nil +} + +// String returns the instruction in assembler notation. +func (a ALUOpX) String() string { + switch a.Op { + case ALUOpAdd: + return "add x" + case ALUOpSub: + return "sub x" + case ALUOpMul: + return "mul x" + case ALUOpDiv: + return "div x" + case ALUOpMod: + return "mod x" + case ALUOpAnd: + return "and x" + case ALUOpOr: + return "or x" + case ALUOpXor: + return "xor x" + case ALUOpShiftLeft: + return "lsh x" + case ALUOpShiftRight: + return "rsh x" + default: + return fmt.Sprintf("unknown instruction: %#v", a) + } +} + +// NegateA executes A = -A. +type NegateA struct{} + +// Assemble implements the Instruction Assemble method. +func (a NegateA) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsALU | uint16(aluOpNeg), + }, nil +} + +// String returns the instruction in assembler notation. +func (a NegateA) String() string { + return fmt.Sprintf("neg") +} + +// Jump skips the following Skip instructions in the program. +type Jump struct { + Skip uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a Jump) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsJump | uint16(opJumpAlways), + K: a.Skip, + }, nil +} + +// String returns the instruction in assembler notation. +func (a Jump) String() string { + return fmt.Sprintf("ja %d", a.Skip) +} + +// JumpIf skips the following Skip instructions in the program if A +// Val is true. +type JumpIf struct { + Cond JumpTest + Val uint32 + SkipTrue uint8 + SkipFalse uint8 +} + +// Assemble implements the Instruction Assemble method. +func (a JumpIf) Assemble() (RawInstruction, error) { + return jumpToRaw(a.Cond, opOperandConstant, a.Val, a.SkipTrue, a.SkipFalse) +} + +// String returns the instruction in assembler notation. +func (a JumpIf) String() string { + return jumpToString(a.Cond, fmt.Sprintf("#%d", a.Val), a.SkipTrue, a.SkipFalse) +} + +// JumpIfX skips the following Skip instructions in the program if A +// X is true. +type JumpIfX struct { + Cond JumpTest + SkipTrue uint8 + SkipFalse uint8 +} + +// Assemble implements the Instruction Assemble method. +func (a JumpIfX) Assemble() (RawInstruction, error) { + return jumpToRaw(a.Cond, opOperandX, 0, a.SkipTrue, a.SkipFalse) +} + +// String returns the instruction in assembler notation. +func (a JumpIfX) String() string { + return jumpToString(a.Cond, "x", a.SkipTrue, a.SkipFalse) +} + +// jumpToRaw assembles a jump instruction into a RawInstruction +func jumpToRaw(test JumpTest, operand opOperand, k uint32, skipTrue, skipFalse uint8) (RawInstruction, error) { + var ( + cond jumpOp + flip bool + ) + switch test { + case JumpEqual: + cond = opJumpEqual + case JumpNotEqual: + cond, flip = opJumpEqual, true + case JumpGreaterThan: + cond = opJumpGT + case JumpLessThan: + cond, flip = opJumpGE, true + case JumpGreaterOrEqual: + cond = opJumpGE + case JumpLessOrEqual: + cond, flip = opJumpGT, true + case JumpBitsSet: + cond = opJumpSet + case JumpBitsNotSet: + cond, flip = opJumpSet, true + default: + return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", test) + } + jt, jf := skipTrue, skipFalse + if flip { + jt, jf = jf, jt + } + return RawInstruction{ + Op: opClsJump | uint16(cond) | uint16(operand), + Jt: jt, + Jf: jf, + K: k, + }, nil +} + +// jumpToString converts a jump instruction to assembler notation +func jumpToString(cond JumpTest, operand string, skipTrue, skipFalse uint8) string { + switch cond { + // K == A + case JumpEqual: + return conditionalJump(operand, skipTrue, skipFalse, "jeq", "jneq") + // K != A + case JumpNotEqual: + return fmt.Sprintf("jneq %s,%d", operand, skipTrue) + // K > A + case JumpGreaterThan: + return conditionalJump(operand, skipTrue, skipFalse, "jgt", "jle") + // K < A + case JumpLessThan: + return fmt.Sprintf("jlt %s,%d", operand, skipTrue) + // K >= A + case JumpGreaterOrEqual: + return conditionalJump(operand, skipTrue, skipFalse, "jge", "jlt") + // K <= A + case JumpLessOrEqual: + return fmt.Sprintf("jle %s,%d", operand, skipTrue) + // K & A != 0 + case JumpBitsSet: + if skipFalse > 0 { + return fmt.Sprintf("jset %s,%d,%d", operand, skipTrue, skipFalse) + } + return fmt.Sprintf("jset %s,%d", operand, skipTrue) + // K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips + case JumpBitsNotSet: + return jumpToString(JumpBitsSet, operand, skipFalse, skipTrue) + default: + return fmt.Sprintf("unknown JumpTest %#v", cond) + } +} + +func conditionalJump(operand string, skipTrue, skipFalse uint8, positiveJump, negativeJump string) string { + if skipTrue > 0 { + if skipFalse > 0 { + return fmt.Sprintf("%s %s,%d,%d", positiveJump, operand, skipTrue, skipFalse) + } + return fmt.Sprintf("%s %s,%d", positiveJump, operand, skipTrue) + } + return fmt.Sprintf("%s %s,%d", negativeJump, operand, skipFalse) +} + +// RetA exits the BPF program, returning the value of register A. +type RetA struct{} + +// Assemble implements the Instruction Assemble method. +func (a RetA) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsReturn | opRetSrcA, + }, nil +} + +// String returns the instruction in assembler notation. +func (a RetA) String() string { + return fmt.Sprintf("ret a") +} + +// RetConstant exits the BPF program, returning a constant value. +type RetConstant struct { + Val uint32 +} + +// Assemble implements the Instruction Assemble method. +func (a RetConstant) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsReturn | opRetSrcConstant, + K: a.Val, + }, nil +} + +// String returns the instruction in assembler notation. +func (a RetConstant) String() string { + return fmt.Sprintf("ret #%d", a.Val) +} + +// TXA copies the value of register X to register A. +type TXA struct{} + +// Assemble implements the Instruction Assemble method. +func (a TXA) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsMisc | opMiscTXA, + }, nil +} + +// String returns the instruction in assembler notation. +func (a TXA) String() string { + return fmt.Sprintf("txa") +} + +// TAX copies the value of register A to register X. +type TAX struct{} + +// Assemble implements the Instruction Assemble method. +func (a TAX) Assemble() (RawInstruction, error) { + return RawInstruction{ + Op: opClsMisc | opMiscTAX, + }, nil +} + +// String returns the instruction in assembler notation. +func (a TAX) String() string { + return fmt.Sprintf("tax") +} + +func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) { + var ( + cls uint16 + sz uint16 + ) + switch dst { + case RegA: + cls = opClsLoadA + case RegX: + cls = opClsLoadX + default: + return RawInstruction{}, fmt.Errorf("invalid target register %v", dst) + } + switch loadSize { + case 1: + sz = opLoadWidth1 + case 2: + sz = opLoadWidth2 + case 4: + sz = opLoadWidth4 + default: + return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz) + } + return RawInstruction{ + Op: cls | sz | mode, + K: k, + }, nil +} diff --git a/src/runtime/vendor/golang.org/x/net/bpf/setter.go b/src/runtime/vendor/golang.org/x/net/bpf/setter.go new file mode 100644 index 000000000..43e35f0ac --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/bpf/setter.go @@ -0,0 +1,10 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +// A Setter is a type which can attach a compiled BPF filter to itself. +type Setter interface { + SetBPF(filter []RawInstruction) error +} diff --git a/src/runtime/vendor/golang.org/x/net/bpf/vm.go b/src/runtime/vendor/golang.org/x/net/bpf/vm.go new file mode 100644 index 000000000..73f57f1f7 --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/bpf/vm.go @@ -0,0 +1,150 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +import ( + "errors" + "fmt" +) + +// A VM is an emulated BPF virtual machine. +type VM struct { + filter []Instruction +} + +// NewVM returns a new VM using the input BPF program. +func NewVM(filter []Instruction) (*VM, error) { + if len(filter) == 0 { + return nil, errors.New("one or more Instructions must be specified") + } + + for i, ins := range filter { + check := len(filter) - (i + 1) + switch ins := ins.(type) { + // Check for out-of-bounds jumps in instructions + case Jump: + if check <= int(ins.Skip) { + return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip) + } + case JumpIf: + if check <= int(ins.SkipTrue) { + return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue) + } + if check <= int(ins.SkipFalse) { + return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse) + } + case JumpIfX: + if check <= int(ins.SkipTrue) { + return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue) + } + if check <= int(ins.SkipFalse) { + return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse) + } + // Check for division or modulus by zero + case ALUOpConstant: + if ins.Val != 0 { + break + } + + switch ins.Op { + case ALUOpDiv, ALUOpMod: + return nil, errors.New("cannot divide by zero using ALUOpConstant") + } + // Check for unknown extensions + case LoadExtension: + switch ins.Num { + case ExtLen: + default: + return nil, fmt.Errorf("extension %d not implemented", ins.Num) + } + } + } + + // Make sure last instruction is a return instruction + switch filter[len(filter)-1].(type) { + case RetA, RetConstant: + default: + return nil, errors.New("BPF program must end with RetA or RetConstant") + } + + // Though our VM works using disassembled instructions, we + // attempt to assemble the input filter anyway to ensure it is compatible + // with an operating system VM. + _, err := Assemble(filter) + + return &VM{ + filter: filter, + }, err +} + +// Run runs the VM's BPF program against the input bytes. +// Run returns the number of bytes accepted by the BPF program, and any errors +// which occurred while processing the program. +func (v *VM) Run(in []byte) (int, error) { + var ( + // Registers of the virtual machine + regA uint32 + regX uint32 + regScratch [16]uint32 + + // OK is true if the program should continue processing the next + // instruction, or false if not, causing the loop to break + ok = true + ) + + // TODO(mdlayher): implement: + // - NegateA: + // - would require a change from uint32 registers to int32 + // registers + + // TODO(mdlayher): add interop tests that check signedness of ALU + // operations against kernel implementation, and make sure Go + // implementation matches behavior + + for i := 0; i < len(v.filter) && ok; i++ { + ins := v.filter[i] + + switch ins := ins.(type) { + case ALUOpConstant: + regA = aluOpConstant(ins, regA) + case ALUOpX: + regA, ok = aluOpX(ins, regA, regX) + case Jump: + i += int(ins.Skip) + case JumpIf: + jump := jumpIf(ins, regA) + i += jump + case JumpIfX: + jump := jumpIfX(ins, regA, regX) + i += jump + case LoadAbsolute: + regA, ok = loadAbsolute(ins, in) + case LoadConstant: + regA, regX = loadConstant(ins, regA, regX) + case LoadExtension: + regA = loadExtension(ins, in) + case LoadIndirect: + regA, ok = loadIndirect(ins, in, regX) + case LoadMemShift: + regX, ok = loadMemShift(ins, in) + case LoadScratch: + regA, regX = loadScratch(ins, regScratch, regA, regX) + case RetA: + return int(regA), nil + case RetConstant: + return int(ins.Val), nil + case StoreScratch: + regScratch = storeScratch(ins, regScratch, regA, regX) + case TAX: + regX = regA + case TXA: + regA = regX + default: + return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins) + } + } + + return 0, nil +} diff --git a/src/runtime/vendor/golang.org/x/net/bpf/vm_instructions.go b/src/runtime/vendor/golang.org/x/net/bpf/vm_instructions.go new file mode 100644 index 000000000..cf8947c33 --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/bpf/vm_instructions.go @@ -0,0 +1,182 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bpf + +import ( + "encoding/binary" + "fmt" +) + +func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 { + return aluOpCommon(ins.Op, regA, ins.Val) +} + +func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) { + // Guard against division or modulus by zero by terminating + // the program, as the OS BPF VM does + if regX == 0 { + switch ins.Op { + case ALUOpDiv, ALUOpMod: + return 0, false + } + } + + return aluOpCommon(ins.Op, regA, regX), true +} + +func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 { + switch op { + case ALUOpAdd: + return regA + value + case ALUOpSub: + return regA - value + case ALUOpMul: + return regA * value + case ALUOpDiv: + // Division by zero not permitted by NewVM and aluOpX checks + return regA / value + case ALUOpOr: + return regA | value + case ALUOpAnd: + return regA & value + case ALUOpShiftLeft: + return regA << value + case ALUOpShiftRight: + return regA >> value + case ALUOpMod: + // Modulus by zero not permitted by NewVM and aluOpX checks + return regA % value + case ALUOpXor: + return regA ^ value + default: + return regA + } +} + +func jumpIf(ins JumpIf, regA uint32) int { + return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val) +} + +func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int { + return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX) +} + +func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int { + var ok bool + + switch cond { + case JumpEqual: + ok = regA == value + case JumpNotEqual: + ok = regA != value + case JumpGreaterThan: + ok = regA > value + case JumpLessThan: + ok = regA < value + case JumpGreaterOrEqual: + ok = regA >= value + case JumpLessOrEqual: + ok = regA <= value + case JumpBitsSet: + ok = (regA & value) != 0 + case JumpBitsNotSet: + ok = (regA & value) == 0 + } + + if ok { + return int(skipTrue) + } + + return int(skipFalse) +} + +func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) { + offset := int(ins.Off) + size := int(ins.Size) + + return loadCommon(in, offset, size) +} + +func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) { + switch ins.Dst { + case RegA: + regA = ins.Val + case RegX: + regX = ins.Val + } + + return regA, regX +} + +func loadExtension(ins LoadExtension, in []byte) uint32 { + switch ins.Num { + case ExtLen: + return uint32(len(in)) + default: + panic(fmt.Sprintf("unimplemented extension: %d", ins.Num)) + } +} + +func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) { + offset := int(ins.Off) + int(regX) + size := int(ins.Size) + + return loadCommon(in, offset, size) +} + +func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) { + offset := int(ins.Off) + + // Size of LoadMemShift is always 1 byte + if !inBounds(len(in), offset, 1) { + return 0, false + } + + // Mask off high 4 bits and multiply low 4 bits by 4 + return uint32(in[offset]&0x0f) * 4, true +} + +func inBounds(inLen int, offset int, size int) bool { + return offset+size <= inLen +} + +func loadCommon(in []byte, offset int, size int) (uint32, bool) { + if !inBounds(len(in), offset, size) { + return 0, false + } + + switch size { + case 1: + return uint32(in[offset]), true + case 2: + return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true + case 4: + return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true + default: + panic(fmt.Sprintf("invalid load size: %d", size)) + } +} + +func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) { + switch ins.Dst { + case RegA: + regA = regScratch[ins.N] + case RegX: + regX = regScratch[ins.N] + } + + return regA, regX +} + +func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 { + switch ins.Src { + case RegA: + regScratch[ins.N] = regA + case RegX: + regScratch[ins.N] = regX + } + + return regScratch +} diff --git a/src/runtime/vendor/golang.org/x/net/http2/client_conn_pool.go b/src/runtime/vendor/golang.org/x/net/http2/client_conn_pool.go index 652bc11a0..c936843ea 100644 --- a/src/runtime/vendor/golang.org/x/net/http2/client_conn_pool.go +++ b/src/runtime/vendor/golang.org/x/net/http2/client_conn_pool.go @@ -16,6 +16,12 @@ import ( // ClientConnPool manages a pool of HTTP/2 client connections. type ClientConnPool interface { + // GetClientConn returns a specific HTTP/2 connection (usually + // a TLS-TCP connection) to an HTTP/2 server. On success, the + // returned ClientConn accounts for the upcoming RoundTrip + // call, so the caller should not omit it. If the caller needs + // to, ClientConn.RoundTrip can be called with a bogus + // new(http.Request) to release the stream reservation. GetClientConn(req *http.Request, addr string) (*ClientConn, error) MarkDead(*ClientConn) } @@ -42,7 +48,7 @@ type clientConnPool struct { conns map[string][]*ClientConn // key is host:port dialing map[string]*dialCall // currently in-flight dials keys map[*ClientConn][]string - addConnCalls map[string]*addConnCall // in-flight addConnIfNeede calls + addConnCalls map[string]*addConnCall // in-flight addConnIfNeeded calls } func (p *clientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) { @@ -54,28 +60,8 @@ const ( noDialOnMiss = false ) -// shouldTraceGetConn reports whether getClientConn should call any -// ClientTrace.GetConn hook associated with the http.Request. -// -// This complexity is needed to avoid double calls of the GetConn hook -// during the back-and-forth between net/http and x/net/http2 (when the -// net/http.Transport is upgraded to also speak http2), as well as support -// the case where x/net/http2 is being used directly. -func (p *clientConnPool) shouldTraceGetConn(st clientConnIdleState) bool { - // If our Transport wasn't made via ConfigureTransport, always - // trace the GetConn hook if provided, because that means the - // http2 package is being used directly and it's the one - // dialing, as opposed to net/http. - if _, ok := p.t.ConnPool.(noDialClientConnPool); !ok { - return true - } - // Otherwise, only use the GetConn hook if this connection has - // been used previously for other requests. For fresh - // connections, the net/http package does the dialing. - return !st.freshConn -} - func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) { + // TODO(dneil): Dial a new connection when t.DisableKeepAlives is set? if isConnectionCloseRequest(req) && dialOnMiss { // It gets its own connection. traceGetConn(req, addr) @@ -89,10 +75,14 @@ func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMis for { p.mu.Lock() for _, cc := range p.conns[addr] { - if st := cc.idleState(); st.canTakeNewRequest { - if p.shouldTraceGetConn(st) { + if cc.ReserveNewRequest() { + // When a connection is presented to us by the net/http package, + // the GetConn hook has already been called. + // Don't call it a second time here. + if !cc.getConnCalled { traceGetConn(req, addr) } + cc.getConnCalled = false p.mu.Unlock() return cc, nil } @@ -108,7 +98,13 @@ func (p *clientConnPool) getClientConn(req *http.Request, addr string, dialOnMis if shouldRetryDial(call, req) { continue } - return call.res, call.err + cc, err := call.res, call.err + if err != nil { + return nil, err + } + if cc.ReserveNewRequest() { + return cc, nil + } } } @@ -205,6 +201,7 @@ func (c *addConnCall) run(t *Transport, key string, tc *tls.Conn) { if err != nil { c.err = err } else { + cc.getConnCalled = true // already called by the net/http package p.addConnLocked(key, cc) } delete(p.addConnCalls, key) diff --git a/src/runtime/vendor/golang.org/x/net/http2/errors.go b/src/runtime/vendor/golang.org/x/net/http2/errors.go index 71f2c4631..2663e5d28 100644 --- a/src/runtime/vendor/golang.org/x/net/http2/errors.go +++ b/src/runtime/vendor/golang.org/x/net/http2/errors.go @@ -53,6 +53,13 @@ func (e ErrCode) String() string { return fmt.Sprintf("unknown error code 0x%x", uint32(e)) } +func (e ErrCode) stringToken() string { + if s, ok := errCodeName[e]; ok { + return s + } + return fmt.Sprintf("ERR_UNKNOWN_%d", uint32(e)) +} + // ConnectionError is an error that results in the termination of the // entire connection. type ConnectionError ErrCode @@ -67,6 +74,11 @@ type StreamError struct { Cause error // optional additional detail } +// errFromPeer is a sentinel error value for StreamError.Cause to +// indicate that the StreamError was sent from the peer over the wire +// and wasn't locally generated in the Transport. +var errFromPeer = errors.New("received from peer") + func streamError(id uint32, code ErrCode) StreamError { return StreamError{StreamID: id, Code: code} } diff --git a/src/runtime/vendor/golang.org/x/net/http2/frame.go b/src/runtime/vendor/golang.org/x/net/http2/frame.go index 514c126c5..96a747905 100644 --- a/src/runtime/vendor/golang.org/x/net/http2/frame.go +++ b/src/runtime/vendor/golang.org/x/net/http2/frame.go @@ -122,7 +122,7 @@ var flagName = map[FrameType]map[Flags]string{ // a frameParser parses a frame given its FrameHeader and payload // bytes. The length of payload will always equal fh.Length (which // might be 0). -type frameParser func(fc *frameCache, fh FrameHeader, payload []byte) (Frame, error) +type frameParser func(fc *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) var frameParsers = map[FrameType]frameParser{ FrameData: parseDataFrame, @@ -267,6 +267,11 @@ type Framer struct { lastFrame Frame errDetail error + // countError is a non-nil func that's called on a frame parse + // error with some unique error path token. It's initialized + // from Transport.CountError or Server.CountError. + countError func(errToken string) + // lastHeaderStream is non-zero if the last frame was an // unfinished HEADERS/CONTINUATION. lastHeaderStream uint32 @@ -426,6 +431,7 @@ func NewFramer(w io.Writer, r io.Reader) *Framer { fr := &Framer{ w: w, r: r, + countError: func(string) {}, logReads: logFrameReads, logWrites: logFrameWrites, debugReadLoggerf: log.Printf, @@ -500,7 +506,7 @@ func (fr *Framer) ReadFrame() (Frame, error) { if _, err := io.ReadFull(fr.r, payload); err != nil { return nil, err } - f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, payload) + f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, fr.countError, payload) if err != nil { if ce, ok := err.(connError); ok { return nil, fr.connError(ce.Code, ce.Reason) @@ -588,13 +594,14 @@ func (f *DataFrame) Data() []byte { return f.data } -func parseDataFrame(fc *frameCache, fh FrameHeader, payload []byte) (Frame, error) { +func parseDataFrame(fc *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) { if fh.StreamID == 0 { // DATA frames MUST be associated with a stream. If a // DATA frame is received whose stream identifier // field is 0x0, the recipient MUST respond with a // connection error (Section 5.4.1) of type // PROTOCOL_ERROR. + countError("frame_data_stream_0") return nil, connError{ErrCodeProtocol, "DATA frame with stream ID 0"} } f := fc.getDataFrame() @@ -605,6 +612,7 @@ func parseDataFrame(fc *frameCache, fh FrameHeader, payload []byte) (Frame, erro var err error payload, padSize, err = readByte(payload) if err != nil { + countError("frame_data_pad_byte_short") return nil, err } } @@ -613,6 +621,7 @@ func parseDataFrame(fc *frameCache, fh FrameHeader, payload []byte) (Frame, erro // length of the frame payload, the recipient MUST // treat this as a connection error. // Filed: https://github.com/http2/http2-spec/issues/610 + countError("frame_data_pad_too_big") return nil, connError{ErrCodeProtocol, "pad size larger than data payload"} } f.data = payload[:len(payload)-int(padSize)] @@ -695,7 +704,7 @@ type SettingsFrame struct { p []byte } -func parseSettingsFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { +func parseSettingsFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) { if fh.Flags.Has(FlagSettingsAck) && fh.Length > 0 { // When this (ACK 0x1) bit is set, the payload of the // SETTINGS frame MUST be empty. Receipt of a @@ -703,6 +712,7 @@ func parseSettingsFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) // field value other than 0 MUST be treated as a // connection error (Section 5.4.1) of type // FRAME_SIZE_ERROR. + countError("frame_settings_ack_with_length") return nil, ConnectionError(ErrCodeFrameSize) } if fh.StreamID != 0 { @@ -713,14 +723,17 @@ func parseSettingsFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) // field is anything other than 0x0, the endpoint MUST // respond with a connection error (Section 5.4.1) of // type PROTOCOL_ERROR. + countError("frame_settings_has_stream") return nil, ConnectionError(ErrCodeProtocol) } if len(p)%6 != 0 { + countError("frame_settings_mod_6") // Expecting even number of 6 byte settings. return nil, ConnectionError(ErrCodeFrameSize) } f := &SettingsFrame{FrameHeader: fh, p: p} if v, ok := f.Value(SettingInitialWindowSize); ok && v > (1<<31)-1 { + countError("frame_settings_window_size_too_big") // Values above the maximum flow control window size of 2^31 - 1 MUST // be treated as a connection error (Section 5.4.1) of type // FLOW_CONTROL_ERROR. @@ -832,11 +845,13 @@ type PingFrame struct { func (f *PingFrame) IsAck() bool { return f.Flags.Has(FlagPingAck) } -func parsePingFrame(_ *frameCache, fh FrameHeader, payload []byte) (Frame, error) { +func parsePingFrame(_ *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) { if len(payload) != 8 { + countError("frame_ping_length") return nil, ConnectionError(ErrCodeFrameSize) } if fh.StreamID != 0 { + countError("frame_ping_has_stream") return nil, ConnectionError(ErrCodeProtocol) } f := &PingFrame{FrameHeader: fh} @@ -872,11 +887,13 @@ func (f *GoAwayFrame) DebugData() []byte { return f.debugData } -func parseGoAwayFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { +func parseGoAwayFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) { if fh.StreamID != 0 { + countError("frame_goaway_has_stream") return nil, ConnectionError(ErrCodeProtocol) } if len(p) < 8 { + countError("frame_goaway_short") return nil, ConnectionError(ErrCodeFrameSize) } return &GoAwayFrame{ @@ -912,7 +929,7 @@ func (f *UnknownFrame) Payload() []byte { return f.p } -func parseUnknownFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { +func parseUnknownFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) { return &UnknownFrame{fh, p}, nil } @@ -923,8 +940,9 @@ type WindowUpdateFrame struct { Increment uint32 // never read with high bit set } -func parseWindowUpdateFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { +func parseWindowUpdateFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) { if len(p) != 4 { + countError("frame_windowupdate_bad_len") return nil, ConnectionError(ErrCodeFrameSize) } inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit @@ -936,8 +954,10 @@ func parseWindowUpdateFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, err // control window MUST be treated as a connection // error (Section 5.4.1). if fh.StreamID == 0 { + countError("frame_windowupdate_zero_inc_conn") return nil, ConnectionError(ErrCodeProtocol) } + countError("frame_windowupdate_zero_inc_stream") return nil, streamError(fh.StreamID, ErrCodeProtocol) } return &WindowUpdateFrame{ @@ -988,7 +1008,7 @@ func (f *HeadersFrame) HasPriority() bool { return f.FrameHeader.Flags.Has(FlagHeadersPriority) } -func parseHeadersFrame(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err error) { +func parseHeadersFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (_ Frame, err error) { hf := &HeadersFrame{ FrameHeader: fh, } @@ -997,11 +1017,13 @@ func parseHeadersFrame(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err er // is received whose stream identifier field is 0x0, the recipient MUST // respond with a connection error (Section 5.4.1) of type // PROTOCOL_ERROR. + countError("frame_headers_zero_stream") return nil, connError{ErrCodeProtocol, "HEADERS frame with stream ID 0"} } var padLength uint8 if fh.Flags.Has(FlagHeadersPadded) { if p, padLength, err = readByte(p); err != nil { + countError("frame_headers_pad_short") return } } @@ -1009,16 +1031,19 @@ func parseHeadersFrame(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err er var v uint32 p, v, err = readUint32(p) if err != nil { + countError("frame_headers_prio_short") return nil, err } hf.Priority.StreamDep = v & 0x7fffffff hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set p, hf.Priority.Weight, err = readByte(p) if err != nil { + countError("frame_headers_prio_weight_short") return nil, err } } - if len(p)-int(padLength) <= 0 { + if len(p)-int(padLength) < 0 { + countError("frame_headers_pad_too_big") return nil, streamError(fh.StreamID, ErrCodeProtocol) } hf.headerFragBuf = p[:len(p)-int(padLength)] @@ -1125,11 +1150,13 @@ func (p PriorityParam) IsZero() bool { return p == PriorityParam{} } -func parsePriorityFrame(_ *frameCache, fh FrameHeader, payload []byte) (Frame, error) { +func parsePriorityFrame(_ *frameCache, fh FrameHeader, countError func(string), payload []byte) (Frame, error) { if fh.StreamID == 0 { + countError("frame_priority_zero_stream") return nil, connError{ErrCodeProtocol, "PRIORITY frame with stream ID 0"} } if len(payload) != 5 { + countError("frame_priority_bad_length") return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))} } v := binary.BigEndian.Uint32(payload[:4]) @@ -1172,11 +1199,13 @@ type RSTStreamFrame struct { ErrCode ErrCode } -func parseRSTStreamFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { +func parseRSTStreamFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) { if len(p) != 4 { + countError("frame_rststream_bad_len") return nil, ConnectionError(ErrCodeFrameSize) } if fh.StreamID == 0 { + countError("frame_rststream_zero_stream") return nil, ConnectionError(ErrCodeProtocol) } return &RSTStreamFrame{fh, ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil @@ -1202,8 +1231,9 @@ type ContinuationFrame struct { headerFragBuf []byte } -func parseContinuationFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) { +func parseContinuationFrame(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (Frame, error) { if fh.StreamID == 0 { + countError("frame_continuation_zero_stream") return nil, connError{ErrCodeProtocol, "CONTINUATION frame with stream ID 0"} } return &ContinuationFrame{fh, p}, nil @@ -1252,7 +1282,7 @@ func (f *PushPromiseFrame) HeadersEnded() bool { return f.FrameHeader.Flags.Has(FlagPushPromiseEndHeaders) } -func parsePushPromise(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err error) { +func parsePushPromise(_ *frameCache, fh FrameHeader, countError func(string), p []byte) (_ Frame, err error) { pp := &PushPromiseFrame{ FrameHeader: fh, } @@ -1263,6 +1293,7 @@ func parsePushPromise(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err err // with. If the stream identifier field specifies the value // 0x0, a recipient MUST respond with a connection error // (Section 5.4.1) of type PROTOCOL_ERROR. + countError("frame_pushpromise_zero_stream") return nil, ConnectionError(ErrCodeProtocol) } // The PUSH_PROMISE frame includes optional padding. @@ -1270,18 +1301,21 @@ func parsePushPromise(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err err var padLength uint8 if fh.Flags.Has(FlagPushPromisePadded) { if p, padLength, err = readByte(p); err != nil { + countError("frame_pushpromise_pad_short") return } } p, pp.PromiseID, err = readUint32(p) if err != nil { + countError("frame_pushpromise_promiseid_short") return } pp.PromiseID = pp.PromiseID & (1<<31 - 1) if int(padLength) > len(p) { // like the DATA frame, error out if padding is longer than the body. + countError("frame_pushpromise_pad_too_big") return nil, ConnectionError(ErrCodeProtocol) } pp.headerFragBuf = p[:len(p)-int(padLength)] diff --git a/src/runtime/vendor/golang.org/x/net/http2/hpack/huffman.go b/src/runtime/vendor/golang.org/x/net/http2/hpack/huffman.go index a1ab2f056..fe0b84ccd 100644 --- a/src/runtime/vendor/golang.org/x/net/http2/hpack/huffman.go +++ b/src/runtime/vendor/golang.org/x/net/http2/hpack/huffman.go @@ -140,25 +140,29 @@ func buildRootHuffmanNode() { panic("unexpected size") } lazyRootHuffmanNode = newInternalNode() - for i, code := range huffmanCodes { - addDecoderNode(byte(i), code, huffmanCodeLen[i]) - } -} + // allocate a leaf node for each of the 256 symbols + leaves := new([256]node) -func addDecoderNode(sym byte, code uint32, codeLen uint8) { - cur := lazyRootHuffmanNode - for codeLen > 8 { - codeLen -= 8 - i := uint8(code >> codeLen) - if cur.children[i] == nil { - cur.children[i] = newInternalNode() + for sym, code := range huffmanCodes { + codeLen := huffmanCodeLen[sym] + + cur := lazyRootHuffmanNode + for codeLen > 8 { + codeLen -= 8 + i := uint8(code >> codeLen) + if cur.children[i] == nil { + cur.children[i] = newInternalNode() + } + cur = cur.children[i] + } + shift := 8 - codeLen + start, end := int(uint8(code< 0 { // Check whether the client has flow control quota. if st.inflow.available() < int32(f.Length) { - return streamError(id, ErrCodeFlowControl) + return sc.countError("flow_on_data_length", streamError(id, ErrCodeFlowControl)) } st.inflow.take(int32(f.Length)) @@ -1710,7 +1727,7 @@ func (sc *serverConn) processData(f *DataFrame) error { wrote, err := st.body.Write(data) if err != nil { sc.sendWindowUpdate(nil, int(f.Length)-wrote) - return streamError(id, ErrCodeStreamClosed) + return sc.countError("body_write_err", streamError(id, ErrCodeStreamClosed)) } if wrote != len(data) { panic("internal error: bad Writer") @@ -1796,7 +1813,7 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error { // stream identifier MUST respond with a connection error // (Section 5.4.1) of type PROTOCOL_ERROR. if id%2 != 1 { - return ConnectionError(ErrCodeProtocol) + return sc.countError("headers_even", ConnectionError(ErrCodeProtocol)) } // A HEADERS frame can be used to create a new stream or // send a trailer for an open one. If we already have a stream @@ -1813,7 +1830,7 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error { // this state, it MUST respond with a stream error (Section 5.4.2) of // type STREAM_CLOSED. if st.state == stateHalfClosedRemote { - return streamError(id, ErrCodeStreamClosed) + return sc.countError("headers_half_closed", streamError(id, ErrCodeStreamClosed)) } return st.processTrailerHeaders(f) } @@ -1824,7 +1841,7 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error { // receives an unexpected stream identifier MUST respond with // a connection error (Section 5.4.1) of type PROTOCOL_ERROR. if id <= sc.maxClientStreamID { - return ConnectionError(ErrCodeProtocol) + return sc.countError("stream_went_down", ConnectionError(ErrCodeProtocol)) } sc.maxClientStreamID = id @@ -1841,14 +1858,14 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error { if sc.curClientStreams+1 > sc.advMaxStreams { if sc.unackedSettings == 0 { // They should know better. - return streamError(id, ErrCodeProtocol) + return sc.countError("over_max_streams", streamError(id, ErrCodeProtocol)) } // Assume it's a network race, where they just haven't // received our last SETTINGS update. But actually // this can't happen yet, because we don't yet provide // a way for users to adjust server parameters at // runtime. - return streamError(id, ErrCodeRefusedStream) + return sc.countError("over_max_streams_race", streamError(id, ErrCodeRefusedStream)) } initialState := stateOpen @@ -1858,7 +1875,7 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error { st := sc.newStream(id, 0, initialState) if f.HasPriority() { - if err := checkPriority(f.StreamID, f.Priority); err != nil { + if err := sc.checkPriority(f.StreamID, f.Priority); err != nil { return err } sc.writeSched.AdjustStream(st.id, f.Priority) @@ -1902,15 +1919,15 @@ func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error { sc := st.sc sc.serveG.check() if st.gotTrailerHeader { - return ConnectionError(ErrCodeProtocol) + return sc.countError("dup_trailers", ConnectionError(ErrCodeProtocol)) } st.gotTrailerHeader = true if !f.StreamEnded() { - return streamError(st.id, ErrCodeProtocol) + return sc.countError("trailers_not_ended", streamError(st.id, ErrCodeProtocol)) } if len(f.PseudoFields()) > 0 { - return streamError(st.id, ErrCodeProtocol) + return sc.countError("trailers_pseudo", streamError(st.id, ErrCodeProtocol)) } if st.trailer != nil { for _, hf := range f.RegularFields() { @@ -1919,7 +1936,7 @@ func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error { // TODO: send more details to the peer somehow. But http2 has // no way to send debug data at a stream level. Discuss with // HTTP folk. - return streamError(st.id, ErrCodeProtocol) + return sc.countError("trailers_bogus", streamError(st.id, ErrCodeProtocol)) } st.trailer[key] = append(st.trailer[key], hf.Value) } @@ -1928,13 +1945,13 @@ func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error { return nil } -func checkPriority(streamID uint32, p PriorityParam) error { +func (sc *serverConn) checkPriority(streamID uint32, p PriorityParam) error { if streamID == p.StreamDep { // Section 5.3.1: "A stream cannot depend on itself. An endpoint MUST treat // this as a stream error (Section 5.4.2) of type PROTOCOL_ERROR." // Section 5.3.3 says that a stream can depend on one of its dependencies, // so it's only self-dependencies that are forbidden. - return streamError(streamID, ErrCodeProtocol) + return sc.countError("priority", streamError(streamID, ErrCodeProtocol)) } return nil } @@ -1943,7 +1960,7 @@ func (sc *serverConn) processPriority(f *PriorityFrame) error { if sc.inGoAway { return nil } - if err := checkPriority(f.StreamID, f.PriorityParam); err != nil { + if err := sc.checkPriority(f.StreamID, f.PriorityParam); err != nil { return err } sc.writeSched.AdjustStream(f.StreamID, f.PriorityParam) @@ -2000,7 +2017,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res isConnect := rp.method == "CONNECT" if isConnect { if rp.path != "" || rp.scheme != "" || rp.authority == "" { - return nil, nil, streamError(f.StreamID, ErrCodeProtocol) + return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol)) } } else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") { // See 8.1.2.6 Malformed Requests and Responses: @@ -2013,13 +2030,13 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res // "All HTTP/2 requests MUST include exactly one valid // value for the :method, :scheme, and :path // pseudo-header fields" - return nil, nil, streamError(f.StreamID, ErrCodeProtocol) + return nil, nil, sc.countError("bad_path_method", streamError(f.StreamID, ErrCodeProtocol)) } bodyOpen := !f.StreamEnded() if rp.method == "HEAD" && bodyOpen { // HEAD requests can't have bodies - return nil, nil, streamError(f.StreamID, ErrCodeProtocol) + return nil, nil, sc.countError("head_body", streamError(f.StreamID, ErrCodeProtocol)) } rp.header = make(http.Header) @@ -2102,7 +2119,7 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r var err error url_, err = url.ParseRequestURI(rp.path) if err != nil { - return nil, nil, streamError(st.id, ErrCodeProtocol) + return nil, nil, sc.countError("bad_path", streamError(st.id, ErrCodeProtocol)) } requestURI = rp.path } @@ -2985,3 +3002,31 @@ func h1ServerKeepAlivesDisabled(hs *http.Server) bool { } return false } + +func (sc *serverConn) countError(name string, err error) error { + if sc == nil || sc.srv == nil { + return err + } + f := sc.srv.CountError + if f == nil { + return err + } + var typ string + var code ErrCode + switch e := err.(type) { + case ConnectionError: + typ = "conn" + code = ErrCode(e) + case StreamError: + typ = "stream" + code = ErrCode(e.Code) + default: + return err + } + codeStr := errCodeName[code] + if codeStr == "" { + codeStr = strconv.Itoa(int(code)) + } + f(fmt.Sprintf("%s_%s_%s", typ, codeStr, name)) + return err +} diff --git a/src/runtime/vendor/golang.org/x/net/http2/transport.go b/src/runtime/vendor/golang.org/x/net/http2/transport.go index b261beb1d..f135b0f75 100644 --- a/src/runtime/vendor/golang.org/x/net/http2/transport.go +++ b/src/runtime/vendor/golang.org/x/net/http2/transport.go @@ -24,6 +24,7 @@ import ( "net/http" "net/http/httptrace" "net/textproto" + "os" "sort" "strconv" "strings" @@ -51,6 +52,15 @@ const ( transportDefaultStreamMinRefresh = 4 << 10 defaultUserAgent = "Go-http-client/2.0" + + // initialMaxConcurrentStreams is a connections maxConcurrentStreams until + // it's received servers initial SETTINGS frame, which corresponds with the + // spec's minimum recommended value. + initialMaxConcurrentStreams = 100 + + // defaultMaxConcurrentStreams is a connections default maxConcurrentStreams + // if the server doesn't include one in its initial SETTINGS frame. + defaultMaxConcurrentStreams = 1000 ) // Transport is an HTTP/2 Transport. @@ -121,6 +131,17 @@ type Transport struct { // Defaults to 15s. PingTimeout time.Duration + // WriteByteTimeout is the timeout after which the connection will be + // closed no data can be written to it. The timeout begins when data is + // available to write, and is extended whenever any bytes are written. + WriteByteTimeout time.Duration + + // CountError, if non-nil, is called on HTTP/2 transport errors. + // It's intended to increment a metric for monitoring, such + // as an expvar or Prometheus metric. + // The errType consists of only ASCII word characters. + CountError func(errType string) + // t1, if non-nil, is the standard library Transport using // this transport. Its settings are used (but not its // RoundTrip method, etc). @@ -227,11 +248,12 @@ func (t *Transport) initConnPool() { // ClientConn is the state of a single HTTP/2 client connection to an // HTTP/2 server. type ClientConn struct { - t *Transport - tconn net.Conn // usually *tls.Conn, except specialized impls - tlsState *tls.ConnectionState // nil only for specialized impls - reused uint32 // whether conn is being reused; atomic - singleUse bool // whether being used for a single http.Request + t *Transport + tconn net.Conn // usually *tls.Conn, except specialized impls + tlsState *tls.ConnectionState // nil only for specialized impls + reused uint32 // whether conn is being reused; atomic + singleUse bool // whether being used for a single http.Request + getConnCalled bool // used by clientConnPool // readLoop goroutine fields: readerDone chan struct{} // closed on error @@ -244,86 +266,94 @@ type ClientConn struct { cond *sync.Cond // hold mu; broadcast on flow/closed changes flow flow // our conn-level flow control quota (cs.flow is per stream) inflow flow // peer's conn-level flow control + doNotReuse bool // whether conn is marked to not be reused for any future requests closing bool closed bool + seenSettings bool // true if we've seen a settings frame, false otherwise wantSettingsAck bool // we sent a SETTINGS frame and haven't heard back goAway *GoAwayFrame // if non-nil, the GoAwayFrame we received goAwayDebug string // goAway frame's debug data, retained as a string streams map[uint32]*clientStream // client-initiated + streamsReserved int // incr by ReserveNewRequest; decr on RoundTrip nextStreamID uint32 pendingRequests int // requests blocked and waiting to be sent because len(streams) == maxConcurrentStreams pings map[[8]byte]chan struct{} // in flight ping data to notification channel - bw *bufio.Writer br *bufio.Reader - fr *Framer lastActive time.Time lastIdle time.Time // time last idle - // Settings from peer: (also guarded by mu) + // Settings from peer: (also guarded by wmu) maxFrameSize uint32 maxConcurrentStreams uint32 peerMaxHeaderListSize uint64 initialWindowSize uint32 + // reqHeaderMu is a 1-element semaphore channel controlling access to sending new requests. + // Write to reqHeaderMu to lock it, read from it to unlock. + // Lock reqmu BEFORE mu or wmu. + reqHeaderMu chan struct{} + + // wmu is held while writing. + // Acquire BEFORE mu when holding both, to avoid blocking mu on network writes. + // Only acquire both at the same time when changing peer settings. + wmu sync.Mutex + bw *bufio.Writer + fr *Framer + werr error // first write error that has occurred hbuf bytes.Buffer // HPACK encoder writes into this henc *hpack.Encoder - - wmu sync.Mutex // held while writing; acquire AFTER mu if holding both - werr error // first write error that has occurred } // clientStream is the state for a single HTTP/2 stream. One of these // is created for each Transport.RoundTrip call. type clientStream struct { - cc *ClientConn - req *http.Request + cc *ClientConn + + // Fields of Request that we may access even after the response body is closed. + ctx context.Context + reqCancel <-chan struct{} + trace *httptrace.ClientTrace // or nil ID uint32 - resc chan resAndError bufPipe pipe // buffered pipe with the flow-controlled response payload - startedWrite bool // started request body write; guarded by cc.mu requestedGzip bool - on100 func() // optional code to run if get a 100 continue response + isHead bool + + abortOnce sync.Once + abort chan struct{} // closed to signal stream should end immediately + abortErr error // set if abort is closed + + peerClosed chan struct{} // closed when the peer sends an END_STREAM flag + donec chan struct{} // closed after the stream is in the closed state + on100 chan struct{} // buffered; written to if a 100 is received + + respHeaderRecv chan struct{} // closed when headers are received + res *http.Response // set if respHeaderRecv is closed flow flow // guarded by cc.mu inflow flow // guarded by cc.mu bytesRemain int64 // -1 means unknown; owned by transportResponseBody.Read readErr error // sticky read error; owned by transportResponseBody.Read - stopReqBody error // if non-nil, stop writing req body; guarded by cc.mu - didReset bool // whether we sent a RST_STREAM to the server; guarded by cc.mu - peerReset chan struct{} // closed on peer reset - resetErr error // populated before peerReset is closed + reqBody io.ReadCloser + reqBodyContentLength int64 // -1 means unknown + reqBodyClosed bool // body has been closed; guarded by cc.mu - done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu + // owned by writeRequest: + sentEndStream bool // sent an END_STREAM flag to the peer + sentHeaders bool // owned by clientConnReadLoop: firstByte bool // got the first response byte pastHeaders bool // got first MetaHeadersFrame (actual headers) pastTrailers bool // got optional second MetaHeadersFrame (trailers) num1xx uint8 // number of 1xx responses seen + readClosed bool // peer sent an END_STREAM flag + readAborted bool // read loop reset the stream trailer http.Header // accumulated trailers resTrailer *http.Header // client's Response.Trailer } -// awaitRequestCancel waits for the user to cancel a request or for the done -// channel to be signaled. A non-nil error is returned only if the request was -// canceled. -func awaitRequestCancel(req *http.Request, done <-chan struct{}) error { - ctx := req.Context() - if req.Cancel == nil && ctx.Done() == nil { - return nil - } - select { - case <-req.Cancel: - return errRequestCanceled - case <-ctx.Done(): - return ctx.Err() - case <-done: - return nil - } -} - var got1xxFuncForTests func(int, textproto.MIMEHeader) error // get1xxTraceFunc returns the value of request's httptrace.ClientTrace.Got1xxResponse func, @@ -335,78 +365,65 @@ func (cs *clientStream) get1xxTraceFunc() func(int, textproto.MIMEHeader) error return traceGot1xxResponseFunc(cs.trace) } -// awaitRequestCancel waits for the user to cancel a request, its context to -// expire, or for the request to be done (any way it might be removed from the -// cc.streams map: peer reset, successful completion, TCP connection breakage, -// etc). If the request is canceled, then cs will be canceled and closed. -func (cs *clientStream) awaitRequestCancel(req *http.Request) { - if err := awaitRequestCancel(req, cs.done); err != nil { - cs.cancelStream() - cs.bufPipe.CloseWithError(err) +func (cs *clientStream) abortStream(err error) { + cs.cc.mu.Lock() + defer cs.cc.mu.Unlock() + cs.abortStreamLocked(err) +} + +func (cs *clientStream) abortStreamLocked(err error) { + cs.abortOnce.Do(func() { + cs.abortErr = err + close(cs.abort) + }) + if cs.reqBody != nil && !cs.reqBodyClosed { + cs.reqBody.Close() + cs.reqBodyClosed = true + } + // TODO(dneil): Clean up tests where cs.cc.cond is nil. + if cs.cc.cond != nil { + // Wake up writeRequestBody if it is waiting on flow control. + cs.cc.cond.Broadcast() } } -func (cs *clientStream) cancelStream() { - cc := cs.cc - cc.mu.Lock() - didReset := cs.didReset - cs.didReset = true - cc.mu.Unlock() - - if !didReset { - cc.writeStreamReset(cs.ID, ErrCodeCancel, nil) - cc.forgetStreamID(cs.ID) - } -} - -// checkResetOrDone reports any error sent in a RST_STREAM frame by the -// server, or errStreamClosed if the stream is complete. -func (cs *clientStream) checkResetOrDone() error { - select { - case <-cs.peerReset: - return cs.resetErr - case <-cs.done: - return errStreamClosed - default: - return nil - } -} - -func (cs *clientStream) getStartedWrite() bool { +func (cs *clientStream) abortRequestBodyWrite() { cc := cs.cc cc.mu.Lock() defer cc.mu.Unlock() - return cs.startedWrite -} - -func (cs *clientStream) abortRequestBodyWrite(err error) { - if err == nil { - panic("nil error") - } - cc := cs.cc - cc.mu.Lock() - if cs.stopReqBody == nil { - cs.stopReqBody = err - if cs.req.Body != nil { - cs.req.Body.Close() - } + if cs.reqBody != nil && !cs.reqBodyClosed { + cs.reqBody.Close() + cs.reqBodyClosed = true cc.cond.Broadcast() } - cc.mu.Unlock() } type stickyErrWriter struct { - w io.Writer - err *error + conn net.Conn + timeout time.Duration + err *error } func (sew stickyErrWriter) Write(p []byte) (n int, err error) { if *sew.err != nil { return 0, *sew.err } - n, err = sew.w.Write(p) - *sew.err = err - return + for { + if sew.timeout != 0 { + sew.conn.SetWriteDeadline(time.Now().Add(sew.timeout)) + } + nn, err := sew.conn.Write(p[n:]) + n += nn + if n < len(p) && nn > 0 && errors.Is(err, os.ErrDeadlineExceeded) { + // Keep extending the deadline so long as we're making progress. + continue + } + if sew.timeout != 0 { + sew.conn.SetWriteDeadline(time.Time{}) + } + *sew.err = err + return n, err + } } // noCachedConnError is the concrete type of ErrNoCachedConn, which @@ -479,9 +496,9 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res } reused := !atomic.CompareAndSwapUint32(&cc.reused, 0, 1) traceGotConn(req, cc, reused) - res, gotErrAfterReqBodyWrite, err := cc.roundTrip(req) + res, err := cc.RoundTrip(req) if err != nil && retry <= 6 { - if req, err = shouldRetryRequest(req, err, gotErrAfterReqBodyWrite); err == nil { + if req, err = shouldRetryRequest(req, err); err == nil { // After the first retry, do exponential backoff with 10% jitter. if retry == 0 { continue @@ -492,7 +509,7 @@ func (t *Transport) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Res case <-time.After(time.Second * time.Duration(backoff)): continue case <-req.Context().Done(): - return nil, req.Context().Err() + err = req.Context().Err() } } } @@ -523,7 +540,7 @@ var ( // response headers. It is always called with a non-nil error. // It returns either a request to retry (either the same request, or a // modified clone), or an error if the request can't be replayed. -func shouldRetryRequest(req *http.Request, err error, afterBodyWrite bool) (*http.Request, error) { +func shouldRetryRequest(req *http.Request, err error) (*http.Request, error) { if !canRetryError(err) { return nil, err } @@ -536,7 +553,6 @@ func shouldRetryRequest(req *http.Request, err error, afterBodyWrite bool) (*htt // If the request body can be reset back to its original // state via the optional req.GetBody, do that. if req.GetBody != nil { - // TODO: consider a req.Body.Close here? or audit that all caller paths do? body, err := req.GetBody() if err != nil { return nil, err @@ -548,10 +564,8 @@ func shouldRetryRequest(req *http.Request, err error, afterBodyWrite bool) (*htt // The Request.Body can't reset back to the beginning, but we // don't seem to have started to read from it yet, so reuse - // the request directly. The "afterBodyWrite" means the - // bodyWrite process has started, which becomes true before - // the first Read. - if !afterBodyWrite { + // the request directly. + if err == errClientConnUnusable { return req, nil } @@ -563,6 +577,10 @@ func canRetryError(err error) bool { return true } if se, ok := err.(StreamError); ok { + if se.Code == ErrCodeProtocol && se.Cause == errFromPeer { + // See golang/go#47635, golang/go#42777 + return true + } return se.Code == ErrCodeRefusedStream } return false @@ -637,14 +655,15 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro tconn: c, readerDone: make(chan struct{}), nextStreamID: 1, - maxFrameSize: 16 << 10, // spec default - initialWindowSize: 65535, // spec default - maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough. - peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead. + maxFrameSize: 16 << 10, // spec default + initialWindowSize: 65535, // spec default + maxConcurrentStreams: initialMaxConcurrentStreams, // "infinite", per spec. Use a smaller value until we have received server settings. + peerMaxHeaderListSize: 0xffffffffffffffff, // "infinite", per spec. Use 2^64-1 instead. streams: make(map[uint32]*clientStream), singleUse: singleUse, wantSettingsAck: true, pings: make(map[[8]byte]chan struct{}), + reqHeaderMu: make(chan struct{}, 1), } if d := t.idleConnTimeout(); d != 0 { cc.idleTimeout = d @@ -659,9 +678,16 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro // TODO: adjust this writer size to account for frame size + // MTU + crypto/tls record padding. - cc.bw = bufio.NewWriter(stickyErrWriter{c, &cc.werr}) + cc.bw = bufio.NewWriter(stickyErrWriter{ + conn: c, + timeout: t.WriteByteTimeout, + err: &cc.werr, + }) cc.br = bufio.NewReader(c) cc.fr = NewFramer(cc.bw, cc.br) + if t.CountError != nil { + cc.fr.countError = t.CountError + } cc.fr.ReadMetaHeaders = hpack.NewDecoder(initialHeaderTableSize, nil) cc.fr.MaxHeaderListSize = t.maxHeaderListSize() @@ -714,6 +740,13 @@ func (cc *ClientConn) healthCheck() { } } +// SetDoNotReuse marks cc as not reusable for future HTTP requests. +func (cc *ClientConn) SetDoNotReuse() { + cc.mu.Lock() + defer cc.mu.Unlock() + cc.doNotReuse = true +} + func (cc *ClientConn) setGoAway(f *GoAwayFrame) { cc.mu.Lock() defer cc.mu.Unlock() @@ -731,27 +764,94 @@ func (cc *ClientConn) setGoAway(f *GoAwayFrame) { last := f.LastStreamID for streamID, cs := range cc.streams { if streamID > last { - select { - case cs.resc <- resAndError{err: errClientConnGotGoAway}: - default: - } + cs.abortStreamLocked(errClientConnGotGoAway) } } } // CanTakeNewRequest reports whether the connection can take a new request, // meaning it has not been closed or received or sent a GOAWAY. +// +// If the caller is going to immediately make a new request on this +// connection, use ReserveNewRequest instead. func (cc *ClientConn) CanTakeNewRequest() bool { cc.mu.Lock() defer cc.mu.Unlock() return cc.canTakeNewRequestLocked() } +// ReserveNewRequest is like CanTakeNewRequest but also reserves a +// concurrent stream in cc. The reservation is decremented on the +// next call to RoundTrip. +func (cc *ClientConn) ReserveNewRequest() bool { + cc.mu.Lock() + defer cc.mu.Unlock() + if st := cc.idleStateLocked(); !st.canTakeNewRequest { + return false + } + cc.streamsReserved++ + return true +} + +// ClientConnState describes the state of a ClientConn. +type ClientConnState struct { + // Closed is whether the connection is closed. + Closed bool + + // Closing is whether the connection is in the process of + // closing. It may be closing due to shutdown, being a + // single-use connection, being marked as DoNotReuse, or + // having received a GOAWAY frame. + Closing bool + + // StreamsActive is how many streams are active. + StreamsActive int + + // StreamsReserved is how many streams have been reserved via + // ClientConn.ReserveNewRequest. + StreamsReserved int + + // StreamsPending is how many requests have been sent in excess + // of the peer's advertised MaxConcurrentStreams setting and + // are waiting for other streams to complete. + StreamsPending int + + // MaxConcurrentStreams is how many concurrent streams the + // peer advertised as acceptable. Zero means no SETTINGS + // frame has been received yet. + MaxConcurrentStreams uint32 + + // LastIdle, if non-zero, is when the connection last + // transitioned to idle state. + LastIdle time.Time +} + +// State returns a snapshot of cc's state. +func (cc *ClientConn) State() ClientConnState { + cc.wmu.Lock() + maxConcurrent := cc.maxConcurrentStreams + if !cc.seenSettings { + maxConcurrent = 0 + } + cc.wmu.Unlock() + + cc.mu.Lock() + defer cc.mu.Unlock() + return ClientConnState{ + Closed: cc.closed, + Closing: cc.closing || cc.singleUse || cc.doNotReuse || cc.goAway != nil, + StreamsActive: len(cc.streams), + StreamsReserved: cc.streamsReserved, + StreamsPending: cc.pendingRequests, + LastIdle: cc.lastIdle, + MaxConcurrentStreams: maxConcurrent, + } +} + // clientConnIdleState describes the suitability of a client // connection to initiate a new RoundTrip request. type clientConnIdleState struct { canTakeNewRequest bool - freshConn bool // whether it's unused by any previous request } func (cc *ClientConn) idleState() clientConnIdleState { @@ -772,13 +872,13 @@ func (cc *ClientConn) idleStateLocked() (st clientConnIdleState) { // writing it. maxConcurrentOkay = true } else { - maxConcurrentOkay = int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) + maxConcurrentOkay = int64(len(cc.streams)+cc.streamsReserved+1) <= int64(cc.maxConcurrentStreams) } st.canTakeNewRequest = cc.goAway == nil && !cc.closed && !cc.closing && maxConcurrentOkay && + !cc.doNotReuse && int64(cc.nextStreamID)+2*int64(cc.pendingRequests) < math.MaxInt32 && !cc.tooIdleLocked() - st.freshConn = cc.nextStreamID == 1 && st.canTakeNewRequest return } @@ -809,7 +909,7 @@ func (cc *ClientConn) onIdleTimeout() { func (cc *ClientConn) closeIfIdle() { cc.mu.Lock() - if len(cc.streams) > 0 { + if len(cc.streams) > 0 || cc.streamsReserved > 0 { cc.mu.Unlock() return } @@ -824,9 +924,15 @@ func (cc *ClientConn) closeIfIdle() { cc.tconn.Close() } +func (cc *ClientConn) isDoNotReuseAndIdle() bool { + cc.mu.Lock() + defer cc.mu.Unlock() + return cc.doNotReuse && len(cc.streams) == 0 +} + var shutdownEnterWaitStateHook = func() {} -// Shutdown gracefully close the client connection, waiting for running streams to complete. +// Shutdown gracefully closes the client connection, waiting for running streams to complete. func (cc *ClientConn) Shutdown(ctx context.Context) error { if err := cc.sendGoAway(); err != nil { return err @@ -865,15 +971,18 @@ func (cc *ClientConn) Shutdown(ctx context.Context) error { func (cc *ClientConn) sendGoAway() error { cc.mu.Lock() - defer cc.mu.Unlock() - cc.wmu.Lock() - defer cc.wmu.Unlock() - if cc.closing { + closing := cc.closing + cc.closing = true + maxStreamID := cc.nextStreamID + cc.mu.Unlock() + if closing { // GOAWAY sent already return nil } + + cc.wmu.Lock() + defer cc.wmu.Unlock() // Send a graceful shutdown frame to server - maxStreamID := cc.nextStreamID if err := cc.fr.WriteGoAway(maxStreamID, ErrCodeNo, nil); err != nil { return err } @@ -881,7 +990,6 @@ func (cc *ClientConn) sendGoAway() error { return err } // Prevent new requests - cc.closing = true return nil } @@ -889,17 +997,12 @@ func (cc *ClientConn) sendGoAway() error { // err is sent to streams. func (cc *ClientConn) closeForError(err error) error { cc.mu.Lock() + cc.closed = true + for _, cs := range cc.streams { + cs.abortStreamLocked(err) + } defer cc.cond.Broadcast() defer cc.mu.Unlock() - for id, cs := range cc.streams { - select { - case cs.resc <- resAndError{err: err}: - default: - } - cs.bufPipe.CloseWithError(err) - delete(cc.streams, id) - } - cc.closed = true return cc.tconn.Close() } @@ -914,6 +1017,9 @@ func (cc *ClientConn) Close() error { // closes the client connection immediately. In-flight requests are interrupted. func (cc *ClientConn) closeForLostPing() error { err := errors.New("http2: client connection lost") + if f := cc.t.CountError; f != nil { + f("conn_close_lost_ping") + } return cc.closeForError(err) } @@ -978,41 +1084,158 @@ func actualContentLength(req *http.Request) int64 { return -1 } -func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) { - resp, _, err := cc.roundTrip(req) - return resp, err +func (cc *ClientConn) decrStreamReservations() { + cc.mu.Lock() + defer cc.mu.Unlock() + cc.decrStreamReservationsLocked() } -func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAfterReqBodyWrite bool, err error) { - if err := checkConnHeaders(req); err != nil { - return nil, false, err +func (cc *ClientConn) decrStreamReservationsLocked() { + if cc.streamsReserved > 0 { + cc.streamsReserved-- } +} + +func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) { + ctx := req.Context() + cs := &clientStream{ + cc: cc, + ctx: ctx, + reqCancel: req.Cancel, + isHead: req.Method == "HEAD", + reqBody: req.Body, + reqBodyContentLength: actualContentLength(req), + trace: httptrace.ContextClientTrace(ctx), + peerClosed: make(chan struct{}), + abort: make(chan struct{}), + respHeaderRecv: make(chan struct{}), + donec: make(chan struct{}), + } + go cs.doRequest(req) + + waitDone := func() error { + select { + case <-cs.donec: + return nil + case <-ctx.Done(): + return ctx.Err() + case <-cs.reqCancel: + return errRequestCanceled + } + } + + handleResponseHeaders := func() (*http.Response, error) { + res := cs.res + if res.StatusCode > 299 { + // On error or status code 3xx, 4xx, 5xx, etc abort any + // ongoing write, assuming that the server doesn't care + // about our request body. If the server replied with 1xx or + // 2xx, however, then assume the server DOES potentially + // want our body (e.g. full-duplex streaming: + // golang.org/issue/13444). If it turns out the server + // doesn't, they'll RST_STREAM us soon enough. This is a + // heuristic to avoid adding knobs to Transport. Hopefully + // we can keep it. + cs.abortRequestBodyWrite() + } + res.Request = req + res.TLS = cc.tlsState + if res.Body == noBody && actualContentLength(req) == 0 { + // If there isn't a request or response body still being + // written, then wait for the stream to be closed before + // RoundTrip returns. + if err := waitDone(); err != nil { + return nil, err + } + } + return res, nil + } + + for { + select { + case <-cs.respHeaderRecv: + return handleResponseHeaders() + case <-cs.abort: + select { + case <-cs.respHeaderRecv: + // If both cs.respHeaderRecv and cs.abort are signaling, + // pick respHeaderRecv. The server probably wrote the + // response and immediately reset the stream. + // golang.org/issue/49645 + return handleResponseHeaders() + default: + waitDone() + return nil, cs.abortErr + } + case <-ctx.Done(): + err := ctx.Err() + cs.abortStream(err) + return nil, err + case <-cs.reqCancel: + cs.abortStream(errRequestCanceled) + return nil, errRequestCanceled + } + } +} + +// doRequest runs for the duration of the request lifetime. +// +// It sends the request and performs post-request cleanup (closing Request.Body, etc.). +func (cs *clientStream) doRequest(req *http.Request) { + err := cs.writeRequest(req) + cs.cleanupWriteRequest(err) +} + +// writeRequest sends a request. +// +// It returns nil after the request is written, the response read, +// and the request stream is half-closed by the peer. +// +// It returns non-nil if the request ends otherwise. +// If the returned error is StreamError, the error Code may be used in resetting the stream. +func (cs *clientStream) writeRequest(req *http.Request) (err error) { + cc := cs.cc + ctx := cs.ctx + + if err := checkConnHeaders(req); err != nil { + return err + } + + // Acquire the new-request lock by writing to reqHeaderMu. + // This lock guards the critical section covering allocating a new stream ID + // (requires mu) and creating the stream (requires wmu). + if cc.reqHeaderMu == nil { + panic("RoundTrip on uninitialized ClientConn") // for tests + } + select { + case cc.reqHeaderMu <- struct{}{}: + case <-cs.reqCancel: + return errRequestCanceled + case <-ctx.Done(): + return ctx.Err() + } + + cc.mu.Lock() if cc.idleTimer != nil { cc.idleTimer.Stop() } - - trailers, err := commaSeparatedTrailers(req) - if err != nil { - return nil, false, err - } - hasTrailers := trailers != "" - - cc.mu.Lock() - if err := cc.awaitOpenSlotForRequest(req); err != nil { + cc.decrStreamReservationsLocked() + if err := cc.awaitOpenSlotForStreamLocked(cs); err != nil { cc.mu.Unlock() - return nil, false, err + <-cc.reqHeaderMu + return err } - - body := req.Body - contentLen := actualContentLength(req) - hasBody := contentLen != 0 + cc.addStreamLocked(cs) // assigns stream ID + if isConnectionCloseRequest(req) { + cc.doNotReuse = true + } + cc.mu.Unlock() // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? - var requestedGzip bool if !cc.t.disableCompression() && req.Header.Get("Accept-Encoding") == "" && req.Header.Get("Range") == "" && - req.Method != "HEAD" { + !cs.isHead { // Request gzip only, not deflate. Deflate is ambiguous and // not as universally supported anyway. // See: https://zlib.net/zlib_faq.html#faq39 @@ -1025,183 +1248,224 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf // We don't request gzip if the request is for a range, since // auto-decoding a portion of a gzipped document will just fail // anyway. See https://golang.org/issue/8923 - requestedGzip = true + cs.requestedGzip = true } - // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is - // sent by writeRequestBody below, along with any Trailers, - // again in form HEADERS{1}, CONTINUATION{0,}) - hdrs, err := cc.encodeHeaders(req, requestedGzip, trailers, contentLen) + continueTimeout := cc.t.expectContinueTimeout() + if continueTimeout != 0 { + if !httpguts.HeaderValuesContainsToken(req.Header["Expect"], "100-continue") { + continueTimeout = 0 + } else { + cs.on100 = make(chan struct{}, 1) + } + } + + // Past this point (where we send request headers), it is possible for + // RoundTrip to return successfully. Since the RoundTrip contract permits + // the caller to "mutate or reuse" the Request after closing the Response's Body, + // we must take care when referencing the Request from here on. + err = cs.encodeAndWriteHeaders(req) + <-cc.reqHeaderMu if err != nil { - cc.mu.Unlock() - return nil, false, err + return err } - cs := cc.newStream() - cs.req = req - cs.trace = httptrace.ContextClientTrace(req.Context()) - cs.requestedGzip = requestedGzip - bodyWriter := cc.t.getBodyWriterState(cs, body) - cs.on100 = bodyWriter.on100 - - defer func() { - cc.wmu.Lock() - werr := cc.werr - cc.wmu.Unlock() - if werr != nil { - cc.Close() + hasBody := cs.reqBodyContentLength != 0 + if !hasBody { + cs.sentEndStream = true + } else { + if continueTimeout != 0 { + traceWait100Continue(cs.trace) + timer := time.NewTimer(continueTimeout) + select { + case <-timer.C: + err = nil + case <-cs.on100: + err = nil + case <-cs.abort: + err = cs.abortErr + case <-ctx.Done(): + err = ctx.Err() + case <-cs.reqCancel: + err = errRequestCanceled + } + timer.Stop() + if err != nil { + traceWroteRequest(cs.trace, err) + return err + } } - }() - cc.wmu.Lock() - endStream := !hasBody && !hasTrailers - werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) - cc.wmu.Unlock() - traceWroteHeaders(cs.trace) - cc.mu.Unlock() - - if werr != nil { - if hasBody { - req.Body.Close() // per RoundTripper contract - bodyWriter.cancel() + if err = cs.writeRequestBody(req); err != nil { + if err != errStopReqBodyWrite { + traceWroteRequest(cs.trace, err) + return err + } + } else { + cs.sentEndStream = true } - cc.forgetStreamID(cs.ID) - // Don't bother sending a RST_STREAM (our write already failed; - // no need to keep writing) - traceWroteRequest(cs.trace, werr) - return nil, false, werr } + traceWroteRequest(cs.trace, err) + var respHeaderTimer <-chan time.Time - if hasBody { - bodyWriter.scheduleBodyWrite() - } else { - traceWroteRequest(cs.trace, nil) - if d := cc.responseHeaderTimeout(); d != 0 { - timer := time.NewTimer(d) - defer timer.Stop() - respHeaderTimer = timer.C - } + var respHeaderRecv chan struct{} + if d := cc.responseHeaderTimeout(); d != 0 { + timer := time.NewTimer(d) + defer timer.Stop() + respHeaderTimer = timer.C + respHeaderRecv = cs.respHeaderRecv } - - readLoopResCh := cs.resc - bodyWritten := false - ctx := req.Context() - - handleReadLoopResponse := func(re resAndError) (*http.Response, bool, error) { - res := re.res - if re.err != nil || res.StatusCode > 299 { - // On error or status code 3xx, 4xx, 5xx, etc abort any - // ongoing write, assuming that the server doesn't care - // about our request body. If the server replied with 1xx or - // 2xx, however, then assume the server DOES potentially - // want our body (e.g. full-duplex streaming: - // golang.org/issue/13444). If it turns out the server - // doesn't, they'll RST_STREAM us soon enough. This is a - // heuristic to avoid adding knobs to Transport. Hopefully - // we can keep it. - bodyWriter.cancel() - cs.abortRequestBodyWrite(errStopReqBodyWrite) - if hasBody && !bodyWritten { - <-bodyWriter.resc - } - } - if re.err != nil { - cc.forgetStreamID(cs.ID) - return nil, cs.getStartedWrite(), re.err - } - res.Request = req - res.TLS = cc.tlsState - return res, false, nil - } - - handleError := func(err error) (*http.Response, bool, error) { - if !hasBody || bodyWritten { - cc.writeStreamReset(cs.ID, ErrCodeCancel, nil) - } else { - bodyWriter.cancel() - cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel) - <-bodyWriter.resc - } - cc.forgetStreamID(cs.ID) - return nil, cs.getStartedWrite(), err - } - + // Wait until the peer half-closes its end of the stream, + // or until the request is aborted (via context, error, or otherwise), + // whichever comes first. for { select { - case re := <-readLoopResCh: - return handleReadLoopResponse(re) + case <-cs.peerClosed: + return nil case <-respHeaderTimer: - return handleError(errTimeout) + return errTimeout + case <-respHeaderRecv: + respHeaderRecv = nil + respHeaderTimer = nil // keep waiting for END_STREAM + case <-cs.abort: + return cs.abortErr case <-ctx.Done(): - return handleError(ctx.Err()) - case <-req.Cancel: - return handleError(errRequestCanceled) - case <-cs.peerReset: - // processResetStream already removed the - // stream from the streams map; no need for - // forgetStreamID. - return nil, cs.getStartedWrite(), cs.resetErr - case err := <-bodyWriter.resc: - bodyWritten = true - // Prefer the read loop's response, if available. Issue 16102. - select { - case re := <-readLoopResCh: - return handleReadLoopResponse(re) - default: - } - if err != nil { - cc.forgetStreamID(cs.ID) - return nil, cs.getStartedWrite(), err - } - if d := cc.responseHeaderTimeout(); d != 0 { - timer := time.NewTimer(d) - defer timer.Stop() - respHeaderTimer = timer.C - } + return ctx.Err() + case <-cs.reqCancel: + return errRequestCanceled } } } -// awaitOpenSlotForRequest waits until len(streams) < maxConcurrentStreams. +func (cs *clientStream) encodeAndWriteHeaders(req *http.Request) error { + cc := cs.cc + ctx := cs.ctx + + cc.wmu.Lock() + defer cc.wmu.Unlock() + + // If the request was canceled while waiting for cc.mu, just quit. + select { + case <-cs.abort: + return cs.abortErr + case <-ctx.Done(): + return ctx.Err() + case <-cs.reqCancel: + return errRequestCanceled + default: + } + + // Encode headers. + // + // we send: HEADERS{1}, CONTINUATION{0,} + DATA{0,} (DATA is + // sent by writeRequestBody below, along with any Trailers, + // again in form HEADERS{1}, CONTINUATION{0,}) + trailers, err := commaSeparatedTrailers(req) + if err != nil { + return err + } + hasTrailers := trailers != "" + contentLen := actualContentLength(req) + hasBody := contentLen != 0 + hdrs, err := cc.encodeHeaders(req, cs.requestedGzip, trailers, contentLen) + if err != nil { + return err + } + + // Write the request. + endStream := !hasBody && !hasTrailers + cs.sentHeaders = true + err = cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) + traceWroteHeaders(cs.trace) + return err +} + +// cleanupWriteRequest performs post-request tasks. +// +// If err (the result of writeRequest) is non-nil and the stream is not closed, +// cleanupWriteRequest will send a reset to the peer. +func (cs *clientStream) cleanupWriteRequest(err error) { + cc := cs.cc + + if cs.ID == 0 { + // We were canceled before creating the stream, so return our reservation. + cc.decrStreamReservations() + } + + // TODO: write h12Compare test showing whether + // Request.Body is closed by the Transport, + // and in multiple cases: server replies <=299 and >299 + // while still writing request body + cc.mu.Lock() + bodyClosed := cs.reqBodyClosed + cs.reqBodyClosed = true + cc.mu.Unlock() + if !bodyClosed && cs.reqBody != nil { + cs.reqBody.Close() + } + + if err != nil && cs.sentEndStream { + // If the connection is closed immediately after the response is read, + // we may be aborted before finishing up here. If the stream was closed + // cleanly on both sides, there is no error. + select { + case <-cs.peerClosed: + err = nil + default: + } + } + if err != nil { + cs.abortStream(err) // possibly redundant, but harmless + if cs.sentHeaders { + if se, ok := err.(StreamError); ok { + if se.Cause != errFromPeer { + cc.writeStreamReset(cs.ID, se.Code, err) + } + } else { + cc.writeStreamReset(cs.ID, ErrCodeCancel, err) + } + } + cs.bufPipe.CloseWithError(err) // no-op if already closed + } else { + if cs.sentHeaders && !cs.sentEndStream { + cc.writeStreamReset(cs.ID, ErrCodeNo, nil) + } + cs.bufPipe.CloseWithError(errRequestCanceled) + } + if cs.ID != 0 { + cc.forgetStreamID(cs.ID) + } + + cc.wmu.Lock() + werr := cc.werr + cc.wmu.Unlock() + if werr != nil { + cc.Close() + } + + close(cs.donec) +} + +// awaitOpenSlotForStream waits until len(streams) < maxConcurrentStreams. // Must hold cc.mu. -func (cc *ClientConn) awaitOpenSlotForRequest(req *http.Request) error { - var waitingForConn chan struct{} - var waitingForConnErr error // guarded by cc.mu +func (cc *ClientConn) awaitOpenSlotForStreamLocked(cs *clientStream) error { for { cc.lastActive = time.Now() if cc.closed || !cc.canTakeNewRequestLocked() { - if waitingForConn != nil { - close(waitingForConn) - } return errClientConnUnusable } cc.lastIdle = time.Time{} - if int64(len(cc.streams))+1 <= int64(cc.maxConcurrentStreams) { - if waitingForConn != nil { - close(waitingForConn) - } + if int64(len(cc.streams)) < int64(cc.maxConcurrentStreams) { return nil } - // Unfortunately, we cannot wait on a condition variable and channel at - // the same time, so instead, we spin up a goroutine to check if the - // request is canceled while we wait for a slot to open in the connection. - if waitingForConn == nil { - waitingForConn = make(chan struct{}) - go func() { - if err := awaitRequestCancel(req, waitingForConn); err != nil { - cc.mu.Lock() - waitingForConnErr = err - cc.cond.Broadcast() - cc.mu.Unlock() - } - }() - } cc.pendingRequests++ cc.cond.Wait() cc.pendingRequests-- - if waitingForConnErr != nil { - return waitingForConnErr + select { + case <-cs.abort: + return cs.abortErr + default: } } } @@ -1228,10 +1492,6 @@ func (cc *ClientConn) writeHeaders(streamID uint32, endStream bool, maxFrameSize cc.fr.WriteContinuation(streamID, endHeaders, chunk) } } - // TODO(bradfitz): this Flush could potentially block (as - // could the WriteHeaders call(s) above), which means they - // wouldn't respond to Request.Cancel being readable. That's - // rare, but this should probably be in a goroutine. cc.bw.Flush() return cc.werr } @@ -1258,7 +1518,7 @@ func (cs *clientStream) frameScratchBufferLen(maxFrameSize int) int { if n > max { n = max } - if cl := actualContentLength(cs.req); cl != -1 && cl+1 < n { + if cl := cs.reqBodyContentLength; cl != -1 && cl+1 < n { // Add an extra byte past the declared content-length to // give the caller's Request.Body io.Reader a chance to // give us more bytes than they declared, so we can catch it @@ -1273,31 +1533,13 @@ func (cs *clientStream) frameScratchBufferLen(maxFrameSize int) int { var bufPool sync.Pool // of *[]byte -func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (err error) { +func (cs *clientStream) writeRequestBody(req *http.Request) (err error) { cc := cs.cc + body := cs.reqBody sentEnd := false // whether we sent the final DATA frame w/ END_STREAM - defer func() { - traceWroteRequest(cs.trace, err) - // TODO: write h12Compare test showing whether - // Request.Body is closed by the Transport, - // and in multiple cases: server replies <=299 and >299 - // while still writing request body - var cerr error - cc.mu.Lock() - if cs.stopReqBody == nil { - cs.stopReqBody = errStopReqBodyWrite - cerr = bodyCloser.Close() - } - cc.mu.Unlock() - if err == nil { - err = cerr - } - }() - - req := cs.req hasTrailers := req.Trailer != nil - remainLen := actualContentLength(req) + remainLen := cs.reqBodyContentLength hasContentLen := remainLen != -1 cc.mu.Lock() @@ -1335,29 +1577,29 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) ( } if remainLen < 0 { err = errReqBodyTooLong - cc.writeStreamReset(cs.ID, ErrCodeCancel, err) return err } } - if err == io.EOF { - sawEOF = true - err = nil - } else if err != nil { - cc.writeStreamReset(cs.ID, ErrCodeCancel, err) - return err + if err != nil { + cc.mu.Lock() + bodyClosed := cs.reqBodyClosed + cc.mu.Unlock() + switch { + case bodyClosed: + return errStopReqBodyWrite + case err == io.EOF: + sawEOF = true + err = nil + default: + return err + } } remain := buf[:n] for len(remain) > 0 && err == nil { var allowed int32 allowed, err = cs.awaitFlowControl(len(remain)) - switch { - case err == errStopReqBodyWrite: - return err - case err == errStopReqBodyWriteAndCancel: - cc.writeStreamReset(cs.ID, ErrCodeCancel, nil) - return err - case err != nil: + if err != nil { return err } cc.wmu.Lock() @@ -1388,20 +1630,26 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) ( return nil } - var trls []byte - if hasTrailers { - cc.mu.Lock() - trls, err = cc.encodeTrailers(req) - cc.mu.Unlock() - if err != nil { - cc.writeStreamReset(cs.ID, ErrCodeInternal, err) - cc.forgetStreamID(cs.ID) - return err - } + // Since the RoundTrip contract permits the caller to "mutate or reuse" + // a request after the Response's Body is closed, verify that this hasn't + // happened before accessing the trailers. + cc.mu.Lock() + trailer := req.Trailer + err = cs.abortErr + cc.mu.Unlock() + if err != nil { + return err } cc.wmu.Lock() defer cc.wmu.Unlock() + var trls []byte + if len(trailer) > 0 { + trls, err = cc.encodeTrailers(trailer) + if err != nil { + return err + } + } // Two ways to send END_STREAM: either with trailers, or // with an empty DATA frame. @@ -1422,17 +1670,24 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) ( // if the stream is dead. func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) { cc := cs.cc + ctx := cs.ctx cc.mu.Lock() defer cc.mu.Unlock() for { if cc.closed { return 0, errClientConnClosed } - if cs.stopReqBody != nil { - return 0, cs.stopReqBody + if cs.reqBodyClosed { + return 0, errStopReqBodyWrite } - if err := cs.checkResetOrDone(); err != nil { - return 0, err + select { + case <-cs.abort: + return 0, cs.abortErr + case <-ctx.Done(): + return 0, ctx.Err() + case <-cs.reqCancel: + return 0, errRequestCanceled + default: } if a := cs.flow.available(); a > 0 { take := a @@ -1450,9 +1705,14 @@ func (cs *clientStream) awaitFlowControl(maxBytes int) (taken int32, err error) } } -// requires cc.mu be held. +var errNilRequestURL = errors.New("http2: Request.URI is nil") + +// requires cc.wmu be held. func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string, contentLength int64) ([]byte, error) { cc.hbuf.Reset() + if req.URL == nil { + return nil, errNilRequestURL + } host := req.Host if host == "" { @@ -1638,12 +1898,12 @@ func shouldSendReqContentLength(method string, contentLength int64) bool { } } -// requires cc.mu be held. -func (cc *ClientConn) encodeTrailers(req *http.Request) ([]byte, error) { +// requires cc.wmu be held. +func (cc *ClientConn) encodeTrailers(trailer http.Header) ([]byte, error) { cc.hbuf.Reset() hlSize := uint64(0) - for k, vv := range req.Trailer { + for k, vv := range trailer { for _, v := range vv { hf := hpack.HeaderField{Name: k, Value: v} hlSize += uint64(hf.Size()) @@ -1653,7 +1913,7 @@ func (cc *ClientConn) encodeTrailers(req *http.Request) ([]byte, error) { return nil, errRequestHeaderListSize } - for k, vv := range req.Trailer { + for k, vv := range trailer { lowKey, ascii := asciiToLower(k) if !ascii { // Skip writing invalid headers. Per RFC 7540, Section 8.1.2, header @@ -1683,51 +1943,51 @@ type resAndError struct { } // requires cc.mu be held. -func (cc *ClientConn) newStream() *clientStream { - cs := &clientStream{ - cc: cc, - ID: cc.nextStreamID, - resc: make(chan resAndError, 1), - peerReset: make(chan struct{}), - done: make(chan struct{}), - } +func (cc *ClientConn) addStreamLocked(cs *clientStream) { cs.flow.add(int32(cc.initialWindowSize)) cs.flow.setConnFlow(&cc.flow) cs.inflow.add(transportDefaultStreamFlow) cs.inflow.setConnFlow(&cc.inflow) + cs.ID = cc.nextStreamID cc.nextStreamID += 2 cc.streams[cs.ID] = cs - return cs + if cs.ID == 0 { + panic("assigned stream ID 0") + } } func (cc *ClientConn) forgetStreamID(id uint32) { - cc.streamByID(id, true) -} - -func (cc *ClientConn) streamByID(id uint32, andRemove bool) *clientStream { cc.mu.Lock() - defer cc.mu.Unlock() - cs := cc.streams[id] - if andRemove && cs != nil && !cc.closed { - cc.lastActive = time.Now() - delete(cc.streams, id) - if len(cc.streams) == 0 && cc.idleTimer != nil { - cc.idleTimer.Reset(cc.idleTimeout) - cc.lastIdle = time.Now() - } - close(cs.done) - // Wake up checkResetOrDone via clientStream.awaitFlowControl and - // wake up RoundTrip if there is a pending request. - cc.cond.Broadcast() + slen := len(cc.streams) + delete(cc.streams, id) + if len(cc.streams) != slen-1 { + panic("forgetting unknown stream id") } - return cs + cc.lastActive = time.Now() + if len(cc.streams) == 0 && cc.idleTimer != nil { + cc.idleTimer.Reset(cc.idleTimeout) + cc.lastIdle = time.Now() + } + // Wake up writeRequestBody via clientStream.awaitFlowControl and + // wake up RoundTrip if there is a pending request. + cc.cond.Broadcast() + + closeOnIdle := cc.singleUse || cc.doNotReuse || cc.t.disableKeepAlives() + if closeOnIdle && cc.streamsReserved == 0 && len(cc.streams) == 0 { + if VerboseLogs { + cc.vlogf("http2: Transport closing idle conn %p (forSingleUse=%v, maxStream=%v)", cc, cc.singleUse, cc.nextStreamID-2) + } + cc.closed = true + defer cc.tconn.Close() + } + + cc.mu.Unlock() } // clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop. type clientConnReadLoop struct { - _ incomparable - cc *ClientConn - closeWhenIdle bool + _ incomparable + cc *ClientConn } // readLoop runs in its own goroutine and reads and dispatches frames. @@ -1787,23 +2047,49 @@ func (rl *clientConnReadLoop) cleanup() { } else if err == io.EOF { err = io.ErrUnexpectedEOF } - for _, cs := range cc.streams { - cs.bufPipe.CloseWithError(err) // no-op if already closed - select { - case cs.resc <- resAndError{err: err}: - default: - } - close(cs.done) - } cc.closed = true + for _, cs := range cc.streams { + select { + case <-cs.peerClosed: + // The server closed the stream before closing the conn, + // so no need to interrupt it. + default: + cs.abortStreamLocked(err) + } + } cc.cond.Broadcast() cc.mu.Unlock() } +// countReadFrameError calls Transport.CountError with a string +// representing err. +func (cc *ClientConn) countReadFrameError(err error) { + f := cc.t.CountError + if f == nil || err == nil { + return + } + if ce, ok := err.(ConnectionError); ok { + errCode := ErrCode(ce) + f(fmt.Sprintf("read_frame_conn_error_%s", errCode.stringToken())) + return + } + if errors.Is(err, io.EOF) { + f("read_frame_eof") + return + } + if errors.Is(err, io.ErrUnexpectedEOF) { + f("read_frame_unexpected_eof") + return + } + if errors.Is(err, ErrFrameTooLarge) { + f("read_frame_too_large") + return + } + f("read_frame_other") +} + func (rl *clientConnReadLoop) run() error { cc := rl.cc - rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse - gotReply := false // ever saw a HEADERS reply gotSettings := false readIdleTimeout := cc.t.ReadIdleTimeout var t *time.Timer @@ -1820,9 +2106,7 @@ func (rl *clientConnReadLoop) run() error { cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err) } if se, ok := err.(StreamError); ok { - if cs := cc.streamByID(se.StreamID, false); cs != nil { - cs.cc.writeStreamReset(cs.ID, se.Code, err) - cs.cc.forgetStreamID(cs.ID) + if cs := rl.streamByID(se.StreamID); cs != nil { if se.Cause == nil { se.Cause = cc.fr.errDetail } @@ -1830,6 +2114,7 @@ func (rl *clientConnReadLoop) run() error { } continue } else if err != nil { + cc.countReadFrameError(err) return err } if VerboseLogs { @@ -1842,22 +2127,16 @@ func (rl *clientConnReadLoop) run() error { } gotSettings = true } - maybeIdle := false // whether frame might transition us to idle switch f := f.(type) { case *MetaHeadersFrame: err = rl.processHeaders(f) - maybeIdle = true - gotReply = true case *DataFrame: err = rl.processData(f) - maybeIdle = true case *GoAwayFrame: err = rl.processGoAway(f) - maybeIdle = true case *RSTStreamFrame: err = rl.processResetStream(f) - maybeIdle = true case *SettingsFrame: err = rl.processSettings(f) case *PushPromiseFrame: @@ -1875,38 +2154,24 @@ func (rl *clientConnReadLoop) run() error { } return err } - if rl.closeWhenIdle && gotReply && maybeIdle { - cc.closeIfIdle() - } } } func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error { - cc := rl.cc - cs := cc.streamByID(f.StreamID, false) + cs := rl.streamByID(f.StreamID) if cs == nil { // We'd get here if we canceled a request while the // server had its response still in flight. So if this // was just something we canceled, ignore it. return nil } - if f.StreamEnded() { - // Issue 20521: If the stream has ended, streamByID() causes - // clientStream.done to be closed, which causes the request's bodyWriter - // to be closed with an errStreamClosed, which may be received by - // clientConn.RoundTrip before the result of processing these headers. - // Deferring stream closure allows the header processing to occur first. - // clientConn.RoundTrip may still receive the bodyWriter error first, but - // the fix for issue 16102 prioritises any response. - // - // Issue 22413: If there is no request body, we should close the - // stream before writing to cs.resc so that the stream is closed - // immediately once RoundTrip returns. - if cs.req.Body != nil { - defer cc.forgetStreamID(f.StreamID) - } else { - cc.forgetStreamID(f.StreamID) - } + if cs.readClosed { + rl.endStreamError(cs, StreamError{ + StreamID: f.StreamID, + Code: ErrCodeProtocol, + Cause: errors.New("protocol error: headers after END_STREAM"), + }) + return nil } if !cs.firstByte { if cs.trace != nil { @@ -1930,9 +2195,11 @@ func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error { return err } // Any other error type is a stream error. - cs.cc.writeStreamReset(f.StreamID, ErrCodeProtocol, err) - cc.forgetStreamID(cs.ID) - cs.resc <- resAndError{err: err} + rl.endStreamError(cs, StreamError{ + StreamID: f.StreamID, + Code: ErrCodeProtocol, + Cause: err, + }) return nil // return nil from process* funcs to keep conn alive } if res == nil { @@ -1940,7 +2207,11 @@ func (rl *clientConnReadLoop) processHeaders(f *MetaHeadersFrame) error { return nil } cs.resTrailer = &res.Trailer - cs.resc <- resAndError{res: res} + cs.res = res + close(cs.respHeaderRecv) + if f.StreamEnded() { + rl.endStream(cs) + } return nil } @@ -2002,6 +2273,9 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra } if statusCode >= 100 && statusCode <= 199 { + if f.StreamEnded() { + return nil, errors.New("1xx informational response with END_STREAM flag") + } cs.num1xx++ const max1xxResponses = 5 // arbitrary bound on number of informational responses, same as net/http if cs.num1xx > max1xxResponses { @@ -2014,42 +2288,49 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra } if statusCode == 100 { traceGot100Continue(cs.trace) - if cs.on100 != nil { - cs.on100() // forces any write delay timer to fire + select { + case cs.on100 <- struct{}{}: + default: } } cs.pastHeaders = false // do it all again return nil, nil } - streamEnded := f.StreamEnded() - isHead := cs.req.Method == "HEAD" - if !streamEnded || isHead { - res.ContentLength = -1 - if clens := res.Header["Content-Length"]; len(clens) == 1 { - if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil { - res.ContentLength = int64(cl) - } else { - // TODO: care? unlike http/1, it won't mess up our framing, so it's - // more safe smuggling-wise to ignore. - } - } else if len(clens) > 1 { + res.ContentLength = -1 + if clens := res.Header["Content-Length"]; len(clens) == 1 { + if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil { + res.ContentLength = int64(cl) + } else { // TODO: care? unlike http/1, it won't mess up our framing, so it's // more safe smuggling-wise to ignore. } + } else if len(clens) > 1 { + // TODO: care? unlike http/1, it won't mess up our framing, so it's + // more safe smuggling-wise to ignore. + } else if f.StreamEnded() && !cs.isHead { + res.ContentLength = 0 } - if streamEnded || isHead { + if cs.isHead { res.Body = noBody return res, nil } - cs.bufPipe = pipe{b: &dataBuffer{expected: res.ContentLength}} + if f.StreamEnded() { + if res.ContentLength > 0 { + res.Body = missingBody{} + } else { + res.Body = noBody + } + return res, nil + } + + cs.bufPipe.setBuffer(&dataBuffer{expected: res.ContentLength}) cs.bytesRemain = res.ContentLength res.Body = transportResponseBody{cs} - go cs.awaitRequestCancel(cs.req) - if cs.requestedGzip && res.Header.Get("Content-Encoding") == "gzip" { + if cs.requestedGzip && asciiEqualFold(res.Header.Get("Content-Encoding"), "gzip") { res.Header.Del("Content-Encoding") res.Header.Del("Content-Length") res.ContentLength = -1 @@ -2088,8 +2369,7 @@ func (rl *clientConnReadLoop) processTrailers(cs *clientStream, f *MetaHeadersFr } // transportResponseBody is the concrete type of Transport.RoundTrip's -// Response.Body. It is an io.ReadCloser. On Read, it reads from cs.body. -// On Close it sends RST_STREAM if EOF wasn't already seen. +// Response.Body. It is an io.ReadCloser. type transportResponseBody struct { cs *clientStream } @@ -2107,7 +2387,7 @@ func (b transportResponseBody) Read(p []byte) (n int, err error) { n = int(cs.bytesRemain) if err == nil { err = errors.New("net/http: server replied with more than declared Content-Length; truncated") - cc.writeStreamReset(cs.ID, ErrCodeProtocol, err) + cs.abortStream(err) } cs.readErr = err return int(cs.bytesRemain), err @@ -2125,8 +2405,6 @@ func (b transportResponseBody) Read(p []byte) (n int, err error) { } cc.mu.Lock() - defer cc.mu.Unlock() - var connAdd, streamAdd int32 // Check the conn-level first, before the stream-level. if v := cc.inflow.available(); v < transportDefaultConnFlow/2 { @@ -2143,6 +2421,8 @@ func (b transportResponseBody) Read(p []byte) (n int, err error) { cs.inflow.add(streamAdd) } } + cc.mu.Unlock() + if connAdd != 0 || streamAdd != 0 { cc.wmu.Lock() defer cc.wmu.Unlock() @@ -2163,34 +2443,45 @@ func (b transportResponseBody) Close() error { cs := b.cs cc := cs.cc - serverSentStreamEnd := cs.bufPipe.Err() == io.EOF unread := cs.bufPipe.Len() - - if unread > 0 || !serverSentStreamEnd { + if unread > 0 { cc.mu.Lock() - cc.wmu.Lock() - if !serverSentStreamEnd { - cc.fr.WriteRSTStream(cs.ID, ErrCodeCancel) - cs.didReset = true - } // Return connection-level flow control. if unread > 0 { cc.inflow.add(int32(unread)) + } + cc.mu.Unlock() + + // TODO(dneil): Acquiring this mutex can block indefinitely. + // Move flow control return to a goroutine? + cc.wmu.Lock() + // Return connection-level flow control. + if unread > 0 { cc.fr.WriteWindowUpdate(0, uint32(unread)) } cc.bw.Flush() cc.wmu.Unlock() - cc.mu.Unlock() } cs.bufPipe.BreakWithError(errClosedResponseBody) - cc.forgetStreamID(cs.ID) + cs.abortStream(errClosedResponseBody) + + select { + case <-cs.donec: + case <-cs.ctx.Done(): + // See golang/go#49366: The net/http package can cancel the + // request context after the response body is fully read. + // Don't treat this as an error. + return nil + case <-cs.reqCancel: + return errRequestCanceled + } return nil } func (rl *clientConnReadLoop) processData(f *DataFrame) error { cc := rl.cc - cs := cc.streamByID(f.StreamID, f.StreamEnded()) + cs := rl.streamByID(f.StreamID) data := f.Data() if cs == nil { cc.mu.Lock() @@ -2219,6 +2510,14 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error { } return nil } + if cs.readClosed { + cc.logf("protocol error: received DATA after END_STREAM") + rl.endStreamError(cs, StreamError{ + StreamID: f.StreamID, + Code: ErrCodeProtocol, + }) + return nil + } if !cs.firstByte { cc.logf("protocol error: received DATA before a HEADERS frame") rl.endStreamError(cs, StreamError{ @@ -2228,7 +2527,7 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error { return nil } if f.Length > 0 { - if cs.req.Method == "HEAD" && len(data) > 0 { + if cs.isHead && len(data) > 0 { cc.logf("protocol error: received DATA on a HEAD request") rl.endStreamError(cs, StreamError{ StreamID: f.StreamID, @@ -2250,30 +2549,39 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error { if pad := int(f.Length) - len(data); pad > 0 { refund += pad } - // Return len(data) now if the stream is already closed, - // since data will never be read. - didReset := cs.didReset - if didReset { - refund += len(data) + + didReset := false + var err error + if len(data) > 0 { + if _, err = cs.bufPipe.Write(data); err != nil { + // Return len(data) now if the stream is already closed, + // since data will never be read. + didReset = true + refund += len(data) + } } + if refund > 0 { cc.inflow.add(int32(refund)) + if !didReset { + cs.inflow.add(int32(refund)) + } + } + cc.mu.Unlock() + + if refund > 0 { cc.wmu.Lock() cc.fr.WriteWindowUpdate(0, uint32(refund)) if !didReset { - cs.inflow.add(int32(refund)) cc.fr.WriteWindowUpdate(cs.ID, uint32(refund)) } cc.bw.Flush() cc.wmu.Unlock() } - cc.mu.Unlock() - if len(data) > 0 && !didReset { - if _, err := cs.bufPipe.Write(data); err != nil { - rl.endStreamError(cs, err) - return err - } + if err != nil { + rl.endStreamError(cs, err) + return nil } } @@ -2286,24 +2594,32 @@ func (rl *clientConnReadLoop) processData(f *DataFrame) error { func (rl *clientConnReadLoop) endStream(cs *clientStream) { // TODO: check that any declared content-length matches, like // server.go's (*stream).endStream method. - rl.endStreamError(cs, nil) + if !cs.readClosed { + cs.readClosed = true + // Close cs.bufPipe and cs.peerClosed with cc.mu held to avoid a + // race condition: The caller can read io.EOF from Response.Body + // and close the body before we close cs.peerClosed, causing + // cleanupWriteRequest to send a RST_STREAM. + rl.cc.mu.Lock() + defer rl.cc.mu.Unlock() + cs.bufPipe.closeWithErrorAndCode(io.EOF, cs.copyTrailers) + close(cs.peerClosed) + } } func (rl *clientConnReadLoop) endStreamError(cs *clientStream, err error) { - var code func() - if err == nil { - err = io.EOF - code = cs.copyTrailers - } - if isConnectionCloseRequest(cs.req) { - rl.closeWhenIdle = true - } - cs.bufPipe.closeWithErrorAndCode(err, code) + cs.readAborted = true + cs.abortStream(err) +} - select { - case cs.resc <- resAndError{err: err}: - default: +func (rl *clientConnReadLoop) streamByID(id uint32) *clientStream { + rl.cc.mu.Lock() + defer rl.cc.mu.Unlock() + cs := rl.cc.streams[id] + if cs != nil && !cs.readAborted { + return cs } + return nil } func (cs *clientStream) copyTrailers() { @@ -2322,12 +2638,33 @@ func (rl *clientConnReadLoop) processGoAway(f *GoAwayFrame) error { if f.ErrCode != 0 { // TODO: deal with GOAWAY more. particularly the error code cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode) + if fn := cc.t.CountError; fn != nil { + fn("recv_goaway_" + f.ErrCode.stringToken()) + } + } cc.setGoAway(f) return nil } func (rl *clientConnReadLoop) processSettings(f *SettingsFrame) error { + cc := rl.cc + // Locking both mu and wmu here allows frame encoding to read settings with only wmu held. + // Acquiring wmu when f.IsAck() is unnecessary, but convenient and mostly harmless. + cc.wmu.Lock() + defer cc.wmu.Unlock() + + if err := rl.processSettingsNoWrite(f); err != nil { + return err + } + if !f.IsAck() { + cc.fr.WriteSettingsAck() + cc.bw.Flush() + } + return nil +} + +func (rl *clientConnReadLoop) processSettingsNoWrite(f *SettingsFrame) error { cc := rl.cc cc.mu.Lock() defer cc.mu.Unlock() @@ -2340,12 +2677,14 @@ func (rl *clientConnReadLoop) processSettings(f *SettingsFrame) error { return ConnectionError(ErrCodeProtocol) } + var seenMaxConcurrentStreams bool err := f.ForeachSetting(func(s Setting) error { switch s.ID { case SettingMaxFrameSize: cc.maxFrameSize = s.Val case SettingMaxConcurrentStreams: cc.maxConcurrentStreams = s.Val + seenMaxConcurrentStreams = true case SettingMaxHeaderListSize: cc.peerMaxHeaderListSize = uint64(s.Val) case SettingInitialWindowSize: @@ -2377,17 +2716,23 @@ func (rl *clientConnReadLoop) processSettings(f *SettingsFrame) error { return err } - cc.wmu.Lock() - defer cc.wmu.Unlock() + if !cc.seenSettings { + if !seenMaxConcurrentStreams { + // This was the servers initial SETTINGS frame and it + // didn't contain a MAX_CONCURRENT_STREAMS field so + // increase the number of concurrent streams this + // connection can establish to our default. + cc.maxConcurrentStreams = defaultMaxConcurrentStreams + } + cc.seenSettings = true + } - cc.fr.WriteSettingsAck() - cc.bw.Flush() - return cc.werr + return nil } func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error { cc := rl.cc - cs := cc.streamByID(f.StreamID, false) + cs := rl.streamByID(f.StreamID) if f.StreamID != 0 && cs == nil { return nil } @@ -2407,24 +2752,22 @@ func (rl *clientConnReadLoop) processWindowUpdate(f *WindowUpdateFrame) error { } func (rl *clientConnReadLoop) processResetStream(f *RSTStreamFrame) error { - cs := rl.cc.streamByID(f.StreamID, true) + cs := rl.streamByID(f.StreamID) if cs == nil { - // TODO: return error if server tries to RST_STEAM an idle stream + // TODO: return error if server tries to RST_STREAM an idle stream return nil } - select { - case <-cs.peerReset: - // Already reset. - // This is the only goroutine - // which closes this, so there - // isn't a race. - default: - err := streamError(cs.ID, f.ErrCode) - cs.resetErr = err - close(cs.peerReset) - cs.bufPipe.CloseWithError(err) - cs.cc.cond.Broadcast() // wake up checkResetOrDone via clientStream.awaitFlowControl + serr := streamError(cs.ID, f.ErrCode) + serr.Cause = errFromPeer + if f.ErrCode == ErrCodeProtocol { + rl.cc.SetDoNotReuse() } + if fn := cs.cc.t.CountError; fn != nil { + fn("recv_rststream_" + f.ErrCode.stringToken()) + } + cs.abortStream(serr) + + cs.bufPipe.CloseWithError(serr) return nil } @@ -2446,19 +2789,24 @@ func (cc *ClientConn) Ping(ctx context.Context) error { } cc.mu.Unlock() } - cc.wmu.Lock() - if err := cc.fr.WritePing(false, p); err != nil { - cc.wmu.Unlock() - return err - } - if err := cc.bw.Flush(); err != nil { - cc.wmu.Unlock() - return err - } - cc.wmu.Unlock() + errc := make(chan error, 1) + go func() { + cc.wmu.Lock() + defer cc.wmu.Unlock() + if err := cc.fr.WritePing(false, p); err != nil { + errc <- err + return + } + if err := cc.bw.Flush(); err != nil { + errc <- err + return + } + }() select { case <-c: return nil + case err := <-errc: + return err case <-ctx.Done(): return ctx.Err() case <-cc.readerDone: @@ -2535,6 +2883,11 @@ func (t *Transport) logf(format string, args ...interface{}) { var noBody io.ReadCloser = ioutil.NopCloser(bytes.NewReader(nil)) +type missingBody struct{} + +func (missingBody) Close() error { return nil } +func (missingBody) Read([]byte) (int, error) { return 0, io.ErrUnexpectedEOF } + func strSliceContains(ss []string, s string) bool { for _, v := range ss { if v == s { @@ -2580,87 +2933,6 @@ type errorReader struct{ err error } func (r errorReader) Read(p []byte) (int, error) { return 0, r.err } -// bodyWriterState encapsulates various state around the Transport's writing -// of the request body, particularly regarding doing delayed writes of the body -// when the request contains "Expect: 100-continue". -type bodyWriterState struct { - cs *clientStream - timer *time.Timer // if non-nil, we're doing a delayed write - fnonce *sync.Once // to call fn with - fn func() // the code to run in the goroutine, writing the body - resc chan error // result of fn's execution - delay time.Duration // how long we should delay a delayed write for -} - -func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s bodyWriterState) { - s.cs = cs - if body == nil { - return - } - resc := make(chan error, 1) - s.resc = resc - s.fn = func() { - cs.cc.mu.Lock() - cs.startedWrite = true - cs.cc.mu.Unlock() - resc <- cs.writeRequestBody(body, cs.req.Body) - } - s.delay = t.expectContinueTimeout() - if s.delay == 0 || - !httpguts.HeaderValuesContainsToken( - cs.req.Header["Expect"], - "100-continue") { - return - } - s.fnonce = new(sync.Once) - - // Arm the timer with a very large duration, which we'll - // intentionally lower later. It has to be large now because - // we need a handle to it before writing the headers, but the - // s.delay value is defined to not start until after the - // request headers were written. - const hugeDuration = 365 * 24 * time.Hour - s.timer = time.AfterFunc(hugeDuration, func() { - s.fnonce.Do(s.fn) - }) - return -} - -func (s bodyWriterState) cancel() { - if s.timer != nil { - if s.timer.Stop() { - s.resc <- nil - } - } -} - -func (s bodyWriterState) on100() { - if s.timer == nil { - // If we didn't do a delayed write, ignore the server's - // bogus 100 continue response. - return - } - s.timer.Stop() - go func() { s.fnonce.Do(s.fn) }() -} - -// scheduleBodyWrite starts writing the body, either immediately (in -// the common case) or after the delay timeout. It should not be -// called until after the headers have been written. -func (s bodyWriterState) scheduleBodyWrite() { - if s.timer == nil { - // We're not doing a delayed write (see - // getBodyWriterState), so just start the writing - // goroutine immediately. - go s.fn() - return - } - traceWait100Continue(s.cs.trace) - if s.timer.Stop() { - s.timer.Reset(s.delay) - } -} - // isConnectionCloseRequest reports whether req should use its own // connection for a single request and then close the connection. func isConnectionCloseRequest(req *http.Request) bool { diff --git a/src/runtime/vendor/golang.org/x/net/http2/writesched.go b/src/runtime/vendor/golang.org/x/net/http2/writesched.go index f24d2b1e7..c7cd00173 100644 --- a/src/runtime/vendor/golang.org/x/net/http2/writesched.go +++ b/src/runtime/vendor/golang.org/x/net/http2/writesched.go @@ -32,7 +32,8 @@ type WriteScheduler interface { // Pop dequeues the next frame to write. Returns false if no frames can // be written. Frames with a given wr.StreamID() are Pop'd in the same - // order they are Push'd. No frames should be discarded except by CloseStream. + // order they are Push'd, except RST_STREAM frames. No frames should be + // discarded except by CloseStream. Pop() (wr FrameWriteRequest, ok bool) } @@ -52,6 +53,7 @@ type FrameWriteRequest struct { // stream is the stream on which this frame will be written. // nil for non-stream frames like PING and SETTINGS. + // nil for RST_STREAM streams, which use the StreamError.StreamID field instead. stream *stream // done, if non-nil, must be a buffered channel with space for diff --git a/src/runtime/vendor/golang.org/x/net/http2/writesched_random.go b/src/runtime/vendor/golang.org/x/net/http2/writesched_random.go index 9a7b9e581..f2e55e05c 100644 --- a/src/runtime/vendor/golang.org/x/net/http2/writesched_random.go +++ b/src/runtime/vendor/golang.org/x/net/http2/writesched_random.go @@ -45,11 +45,11 @@ func (ws *randomWriteScheduler) AdjustStream(streamID uint32, priority PriorityP } func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) { - id := wr.StreamID() - if id == 0 { + if wr.isControl() { ws.zero.push(wr) return } + id := wr.StreamID() q, ok := ws.sq[id] if !ok { q = ws.queuePool.get() @@ -59,7 +59,7 @@ func (ws *randomWriteScheduler) Push(wr FrameWriteRequest) { } func (ws *randomWriteScheduler) Pop() (FrameWriteRequest, bool) { - // Control frames first. + // Control and RST_STREAM frames first. if !ws.zero.empty() { return ws.zero.shift(), true } diff --git a/src/runtime/vendor/golang.org/x/net/idna/go118.go b/src/runtime/vendor/golang.org/x/net/idna/go118.go new file mode 100644 index 000000000..c5c4338db --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/idna/go118.go @@ -0,0 +1,14 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// Copyright 2021 The Go 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 go1.18 +// +build go1.18 + +package idna + +// Transitional processing is disabled by default in Go 1.18. +// https://golang.org/issue/47510 +const transitionalLookup = false diff --git a/src/runtime/vendor/golang.org/x/net/idna/idna10.0.0.go b/src/runtime/vendor/golang.org/x/net/idna/idna10.0.0.go index 5208ba6cb..64ccf85fe 100644 --- a/src/runtime/vendor/golang.org/x/net/idna/idna10.0.0.go +++ b/src/runtime/vendor/golang.org/x/net/idna/idna10.0.0.go @@ -59,10 +59,10 @@ type Option func(*options) // Transitional sets a Profile to use the Transitional mapping as defined in UTS // #46. This will cause, for example, "ß" to be mapped to "ss". Using the // transitional mapping provides a compromise between IDNA2003 and IDNA2008 -// compatibility. It is used by most browsers when resolving domain names. This +// compatibility. It is used by some browsers when resolving domain names. This // option is only meaningful if combined with MapForLookup. func Transitional(transitional bool) Option { - return func(o *options) { o.transitional = true } + return func(o *options) { o.transitional = transitional } } // VerifyDNSLength sets whether a Profile should fail if any of the IDN parts @@ -284,7 +284,7 @@ var ( punycode = &Profile{} lookup = &Profile{options{ - transitional: true, + transitional: transitionalLookup, useSTD3Rules: true, checkHyphens: true, checkJoiners: true, diff --git a/src/runtime/vendor/golang.org/x/net/idna/idna9.0.0.go b/src/runtime/vendor/golang.org/x/net/idna/idna9.0.0.go index 55f718f12..aae6aac87 100644 --- a/src/runtime/vendor/golang.org/x/net/idna/idna9.0.0.go +++ b/src/runtime/vendor/golang.org/x/net/idna/idna9.0.0.go @@ -58,10 +58,10 @@ type Option func(*options) // Transitional sets a Profile to use the Transitional mapping as defined in UTS // #46. This will cause, for example, "ß" to be mapped to "ss". Using the // transitional mapping provides a compromise between IDNA2003 and IDNA2008 -// compatibility. It is used by most browsers when resolving domain names. This +// compatibility. It is used by some browsers when resolving domain names. This // option is only meaningful if combined with MapForLookup. func Transitional(transitional bool) Option { - return func(o *options) { o.transitional = true } + return func(o *options) { o.transitional = transitional } } // VerifyDNSLength sets whether a Profile should fail if any of the IDN parts diff --git a/src/runtime/vendor/golang.org/x/net/idna/pre_go118.go b/src/runtime/vendor/golang.org/x/net/idna/pre_go118.go new file mode 100644 index 000000000..3aaccab1c --- /dev/null +++ b/src/runtime/vendor/golang.org/x/net/idna/pre_go118.go @@ -0,0 +1,12 @@ +// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. + +// Copyright 2021 The Go 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 !go1.18 +// +build !go1.18 + +package idna + +const transitionalLookup = true diff --git a/src/runtime/vendor/golang.org/x/net/idna/punycode.go b/src/runtime/vendor/golang.org/x/net/idna/punycode.go index 02c7d59af..e8e3ac11a 100644 --- a/src/runtime/vendor/golang.org/x/net/idna/punycode.go +++ b/src/runtime/vendor/golang.org/x/net/idna/punycode.go @@ -49,6 +49,7 @@ func decode(encoded string) (string, error) { } } i, n, bias := int32(0), initialN, initialBias + overflow := false for pos < len(encoded) { oldI, w := i, int32(1) for k := base; ; k += base { @@ -60,29 +61,32 @@ func decode(encoded string) (string, error) { return "", punyError(encoded) } pos++ - i += digit * w - if i < 0 { + i, overflow = madd(i, digit, w) + if overflow { return "", punyError(encoded) } t := k - bias - if t < tmin { + if k <= bias { t = tmin - } else if t > tmax { + } else if k >= bias+tmax { t = tmax } if digit < t { break } - w *= base - t - if w >= math.MaxInt32/base { + w, overflow = madd(0, w, base-t) + if overflow { return "", punyError(encoded) } } + if len(output) >= 1024 { + return "", punyError(encoded) + } x := int32(len(output) + 1) bias = adapt(i-oldI, x, oldI == 0) n += i / x i %= x - if n > utf8.MaxRune || len(output) >= 1024 { + if n < 0 || n > utf8.MaxRune { return "", punyError(encoded) } output = append(output, 0) @@ -115,6 +119,7 @@ func encode(prefix, s string) (string, error) { if b > 0 { output = append(output, '-') } + overflow := false for remaining != 0 { m := int32(0x7fffffff) for _, r := range s { @@ -122,8 +127,8 @@ func encode(prefix, s string) (string, error) { m = r } } - delta += (m - n) * (h + 1) - if delta < 0 { + delta, overflow = madd(delta, m-n, h+1) + if overflow { return "", punyError(s) } n = m @@ -141,9 +146,9 @@ func encode(prefix, s string) (string, error) { q := delta for k := base; ; k += base { t := k - bias - if t < tmin { + if k <= bias { t = tmin - } else if t > tmax { + } else if k >= bias+tmax { t = tmax } if q < t { @@ -164,6 +169,15 @@ func encode(prefix, s string) (string, error) { return string(output), nil } +// madd computes a + (b * c), detecting overflow. +func madd(a, b, c int32) (next int32, overflow bool) { + p := int64(b) * int64(c) + if p > math.MaxInt32-int64(a) { + return 0, true + } + return a + int32(p), false +} + func decodeDigit(x byte) (digit int32, ok bool) { switch { case '0' <= x && x <= '9': diff --git a/src/runtime/vendor/golang.org/x/sys/unix/README.md b/src/runtime/vendor/golang.org/x/sys/unix/README.md index 474efad0e..7d3c060e1 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/README.md +++ b/src/runtime/vendor/golang.org/x/sys/unix/README.md @@ -149,7 +149,7 @@ To add a constant, add the header that includes it to the appropriate variable. Then, edit the regex (if necessary) to match the desired constant. Avoid making the regex too broad to avoid matching unintended constants. -### mkmerge.go +### internal/mkmerge This program is used to extract duplicate const, func, and type declarations from the generated architecture-specific files listed below, and merge these diff --git a/src/runtime/vendor/golang.org/x/sys/unix/mkall.sh b/src/runtime/vendor/golang.org/x/sys/unix/mkall.sh index 396aadf86..ee7362348 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/mkall.sh +++ b/src/runtime/vendor/golang.org/x/sys/unix/mkall.sh @@ -50,7 +50,7 @@ if [[ "$GOOS" = "linux" ]]; then # Use the Docker-based build system # Files generated through docker (use $cmd so you can Ctl-C the build or run) $cmd docker build --tag generate:$GOOS $GOOS - $cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")" && /bin/pwd):/build generate:$GOOS + $cmd docker run --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && /bin/pwd):/build generate:$GOOS exit fi diff --git a/src/runtime/vendor/golang.org/x/sys/unix/mkerrors.sh b/src/runtime/vendor/golang.org/x/sys/unix/mkerrors.sh index a74ef58f8..a47b035f9 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/src/runtime/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -239,6 +239,7 @@ struct ltchars { #include #include #include +#include #include #include #include @@ -260,6 +261,7 @@ struct ltchars { #include #include #include +#include #include #include @@ -520,7 +522,7 @@ ccflags="$@" $2 ~ /^HW_MACHINE$/ || $2 ~ /^SYSCTL_VERS/ || $2 !~ "MNT_BITS" && - $2 ~ /^(MS|MNT|UMOUNT)_/ || + $2 ~ /^(MS|MNT|MOUNT|UMOUNT)_/ || $2 ~ /^NS_GET_/ || $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ || $2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT|TFD)_/ || @@ -605,6 +607,7 @@ ccflags="$@" $2 ~ /^MTD/ || $2 ~ /^OTP/ || $2 ~ /^MEM/ || + $2 ~ /^WG/ || $2 ~ /^BLK[A-Z]*(GET$|SET$|BUF$|PART$|SIZE)/ {printf("\t%s = C.%s\n", $2, $2)} $2 ~ /^__WCOREFLAG$/ {next} $2 ~ /^__W[A-Z0-9]+$/ {printf("\t%s = C.%s\n", substr($2,3), $2)} diff --git a/src/runtime/vendor/golang.org/x/sys/unix/sockcmsg_linux.go b/src/runtime/vendor/golang.org/x/sys/unix/sockcmsg_linux.go index 326fb04a5..5f63147e0 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/sockcmsg_linux.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/sockcmsg_linux.go @@ -67,9 +67,7 @@ func ParseOrigDstAddr(m *SocketControlMessage) (Sockaddr, error) { sa := new(SockaddrInet4) p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil case m.Header.Level == SOL_IPV6 && m.Header.Type == IPV6_ORIGDSTADDR: @@ -78,9 +76,7 @@ func ParseOrigDstAddr(m *SocketControlMessage) (Sockaddr, error) { p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) sa.ZoneId = pp.Scope_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil default: diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_aix.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_aix.go index d8efb715f..4f55c8d99 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_aix.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_aix.go @@ -70,9 +70,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil } @@ -85,9 +83,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) sa.raw.Scope_id = sa.ZoneId - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil } @@ -261,9 +257,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { sa := new(SockaddrInet4) p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil case AF_INET6: @@ -272,9 +266,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) sa.ZoneId = pp.Scope_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil } return nil, EAFNOSUPPORT @@ -385,6 +377,11 @@ func (w WaitStatus) TrapCause() int { return -1 } //sys fcntl(fd int, cmd int, arg int) (val int, err error) +//sys fsyncRange(fd int, how int, start int64, length int64) (err error) = fsync_range +func Fsync(fd int) error { + return fsyncRange(fd, O_SYNC, 0, 0) +} + /* * Direct access */ @@ -401,7 +398,6 @@ func (w WaitStatus) TrapCause() int { return -1 } //sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) //sys Fdatasync(fd int) (err error) -//sys Fsync(fd int) (err error) // readdir_r //sysnb Getpgid(pid int) (pgid int, err error) @@ -523,8 +519,10 @@ func Pipe(p []int) (err error) { } var pp [2]_C_int err = pipe(&pp) - p[0] = int(pp[0]) - p[1] = int(pp[1]) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } return } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_bsd.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_bsd.go index 95ac3946b..0ce452326 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_bsd.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_bsd.go @@ -163,9 +163,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil } @@ -179,9 +177,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) sa.raw.Scope_id = sa.ZoneId - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil } @@ -210,9 +206,7 @@ func (sa *SockaddrDatalink) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Nlen = sa.Nlen sa.raw.Alen = sa.Alen sa.raw.Slen = sa.Slen - for i := 0; i < len(sa.raw.Data); i++ { - sa.raw.Data[i] = sa.Data[i] - } + sa.raw.Data = sa.Data return unsafe.Pointer(&sa.raw), SizeofSockaddrDatalink, nil } @@ -228,9 +222,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { sa.Nlen = pp.Nlen sa.Alen = pp.Alen sa.Slen = pp.Slen - for i := 0; i < len(sa.Data); i++ { - sa.Data[i] = pp.Data[i] - } + sa.Data = pp.Data return sa, nil case AF_UNIX: @@ -262,9 +254,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { sa := new(SockaddrInet4) p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil case AF_INET6: @@ -273,9 +263,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) sa.ZoneId = pp.Scope_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil } return anyToSockaddrGOOS(fd, rsa) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_darwin.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_darwin.go index a8c13317d..0eaab9131 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_darwin.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_darwin.go @@ -159,8 +159,10 @@ func Pipe(p []int) (err error) { } var x [2]int32 err = pipe(&x) - p[0] = int(x[0]) - p[1] = int(x[1]) + if err == nil { + p[0] = int(x[0]) + p[1] = int(x[1]) + } return } @@ -430,8 +432,25 @@ func GetsockoptXucred(fd, level, opt int) (*Xucred, error) { return x, err } -func SysctlKinfoProcSlice(name string) ([]KinfoProc, error) { - mib, err := sysctlmib(name) +func SysctlKinfoProc(name string, args ...int) (*KinfoProc, error) { + mib, err := sysctlmib(name, args...) + if err != nil { + return nil, err + } + + var kinfo KinfoProc + n := uintptr(SizeofKinfoProc) + if err := sysctl(mib, (*byte)(unsafe.Pointer(&kinfo)), &n, nil, 0); err != nil { + return nil, err + } + if n != SizeofKinfoProc { + return nil, EIO + } + return &kinfo, nil +} + +func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) { + mib, err := sysctlmib(name, args...) if err != nil { return nil, err } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_dragonfly.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_dragonfly.go index 5af108a50..2e37c3167 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_dragonfly.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_dragonfly.go @@ -101,7 +101,10 @@ func Pipe(p []int) (err error) { if len(p) != 2 { return EINVAL } - p[0], p[1], err = pipe() + r, w, err := pipe() + if err == nil { + p[0], p[1] = r, w + } return } @@ -114,7 +117,10 @@ func Pipe2(p []int, flags int) (err error) { var pp [2]_C_int // pipe2 on dragonfly takes an fds array as an argument, but still // returns the file descriptors. - p[0], p[1], err = pipe2(&pp, flags) + r, w, err := pipe2(&pp, flags) + if err == nil { + p[0], p[1] = r, w + } return err } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_freebsd.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_freebsd.go index 18c392cf3..2f650ae66 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_freebsd.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_freebsd.go @@ -110,8 +110,10 @@ func Pipe2(p []int, flags int) error { } var pp [2]_C_int err := pipe2(&pp, flags) - p[0] = int(pp[0]) - p[1] = int(pp[1]) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } return err } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_linux.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_linux.go index fff38a84c..f432b0684 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_linux.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_linux.go @@ -131,8 +131,10 @@ func Pipe2(p []int, flags int) error { } var pp [2]_C_int err := pipe2(&pp, flags) - p[0] = int(pp[0]) - p[1] = int(pp[1]) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } return err } @@ -372,9 +374,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil } @@ -387,9 +387,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) sa.raw.Scope_id = sa.ZoneId - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil } @@ -438,9 +436,7 @@ func (sa *SockaddrLinklayer) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Hatype = sa.Hatype sa.raw.Pkttype = sa.Pkttype sa.raw.Halen = sa.Halen - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrLinklayer, nil } @@ -855,12 +851,10 @@ func (sa *SockaddrTIPC) sockaddr() (unsafe.Pointer, _Socklen, error) { if sa.Addr == nil { return nil, 0, EINVAL } - sa.raw.Family = AF_TIPC sa.raw.Scope = int8(sa.Scope) sa.raw.Addrtype = sa.Addr.tipcAddrtype() sa.raw.Addr = sa.Addr.tipcAddr() - return unsafe.Pointer(&sa.raw), SizeofSockaddrTIPC, nil } @@ -874,9 +868,7 @@ type SockaddrL2TPIP struct { func (sa *SockaddrL2TPIP) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Family = AF_INET sa.raw.Conn_id = sa.ConnId - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrL2TPIP, nil } @@ -892,9 +884,7 @@ func (sa *SockaddrL2TPIP6) sockaddr() (unsafe.Pointer, _Socklen, error) { sa.raw.Family = AF_INET6 sa.raw.Conn_id = sa.ConnId sa.raw.Scope_id = sa.ZoneId - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrL2TPIP6, nil } @@ -990,9 +980,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { sa.Hatype = pp.Hatype sa.Pkttype = pp.Pkttype sa.Halen = pp.Halen - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil case AF_UNIX: @@ -1031,18 +1019,14 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { pp := (*RawSockaddrL2TPIP)(unsafe.Pointer(rsa)) sa := new(SockaddrL2TPIP) sa.ConnId = pp.Conn_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil default: pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa)) sa := new(SockaddrInet4) p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil } @@ -1058,9 +1042,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { sa := new(SockaddrL2TPIP6) sa.ConnId = pp.Conn_id sa.ZoneId = pp.Scope_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil default: pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa)) @@ -1068,9 +1050,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) sa.ZoneId = pp.Scope_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil } @@ -1797,6 +1777,16 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri return mount(source, target, fstype, flags, datap) } +//sys mountSetattr(dirfd int, pathname string, flags uint, attr *MountAttr, size uintptr) (err error) = SYS_MOUNT_SETATTR + +// MountSetattr is a wrapper for mount_setattr(2). +// https://man7.org/linux/man-pages/man2/mount_setattr.2.html +// +// Requires kernel >= 5.12. +func MountSetattr(dirfd int, pathname string, flags uint, attr *MountAttr) error { + return mountSetattr(dirfd, pathname, flags, attr, unsafe.Sizeof(*attr)) +} + func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { if raceenabled { raceReleaseMerge(unsafe.Pointer(&ioSync)) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_netbsd.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_netbsd.go index 853d5f0f4..696fed496 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_netbsd.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_netbsd.go @@ -110,14 +110,8 @@ func direntNamlen(buf []byte) (uint64, bool) { return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) } -//sysnb pipe() (fd1 int, fd2 int, err error) - func Pipe(p []int) (err error) { - if len(p) != 2 { - return EINVAL - } - p[0], p[1], err = pipe() - return + return Pipe2(p, 0) } //sysnb pipe2(p *[2]_C_int, flags int) (err error) @@ -128,8 +122,10 @@ func Pipe2(p []int, flags int) error { } var pp [2]_C_int err := pipe2(&pp, flags) - p[0] = int(pp[0]) - p[1] = int(pp[1]) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } return err } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_openbsd.go index 22b550385..11b1d419d 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_openbsd.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_openbsd.go @@ -87,8 +87,10 @@ func Pipe2(p []int, flags int) error { } var pp [2]_C_int err := pipe2(&pp, flags) - p[0] = int(pp[0]) - p[1] = int(pp[1]) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } return err } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_solaris.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_solaris.go index d2a6495c7..5c813921e 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -66,8 +66,10 @@ func Pipe(p []int) (err error) { if n != 0 { return err } - p[0] = int(pp[0]) - p[1] = int(pp[1]) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } return nil } @@ -79,8 +81,10 @@ func Pipe2(p []int, flags int) error { } var pp [2]_C_int err := pipe2(&pp, flags) - p[0] = int(pp[0]) - p[1] = int(pp[1]) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } return err } @@ -92,9 +96,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil } @@ -107,9 +109,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) sa.raw.Scope_id = sa.ZoneId - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil } @@ -417,9 +417,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { sa := new(SockaddrInet4) p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil case AF_INET6: @@ -428,9 +426,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) { p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) sa.ZoneId = pp.Scope_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil } return nil, EAFNOSUPPORT diff --git a/src/runtime/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go b/src/runtime/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go index 1ffd8bfcf..f8616f454 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/syscall_zos_s390x.go @@ -67,9 +67,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) { p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil } @@ -83,9 +81,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) { p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) sa.raw.Scope_id = sa.ZoneId - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil } @@ -144,9 +140,7 @@ func anyToSockaddr(_ int, rsa *RawSockaddrAny) (Sockaddr, error) { sa := new(SockaddrInet4) p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil case AF_INET6: @@ -155,9 +149,7 @@ func anyToSockaddr(_ int, rsa *RawSockaddrAny) (Sockaddr, error) { p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) sa.ZoneId = pp.Scope_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil } return nil, EAFNOSUPPORT @@ -587,8 +579,10 @@ func Pipe(p []int) (err error) { } var pp [2]_C_int err = pipe(&pp) - p[0] = int(pp[0]) - p[1] = int(pp[1]) + if err == nil { + p[0] = int(pp[0]) + p[1] = int(pp[1]) + } return } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux.go index 78d4b85ec..6bce65803 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -1,4 +1,4 @@ -// Code generated by mkmerge.go; DO NOT EDIT. +// Code generated by mkmerge; DO NOT EDIT. //go:build linux // +build linux @@ -38,7 +38,8 @@ const ( AF_KEY = 0xf AF_LLC = 0x1a AF_LOCAL = 0x1 - AF_MAX = 0x2d + AF_MAX = 0x2e + AF_MCTP = 0x2d AF_MPLS = 0x1c AF_NETBEUI = 0xd AF_NETLINK = 0x10 @@ -116,6 +117,7 @@ const ( ARPHRD_LAPB = 0x204 ARPHRD_LOCALTLK = 0x305 ARPHRD_LOOPBACK = 0x304 + ARPHRD_MCTP = 0x122 ARPHRD_METRICOM = 0x17 ARPHRD_NETLINK = 0x338 ARPHRD_NETROM = 0x0 @@ -472,6 +474,7 @@ const ( DM_DEV_WAIT = 0xc138fd08 DM_DIR = "mapper" DM_GET_TARGET_VERSION = 0xc138fd11 + DM_IMA_MEASUREMENT_FLAG = 0x80000 DM_INACTIVE_PRESENT_FLAG = 0x40 DM_INTERNAL_SUSPEND_FLAG = 0x40000 DM_IOCTL = 0xfd @@ -716,6 +719,7 @@ const ( ETH_P_LOOPBACK = 0x9000 ETH_P_MACSEC = 0x88e5 ETH_P_MAP = 0xf9 + ETH_P_MCTP = 0xfa ETH_P_MOBITEX = 0x15 ETH_P_MPLS_MC = 0x8848 ETH_P_MPLS_UC = 0x8847 @@ -738,6 +742,7 @@ const ( ETH_P_QINQ2 = 0x9200 ETH_P_QINQ3 = 0x9300 ETH_P_RARP = 0x8035 + ETH_P_REALTEK = 0x8899 ETH_P_SCA = 0x6007 ETH_P_SLOW = 0x8809 ETH_P_SNAP = 0x5 @@ -751,6 +756,21 @@ const ( ETH_P_WCCP = 0x883e ETH_P_X25 = 0x805 ETH_P_XDSA = 0xf8 + EV_ABS = 0x3 + EV_CNT = 0x20 + EV_FF = 0x15 + EV_FF_STATUS = 0x17 + EV_KEY = 0x1 + EV_LED = 0x11 + EV_MAX = 0x1f + EV_MSC = 0x4 + EV_PWR = 0x16 + EV_REL = 0x2 + EV_REP = 0x14 + EV_SND = 0x12 + EV_SW = 0x5 + EV_SYN = 0x0 + EV_VERSION = 0x10001 EXABYTE_ENABLE_NEST = 0xf0 EXT2_SUPER_MAGIC = 0xef53 EXT3_SUPER_MAGIC = 0xef53 @@ -789,11 +809,15 @@ const ( FAN_DELETE_SELF = 0x400 FAN_DENY = 0x2 FAN_ENABLE_AUDIT = 0x40 + FAN_EPIDFD = -0x2 FAN_EVENT_INFO_TYPE_DFID = 0x3 FAN_EVENT_INFO_TYPE_DFID_NAME = 0x2 + FAN_EVENT_INFO_TYPE_ERROR = 0x5 FAN_EVENT_INFO_TYPE_FID = 0x1 + FAN_EVENT_INFO_TYPE_PIDFD = 0x4 FAN_EVENT_METADATA_LEN = 0x18 FAN_EVENT_ON_CHILD = 0x8000000 + FAN_FS_ERROR = 0x8000 FAN_MARK_ADD = 0x1 FAN_MARK_DONT_FOLLOW = 0x4 FAN_MARK_FILESYSTEM = 0x100 @@ -811,6 +835,7 @@ const ( FAN_MOVE_SELF = 0x800 FAN_NOFD = -0x1 FAN_NONBLOCK = 0x2 + FAN_NOPIDFD = -0x1 FAN_ONDIR = 0x40000000 FAN_OPEN = 0x20 FAN_OPEN_EXEC = 0x1000 @@ -821,6 +846,7 @@ const ( FAN_REPORT_DIR_FID = 0x400 FAN_REPORT_FID = 0x200 FAN_REPORT_NAME = 0x800 + FAN_REPORT_PIDFD = 0x80 FAN_REPORT_TID = 0x100 FAN_UNLIMITED_MARKS = 0x20 FAN_UNLIMITED_QUEUE = 0x10 @@ -1454,6 +1480,18 @@ const ( MNT_FORCE = 0x1 MODULE_INIT_IGNORE_MODVERSIONS = 0x1 MODULE_INIT_IGNORE_VERMAGIC = 0x2 + MOUNT_ATTR_IDMAP = 0x100000 + MOUNT_ATTR_NOATIME = 0x10 + MOUNT_ATTR_NODEV = 0x4 + MOUNT_ATTR_NODIRATIME = 0x80 + MOUNT_ATTR_NOEXEC = 0x8 + MOUNT_ATTR_NOSUID = 0x2 + MOUNT_ATTR_NOSYMFOLLOW = 0x200000 + MOUNT_ATTR_RDONLY = 0x1 + MOUNT_ATTR_RELATIME = 0x0 + MOUNT_ATTR_SIZE_VER0 = 0x20 + MOUNT_ATTR_STRICTATIME = 0x20 + MOUNT_ATTR__ATIME = 0x70 MSDOS_SUPER_MAGIC = 0x4d44 MSG_BATCH = 0x40000 MSG_CMSG_CLOEXEC = 0x40000000 @@ -1793,6 +1831,8 @@ const ( PERF_MEM_BLK_DATA = 0x2 PERF_MEM_BLK_NA = 0x1 PERF_MEM_BLK_SHIFT = 0x28 + PERF_MEM_HOPS_0 = 0x1 + PERF_MEM_HOPS_SHIFT = 0x2b PERF_MEM_LOCK_LOCKED = 0x2 PERF_MEM_LOCK_NA = 0x1 PERF_MEM_LOCK_SHIFT = 0x18 @@ -1952,6 +1992,9 @@ const ( PR_SCHED_CORE_CREATE = 0x1 PR_SCHED_CORE_GET = 0x0 PR_SCHED_CORE_MAX = 0x4 + PR_SCHED_CORE_SCOPE_PROCESS_GROUP = 0x2 + PR_SCHED_CORE_SCOPE_THREAD = 0x0 + PR_SCHED_CORE_SCOPE_THREAD_GROUP = 0x1 PR_SCHED_CORE_SHARE_FROM = 0x3 PR_SCHED_CORE_SHARE_TO = 0x2 PR_SET_CHILD_SUBREAPER = 0x24 @@ -1997,6 +2040,7 @@ const ( PR_SPEC_ENABLE = 0x2 PR_SPEC_FORCE_DISABLE = 0x8 PR_SPEC_INDIRECT_BRANCH = 0x1 + PR_SPEC_L1D_FLUSH = 0x2 PR_SPEC_NOT_AFFECTED = 0x0 PR_SPEC_PRCTL = 0x1 PR_SPEC_STORE_BYPASS = 0x0 @@ -2132,12 +2176,23 @@ const ( RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 RTC_AF = 0x20 + RTC_BSM_DIRECT = 0x1 + RTC_BSM_DISABLED = 0x0 + RTC_BSM_LEVEL = 0x2 + RTC_BSM_STANDBY = 0x3 RTC_FEATURE_ALARM = 0x0 + RTC_FEATURE_ALARM_RES_2S = 0x3 RTC_FEATURE_ALARM_RES_MINUTE = 0x1 - RTC_FEATURE_CNT = 0x3 + RTC_FEATURE_BACKUP_SWITCH_MODE = 0x6 + RTC_FEATURE_CNT = 0x7 + RTC_FEATURE_CORRECTION = 0x5 RTC_FEATURE_NEED_WEEK_DAY = 0x2 + RTC_FEATURE_UPDATE_INTERRUPT = 0x4 RTC_IRQF = 0x80 RTC_MAX_FREQ = 0x2000 + RTC_PARAM_BACKUP_SWITCH_MODE = 0x2 + RTC_PARAM_CORRECTION = 0x1 + RTC_PARAM_FEATURES = 0x0 RTC_PF = 0x40 RTC_UF = 0x10 RTF_ADDRCLASSMASK = 0xf8000000 @@ -2432,12 +2487,15 @@ const ( SMART_WRITE_THRESHOLDS = 0xd7 SMB_SUPER_MAGIC = 0x517b SOCKFS_MAGIC = 0x534f434b + SOCK_BUF_LOCK_MASK = 0x3 SOCK_DCCP = 0x6 SOCK_IOC_TYPE = 0x89 SOCK_PACKET = 0xa SOCK_RAW = 0x3 + SOCK_RCVBUF_LOCK = 0x2 SOCK_RDM = 0x4 SOCK_SEQPACKET = 0x5 + SOCK_SNDBUF_LOCK = 0x1 SOL_AAL = 0x109 SOL_ALG = 0x117 SOL_ATM = 0x108 @@ -2494,6 +2552,8 @@ const ( SO_VM_SOCKETS_BUFFER_MIN_SIZE = 0x1 SO_VM_SOCKETS_BUFFER_SIZE = 0x0 SO_VM_SOCKETS_CONNECT_TIMEOUT = 0x6 + SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW = 0x8 + SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD = 0x6 SO_VM_SOCKETS_NONBLOCK_TXRX = 0x7 SO_VM_SOCKETS_PEER_HOST_VM_ID = 0x3 SO_VM_SOCKETS_TRUSTED = 0x5 @@ -2788,6 +2848,13 @@ const ( WDIOS_TEMPPANIC = 0x4 WDIOS_UNKNOWN = -0x1 WEXITED = 0x4 + WGALLOWEDIP_A_MAX = 0x3 + WGDEVICE_A_MAX = 0x8 + WGPEER_A_MAX = 0xa + WG_CMD_MAX = 0x1 + WG_GENL_NAME = "wireguard" + WG_GENL_VERSION = 0x1 + WG_KEY_LEN = 0x20 WIN_ACKMEDIACHANGE = 0xdb WIN_CHECKPOWERMODE1 = 0xe5 WIN_CHECKPOWERMODE2 = 0x98 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 697811a46..234fd4a5d 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -5,7 +5,7 @@ // +build 386,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 /build/unix/_const.go package unix @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x4004700e RTC_IRQP_READ = 0x8004700b RTC_IRQP_SET = 0x4004700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x801c7011 @@ -293,6 +295,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -326,6 +329,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 7d8d93bfc..58619b758 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -5,7 +5,7 @@ // +build amd64,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 /build/unix/_const.go package unix @@ -251,6 +251,8 @@ const ( RTC_EPOCH_SET = 0x4008700e RTC_IRQP_READ = 0x8008700b RTC_IRQP_SET = 0x4008700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x80207011 @@ -294,6 +296,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -327,6 +330,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index f707d5089..3a64ff59d 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -5,7 +5,7 @@ // +build arm,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -257,6 +257,8 @@ const ( RTC_EPOCH_SET = 0x4004700e RTC_IRQP_READ = 0x8004700b RTC_IRQP_SET = 0x4004700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x801c7011 @@ -300,6 +302,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -333,6 +336,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 3a67a9c85..abe0b9257 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -5,7 +5,7 @@ // +build arm64,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/unix/_const.go package unix @@ -247,6 +247,8 @@ const ( RTC_EPOCH_SET = 0x4008700e RTC_IRQP_READ = 0x8008700b RTC_IRQP_SET = 0x4008700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x80207011 @@ -290,6 +292,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -323,6 +326,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index a7ccef56c..14d7a8439 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -5,7 +5,7 @@ // +build mips,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x8004700e RTC_IRQP_READ = 0x4004700b RTC_IRQP_SET = 0x8004700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x401c7011 @@ -293,6 +295,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x20 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -326,6 +329,7 @@ const ( SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index f7b7cec91..99e7c4ac0 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -5,7 +5,7 @@ // +build mips64,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -293,6 +295,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x20 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -326,6 +329,7 @@ const ( SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 4fcacf958..496364c33 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -5,7 +5,7 @@ // +build mips64le,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -293,6 +295,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x20 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -326,6 +329,7 @@ const ( SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index 6f6c223a2..3e4083085 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -5,7 +5,7 @@ // +build mipsle,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -250,6 +250,8 @@ const ( RTC_EPOCH_SET = 0x8004700e RTC_IRQP_READ = 0x4004700b RTC_IRQP_SET = 0x8004700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x401c7011 @@ -293,6 +295,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x20 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -326,6 +329,7 @@ const ( SO_RCVTIMEO = 0x1006 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x1006 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index 59e522bcf..1151a7dfa 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -5,7 +5,7 @@ // +build ppc,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -305,6 +305,8 @@ const ( RTC_EPOCH_SET = 0x8004700e RTC_IRQP_READ = 0x4004700b RTC_IRQP_SET = 0x8004700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x401c7011 @@ -348,6 +350,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -381,6 +384,7 @@ const ( SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index d4264a0f7..ed17f249e 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -5,7 +5,7 @@ // +build ppc64,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -309,6 +309,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -352,6 +354,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -385,6 +388,7 @@ const ( SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index 21cbec1dd..d84a37c1a 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -5,7 +5,7 @@ // +build ppc64le,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -309,6 +309,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -352,6 +354,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -385,6 +388,7 @@ const ( SO_RCVTIMEO = 0x12 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x12 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 9b05bf12f..5cafba83f 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -5,7 +5,7 @@ // +build riscv64,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -238,6 +238,8 @@ const ( RTC_EPOCH_SET = 0x4008700e RTC_IRQP_READ = 0x8008700b RTC_IRQP_SET = 0x4008700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x80207011 @@ -281,6 +283,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -314,6 +317,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index bd82ace09..6d122da41 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -5,7 +5,7 @@ // +build s390x,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/unix/_const.go package unix @@ -313,6 +313,8 @@ const ( RTC_EPOCH_SET = 0x4008700e RTC_IRQP_READ = 0x8008700b RTC_IRQP_SET = 0x4008700c + RTC_PARAM_GET = 0x40187013 + RTC_PARAM_SET = 0x40187014 RTC_PIE_OFF = 0x7006 RTC_PIE_ON = 0x7005 RTC_PLL_GET = 0x80207011 @@ -356,6 +358,7 @@ const ( SO_BPF_EXTENSIONS = 0x30 SO_BROADCAST = 0x6 SO_BSDCOMPAT = 0xe + SO_BUF_LOCK = 0x48 SO_BUSY_POLL = 0x2e SO_BUSY_POLL_BUDGET = 0x46 SO_CNX_ADVICE = 0x35 @@ -389,6 +392,7 @@ const ( SO_RCVTIMEO = 0x14 SO_RCVTIMEO_NEW = 0x42 SO_RCVTIMEO_OLD = 0x14 + SO_RESERVE_MEM = 0x49 SO_REUSEADDR = 0x2 SO_REUSEPORT = 0xf SO_RXQ_OVFL = 0x28 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 1f8bded56..6bd19e51d 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -5,7 +5,7 @@ // +build sparc64,linux // Code generated by cmd/cgo -godefs; DO NOT EDIT. -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/_const.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/_const.go package unix @@ -304,6 +304,8 @@ const ( RTC_EPOCH_SET = 0x8008700e RTC_IRQP_READ = 0x4008700b RTC_IRQP_SET = 0x8008700c + RTC_PARAM_GET = 0x80187013 + RTC_PARAM_SET = 0x80187014 RTC_PIE_OFF = 0x20007006 RTC_PIE_ON = 0x20007005 RTC_PLL_GET = 0x40207011 @@ -347,6 +349,7 @@ const ( SO_BPF_EXTENSIONS = 0x32 SO_BROADCAST = 0x20 SO_BSDCOMPAT = 0x400 + SO_BUF_LOCK = 0x51 SO_BUSY_POLL = 0x30 SO_BUSY_POLL_BUDGET = 0x49 SO_CNX_ADVICE = 0x37 @@ -380,6 +383,7 @@ const ( SO_RCVTIMEO = 0x2000 SO_RCVTIMEO_NEW = 0x44 SO_RCVTIMEO_OLD = 0x2000 + SO_RESERVE_MEM = 0x52 SO_REUSEADDR = 0x4 SO_REUSEPORT = 0x200 SO_RXQ_OVFL = 0x24 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go index 91a23cc72..85e0cc386 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc.go @@ -17,6 +17,7 @@ int getdirent(int, uintptr_t, size_t); int wait4(int, uintptr_t, int, uintptr_t); int ioctl(int, int, uintptr_t); int fcntl(uintptr_t, int, uintptr_t); +int fsync_range(int, int, long long, long long); int acct(uintptr_t); int chdir(uintptr_t); int chroot(uintptr_t); @@ -29,7 +30,6 @@ int fchmod(int, unsigned int); int fchmodat(int, uintptr_t, unsigned int, int); int fchownat(int, uintptr_t, int, int, int); int fdatasync(int); -int fsync(int); int getpgid(int); int getpgrp(); int getpid(); @@ -255,6 +255,16 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fsyncRange(fd int, how int, start int64, length int64) (err error) { + r0, er := C.fsync_range(C.int(fd), C.int(how), C.longlong(start), C.longlong(length)) + if r0 == -1 && er != nil { + err = er + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Acct(path string) (err error) { _p0 := uintptr(unsafe.Pointer(C.CString(path))) r0, er := C.acct(C.uintptr_t(_p0)) @@ -379,16 +389,6 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fsync(fd int) (err error) { - r0, er := C.fsync(C.int(fd)) - if r0 == -1 && er != nil { - err = er - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getpgid(pid int) (pgid int, err error) { r0, er := C.getpgid(C.int(pid)) pgid = int(r0) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go index 33c2609b8..f1d4a73b0 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64.go @@ -135,6 +135,16 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fsyncRange(fd int, how int, start int64, length int64) (err error) { + _, e1 := callfsync_range(fd, how, start, length) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Acct(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -283,16 +293,6 @@ func Fdatasync(fd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fsync(fd int) (err error) { - _, e1 := callfsync(fd) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getpgid(pid int) (pgid int, err error) { r0, e1 := callgetpgid(pid) pgid = int(r0) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go index 8b737fa97..2caa5adf9 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gc.go @@ -18,6 +18,7 @@ import ( //go:cgo_import_dynamic libc_wait4 wait4 "libc.a/shr_64.o" //go:cgo_import_dynamic libc_ioctl ioctl "libc.a/shr_64.o" //go:cgo_import_dynamic libc_fcntl fcntl "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_fsync_range fsync_range "libc.a/shr_64.o" //go:cgo_import_dynamic libc_acct acct "libc.a/shr_64.o" //go:cgo_import_dynamic libc_chdir chdir "libc.a/shr_64.o" //go:cgo_import_dynamic libc_chroot chroot "libc.a/shr_64.o" @@ -30,7 +31,6 @@ import ( //go:cgo_import_dynamic libc_fchmodat fchmodat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_fchownat fchownat "libc.a/shr_64.o" //go:cgo_import_dynamic libc_fdatasync fdatasync "libc.a/shr_64.o" -//go:cgo_import_dynamic libc_fsync fsync "libc.a/shr_64.o" //go:cgo_import_dynamic libc_getpgid getpgid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_getpgrp getpgrp "libc.a/shr_64.o" //go:cgo_import_dynamic libc_getpid getpid "libc.a/shr_64.o" @@ -136,6 +136,7 @@ import ( //go:linkname libc_wait4 libc_wait4 //go:linkname libc_ioctl libc_ioctl //go:linkname libc_fcntl libc_fcntl +//go:linkname libc_fsync_range libc_fsync_range //go:linkname libc_acct libc_acct //go:linkname libc_chdir libc_chdir //go:linkname libc_chroot libc_chroot @@ -148,7 +149,6 @@ import ( //go:linkname libc_fchmodat libc_fchmodat //go:linkname libc_fchownat libc_fchownat //go:linkname libc_fdatasync libc_fdatasync -//go:linkname libc_fsync libc_fsync //go:linkname libc_getpgid libc_getpgid //go:linkname libc_getpgrp libc_getpgrp //go:linkname libc_getpid libc_getpid @@ -257,6 +257,7 @@ var ( libc_wait4, libc_ioctl, libc_fcntl, + libc_fsync_range, libc_acct, libc_chdir, libc_chroot, @@ -269,7 +270,6 @@ var ( libc_fchmodat, libc_fchownat, libc_fdatasync, - libc_fsync, libc_getpgid, libc_getpgrp, libc_getpid, @@ -430,6 +430,13 @@ func callfcntl(fd uintptr, cmd int, arg uintptr) (r1 uintptr, e1 Errno) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func callfsync_range(fd int, how int, start int64, length int64) (r1 uintptr, e1 Errno) { + r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fsync_range)), 4, uintptr(fd), uintptr(how), uintptr(start), uintptr(length), 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func callacct(_p0 uintptr) (r1 uintptr, e1 Errno) { r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_acct)), 1, _p0, 0, 0, 0, 0, 0) return @@ -514,13 +521,6 @@ func callfdatasync(fd int) (r1 uintptr, e1 Errno) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func callfsync(fd int) (r1 uintptr, e1 Errno) { - r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0) - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func callgetpgid(pid int) (r1 uintptr, e1 Errno) { r1, _, e1 = rawSyscall6(uintptr(unsafe.Pointer(&libc_getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0) return diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go index 3c260917e..944a714b1 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_aix_ppc64_gccgo.go @@ -16,6 +16,7 @@ int getdirent(int, uintptr_t, size_t); int wait4(int, uintptr_t, int, uintptr_t); int ioctl(int, int, uintptr_t); int fcntl(uintptr_t, int, uintptr_t); +int fsync_range(int, int, long long, long long); int acct(uintptr_t); int chdir(uintptr_t); int chroot(uintptr_t); @@ -28,7 +29,6 @@ int fchmod(int, unsigned int); int fchmodat(int, uintptr_t, unsigned int, int); int fchownat(int, uintptr_t, int, int, int); int fdatasync(int); -int fsync(int); int getpgid(int); int getpgrp(); int getpid(); @@ -199,6 +199,14 @@ func callfcntl(fd uintptr, cmd int, arg uintptr) (r1 uintptr, e1 Errno) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func callfsync_range(fd int, how int, start int64, length int64) (r1 uintptr, e1 Errno) { + r1 = uintptr(C.fsync_range(C.int(fd), C.int(how), C.longlong(start), C.longlong(length))) + e1 = syscall.GetErrno() + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func callacct(_p0 uintptr) (r1 uintptr, e1 Errno) { r1 = uintptr(C.acct(C.uintptr_t(_p0))) e1 = syscall.GetErrno() @@ -295,14 +303,6 @@ func callfdatasync(fd int) (r1 uintptr, e1 Errno) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func callfsync(fd int) (r1 uintptr, e1 Errno) { - r1 = uintptr(C.fsync(C.int(fd))) - e1 = syscall.GetErrno() - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func callgetpgid(pid int) (r1 uintptr, e1 Errno) { r1 = uintptr(C.getpgid(C.int(pid))) e1 = syscall.GetErrno() diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_linux.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_linux.go index 4f5da1f54..93edda4c4 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_linux.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_linux.go @@ -1,4 +1,4 @@ -// Code generated by mkmerge.go; DO NOT EDIT. +// Code generated by mkmerge; DO NOT EDIT. //go:build linux // +build linux @@ -409,6 +409,21 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func mountSetattr(dirfd int, pathname string, flags uint, attr *MountAttr, size uintptr) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(pathname) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_MOUNT_SETATTR, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(unsafe.Pointer(attr)), uintptr(size), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Acct(path string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go index 4726ab30a..51d0c0742 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go @@ -351,18 +351,6 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pipe() (fd1 int, fd2 int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) - fd1 = int(r0) - fd2 = int(r1) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go index fe71456db..df2efb6db 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go @@ -351,18 +351,6 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pipe() (fd1 int, fd2 int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) - fd1 = int(r0) - fd2 = int(r1) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go index 0b5b2f014..c8536c2c9 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go @@ -351,18 +351,6 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pipe() (fd1 int, fd2 int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) - fd1 = int(r0) - fd2 = int(r1) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go index bfca28648..8b981bfc2 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm64.go @@ -351,18 +351,6 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func pipe() (fd1 int, fd2 int, err error) { - r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0) - fd1 = int(r0) - fd2 = int(r1) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index aa7ce85d1..cac1f758b 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -444,4 +444,6 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_MEMFD_SECRET = 447 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index b83032638..f327e4a0b 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -366,4 +366,6 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_MEMFD_SECRET = 447 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index d75f65a0a..fb06a08d4 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -7,6 +7,7 @@ package unix const ( + SYS_SYSCALL_MASK = 0 SYS_RESTART_SYSCALL = 0 SYS_EXIT = 1 SYS_FORK = 2 @@ -407,4 +408,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 444 SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 8b02f09e9..58285646e 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -311,4 +311,6 @@ const ( SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 SYS_MEMFD_SECRET = 447 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index 026695abb..3b0418e68 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -428,4 +428,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 4444 SYS_LANDLOCK_ADD_RULE = 4445 SYS_LANDLOCK_RESTRICT_SELF = 4446 + SYS_PROCESS_MRELEASE = 4448 + SYS_FUTEX_WAITV = 4449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index 7320ba958..314ebf166 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -358,4 +358,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 5444 SYS_LANDLOCK_ADD_RULE = 5445 SYS_LANDLOCK_RESTRICT_SELF = 5446 + SYS_PROCESS_MRELEASE = 5448 + SYS_FUTEX_WAITV = 5449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index 45082dd67..b8fbb937a 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -358,4 +358,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 5444 SYS_LANDLOCK_ADD_RULE = 5445 SYS_LANDLOCK_RESTRICT_SELF = 5446 + SYS_PROCESS_MRELEASE = 5448 + SYS_FUTEX_WAITV = 5449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index 570a857a5..ee309b2ba 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -428,4 +428,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 4444 SYS_LANDLOCK_ADD_RULE = 4445 SYS_LANDLOCK_RESTRICT_SELF = 4446 + SYS_PROCESS_MRELEASE = 4448 + SYS_FUTEX_WAITV = 4449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go index 638498d62..ac3748104 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -435,4 +435,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 444 SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index 702beebfe..5aa472111 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -407,4 +407,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 444 SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index bfc87ea44..0793ac1a6 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -407,4 +407,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 444 SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index a390e147d..a520962e3 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -309,4 +309,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 444 SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index 3e791e6cd..d1738586b 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -372,4 +372,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 444 SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index 78802a5cf..dfd5660f9 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -386,4 +386,6 @@ const ( SYS_LANDLOCK_CREATE_RULESET = 444 SYS_LANDLOCK_ADD_RULE = 445 SYS_LANDLOCK_RESTRICT_SELF = 446 + SYS_PROCESS_MRELEASE = 448 + SYS_FUTEX_WAITV = 449 ) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go index 7efe5ccba..885842c0e 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_darwin_amd64.go @@ -641,13 +641,13 @@ type Eproc struct { Tdev int32 Tpgid int32 Tsess uintptr - Wmesg [8]int8 + Wmesg [8]byte Xsize int32 Xrssize int16 Xccount int16 Xswrss int16 Flag int32 - Login [12]int8 + Login [12]byte Spare [4]int32 _ [4]byte } @@ -688,7 +688,7 @@ type ExternProc struct { P_priority uint8 P_usrpri uint8 P_nice int8 - P_comm [17]int8 + P_comm [17]byte P_pgrp uintptr P_addr uintptr P_xstat uint16 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go index b23a2efe8..b23c02337 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_darwin_arm64.go @@ -641,13 +641,13 @@ type Eproc struct { Tdev int32 Tpgid int32 Tsess uintptr - Wmesg [8]int8 + Wmesg [8]byte Xsize int32 Xrssize int16 Xccount int16 Xswrss int16 Flag int32 - Login [12]int8 + Login [12]byte Spare [4]int32 _ [4]byte } @@ -688,7 +688,7 @@ type ExternProc struct { P_priority uint8 P_usrpri uint8 P_nice int8 - P_comm [17]int8 + P_comm [17]byte P_pgrp uintptr P_addr uintptr P_xstat uint16 diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux.go index 249ecfcd4..66788f156 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -1,4 +1,4 @@ -// Code generated by mkmerge.go; DO NOT EDIT. +// Code generated by mkmerge; DO NOT EDIT. //go:build linux // +build linux @@ -743,6 +743,8 @@ const ( AT_STATX_FORCE_SYNC = 0x2000 AT_STATX_DONT_SYNC = 0x4000 + AT_RECURSIVE = 0x8000 + AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 @@ -865,6 +867,7 @@ const ( CTRL_CMD_NEWMCAST_GRP = 0x7 CTRL_CMD_DELMCAST_GRP = 0x8 CTRL_CMD_GETMCAST_GRP = 0x9 + CTRL_CMD_GETPOLICY = 0xa CTRL_ATTR_UNSPEC = 0x0 CTRL_ATTR_FAMILY_ID = 0x1 CTRL_ATTR_FAMILY_NAME = 0x2 @@ -873,12 +876,19 @@ const ( CTRL_ATTR_MAXATTR = 0x5 CTRL_ATTR_OPS = 0x6 CTRL_ATTR_MCAST_GROUPS = 0x7 + CTRL_ATTR_POLICY = 0x8 + CTRL_ATTR_OP_POLICY = 0x9 + CTRL_ATTR_OP = 0xa CTRL_ATTR_OP_UNSPEC = 0x0 CTRL_ATTR_OP_ID = 0x1 CTRL_ATTR_OP_FLAGS = 0x2 CTRL_ATTR_MCAST_GRP_UNSPEC = 0x0 CTRL_ATTR_MCAST_GRP_NAME = 0x1 CTRL_ATTR_MCAST_GRP_ID = 0x2 + CTRL_ATTR_POLICY_UNSPEC = 0x0 + CTRL_ATTR_POLICY_DO = 0x1 + CTRL_ATTR_POLICY_DUMP = 0x2 + CTRL_ATTR_POLICY_DUMP_MAX = 0x2 ) const ( @@ -1134,7 +1144,8 @@ const ( PERF_RECORD_BPF_EVENT = 0x12 PERF_RECORD_CGROUP = 0x13 PERF_RECORD_TEXT_POKE = 0x14 - PERF_RECORD_MAX = 0x15 + PERF_RECORD_AUX_OUTPUT_HW_ID = 0x15 + PERF_RECORD_MAX = 0x16 PERF_RECORD_KSYMBOL_TYPE_UNKNOWN = 0x0 PERF_RECORD_KSYMBOL_TYPE_BPF = 0x1 PERF_RECORD_KSYMBOL_TYPE_OOL = 0x2 @@ -1774,7 +1785,8 @@ const ( const ( NF_NETDEV_INGRESS = 0x0 - NF_NETDEV_NUMHOOKS = 0x1 + NF_NETDEV_EGRESS = 0x1 + NF_NETDEV_NUMHOOKS = 0x2 ) const ( @@ -3156,7 +3168,13 @@ const ( DEVLINK_ATTR_RELOAD_ACTION_INFO = 0xa2 DEVLINK_ATTR_RELOAD_ACTION_STATS = 0xa3 DEVLINK_ATTR_PORT_PCI_SF_NUMBER = 0xa4 - DEVLINK_ATTR_MAX = 0xa9 + DEVLINK_ATTR_RATE_TYPE = 0xa5 + DEVLINK_ATTR_RATE_TX_SHARE = 0xa6 + DEVLINK_ATTR_RATE_TX_MAX = 0xa7 + DEVLINK_ATTR_RATE_NODE_NAME = 0xa8 + DEVLINK_ATTR_RATE_PARENT_NODE_NAME = 0xa9 + DEVLINK_ATTR_REGION_MAX_SNAPSHOTS = 0xaa + DEVLINK_ATTR_MAX = 0xaa DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE = 0x0 DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX = 0x1 DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT = 0x0 @@ -3264,7 +3282,8 @@ const ( LWTUNNEL_ENCAP_BPF = 0x6 LWTUNNEL_ENCAP_SEG6_LOCAL = 0x7 LWTUNNEL_ENCAP_RPL = 0x8 - LWTUNNEL_ENCAP_MAX = 0x8 + LWTUNNEL_ENCAP_IOAM6 = 0x9 + LWTUNNEL_ENCAP_MAX = 0x9 MPLS_IPTUNNEL_UNSPEC = 0x0 MPLS_IPTUNNEL_DST = 0x1 @@ -3452,7 +3471,14 @@ const ( ETHTOOL_MSG_CABLE_TEST_ACT = 0x1a ETHTOOL_MSG_CABLE_TEST_TDR_ACT = 0x1b ETHTOOL_MSG_TUNNEL_INFO_GET = 0x1c - ETHTOOL_MSG_USER_MAX = 0x21 + ETHTOOL_MSG_FEC_GET = 0x1d + ETHTOOL_MSG_FEC_SET = 0x1e + ETHTOOL_MSG_MODULE_EEPROM_GET = 0x1f + ETHTOOL_MSG_STATS_GET = 0x20 + ETHTOOL_MSG_PHC_VCLOCKS_GET = 0x21 + ETHTOOL_MSG_MODULE_GET = 0x22 + ETHTOOL_MSG_MODULE_SET = 0x23 + ETHTOOL_MSG_USER_MAX = 0x23 ETHTOOL_MSG_KERNEL_NONE = 0x0 ETHTOOL_MSG_STRSET_GET_REPLY = 0x1 ETHTOOL_MSG_LINKINFO_GET_REPLY = 0x2 @@ -3483,7 +3509,14 @@ const ( ETHTOOL_MSG_CABLE_TEST_NTF = 0x1b ETHTOOL_MSG_CABLE_TEST_TDR_NTF = 0x1c ETHTOOL_MSG_TUNNEL_INFO_GET_REPLY = 0x1d - ETHTOOL_MSG_KERNEL_MAX = 0x22 + ETHTOOL_MSG_FEC_GET_REPLY = 0x1e + ETHTOOL_MSG_FEC_NTF = 0x1f + ETHTOOL_MSG_MODULE_EEPROM_GET_REPLY = 0x20 + ETHTOOL_MSG_STATS_GET_REPLY = 0x21 + ETHTOOL_MSG_PHC_VCLOCKS_GET_REPLY = 0x22 + ETHTOOL_MSG_MODULE_GET_REPLY = 0x23 + ETHTOOL_MSG_MODULE_NTF = 0x24 + ETHTOOL_MSG_KERNEL_MAX = 0x24 ETHTOOL_A_HEADER_UNSPEC = 0x0 ETHTOOL_A_HEADER_DEV_INDEX = 0x1 ETHTOOL_A_HEADER_DEV_NAME = 0x2 @@ -3617,7 +3650,9 @@ const ( ETHTOOL_A_COALESCE_TX_USECS_HIGH = 0x15 ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH = 0x16 ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL = 0x17 - ETHTOOL_A_COALESCE_MAX = 0x17 + ETHTOOL_A_COALESCE_USE_CQE_MODE_TX = 0x18 + ETHTOOL_A_COALESCE_USE_CQE_MODE_RX = 0x19 + ETHTOOL_A_COALESCE_MAX = 0x19 ETHTOOL_A_PAUSE_UNSPEC = 0x0 ETHTOOL_A_PAUSE_HEADER = 0x1 ETHTOOL_A_PAUSE_AUTONEG = 0x2 @@ -3956,3 +3991,77 @@ const ( SHM_RDONLY = 0x1000 SHM_RND = 0x2000 ) + +type MountAttr struct { + Attr_set uint64 + Attr_clr uint64 + Propagation uint64 + Userns_fd uint64 +} + +const ( + WG_CMD_GET_DEVICE = 0x0 + WG_CMD_SET_DEVICE = 0x1 + WGDEVICE_F_REPLACE_PEERS = 0x1 + WGDEVICE_A_UNSPEC = 0x0 + WGDEVICE_A_IFINDEX = 0x1 + WGDEVICE_A_IFNAME = 0x2 + WGDEVICE_A_PRIVATE_KEY = 0x3 + WGDEVICE_A_PUBLIC_KEY = 0x4 + WGDEVICE_A_FLAGS = 0x5 + WGDEVICE_A_LISTEN_PORT = 0x6 + WGDEVICE_A_FWMARK = 0x7 + WGDEVICE_A_PEERS = 0x8 + WGPEER_F_REMOVE_ME = 0x1 + WGPEER_F_REPLACE_ALLOWEDIPS = 0x2 + WGPEER_F_UPDATE_ONLY = 0x4 + WGPEER_A_UNSPEC = 0x0 + WGPEER_A_PUBLIC_KEY = 0x1 + WGPEER_A_PRESHARED_KEY = 0x2 + WGPEER_A_FLAGS = 0x3 + WGPEER_A_ENDPOINT = 0x4 + WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL = 0x5 + WGPEER_A_LAST_HANDSHAKE_TIME = 0x6 + WGPEER_A_RX_BYTES = 0x7 + WGPEER_A_TX_BYTES = 0x8 + WGPEER_A_ALLOWEDIPS = 0x9 + WGPEER_A_PROTOCOL_VERSION = 0xa + WGALLOWEDIP_A_UNSPEC = 0x0 + WGALLOWEDIP_A_FAMILY = 0x1 + WGALLOWEDIP_A_IPADDR = 0x2 + WGALLOWEDIP_A_CIDR_MASK = 0x3 +) + +const ( + NL_ATTR_TYPE_INVALID = 0x0 + NL_ATTR_TYPE_FLAG = 0x1 + NL_ATTR_TYPE_U8 = 0x2 + NL_ATTR_TYPE_U16 = 0x3 + NL_ATTR_TYPE_U32 = 0x4 + NL_ATTR_TYPE_U64 = 0x5 + NL_ATTR_TYPE_S8 = 0x6 + NL_ATTR_TYPE_S16 = 0x7 + NL_ATTR_TYPE_S32 = 0x8 + NL_ATTR_TYPE_S64 = 0x9 + NL_ATTR_TYPE_BINARY = 0xa + NL_ATTR_TYPE_STRING = 0xb + NL_ATTR_TYPE_NUL_STRING = 0xc + NL_ATTR_TYPE_NESTED = 0xd + NL_ATTR_TYPE_NESTED_ARRAY = 0xe + NL_ATTR_TYPE_BITFIELD32 = 0xf + + NL_POLICY_TYPE_ATTR_UNSPEC = 0x0 + NL_POLICY_TYPE_ATTR_TYPE = 0x1 + NL_POLICY_TYPE_ATTR_MIN_VALUE_S = 0x2 + NL_POLICY_TYPE_ATTR_MAX_VALUE_S = 0x3 + NL_POLICY_TYPE_ATTR_MIN_VALUE_U = 0x4 + NL_POLICY_TYPE_ATTR_MAX_VALUE_U = 0x5 + NL_POLICY_TYPE_ATTR_MIN_LENGTH = 0x6 + NL_POLICY_TYPE_ATTR_MAX_LENGTH = 0x7 + NL_POLICY_TYPE_ATTR_POLICY_IDX = 0x8 + NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE = 0x9 + NL_POLICY_TYPE_ATTR_BITFIELD32_MASK = 0xa + NL_POLICY_TYPE_ATTR_PAD = 0xb + NL_POLICY_TYPE_ATTR_MASK = 0xc + NL_POLICY_TYPE_ATTR_MAX = 0xc +) diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index eeeb9aa39..bea254945 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build 386 && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index d30e1155c..b8c8f2894 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build amd64 && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index 69d029752..4db443016 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build arm && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index 28a0455bc..3ebcad8a8 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build arm64 && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index 64a845483..3eb33e48a 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build mips && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index a1b7dee41..79a944672 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build mips64 && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index 936fa6a26..8f4b107ca 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build mips64le && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index 5dd546fbf..e4eb21798 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build mipsle && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go index 947b32e43..d5b21f0f7 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build ppc && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 2a606151b..5188d142b 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build ppc64 && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index d0d735d02..de4dd4c73 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build ppc64le && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go index 95e3d6d06..dccbf9b06 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build riscv64 && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index cccf1ef26..635880610 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build s390x && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go index 44fcbe4e9..765edc13f 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go @@ -1,4 +1,4 @@ -// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/linux/types.go | go run mkpost.go +// cgo -godefs -- -Wall -Werror -static -I/tmp/include /build/unix/linux/types.go | go run mkpost.go // Code generated by the command above; see README.md. DO NOT EDIT. //go:build sparc64 && linux diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go index 2a8b1e6f7..baf5fe650 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_386.go @@ -564,12 +564,11 @@ type Uvmexp struct { Kmapent int32 } -const SizeofClockinfo = 0x14 +const SizeofClockinfo = 0x10 type Clockinfo struct { - Hz int32 - Tick int32 - Tickadj int32 - Stathz int32 - Profhz int32 + Hz int32 + Tick int32 + Stathz int32 + Profhz int32 } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go index b1759cf70..e21ae8ecf 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_amd64.go @@ -564,12 +564,11 @@ type Uvmexp struct { Kmapent int32 } -const SizeofClockinfo = 0x14 +const SizeofClockinfo = 0x10 type Clockinfo struct { - Hz int32 - Tick int32 - Tickadj int32 - Stathz int32 - Profhz int32 + Hz int32 + Tick int32 + Stathz int32 + Profhz int32 } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go index e807de206..f190651cd 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm.go @@ -565,12 +565,11 @@ type Uvmexp struct { Kmapent int32 } -const SizeofClockinfo = 0x14 +const SizeofClockinfo = 0x10 type Clockinfo struct { - Hz int32 - Tick int32 - Tickadj int32 - Stathz int32 - Profhz int32 + Hz int32 + Tick int32 + Stathz int32 + Profhz int32 } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go index ff3aecaee..84747c582 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_arm64.go @@ -558,12 +558,11 @@ type Uvmexp struct { Kmapent int32 } -const SizeofClockinfo = 0x14 +const SizeofClockinfo = 0x10 type Clockinfo struct { - Hz int32 - Tick int32 - Tickadj int32 - Stathz int32 - Profhz int32 + Hz int32 + Tick int32 + Stathz int32 + Profhz int32 } diff --git a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go index 9ecda6917..ac5c8b637 100644 --- a/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go +++ b/src/runtime/vendor/golang.org/x/sys/unix/ztypes_openbsd_mips64.go @@ -558,12 +558,11 @@ type Uvmexp struct { Kmapent int32 } -const SizeofClockinfo = 0x14 +const SizeofClockinfo = 0x10 type Clockinfo struct { - Hz int32 - Tick int32 - Tickadj int32 - Stathz int32 - Profhz int32 + Hz int32 + Tick int32 + Stathz int32 + Profhz int32 } diff --git a/src/runtime/vendor/golang.org/x/sys/windows/exec_windows.go b/src/runtime/vendor/golang.org/x/sys/windows/exec_windows.go index 7a11e83b7..855698bb2 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/exec_windows.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/exec_windows.go @@ -9,8 +9,6 @@ package windows import ( errorspkg "errors" "unsafe" - - "golang.org/x/sys/internal/unsafeheader" ) // EscapeArg rewrites command line argument s as prescribed @@ -147,8 +145,12 @@ func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListCo } return nil, err } + alloc, err := LocalAlloc(LMEM_FIXED, uint32(size)) + if err != nil { + return nil, err + } // size is guaranteed to be ≥1 by InitializeProcThreadAttributeList. - al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(&make([]byte, size)[0]))} + al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(alloc))} err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size) if err != nil { return nil, err @@ -157,36 +159,17 @@ func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListCo } // Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute. -// Note that the value passed to this function will be copied into memory -// allocated by LocalAlloc, the contents of which should not contain any -// Go-managed pointers, even if the passed value itself is a Go-managed -// pointer. func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error { - alloc, err := LocalAlloc(LMEM_FIXED, uint32(size)) - if err != nil { - return err - } - var src, dst []byte - hdr := (*unsafeheader.Slice)(unsafe.Pointer(&src)) - hdr.Data = value - hdr.Cap = int(size) - hdr.Len = int(size) - hdr = (*unsafeheader.Slice)(unsafe.Pointer(&dst)) - hdr.Data = unsafe.Pointer(alloc) - hdr.Cap = int(size) - hdr.Len = int(size) - copy(dst, src) - al.heapAllocations = append(al.heapAllocations, alloc) - return updateProcThreadAttribute(al.data, 0, attribute, unsafe.Pointer(alloc), size, nil, nil) + al.pointers = append(al.pointers, value) + return updateProcThreadAttribute(al.data, 0, attribute, value, size, nil, nil) } // Delete frees ProcThreadAttributeList's resources. func (al *ProcThreadAttributeListContainer) Delete() { deleteProcThreadAttributeList(al.data) - for i := range al.heapAllocations { - LocalFree(Handle(al.heapAllocations[i])) - } - al.heapAllocations = nil + LocalFree(Handle(unsafe.Pointer(al.data))) + al.data = nil + al.pointers = nil } // List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx. diff --git a/src/runtime/vendor/golang.org/x/sys/windows/mksyscall.go b/src/runtime/vendor/golang.org/x/sys/windows/mksyscall.go index 610291098..8563f79c5 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/mksyscall.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/mksyscall.go @@ -7,4 +7,4 @@ package windows -//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go +//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go setupapi_windows.go diff --git a/src/runtime/vendor/golang.org/x/sys/windows/registry/key.go b/src/runtime/vendor/golang.org/x/sys/windows/registry/key.go index c25648343..906325e09 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/registry/key.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/registry/key.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows // Package registry provides access to the Windows registry. @@ -24,6 +25,7 @@ package registry import ( "io" + "runtime" "syscall" "time" ) @@ -113,6 +115,13 @@ func OpenRemoteKey(pcname string, k Key) (Key, error) { // The parameter n controls the number of returned names, // analogous to the way os.File.Readdirnames works. func (k Key) ReadSubKeyNames(n int) ([]string, error) { + // RegEnumKeyEx must be called repeatedly and to completion. + // During this time, this goroutine cannot migrate away from + // its current thread. See https://golang.org/issue/49320 and + // https://golang.org/issue/49466. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + names := make([]string, 0) // Registry key size limit is 255 bytes and described there: // https://msdn.microsoft.com/library/windows/desktop/ms724872.aspx diff --git a/src/runtime/vendor/golang.org/x/sys/windows/registry/mksyscall.go b/src/runtime/vendor/golang.org/x/sys/windows/registry/mksyscall.go index 50c32a3f4..ee74927d3 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/registry/mksyscall.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/registry/mksyscall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build generate // +build generate package registry diff --git a/src/runtime/vendor/golang.org/x/sys/windows/registry/syscall.go b/src/runtime/vendor/golang.org/x/sys/windows/registry/syscall.go index e66643cba..417335123 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/registry/syscall.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/registry/syscall.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package registry diff --git a/src/runtime/vendor/golang.org/x/sys/windows/registry/value.go b/src/runtime/vendor/golang.org/x/sys/windows/registry/value.go index f25e7e97a..2789f6f18 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/registry/value.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/registry/value.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build windows // +build windows package registry diff --git a/src/runtime/vendor/golang.org/x/sys/windows/service.go b/src/runtime/vendor/golang.org/x/sys/windows/service.go index 5b28ae168..f8deca839 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/service.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/service.go @@ -17,8 +17,6 @@ const ( SC_MANAGER_ALL_ACCESS = 0xf003f ) -//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW - const ( SERVICE_KERNEL_DRIVER = 1 SERVICE_FILE_SYSTEM_DRIVER = 2 @@ -133,6 +131,14 @@ const ( SC_EVENT_DATABASE_CHANGE = 0 SC_EVENT_PROPERTY_CHANGE = 1 SC_EVENT_STATUS_CHANGE = 2 + + SERVICE_START_REASON_DEMAND = 0x00000001 + SERVICE_START_REASON_AUTO = 0x00000002 + SERVICE_START_REASON_TRIGGER = 0x00000004 + SERVICE_START_REASON_RESTART_ON_FAILURE = 0x00000008 + SERVICE_START_REASON_DELAYEDAUTO = 0x00000010 + + SERVICE_DYNAMIC_INFORMATION_LEVEL_START_REASON = 1 ) type SERVICE_STATUS struct { @@ -217,6 +223,7 @@ type QUERY_SERVICE_LOCK_STATUS struct { LockDuration uint32 } +//sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenSCManagerW //sys CloseServiceHandle(handle Handle) (err error) = advapi32.CloseServiceHandle //sys CreateService(mgr Handle, serviceName *uint16, displayName *uint16, access uint32, srvType uint32, startType uint32, errCtl uint32, pathName *uint16, loadOrderGroup *uint16, tagId *uint32, dependencies *uint16, serviceStartName *uint16, password *uint16) (handle Handle, err error) [failretval==0] = advapi32.CreateServiceW //sys OpenService(mgr Handle, serviceName *uint16, access uint32) (handle Handle, err error) [failretval==0] = advapi32.OpenServiceW @@ -237,3 +244,4 @@ type QUERY_SERVICE_LOCK_STATUS struct { //sys SubscribeServiceChangeNotifications(service Handle, eventType uint32, callback uintptr, callbackCtx uintptr, subscription *uintptr) (ret error) = sechost.SubscribeServiceChangeNotifications? //sys UnsubscribeServiceChangeNotifications(subscription uintptr) = sechost.UnsubscribeServiceChangeNotifications? //sys RegisterServiceCtrlHandlerEx(serviceName *uint16, handlerProc uintptr, context uintptr) (handle Handle, err error) = advapi32.RegisterServiceCtrlHandlerExW +//sys QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInfo unsafe.Pointer) (err error) = advapi32.QueryServiceDynamicInformation? diff --git a/src/runtime/vendor/golang.org/x/sys/windows/setupapi_windows.go b/src/runtime/vendor/golang.org/x/sys/windows/setupapi_windows.go new file mode 100644 index 000000000..14027da3f --- /dev/null +++ b/src/runtime/vendor/golang.org/x/sys/windows/setupapi_windows.go @@ -0,0 +1,1425 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import ( + "encoding/binary" + "errors" + "fmt" + "runtime" + "strings" + "syscall" + "unsafe" +) + +// This file contains functions that wrap SetupAPI.dll and CfgMgr32.dll, +// core system functions for managing hardware devices, drivers, and the PnP tree. +// Information about these APIs can be found at: +// https://docs.microsoft.com/en-us/windows-hardware/drivers/install/setupapi +// https://docs.microsoft.com/en-us/windows/win32/devinst/cfgmgr32- + +const ( + ERROR_EXPECTED_SECTION_NAME Errno = 0x20000000 | 0xC0000000 | 0 + ERROR_BAD_SECTION_NAME_LINE Errno = 0x20000000 | 0xC0000000 | 1 + ERROR_SECTION_NAME_TOO_LONG Errno = 0x20000000 | 0xC0000000 | 2 + ERROR_GENERAL_SYNTAX Errno = 0x20000000 | 0xC0000000 | 3 + ERROR_WRONG_INF_STYLE Errno = 0x20000000 | 0xC0000000 | 0x100 + ERROR_SECTION_NOT_FOUND Errno = 0x20000000 | 0xC0000000 | 0x101 + ERROR_LINE_NOT_FOUND Errno = 0x20000000 | 0xC0000000 | 0x102 + ERROR_NO_BACKUP Errno = 0x20000000 | 0xC0000000 | 0x103 + ERROR_NO_ASSOCIATED_CLASS Errno = 0x20000000 | 0xC0000000 | 0x200 + ERROR_CLASS_MISMATCH Errno = 0x20000000 | 0xC0000000 | 0x201 + ERROR_DUPLICATE_FOUND Errno = 0x20000000 | 0xC0000000 | 0x202 + ERROR_NO_DRIVER_SELECTED Errno = 0x20000000 | 0xC0000000 | 0x203 + ERROR_KEY_DOES_NOT_EXIST Errno = 0x20000000 | 0xC0000000 | 0x204 + ERROR_INVALID_DEVINST_NAME Errno = 0x20000000 | 0xC0000000 | 0x205 + ERROR_INVALID_CLASS Errno = 0x20000000 | 0xC0000000 | 0x206 + ERROR_DEVINST_ALREADY_EXISTS Errno = 0x20000000 | 0xC0000000 | 0x207 + ERROR_DEVINFO_NOT_REGISTERED Errno = 0x20000000 | 0xC0000000 | 0x208 + ERROR_INVALID_REG_PROPERTY Errno = 0x20000000 | 0xC0000000 | 0x209 + ERROR_NO_INF Errno = 0x20000000 | 0xC0000000 | 0x20A + ERROR_NO_SUCH_DEVINST Errno = 0x20000000 | 0xC0000000 | 0x20B + ERROR_CANT_LOAD_CLASS_ICON Errno = 0x20000000 | 0xC0000000 | 0x20C + ERROR_INVALID_CLASS_INSTALLER Errno = 0x20000000 | 0xC0000000 | 0x20D + ERROR_DI_DO_DEFAULT Errno = 0x20000000 | 0xC0000000 | 0x20E + ERROR_DI_NOFILECOPY Errno = 0x20000000 | 0xC0000000 | 0x20F + ERROR_INVALID_HWPROFILE Errno = 0x20000000 | 0xC0000000 | 0x210 + ERROR_NO_DEVICE_SELECTED Errno = 0x20000000 | 0xC0000000 | 0x211 + ERROR_DEVINFO_LIST_LOCKED Errno = 0x20000000 | 0xC0000000 | 0x212 + ERROR_DEVINFO_DATA_LOCKED Errno = 0x20000000 | 0xC0000000 | 0x213 + ERROR_DI_BAD_PATH Errno = 0x20000000 | 0xC0000000 | 0x214 + ERROR_NO_CLASSINSTALL_PARAMS Errno = 0x20000000 | 0xC0000000 | 0x215 + ERROR_FILEQUEUE_LOCKED Errno = 0x20000000 | 0xC0000000 | 0x216 + ERROR_BAD_SERVICE_INSTALLSECT Errno = 0x20000000 | 0xC0000000 | 0x217 + ERROR_NO_CLASS_DRIVER_LIST Errno = 0x20000000 | 0xC0000000 | 0x218 + ERROR_NO_ASSOCIATED_SERVICE Errno = 0x20000000 | 0xC0000000 | 0x219 + ERROR_NO_DEFAULT_DEVICE_INTERFACE Errno = 0x20000000 | 0xC0000000 | 0x21A + ERROR_DEVICE_INTERFACE_ACTIVE Errno = 0x20000000 | 0xC0000000 | 0x21B + ERROR_DEVICE_INTERFACE_REMOVED Errno = 0x20000000 | 0xC0000000 | 0x21C + ERROR_BAD_INTERFACE_INSTALLSECT Errno = 0x20000000 | 0xC0000000 | 0x21D + ERROR_NO_SUCH_INTERFACE_CLASS Errno = 0x20000000 | 0xC0000000 | 0x21E + ERROR_INVALID_REFERENCE_STRING Errno = 0x20000000 | 0xC0000000 | 0x21F + ERROR_INVALID_MACHINENAME Errno = 0x20000000 | 0xC0000000 | 0x220 + ERROR_REMOTE_COMM_FAILURE Errno = 0x20000000 | 0xC0000000 | 0x221 + ERROR_MACHINE_UNAVAILABLE Errno = 0x20000000 | 0xC0000000 | 0x222 + ERROR_NO_CONFIGMGR_SERVICES Errno = 0x20000000 | 0xC0000000 | 0x223 + ERROR_INVALID_PROPPAGE_PROVIDER Errno = 0x20000000 | 0xC0000000 | 0x224 + ERROR_NO_SUCH_DEVICE_INTERFACE Errno = 0x20000000 | 0xC0000000 | 0x225 + ERROR_DI_POSTPROCESSING_REQUIRED Errno = 0x20000000 | 0xC0000000 | 0x226 + ERROR_INVALID_COINSTALLER Errno = 0x20000000 | 0xC0000000 | 0x227 + ERROR_NO_COMPAT_DRIVERS Errno = 0x20000000 | 0xC0000000 | 0x228 + ERROR_NO_DEVICE_ICON Errno = 0x20000000 | 0xC0000000 | 0x229 + ERROR_INVALID_INF_LOGCONFIG Errno = 0x20000000 | 0xC0000000 | 0x22A + ERROR_DI_DONT_INSTALL Errno = 0x20000000 | 0xC0000000 | 0x22B + ERROR_INVALID_FILTER_DRIVER Errno = 0x20000000 | 0xC0000000 | 0x22C + ERROR_NON_WINDOWS_NT_DRIVER Errno = 0x20000000 | 0xC0000000 | 0x22D + ERROR_NON_WINDOWS_DRIVER Errno = 0x20000000 | 0xC0000000 | 0x22E + ERROR_NO_CATALOG_FOR_OEM_INF Errno = 0x20000000 | 0xC0000000 | 0x22F + ERROR_DEVINSTALL_QUEUE_NONNATIVE Errno = 0x20000000 | 0xC0000000 | 0x230 + ERROR_NOT_DISABLEABLE Errno = 0x20000000 | 0xC0000000 | 0x231 + ERROR_CANT_REMOVE_DEVINST Errno = 0x20000000 | 0xC0000000 | 0x232 + ERROR_INVALID_TARGET Errno = 0x20000000 | 0xC0000000 | 0x233 + ERROR_DRIVER_NONNATIVE Errno = 0x20000000 | 0xC0000000 | 0x234 + ERROR_IN_WOW64 Errno = 0x20000000 | 0xC0000000 | 0x235 + ERROR_SET_SYSTEM_RESTORE_POINT Errno = 0x20000000 | 0xC0000000 | 0x236 + ERROR_SCE_DISABLED Errno = 0x20000000 | 0xC0000000 | 0x238 + ERROR_UNKNOWN_EXCEPTION Errno = 0x20000000 | 0xC0000000 | 0x239 + ERROR_PNP_REGISTRY_ERROR Errno = 0x20000000 | 0xC0000000 | 0x23A + ERROR_REMOTE_REQUEST_UNSUPPORTED Errno = 0x20000000 | 0xC0000000 | 0x23B + ERROR_NOT_AN_INSTALLED_OEM_INF Errno = 0x20000000 | 0xC0000000 | 0x23C + ERROR_INF_IN_USE_BY_DEVICES Errno = 0x20000000 | 0xC0000000 | 0x23D + ERROR_DI_FUNCTION_OBSOLETE Errno = 0x20000000 | 0xC0000000 | 0x23E + ERROR_NO_AUTHENTICODE_CATALOG Errno = 0x20000000 | 0xC0000000 | 0x23F + ERROR_AUTHENTICODE_DISALLOWED Errno = 0x20000000 | 0xC0000000 | 0x240 + ERROR_AUTHENTICODE_TRUSTED_PUBLISHER Errno = 0x20000000 | 0xC0000000 | 0x241 + ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED Errno = 0x20000000 | 0xC0000000 | 0x242 + ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED Errno = 0x20000000 | 0xC0000000 | 0x243 + ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH Errno = 0x20000000 | 0xC0000000 | 0x244 + ERROR_ONLY_VALIDATE_VIA_AUTHENTICODE Errno = 0x20000000 | 0xC0000000 | 0x245 + ERROR_DEVICE_INSTALLER_NOT_READY Errno = 0x20000000 | 0xC0000000 | 0x246 + ERROR_DRIVER_STORE_ADD_FAILED Errno = 0x20000000 | 0xC0000000 | 0x247 + ERROR_DEVICE_INSTALL_BLOCKED Errno = 0x20000000 | 0xC0000000 | 0x248 + ERROR_DRIVER_INSTALL_BLOCKED Errno = 0x20000000 | 0xC0000000 | 0x249 + ERROR_WRONG_INF_TYPE Errno = 0x20000000 | 0xC0000000 | 0x24A + ERROR_FILE_HASH_NOT_IN_CATALOG Errno = 0x20000000 | 0xC0000000 | 0x24B + ERROR_DRIVER_STORE_DELETE_FAILED Errno = 0x20000000 | 0xC0000000 | 0x24C + ERROR_UNRECOVERABLE_STACK_OVERFLOW Errno = 0x20000000 | 0xC0000000 | 0x300 + EXCEPTION_SPAPI_UNRECOVERABLE_STACK_OVERFLOW Errno = ERROR_UNRECOVERABLE_STACK_OVERFLOW + ERROR_NO_DEFAULT_INTERFACE_DEVICE Errno = ERROR_NO_DEFAULT_DEVICE_INTERFACE + ERROR_INTERFACE_DEVICE_ACTIVE Errno = ERROR_DEVICE_INTERFACE_ACTIVE + ERROR_INTERFACE_DEVICE_REMOVED Errno = ERROR_DEVICE_INTERFACE_REMOVED + ERROR_NO_SUCH_INTERFACE_DEVICE Errno = ERROR_NO_SUCH_DEVICE_INTERFACE +) + +const ( + MAX_DEVICE_ID_LEN = 200 + MAX_DEVNODE_ID_LEN = MAX_DEVICE_ID_LEN + MAX_GUID_STRING_LEN = 39 // 38 chars + terminator null + MAX_CLASS_NAME_LEN = 32 + MAX_PROFILE_LEN = 80 + MAX_CONFIG_VALUE = 9999 + MAX_INSTANCE_VALUE = 9999 + CONFIGMG_VERSION = 0x0400 +) + +// Maximum string length constants +const ( + LINE_LEN = 256 // Windows 9x-compatible maximum for displayable strings coming from a device INF. + MAX_INF_STRING_LENGTH = 4096 // Actual maximum size of an INF string (including string substitutions). + MAX_INF_SECTION_NAME_LENGTH = 255 // For Windows 9x compatibility, INF section names should be constrained to 32 characters. + MAX_TITLE_LEN = 60 + MAX_INSTRUCTION_LEN = 256 + MAX_LABEL_LEN = 30 + MAX_SERVICE_NAME_LEN = 256 + MAX_SUBTITLE_LEN = 256 +) + +const ( + // SP_MAX_MACHINENAME_LENGTH defines maximum length of a machine name in the format expected by ConfigMgr32 CM_Connect_Machine (i.e., "\\\\MachineName\0"). + SP_MAX_MACHINENAME_LENGTH = MAX_PATH + 3 +) + +// HSPFILEQ is type for setup file queue +type HSPFILEQ uintptr + +// DevInfo holds reference to device information set +type DevInfo Handle + +// DEVINST is a handle usually recognized by cfgmgr32 APIs +type DEVINST uint32 + +// DevInfoData is a device information structure (references a device instance that is a member of a device information set) +type DevInfoData struct { + size uint32 + ClassGUID GUID + DevInst DEVINST + _ uintptr +} + +// DevInfoListDetailData is a structure for detailed information on a device information set (used for SetupDiGetDeviceInfoListDetail which supersedes the functionality of SetupDiGetDeviceInfoListClass). +type DevInfoListDetailData struct { + size uint32 // Use unsafeSizeOf method + ClassGUID GUID + RemoteMachineHandle Handle + remoteMachineName [SP_MAX_MACHINENAME_LENGTH]uint16 +} + +func (*DevInfoListDetailData) unsafeSizeOf() uint32 { + if unsafe.Sizeof(uintptr(0)) == 4 { + // Windows declares this with pshpack1.h + return uint32(unsafe.Offsetof(DevInfoListDetailData{}.remoteMachineName) + unsafe.Sizeof(DevInfoListDetailData{}.remoteMachineName)) + } + return uint32(unsafe.Sizeof(DevInfoListDetailData{})) +} + +func (data *DevInfoListDetailData) RemoteMachineName() string { + return UTF16ToString(data.remoteMachineName[:]) +} + +func (data *DevInfoListDetailData) SetRemoteMachineName(remoteMachineName string) error { + str, err := UTF16FromString(remoteMachineName) + if err != nil { + return err + } + copy(data.remoteMachineName[:], str) + return nil +} + +// DI_FUNCTION is function type for device installer +type DI_FUNCTION uint32 + +const ( + DIF_SELECTDEVICE DI_FUNCTION = 0x00000001 + DIF_INSTALLDEVICE DI_FUNCTION = 0x00000002 + DIF_ASSIGNRESOURCES DI_FUNCTION = 0x00000003 + DIF_PROPERTIES DI_FUNCTION = 0x00000004 + DIF_REMOVE DI_FUNCTION = 0x00000005 + DIF_FIRSTTIMESETUP DI_FUNCTION = 0x00000006 + DIF_FOUNDDEVICE DI_FUNCTION = 0x00000007 + DIF_SELECTCLASSDRIVERS DI_FUNCTION = 0x00000008 + DIF_VALIDATECLASSDRIVERS DI_FUNCTION = 0x00000009 + DIF_INSTALLCLASSDRIVERS DI_FUNCTION = 0x0000000A + DIF_CALCDISKSPACE DI_FUNCTION = 0x0000000B + DIF_DESTROYPRIVATEDATA DI_FUNCTION = 0x0000000C + DIF_VALIDATEDRIVER DI_FUNCTION = 0x0000000D + DIF_DETECT DI_FUNCTION = 0x0000000F + DIF_INSTALLWIZARD DI_FUNCTION = 0x00000010 + DIF_DESTROYWIZARDDATA DI_FUNCTION = 0x00000011 + DIF_PROPERTYCHANGE DI_FUNCTION = 0x00000012 + DIF_ENABLECLASS DI_FUNCTION = 0x00000013 + DIF_DETECTVERIFY DI_FUNCTION = 0x00000014 + DIF_INSTALLDEVICEFILES DI_FUNCTION = 0x00000015 + DIF_UNREMOVE DI_FUNCTION = 0x00000016 + DIF_SELECTBESTCOMPATDRV DI_FUNCTION = 0x00000017 + DIF_ALLOW_INSTALL DI_FUNCTION = 0x00000018 + DIF_REGISTERDEVICE DI_FUNCTION = 0x00000019 + DIF_NEWDEVICEWIZARD_PRESELECT DI_FUNCTION = 0x0000001A + DIF_NEWDEVICEWIZARD_SELECT DI_FUNCTION = 0x0000001B + DIF_NEWDEVICEWIZARD_PREANALYZE DI_FUNCTION = 0x0000001C + DIF_NEWDEVICEWIZARD_POSTANALYZE DI_FUNCTION = 0x0000001D + DIF_NEWDEVICEWIZARD_FINISHINSTALL DI_FUNCTION = 0x0000001E + DIF_INSTALLINTERFACES DI_FUNCTION = 0x00000020 + DIF_DETECTCANCEL DI_FUNCTION = 0x00000021 + DIF_REGISTER_COINSTALLERS DI_FUNCTION = 0x00000022 + DIF_ADDPROPERTYPAGE_ADVANCED DI_FUNCTION = 0x00000023 + DIF_ADDPROPERTYPAGE_BASIC DI_FUNCTION = 0x00000024 + DIF_TROUBLESHOOTER DI_FUNCTION = 0x00000026 + DIF_POWERMESSAGEWAKE DI_FUNCTION = 0x00000027 + DIF_ADDREMOTEPROPERTYPAGE_ADVANCED DI_FUNCTION = 0x00000028 + DIF_UPDATEDRIVER_UI DI_FUNCTION = 0x00000029 + DIF_FINISHINSTALL_ACTION DI_FUNCTION = 0x0000002A +) + +// DevInstallParams is device installation parameters structure (associated with a particular device information element, or globally with a device information set) +type DevInstallParams struct { + size uint32 + Flags DI_FLAGS + FlagsEx DI_FLAGSEX + hwndParent uintptr + InstallMsgHandler uintptr + InstallMsgHandlerContext uintptr + FileQueue HSPFILEQ + _ uintptr + _ uint32 + driverPath [MAX_PATH]uint16 +} + +func (params *DevInstallParams) DriverPath() string { + return UTF16ToString(params.driverPath[:]) +} + +func (params *DevInstallParams) SetDriverPath(driverPath string) error { + str, err := UTF16FromString(driverPath) + if err != nil { + return err + } + copy(params.driverPath[:], str) + return nil +} + +// DI_FLAGS is SP_DEVINSTALL_PARAMS.Flags values +type DI_FLAGS uint32 + +const ( + // Flags for choosing a device + DI_SHOWOEM DI_FLAGS = 0x00000001 // support Other... button + DI_SHOWCOMPAT DI_FLAGS = 0x00000002 // show compatibility list + DI_SHOWCLASS DI_FLAGS = 0x00000004 // show class list + DI_SHOWALL DI_FLAGS = 0x00000007 // both class & compat list shown + DI_NOVCP DI_FLAGS = 0x00000008 // don't create a new copy queue--use caller-supplied FileQueue + DI_DIDCOMPAT DI_FLAGS = 0x00000010 // Searched for compatible devices + DI_DIDCLASS DI_FLAGS = 0x00000020 // Searched for class devices + DI_AUTOASSIGNRES DI_FLAGS = 0x00000040 // No UI for resources if possible + + // Flags returned by DiInstallDevice to indicate need to reboot/restart + DI_NEEDRESTART DI_FLAGS = 0x00000080 // Reboot required to take effect + DI_NEEDREBOOT DI_FLAGS = 0x00000100 // "" + + // Flags for device installation + DI_NOBROWSE DI_FLAGS = 0x00000200 // no Browse... in InsertDisk + + // Flags set by DiBuildDriverInfoList + DI_MULTMFGS DI_FLAGS = 0x00000400 // Set if multiple manufacturers in class driver list + + // Flag indicates that device is disabled + DI_DISABLED DI_FLAGS = 0x00000800 // Set if device disabled + + // Flags for Device/Class Properties + DI_GENERALPAGE_ADDED DI_FLAGS = 0x00001000 + DI_RESOURCEPAGE_ADDED DI_FLAGS = 0x00002000 + + // Flag to indicate the setting properties for this Device (or class) caused a change so the Dev Mgr UI probably needs to be updated. + DI_PROPERTIES_CHANGE DI_FLAGS = 0x00004000 + + // Flag to indicate that the sorting from the INF file should be used. + DI_INF_IS_SORTED DI_FLAGS = 0x00008000 + + // Flag to indicate that only the the INF specified by SP_DEVINSTALL_PARAMS.DriverPath should be searched. + DI_ENUMSINGLEINF DI_FLAGS = 0x00010000 + + // Flag that prevents ConfigMgr from removing/re-enumerating devices during device + // registration, installation, and deletion. + DI_DONOTCALLCONFIGMG DI_FLAGS = 0x00020000 + + // The following flag can be used to install a device disabled + DI_INSTALLDISABLED DI_FLAGS = 0x00040000 + + // Flag that causes SetupDiBuildDriverInfoList to build a device's compatible driver + // list from its existing class driver list, instead of the normal INF search. + DI_COMPAT_FROM_CLASS DI_FLAGS = 0x00080000 + + // This flag is set if the Class Install params should be used. + DI_CLASSINSTALLPARAMS DI_FLAGS = 0x00100000 + + // This flag is set if the caller of DiCallClassInstaller does NOT want the internal default action performed if the Class installer returns ERROR_DI_DO_DEFAULT. + DI_NODI_DEFAULTACTION DI_FLAGS = 0x00200000 + + // Flags for device installation + DI_QUIETINSTALL DI_FLAGS = 0x00800000 // don't confuse the user with questions or excess info + DI_NOFILECOPY DI_FLAGS = 0x01000000 // No file Copy necessary + DI_FORCECOPY DI_FLAGS = 0x02000000 // Force files to be copied from install path + DI_DRIVERPAGE_ADDED DI_FLAGS = 0x04000000 // Prop provider added Driver page. + DI_USECI_SELECTSTRINGS DI_FLAGS = 0x08000000 // Use Class Installer Provided strings in the Select Device Dlg + DI_OVERRIDE_INFFLAGS DI_FLAGS = 0x10000000 // Override INF flags + DI_PROPS_NOCHANGEUSAGE DI_FLAGS = 0x20000000 // No Enable/Disable in General Props + + DI_NOSELECTICONS DI_FLAGS = 0x40000000 // No small icons in select device dialogs + + DI_NOWRITE_IDS DI_FLAGS = 0x80000000 // Don't write HW & Compat IDs on install +) + +// DI_FLAGSEX is SP_DEVINSTALL_PARAMS.FlagsEx values +type DI_FLAGSEX uint32 + +const ( + DI_FLAGSEX_CI_FAILED DI_FLAGSEX = 0x00000004 // Failed to Load/Call class installer + DI_FLAGSEX_FINISHINSTALL_ACTION DI_FLAGSEX = 0x00000008 // Class/co-installer wants to get a DIF_FINISH_INSTALL action in client context. + DI_FLAGSEX_DIDINFOLIST DI_FLAGSEX = 0x00000010 // Did the Class Info List + DI_FLAGSEX_DIDCOMPATINFO DI_FLAGSEX = 0x00000020 // Did the Compat Info List + DI_FLAGSEX_FILTERCLASSES DI_FLAGSEX = 0x00000040 + DI_FLAGSEX_SETFAILEDINSTALL DI_FLAGSEX = 0x00000080 + DI_FLAGSEX_DEVICECHANGE DI_FLAGSEX = 0x00000100 + DI_FLAGSEX_ALWAYSWRITEIDS DI_FLAGSEX = 0x00000200 + DI_FLAGSEX_PROPCHANGE_PENDING DI_FLAGSEX = 0x00000400 // One or more device property sheets have had changes made to them, and need to have a DIF_PROPERTYCHANGE occur. + DI_FLAGSEX_ALLOWEXCLUDEDDRVS DI_FLAGSEX = 0x00000800 + DI_FLAGSEX_NOUIONQUERYREMOVE DI_FLAGSEX = 0x00001000 + DI_FLAGSEX_USECLASSFORCOMPAT DI_FLAGSEX = 0x00002000 // Use the device's class when building compat drv list. (Ignored if DI_COMPAT_FROM_CLASS flag is specified.) + DI_FLAGSEX_NO_DRVREG_MODIFY DI_FLAGSEX = 0x00008000 // Don't run AddReg and DelReg for device's software (driver) key. + DI_FLAGSEX_IN_SYSTEM_SETUP DI_FLAGSEX = 0x00010000 // Installation is occurring during initial system setup. + DI_FLAGSEX_INET_DRIVER DI_FLAGSEX = 0x00020000 // Driver came from Windows Update + DI_FLAGSEX_APPENDDRIVERLIST DI_FLAGSEX = 0x00040000 // Cause SetupDiBuildDriverInfoList to append a new driver list to an existing list. + DI_FLAGSEX_PREINSTALLBACKUP DI_FLAGSEX = 0x00080000 // not used + DI_FLAGSEX_BACKUPONREPLACE DI_FLAGSEX = 0x00100000 // not used + DI_FLAGSEX_DRIVERLIST_FROM_URL DI_FLAGSEX = 0x00200000 // build driver list from INF(s) retrieved from URL specified in SP_DEVINSTALL_PARAMS.DriverPath (empty string means Windows Update website) + DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS DI_FLAGSEX = 0x00800000 // Don't include old Internet drivers when building a driver list. Ignored on Windows Vista and later. + DI_FLAGSEX_POWERPAGE_ADDED DI_FLAGSEX = 0x01000000 // class installer added their own power page + DI_FLAGSEX_FILTERSIMILARDRIVERS DI_FLAGSEX = 0x02000000 // only include similar drivers in class list + DI_FLAGSEX_INSTALLEDDRIVER DI_FLAGSEX = 0x04000000 // only add the installed driver to the class or compat driver list. Used in calls to SetupDiBuildDriverInfoList + DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE DI_FLAGSEX = 0x08000000 // Don't remove identical driver nodes from the class list + DI_FLAGSEX_ALTPLATFORM_DRVSEARCH DI_FLAGSEX = 0x10000000 // Build driver list based on alternate platform information specified in associated file queue + DI_FLAGSEX_RESTART_DEVICE_ONLY DI_FLAGSEX = 0x20000000 // only restart the device drivers are being installed on as opposed to restarting all devices using those drivers. + DI_FLAGSEX_RECURSIVESEARCH DI_FLAGSEX = 0x40000000 // Tell SetupDiBuildDriverInfoList to do a recursive search + DI_FLAGSEX_SEARCH_PUBLISHED_INFS DI_FLAGSEX = 0x80000000 // Tell SetupDiBuildDriverInfoList to do a "published INF" search +) + +// ClassInstallHeader is the first member of any class install parameters structure. It contains the device installation request code that defines the format of the rest of the install parameters structure. +type ClassInstallHeader struct { + size uint32 + InstallFunction DI_FUNCTION +} + +func MakeClassInstallHeader(installFunction DI_FUNCTION) *ClassInstallHeader { + hdr := &ClassInstallHeader{InstallFunction: installFunction} + hdr.size = uint32(unsafe.Sizeof(*hdr)) + return hdr +} + +// DICS_STATE specifies values indicating a change in a device's state +type DICS_STATE uint32 + +const ( + DICS_ENABLE DICS_STATE = 0x00000001 // The device is being enabled. + DICS_DISABLE DICS_STATE = 0x00000002 // The device is being disabled. + DICS_PROPCHANGE DICS_STATE = 0x00000003 // The properties of the device have changed. + DICS_START DICS_STATE = 0x00000004 // The device is being started (if the request is for the currently active hardware profile). + DICS_STOP DICS_STATE = 0x00000005 // The device is being stopped. The driver stack will be unloaded and the CSCONFIGFLAG_DO_NOT_START flag will be set for the device. +) + +// DICS_FLAG specifies the scope of a device property change +type DICS_FLAG uint32 + +const ( + DICS_FLAG_GLOBAL DICS_FLAG = 0x00000001 // make change in all hardware profiles + DICS_FLAG_CONFIGSPECIFIC DICS_FLAG = 0x00000002 // make change in specified profile only + DICS_FLAG_CONFIGGENERAL DICS_FLAG = 0x00000004 // 1 or more hardware profile-specific changes to follow (obsolete) +) + +// PropChangeParams is a structure corresponding to a DIF_PROPERTYCHANGE install function. +type PropChangeParams struct { + ClassInstallHeader ClassInstallHeader + StateChange DICS_STATE + Scope DICS_FLAG + HwProfile uint32 +} + +// DI_REMOVEDEVICE specifies the scope of the device removal +type DI_REMOVEDEVICE uint32 + +const ( + DI_REMOVEDEVICE_GLOBAL DI_REMOVEDEVICE = 0x00000001 // Make this change in all hardware profiles. Remove information about the device from the registry. + DI_REMOVEDEVICE_CONFIGSPECIFIC DI_REMOVEDEVICE = 0x00000002 // Make this change to only the hardware profile specified by HwProfile. this flag only applies to root-enumerated devices. When Windows removes the device from the last hardware profile in which it was configured, Windows performs a global removal. +) + +// RemoveDeviceParams is a structure corresponding to a DIF_REMOVE install function. +type RemoveDeviceParams struct { + ClassInstallHeader ClassInstallHeader + Scope DI_REMOVEDEVICE + HwProfile uint32 +} + +// DrvInfoData is driver information structure (member of a driver info list that may be associated with a particular device instance, or (globally) with a device information set) +type DrvInfoData struct { + size uint32 + DriverType uint32 + _ uintptr + description [LINE_LEN]uint16 + mfgName [LINE_LEN]uint16 + providerName [LINE_LEN]uint16 + DriverDate Filetime + DriverVersion uint64 +} + +func (data *DrvInfoData) Description() string { + return UTF16ToString(data.description[:]) +} + +func (data *DrvInfoData) SetDescription(description string) error { + str, err := UTF16FromString(description) + if err != nil { + return err + } + copy(data.description[:], str) + return nil +} + +func (data *DrvInfoData) MfgName() string { + return UTF16ToString(data.mfgName[:]) +} + +func (data *DrvInfoData) SetMfgName(mfgName string) error { + str, err := UTF16FromString(mfgName) + if err != nil { + return err + } + copy(data.mfgName[:], str) + return nil +} + +func (data *DrvInfoData) ProviderName() string { + return UTF16ToString(data.providerName[:]) +} + +func (data *DrvInfoData) SetProviderName(providerName string) error { + str, err := UTF16FromString(providerName) + if err != nil { + return err + } + copy(data.providerName[:], str) + return nil +} + +// IsNewer method returns true if DrvInfoData date and version is newer than supplied parameters. +func (data *DrvInfoData) IsNewer(driverDate Filetime, driverVersion uint64) bool { + if data.DriverDate.HighDateTime > driverDate.HighDateTime { + return true + } + if data.DriverDate.HighDateTime < driverDate.HighDateTime { + return false + } + + if data.DriverDate.LowDateTime > driverDate.LowDateTime { + return true + } + if data.DriverDate.LowDateTime < driverDate.LowDateTime { + return false + } + + if data.DriverVersion > driverVersion { + return true + } + if data.DriverVersion < driverVersion { + return false + } + + return false +} + +// DrvInfoDetailData is driver information details structure (provides detailed information about a particular driver information structure) +type DrvInfoDetailData struct { + size uint32 // Use unsafeSizeOf method + InfDate Filetime + compatIDsOffset uint32 + compatIDsLength uint32 + _ uintptr + sectionName [LINE_LEN]uint16 + infFileName [MAX_PATH]uint16 + drvDescription [LINE_LEN]uint16 + hardwareID [1]uint16 +} + +func (*DrvInfoDetailData) unsafeSizeOf() uint32 { + if unsafe.Sizeof(uintptr(0)) == 4 { + // Windows declares this with pshpack1.h + return uint32(unsafe.Offsetof(DrvInfoDetailData{}.hardwareID) + unsafe.Sizeof(DrvInfoDetailData{}.hardwareID)) + } + return uint32(unsafe.Sizeof(DrvInfoDetailData{})) +} + +func (data *DrvInfoDetailData) SectionName() string { + return UTF16ToString(data.sectionName[:]) +} + +func (data *DrvInfoDetailData) InfFileName() string { + return UTF16ToString(data.infFileName[:]) +} + +func (data *DrvInfoDetailData) DrvDescription() string { + return UTF16ToString(data.drvDescription[:]) +} + +func (data *DrvInfoDetailData) HardwareID() string { + if data.compatIDsOffset > 1 { + bufW := data.getBuf() + return UTF16ToString(bufW[:wcslen(bufW)]) + } + + return "" +} + +func (data *DrvInfoDetailData) CompatIDs() []string { + a := make([]string, 0) + + if data.compatIDsLength > 0 { + bufW := data.getBuf() + bufW = bufW[data.compatIDsOffset : data.compatIDsOffset+data.compatIDsLength] + for i := 0; i < len(bufW); { + j := i + wcslen(bufW[i:]) + if i < j { + a = append(a, UTF16ToString(bufW[i:j])) + } + i = j + 1 + } + } + + return a +} + +func (data *DrvInfoDetailData) getBuf() []uint16 { + len := (data.size - uint32(unsafe.Offsetof(data.hardwareID))) / 2 + sl := struct { + addr *uint16 + len int + cap int + }{&data.hardwareID[0], int(len), int(len)} + return *(*[]uint16)(unsafe.Pointer(&sl)) +} + +// IsCompatible method tests if given hardware ID matches the driver or is listed on the compatible ID list. +func (data *DrvInfoDetailData) IsCompatible(hwid string) bool { + hwidLC := strings.ToLower(hwid) + if strings.ToLower(data.HardwareID()) == hwidLC { + return true + } + a := data.CompatIDs() + for i := range a { + if strings.ToLower(a[i]) == hwidLC { + return true + } + } + + return false +} + +// DICD flags control SetupDiCreateDeviceInfo +type DICD uint32 + +const ( + DICD_GENERATE_ID DICD = 0x00000001 + DICD_INHERIT_CLASSDRVS DICD = 0x00000002 +) + +// SUOI flags control SetupUninstallOEMInf +type SUOI uint32 + +const ( + SUOI_FORCEDELETE SUOI = 0x0001 +) + +// SPDIT flags to distinguish between class drivers and +// device drivers. (Passed in 'DriverType' parameter of +// driver information list APIs) +type SPDIT uint32 + +const ( + SPDIT_NODRIVER SPDIT = 0x00000000 + SPDIT_CLASSDRIVER SPDIT = 0x00000001 + SPDIT_COMPATDRIVER SPDIT = 0x00000002 +) + +// DIGCF flags control what is included in the device information set built by SetupDiGetClassDevs +type DIGCF uint32 + +const ( + DIGCF_DEFAULT DIGCF = 0x00000001 // only valid with DIGCF_DEVICEINTERFACE + DIGCF_PRESENT DIGCF = 0x00000002 + DIGCF_ALLCLASSES DIGCF = 0x00000004 + DIGCF_PROFILE DIGCF = 0x00000008 + DIGCF_DEVICEINTERFACE DIGCF = 0x00000010 +) + +// DIREG specifies values for SetupDiCreateDevRegKey, SetupDiOpenDevRegKey, and SetupDiDeleteDevRegKey. +type DIREG uint32 + +const ( + DIREG_DEV DIREG = 0x00000001 // Open/Create/Delete device key + DIREG_DRV DIREG = 0x00000002 // Open/Create/Delete driver key + DIREG_BOTH DIREG = 0x00000004 // Delete both driver and Device key +) + +// SPDRP specifies device registry property codes +// (Codes marked as read-only (R) may only be used for +// SetupDiGetDeviceRegistryProperty) +// +// These values should cover the same set of registry properties +// as defined by the CM_DRP codes in cfgmgr32.h. +// +// Note that SPDRP codes are zero based while CM_DRP codes are one based! +type SPDRP uint32 + +const ( + SPDRP_DEVICEDESC SPDRP = 0x00000000 // DeviceDesc (R/W) + SPDRP_HARDWAREID SPDRP = 0x00000001 // HardwareID (R/W) + SPDRP_COMPATIBLEIDS SPDRP = 0x00000002 // CompatibleIDs (R/W) + SPDRP_SERVICE SPDRP = 0x00000004 // Service (R/W) + SPDRP_CLASS SPDRP = 0x00000007 // Class (R--tied to ClassGUID) + SPDRP_CLASSGUID SPDRP = 0x00000008 // ClassGUID (R/W) + SPDRP_DRIVER SPDRP = 0x00000009 // Driver (R/W) + SPDRP_CONFIGFLAGS SPDRP = 0x0000000A // ConfigFlags (R/W) + SPDRP_MFG SPDRP = 0x0000000B // Mfg (R/W) + SPDRP_FRIENDLYNAME SPDRP = 0x0000000C // FriendlyName (R/W) + SPDRP_LOCATION_INFORMATION SPDRP = 0x0000000D // LocationInformation (R/W) + SPDRP_PHYSICAL_DEVICE_OBJECT_NAME SPDRP = 0x0000000E // PhysicalDeviceObjectName (R) + SPDRP_CAPABILITIES SPDRP = 0x0000000F // Capabilities (R) + SPDRP_UI_NUMBER SPDRP = 0x00000010 // UiNumber (R) + SPDRP_UPPERFILTERS SPDRP = 0x00000011 // UpperFilters (R/W) + SPDRP_LOWERFILTERS SPDRP = 0x00000012 // LowerFilters (R/W) + SPDRP_BUSTYPEGUID SPDRP = 0x00000013 // BusTypeGUID (R) + SPDRP_LEGACYBUSTYPE SPDRP = 0x00000014 // LegacyBusType (R) + SPDRP_BUSNUMBER SPDRP = 0x00000015 // BusNumber (R) + SPDRP_ENUMERATOR_NAME SPDRP = 0x00000016 // Enumerator Name (R) + SPDRP_SECURITY SPDRP = 0x00000017 // Security (R/W, binary form) + SPDRP_SECURITY_SDS SPDRP = 0x00000018 // Security (W, SDS form) + SPDRP_DEVTYPE SPDRP = 0x00000019 // Device Type (R/W) + SPDRP_EXCLUSIVE SPDRP = 0x0000001A // Device is exclusive-access (R/W) + SPDRP_CHARACTERISTICS SPDRP = 0x0000001B // Device Characteristics (R/W) + SPDRP_ADDRESS SPDRP = 0x0000001C // Device Address (R) + SPDRP_UI_NUMBER_DESC_FORMAT SPDRP = 0x0000001D // UiNumberDescFormat (R/W) + SPDRP_DEVICE_POWER_DATA SPDRP = 0x0000001E // Device Power Data (R) + SPDRP_REMOVAL_POLICY SPDRP = 0x0000001F // Removal Policy (R) + SPDRP_REMOVAL_POLICY_HW_DEFAULT SPDRP = 0x00000020 // Hardware Removal Policy (R) + SPDRP_REMOVAL_POLICY_OVERRIDE SPDRP = 0x00000021 // Removal Policy Override (RW) + SPDRP_INSTALL_STATE SPDRP = 0x00000022 // Device Install State (R) + SPDRP_LOCATION_PATHS SPDRP = 0x00000023 // Device Location Paths (R) + SPDRP_BASE_CONTAINERID SPDRP = 0x00000024 // Base ContainerID (R) + + SPDRP_MAXIMUM_PROPERTY SPDRP = 0x00000025 // Upper bound on ordinals +) + +// DEVPROPTYPE represents the property-data-type identifier that specifies the +// data type of a device property value in the unified device property model. +type DEVPROPTYPE uint32 + +const ( + DEVPROP_TYPEMOD_ARRAY DEVPROPTYPE = 0x00001000 + DEVPROP_TYPEMOD_LIST DEVPROPTYPE = 0x00002000 + + DEVPROP_TYPE_EMPTY DEVPROPTYPE = 0x00000000 + DEVPROP_TYPE_NULL DEVPROPTYPE = 0x00000001 + DEVPROP_TYPE_SBYTE DEVPROPTYPE = 0x00000002 + DEVPROP_TYPE_BYTE DEVPROPTYPE = 0x00000003 + DEVPROP_TYPE_INT16 DEVPROPTYPE = 0x00000004 + DEVPROP_TYPE_UINT16 DEVPROPTYPE = 0x00000005 + DEVPROP_TYPE_INT32 DEVPROPTYPE = 0x00000006 + DEVPROP_TYPE_UINT32 DEVPROPTYPE = 0x00000007 + DEVPROP_TYPE_INT64 DEVPROPTYPE = 0x00000008 + DEVPROP_TYPE_UINT64 DEVPROPTYPE = 0x00000009 + DEVPROP_TYPE_FLOAT DEVPROPTYPE = 0x0000000A + DEVPROP_TYPE_DOUBLE DEVPROPTYPE = 0x0000000B + DEVPROP_TYPE_DECIMAL DEVPROPTYPE = 0x0000000C + DEVPROP_TYPE_GUID DEVPROPTYPE = 0x0000000D + DEVPROP_TYPE_CURRENCY DEVPROPTYPE = 0x0000000E + DEVPROP_TYPE_DATE DEVPROPTYPE = 0x0000000F + DEVPROP_TYPE_FILETIME DEVPROPTYPE = 0x00000010 + DEVPROP_TYPE_BOOLEAN DEVPROPTYPE = 0x00000011 + DEVPROP_TYPE_STRING DEVPROPTYPE = 0x00000012 + DEVPROP_TYPE_STRING_LIST DEVPROPTYPE = DEVPROP_TYPE_STRING | DEVPROP_TYPEMOD_LIST + DEVPROP_TYPE_SECURITY_DESCRIPTOR DEVPROPTYPE = 0x00000013 + DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING DEVPROPTYPE = 0x00000014 + DEVPROP_TYPE_DEVPROPKEY DEVPROPTYPE = 0x00000015 + DEVPROP_TYPE_DEVPROPTYPE DEVPROPTYPE = 0x00000016 + DEVPROP_TYPE_BINARY DEVPROPTYPE = DEVPROP_TYPE_BYTE | DEVPROP_TYPEMOD_ARRAY + DEVPROP_TYPE_ERROR DEVPROPTYPE = 0x00000017 + DEVPROP_TYPE_NTSTATUS DEVPROPTYPE = 0x00000018 + DEVPROP_TYPE_STRING_INDIRECT DEVPROPTYPE = 0x00000019 + + MAX_DEVPROP_TYPE DEVPROPTYPE = 0x00000019 + MAX_DEVPROP_TYPEMOD DEVPROPTYPE = 0x00002000 + + DEVPROP_MASK_TYPE DEVPROPTYPE = 0x00000FFF + DEVPROP_MASK_TYPEMOD DEVPROPTYPE = 0x0000F000 +) + +// DEVPROPGUID specifies a property category. +type DEVPROPGUID GUID + +// DEVPROPID uniquely identifies the property within the property category. +type DEVPROPID uint32 + +const DEVPROPID_FIRST_USABLE DEVPROPID = 2 + +// DEVPROPKEY represents a device property key for a device property in the +// unified device property model. +type DEVPROPKEY struct { + FmtID DEVPROPGUID + PID DEVPROPID +} + +// CONFIGRET is a return value or error code from cfgmgr32 APIs +type CONFIGRET uint32 + +func (ret CONFIGRET) Error() string { + if win32Error, ok := ret.Unwrap().(Errno); ok { + return fmt.Sprintf("%s (CfgMgr error: 0x%08x)", win32Error.Error(), uint32(ret)) + } + return fmt.Sprintf("CfgMgr error: 0x%08x", uint32(ret)) +} + +func (ret CONFIGRET) Win32Error(defaultError Errno) Errno { + return cm_MapCrToWin32Err(ret, defaultError) +} + +func (ret CONFIGRET) Unwrap() error { + const noMatch = Errno(^uintptr(0)) + win32Error := ret.Win32Error(noMatch) + if win32Error == noMatch { + return nil + } + return win32Error +} + +const ( + CR_SUCCESS CONFIGRET = 0x00000000 + CR_DEFAULT CONFIGRET = 0x00000001 + CR_OUT_OF_MEMORY CONFIGRET = 0x00000002 + CR_INVALID_POINTER CONFIGRET = 0x00000003 + CR_INVALID_FLAG CONFIGRET = 0x00000004 + CR_INVALID_DEVNODE CONFIGRET = 0x00000005 + CR_INVALID_DEVINST = CR_INVALID_DEVNODE + CR_INVALID_RES_DES CONFIGRET = 0x00000006 + CR_INVALID_LOG_CONF CONFIGRET = 0x00000007 + CR_INVALID_ARBITRATOR CONFIGRET = 0x00000008 + CR_INVALID_NODELIST CONFIGRET = 0x00000009 + CR_DEVNODE_HAS_REQS CONFIGRET = 0x0000000A + CR_DEVINST_HAS_REQS = CR_DEVNODE_HAS_REQS + CR_INVALID_RESOURCEID CONFIGRET = 0x0000000B + CR_DLVXD_NOT_FOUND CONFIGRET = 0x0000000C + CR_NO_SUCH_DEVNODE CONFIGRET = 0x0000000D + CR_NO_SUCH_DEVINST = CR_NO_SUCH_DEVNODE + CR_NO_MORE_LOG_CONF CONFIGRET = 0x0000000E + CR_NO_MORE_RES_DES CONFIGRET = 0x0000000F + CR_ALREADY_SUCH_DEVNODE CONFIGRET = 0x00000010 + CR_ALREADY_SUCH_DEVINST = CR_ALREADY_SUCH_DEVNODE + CR_INVALID_RANGE_LIST CONFIGRET = 0x00000011 + CR_INVALID_RANGE CONFIGRET = 0x00000012 + CR_FAILURE CONFIGRET = 0x00000013 + CR_NO_SUCH_LOGICAL_DEV CONFIGRET = 0x00000014 + CR_CREATE_BLOCKED CONFIGRET = 0x00000015 + CR_NOT_SYSTEM_VM CONFIGRET = 0x00000016 + CR_REMOVE_VETOED CONFIGRET = 0x00000017 + CR_APM_VETOED CONFIGRET = 0x00000018 + CR_INVALID_LOAD_TYPE CONFIGRET = 0x00000019 + CR_BUFFER_SMALL CONFIGRET = 0x0000001A + CR_NO_ARBITRATOR CONFIGRET = 0x0000001B + CR_NO_REGISTRY_HANDLE CONFIGRET = 0x0000001C + CR_REGISTRY_ERROR CONFIGRET = 0x0000001D + CR_INVALID_DEVICE_ID CONFIGRET = 0x0000001E + CR_INVALID_DATA CONFIGRET = 0x0000001F + CR_INVALID_API CONFIGRET = 0x00000020 + CR_DEVLOADER_NOT_READY CONFIGRET = 0x00000021 + CR_NEED_RESTART CONFIGRET = 0x00000022 + CR_NO_MORE_HW_PROFILES CONFIGRET = 0x00000023 + CR_DEVICE_NOT_THERE CONFIGRET = 0x00000024 + CR_NO_SUCH_VALUE CONFIGRET = 0x00000025 + CR_WRONG_TYPE CONFIGRET = 0x00000026 + CR_INVALID_PRIORITY CONFIGRET = 0x00000027 + CR_NOT_DISABLEABLE CONFIGRET = 0x00000028 + CR_FREE_RESOURCES CONFIGRET = 0x00000029 + CR_QUERY_VETOED CONFIGRET = 0x0000002A + CR_CANT_SHARE_IRQ CONFIGRET = 0x0000002B + CR_NO_DEPENDENT CONFIGRET = 0x0000002C + CR_SAME_RESOURCES CONFIGRET = 0x0000002D + CR_NO_SUCH_REGISTRY_KEY CONFIGRET = 0x0000002E + CR_INVALID_MACHINENAME CONFIGRET = 0x0000002F + CR_REMOTE_COMM_FAILURE CONFIGRET = 0x00000030 + CR_MACHINE_UNAVAILABLE CONFIGRET = 0x00000031 + CR_NO_CM_SERVICES CONFIGRET = 0x00000032 + CR_ACCESS_DENIED CONFIGRET = 0x00000033 + CR_CALL_NOT_IMPLEMENTED CONFIGRET = 0x00000034 + CR_INVALID_PROPERTY CONFIGRET = 0x00000035 + CR_DEVICE_INTERFACE_ACTIVE CONFIGRET = 0x00000036 + CR_NO_SUCH_DEVICE_INTERFACE CONFIGRET = 0x00000037 + CR_INVALID_REFERENCE_STRING CONFIGRET = 0x00000038 + CR_INVALID_CONFLICT_LIST CONFIGRET = 0x00000039 + CR_INVALID_INDEX CONFIGRET = 0x0000003A + CR_INVALID_STRUCTURE_SIZE CONFIGRET = 0x0000003B + NUM_CR_RESULTS CONFIGRET = 0x0000003C +) + +const ( + CM_GET_DEVICE_INTERFACE_LIST_PRESENT = 0 // only currently 'live' device interfaces + CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES = 1 // all registered device interfaces, live or not +) + +const ( + DN_ROOT_ENUMERATED = 0x00000001 // Was enumerated by ROOT + DN_DRIVER_LOADED = 0x00000002 // Has Register_Device_Driver + DN_ENUM_LOADED = 0x00000004 // Has Register_Enumerator + DN_STARTED = 0x00000008 // Is currently configured + DN_MANUAL = 0x00000010 // Manually installed + DN_NEED_TO_ENUM = 0x00000020 // May need reenumeration + DN_NOT_FIRST_TIME = 0x00000040 // Has received a config + DN_HARDWARE_ENUM = 0x00000080 // Enum generates hardware ID + DN_LIAR = 0x00000100 // Lied about can reconfig once + DN_HAS_MARK = 0x00000200 // Not CM_Create_DevInst lately + DN_HAS_PROBLEM = 0x00000400 // Need device installer + DN_FILTERED = 0x00000800 // Is filtered + DN_MOVED = 0x00001000 // Has been moved + DN_DISABLEABLE = 0x00002000 // Can be disabled + DN_REMOVABLE = 0x00004000 // Can be removed + DN_PRIVATE_PROBLEM = 0x00008000 // Has a private problem + DN_MF_PARENT = 0x00010000 // Multi function parent + DN_MF_CHILD = 0x00020000 // Multi function child + DN_WILL_BE_REMOVED = 0x00040000 // DevInst is being removed + DN_NOT_FIRST_TIMEE = 0x00080000 // Has received a config enumerate + DN_STOP_FREE_RES = 0x00100000 // When child is stopped, free resources + DN_REBAL_CANDIDATE = 0x00200000 // Don't skip during rebalance + DN_BAD_PARTIAL = 0x00400000 // This devnode's log_confs do not have same resources + DN_NT_ENUMERATOR = 0x00800000 // This devnode's is an NT enumerator + DN_NT_DRIVER = 0x01000000 // This devnode's is an NT driver + DN_NEEDS_LOCKING = 0x02000000 // Devnode need lock resume processing + DN_ARM_WAKEUP = 0x04000000 // Devnode can be the wakeup device + DN_APM_ENUMERATOR = 0x08000000 // APM aware enumerator + DN_APM_DRIVER = 0x10000000 // APM aware driver + DN_SILENT_INSTALL = 0x20000000 // Silent install + DN_NO_SHOW_IN_DM = 0x40000000 // No show in device manager + DN_BOOT_LOG_PROB = 0x80000000 // Had a problem during preassignment of boot log conf + DN_NEED_RESTART = DN_LIAR // System needs to be restarted for this Devnode to work properly + DN_DRIVER_BLOCKED = DN_NOT_FIRST_TIME // One or more drivers are blocked from loading for this Devnode + DN_LEGACY_DRIVER = DN_MOVED // This device is using a legacy driver + DN_CHILD_WITH_INVALID_ID = DN_HAS_MARK // One or more children have invalid IDs + DN_DEVICE_DISCONNECTED = DN_NEEDS_LOCKING // The function driver for a device reported that the device is not connected. Typically this means a wireless device is out of range. + DN_QUERY_REMOVE_PENDING = DN_MF_PARENT // Device is part of a set of related devices collectively pending query-removal + DN_QUERY_REMOVE_ACTIVE = DN_MF_CHILD // Device is actively engaged in a query-remove IRP + DN_CHANGEABLE_FLAGS = DN_NOT_FIRST_TIME | DN_HARDWARE_ENUM | DN_HAS_MARK | DN_DISABLEABLE | DN_REMOVABLE | DN_MF_CHILD | DN_MF_PARENT | DN_NOT_FIRST_TIMEE | DN_STOP_FREE_RES | DN_REBAL_CANDIDATE | DN_NT_ENUMERATOR | DN_NT_DRIVER | DN_SILENT_INSTALL | DN_NO_SHOW_IN_DM +) + +//sys setupDiCreateDeviceInfoListEx(classGUID *GUID, hwndParent uintptr, machineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(InvalidHandle)] = setupapi.SetupDiCreateDeviceInfoListExW + +// SetupDiCreateDeviceInfoListEx function creates an empty device information set on a remote or a local computer and optionally associates the set with a device setup class. +func SetupDiCreateDeviceInfoListEx(classGUID *GUID, hwndParent uintptr, machineName string) (deviceInfoSet DevInfo, err error) { + var machineNameUTF16 *uint16 + if machineName != "" { + machineNameUTF16, err = UTF16PtrFromString(machineName) + if err != nil { + return + } + } + return setupDiCreateDeviceInfoListEx(classGUID, hwndParent, machineNameUTF16, 0) +} + +//sys setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailData *DevInfoListDetailData) (err error) = setupapi.SetupDiGetDeviceInfoListDetailW + +// SetupDiGetDeviceInfoListDetail function retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name. +func SetupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo) (deviceInfoSetDetailData *DevInfoListDetailData, err error) { + data := &DevInfoListDetailData{} + data.size = data.unsafeSizeOf() + + return data, setupDiGetDeviceInfoListDetail(deviceInfoSet, data) +} + +// DeviceInfoListDetail method retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name. +func (deviceInfoSet DevInfo) DeviceInfoListDetail() (*DevInfoListDetailData, error) { + return SetupDiGetDeviceInfoListDetail(deviceInfoSet) +} + +//sys setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUID *GUID, DeviceDescription *uint16, hwndParent uintptr, CreationFlags DICD, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiCreateDeviceInfoW + +// SetupDiCreateDeviceInfo function creates a new device information element and adds it as a new member to the specified device information set. +func SetupDiCreateDeviceInfo(deviceInfoSet DevInfo, deviceName string, classGUID *GUID, deviceDescription string, hwndParent uintptr, creationFlags DICD) (deviceInfoData *DevInfoData, err error) { + deviceNameUTF16, err := UTF16PtrFromString(deviceName) + if err != nil { + return + } + + var deviceDescriptionUTF16 *uint16 + if deviceDescription != "" { + deviceDescriptionUTF16, err = UTF16PtrFromString(deviceDescription) + if err != nil { + return + } + } + + data := &DevInfoData{} + data.size = uint32(unsafe.Sizeof(*data)) + + return data, setupDiCreateDeviceInfo(deviceInfoSet, deviceNameUTF16, classGUID, deviceDescriptionUTF16, hwndParent, creationFlags, data) +} + +// CreateDeviceInfo method creates a new device information element and adds it as a new member to the specified device information set. +func (deviceInfoSet DevInfo) CreateDeviceInfo(deviceName string, classGUID *GUID, deviceDescription string, hwndParent uintptr, creationFlags DICD) (*DevInfoData, error) { + return SetupDiCreateDeviceInfo(deviceInfoSet, deviceName, classGUID, deviceDescription, hwndParent, creationFlags) +} + +//sys setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiEnumDeviceInfo + +// SetupDiEnumDeviceInfo function returns a DevInfoData structure that specifies a device information element in a device information set. +func SetupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex int) (*DevInfoData, error) { + data := &DevInfoData{} + data.size = uint32(unsafe.Sizeof(*data)) + + return data, setupDiEnumDeviceInfo(deviceInfoSet, uint32(memberIndex), data) +} + +// EnumDeviceInfo method returns a DevInfoData structure that specifies a device information element in a device information set. +func (deviceInfoSet DevInfo) EnumDeviceInfo(memberIndex int) (*DevInfoData, error) { + return SetupDiEnumDeviceInfo(deviceInfoSet, memberIndex) +} + +// SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory. +//sys SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) = setupapi.SetupDiDestroyDeviceInfoList + +// Close method deletes a device information set and frees all associated memory. +func (deviceInfoSet DevInfo) Close() error { + return SetupDiDestroyDeviceInfoList(deviceInfoSet) +} + +//sys SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) = setupapi.SetupDiBuildDriverInfoList + +// BuildDriverInfoList method builds a list of drivers that is associated with a specific device or with the global class driver list for a device information set. +func (deviceInfoSet DevInfo) BuildDriverInfoList(deviceInfoData *DevInfoData, driverType SPDIT) error { + return SetupDiBuildDriverInfoList(deviceInfoSet, deviceInfoData, driverType) +} + +//sys SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) = setupapi.SetupDiCancelDriverInfoSearch + +// CancelDriverInfoSearch method cancels a driver list search that is currently in progress in a different thread. +func (deviceInfoSet DevInfo) CancelDriverInfoSearch() error { + return SetupDiCancelDriverInfoSearch(deviceInfoSet) +} + +//sys setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex uint32, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiEnumDriverInfoW + +// SetupDiEnumDriverInfo function enumerates the members of a driver list. +func SetupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex int) (*DrvInfoData, error) { + data := &DrvInfoData{} + data.size = uint32(unsafe.Sizeof(*data)) + + return data, setupDiEnumDriverInfo(deviceInfoSet, deviceInfoData, driverType, uint32(memberIndex), data) +} + +// EnumDriverInfo method enumerates the members of a driver list. +func (deviceInfoSet DevInfo) EnumDriverInfo(deviceInfoData *DevInfoData, driverType SPDIT, memberIndex int) (*DrvInfoData, error) { + return SetupDiEnumDriverInfo(deviceInfoSet, deviceInfoData, driverType, memberIndex) +} + +//sys setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiGetSelectedDriverW + +// SetupDiGetSelectedDriver function retrieves the selected driver for a device information set or a particular device information element. +func SetupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (*DrvInfoData, error) { + data := &DrvInfoData{} + data.size = uint32(unsafe.Sizeof(*data)) + + return data, setupDiGetSelectedDriver(deviceInfoSet, deviceInfoData, data) +} + +// SelectedDriver method retrieves the selected driver for a device information set or a particular device information element. +func (deviceInfoSet DevInfo) SelectedDriver(deviceInfoData *DevInfoData) (*DrvInfoData, error) { + return SetupDiGetSelectedDriver(deviceInfoSet, deviceInfoData) +} + +//sys SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiSetSelectedDriverW + +// SetSelectedDriver method sets, or resets, the selected driver for a device information element or the selected class driver for a device information set. +func (deviceInfoSet DevInfo) SetSelectedDriver(deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) error { + return SetupDiSetSelectedDriver(deviceInfoSet, deviceInfoData, driverInfoData) +} + +//sys setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData, driverInfoDetailData *DrvInfoDetailData, driverInfoDetailDataSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetDriverInfoDetailW + +// SetupDiGetDriverInfoDetail function retrieves driver information detail for a device information set or a particular device information element in the device information set. +func SetupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (*DrvInfoDetailData, error) { + reqSize := uint32(2048) + for { + buf := make([]byte, reqSize) + data := (*DrvInfoDetailData)(unsafe.Pointer(&buf[0])) + data.size = data.unsafeSizeOf() + err := setupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData, data, uint32(len(buf)), &reqSize) + if err == ERROR_INSUFFICIENT_BUFFER { + continue + } + if err != nil { + return nil, err + } + data.size = reqSize + return data, nil + } +} + +// DriverInfoDetail method retrieves driver information detail for a device information set or a particular device information element in the device information set. +func (deviceInfoSet DevInfo) DriverInfoDetail(deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (*DrvInfoDetailData, error) { + return SetupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData) +} + +//sys SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) = setupapi.SetupDiDestroyDriverInfoList + +// DestroyDriverInfoList method deletes a driver list. +func (deviceInfoSet DevInfo) DestroyDriverInfoList(deviceInfoData *DevInfoData, driverType SPDIT) error { + return SetupDiDestroyDriverInfoList(deviceInfoSet, deviceInfoData, driverType) +} + +//sys setupDiGetClassDevsEx(classGUID *GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, deviceInfoSet DevInfo, machineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(InvalidHandle)] = setupapi.SetupDiGetClassDevsExW + +// SetupDiGetClassDevsEx function returns a handle to a device information set that contains requested device information elements for a local or a remote computer. +func SetupDiGetClassDevsEx(classGUID *GUID, enumerator string, hwndParent uintptr, flags DIGCF, deviceInfoSet DevInfo, machineName string) (handle DevInfo, err error) { + var enumeratorUTF16 *uint16 + if enumerator != "" { + enumeratorUTF16, err = UTF16PtrFromString(enumerator) + if err != nil { + return + } + } + var machineNameUTF16 *uint16 + if machineName != "" { + machineNameUTF16, err = UTF16PtrFromString(machineName) + if err != nil { + return + } + } + return setupDiGetClassDevsEx(classGUID, enumeratorUTF16, hwndParent, flags, deviceInfoSet, machineNameUTF16, 0) +} + +// SetupDiCallClassInstaller function calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code). +//sys SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiCallClassInstaller + +// CallClassInstaller member calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code). +func (deviceInfoSet DevInfo) CallClassInstaller(installFunction DI_FUNCTION, deviceInfoData *DevInfoData) error { + return SetupDiCallClassInstaller(installFunction, deviceInfoSet, deviceInfoData) +} + +// SetupDiOpenDevRegKey function opens a registry key for device-specific configuration information. +//sys SetupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key Handle, err error) [failretval==InvalidHandle] = setupapi.SetupDiOpenDevRegKey + +// OpenDevRegKey method opens a registry key for device-specific configuration information. +func (deviceInfoSet DevInfo) OpenDevRegKey(DeviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (Handle, error) { + return SetupDiOpenDevRegKey(deviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired) +} + +//sys setupDiGetDeviceProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, propertyKey *DEVPROPKEY, propertyType *DEVPROPTYPE, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32, flags uint32) (err error) = setupapi.SetupDiGetDevicePropertyW + +// SetupDiGetDeviceProperty function retrieves a specified device instance property. +func SetupDiGetDeviceProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, propertyKey *DEVPROPKEY) (value interface{}, err error) { + reqSize := uint32(256) + for { + var dataType DEVPROPTYPE + buf := make([]byte, reqSize) + err = setupDiGetDeviceProperty(deviceInfoSet, deviceInfoData, propertyKey, &dataType, &buf[0], uint32(len(buf)), &reqSize, 0) + if err == ERROR_INSUFFICIENT_BUFFER { + continue + } + if err != nil { + return + } + switch dataType { + case DEVPROP_TYPE_STRING: + ret := UTF16ToString(bufToUTF16(buf)) + runtime.KeepAlive(buf) + return ret, nil + } + return nil, errors.New("unimplemented property type") + } +} + +//sys setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyRegDataType *uint32, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetDeviceRegistryPropertyW + +// SetupDiGetDeviceRegistryProperty function retrieves a specified Plug and Play device property. +func SetupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP) (value interface{}, err error) { + reqSize := uint32(256) + for { + var dataType uint32 + buf := make([]byte, reqSize) + err = setupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &dataType, &buf[0], uint32(len(buf)), &reqSize) + if err == ERROR_INSUFFICIENT_BUFFER { + continue + } + if err != nil { + return + } + return getRegistryValue(buf[:reqSize], dataType) + } +} + +func getRegistryValue(buf []byte, dataType uint32) (interface{}, error) { + switch dataType { + case REG_SZ: + ret := UTF16ToString(bufToUTF16(buf)) + runtime.KeepAlive(buf) + return ret, nil + case REG_EXPAND_SZ: + value := UTF16ToString(bufToUTF16(buf)) + if value == "" { + return "", nil + } + p, err := syscall.UTF16PtrFromString(value) + if err != nil { + return "", err + } + ret := make([]uint16, 100) + for { + n, err := ExpandEnvironmentStrings(p, &ret[0], uint32(len(ret))) + if err != nil { + return "", err + } + if n <= uint32(len(ret)) { + return UTF16ToString(ret[:n]), nil + } + ret = make([]uint16, n) + } + case REG_BINARY: + return buf, nil + case REG_DWORD_LITTLE_ENDIAN: + return binary.LittleEndian.Uint32(buf), nil + case REG_DWORD_BIG_ENDIAN: + return binary.BigEndian.Uint32(buf), nil + case REG_MULTI_SZ: + bufW := bufToUTF16(buf) + a := []string{} + for i := 0; i < len(bufW); { + j := i + wcslen(bufW[i:]) + if i < j { + a = append(a, UTF16ToString(bufW[i:j])) + } + i = j + 1 + } + runtime.KeepAlive(buf) + return a, nil + case REG_QWORD_LITTLE_ENDIAN: + return binary.LittleEndian.Uint64(buf), nil + default: + return nil, fmt.Errorf("Unsupported registry value type: %v", dataType) + } +} + +// bufToUTF16 function reinterprets []byte buffer as []uint16 +func bufToUTF16(buf []byte) []uint16 { + sl := struct { + addr *uint16 + len int + cap int + }{(*uint16)(unsafe.Pointer(&buf[0])), len(buf) / 2, cap(buf) / 2} + return *(*[]uint16)(unsafe.Pointer(&sl)) +} + +// utf16ToBuf function reinterprets []uint16 as []byte +func utf16ToBuf(buf []uint16) []byte { + sl := struct { + addr *byte + len int + cap int + }{(*byte)(unsafe.Pointer(&buf[0])), len(buf) * 2, cap(buf) * 2} + return *(*[]byte)(unsafe.Pointer(&sl)) +} + +func wcslen(str []uint16) int { + for i := 0; i < len(str); i++ { + if str[i] == 0 { + return i + } + } + return len(str) +} + +// DeviceRegistryProperty method retrieves a specified Plug and Play device property. +func (deviceInfoSet DevInfo) DeviceRegistryProperty(deviceInfoData *DevInfoData, property SPDRP) (interface{}, error) { + return SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property) +} + +//sys setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffer *byte, propertyBufferSize uint32) (err error) = setupapi.SetupDiSetDeviceRegistryPropertyW + +// SetupDiSetDeviceRegistryProperty function sets a Plug and Play device property for a device. +func SetupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffers []byte) error { + return setupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &propertyBuffers[0], uint32(len(propertyBuffers))) +} + +// SetDeviceRegistryProperty function sets a Plug and Play device property for a device. +func (deviceInfoSet DevInfo) SetDeviceRegistryProperty(deviceInfoData *DevInfoData, property SPDRP, propertyBuffers []byte) error { + return SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, propertyBuffers) +} + +// SetDeviceRegistryPropertyString method sets a Plug and Play device property string for a device. +func (deviceInfoSet DevInfo) SetDeviceRegistryPropertyString(deviceInfoData *DevInfoData, property SPDRP, str string) error { + str16, err := UTF16FromString(str) + if err != nil { + return err + } + err = SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, utf16ToBuf(append(str16, 0))) + runtime.KeepAlive(str16) + return err +} + +//sys setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiGetDeviceInstallParamsW + +// SetupDiGetDeviceInstallParams function retrieves device installation parameters for a device information set or a particular device information element. +func SetupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (*DevInstallParams, error) { + params := &DevInstallParams{} + params.size = uint32(unsafe.Sizeof(*params)) + + return params, setupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData, params) +} + +// DeviceInstallParams method retrieves device installation parameters for a device information set or a particular device information element. +func (deviceInfoSet DevInfo) DeviceInstallParams(deviceInfoData *DevInfoData) (*DevInstallParams, error) { + return SetupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData) +} + +//sys setupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, instanceId *uint16, instanceIdSize uint32, instanceIdRequiredSize *uint32) (err error) = setupapi.SetupDiGetDeviceInstanceIdW + +// SetupDiGetDeviceInstanceId function retrieves the instance ID of the device. +func SetupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (string, error) { + reqSize := uint32(1024) + for { + buf := make([]uint16, reqSize) + err := setupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData, &buf[0], uint32(len(buf)), &reqSize) + if err == ERROR_INSUFFICIENT_BUFFER { + continue + } + if err != nil { + return "", err + } + return UTF16ToString(buf), nil + } +} + +// DeviceInstanceID method retrieves the instance ID of the device. +func (deviceInfoSet DevInfo) DeviceInstanceID(deviceInfoData *DevInfoData) (string, error) { + return SetupDiGetDeviceInstanceId(deviceInfoSet, deviceInfoData) +} + +// SetupDiGetClassInstallParams function retrieves class installation parameters for a device information set or a particular device information element. +//sys SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetClassInstallParamsW + +// ClassInstallParams method retrieves class installation parameters for a device information set or a particular device information element. +func (deviceInfoSet DevInfo) ClassInstallParams(deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) error { + return SetupDiGetClassInstallParams(deviceInfoSet, deviceInfoData, classInstallParams, classInstallParamsSize, requiredSize) +} + +//sys SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiSetDeviceInstallParamsW + +// SetDeviceInstallParams member sets device installation parameters for a device information set or a particular device information element. +func (deviceInfoSet DevInfo) SetDeviceInstallParams(deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) error { + return SetupDiSetDeviceInstallParams(deviceInfoSet, deviceInfoData, deviceInstallParams) +} + +// SetupDiSetClassInstallParams function sets or clears class install parameters for a device information set or a particular device information element. +//sys SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) (err error) = setupapi.SetupDiSetClassInstallParamsW + +// SetClassInstallParams method sets or clears class install parameters for a device information set or a particular device information element. +func (deviceInfoSet DevInfo) SetClassInstallParams(deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) error { + return SetupDiSetClassInstallParams(deviceInfoSet, deviceInfoData, classInstallParams, classInstallParamsSize) +} + +//sys setupDiClassNameFromGuidEx(classGUID *GUID, className *uint16, classNameSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) = setupapi.SetupDiClassNameFromGuidExW + +// SetupDiClassNameFromGuidEx function retrieves the class name associated with a class GUID. The class can be installed on a local or remote computer. +func SetupDiClassNameFromGuidEx(classGUID *GUID, machineName string) (className string, err error) { + var classNameUTF16 [MAX_CLASS_NAME_LEN]uint16 + + var machineNameUTF16 *uint16 + if machineName != "" { + machineNameUTF16, err = UTF16PtrFromString(machineName) + if err != nil { + return + } + } + + err = setupDiClassNameFromGuidEx(classGUID, &classNameUTF16[0], MAX_CLASS_NAME_LEN, nil, machineNameUTF16, 0) + if err != nil { + return + } + + className = UTF16ToString(classNameUTF16[:]) + return +} + +//sys setupDiClassGuidsFromNameEx(className *uint16, classGuidList *GUID, classGuidListSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) = setupapi.SetupDiClassGuidsFromNameExW + +// SetupDiClassGuidsFromNameEx function retrieves the GUIDs associated with the specified class name. This resulting list contains the classes currently installed on a local or remote computer. +func SetupDiClassGuidsFromNameEx(className string, machineName string) ([]GUID, error) { + classNameUTF16, err := UTF16PtrFromString(className) + if err != nil { + return nil, err + } + + var machineNameUTF16 *uint16 + if machineName != "" { + machineNameUTF16, err = UTF16PtrFromString(machineName) + if err != nil { + return nil, err + } + } + + reqSize := uint32(4) + for { + buf := make([]GUID, reqSize) + err = setupDiClassGuidsFromNameEx(classNameUTF16, &buf[0], uint32(len(buf)), &reqSize, machineNameUTF16, 0) + if err == ERROR_INSUFFICIENT_BUFFER { + continue + } + if err != nil { + return nil, err + } + return buf[:reqSize], nil + } +} + +//sys setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiGetSelectedDevice + +// SetupDiGetSelectedDevice function retrieves the selected device information element in a device information set. +func SetupDiGetSelectedDevice(deviceInfoSet DevInfo) (*DevInfoData, error) { + data := &DevInfoData{} + data.size = uint32(unsafe.Sizeof(*data)) + + return data, setupDiGetSelectedDevice(deviceInfoSet, data) +} + +// SelectedDevice method retrieves the selected device information element in a device information set. +func (deviceInfoSet DevInfo) SelectedDevice() (*DevInfoData, error) { + return SetupDiGetSelectedDevice(deviceInfoSet) +} + +// SetupDiSetSelectedDevice function sets a device information element as the selected member of a device information set. This function is typically used by an installation wizard. +//sys SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiSetSelectedDevice + +// SetSelectedDevice method sets a device information element as the selected member of a device information set. This function is typically used by an installation wizard. +func (deviceInfoSet DevInfo) SetSelectedDevice(deviceInfoData *DevInfoData) error { + return SetupDiSetSelectedDevice(deviceInfoSet, deviceInfoData) +} + +//sys setupUninstallOEMInf(infFileName *uint16, flags SUOI, reserved uintptr) (err error) = setupapi.SetupUninstallOEMInfW + +// SetupUninstallOEMInf uninstalls the specified driver. +func SetupUninstallOEMInf(infFileName string, flags SUOI) error { + infFileName16, err := UTF16PtrFromString(infFileName) + if err != nil { + return err + } + return setupUninstallOEMInf(infFileName16, flags, 0) +} + +//sys cm_MapCrToWin32Err(configRet CONFIGRET, defaultWin32Error Errno) (ret Errno) = CfgMgr32.CM_MapCrToWin32Err + +//sys cm_Get_Device_Interface_List_Size(len *uint32, interfaceClass *GUID, deviceID *uint16, flags uint32) (ret CONFIGRET) = CfgMgr32.CM_Get_Device_Interface_List_SizeW +//sys cm_Get_Device_Interface_List(interfaceClass *GUID, deviceID *uint16, buffer *uint16, bufferLen uint32, flags uint32) (ret CONFIGRET) = CfgMgr32.CM_Get_Device_Interface_ListW + +func CM_Get_Device_Interface_List(deviceID string, interfaceClass *GUID, flags uint32) ([]string, error) { + deviceID16, err := UTF16PtrFromString(deviceID) + if err != nil { + return nil, err + } + var buf []uint16 + var buflen uint32 + for { + if ret := cm_Get_Device_Interface_List_Size(&buflen, interfaceClass, deviceID16, flags); ret != CR_SUCCESS { + return nil, ret + } + buf = make([]uint16, buflen) + if ret := cm_Get_Device_Interface_List(interfaceClass, deviceID16, &buf[0], buflen, flags); ret == CR_SUCCESS { + break + } else if ret != CR_BUFFER_SMALL { + return nil, ret + } + } + var interfaces []string + for i := 0; i < len(buf); { + j := i + wcslen(buf[i:]) + if i < j { + interfaces = append(interfaces, UTF16ToString(buf[i:j])) + } + i = j + 1 + } + if interfaces == nil { + return nil, ERROR_NO_SUCH_DEVICE_INTERFACE + } + return interfaces, nil +} + +//sys cm_Get_DevNode_Status(status *uint32, problemNumber *uint32, devInst DEVINST, flags uint32) (ret CONFIGRET) = CfgMgr32.CM_Get_DevNode_Status + +func CM_Get_DevNode_Status(status *uint32, problemNumber *uint32, devInst DEVINST, flags uint32) error { + ret := cm_Get_DevNode_Status(status, problemNumber, devInst, flags) + if ret == CR_SUCCESS { + return nil + } + return ret +} diff --git a/src/runtime/vendor/golang.org/x/sys/windows/setupapierrors_windows.go b/src/runtime/vendor/golang.org/x/sys/windows/setupapierrors_windows.go deleted file mode 100644 index 1681810e0..000000000 --- a/src/runtime/vendor/golang.org/x/sys/windows/setupapierrors_windows.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package windows - -import "syscall" - -const ( - ERROR_EXPECTED_SECTION_NAME syscall.Errno = 0x20000000 | 0xC0000000 | 0 - ERROR_BAD_SECTION_NAME_LINE syscall.Errno = 0x20000000 | 0xC0000000 | 1 - ERROR_SECTION_NAME_TOO_LONG syscall.Errno = 0x20000000 | 0xC0000000 | 2 - ERROR_GENERAL_SYNTAX syscall.Errno = 0x20000000 | 0xC0000000 | 3 - ERROR_WRONG_INF_STYLE syscall.Errno = 0x20000000 | 0xC0000000 | 0x100 - ERROR_SECTION_NOT_FOUND syscall.Errno = 0x20000000 | 0xC0000000 | 0x101 - ERROR_LINE_NOT_FOUND syscall.Errno = 0x20000000 | 0xC0000000 | 0x102 - ERROR_NO_BACKUP syscall.Errno = 0x20000000 | 0xC0000000 | 0x103 - ERROR_NO_ASSOCIATED_CLASS syscall.Errno = 0x20000000 | 0xC0000000 | 0x200 - ERROR_CLASS_MISMATCH syscall.Errno = 0x20000000 | 0xC0000000 | 0x201 - ERROR_DUPLICATE_FOUND syscall.Errno = 0x20000000 | 0xC0000000 | 0x202 - ERROR_NO_DRIVER_SELECTED syscall.Errno = 0x20000000 | 0xC0000000 | 0x203 - ERROR_KEY_DOES_NOT_EXIST syscall.Errno = 0x20000000 | 0xC0000000 | 0x204 - ERROR_INVALID_DEVINST_NAME syscall.Errno = 0x20000000 | 0xC0000000 | 0x205 - ERROR_INVALID_CLASS syscall.Errno = 0x20000000 | 0xC0000000 | 0x206 - ERROR_DEVINST_ALREADY_EXISTS syscall.Errno = 0x20000000 | 0xC0000000 | 0x207 - ERROR_DEVINFO_NOT_REGISTERED syscall.Errno = 0x20000000 | 0xC0000000 | 0x208 - ERROR_INVALID_REG_PROPERTY syscall.Errno = 0x20000000 | 0xC0000000 | 0x209 - ERROR_NO_INF syscall.Errno = 0x20000000 | 0xC0000000 | 0x20A - ERROR_NO_SUCH_DEVINST syscall.Errno = 0x20000000 | 0xC0000000 | 0x20B - ERROR_CANT_LOAD_CLASS_ICON syscall.Errno = 0x20000000 | 0xC0000000 | 0x20C - ERROR_INVALID_CLASS_INSTALLER syscall.Errno = 0x20000000 | 0xC0000000 | 0x20D - ERROR_DI_DO_DEFAULT syscall.Errno = 0x20000000 | 0xC0000000 | 0x20E - ERROR_DI_NOFILECOPY syscall.Errno = 0x20000000 | 0xC0000000 | 0x20F - ERROR_INVALID_HWPROFILE syscall.Errno = 0x20000000 | 0xC0000000 | 0x210 - ERROR_NO_DEVICE_SELECTED syscall.Errno = 0x20000000 | 0xC0000000 | 0x211 - ERROR_DEVINFO_LIST_LOCKED syscall.Errno = 0x20000000 | 0xC0000000 | 0x212 - ERROR_DEVINFO_DATA_LOCKED syscall.Errno = 0x20000000 | 0xC0000000 | 0x213 - ERROR_DI_BAD_PATH syscall.Errno = 0x20000000 | 0xC0000000 | 0x214 - ERROR_NO_CLASSINSTALL_PARAMS syscall.Errno = 0x20000000 | 0xC0000000 | 0x215 - ERROR_FILEQUEUE_LOCKED syscall.Errno = 0x20000000 | 0xC0000000 | 0x216 - ERROR_BAD_SERVICE_INSTALLSECT syscall.Errno = 0x20000000 | 0xC0000000 | 0x217 - ERROR_NO_CLASS_DRIVER_LIST syscall.Errno = 0x20000000 | 0xC0000000 | 0x218 - ERROR_NO_ASSOCIATED_SERVICE syscall.Errno = 0x20000000 | 0xC0000000 | 0x219 - ERROR_NO_DEFAULT_DEVICE_INTERFACE syscall.Errno = 0x20000000 | 0xC0000000 | 0x21A - ERROR_DEVICE_INTERFACE_ACTIVE syscall.Errno = 0x20000000 | 0xC0000000 | 0x21B - ERROR_DEVICE_INTERFACE_REMOVED syscall.Errno = 0x20000000 | 0xC0000000 | 0x21C - ERROR_BAD_INTERFACE_INSTALLSECT syscall.Errno = 0x20000000 | 0xC0000000 | 0x21D - ERROR_NO_SUCH_INTERFACE_CLASS syscall.Errno = 0x20000000 | 0xC0000000 | 0x21E - ERROR_INVALID_REFERENCE_STRING syscall.Errno = 0x20000000 | 0xC0000000 | 0x21F - ERROR_INVALID_MACHINENAME syscall.Errno = 0x20000000 | 0xC0000000 | 0x220 - ERROR_REMOTE_COMM_FAILURE syscall.Errno = 0x20000000 | 0xC0000000 | 0x221 - ERROR_MACHINE_UNAVAILABLE syscall.Errno = 0x20000000 | 0xC0000000 | 0x222 - ERROR_NO_CONFIGMGR_SERVICES syscall.Errno = 0x20000000 | 0xC0000000 | 0x223 - ERROR_INVALID_PROPPAGE_PROVIDER syscall.Errno = 0x20000000 | 0xC0000000 | 0x224 - ERROR_NO_SUCH_DEVICE_INTERFACE syscall.Errno = 0x20000000 | 0xC0000000 | 0x225 - ERROR_DI_POSTPROCESSING_REQUIRED syscall.Errno = 0x20000000 | 0xC0000000 | 0x226 - ERROR_INVALID_COINSTALLER syscall.Errno = 0x20000000 | 0xC0000000 | 0x227 - ERROR_NO_COMPAT_DRIVERS syscall.Errno = 0x20000000 | 0xC0000000 | 0x228 - ERROR_NO_DEVICE_ICON syscall.Errno = 0x20000000 | 0xC0000000 | 0x229 - ERROR_INVALID_INF_LOGCONFIG syscall.Errno = 0x20000000 | 0xC0000000 | 0x22A - ERROR_DI_DONT_INSTALL syscall.Errno = 0x20000000 | 0xC0000000 | 0x22B - ERROR_INVALID_FILTER_DRIVER syscall.Errno = 0x20000000 | 0xC0000000 | 0x22C - ERROR_NON_WINDOWS_NT_DRIVER syscall.Errno = 0x20000000 | 0xC0000000 | 0x22D - ERROR_NON_WINDOWS_DRIVER syscall.Errno = 0x20000000 | 0xC0000000 | 0x22E - ERROR_NO_CATALOG_FOR_OEM_INF syscall.Errno = 0x20000000 | 0xC0000000 | 0x22F - ERROR_DEVINSTALL_QUEUE_NONNATIVE syscall.Errno = 0x20000000 | 0xC0000000 | 0x230 - ERROR_NOT_DISABLEABLE syscall.Errno = 0x20000000 | 0xC0000000 | 0x231 - ERROR_CANT_REMOVE_DEVINST syscall.Errno = 0x20000000 | 0xC0000000 | 0x232 - ERROR_INVALID_TARGET syscall.Errno = 0x20000000 | 0xC0000000 | 0x233 - ERROR_DRIVER_NONNATIVE syscall.Errno = 0x20000000 | 0xC0000000 | 0x234 - ERROR_IN_WOW64 syscall.Errno = 0x20000000 | 0xC0000000 | 0x235 - ERROR_SET_SYSTEM_RESTORE_POINT syscall.Errno = 0x20000000 | 0xC0000000 | 0x236 - ERROR_SCE_DISABLED syscall.Errno = 0x20000000 | 0xC0000000 | 0x238 - ERROR_UNKNOWN_EXCEPTION syscall.Errno = 0x20000000 | 0xC0000000 | 0x239 - ERROR_PNP_REGISTRY_ERROR syscall.Errno = 0x20000000 | 0xC0000000 | 0x23A - ERROR_REMOTE_REQUEST_UNSUPPORTED syscall.Errno = 0x20000000 | 0xC0000000 | 0x23B - ERROR_NOT_AN_INSTALLED_OEM_INF syscall.Errno = 0x20000000 | 0xC0000000 | 0x23C - ERROR_INF_IN_USE_BY_DEVICES syscall.Errno = 0x20000000 | 0xC0000000 | 0x23D - ERROR_DI_FUNCTION_OBSOLETE syscall.Errno = 0x20000000 | 0xC0000000 | 0x23E - ERROR_NO_AUTHENTICODE_CATALOG syscall.Errno = 0x20000000 | 0xC0000000 | 0x23F - ERROR_AUTHENTICODE_DISALLOWED syscall.Errno = 0x20000000 | 0xC0000000 | 0x240 - ERROR_AUTHENTICODE_TRUSTED_PUBLISHER syscall.Errno = 0x20000000 | 0xC0000000 | 0x241 - ERROR_AUTHENTICODE_TRUST_NOT_ESTABLISHED syscall.Errno = 0x20000000 | 0xC0000000 | 0x242 - ERROR_AUTHENTICODE_PUBLISHER_NOT_TRUSTED syscall.Errno = 0x20000000 | 0xC0000000 | 0x243 - ERROR_SIGNATURE_OSATTRIBUTE_MISMATCH syscall.Errno = 0x20000000 | 0xC0000000 | 0x244 - ERROR_ONLY_VALIDATE_VIA_AUTHENTICODE syscall.Errno = 0x20000000 | 0xC0000000 | 0x245 - ERROR_DEVICE_INSTALLER_NOT_READY syscall.Errno = 0x20000000 | 0xC0000000 | 0x246 - ERROR_DRIVER_STORE_ADD_FAILED syscall.Errno = 0x20000000 | 0xC0000000 | 0x247 - ERROR_DEVICE_INSTALL_BLOCKED syscall.Errno = 0x20000000 | 0xC0000000 | 0x248 - ERROR_DRIVER_INSTALL_BLOCKED syscall.Errno = 0x20000000 | 0xC0000000 | 0x249 - ERROR_WRONG_INF_TYPE syscall.Errno = 0x20000000 | 0xC0000000 | 0x24A - ERROR_FILE_HASH_NOT_IN_CATALOG syscall.Errno = 0x20000000 | 0xC0000000 | 0x24B - ERROR_DRIVER_STORE_DELETE_FAILED syscall.Errno = 0x20000000 | 0xC0000000 | 0x24C - ERROR_UNRECOVERABLE_STACK_OVERFLOW syscall.Errno = 0x20000000 | 0xC0000000 | 0x300 - EXCEPTION_SPAPI_UNRECOVERABLE_STACK_OVERFLOW syscall.Errno = ERROR_UNRECOVERABLE_STACK_OVERFLOW - ERROR_NO_DEFAULT_INTERFACE_DEVICE syscall.Errno = ERROR_NO_DEFAULT_DEVICE_INTERFACE - ERROR_INTERFACE_DEVICE_ACTIVE syscall.Errno = ERROR_DEVICE_INTERFACE_ACTIVE - ERROR_INTERFACE_DEVICE_REMOVED syscall.Errno = ERROR_DEVICE_INTERFACE_REMOVED - ERROR_NO_SUCH_INTERFACE_DEVICE syscall.Errno = ERROR_NO_SUCH_DEVICE_INTERFACE -) diff --git a/src/runtime/vendor/golang.org/x/sys/windows/syscall_windows.go b/src/runtime/vendor/golang.org/x/sys/windows/syscall_windows.go index 53ee74e08..cf44e6933 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -248,6 +248,7 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys FreeEnvironmentStrings(envs *uint16) (err error) = kernel32.FreeEnvironmentStringsW //sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, err error) = kernel32.GetEnvironmentVariableW //sys SetEnvironmentVariable(name *uint16, value *uint16) (err error) = kernel32.SetEnvironmentVariableW +//sys ExpandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW //sys CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock //sys getTickCount64() (ms uint64) = kernel32.GetTickCount64 @@ -322,6 +323,8 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW //sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW //sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot +//sys Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW +//sys Module32Next(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32NextW //sys Process32First(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32FirstW //sys Process32Next(snapshot Handle, procEntry *ProcessEntry32) (err error) = kernel32.Process32NextW //sys Thread32First(snapshot Handle, threadEntry *ThreadEntry32) (err error) @@ -360,6 +363,8 @@ func NewCallbackCDecl(fn interface{}) uintptr { //sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error) //sys GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) //sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) +//sys GetActiveProcessorCount(groupNumber uint16) (ret uint32) +//sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32) // Volume Management Functions //sys DefineDosDevice(flags uint32, deviceName *uint16, targetPath *uint16) (err error) = DefineDosDeviceW @@ -893,9 +898,7 @@ func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, int32, error) { p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port)) p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil } @@ -915,9 +918,7 @@ func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, int32, error) { p[0] = byte(sa.Port >> 8) p[1] = byte(sa.Port) sa.raw.Scope_id = sa.ZoneId - for i := 0; i < len(sa.Addr); i++ { - sa.raw.Addr[i] = sa.Addr[i] - } + sa.raw.Addr = sa.Addr return unsafe.Pointer(&sa.raw), int32(unsafe.Sizeof(sa.raw)), nil } @@ -990,9 +991,7 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) { sa := new(SockaddrInet4) p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil case AF_INET6: @@ -1001,9 +1000,7 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) { p := (*[2]byte)(unsafe.Pointer(&pp.Port)) sa.Port = int(p[0])<<8 + int(p[1]) sa.ZoneId = pp.Scope_id - for i := 0; i < len(sa.Addr); i++ { - sa.Addr[i] = pp.Addr[i] - } + sa.Addr = pp.Addr return sa, nil } return nil, syscall.EAFNOSUPPORT diff --git a/src/runtime/vendor/golang.org/x/sys/windows/types_windows.go b/src/runtime/vendor/golang.org/x/sys/windows/types_windows.go index 286dd1eab..e19471c6a 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/types_windows.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/types_windows.go @@ -156,6 +156,8 @@ const ( MAX_PATH = 260 MAX_LONG_PATH = 32768 + MAX_MODULE_NAME32 = 255 + MAX_COMPUTERNAME_LENGTH = 15 TIME_ZONE_ID_UNKNOWN = 0 @@ -936,8 +938,8 @@ type StartupInfoEx struct { type ProcThreadAttributeList struct{} type ProcThreadAttributeListContainer struct { - data *ProcThreadAttributeList - heapAllocations []uintptr + data *ProcThreadAttributeList + pointers []unsafe.Pointer } type ProcessInformation struct { @@ -970,6 +972,21 @@ type ThreadEntry32 struct { Flags uint32 } +type ModuleEntry32 struct { + Size uint32 + ModuleID uint32 + ProcessID uint32 + GlblcntUsage uint32 + ProccntUsage uint32 + ModBaseAddr uintptr + ModBaseSize uint32 + ModuleHandle Handle + Module [MAX_MODULE_NAME32 + 1]uint16 + ExePath [MAX_PATH]uint16 +} + +const SizeofModuleEntry32 = unsafe.Sizeof(ModuleEntry32{}) + type Systemtime struct { Year uint16 Month uint16 @@ -2732,6 +2749,43 @@ type PROCESS_BASIC_INFORMATION struct { InheritedFromUniqueProcessId uintptr } +type SYSTEM_PROCESS_INFORMATION struct { + NextEntryOffset uint32 + NumberOfThreads uint32 + WorkingSetPrivateSize int64 + HardFaultCount uint32 + NumberOfThreadsHighWatermark uint32 + CycleTime uint64 + CreateTime int64 + UserTime int64 + KernelTime int64 + ImageName NTUnicodeString + BasePriority int32 + UniqueProcessID uintptr + InheritedFromUniqueProcessID uintptr + HandleCount uint32 + SessionID uint32 + UniqueProcessKey *uint32 + PeakVirtualSize uintptr + VirtualSize uintptr + PageFaultCount uint32 + PeakWorkingSetSize uintptr + WorkingSetSize uintptr + QuotaPeakPagedPoolUsage uintptr + QuotaPagedPoolUsage uintptr + QuotaPeakNonPagedPoolUsage uintptr + QuotaNonPagedPoolUsage uintptr + PagefileUsage uintptr + PeakPagefileUsage uintptr + PrivatePageCount uintptr + ReadOperationCount int64 + WriteOperationCount int64 + OtherOperationCount int64 + ReadTransferCount int64 + WriteTransferCount int64 + OtherTransferCount int64 +} + // SystemInformationClasses for NtQuerySystemInformation and NtSetSystemInformation const ( SystemBasicInformation = iota @@ -3118,3 +3172,5 @@ type ModuleInfo struct { SizeOfImage uint32 EntryPoint uintptr } + +const ALL_PROCESSOR_GROUPS = 0xFFFF diff --git a/src/runtime/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/src/runtime/vendor/golang.org/x/sys/windows/zsyscall_windows.go index ef3cfcfb2..9ea1a44f0 100644 --- a/src/runtime/vendor/golang.org/x/sys/windows/zsyscall_windows.go +++ b/src/runtime/vendor/golang.org/x/sys/windows/zsyscall_windows.go @@ -36,6 +36,7 @@ func errnoErr(e syscall.Errno) error { } var ( + modCfgMgr32 = NewLazySystemDLL("CfgMgr32.dll") modadvapi32 = NewLazySystemDLL("advapi32.dll") modcrypt32 = NewLazySystemDLL("crypt32.dll") moddnsapi = NewLazySystemDLL("dnsapi.dll") @@ -48,6 +49,7 @@ var ( modpsapi = NewLazySystemDLL("psapi.dll") modsechost = NewLazySystemDLL("sechost.dll") modsecur32 = NewLazySystemDLL("secur32.dll") + modsetupapi = NewLazySystemDLL("setupapi.dll") modshell32 = NewLazySystemDLL("shell32.dll") moduser32 = NewLazySystemDLL("user32.dll") moduserenv = NewLazySystemDLL("userenv.dll") @@ -56,6 +58,10 @@ var ( modws2_32 = NewLazySystemDLL("ws2_32.dll") modwtsapi32 = NewLazySystemDLL("wtsapi32.dll") + procCM_Get_DevNode_Status = modCfgMgr32.NewProc("CM_Get_DevNode_Status") + procCM_Get_Device_Interface_ListW = modCfgMgr32.NewProc("CM_Get_Device_Interface_ListW") + procCM_Get_Device_Interface_List_SizeW = modCfgMgr32.NewProc("CM_Get_Device_Interface_List_SizeW") + procCM_MapCrToWin32Err = modCfgMgr32.NewProc("CM_MapCrToWin32Err") procAdjustTokenGroups = modadvapi32.NewProc("AdjustTokenGroups") procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") procAllocateAndInitializeSid = modadvapi32.NewProc("AllocateAndInitializeSid") @@ -115,6 +121,7 @@ var ( procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken") procQueryServiceConfig2W = modadvapi32.NewProc("QueryServiceConfig2W") procQueryServiceConfigW = modadvapi32.NewProc("QueryServiceConfigW") + procQueryServiceDynamicInformation = modadvapi32.NewProc("QueryServiceDynamicInformation") procQueryServiceLockStatusW = modadvapi32.NewProc("QueryServiceLockStatusW") procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") procQueryServiceStatusEx = modadvapi32.NewProc("QueryServiceStatusEx") @@ -198,6 +205,7 @@ var ( procDeviceIoControl = modkernel32.NewProc("DeviceIoControl") procDuplicateHandle = modkernel32.NewProc("DuplicateHandle") procExitProcess = modkernel32.NewProc("ExitProcess") + procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") procFindClose = modkernel32.NewProc("FindClose") procFindCloseChangeNotification = modkernel32.NewProc("FindCloseChangeNotification") procFindFirstChangeNotificationW = modkernel32.NewProc("FindFirstChangeNotificationW") @@ -218,6 +226,7 @@ var ( procFreeLibrary = modkernel32.NewProc("FreeLibrary") procGenerateConsoleCtrlEvent = modkernel32.NewProc("GenerateConsoleCtrlEvent") procGetACP = modkernel32.NewProc("GetACP") + procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount") procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts") procGetCommandLineW = modkernel32.NewProc("GetCommandLineW") procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") @@ -243,6 +252,7 @@ var ( procGetLogicalDriveStringsW = modkernel32.NewProc("GetLogicalDriveStringsW") procGetLogicalDrives = modkernel32.NewProc("GetLogicalDrives") procGetLongPathNameW = modkernel32.NewProc("GetLongPathNameW") + procGetMaximumProcessorCount = modkernel32.NewProc("GetMaximumProcessorCount") procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") procGetModuleHandleExW = modkernel32.NewProc("GetModuleHandleExW") procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW") @@ -287,6 +297,8 @@ var ( procLockFileEx = modkernel32.NewProc("LockFileEx") procLockResource = modkernel32.NewProc("LockResource") procMapViewOfFile = modkernel32.NewProc("MapViewOfFile") + procModule32FirstW = modkernel32.NewProc("Module32FirstW") + procModule32NextW = modkernel32.NewProc("Module32NextW") procMoveFileExW = modkernel32.NewProc("MoveFileExW") procMoveFileW = modkernel32.NewProc("MoveFileW") procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar") @@ -366,9 +378,9 @@ var ( procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") procNtCreateFile = modntdll.NewProc("NtCreateFile") procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile") - procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile") procNtQueryInformationProcess = modntdll.NewProc("NtQueryInformationProcess") procNtQuerySystemInformation = modntdll.NewProc("NtQuerySystemInformation") + procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile") procNtSetInformationProcess = modntdll.NewProc("NtSetInformationProcess") procNtSetSystemInformation = modntdll.NewProc("NtSetSystemInformation") procRtlAddFunctionTable = modntdll.NewProc("RtlAddFunctionTable") @@ -399,6 +411,34 @@ var ( procUnsubscribeServiceChangeNotifications = modsechost.NewProc("UnsubscribeServiceChangeNotifications") procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") procTranslateNameW = modsecur32.NewProc("TranslateNameW") + procSetupDiBuildDriverInfoList = modsetupapi.NewProc("SetupDiBuildDriverInfoList") + procSetupDiCallClassInstaller = modsetupapi.NewProc("SetupDiCallClassInstaller") + procSetupDiCancelDriverInfoSearch = modsetupapi.NewProc("SetupDiCancelDriverInfoSearch") + procSetupDiClassGuidsFromNameExW = modsetupapi.NewProc("SetupDiClassGuidsFromNameExW") + procSetupDiClassNameFromGuidExW = modsetupapi.NewProc("SetupDiClassNameFromGuidExW") + procSetupDiCreateDeviceInfoListExW = modsetupapi.NewProc("SetupDiCreateDeviceInfoListExW") + procSetupDiCreateDeviceInfoW = modsetupapi.NewProc("SetupDiCreateDeviceInfoW") + procSetupDiDestroyDeviceInfoList = modsetupapi.NewProc("SetupDiDestroyDeviceInfoList") + procSetupDiDestroyDriverInfoList = modsetupapi.NewProc("SetupDiDestroyDriverInfoList") + procSetupDiEnumDeviceInfo = modsetupapi.NewProc("SetupDiEnumDeviceInfo") + procSetupDiEnumDriverInfoW = modsetupapi.NewProc("SetupDiEnumDriverInfoW") + procSetupDiGetClassDevsExW = modsetupapi.NewProc("SetupDiGetClassDevsExW") + procSetupDiGetClassInstallParamsW = modsetupapi.NewProc("SetupDiGetClassInstallParamsW") + procSetupDiGetDeviceInfoListDetailW = modsetupapi.NewProc("SetupDiGetDeviceInfoListDetailW") + procSetupDiGetDeviceInstallParamsW = modsetupapi.NewProc("SetupDiGetDeviceInstallParamsW") + procSetupDiGetDeviceInstanceIdW = modsetupapi.NewProc("SetupDiGetDeviceInstanceIdW") + procSetupDiGetDevicePropertyW = modsetupapi.NewProc("SetupDiGetDevicePropertyW") + procSetupDiGetDeviceRegistryPropertyW = modsetupapi.NewProc("SetupDiGetDeviceRegistryPropertyW") + procSetupDiGetDriverInfoDetailW = modsetupapi.NewProc("SetupDiGetDriverInfoDetailW") + procSetupDiGetSelectedDevice = modsetupapi.NewProc("SetupDiGetSelectedDevice") + procSetupDiGetSelectedDriverW = modsetupapi.NewProc("SetupDiGetSelectedDriverW") + procSetupDiOpenDevRegKey = modsetupapi.NewProc("SetupDiOpenDevRegKey") + procSetupDiSetClassInstallParamsW = modsetupapi.NewProc("SetupDiSetClassInstallParamsW") + procSetupDiSetDeviceInstallParamsW = modsetupapi.NewProc("SetupDiSetDeviceInstallParamsW") + procSetupDiSetDeviceRegistryPropertyW = modsetupapi.NewProc("SetupDiSetDeviceRegistryPropertyW") + procSetupDiSetSelectedDevice = modsetupapi.NewProc("SetupDiSetSelectedDevice") + procSetupDiSetSelectedDriverW = modsetupapi.NewProc("SetupDiSetSelectedDriverW") + procSetupUninstallOEMInfW = modsetupapi.NewProc("SetupUninstallOEMInfW") procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") procSHGetKnownFolderPath = modshell32.NewProc("SHGetKnownFolderPath") procShellExecuteW = modshell32.NewProc("ShellExecuteW") @@ -446,6 +486,30 @@ var ( procWTSQueryUserToken = modwtsapi32.NewProc("WTSQueryUserToken") ) +func cm_Get_DevNode_Status(status *uint32, problemNumber *uint32, devInst DEVINST, flags uint32) (ret CONFIGRET) { + r0, _, _ := syscall.Syscall6(procCM_Get_DevNode_Status.Addr(), 4, uintptr(unsafe.Pointer(status)), uintptr(unsafe.Pointer(problemNumber)), uintptr(devInst), uintptr(flags), 0, 0) + ret = CONFIGRET(r0) + return +} + +func cm_Get_Device_Interface_List(interfaceClass *GUID, deviceID *uint16, buffer *uint16, bufferLen uint32, flags uint32) (ret CONFIGRET) { + r0, _, _ := syscall.Syscall6(procCM_Get_Device_Interface_ListW.Addr(), 5, uintptr(unsafe.Pointer(interfaceClass)), uintptr(unsafe.Pointer(deviceID)), uintptr(unsafe.Pointer(buffer)), uintptr(bufferLen), uintptr(flags), 0) + ret = CONFIGRET(r0) + return +} + +func cm_Get_Device_Interface_List_Size(len *uint32, interfaceClass *GUID, deviceID *uint16, flags uint32) (ret CONFIGRET) { + r0, _, _ := syscall.Syscall6(procCM_Get_Device_Interface_List_SizeW.Addr(), 4, uintptr(unsafe.Pointer(len)), uintptr(unsafe.Pointer(interfaceClass)), uintptr(unsafe.Pointer(deviceID)), uintptr(flags), 0, 0) + ret = CONFIGRET(r0) + return +} + +func cm_MapCrToWin32Err(configRet CONFIGRET, defaultWin32Error Errno) (ret Errno) { + r0, _, _ := syscall.Syscall(procCM_MapCrToWin32Err.Addr(), 2, uintptr(configRet), uintptr(defaultWin32Error), 0) + ret = Errno(r0) + return +} + func AdjustTokenGroups(token Token, resetToDefault bool, newstate *Tokengroups, buflen uint32, prevstate *Tokengroups, returnlen *uint32) (err error) { var _p0 uint32 if resetToDefault { @@ -976,6 +1040,18 @@ func QueryServiceConfig(service Handle, serviceConfig *QUERY_SERVICE_CONFIG, buf return } +func QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInfo unsafe.Pointer) (err error) { + err = procQueryServiceDynamicInformation.Find() + if err != nil { + return + } + r1, _, e1 := syscall.Syscall(procQueryServiceDynamicInformation.Addr(), 3, uintptr(service), uintptr(infoLevel), uintptr(dynamicInfo)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func QueryServiceLockStatus(mgr Handle, lockStatus *QUERY_SERVICE_LOCK_STATUS, bufSize uint32, bytesNeeded *uint32) (err error) { r1, _, e1 := syscall.Syscall6(procQueryServiceLockStatusW.Addr(), 4, uintptr(mgr), uintptr(unsafe.Pointer(lockStatus)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), 0, 0) if r1 == 0 { @@ -1703,6 +1779,15 @@ func ExitProcess(exitcode uint32) { return } +func ExpandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size)) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + func FindClose(handle Handle) (err error) { r1, _, e1 := syscall.Syscall(procFindClose.Addr(), 1, uintptr(handle), 0, 0) if r1 == 0 { @@ -1884,6 +1969,12 @@ func GetACP() (acp uint32) { return } +func GetActiveProcessorCount(groupNumber uint16) (ret uint32) { + r0, _, _ := syscall.Syscall(procGetActiveProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0) + ret = uint32(r0) + return +} + func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) { r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0) if r1 == 0 { @@ -2086,6 +2177,12 @@ func GetLongPathName(path *uint16, buf *uint16, buflen uint32) (n uint32, err er return } +func GetMaximumProcessorCount(groupNumber uint16) (ret uint32) { + r0, _, _ := syscall.Syscall(procGetMaximumProcessorCount.Addr(), 1, uintptr(groupNumber), 0, 0) + ret = uint32(r0) + return +} + func GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) { r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(filename)), uintptr(size)) n = uint32(r0) @@ -2486,6 +2583,22 @@ func MapViewOfFile(handle Handle, access uint32, offsetHigh uint32, offsetLow ui return } +func Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procModule32FirstW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func Module32Next(snapshot Handle, moduleEntry *ModuleEntry32) (err error) { + r1, _, e1 := syscall.Syscall(procModule32NextW.Addr(), 2, uintptr(snapshot), uintptr(unsafe.Pointer(moduleEntry)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) if r1 == 0 { @@ -3171,14 +3284,6 @@ func NtCreateNamedPipeFile(pipe *Handle, access uint32, oa *OBJECT_ATTRIBUTES, i return } -func NtSetInformationFile(handle Handle, iosb *IO_STATUS_BLOCK, inBuffer *byte, inBufferLen uint32, class uint32) (ntstatus error) { - r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferLen), uintptr(class), 0) - if r0 != 0 { - ntstatus = NTStatus(r0) - } - return -} - func NtQueryInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe.Pointer, procInfoLen uint32, retLen *uint32) (ntstatus error) { r0, _, _ := syscall.Syscall6(procNtQueryInformationProcess.Addr(), 5, uintptr(proc), uintptr(procInfoClass), uintptr(procInfo), uintptr(procInfoLen), uintptr(unsafe.Pointer(retLen)), 0) if r0 != 0 { @@ -3195,6 +3300,14 @@ func NtQuerySystemInformation(sysInfoClass int32, sysInfo unsafe.Pointer, sysInf return } +func NtSetInformationFile(handle Handle, iosb *IO_STATUS_BLOCK, inBuffer *byte, inBufferLen uint32, class uint32) (ntstatus error) { + r0, _, _ := syscall.Syscall6(procNtSetInformationFile.Addr(), 5, uintptr(handle), uintptr(unsafe.Pointer(iosb)), uintptr(unsafe.Pointer(inBuffer)), uintptr(inBufferLen), uintptr(class), 0) + if r0 != 0 { + ntstatus = NTStatus(r0) + } + return +} + func NtSetInformationProcess(proc Handle, procInfoClass int32, procInfo unsafe.Pointer, procInfoLen uint32) (ntstatus error) { r0, _, _ := syscall.Syscall6(procNtSetInformationProcess.Addr(), 4, uintptr(proc), uintptr(procInfoClass), uintptr(procInfo), uintptr(procInfoLen), 0, 0) if r0 != 0 { @@ -3419,6 +3532,233 @@ func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint return } +func SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiBuildDriverInfoList.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiCallClassInstaller.Addr(), 3, uintptr(installFunction), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiCancelDriverInfoSearch.Addr(), 1, uintptr(deviceInfoSet), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiClassGuidsFromNameEx(className *uint16, classGuidList *GUID, classGuidListSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) { + r1, _, e1 := syscall.Syscall6(procSetupDiClassGuidsFromNameExW.Addr(), 6, uintptr(unsafe.Pointer(className)), uintptr(unsafe.Pointer(classGuidList)), uintptr(classGuidListSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiClassNameFromGuidEx(classGUID *GUID, className *uint16, classNameSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) { + r1, _, e1 := syscall.Syscall6(procSetupDiClassNameFromGuidExW.Addr(), 6, uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(className)), uintptr(classNameSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiCreateDeviceInfoListEx(classGUID *GUID, hwndParent uintptr, machineName *uint16, reserved uintptr) (handle DevInfo, err error) { + r0, _, e1 := syscall.Syscall6(procSetupDiCreateDeviceInfoListExW.Addr(), 4, uintptr(unsafe.Pointer(classGUID)), uintptr(hwndParent), uintptr(unsafe.Pointer(machineName)), uintptr(reserved), 0, 0) + handle = DevInfo(r0) + if handle == DevInfo(InvalidHandle) { + err = errnoErr(e1) + } + return +} + +func setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUID *GUID, DeviceDescription *uint16, hwndParent uintptr, CreationFlags DICD, deviceInfoData *DevInfoData) (err error) { + r1, _, e1 := syscall.Syscall9(procSetupDiCreateDeviceInfoW.Addr(), 7, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(DeviceName)), uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(DeviceDescription)), uintptr(hwndParent), uintptr(CreationFlags), uintptr(unsafe.Pointer(deviceInfoData)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiDestroyDeviceInfoList.Addr(), 1, uintptr(deviceInfoSet), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiDestroyDriverInfoList.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfoData *DevInfoData) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiEnumDeviceInfo.Addr(), 3, uintptr(deviceInfoSet), uintptr(memberIndex), uintptr(unsafe.Pointer(deviceInfoData))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex uint32, driverInfoData *DrvInfoData) (err error) { + r1, _, e1 := syscall.Syscall6(procSetupDiEnumDriverInfoW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType), uintptr(memberIndex), uintptr(unsafe.Pointer(driverInfoData)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetClassDevsEx(classGUID *GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, deviceInfoSet DevInfo, machineName *uint16, reserved uintptr) (handle DevInfo, err error) { + r0, _, e1 := syscall.Syscall9(procSetupDiGetClassDevsExW.Addr(), 7, uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(Enumerator)), uintptr(hwndParent), uintptr(Flags), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(machineName)), uintptr(reserved), 0, 0) + handle = DevInfo(r0) + if handle == DevInfo(InvalidHandle) { + err = errnoErr(e1) + } + return +} + +func SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetupDiGetClassInstallParamsW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), uintptr(unsafe.Pointer(requiredSize)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailData *DevInfoListDetailData) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiGetDeviceInfoListDetailW.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoSetDetailData)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiGetDeviceInstallParamsW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetDeviceInstanceId(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, instanceId *uint16, instanceIdSize uint32, instanceIdRequiredSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetupDiGetDeviceInstanceIdW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(instanceId)), uintptr(instanceIdSize), uintptr(unsafe.Pointer(instanceIdRequiredSize)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetDeviceProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, propertyKey *DEVPROPKEY, propertyType *DEVPROPTYPE, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procSetupDiGetDevicePropertyW.Addr(), 8, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(propertyKey)), uintptr(unsafe.Pointer(propertyType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(flags), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyRegDataType *uint32, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall9(procSetupDiGetDeviceRegistryPropertyW.Addr(), 7, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyRegDataType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), uintptr(unsafe.Pointer(requiredSize)), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData, driverInfoDetailData *DrvInfoDetailData, driverInfoDetailDataSize uint32, requiredSize *uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetupDiGetDriverInfoDetailW.Addr(), 6, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData)), uintptr(unsafe.Pointer(driverInfoDetailData)), uintptr(driverInfoDetailDataSize), uintptr(unsafe.Pointer(requiredSize))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDevice.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDriverW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key Handle, err error) { + r0, _, e1 := syscall.Syscall6(procSetupDiOpenDevRegKey.Addr(), 6, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(Scope), uintptr(HwProfile), uintptr(KeyType), uintptr(samDesired)) + key = Handle(r0) + if key == InvalidHandle { + err = errnoErr(e1) + } + return +} + +func SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetupDiSetClassInstallParamsW.Addr(), 4, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), 0, 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiSetDeviceInstallParamsW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffer *byte, propertyBufferSize uint32) (err error) { + r1, _, e1 := syscall.Syscall6(procSetupDiSetDeviceRegistryPropertyW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDevice.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) { + r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDriverW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData))) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + +func setupUninstallOEMInf(infFileName *uint16, flags SUOI, reserved uintptr) (err error) { + r1, _, e1 := syscall.Syscall(procSetupUninstallOEMInfW.Addr(), 3, uintptr(unsafe.Pointer(infFileName)), uintptr(flags), uintptr(reserved)) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) { r0, _, e1 := syscall.Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0) argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0)) diff --git a/src/runtime/vendor/modules.txt b/src/runtime/vendor/modules.txt index f663a8033..0b7d58f3d 100644 --- a/src/runtime/vendor/modules.txt +++ b/src/runtime/vendor/modules.txt @@ -212,7 +212,9 @@ github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter # github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 github.com/matttproud/golang_protobuf_extensions/pbutil -# github.com/mdlayher/vsock v0.0.0-20191108225356-d9c65923cb8f +# github.com/mdlayher/socket v0.2.0 +github.com/mdlayher/socket +# github.com/mdlayher/vsock v1.1.0 ## explicit github.com/mdlayher/vsock # github.com/mitchellh/mapstructure v1.1.2 @@ -328,8 +330,9 @@ go.opentelemetry.io/otel/sdk/trace # go.opentelemetry.io/otel/trace v1.0.1 ## explicit go.opentelemetry.io/otel/trace -# golang.org/x/net v0.0.0-20210825183410-e898025ed96a +# golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd ## explicit +golang.org/x/net/bpf golang.org/x/net/context golang.org/x/net/context/ctxhttp golang.org/x/net/http/httpguts @@ -344,14 +347,14 @@ golang.org/x/oauth2 golang.org/x/oauth2/internal # golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/sync/errgroup -# golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 +# golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a ## explicit golang.org/x/sys/execabs golang.org/x/sys/internal/unsafeheader golang.org/x/sys/unix golang.org/x/sys/windows golang.org/x/sys/windows/registry -# golang.org/x/text v0.3.6 +# golang.org/x/text v0.3.7 golang.org/x/text/secure/bidirule golang.org/x/text/transform golang.org/x/text/unicode/bidi diff --git a/src/runtime/virtcontainers/pkg/agent/protocols/client/client.go b/src/runtime/virtcontainers/pkg/agent/protocols/client/client.go index 2cc976128..b31c86ad8 100644 --- a/src/runtime/virtcontainers/pkg/agent/protocols/client/client.go +++ b/src/runtime/virtcontainers/pkg/agent/protocols/client/client.go @@ -359,7 +359,7 @@ func VsockDialer(sock string, timeout time.Duration) (net.Conn, error) { } dialFunc := func() (net.Conn, error) { - return vsock.Dial(cid, port) + return vsock.Dial(cid, port, nil) } timeoutErr := grpcStatus.Errorf(codes.DeadlineExceeded, "timed out connecting to vsock %d:%d", cid, port) From 12c37fafc5bea78cb73228b7504f2bff9b73da30 Mon Sep 17 00:00:00 2001 From: bin Date: Mon, 14 Feb 2022 16:17:53 +0800 Subject: [PATCH 07/47] trace-forwarder: add make check for Rust Add make check to run cargo fmt/clippy for Rust projects. Fixes: #3656 Signed-off-by: bin --- src/agent/Makefile | 15 +++------------ src/tools/agent-ctl/Makefile | 1 + src/tools/trace-forwarder/Makefile | 3 ++- src/tools/trace-forwarder/src/handler.rs | 3 +-- utils.mk | 6 ++++++ 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/agent/Makefile b/src/agent/Makefile index 07439b09b..a0f330ea1 100644 --- a/src/agent/Makefile +++ b/src/agent/Makefile @@ -98,6 +98,8 @@ define INSTALL_FILE install -D -m 644 $1 $(DESTDIR)$2/$1 || exit 1; endef +.DEFAULT_GOAL := default + ##TARGET default: build code default: $(TARGET) show-header @@ -116,17 +118,6 @@ $(GENERATED_FILES): %: %.in optimize: $(SOURCES) | show-summary show-header @RUSTFLAGS="-C link-arg=-s $(EXTRA_RUSTFLAGS) --deny warnings" cargo build --target $(TRIPLE) --$(BUILD_TYPE) $(EXTRA_RUSTFEATURES) -##TARGET clippy: run clippy linter -clippy: $(GENERATED_CODE) - cargo clippy --all-targets --all-features --release \ - -- \ - -Aclippy::redundant_allocation \ - -D warnings - -format: - cargo fmt -- --check - - ##TARGET install: install agent install: install-services @install -D $(TARGET_PATH) $(DESTDIR)/$(BINDIR)/$(TARGET) @@ -146,7 +137,7 @@ test: @cargo test --all --target $(TRIPLE) $(EXTRA_RUSTFEATURES) -- --nocapture ##TARGET check: run test -check: clippy format +check: $(GENERATED_FILES) standard_rust_check ##TARGET run: build and run agent run: diff --git a/src/tools/agent-ctl/Makefile b/src/tools/agent-ctl/Makefile index 1cb20e1d7..ca25f954e 100644 --- a/src/tools/agent-ctl/Makefile +++ b/src/tools/agent-ctl/Makefile @@ -5,6 +5,7 @@ include ../../../utils.mk +.DEFAULT_GOAL := default default: build build: logging-crate-tests diff --git a/src/tools/trace-forwarder/Makefile b/src/tools/trace-forwarder/Makefile index 06530face..5b1c53849 100644 --- a/src/tools/trace-forwarder/Makefile +++ b/src/tools/trace-forwarder/Makefile @@ -5,6 +5,7 @@ include ../../../utils.mk +.DEFAULT_GOAL := default default: build build: logging-crate-tests @@ -24,7 +25,7 @@ test: install: -check: +check: standard_rust_check .PHONY: \ build \ diff --git a/src/tools/trace-forwarder/src/handler.rs b/src/tools/trace-forwarder/src/handler.rs index 1ac76ec2d..b669f0613 100644 --- a/src/tools/trace-forwarder/src/handler.rs +++ b/src/tools/trace-forwarder/src/handler.rs @@ -73,8 +73,7 @@ async fn handle_trace_data<'a>( let payload_len: u64 = NetworkEndian::read_u64(&header); - let mut encoded_payload = Vec::with_capacity(payload_len as usize); - encoded_payload.resize(payload_len as usize, 0); + let mut encoded_payload = vec![0; payload_len as usize]; reader .read_exact(&mut encoded_payload) diff --git a/utils.mk b/utils.mk index dbfefb5a2..e833b40d7 100644 --- a/utils.mk +++ b/utils.mk @@ -145,3 +145,9 @@ endif TRIPLE = $(ARCH)-unknown-linux-$(LIBC) CWD := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) + +standard_rust_check: + cargo fmt -- --check + cargo clippy --all-targets --all-features --release \ + -- \ + -D warnings From 734b618c16febd3801396a875d5567a3751ba145 Mon Sep 17 00:00:00 2001 From: bin Date: Mon, 14 Feb 2022 19:47:41 +0800 Subject: [PATCH 08/47] agent-ctl: run cargo fmt/clippy in make check Run cargo fmt/clippy in make check and clear clippy warnings. Fixes: #3656 Signed-off-by: bin --- src/tools/agent-ctl/Makefile | 2 +- src/tools/agent-ctl/src/client.rs | 81 +++++++++++++++---------------- src/tools/agent-ctl/src/main.rs | 6 +-- src/tools/agent-ctl/src/utils.rs | 25 +++++----- 4 files changed, 52 insertions(+), 62 deletions(-) diff --git a/src/tools/agent-ctl/Makefile b/src/tools/agent-ctl/Makefile index ca25f954e..df3eacf24 100644 --- a/src/tools/agent-ctl/Makefile +++ b/src/tools/agent-ctl/Makefile @@ -25,7 +25,7 @@ test: install: @RUSTFLAGS="$(EXTRA_RUSTFLAGS) --deny warnings" cargo install --target $(TRIPLE) --path . -check: +check: standard_rust_check .PHONY: \ build \ diff --git a/src/tools/agent-ctl/src/client.rs b/src/tools/agent-ctl/src/client.rs index ce88d10bb..a27b88cc8 100644 --- a/src/tools/agent-ctl/src/client.rs +++ b/src/tools/agent-ctl/src/client.rs @@ -22,7 +22,6 @@ use std::os::unix::io::{IntoRawFd, RawFd}; use std::os::unix::net::UnixStream; use std::thread::sleep; use std::time::Duration; -use ttrpc; use ttrpc::context::Context; // Run the specified closure to set an automatic value if the ttRPC Context @@ -89,13 +88,13 @@ struct BuiltinCmd { } // Command that causes the agent to exit (iff tracing is enabled) -const SHUTDOWN_CMD: &'static str = "DestroySandbox"; +const SHUTDOWN_CMD: &str = "DestroySandbox"; // Command that requests this program ends -const CMD_QUIT: &'static str = "quit"; -const CMD_REPEAT: &'static str = "repeat"; +const CMD_QUIT: &str = "quit"; +const CMD_REPEAT: &str = "repeat"; -const DEFAULT_PROC_SIGNAL: &'static str = "SIGKILL"; +const DEFAULT_PROC_SIGNAL: &str = "SIGKILL"; const ERR_API_FAILED: &str = "API failed"; @@ -106,7 +105,7 @@ const METADATA_CFG_NS: &str = "agent-ctl-cfg"; // automatically. const NO_AUTO_VALUES_CFG_NAME: &str = "no-auto-values"; -static AGENT_CMDS: &'static [AgentCmd] = &[ +static AGENT_CMDS: &[AgentCmd] = &[ AgentCmd { name: "AddARPNeighbors", st: ServiceType::Agent, @@ -274,7 +273,7 @@ static AGENT_CMDS: &'static [AgentCmd] = &[ }, ]; -static BUILTIN_CMDS: &'static [BuiltinCmd] = &[ +static BUILTIN_CMDS: & [BuiltinCmd] = &[ BuiltinCmd { name: "echo", descr: "Display the arguments", @@ -638,7 +637,7 @@ pub fn client(cfg: &Config, commands: Vec<&str>) -> Result<()> { "server-address" => cfg.server_address.to_string()); if cfg.interactive { - return interactive_client_loop(&cfg, &mut options, &client, &health, &ttrpc_ctx); + return interactive_client_loop(cfg, &mut options, &client, &health, &ttrpc_ctx); } let mut repeat_count = 1; @@ -650,17 +649,16 @@ pub fn client(cfg: &Config, commands: Vec<&str>) -> Result<()> { } let (result, shutdown) = handle_cmd( - &cfg, + cfg, &client, &health, &ttrpc_ctx, repeat_count, &mut options, - &cmd, + cmd, ); - if result.is_err() { - return result; - } + + result.map_err(|e| anyhow!(e))?; if shutdown { break; @@ -692,7 +690,7 @@ fn handle_cmd( return (Ok(()), false); } - let first = match cmd.chars().nth(0) { + let first = match cmd.chars().next() { Some(c) => c, None => return (Err(anyhow!("failed to check command name")), false), }; @@ -759,12 +757,12 @@ fn handle_cmd( } fn handle_builtin_cmd(cmd: &str, args: &str) -> (Result<()>, bool) { - let f = match get_builtin_cmd_func(&cmd) { + let f = match get_builtin_cmd_func(cmd) { Ok(fp) => fp, Err(e) => return (Err(e), false), }; - f(&args) + f(args) } // Execute the ttRPC specified by the first field of "line". Return a result @@ -777,12 +775,12 @@ fn handle_agent_cmd( cmd: &str, args: &str, ) -> (Result<()>, bool) { - let f = match get_agent_cmd_func(&cmd) { + let f = match get_agent_cmd_func(cmd) { Ok(fp) => fp, Err(e) => return (Err(e), false), }; - let result = f(ctx, client, health, options, &args); + let result = f(ctx, client, health, options, args); if result.is_err() { return (result, false); } @@ -821,9 +819,8 @@ fn interactive_client_loop( let (result, shutdown) = handle_cmd(cfg, client, health, ctx, repeat_count, options, &cmdline); - if result.is_err() { - return result; - } + + result.map_err(|e| anyhow!(e))?; if shutdown { break; @@ -1412,7 +1409,7 @@ fn agent_cmd_container_tty_win_resize( let rows_str = utils::get_option("row", options, args)?; - if rows_str != "" { + if !rows_str.is_empty() { let rows = rows_str .parse::() .map_err(|e| anyhow!(e).context("invalid row size"))?; @@ -1421,7 +1418,7 @@ fn agent_cmd_container_tty_win_resize( let cols_str = utils::get_option("column", options, args)?; - if cols_str != "" { + if !cols_str.is_empty() { let cols = cols_str .parse::() .map_err(|e| anyhow!(e).context("invalid column size"))?; @@ -1497,7 +1494,7 @@ fn agent_cmd_container_read_stdout( let length_str = utils::get_option("len", options, args)?; - if length_str != "" { + if !length_str.is_empty() { let length = length_str .parse::() .map_err(|e| anyhow!(e).context("invalid length"))?; @@ -1539,7 +1536,7 @@ fn agent_cmd_container_read_stderr( let length_str = utils::get_option("len", options, args)?; - if length_str != "" { + if !length_str.is_empty() { let length = length_str .parse::() .map_err(|e| anyhow!(e).context("invalid length"))?; @@ -1657,13 +1654,13 @@ fn agent_cmd_sandbox_copy_file( run_if_auto_values!(ctx, || -> Result<()> { let path = utils::get_option("path", options, args)?; - if path != "" { + if !path.is_empty() { req.set_path(path); } let file_size_str = utils::get_option("file_size", options, args)?; - if file_size_str != "" { + if !file_size_str.is_empty() { let file_size = file_size_str .parse::() .map_err(|e| anyhow!(e).context("invalid file_size"))?; @@ -1673,7 +1670,7 @@ fn agent_cmd_sandbox_copy_file( let file_mode_str = utils::get_option("file_mode", options, args)?; - if file_mode_str != "" { + if !file_mode_str.is_empty() { let file_mode = file_mode_str .parse::() .map_err(|e| anyhow!(e).context("invalid file_mode"))?; @@ -1683,7 +1680,7 @@ fn agent_cmd_sandbox_copy_file( let dir_mode_str = utils::get_option("dir_mode", options, args)?; - if dir_mode_str != "" { + if !dir_mode_str.is_empty() { let dir_mode = dir_mode_str .parse::() .map_err(|e| anyhow!(e).context("invalid dir_mode"))?; @@ -1693,7 +1690,7 @@ fn agent_cmd_sandbox_copy_file( let uid_str = utils::get_option("uid", options, args)?; - if uid_str != "" { + if !uid_str.is_empty() { let uid = uid_str .parse::() .map_err(|e| anyhow!(e).context("invalid uid"))?; @@ -1703,7 +1700,7 @@ fn agent_cmd_sandbox_copy_file( let gid_str = utils::get_option("gid", options, args)?; - if gid_str != "" { + if !gid_str.is_empty() { let gid = gid_str .parse::() .map_err(|e| anyhow!(e).context("invalid gid"))?; @@ -1712,7 +1709,7 @@ fn agent_cmd_sandbox_copy_file( let offset_str = utils::get_option("offset", options, args)?; - if offset_str != "" { + if !offset_str.is_empty() { let offset = offset_str .parse::() .map_err(|e| anyhow!(e).context("invalid offset"))?; @@ -1720,7 +1717,7 @@ fn agent_cmd_sandbox_copy_file( } let data_str = utils::get_option("data", options, args)?; - if data_str != "" { + if !data_str.is_empty() { let data = utils::str_to_bytes(&data_str)?; req.set_data(data.to_vec()); } @@ -1786,7 +1783,7 @@ fn agent_cmd_sandbox_online_cpu_mem( run_if_auto_values!(ctx, || -> Result<()> { let wait_str = utils::get_option("wait", options, args)?; - if wait_str != "" { + if !wait_str.is_empty() { let wait = wait_str .parse::() .map_err(|e| anyhow!(e).context("invalid wait bool"))?; @@ -1796,7 +1793,7 @@ fn agent_cmd_sandbox_online_cpu_mem( let nb_cpus_str = utils::get_option("nb_cpus", options, args)?; - if nb_cpus_str != "" { + if !nb_cpus_str.is_empty() { let nb_cpus = nb_cpus_str .parse::() .map_err(|e| anyhow!(e).context("invalid nb_cpus value"))?; @@ -1806,7 +1803,7 @@ fn agent_cmd_sandbox_online_cpu_mem( let cpu_only_str = utils::get_option("cpu_only", options, args)?; - if cpu_only_str != "" { + if !cpu_only_str.is_empty() { let cpu_only = cpu_only_str .parse::() .map_err(|e| anyhow!(e).context("invalid cpu_only bool"))?; @@ -1843,7 +1840,7 @@ fn agent_cmd_sandbox_set_guest_date_time( run_if_auto_values!(ctx, || -> Result<()> { let secs_str = utils::get_option("sec", options, args)?; - if secs_str != "" { + if !secs_str.is_empty() { let secs = secs_str .parse::() .map_err(|e| anyhow!(e).context("invalid seconds"))?; @@ -1853,7 +1850,7 @@ fn agent_cmd_sandbox_set_guest_date_time( let usecs_str = utils::get_option("usec", options, args)?; - if usecs_str != "" { + if !usecs_str.is_empty() { let usecs = usecs_str .parse::() .map_err(|e| anyhow!(e).context("invalid useconds"))?; @@ -1954,7 +1951,7 @@ fn agent_cmd_sandbox_mem_hotplug_by_probe( if !addr_list.is_empty() { let addrs: Vec = addr_list // Convert into a list of string values. - .split(",") + .split(',') // Convert each string element into a u8 array of bytes, ignoring // those elements that fail the conversion. .filter_map(|s| hex::decode(s.trim_start_matches("0x")).ok()) @@ -2025,7 +2022,7 @@ fn builtin_cmd_list(_args: &str) -> (Result<()>, bool) { cmds.iter().for_each(|n| println!(" - {}", n)); - println!(""); + println!(); (Ok(()), false) } @@ -2046,8 +2043,8 @@ fn get_repeat_count(cmdline: &str) -> i64 { let count = fields[1]; match count.parse::() { - Ok(n) => return n, - Err(_) => return default_repeat_count, + Ok(n) => n, + Err(_) => default_repeat_count, } } diff --git a/src/tools/agent-ctl/src/main.rs b/src/tools/agent-ctl/src/main.rs index 88c12e984..61701a664 100644 --- a/src/tools/agent-ctl/src/main.rs +++ b/src/tools/agent-ctl/src/main.rs @@ -191,11 +191,7 @@ fn connect(name: &str, global_args: clap::ArgMatches) -> Result<()> { let result = rpc::run(&logger, &cfg, commands); - if result.is_err() { - return result; - } - - Ok(()) + result.map_err(|e| anyhow!(e)) } fn real_main() -> Result<()> { diff --git a/src/tools/agent-ctl/src/utils.rs b/src/tools/agent-ctl/src/utils.rs index 14359c6d9..8dbfa53f4 100644 --- a/src/tools/agent-ctl/src/utils.rs +++ b/src/tools/agent-ctl/src/utils.rs @@ -92,12 +92,10 @@ pub fn signame_to_signum(name: &str) -> Result { return Err(anyhow!("invalid signal")); } - match name.parse::() { - Ok(n) => return Ok(n), - - // "fall through" on error as we assume the name is not a number, but - // a signal name. - Err(_) => (), + // "fall through" on error as we assume the name is not a number, but + // a signal name. + if let Ok(n) = name.parse::() { + return Ok(n); } let mut search_term: String; @@ -129,8 +127,7 @@ pub fn human_time_to_ns(human_time: &str) -> Result { let d: humantime::Duration = human_time .parse::() - .map_err(|e| anyhow!(e))? - .into(); + .map_err(|e| anyhow!(e))?; Ok(d.as_nanos() as i64) } @@ -262,8 +259,8 @@ fn config_file_from_bundle_dir(bundle_dir: &str) -> Result { fn root_oci_to_ttrpc(bundle_dir: &str, root: &ociRoot) -> Result { let root_dir = root.path.clone(); - let path = if root_dir.starts_with("/") { - root_dir.clone() + let path = if root_dir.starts_with('/') { + root_dir } else { // Expand the root directory into an absolute value let abs_root_dir = PathBuf::from(&bundle_dir).join(&root_dir); @@ -685,13 +682,13 @@ fn linux_oci_to_ttrpc(l: &ociLinux) -> ttrpcLinux { fn oci_to_ttrpc(bundle_dir: &str, cid: &str, oci: &ociSpec) -> Result { let process = match &oci.process { - Some(p) => protobuf::SingularPtrField::some(process_oci_to_ttrpc(&p)), + Some(p) => protobuf::SingularPtrField::some(process_oci_to_ttrpc(p)), None => protobuf::SingularPtrField::none(), }; let root = match &oci.root { Some(r) => { - let ttrpc_root = root_oci_to_ttrpc(bundle_dir, &r).map_err(|e| e)?; + let ttrpc_root = root_oci_to_ttrpc(bundle_dir, r).map_err(|e| e)?; protobuf::SingularPtrField::some(ttrpc_root) } @@ -700,7 +697,7 @@ fn oci_to_ttrpc(bundle_dir: &str, cid: &str, oci: &ociSpec) -> Result let mut mounts = protobuf::RepeatedField::new(); for m in &oci.mounts { - mounts.push(mount_oci_to_ttrpc(&m)); + mounts.push(mount_oci_to_ttrpc(m)); } let linux = match &oci.linux { @@ -770,7 +767,7 @@ pub fn get_ttrpc_spec(options: &mut Options, cid: &str) -> Result { let oci_spec: ociSpec = serde_json::from_str(&json_spec).map_err(|e| anyhow!(e))?; - Ok(oci_to_ttrpc(&bundle_dir, cid, &oci_spec)?) + oci_to_ttrpc(&bundle_dir, cid, &oci_spec) } pub fn str_to_bytes(s: &str) -> Result> { From 955d359f9ee25c16f1158bcc75f5b660f72d3ec3 Mon Sep 17 00:00:00 2001 From: Julio Montes Date: Mon, 14 Feb 2022 07:40:12 -0600 Subject: [PATCH 09/47] kernel: add missing config fragment for TDx Add kernel config fragment that enables TDx fixes #3659 Signed-off-by: Julio Montes --- .../kernel/configs/fragments/x86_64/tdx/tdx.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tools/packaging/kernel/configs/fragments/x86_64/tdx/tdx.conf diff --git a/tools/packaging/kernel/configs/fragments/x86_64/tdx/tdx.conf b/tools/packaging/kernel/configs/fragments/x86_64/tdx/tdx.conf new file mode 100644 index 000000000..214c469b5 --- /dev/null +++ b/tools/packaging/kernel/configs/fragments/x86_64/tdx/tdx.conf @@ -0,0 +1,12 @@ +# Intel Trust Domain Extensions (Intel TDX) + +CONFIG_EFI_STUB=y +CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS=y +CONFIG_INTEL_TDX_GUEST=y +CONFIG_INTEL_TDX_FIXES=y +CONFIG_X86_MEM_ENCRYPT_COMMON=y +CONFIG_X86_5LEVEL=y +CONFIG_OF=y +CONFIG_CLK_LGM_CGU=y +CONFIG_OF_RESERVED_MEM=y +CONFIG_DMA_RESTRICTED_POOL=y From 90fd625d0cd5feed032089ad2064bea148170d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Mon, 14 Feb 2022 17:20:27 +0100 Subject: [PATCH 10/47] versions: Udpate Cloud Hypervisor to 55479a64d237 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's update cloud-hypervisor to a version that exposes the TDx support via the OpenAPI's auto-generated code. Fixes: #3663 Signed-off-by: Fabiano Fidêncio --- .../client/.openapi-generator/FILES | 4 + .../pkg/cloud-hypervisor/client/README.md | 2 + .../cloud-hypervisor/client/api/openapi.yaml | 233 ++++++++++-------- .../client/docs/BalloonConfig.md | 28 ++- .../cloud-hypervisor/client/docs/NetConfig.md | 26 -- .../client/docs/PlatformConfig.md | 82 ++++++ .../cloud-hypervisor/client/docs/TdxConfig.md | 51 ++++ .../cloud-hypervisor/client/docs/VmConfig.md | 52 ++++ .../client/model_balloon_config.go | 43 +++- .../client/model_net_config.go | 36 --- .../client/model_platform_config.go | 149 +++++++++++ .../client/model_tdx_config.go | 107 ++++++++ .../client/model_vm_config.go | 72 ++++++ .../cloud-hypervisor/cloud-hypervisor.yaml | 36 ++- versions.yaml | 2 +- 15 files changed, 751 insertions(+), 172 deletions(-) create mode 100644 src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/PlatformConfig.md create mode 100644 src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/TdxConfig.md create mode 100644 src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_platform_config.go create mode 100644 src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_tdx_config.go diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/.openapi-generator/FILES b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/.openapi-generator/FILES index 22dad792f..ed5dc5764 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/.openapi-generator/FILES +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/.openapi-generator/FILES @@ -25,6 +25,7 @@ docs/NetConfig.md docs/NumaConfig.md docs/NumaDistance.md docs/PciDeviceInfo.md +docs/PlatformConfig.md docs/PmemConfig.md docs/RateLimiterConfig.md docs/ReceiveMigrationData.md @@ -32,6 +33,7 @@ docs/RestoreConfig.md docs/RngConfig.md docs/SendMigrationData.md docs/SgxEpcConfig.md +docs/TdxConfig.md docs/TokenBucket.md docs/VmAddDevice.md docs/VmConfig.md @@ -63,6 +65,7 @@ model_net_config.go model_numa_config.go model_numa_distance.go model_pci_device_info.go +model_platform_config.go model_pmem_config.go model_rate_limiter_config.go model_receive_migration_data.go @@ -70,6 +73,7 @@ model_restore_config.go model_rng_config.go model_send_migration_data.go model_sgx_epc_config.go +model_tdx_config.go model_token_bucket.go model_vm_add_device.go model_vm_config.go diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/README.md b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/README.md index b9829e33e..3b7967c4b 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/README.md +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/README.md @@ -125,6 +125,7 @@ Class | Method | HTTP request | Description - [NumaConfig](docs/NumaConfig.md) - [NumaDistance](docs/NumaDistance.md) - [PciDeviceInfo](docs/PciDeviceInfo.md) + - [PlatformConfig](docs/PlatformConfig.md) - [PmemConfig](docs/PmemConfig.md) - [RateLimiterConfig](docs/RateLimiterConfig.md) - [ReceiveMigrationData](docs/ReceiveMigrationData.md) @@ -132,6 +133,7 @@ Class | Method | HTTP request | Description - [RngConfig](docs/RngConfig.md) - [SendMigrationData](docs/SendMigrationData.md) - [SgxEpcConfig](docs/SgxEpcConfig.md) + - [TdxConfig](docs/TdxConfig.md) - [TokenBucket](docs/TokenBucket.md) - [VmAddDevice](docs/VmAddDevice.md) - [VmConfig](docs/VmConfig.md) diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/api/openapi.yaml b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/api/openapi.yaml index a00924ac5..b820e01cc 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/api/openapi.yaml +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/api/openapi.yaml @@ -374,7 +374,7 @@ components: VmInfo: description: Virtual Machine information example: - memory_actual_size: 7 + memory_actual_size: 3 state: Created config: console: @@ -382,8 +382,9 @@ components: file: file iommu: false balloon: - size: 1 + size: 6 deflate_on_oom: false + free_page_reporting: false memory: hugepages: false shared: false @@ -489,80 +490,87 @@ components: path: path numa: - distances: - - distance: 8 - destination: 4 - - distance: 8 - destination: 4 + - distance: 4 + destination: 0 + - distance: 4 + destination: 0 cpus: - - 0 - - 0 + - 6 + - 6 sgx_epc_sections: - sgx_epc_sections - sgx_epc_sections memory_zones: - memory_zones - memory_zones - guest_numa_id: 6 + guest_numa_id: 7 - distances: - - distance: 8 - destination: 4 - - distance: 8 - destination: 4 + - distance: 4 + destination: 0 + - distance: 4 + destination: 0 cpus: - - 0 - - 0 + - 6 + - 6 sgx_epc_sections: - sgx_epc_sections - sgx_epc_sections memory_zones: - memory_zones - memory_zones - guest_numa_id: 6 + guest_numa_id: 7 + tdx: + firmware: firmware rng: iommu: false src: /dev/urandom sgx_epc: - prefault: false - size: 7 + size: 0 id: id - prefault: false - size: 7 + size: 0 id: id fs: - - pci_segment: 5 - num_queues: 2 - queue_size: 6 + - pci_segment: 6 + num_queues: 1 + queue_size: 2 cache_size: 6 dax: true tag: tag socket: socket id: id - - pci_segment: 5 - num_queues: 2 - queue_size: 6 + - pci_segment: 6 + num_queues: 1 + queue_size: 2 cache_size: 6 dax: true tag: tag socket: socket id: id vsock: - pci_segment: 0 + pci_segment: 7 iommu: false socket: socket id: id cid: 3 + platform: + iommu_segments: + - 7 + - 7 + num_pci_segments: 8 pmem: - - pci_segment: 3 + - pci_segment: 6 mergeable: false file: file - size: 6 + size: 5 iommu: false id: id discard_writes: false - - pci_segment: 3 + - pci_segment: 6 mergeable: false file: file - size: 6 + size: 5 iommu: false id: id discard_writes: false @@ -591,12 +599,9 @@ components: one_time_burst: 0 refill_time: 0 mac: mac - pci_segment: 6 + pci_segment: 3 vhost_mode: Client iommu: false - fds: - - 3 - - 3 vhost_socket: vhost_socket vhost_user: false id: id @@ -615,12 +620,9 @@ components: one_time_burst: 0 refill_time: 0 mac: mac - pci_segment: 6 + pci_segment: 3 vhost_mode: Client iommu: false - fds: - - 3 - - 3 vhost_socket: vhost_socket vhost_user: false id: id @@ -710,8 +712,9 @@ components: file: file iommu: false balloon: - size: 1 + size: 6 deflate_on_oom: false + free_page_reporting: false memory: hugepages: false shared: false @@ -817,80 +820,87 @@ components: path: path numa: - distances: - - distance: 8 - destination: 4 - - distance: 8 - destination: 4 + - distance: 4 + destination: 0 + - distance: 4 + destination: 0 cpus: - - 0 - - 0 + - 6 + - 6 sgx_epc_sections: - sgx_epc_sections - sgx_epc_sections memory_zones: - memory_zones - memory_zones - guest_numa_id: 6 + guest_numa_id: 7 - distances: - - distance: 8 - destination: 4 - - distance: 8 - destination: 4 + - distance: 4 + destination: 0 + - distance: 4 + destination: 0 cpus: - - 0 - - 0 + - 6 + - 6 sgx_epc_sections: - sgx_epc_sections - sgx_epc_sections memory_zones: - memory_zones - memory_zones - guest_numa_id: 6 + guest_numa_id: 7 + tdx: + firmware: firmware rng: iommu: false src: /dev/urandom sgx_epc: - prefault: false - size: 7 + size: 0 id: id - prefault: false - size: 7 + size: 0 id: id fs: - - pci_segment: 5 - num_queues: 2 - queue_size: 6 + - pci_segment: 6 + num_queues: 1 + queue_size: 2 cache_size: 6 dax: true tag: tag socket: socket id: id - - pci_segment: 5 - num_queues: 2 - queue_size: 6 + - pci_segment: 6 + num_queues: 1 + queue_size: 2 cache_size: 6 dax: true tag: tag socket: socket id: id vsock: - pci_segment: 0 + pci_segment: 7 iommu: false socket: socket id: id cid: 3 + platform: + iommu_segments: + - 7 + - 7 + num_pci_segments: 8 pmem: - - pci_segment: 3 + - pci_segment: 6 mergeable: false file: file - size: 6 + size: 5 iommu: false id: id discard_writes: false - - pci_segment: 3 + - pci_segment: 6 mergeable: false file: file - size: 6 + size: 5 iommu: false id: id discard_writes: false @@ -919,12 +929,9 @@ components: one_time_burst: 0 refill_time: 0 mac: mac - pci_segment: 6 + pci_segment: 3 vhost_mode: Client iommu: false - fds: - - 3 - - 3 vhost_socket: vhost_socket vhost_user: false id: id @@ -943,12 +950,9 @@ components: one_time_burst: 0 refill_time: 0 mac: mac - pci_segment: 6 + pci_segment: 3 vhost_mode: Client iommu: false - fds: - - 3 - - 3 vhost_socket: vhost_socket vhost_user: false id: id @@ -998,6 +1002,8 @@ components: items: $ref: '#/components/schemas/SgxEpcConfig' type: array + tdx: + $ref: '#/components/schemas/TdxConfig' numa: items: $ref: '#/components/schemas/NumaConfig' @@ -1008,6 +1014,8 @@ components: watchdog: default: false type: boolean + platform: + $ref: '#/components/schemas/PlatformConfig' required: - kernel type: object @@ -1081,6 +1089,22 @@ components: - boot_vcpus - max_vcpus type: object + PlatformConfig: + example: + iommu_segments: + - 7 + - 7 + num_pci_segments: 8 + properties: + num_pci_segments: + format: int16 + type: integer + iommu_segments: + items: + format: int16 + type: integer + type: array + type: object MemoryZoneConfig: example: hugepages: false @@ -1353,12 +1377,9 @@ components: one_time_burst: 0 refill_time: 0 mac: mac - pci_segment: 6 + pci_segment: 3 vhost_mode: Client iommu: false - fds: - - 3 - - 3 vhost_socket: vhost_socket vhost_user: false id: id @@ -1393,11 +1414,6 @@ components: type: string id: type: string - fds: - items: - format: int32 - type: integer - type: array pci_segment: format: int16 type: integer @@ -1420,25 +1436,29 @@ components: type: object BalloonConfig: example: - size: 1 + size: 6 deflate_on_oom: false + free_page_reporting: false properties: size: format: int64 type: integer deflate_on_oom: default: false - description: Whether the balloon should deflate when the guest is under - memory pressure. + description: Deflate balloon when the guest is under memory pressure. + type: boolean + free_page_reporting: + default: false + description: Enable guest to report free pages. type: boolean required: - size type: object FsConfig: example: - pci_segment: 5 - num_queues: 2 - queue_size: 6 + pci_segment: 6 + num_queues: 1 + queue_size: 2 cache_size: 6 dax: true tag: tag @@ -1476,10 +1496,10 @@ components: type: object PmemConfig: example: - pci_segment: 3 + pci_segment: 6 mergeable: false file: file - size: 6 + size: 5 iommu: false id: id discard_writes: false @@ -1550,7 +1570,7 @@ components: type: object VsockConfig: example: - pci_segment: 0 + pci_segment: 7 iommu: false socket: socket id: id @@ -1579,7 +1599,7 @@ components: SgxEpcConfig: example: prefault: false - size: 7 + size: 0 id: id properties: id: @@ -1594,10 +1614,21 @@ components: - id - size type: object + TdxConfig: + example: + firmware: firmware + properties: + firmware: + description: Path to the firmware that will be used to boot the TDx guest + up. + type: string + required: + - firmware + type: object NumaDistance: example: - distance: 8 - destination: 4 + distance: 4 + destination: 0 properties: destination: format: int32 @@ -1612,20 +1643,20 @@ components: NumaConfig: example: distances: - - distance: 8 - destination: 4 - - distance: 8 - destination: 4 + - distance: 4 + destination: 0 + - distance: 4 + destination: 0 cpus: - - 0 - - 0 + - 6 + - 6 sgx_epc_sections: - sgx_epc_sections - sgx_epc_sections memory_zones: - memory_zones - memory_zones - guest_numa_id: 6 + guest_numa_id: 7 properties: guest_numa_id: format: int32 diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/BalloonConfig.md b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/BalloonConfig.md index e6f222847..196e9c1da 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/BalloonConfig.md +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/BalloonConfig.md @@ -5,7 +5,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **Size** | **int64** | | -**DeflateOnOom** | Pointer to **bool** | Whether the balloon should deflate when the guest is under memory pressure. | [optional] [default to false] +**DeflateOnOom** | Pointer to **bool** | Deflate balloon when the guest is under memory pressure. | [optional] [default to false] +**FreePageReporting** | Pointer to **bool** | Enable guest to report free pages. | [optional] [default to false] ## Methods @@ -71,6 +72,31 @@ SetDeflateOnOom sets DeflateOnOom field to given value. HasDeflateOnOom returns a boolean if a field has been set. +### GetFreePageReporting + +`func (o *BalloonConfig) GetFreePageReporting() bool` + +GetFreePageReporting returns the FreePageReporting field if non-nil, zero value otherwise. + +### GetFreePageReportingOk + +`func (o *BalloonConfig) GetFreePageReportingOk() (*bool, bool)` + +GetFreePageReportingOk returns a tuple with the FreePageReporting field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFreePageReporting + +`func (o *BalloonConfig) SetFreePageReporting(v bool)` + +SetFreePageReporting sets FreePageReporting field to given value. + +### HasFreePageReporting + +`func (o *BalloonConfig) HasFreePageReporting() bool` + +HasFreePageReporting returns a boolean if a field has been set. + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/NetConfig.md b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/NetConfig.md index ff4f2dcfb..073401d19 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/NetConfig.md +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/NetConfig.md @@ -15,7 +15,6 @@ Name | Type | Description | Notes **VhostSocket** | Pointer to **string** | | [optional] **VhostMode** | Pointer to **string** | | [optional] [default to "Client"] **Id** | Pointer to **string** | | [optional] -**Fds** | Pointer to **[]int32** | | [optional] **PciSegment** | Pointer to **int32** | | [optional] **RateLimiterConfig** | Pointer to [**RateLimiterConfig**](RateLimiterConfig.md) | | [optional] @@ -313,31 +312,6 @@ SetId sets Id field to given value. HasId returns a boolean if a field has been set. -### GetFds - -`func (o *NetConfig) GetFds() []int32` - -GetFds returns the Fds field if non-nil, zero value otherwise. - -### GetFdsOk - -`func (o *NetConfig) GetFdsOk() (*[]int32, bool)` - -GetFdsOk returns a tuple with the Fds field if it's non-nil, zero value otherwise -and a boolean to check if the value has been set. - -### SetFds - -`func (o *NetConfig) SetFds(v []int32)` - -SetFds sets Fds field to given value. - -### HasFds - -`func (o *NetConfig) HasFds() bool` - -HasFds returns a boolean if a field has been set. - ### GetPciSegment `func (o *NetConfig) GetPciSegment() int32` diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/PlatformConfig.md b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/PlatformConfig.md new file mode 100644 index 000000000..91adf0d99 --- /dev/null +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/PlatformConfig.md @@ -0,0 +1,82 @@ +# PlatformConfig + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**NumPciSegments** | Pointer to **int32** | | [optional] +**IommuSegments** | Pointer to **[]int32** | | [optional] + +## Methods + +### NewPlatformConfig + +`func NewPlatformConfig() *PlatformConfig` + +NewPlatformConfig instantiates a new PlatformConfig object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewPlatformConfigWithDefaults + +`func NewPlatformConfigWithDefaults() *PlatformConfig` + +NewPlatformConfigWithDefaults instantiates a new PlatformConfig object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetNumPciSegments + +`func (o *PlatformConfig) GetNumPciSegments() int32` + +GetNumPciSegments returns the NumPciSegments field if non-nil, zero value otherwise. + +### GetNumPciSegmentsOk + +`func (o *PlatformConfig) GetNumPciSegmentsOk() (*int32, bool)` + +GetNumPciSegmentsOk returns a tuple with the NumPciSegments field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetNumPciSegments + +`func (o *PlatformConfig) SetNumPciSegments(v int32)` + +SetNumPciSegments sets NumPciSegments field to given value. + +### HasNumPciSegments + +`func (o *PlatformConfig) HasNumPciSegments() bool` + +HasNumPciSegments returns a boolean if a field has been set. + +### GetIommuSegments + +`func (o *PlatformConfig) GetIommuSegments() []int32` + +GetIommuSegments returns the IommuSegments field if non-nil, zero value otherwise. + +### GetIommuSegmentsOk + +`func (o *PlatformConfig) GetIommuSegmentsOk() (*[]int32, bool)` + +GetIommuSegmentsOk returns a tuple with the IommuSegments field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetIommuSegments + +`func (o *PlatformConfig) SetIommuSegments(v []int32)` + +SetIommuSegments sets IommuSegments field to given value. + +### HasIommuSegments + +`func (o *PlatformConfig) HasIommuSegments() bool` + +HasIommuSegments returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/TdxConfig.md b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/TdxConfig.md new file mode 100644 index 000000000..8577bcf5b --- /dev/null +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/TdxConfig.md @@ -0,0 +1,51 @@ +# TdxConfig + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Firmware** | **string** | Path to the firmware that will be used to boot the TDx guest up. | + +## Methods + +### NewTdxConfig + +`func NewTdxConfig(firmware string, ) *TdxConfig` + +NewTdxConfig instantiates a new TdxConfig object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewTdxConfigWithDefaults + +`func NewTdxConfigWithDefaults() *TdxConfig` + +NewTdxConfigWithDefaults instantiates a new TdxConfig object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetFirmware + +`func (o *TdxConfig) GetFirmware() string` + +GetFirmware returns the Firmware field if non-nil, zero value otherwise. + +### GetFirmwareOk + +`func (o *TdxConfig) GetFirmwareOk() (*string, bool)` + +GetFirmwareOk returns a tuple with the Firmware field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFirmware + +`func (o *TdxConfig) SetFirmware(v string)` + +SetFirmware sets Firmware field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/VmConfig.md b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/VmConfig.md index b65a194b2..b01b81db5 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/VmConfig.md +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/docs/VmConfig.md @@ -20,9 +20,11 @@ Name | Type | Description | Notes **Devices** | Pointer to [**[]DeviceConfig**](DeviceConfig.md) | | [optional] **Vsock** | Pointer to [**VsockConfig**](VsockConfig.md) | | [optional] **SgxEpc** | Pointer to [**[]SgxEpcConfig**](SgxEpcConfig.md) | | [optional] +**Tdx** | Pointer to [**TdxConfig**](TdxConfig.md) | | [optional] **Numa** | Pointer to [**[]NumaConfig**](NumaConfig.md) | | [optional] **Iommu** | Pointer to **bool** | | [optional] [default to false] **Watchdog** | Pointer to **bool** | | [optional] [default to false] +**Platform** | Pointer to [**PlatformConfig**](PlatformConfig.md) | | [optional] ## Methods @@ -448,6 +450,31 @@ SetSgxEpc sets SgxEpc field to given value. HasSgxEpc returns a boolean if a field has been set. +### GetTdx + +`func (o *VmConfig) GetTdx() TdxConfig` + +GetTdx returns the Tdx field if non-nil, zero value otherwise. + +### GetTdxOk + +`func (o *VmConfig) GetTdxOk() (*TdxConfig, bool)` + +GetTdxOk returns a tuple with the Tdx field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTdx + +`func (o *VmConfig) SetTdx(v TdxConfig)` + +SetTdx sets Tdx field to given value. + +### HasTdx + +`func (o *VmConfig) HasTdx() bool` + +HasTdx returns a boolean if a field has been set. + ### GetNuma `func (o *VmConfig) GetNuma() []NumaConfig` @@ -523,6 +550,31 @@ SetWatchdog sets Watchdog field to given value. HasWatchdog returns a boolean if a field has been set. +### GetPlatform + +`func (o *VmConfig) GetPlatform() PlatformConfig` + +GetPlatform returns the Platform field if non-nil, zero value otherwise. + +### GetPlatformOk + +`func (o *VmConfig) GetPlatformOk() (*PlatformConfig, bool)` + +GetPlatformOk returns a tuple with the Platform field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPlatform + +`func (o *VmConfig) SetPlatform(v PlatformConfig)` + +SetPlatform sets Platform field to given value. + +### HasPlatform + +`func (o *VmConfig) HasPlatform() bool` + +HasPlatform returns a boolean if a field has been set. + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_balloon_config.go b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_balloon_config.go index 704bb5b8d..765da2a8a 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_balloon_config.go +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_balloon_config.go @@ -17,8 +17,10 @@ import ( // BalloonConfig struct for BalloonConfig type BalloonConfig struct { Size int64 `json:"size"` - // Whether the balloon should deflate when the guest is under memory pressure. + // Deflate balloon when the guest is under memory pressure. DeflateOnOom *bool `json:"deflate_on_oom,omitempty"` + // Enable guest to report free pages. + FreePageReporting *bool `json:"free_page_reporting,omitempty"` } // NewBalloonConfig instantiates a new BalloonConfig object @@ -30,6 +32,8 @@ func NewBalloonConfig(size int64) *BalloonConfig { this.Size = size var deflateOnOom bool = false this.DeflateOnOom = &deflateOnOom + var freePageReporting bool = false + this.FreePageReporting = &freePageReporting return &this } @@ -40,6 +44,8 @@ func NewBalloonConfigWithDefaults() *BalloonConfig { this := BalloonConfig{} var deflateOnOom bool = false this.DeflateOnOom = &deflateOnOom + var freePageReporting bool = false + this.FreePageReporting = &freePageReporting return &this } @@ -99,6 +105,38 @@ func (o *BalloonConfig) SetDeflateOnOom(v bool) { o.DeflateOnOom = &v } +// GetFreePageReporting returns the FreePageReporting field value if set, zero value otherwise. +func (o *BalloonConfig) GetFreePageReporting() bool { + if o == nil || o.FreePageReporting == nil { + var ret bool + return ret + } + return *o.FreePageReporting +} + +// GetFreePageReportingOk returns a tuple with the FreePageReporting field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *BalloonConfig) GetFreePageReportingOk() (*bool, bool) { + if o == nil || o.FreePageReporting == nil { + return nil, false + } + return o.FreePageReporting, true +} + +// HasFreePageReporting returns a boolean if a field has been set. +func (o *BalloonConfig) HasFreePageReporting() bool { + if o != nil && o.FreePageReporting != nil { + return true + } + + return false +} + +// SetFreePageReporting gets a reference to the given bool and assigns it to the FreePageReporting field. +func (o *BalloonConfig) SetFreePageReporting(v bool) { + o.FreePageReporting = &v +} + func (o BalloonConfig) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} if true { @@ -107,6 +145,9 @@ func (o BalloonConfig) MarshalJSON() ([]byte, error) { if o.DeflateOnOom != nil { toSerialize["deflate_on_oom"] = o.DeflateOnOom } + if o.FreePageReporting != nil { + toSerialize["free_page_reporting"] = o.FreePageReporting + } return json.Marshal(toSerialize) } diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_net_config.go b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_net_config.go index 72bdb5422..976d8cd33 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_net_config.go +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_net_config.go @@ -27,7 +27,6 @@ type NetConfig struct { VhostSocket *string `json:"vhost_socket,omitempty"` VhostMode *string `json:"vhost_mode,omitempty"` Id *string `json:"id,omitempty"` - Fds *[]int32 `json:"fds,omitempty"` PciSegment *int32 `json:"pci_segment,omitempty"` RateLimiterConfig *RateLimiterConfig `json:"rate_limiter_config,omitempty"` } @@ -429,38 +428,6 @@ func (o *NetConfig) SetId(v string) { o.Id = &v } -// GetFds returns the Fds field value if set, zero value otherwise. -func (o *NetConfig) GetFds() []int32 { - if o == nil || o.Fds == nil { - var ret []int32 - return ret - } - return *o.Fds -} - -// GetFdsOk returns a tuple with the Fds field value if set, nil otherwise -// and a boolean to check if the value has been set. -func (o *NetConfig) GetFdsOk() (*[]int32, bool) { - if o == nil || o.Fds == nil { - return nil, false - } - return o.Fds, true -} - -// HasFds returns a boolean if a field has been set. -func (o *NetConfig) HasFds() bool { - if o != nil && o.Fds != nil { - return true - } - - return false -} - -// SetFds gets a reference to the given []int32 and assigns it to the Fds field. -func (o *NetConfig) SetFds(v []int32) { - o.Fds = &v -} - // GetPciSegment returns the PciSegment field value if set, zero value otherwise. func (o *NetConfig) GetPciSegment() int32 { if o == nil || o.PciSegment == nil { @@ -560,9 +527,6 @@ func (o NetConfig) MarshalJSON() ([]byte, error) { if o.Id != nil { toSerialize["id"] = o.Id } - if o.Fds != nil { - toSerialize["fds"] = o.Fds - } if o.PciSegment != nil { toSerialize["pci_segment"] = o.PciSegment } diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_platform_config.go b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_platform_config.go new file mode 100644 index 000000000..e480c8a91 --- /dev/null +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_platform_config.go @@ -0,0 +1,149 @@ +/* +Cloud Hypervisor API + +Local HTTP based API for managing and inspecting a cloud-hypervisor virtual machine. + +API version: 0.3.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// PlatformConfig struct for PlatformConfig +type PlatformConfig struct { + NumPciSegments *int32 `json:"num_pci_segments,omitempty"` + IommuSegments *[]int32 `json:"iommu_segments,omitempty"` +} + +// NewPlatformConfig instantiates a new PlatformConfig object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewPlatformConfig() *PlatformConfig { + this := PlatformConfig{} + return &this +} + +// NewPlatformConfigWithDefaults instantiates a new PlatformConfig object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewPlatformConfigWithDefaults() *PlatformConfig { + this := PlatformConfig{} + return &this +} + +// GetNumPciSegments returns the NumPciSegments field value if set, zero value otherwise. +func (o *PlatformConfig) GetNumPciSegments() int32 { + if o == nil || o.NumPciSegments == nil { + var ret int32 + return ret + } + return *o.NumPciSegments +} + +// GetNumPciSegmentsOk returns a tuple with the NumPciSegments field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *PlatformConfig) GetNumPciSegmentsOk() (*int32, bool) { + if o == nil || o.NumPciSegments == nil { + return nil, false + } + return o.NumPciSegments, true +} + +// HasNumPciSegments returns a boolean if a field has been set. +func (o *PlatformConfig) HasNumPciSegments() bool { + if o != nil && o.NumPciSegments != nil { + return true + } + + return false +} + +// SetNumPciSegments gets a reference to the given int32 and assigns it to the NumPciSegments field. +func (o *PlatformConfig) SetNumPciSegments(v int32) { + o.NumPciSegments = &v +} + +// GetIommuSegments returns the IommuSegments field value if set, zero value otherwise. +func (o *PlatformConfig) GetIommuSegments() []int32 { + if o == nil || o.IommuSegments == nil { + var ret []int32 + return ret + } + return *o.IommuSegments +} + +// GetIommuSegmentsOk returns a tuple with the IommuSegments field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *PlatformConfig) GetIommuSegmentsOk() (*[]int32, bool) { + if o == nil || o.IommuSegments == nil { + return nil, false + } + return o.IommuSegments, true +} + +// HasIommuSegments returns a boolean if a field has been set. +func (o *PlatformConfig) HasIommuSegments() bool { + if o != nil && o.IommuSegments != nil { + return true + } + + return false +} + +// SetIommuSegments gets a reference to the given []int32 and assigns it to the IommuSegments field. +func (o *PlatformConfig) SetIommuSegments(v []int32) { + o.IommuSegments = &v +} + +func (o PlatformConfig) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if o.NumPciSegments != nil { + toSerialize["num_pci_segments"] = o.NumPciSegments + } + if o.IommuSegments != nil { + toSerialize["iommu_segments"] = o.IommuSegments + } + return json.Marshal(toSerialize) +} + +type NullablePlatformConfig struct { + value *PlatformConfig + isSet bool +} + +func (v NullablePlatformConfig) Get() *PlatformConfig { + return v.value +} + +func (v *NullablePlatformConfig) Set(val *PlatformConfig) { + v.value = val + v.isSet = true +} + +func (v NullablePlatformConfig) IsSet() bool { + return v.isSet +} + +func (v *NullablePlatformConfig) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullablePlatformConfig(val *PlatformConfig) *NullablePlatformConfig { + return &NullablePlatformConfig{value: val, isSet: true} +} + +func (v NullablePlatformConfig) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullablePlatformConfig) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_tdx_config.go b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_tdx_config.go new file mode 100644 index 000000000..3fe9057da --- /dev/null +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_tdx_config.go @@ -0,0 +1,107 @@ +/* +Cloud Hypervisor API + +Local HTTP based API for managing and inspecting a cloud-hypervisor virtual machine. + +API version: 0.3.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// TdxConfig struct for TdxConfig +type TdxConfig struct { + // Path to the firmware that will be used to boot the TDx guest up. + Firmware string `json:"firmware"` +} + +// NewTdxConfig instantiates a new TdxConfig object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewTdxConfig(firmware string) *TdxConfig { + this := TdxConfig{} + this.Firmware = firmware + return &this +} + +// NewTdxConfigWithDefaults instantiates a new TdxConfig object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewTdxConfigWithDefaults() *TdxConfig { + this := TdxConfig{} + return &this +} + +// GetFirmware returns the Firmware field value +func (o *TdxConfig) GetFirmware() string { + if o == nil { + var ret string + return ret + } + + return o.Firmware +} + +// GetFirmwareOk returns a tuple with the Firmware field value +// and a boolean to check if the value has been set. +func (o *TdxConfig) GetFirmwareOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Firmware, true +} + +// SetFirmware sets field value +func (o *TdxConfig) SetFirmware(v string) { + o.Firmware = v +} + +func (o TdxConfig) MarshalJSON() ([]byte, error) { + toSerialize := map[string]interface{}{} + if true { + toSerialize["firmware"] = o.Firmware + } + return json.Marshal(toSerialize) +} + +type NullableTdxConfig struct { + value *TdxConfig + isSet bool +} + +func (v NullableTdxConfig) Get() *TdxConfig { + return v.value +} + +func (v *NullableTdxConfig) Set(val *TdxConfig) { + v.value = val + v.isSet = true +} + +func (v NullableTdxConfig) IsSet() bool { + return v.isSet +} + +func (v *NullableTdxConfig) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableTdxConfig(val *TdxConfig) *NullableTdxConfig { + return &NullableTdxConfig{value: val, isSet: true} +} + +func (v NullableTdxConfig) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableTdxConfig) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_vm_config.go b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_vm_config.go index cf4e7e0d5..24c2e6289 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_vm_config.go +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/client/model_vm_config.go @@ -32,9 +32,11 @@ type VmConfig struct { Devices *[]DeviceConfig `json:"devices,omitempty"` Vsock *VsockConfig `json:"vsock,omitempty"` SgxEpc *[]SgxEpcConfig `json:"sgx_epc,omitempty"` + Tdx *TdxConfig `json:"tdx,omitempty"` Numa *[]NumaConfig `json:"numa,omitempty"` Iommu *bool `json:"iommu,omitempty"` Watchdog *bool `json:"watchdog,omitempty"` + Platform *PlatformConfig `json:"platform,omitempty"` } // NewVmConfig instantiates a new VmConfig object @@ -578,6 +580,38 @@ func (o *VmConfig) SetSgxEpc(v []SgxEpcConfig) { o.SgxEpc = &v } +// GetTdx returns the Tdx field value if set, zero value otherwise. +func (o *VmConfig) GetTdx() TdxConfig { + if o == nil || o.Tdx == nil { + var ret TdxConfig + return ret + } + return *o.Tdx +} + +// GetTdxOk returns a tuple with the Tdx field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VmConfig) GetTdxOk() (*TdxConfig, bool) { + if o == nil || o.Tdx == nil { + return nil, false + } + return o.Tdx, true +} + +// HasTdx returns a boolean if a field has been set. +func (o *VmConfig) HasTdx() bool { + if o != nil && o.Tdx != nil { + return true + } + + return false +} + +// SetTdx gets a reference to the given TdxConfig and assigns it to the Tdx field. +func (o *VmConfig) SetTdx(v TdxConfig) { + o.Tdx = &v +} + // GetNuma returns the Numa field value if set, zero value otherwise. func (o *VmConfig) GetNuma() []NumaConfig { if o == nil || o.Numa == nil { @@ -674,6 +708,38 @@ func (o *VmConfig) SetWatchdog(v bool) { o.Watchdog = &v } +// GetPlatform returns the Platform field value if set, zero value otherwise. +func (o *VmConfig) GetPlatform() PlatformConfig { + if o == nil || o.Platform == nil { + var ret PlatformConfig + return ret + } + return *o.Platform +} + +// GetPlatformOk returns a tuple with the Platform field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VmConfig) GetPlatformOk() (*PlatformConfig, bool) { + if o == nil || o.Platform == nil { + return nil, false + } + return o.Platform, true +} + +// HasPlatform returns a boolean if a field has been set. +func (o *VmConfig) HasPlatform() bool { + if o != nil && o.Platform != nil { + return true + } + + return false +} + +// SetPlatform gets a reference to the given PlatformConfig and assigns it to the Platform field. +func (o *VmConfig) SetPlatform(v PlatformConfig) { + o.Platform = &v +} + func (o VmConfig) MarshalJSON() ([]byte, error) { toSerialize := map[string]interface{}{} if o.Cpus != nil { @@ -724,6 +790,9 @@ func (o VmConfig) MarshalJSON() ([]byte, error) { if o.SgxEpc != nil { toSerialize["sgx_epc"] = o.SgxEpc } + if o.Tdx != nil { + toSerialize["tdx"] = o.Tdx + } if o.Numa != nil { toSerialize["numa"] = o.Numa } @@ -733,6 +802,9 @@ func (o VmConfig) MarshalJSON() ([]byte, error) { if o.Watchdog != nil { toSerialize["watchdog"] = o.Watchdog } + if o.Platform != nil { + toSerialize["platform"] = o.Platform + } return json.Marshal(toSerialize) } diff --git a/src/runtime/virtcontainers/pkg/cloud-hypervisor/cloud-hypervisor.yaml b/src/runtime/virtcontainers/pkg/cloud-hypervisor/cloud-hypervisor.yaml index 476c179fe..c4dcae04c 100644 --- a/src/runtime/virtcontainers/pkg/cloud-hypervisor/cloud-hypervisor.yaml +++ b/src/runtime/virtcontainers/pkg/cloud-hypervisor/cloud-hypervisor.yaml @@ -500,6 +500,8 @@ components: type: array items: $ref: '#/components/schemas/SgxEpcConfig' + tdx: + $ref: '#/components/schemas/TdxConfig' numa: type: array items: @@ -510,6 +512,8 @@ components: watchdog: type: boolean default: false + platform: + $ref: '#/components/schemas/PlatformConfig' description: Virtual machine configuration CpuAffinity: @@ -557,6 +561,18 @@ components: items: $ref: '#/components/schemas/CpuAffinity' + PlatformConfig: + type: object + properties: + num_pci_segments: + type: integer + format: int16 + iommu_segments: + type: array + items: + type: integer + format: int16 + MemoryZoneConfig: required: - id @@ -771,11 +787,6 @@ components: default: "Client" id: type: string - fds: - type: array - items: - type: integer - format: int32 pci_segment: type: integer format: int16 @@ -805,7 +816,11 @@ components: deflate_on_oom: type: boolean default: false - description: Whether the balloon should deflate when the guest is under memory pressure. + description: Deflate balloon when the guest is under memory pressure. + free_page_reporting: + type: boolean + default: false + description: Enable guest to report free pages. FsConfig: required: @@ -933,6 +948,15 @@ components: type: boolean default: false + TdxConfig: + required: + - firmware + type: object + properties: + firmware: + type: string + description: Path to the firmware that will be used to boot the TDx guest up. + NumaDistance: required: - destination diff --git a/versions.yaml b/versions.yaml index fea9e1961..f8154866c 100644 --- a/versions.yaml +++ b/versions.yaml @@ -75,7 +75,7 @@ assets: url: "https://github.com/cloud-hypervisor/cloud-hypervisor" uscan-url: >- https://github.com/cloud-hypervisor/cloud-hypervisor/tags.*/v?(\d\S+)\.tar\.gz - version: "v21.0" + version: "55479a64d237d4c757dba19a696abefd27ec74fd" firecracker: description: "Firecracker micro-VMM" From 4bd945b67b30ac00b0198de5039ce0439e624350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Tue, 15 Feb 2022 08:52:03 +0100 Subject: [PATCH 11/47] virtiofsd: Use "-o announce_submounts" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit German Maglione, one of the current virtio-fs developers, has brought to our attention that using "announce-submounts" could help us to prevent inode number collisions. This feature was introduced a year ago or so by Hanna Reitz as part of the 08dce386e77eb9ab044cb118e5391dc9ae11c5a8, and as we already mandate QEMU >= 6.1.0, let's take advantage of that. Fixes: #3507 Signed-off-by: Fabiano Fidêncio --- src/runtime/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime/Makefile b/src/runtime/Makefile index f936bd796..9c6dc521a 100644 --- a/src/runtime/Makefile +++ b/src/runtime/Makefile @@ -175,7 +175,7 @@ DEFVIRTIOFSCACHE ?= auto # # see `virtiofsd -h` for possible options. # Make sure you quote args. -DEFVIRTIOFSEXTRAARGS ?= [\"--thread-pool-size=1\"] +DEFVIRTIOFSEXTRAARGS ?= [\"--thread-pool-size=1\", \"-o\", \"announce_submounts\"] DEFENABLEIOTHREADS := false DEFENABLEVHOSTUSERSTORE := false DEFVHOSTUSERSTOREPATH := $(PKGRUNDIR)/vhost-user From 3f87835a0ef42319482a62079a97246d2c8c701c Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 08:55:54 +0000 Subject: [PATCH 12/47] utils: Switch kata manager to use getopts Use `getopts(1)` for command line argument parsing in `kata-manager.sh`. Signed-off-by: James O. D. Hunt --- utils/kata-manager.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/utils/kata-manager.sh b/utils/kata-manager.sh index 52416b920..7330aece2 100755 --- a/utils/kata-manager.sh +++ b/utils/kata-manager.sh @@ -560,9 +560,16 @@ handle_installation() handle_args() { - case "${1:-}" in - -h|--help|help) usage; exit 0;; - esac + local opt + + while getopts "h" opt "$@" + do + case "$opt" in + h) usage; exit 0 ;; + esac + done + + shift $[$OPTIND-1] local kata_version="${1:-}" local containerd_version="${2:-}" From 55cdef2295a318d22d63f212085f350f2c2931d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Tue, 15 Feb 2022 13:16:44 +0100 Subject: [PATCH 13/47] tools: clh: Add the possibility to always build from sources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current code will always pull the release binaries in case the version requested by Kata Containers matches with a released version. This, however, has a limitation of preventing users / CIs to build cloud-hypervisor from source for a reason or another, such as passing a specific build flag to cloud-hypervisor. This is a pre-req to solving https://github.com/kata-containers/kata-containers/issues/3671. While here, a small changes were needed in order to improve readability and debugability of why we're building something from the sources rather than simply downloading and using a pre-built binary. Fixes: #3672 Signed-off-by: Fabiano Fidêncio --- .../cloud-hypervisor/build-static-clh.sh | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh b/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh index f174daac0..e1ceb42f7 100755 --- a/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh +++ b/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh @@ -15,6 +15,7 @@ ARCH=$(uname -m) script_dir=$(dirname $(readlink -f "$0")) kata_version="${kata_version:-}" +force_build_from_source="${force_build_from_source:-false}" source "${script_dir}/../../scripts/lib.sh" @@ -55,7 +56,15 @@ build_clh_from_source() { popd } -if [ ${ARCH} == "aarch64" ] || ! pull_clh_released_binary; then - info "arch is aarch64 or failed to pull cloud-hypervisor released binary on x86_64, trying to build from source" - build_clh_from_source +if [ "${ARCH}" == "aarch64" ]; then + info "aarch64 binaries are not distributed as part of the Cloud Hypervisor releases, forcing to build from source" + force_build_from_source="true" +fi + +if [ "${force_build_from_source}" == "true" ]; then + info "Build cloud-hypervisor from source as it's been request via the force_build_from_source flag" + build_clh_from_source +else + pull_clh_released_binary || + (info "Failed to pull cloud-hypervisor released binary, trying to build from source" && build_clh_from_source) fi From e07545a23ca24104c2cdcdede6c951fcfd6e1e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Tue, 15 Feb 2022 13:59:24 +0100 Subject: [PATCH 14/47] tools: clh: Allow passing down a build flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's allow passing down a build flag to cargo, when building Cloud Hypervisor. By doing this we allow calling this script with: ``` extra_build_flags="--features tdx" ./build-static-clh.sh ``` Fixes: #3671 Signed-off-by: Fabiano Fidêncio --- .../cloud-hypervisor/build-static-clh.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh b/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh index e1ceb42f7..8569ac87c 100755 --- a/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh +++ b/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh @@ -16,6 +16,7 @@ ARCH=$(uname -m) script_dir=$(dirname $(readlink -f "$0")) kata_version="${kata_version:-}" force_build_from_source="${force_build_from_source:-false}" +extra_build_args="${extra_build_args:-}" source "${script_dir}/../../scripts/lib.sh" @@ -50,7 +51,12 @@ build_clh_from_source() { pushd "${repo_dir}" git fetch || true git checkout "${cloud_hypervisor_version}" - ./scripts/dev_cli.sh build --release --libc musl + if [ -n "${extra_build_args}" ]; then + info "Build cloud-hypervisor with extra args: ${extra_build_args}" + ./scripts/dev_cli.sh build --release --libc musl -- ${extra_build_args} + else + ./scripts/dev_cli.sh build --release --libc musl + fi rm -f cloud-hypervisor cp build/cargo_target/$(uname -m)-unknown-linux-musl/release/cloud-hypervisor . popd @@ -61,6 +67,11 @@ if [ "${ARCH}" == "aarch64" ]; then force_build_from_source="true" fi +if [ -n "${extra_build_args}" ]; then + info "As an extra build argument has been passed to the script, forcing to build from source" + force_build_from_source="true" +fi + if [ "${force_build_from_source}" == "true" ]; then info "Build cloud-hypervisor from source as it's been request via the force_build_from_source flag" build_clh_from_source From 395cff480d2d27bbd4d35ca548def18744d9cc4b Mon Sep 17 00:00:00 2001 From: Gabriela Cervantes Date: Tue, 15 Feb 2022 15:29:12 +0000 Subject: [PATCH 15/47] docs: Remove docker run and shared memory from limitations This PR removes the docker run and shared memory segment from the limitations document as for kata 2.0 we do not support docker and this is not longer valid. Fixes #3676 Signed-off-by: Gabriela Cervantes --- docs/Limitations.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/Limitations.md b/docs/Limitations.md index 9ffd5833a..9c2b44c27 100644 --- a/docs/Limitations.md +++ b/docs/Limitations.md @@ -97,13 +97,6 @@ See issue https://github.com/clearcontainers/runtime/issues/341 and [the constra For CPUs resource management see [CPU constraints](design/vcpu-handling.md). -### docker run and shared memory - -The runtime does not implement the `docker run --shm-size` command to -set the size of the `/dev/shm tmpfs` within the container. It is possible to pass this configuration value into the VM container so the appropriate mount command happens at launch time. - -See issue https://github.com/kata-containers/kata-containers/issues/21 for more information. - # Architectural limitations This section lists items that might not be fixed due to fundamental From f4d1e45c33ee3349176d92c6753871f36c3b58e2 Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 08:58:36 +0000 Subject: [PATCH 16/47] utils: Add kata-manager CLI options for kata and containerd Add options to `kata-manager.sh` to allow the version of Kata and containerd to be specified. Signed-off-by: James O. D. Hunt --- utils/kata-manager.sh | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/utils/kata-manager.sh b/utils/kata-manager.sh index 7330aece2..45c844831 100755 --- a/utils/kata-manager.sh +++ b/utils/kata-manager.sh @@ -191,7 +191,9 @@ Description: Install $kata_project [1] and $containerd_project [2] from GitHub r Options: - -h : Show this help statement. + -c : Specify containerd version. + -h : Show this help statement. + -k : Specify Kata Containers version. Notes: @@ -562,17 +564,22 @@ handle_args() { local opt - while getopts "h" opt "$@" + local kata_version="" + local containerd_version="" + + while getopts "c:hk:" opt "$@" do case "$opt" in + c) containerd_version="$OPTARG" ;; h) usage; exit 0 ;; + k) kata_version="$OPTARG" ;; esac done shift $[$OPTIND-1] - local kata_version="${1:-}" - local containerd_version="${2:-}" + [ -z "$kata_version" ] && kata_version="${1:-}" || true + [ -z "$containerd_version" ] && containerd_version="${2:-}" || true handle_installation \ "$kata_version" \ From ae21fcc799fb21ee8a8c65b3bf68fbcd8630b194 Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 13:29:27 +0000 Subject: [PATCH 17/47] utils: Fix Kata tar archive check The static tar archive published on GitHub (now) contains `./` which is being being flagged as an "unknown path" and resulting in the `kata-manager.sh` script failing. Partially fixes: #3674. Signed-off-by: James O. D. Hunt --- utils/kata-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/kata-manager.sh b/utils/kata-manager.sh index 45c844831..147891176 100755 --- a/utils/kata-manager.sh +++ b/utils/kata-manager.sh @@ -473,7 +473,7 @@ install_kata() # Since we're unpacking to the root directory, perform a sanity check # on the archive first. local unexpected=$(tar -tf "${file}" |\ - egrep -v "^(\./opt/$|\.${kata_install_dir}/)" || true) + egrep -v "^(\./$|\./opt/$|\.${kata_install_dir}/)" || true) [ -n "$unexpected" ] && die "File '$file' contains unexpected paths: '$unexpected'" From 601be4e63bd18561d3ce66b360f033821c992e8b Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 13:31:30 +0000 Subject: [PATCH 18/47] utils: Fix containerd installation Fix bug introduced inadvertently on #3330 which fixes the Kata installation, but unfortunately breaks installing containerd. The new approach is to check that the download URL matches a project-specific regular expression. Also improves the architecture test to handle the containerd architecture name (`amd64` rather than `x86_64`). Fixes: #3674. Signed-off-by: James O. D. Hunt --- utils/kata-manager.sh | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/utils/kata-manager.sh b/utils/kata-manager.sh index 147891176..1a494feac 100755 --- a/utils/kata-manager.sh +++ b/utils/kata-manager.sh @@ -136,16 +136,31 @@ github_get_release_file_url() local url="${1:-}" local version="${2:-}" - download_urls=$(curl -sL "$url" |\ + local arch=$(uname -m) + + local regex="" + + case "$url" in + *kata*) + regex="kata-static-.*-${arch}.tar.xz" + ;; + + *containerd*) + [ "$arch" = "x86_64" ] && arch="amd64" + regex="containerd-.*-linux-${arch}.tar.gz" + ;; + + *) die "invalid url: '$url'" ;; + esac + + local download_url + + download_url=$(curl -sL "$url" |\ jq --arg version "$version" \ -r '.[] | select(.tag_name == $version) | .assets[].browser_download_url' |\ - grep static) + grep "/${regex}$") - [ -z "$download_urls" ] && die "Cannot determine download URL for version $version ($url)" - - local arch=$(uname -m) - local download_url=$(grep "$arch" <<< "$download_urls") - [ -z "$download_url" ] && die "No release for architecture '$arch' ($url)" + [ -z "$download_url" ] && die "Cannot determine download URL for version $version ($url)" echo "$download_url" } From 4755d004a724733f66447b11d13ec5a3ecc8ffa8 Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 13:37:32 +0000 Subject: [PATCH 19/47] utils: Fix unused parameter Actually make use of the `requested_version` parameter in `kata-manager.sh` and added a comment. Signed-off-by: James O. D. Hunt --- utils/kata-manager.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/utils/kata-manager.sh b/utils/kata-manager.sh index 1a494feac..3ee8245d1 100755 --- a/utils/kata-manager.sh +++ b/utils/kata-manager.sh @@ -330,6 +330,8 @@ github_download_package() { local releases_url="${1:-}" local requested_version="${2:-}" + + # Only used for error message local project="${3:-}" [ -z "$releases_url" ] && die "need releases URL" @@ -337,7 +339,7 @@ github_download_package() local version=$(github_resolve_version_to_download \ "$releases_url" \ - "$version" || true) + "$requested_version" || true) [ -z "$version" ] && die "Unable to determine $project version to download" From c464f3267651d92ec1aed810fe38804d560faa4a Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 14:02:17 +0000 Subject: [PATCH 20/47] utils: kata-manager: Force containerd sym link creation For consistency with the rest of the script force the creation of a symbolic link for containerd in `kata-manager.sh`. Signed-off-by: James O. D. Hunt --- utils/kata-manager.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/kata-manager.sh b/utils/kata-manager.sh index 3ee8245d1..f7e11e425 100755 --- a/utils/kata-manager.sh +++ b/utils/kata-manager.sh @@ -378,7 +378,7 @@ install_containerd() sudo tar -C /usr/local -xvf "${file}" - sudo ln -s /usr/local/bin/ctr "${link_dir}" + sudo ln -sf /usr/local/bin/ctr "${link_dir}" info "$project installed\n" } From 714c9f56fdad47fcad4df58fee7c8425f4559899 Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 14:05:06 +0000 Subject: [PATCH 21/47] utils: Improve containerd configuration `kata-manager.sh` improvements for containerd: - Fixed containerd default branch (which is now `main`). - Only install service file if it doesn't already exist. - Enable the containerd service to ensure it can be started. Signed-off-by: James O. D. Hunt --- utils/kata-manager.sh | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/utils/kata-manager.sh b/utils/kata-manager.sh index f7e11e425..e0cc95457 100755 --- a/utils/kata-manager.sh +++ b/utils/kata-manager.sh @@ -391,31 +391,35 @@ configure_containerd() local cfg="/etc/containerd/config.toml" - pushd "$tmpdir" >/dev/null - - local service_url=$(printf "%s/%s/%s/%s" \ - "https://raw.githubusercontent.com" \ - "${containerd_slug}" \ - "master" \ - "${containerd_service_name}") - - curl -LO "$service_url" - - printf "# %s: Service installed for Kata Containers\n" \ - "$(date -Iseconds)" |\ - tee -a "$containerd_service_name" - local systemd_unit_dir="/etc/systemd/system" sudo mkdir -p "$systemd_unit_dir" local dest="${systemd_unit_dir}/${containerd_service_name}" - sudo cp "${containerd_service_name}" "${dest}" - sudo systemctl daemon-reload + if [ ! -f "$dest" ] + then + pushd "$tmpdir" >/dev/null - info "Installed ${dest}" + local service_url=$(printf "%s/%s/%s/%s" \ + "https://raw.githubusercontent.com" \ + "${containerd_slug}" \ + "main" \ + "${containerd_service_name}") - popd >/dev/null + curl -LO "$service_url" + + printf "# %s: Service installed for Kata Containers\n" \ + "$(date -Iseconds)" |\ + tee -a "$containerd_service_name" + + + sudo cp "${containerd_service_name}" "${dest}" + sudo systemctl daemon-reload + + info "Installed ${dest}" + + popd >/dev/null + fi # Backup the original containerd configuration: sudo mkdir -p "$(dirname $cfg)" @@ -448,6 +452,7 @@ EOT info "Modified $cfg" } + sudo systemctl enable containerd sudo systemctl start containerd info "Configured $project\n" From 34b2e67d48a29bf8be2e2422b2feda22946ebbcf Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 14:08:18 +0000 Subject: [PATCH 22/47] utils: Added more kata manager cli options Added CLI options to the `kata-manager.sh` script to: - Force installation - Disable cleanup (retain downloaded files) - Only install Kata (don't consider containerd). > **Note:** > > This change introduces a subtle behaviour difference: > > - Previously, the script would error if containerd was already installed. > > - Now, the script will detect the existing installation and skip > trying to install containerd. > > This new behaviour makes more sense for most users but if you wish > to use the old behaviour, you (now) need to run the script specifying > the `-f` (force) option. Signed-off-by: James O. D. Hunt --- utils/kata-manager.sh | 98 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 84 insertions(+), 14 deletions(-) diff --git a/utils/kata-manager.sh b/utils/kata-manager.sh index e0cc95457..38260c865 100755 --- a/utils/kata-manager.sh +++ b/utils/kata-manager.sh @@ -202,13 +202,17 @@ usage() cat < []] -Description: Install $kata_project [1] and $containerd_project [2] from GitHub release binaries. +Description: Install $kata_project [1] (and optionally $containerd_project [2]) + from GitHub release binaries. Options: -c : Specify containerd version. + -f : Force installation (use with care). -h : Show this help statement. -k : Specify Kata Containers version. + -o : Only install Kata Containers. + -r : Don't cleanup on failure (retain files). Notes: @@ -248,6 +252,18 @@ only_supports_cgroups_v2() return 0 } +# Return 0 if containerd is already installed, else return 1. +containerd_installed() +{ + command -v containerd &>/dev/null && return 0 + + systemctl list-unit-files --type service |\ + egrep -q "^${containerd_service_name}\>" \ + && return 0 + + return 1 +} + pre_checks() { info "Running pre-checks" @@ -255,12 +271,11 @@ pre_checks() command -v "${kata_shim_v2}" &>/dev/null \ && die "Please remove existing $kata_project installation" - command -v containerd &>/dev/null \ - && die "$containerd_project already installed" + local ret - systemctl list-unit-files --type service |\ - egrep -q "^${containerd_service_name}\>" \ - && die "$containerd_project already installed" + { containerd_installed; ret=$?; } || true + + [ "$ret" -eq 0 ] && die "$containerd_project already installed" local cgroups_v2_only=$(only_supports_cgroups_v2 || true) @@ -315,9 +330,18 @@ check_deps() setup() { - trap cleanup EXIT + local cleanup="${1:-}" + [ -z "$cleanup" ] && die "no cleanup value" + + local force="${2:-}" + [ -z "$force" ] && die "no force value" + + [ "$cleanup" = "true" ] && trap cleanup EXIT + source /etc/os-release || source /usr/lib/os-release + [ "$force" = "true" ] && return 0 + pre_checks check_deps } @@ -529,7 +553,24 @@ handle_containerd() { local version="${1:-}" - install_containerd "$version" + local force="${2:-}" + [ -z "$force" ] && die "need force value" + + local ret + + if [ "$force" = "true" ] + then + install_containerd "$version" + else + { containerd_installed; ret=$?; } || true + + if [ "$ret" -eq 0 ] + then + info "Using existing containerd installation" + else + install_containerd "$version" + fi + fi configure_containerd @@ -567,34 +608,60 @@ test_installation() handle_installation() { - local kata_version="${1:-}" - local containerd_version="${2:-}" + local cleanup="${1:-}" + [ -z "$cleanup" ] && die "no cleanup value" - setup + local force="${2:-}" + [ -z "$force" ] && die "no force value" + + local only_kata="${3:-}" + [ -z "$only_kata" ] && die "no only Kata value" + + # These params can be blank + local kata_version="${4:-}" + local containerd_version="${5:-}" + + setup "$cleanup" "$force" handle_kata "$kata_version" - handle_containerd "$containerd_version" + + [ "$only_kata" = "false" ] && \ + handle_containerd \ + "$containerd_version" \ + "$force" test_installation - info "$kata_project and $containerd_project are now installed" + if [ "$only_kata" = "true" ] + then + info "$kata_project is now installed" + else + info "$kata_project and $containerd_project are now installed" + fi echo -e "\n${warnings}\n" } handle_args() { + local cleanup="true" + local force="false" + local only_kata="false" + local opt local kata_version="" local containerd_version="" - while getopts "c:hk:" opt "$@" + while getopts "c:fhk:or" opt "$@" do case "$opt" in c) containerd_version="$OPTARG" ;; + f) force="true" ;; h) usage; exit 0 ;; k) kata_version="$OPTARG" ;; + o) only_kata="true" ;; + r) cleanup="false" ;; esac done @@ -604,6 +671,9 @@ handle_args() [ -z "$containerd_version" ] && containerd_version="${2:-}" || true handle_installation \ + "$cleanup" \ + "$force" \ + "$only_kata" \ "$kata_version" \ "$containerd_version" } From 493ebc8ca5a17925ae5de2afa1eb1ec8f1c1ce25 Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Tue, 15 Feb 2022 14:27:08 +0000 Subject: [PATCH 23/47] utils: Update kata manager docs Update the `kata-manager.sh` README to recommend users view the available options before running the script. Signed-off-by: James O. D. Hunt --- utils/README.md | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/utils/README.md b/utils/README.md index 57e9a879b..255568a71 100644 --- a/utils/README.md +++ b/utils/README.md @@ -38,18 +38,36 @@ If you still wish to continue, but prefer a manual installation, see ## Install a minimal Kata Containers system +By default, the script will attempt to install Kata Containers and +containerd, and then configure containerd to use Kata Containers. However, +the script provides a number of options to allow you to change its +behaviour. + +> **Note:** +> +> Before running the script to install Kata Containers, we recommend +> that you [review the available options](#show-available-options). + +### Show available options + +To show the available options without installing anything, run: + +```sh +$ bash -c "$(curl -fsSL https://raw.githubusercontent.com/kata-containers/kata-containers/main/utils/kata-manager.sh) -h" +``` + +### To install Kata Containers only + +If your system already has containerd installed, to install Kata Containers and only configure containerd, run: + +```sh +$ bash -c "$(curl -fsSL https://raw.githubusercontent.com/kata-containers/kata-containers/main/utils/kata-manager.sh) -o" +``` + +### To install Kata Containers and containerd + To install and configure a system with Kata Containers and containerd, run: ```bash $ bash -c "$(curl -fsSL https://raw.githubusercontent.com/kata-containers/kata-containers/main/utils/kata-manager.sh)" ``` - -> **Notes:** -> -> - The script must be run on a system that does not have Kata Containers or -> containerd already installed on it. -> -> - The script accepts up to two parameters which can be used to test -> pre-release versions (a Kata Containers version, and a containerd -> version). If either version is unspecified or specified as `""`, the -> latest official version will be installed. From 80e8dbf1f5e4ecd59a621bbcd70c413102b31968 Mon Sep 17 00:00:00 2001 From: bin Date: Tue, 15 Feb 2022 11:51:23 +0800 Subject: [PATCH 24/47] agent: valid envs for hooks Envs contain null-byte will cause running hooks to panic, this commit will filter envs and only pass valid envs to hooks. Fixes: #3667 Signed-off-by: bin --- src/agent/rustjail/src/container.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/agent/rustjail/src/container.rs b/src/agent/rustjail/src/container.rs index 088364c7c..d29a4339d 100644 --- a/src/agent/rustjail/src/container.rs +++ b/src/agent/rustjail/src/container.rs @@ -1488,14 +1488,9 @@ async fn execute_hook(logger: &Logger, h: &Hook, st: &OCIState) -> Result<()> { if args.len() > 1 { args.remove(0); } - let env: HashMap = h - .env - .iter() - .map(|e| { - let v: Vec<&str> = e.split('=').collect(); - (v[0].to_string(), v[1].to_string()) - }) - .collect(); + + // all invalid envs will be ommit, only valid envs will be passed to hook. + let env: HashMap<&str, &str> = h.env.iter().filter_map(|e| valid_env(e)).collect(); // Avoid the exit signal to be reaped by the global reaper. let _wait_locker = WAIT_PID_LOCKER.lock().await; @@ -1506,8 +1501,7 @@ async fn execute_hook(logger: &Logger, h: &Hook, st: &OCIState) -> Result<()> { .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) - .spawn() - .unwrap(); + .spawn()?; // default timeout 10s let mut timeout: u64 = 10; @@ -1647,13 +1641,16 @@ mod tests { let touch = which("touch").await; defer!(fs::remove_file(temp_file).unwrap();); + let invalid_str = vec![97, b'\0', 98]; + let invalid_string = std::str::from_utf8(&invalid_str).unwrap(); + let invalid_env = format!("{}=value", invalid_string); execute_hook( &slog_scope::logger(), &Hook { path: touch, args: vec!["touch".to_string(), temp_file.to_string()], - env: vec![], + env: vec![invalid_env], timeout: Some(10), }, &OCIState { From 72bf5496fd516f9b5f532cd2e0e9f2e987937bc8 Mon Sep 17 00:00:00 2001 From: bin Date: Tue, 15 Feb 2022 13:27:14 +0800 Subject: [PATCH 25/47] agent: handle hook process result Current hook process is handled by just calling unwrap() on it, sometime it will cause panic. By handling all Result type and check the error can avoid panic. Fixes: #3649 Signed-off-by: bin --- src/agent/rustjail/src/container.rs | 58 +++++++++++++++-------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/agent/rustjail/src/container.rs b/src/agent/rustjail/src/container.rs index d29a4339d..942a625d5 100644 --- a/src/agent/rustjail/src/container.rs +++ b/src/agent/rustjail/src/container.rs @@ -1489,7 +1489,7 @@ async fn execute_hook(logger: &Logger, h: &Hook, st: &OCIState) -> Result<()> { args.remove(0); } - // all invalid envs will be ommit, only valid envs will be passed to hook. + // all invalid envs will be omitted, only valid envs will be passed to hook. let env: HashMap<&str, &str> = h.env.iter().filter_map(|e| valid_env(e)).collect(); // Avoid the exit signal to be reaped by the global reaper. @@ -1517,37 +1517,39 @@ async fn execute_hook(logger: &Logger, h: &Hook, st: &OCIState) -> Result<()> { let path = h.path.clone(); let join_handle = tokio::spawn(async move { - child - .stdin - .as_mut() - .unwrap() - .write_all(state.as_bytes()) - .await - .unwrap(); - - // Close stdin so that hook program could receive EOF - child.stdin.take(); + if let Some(mut stdin) = child.stdin.take() { + match stdin.write_all(state.as_bytes()).await { + Ok(_) => {} + Err(e) => { + info!(logger, "write to child stdin failed: {:?}", e); + } + } + } // read something from stdout and stderr for debug - let mut out = String::new(); - child - .stdout - .as_mut() - .unwrap() - .read_to_string(&mut out) - .await - .unwrap(); - info!(logger, "child stdout: {}", out.as_str()); + if let Some(stdout) = child.stdout.as_mut() { + let mut out = String::new(); + match stdout.read_to_string(&mut out).await { + Ok(_) => { + info!(logger, "child stdout: {}", out.as_str()); + } + Err(e) => { + info!(logger, "read from child stdout failed: {:?}", e); + } + } + } let mut err = String::new(); - child - .stderr - .as_mut() - .unwrap() - .read_to_string(&mut err) - .await - .unwrap(); - info!(logger, "child stderr: {}", err.as_str()); + if let Some(stderr) = child.stderr.as_mut() { + match stderr.read_to_string(&mut err).await { + Ok(_) => { + info!(logger, "child stderr: {}", err.as_str()); + } + Err(e) => { + info!(logger, "read from child stderr failed: {:?}", e); + } + } + } match child.wait().await { Ok(exit) => { From 948a2b099c6f079688df372cca6005f12c032839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Tue, 15 Feb 2022 15:06:51 +0100 Subject: [PATCH 26/47] tools: clh: Ensure the download binary is executable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're downloading the released cloud-hypervisor binary from GitHub, but we should also ensure we set the binary as executable. Signed-off-by: Fabiano Fidêncio --- .../packaging/static-build/cloud-hypervisor/build-static-clh.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh b/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh index 8569ac87c..61a0824eb 100755 --- a/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh +++ b/tools/packaging/static-build/cloud-hypervisor/build-static-clh.sh @@ -41,6 +41,7 @@ pull_clh_released_binary() { curl --fail -L ${cloud_hypervisor_binary} -o cloud-hypervisor-static || return 1 mkdir -p cloud-hypervisor mv -f cloud-hypervisor-static cloud-hypervisor/cloud-hypervisor + chmod +x cloud_hypervisor/cloud-hypervisor } build_clh_from_source() { From 7df677c01e8ce8ed206eb51e67695c03a9e6fa9b Mon Sep 17 00:00:00 2001 From: bin Date: Thu, 23 Dec 2021 13:26:40 +0800 Subject: [PATCH 27/47] runtime: Update calculateSandboxMemory to include Hugepages Limit Support hugepages and port from: https://github.com/kata-containers/runtime/pull/3109/commits/96dbb2e8f09ba849e43748afcdc26c8e039014b1 Fixes: #3342 Signed-off-by: James O. D. Hunt Signed-off-by: Pradipta Banerjee Signed-off-by: bin --- src/runtime/virtcontainers/sandbox.go | 25 +++++++++--- src/runtime/virtcontainers/sandbox_test.go | 47 ++++++++++++++++++++-- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/src/runtime/virtcontainers/sandbox.go b/src/runtime/virtcontainers/sandbox.go index 8baccb185..623ccb8dc 100644 --- a/src/runtime/virtcontainers/sandbox.go +++ b/src/runtime/virtcontainers/sandbox.go @@ -1942,11 +1942,13 @@ func (s *Sandbox) updateResources(ctx context.Context) error { sandboxVCPUs += s.hypervisor.HypervisorConfig().NumVCPUs sandboxMemoryByte, sandboxneedPodSwap, sandboxSwapByte := s.calculateSandboxMemory() + // Add default / rsvd memory for sandbox. - hypervisorMemoryByte := int64(s.hypervisor.HypervisorConfig().MemorySize) << utils.MibToBytesShift + hypervisorMemoryByteI64 := int64(s.hypervisor.HypervisorConfig().MemorySize) << utils.MibToBytesShift + hypervisorMemoryByte := uint64(hypervisorMemoryByteI64) sandboxMemoryByte += hypervisorMemoryByte if sandboxneedPodSwap { - sandboxSwapByte += hypervisorMemoryByte + sandboxSwapByte += hypervisorMemoryByteI64 } s.Logger().WithField("sandboxMemoryByte", sandboxMemoryByte).WithField("sandboxneedPodSwap", sandboxneedPodSwap).WithField("sandboxSwapByte", sandboxSwapByte).Debugf("updateResources: after calculateSandboxMemory") @@ -1978,7 +1980,8 @@ func (s *Sandbox) updateResources(ctx context.Context) error { // Update Memory s.Logger().WithField("memory-sandbox-size-byte", sandboxMemoryByte).Debugf("Request to hypervisor to update memory") - newMemory, updatedMemoryDevice, err := s.hypervisor.ResizeMemory(ctx, uint32(sandboxMemoryByte>>utils.MibToBytesShift), s.state.GuestMemoryBlockSizeMB, s.state.GuestMemoryHotplugProbe) + newMemoryMB := uint32(sandboxMemoryByte >> utils.MibToBytesShift) + newMemory, updatedMemoryDevice, err := s.hypervisor.ResizeMemory(ctx, newMemoryMB, s.state.GuestMemoryBlockSizeMB, s.state.GuestMemoryHotplugProbe) if err != nil { if err == noGuestMemHotplugErr { s.Logger().Warnf("%s, memory specifications cannot be guaranteed", err) @@ -2001,8 +2004,8 @@ func (s *Sandbox) updateResources(ctx context.Context) error { return nil } -func (s *Sandbox) calculateSandboxMemory() (int64, bool, int64) { - memorySandbox := int64(0) +func (s *Sandbox) calculateSandboxMemory() (uint64, bool, int64) { + memorySandbox := uint64(0) needPodSwap := false swapSandbox := int64(0) for _, c := range s.config.Containers { @@ -2016,8 +2019,17 @@ func (s *Sandbox) calculateSandboxMemory() (int64, bool, int64) { currentLimit := int64(0) if m.Limit != nil && *m.Limit > 0 { currentLimit = *m.Limit - memorySandbox += currentLimit + memorySandbox += uint64(currentLimit) + s.Logger().WithField("memory limit", memorySandbox).Info("Memory Sandbox + Memory Limit ") } + + // Add hugepages memory + // HugepageLimit is uint64 - https://github.com/opencontainers/runtime-spec/blob/master/specs-go/config.go#L242 + for _, l := range c.Resources.HugepageLimits { + memorySandbox += l.Limit + } + + // Add swap if s.config.HypervisorConfig.GuestSwap && m.Swappiness != nil && *m.Swappiness > 0 { currentSwap := int64(0) if m.Swap != nil { @@ -2035,6 +2047,7 @@ func (s *Sandbox) calculateSandboxMemory() (int64, bool, int64) { } } } + return memorySandbox, needPodSwap, swapSandbox } diff --git a/src/runtime/virtcontainers/sandbox_test.go b/src/runtime/virtcontainers/sandbox_test.go index ca02210cd..eb3314857 100644 --- a/src/runtime/virtcontainers/sandbox_test.go +++ b/src/runtime/virtcontainers/sandbox_test.go @@ -152,13 +152,14 @@ func TestCalculateSandboxMem(t *testing.T) { sandbox.config = &SandboxConfig{} unconstrained := newTestContainerConfigNoop("cont-00001") constrained := newTestContainerConfigNoop("cont-00001") - limit := int64(4000) - constrained.Resources.Memory = &specs.LinuxMemory{Limit: &limit} + mlimit := int64(4000) + limit := uint64(4000) + constrained.Resources.Memory = &specs.LinuxMemory{Limit: &mlimit} tests := []struct { name string containers []ContainerConfig - want int64 + want uint64 }{ {"1-unconstrained", []ContainerConfig{unconstrained}, 0}, {"2-unconstrained", []ContainerConfig{unconstrained, unconstrained}, 0}, @@ -187,7 +188,7 @@ func TestCalculateSandboxMemHandlesNegativeLimits(t *testing.T) { sandbox.config.Containers = []ContainerConfig{container} mem, needSwap, swap := sandbox.calculateSandboxMemory() - assert.Equal(t, mem, int64(0)) + assert.Equal(t, mem, uint64(0)) assert.Equal(t, needSwap, false) assert.Equal(t, swap, int64(0)) } @@ -1639,3 +1640,41 @@ func TestGetSandboxCpuSet(t *testing.T) { }) } } + +func TestSandboxHugepageLimit(t *testing.T) { + contConfig1 := newTestContainerConfigNoop("cont-00001") + contConfig2 := newTestContainerConfigNoop("cont-00002") + limit := int64(4000) + contConfig1.Resources.Memory = &specs.LinuxMemory{Limit: &limit} + contConfig2.Resources.Memory = &specs.LinuxMemory{Limit: &limit} + hConfig := newHypervisorConfig(nil, nil) + + defer cleanUp() + // create a sandbox + s, err := testCreateSandbox(t, + testSandboxID, + MockHypervisor, + hConfig, + NetworkConfig{}, + []ContainerConfig{contConfig1, contConfig2}, + nil) + + assert.NoError(t, err) + + hugepageLimits := []specs.LinuxHugepageLimit{ + { + Pagesize: "1GB", + Limit: 322122547, + }, + { + Pagesize: "2MB", + Limit: 134217728, + }, + } + + for i := range s.config.Containers { + s.config.Containers[i].Resources.HugepageLimits = hugepageLimits + } + err = s.updateResources(context.Background()) + assert.NoError(t, err) +} From 81a8baa5e596d2ce99cbeeee418798a62734a11a Mon Sep 17 00:00:00 2001 From: bin Date: Thu, 23 Dec 2021 14:02:11 +0800 Subject: [PATCH 28/47] runtime: add hugepages support Add hugepages support, port from: https://github.com/kata-containers/runtime/pull/3109/commits/b486387cbad09428202154ed7bf2acfdda88f388 Signed-off-by: Pradipta Banerjee Signed-off-by: bin --- src/runtime/go.mod | 1 + src/runtime/vendor/modules.txt | 1 + src/runtime/virtcontainers/container.go | 2 +- .../virtcontainers/device/config/pmem.go | 2 +- src/runtime/virtcontainers/kata_agent.go | 84 +++++++++++++++++++ src/runtime/virtcontainers/kata_agent_test.go | 55 ++++++++++++ src/runtime/virtcontainers/mount.go | 4 +- .../virtcontainers/utils/utils_linux.go | 8 +- .../virtcontainers/utils/utils_linux_test.go | 22 ++++- 9 files changed, 168 insertions(+), 11 deletions(-) diff --git a/src/runtime/go.mod b/src/runtime/go.mod index 07d393227..9a485b28a 100644 --- a/src/runtime/go.mod +++ b/src/runtime/go.mod @@ -17,6 +17,7 @@ require ( github.com/containernetworking/plugins v1.0.1 github.com/coreos/go-systemd/v22 v22.3.2 github.com/cri-o/cri-o v1.0.0-rc2.0.20170928185954-3394b3b2d6af + github.com/docker/go-units v0.4.0 github.com/fsnotify/fsnotify v1.4.9 github.com/go-ini/ini v1.28.2 github.com/go-openapi/errors v0.18.0 diff --git a/src/runtime/vendor/modules.txt b/src/runtime/vendor/modules.txt index f663a8033..cde9b39f4 100644 --- a/src/runtime/vendor/modules.txt +++ b/src/runtime/vendor/modules.txt @@ -134,6 +134,7 @@ github.com/davecgh/go-spew/spew # github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c github.com/docker/go-events # github.com/docker/go-units v0.4.0 +## explicit github.com/docker/go-units # github.com/fsnotify/fsnotify v1.4.9 ## explicit diff --git a/src/runtime/virtcontainers/container.go b/src/runtime/virtcontainers/container.go index 5c13b0846..87a2a23a5 100644 --- a/src/runtime/virtcontainers/container.go +++ b/src/runtime/virtcontainers/container.go @@ -1315,7 +1315,7 @@ func (c *Container) hotplugDrive(ctx context.Context) error { c.rootfsSuffix = "" } // If device mapper device, then fetch the full path of the device - devicePath, fsType, err = utils.GetDevicePathAndFsType(dev.mountPoint) + devicePath, fsType, _, err = utils.GetDevicePathAndFsTypeOptions(dev.mountPoint) if err != nil { return err } diff --git a/src/runtime/virtcontainers/device/config/pmem.go b/src/runtime/virtcontainers/device/config/pmem.go index 44ea63f72..33ce4fdff 100644 --- a/src/runtime/virtcontainers/device/config/pmem.go +++ b/src/runtime/virtcontainers/device/config/pmem.go @@ -75,7 +75,7 @@ func PmemDeviceInfo(source, destination string) (*DeviceInfo, error) { return nil, fmt.Errorf("backing file %v has not PFN signature", device.HostPath) } - _, fstype, err := utils.GetDevicePathAndFsType(source) + _, fstype, _, err := utils.GetDevicePathAndFsTypeOptions(source) if err != nil { pmemLog.WithError(err).WithField("mount-point", source).Warn("failed to get fstype: using ext4") fstype = "ext4" diff --git a/src/runtime/virtcontainers/kata_agent.go b/src/runtime/virtcontainers/kata_agent.go index dc7b99817..822e84f97 100644 --- a/src/runtime/virtcontainers/kata_agent.go +++ b/src/runtime/virtcontainers/kata_agent.go @@ -17,6 +17,7 @@ import ( "syscall" "time" + "github.com/docker/go-units" "github.com/kata-containers/kata-containers/src/runtime/pkg/katautils/katatrace" "github.com/kata-containers/kata-containers/src/runtime/pkg/uuid" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/api" @@ -30,6 +31,7 @@ import ( "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/rootless" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types" vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types" + "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils" "github.com/gogo/protobuf/proto" "github.com/opencontainers/runtime-spec/specs-go" @@ -156,6 +158,16 @@ var kataHostSharedDir = func() string { return defaultKataHostSharedDir } +func getPagesizeFromOpt(fsOpts []string) string { + // example options array: "rw", "relatime", "seclabel", "pagesize=2M" + for _, opt := range fsOpts { + if strings.HasPrefix(opt, "pagesize=") { + return strings.TrimPrefix(opt, "pagesize=") + } + } + return "" +} + // Shared path handling: // 1. create three directories for each sandbox: // -. /run/kata-containers/shared/sandboxes/$sbx_id/mounts/, a directory to hold all host/guest shared mounts @@ -1450,6 +1462,13 @@ func (k *kataAgent) createContainer(ctx context.Context, sandbox *Sandbox, c *Co ctrStorages = append(ctrStorages, epheStorages...) + k.Logger().WithField("ociSpec Hugepage Resources", ociSpec.Linux.Resources.HugepageLimits).Debug("ociSpec HugepageLimit") + hugepages, err := k.handleHugepages(ociSpec.Mounts, ociSpec.Linux.Resources.HugepageLimits) + if err != nil { + return nil, err + } + ctrStorages = append(ctrStorages, hugepages...) + localStorages, err := k.handleLocalStorage(ociSpec.Mounts, sandbox.id, c.rootfsSuffix) if err != nil { return nil, err @@ -1530,6 +1549,71 @@ func buildProcessFromExecID(token string) (*Process, error) { }, nil } +// handleHugePages handles hugepages storage by +// creating a Storage from corresponding source of the mount point +func (k *kataAgent) handleHugepages(mounts []specs.Mount, hugepageLimits []specs.LinuxHugepageLimit) ([]*grpc.Storage, error) { + //Map to hold the total memory of each type of hugepages + optionsMap := make(map[int64]string) + + for _, hp := range hugepageLimits { + if hp.Limit != 0 { + k.Logger().WithFields(logrus.Fields{ + "Pagesize": hp.Pagesize, + "Limit": hp.Limit, + }).Info("hugepage request") + //example Pagesize 2MB, 1GB etc. The Limit are in Bytes + pageSize, err := units.RAMInBytes(hp.Pagesize) + if err != nil { + k.Logger().Error("Unable to convert pagesize to bytes") + return nil, err + } + totalHpSizeStr := strconv.FormatUint(hp.Limit, 10) + optionsMap[pageSize] = totalHpSizeStr + } + } + + var hugepages []*grpc.Storage + for idx, mnt := range mounts { + if mnt.Type != KataLocalDevType { + continue + } + //HugePages mount Type is Local + if _, fsType, fsOptions, _ := utils.GetDevicePathAndFsTypeOptions(mnt.Source); fsType == "hugetlbfs" { + k.Logger().WithField("fsOptions", fsOptions).Debug("hugepage mount options") + //Find the pagesize from the mountpoint options + pagesizeOpt := getPagesizeFromOpt(fsOptions) + if pagesizeOpt == "" { + return nil, fmt.Errorf("No pagesize option found in filesystem mount options") + } + pageSize, err := units.RAMInBytes(pagesizeOpt) + if err != nil { + k.Logger().Error("Unable to convert pagesize from fs mount options to bytes") + return nil, err + } + //Create mount option string + options := fmt.Sprintf("pagesize=%s,size=%s", strconv.FormatInt(pageSize, 10), optionsMap[pageSize]) + k.Logger().WithField("Hugepage options string", options).Debug("hugepage mount options") + // Set the mount source path to a path that resides inside the VM + mounts[idx].Source = filepath.Join(ephemeralPath(), filepath.Base(mnt.Source)) + // Set the mount type to "bind" + mounts[idx].Type = "bind" + + // Create a storage struct so that kata agent is able to create + // hugetlbfs backed volume inside the VM + hugepage := &grpc.Storage{ + Driver: KataEphemeralDevType, + Source: "nodev", + Fstype: "hugetlbfs", + MountPoint: mounts[idx].Source, + Options: []string{options}, + } + hugepages = append(hugepages, hugepage) + } + + } + return hugepages, nil +} + // handleEphemeralStorage handles ephemeral storages by // creating a Storage from corresponding source of the mount point func (k *kataAgent) handleEphemeralStorage(mounts []specs.Mount) ([]*grpc.Storage, error) { diff --git a/src/runtime/virtcontainers/kata_agent_test.go b/src/runtime/virtcontainers/kata_agent_test.go index fb596da12..6475e8b06 100644 --- a/src/runtime/virtcontainers/kata_agent_test.go +++ b/src/runtime/virtcontainers/kata_agent_test.go @@ -9,6 +9,7 @@ import ( "bufio" "context" "fmt" + "io/ioutil" "os" "path" "path/filepath" @@ -1230,3 +1231,57 @@ func TestSandboxBindMount(t *testing.T) { assert.True(os.IsNotExist(err)) } + +func TestHandleHugepages(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("Test disabled as requires root user") + } + + assert := assert.New(t) + + dir, err := ioutil.TempDir("", "hugepages-test") + assert.Nil(err) + defer os.RemoveAll(dir) + + k := kataAgent{} + var mounts []specs.Mount + var hugepageLimits []specs.LinuxHugepageLimit + + hugepageDirs := [2]string{"hugepages-1Gi", "hugepages-2Mi"} + options := [2]string{"pagesize=1024M", "pagesize=2M"} + + for i := 0; i < 2; i++ { + target := path.Join(dir, hugepageDirs[i]) + err := os.MkdirAll(target, 0777) + assert.NoError(err, "Unable to create dir %s", target) + + err = syscall.Mount("nodev", target, "hugetlbfs", uintptr(0), options[i]) + assert.NoError(err, "Unable to mount %s", target) + + defer syscall.Unmount(target, 0) + defer os.RemoveAll(target) + mount := specs.Mount{ + Type: KataLocalDevType, + Source: target, + } + mounts = append(mounts, mount) + } + + hugepageLimits = []specs.LinuxHugepageLimit{ + { + Pagesize: "1GB", + Limit: 1073741824, + }, + { + Pagesize: "2MB", + Limit: 134217728, + }, + } + + hugepages, err := k.handleHugepages(mounts, hugepageLimits) + + assert.NoError(err, "Unable to handle hugepages %v", hugepageLimits) + assert.NotNil(hugepages) + assert.Equal(len(hugepages), 2) + +} diff --git a/src/runtime/virtcontainers/mount.go b/src/runtime/virtcontainers/mount.go index b23bd0879..aca557d46 100644 --- a/src/runtime/virtcontainers/mount.go +++ b/src/runtime/virtcontainers/mount.go @@ -470,7 +470,7 @@ func IsEphemeralStorage(path string) bool { return false } - if _, fsType, _ := utils.GetDevicePathAndFsType(path); fsType == "tmpfs" { + if _, fsType, _, _ := utils.GetDevicePathAndFsTypeOptions(path); fsType == "tmpfs" { return true } @@ -485,7 +485,7 @@ func Isk8sHostEmptyDir(path string) bool { return false } - if _, fsType, _ := utils.GetDevicePathAndFsType(path); fsType != "tmpfs" { + if _, fsType, _, _ := utils.GetDevicePathAndFsTypeOptions(path); fsType != "tmpfs" { return true } return false diff --git a/src/runtime/virtcontainers/utils/utils_linux.go b/src/runtime/virtcontainers/utils/utils_linux.go index 90e0d631b..265f10d11 100644 --- a/src/runtime/virtcontainers/utils/utils_linux.go +++ b/src/runtime/virtcontainers/utils/utils_linux.go @@ -96,11 +96,12 @@ const ( procDeviceIndex = iota procPathIndex procTypeIndex + procOptionIndex ) -// GetDevicePathAndFsType gets the device for the mount point and the file system type -// of the mount. -func GetDevicePathAndFsType(mountPoint string) (devicePath, fsType string, err error) { +// GetDevicePathAndFsTypeOptions gets the device for the mount point, the file system type +// and mount options +func GetDevicePathAndFsTypeOptions(mountPoint string) (devicePath, fsType string, fsOptions []string, err error) { if mountPoint == "" { err = fmt.Errorf("Mount point cannot be empty") return @@ -134,6 +135,7 @@ func GetDevicePathAndFsType(mountPoint string) (devicePath, fsType string, err e if mountPoint == fields[procPathIndex] { devicePath = fields[procDeviceIndex] fsType = fields[procTypeIndex] + fsOptions = strings.Split(fields[procOptionIndex], ",") return } } diff --git a/src/runtime/virtcontainers/utils/utils_linux_test.go b/src/runtime/virtcontainers/utils/utils_linux_test.go index c7b2b8793..dbf9fde38 100644 --- a/src/runtime/virtcontainers/utils/utils_linux_test.go +++ b/src/runtime/virtcontainers/utils/utils_linux_test.go @@ -6,7 +6,10 @@ package utils import ( + "bytes" "errors" + "os/exec" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -34,20 +37,31 @@ func TestFindContextID(t *testing.T) { assert.Error(err) } -func TestGetDevicePathAndFsTypeEmptyMount(t *testing.T) { +func TestGetDevicePathAndFsTypeOptionsEmptyMount(t *testing.T) { assert := assert.New(t) - _, _, err := GetDevicePathAndFsType("") + _, _, _, err := GetDevicePathAndFsTypeOptions("") assert.Error(err) } -func TestGetDevicePathAndFsTypeSuccessful(t *testing.T) { +func TestGetDevicePathAndFsTypeOptionsSuccessful(t *testing.T) { assert := assert.New(t) - path, fstype, err := GetDevicePathAndFsType("/proc") + cmdStr := "grep ^proc /proc/mounts" + cmd := exec.Command("sh", "-c", cmdStr) + output, err := cmd.Output() + assert.NoError(err) + + data := bytes.Split(output, []byte(" ")) + fstypeOut := string(data[2]) + optsOut := strings.Split(string(data[3]), ",") + + path, fstype, fsOptions, err := GetDevicePathAndFsTypeOptions("/proc") assert.NoError(err) assert.Equal(path, "proc") assert.Equal(fstype, "proc") + assert.Equal(fstype, fstypeOut) + assert.Equal(fsOptions, optsOut) } func TestIsAPVFIOMediatedDeviceFalse(t *testing.T) { From 36c3fc12ce6813763538ada66334a3d8a28845f0 Mon Sep 17 00:00:00 2001 From: bin Date: Thu, 23 Dec 2021 16:50:09 +0800 Subject: [PATCH 29/47] agent: support hugepages for containers Mount hugepage directories and configure the requested number of hugepages dynamically by writing to sysfs files Port from: https://github.com/kata-containers/agent/pull/872/commits/78b307b5bd299517a959fab8c0773992294c8e7c Fixes: #3342 Signed-off-by: Pradipta Banerjee Signed-off-by: bin --- src/agent/src/device.rs | 1 + src/agent/src/mount.rs | 161 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/src/agent/src/device.rs b/src/agent/src/device.rs index 0f3eca513..7d89d0124 100644 --- a/src/agent/src/device.rs +++ b/src/agent/src/device.rs @@ -52,6 +52,7 @@ pub const DRIVER_VFIO_GK_TYPE: &str = "vfio-gk"; // container as a VFIO device node pub const DRIVER_VFIO_TYPE: &str = "vfio"; pub const DRIVER_OVERLAYFS_TYPE: &str = "overlayfs"; +pub const FS_TYPE_HUGETLB: &str = "hugetlbfs"; #[instrument] pub fn online_device(path: &str) -> Result<()> { diff --git a/src/agent/src/mount.rs b/src/agent/src/mount.rs index 9618ae94c..d7dbc08ef 100644 --- a/src/agent/src/mount.rs +++ b/src/agent/src/mount.rs @@ -5,8 +5,8 @@ use std::collections::HashMap; use std::fs; -use std::fs::File; -use std::io::{BufRead, BufReader}; +use std::fs::{File, OpenOptions}; +use std::io::{BufRead, BufReader, Write}; use std::iter; use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::path::Path; @@ -24,7 +24,7 @@ use crate::device::{ get_scsi_device_name, get_virtio_blk_pci_device_name, online_device, wait_for_pmem_device, DRIVER_9P_TYPE, DRIVER_BLK_CCW_TYPE, DRIVER_BLK_TYPE, DRIVER_EPHEMERAL_TYPE, DRIVER_LOCAL_TYPE, DRIVER_MMIO_BLK_TYPE, DRIVER_NVDIMM_TYPE, DRIVER_OVERLAYFS_TYPE, DRIVER_SCSI_TYPE, - DRIVER_VIRTIOFS_TYPE, DRIVER_WATCHABLE_BIND_TYPE, + DRIVER_VIRTIOFS_TYPE, DRIVER_WATCHABLE_BIND_TYPE, FS_TYPE_HUGETLB, }; use crate::linux_abi::*; use crate::pci; @@ -37,7 +37,7 @@ use slog::Logger; use tracing::instrument; pub const TYPE_ROOTFS: &str = "rootfs"; - +const SYS_FS_HUGEPAGES_PREFIX: &str = "/sys/kernel/mm/hugepages"; pub const MOUNT_GUEST_TAG: &str = "kataShared"; // Allocating an FSGroup that owns the pod's volumes @@ -200,6 +200,12 @@ async fn ephemeral_storage_handler( return Ok("".to_string()); } + // hugetlbfs + if storage.fstype == FS_TYPE_HUGETLB { + return handle_hugetlbfs_storage(logger, storage).await; + } + + // normal ephemeral storage fs::create_dir_all(Path::new(&storage.mount_point))?; // By now we only support one option field: "fsGroup" which @@ -299,6 +305,97 @@ async fn virtio9p_storage_handler( common_storage_handler(logger, storage) } +#[instrument] +async fn handle_hugetlbfs_storage(logger: &Logger, storage: &Storage) -> Result { + info!(logger, "handle hugetlbfs storage"); + // Allocate hugepages before mount + // /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages + // /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages + // options eg "pagesize=2097152,size=524288000"(2M, 500M) + allocate_hugepages(logger, &storage.options.to_vec()).context("allocate hugepages")?; + + common_storage_handler(logger, storage)?; + + // hugetlbfs return empty string as ephemeral_storage_handler do. + // this is a sandbox level storage, but not a container-level mount. + Ok("".to_string()) +} + +// Allocate hugepages by writing to sysfs +fn allocate_hugepages(logger: &Logger, options: &[String]) -> Result<()> { + info!(logger, "mounting hugePages storage options: {:?}", options); + + let (pagesize, size) = get_pagesize_and_size_from_option(options) + .context(format!("parse mount options: {:?}", &options))?; + + info!( + logger, + "allocate hugepages. pageSize: {}, size: {}", pagesize, size + ); + + // sysfs entry is always of the form hugepages-${pagesize}kB + // Ref: https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt + let path = Path::new(SYS_FS_HUGEPAGES_PREFIX).join(format!("hugepages-{}kB", pagesize / 1024)); + + if !path.exists() { + fs::create_dir_all(&path).context("create hugepages-size directory")?; + } + + // write numpages to nr_hugepages file. + let path = path.join("nr_hugepages"); + let numpages = format!("{}", size / pagesize); + info!(logger, "write {} pages to {:?}", &numpages, &path); + + let mut file = OpenOptions::new() + .write(true) + .create(true) + .open(&path) + .context(format!("open nr_hugepages directory {:?}", &path))?; + + file.write_all(numpages.as_bytes()) + .context(format!("write nr_hugepages failed: {:?}", &path))?; + + Ok(()) +} + +// Parse filesystem options string to retrieve hugepage details +// options eg "pagesize=2048,size=107374182" +fn get_pagesize_and_size_from_option(options: &[String]) -> Result<(u64, u64)> { + let mut pagesize_str: Option<&str> = None; + let mut size_str: Option<&str> = None; + + for option in options { + let vars: Vec<&str> = option.trim().split(',').collect(); + + for var in vars { + if let Some(stripped) = var.strip_prefix("pagesize=") { + pagesize_str = Some(stripped); + } else if let Some(stripped) = var.strip_prefix("size=") { + size_str = Some(stripped); + } + + if pagesize_str.is_some() && size_str.is_some() { + break; + } + } + } + + if pagesize_str.is_none() || size_str.is_none() { + return Err(anyhow!("no pagesize/size options found")); + } + + let pagesize = pagesize_str + .unwrap() + .parse::() + .context(format!("parse pagesize: {:?}", &pagesize_str))?; + let size = size_str + .unwrap() + .parse::() + .context(format!("parse size: {:?}", &pagesize_str))?; + + Ok((pagesize, size)) +} + // virtiommio_blk_storage_handler handles the storage for mmio blk driver. #[instrument] async fn virtiommio_blk_storage_handler( @@ -1392,4 +1489,60 @@ mod tests { assert!(testfile.is_file()); } + + #[test] + fn test_get_pagesize_and_size_from_option() { + let expected_pagesize = 2048; + let expected_size = 107374182; + let expected = (expected_pagesize, expected_size); + + let data = vec![ + // (input, expected, is_ok) + ("size-1=107374182,pagesize-1=2048", expected, false), + ("size-1=107374182,pagesize=2048", expected, false), + ("size=107374182,pagesize-1=2048", expected, false), + ("size=107374182,pagesize=abc", expected, false), + ("size=abc,pagesize=2048", expected, false), + ("size=,pagesize=2048", expected, false), + ("size=107374182,pagesize=", expected, false), + ("size=107374182,pagesize=2048", expected, true), + ("pagesize=2048,size=107374182", expected, true), + ("foo=bar,pagesize=2048,size=107374182", expected, true), + ( + "foo=bar,pagesize=2048,foo1=bar1,size=107374182", + expected, + true, + ), + ( + "pagesize=2048,foo1=bar1,foo=bar,size=107374182", + expected, + true, + ), + ( + "foo=bar,pagesize=2048,foo1=bar1,size=107374182,foo2=bar2", + expected, + true, + ), + ( + "foo=bar,size=107374182,foo1=bar1,pagesize=2048", + expected, + true, + ), + ]; + + for case in data { + let input = case.0; + let r = get_pagesize_and_size_from_option(&[input.to_string()]); + + let is_ok = case.2; + if is_ok { + let expected = case.1; + let (pagesize, size) = r.unwrap(); + assert_eq!(expected.0, pagesize); + assert_eq!(expected.1, size); + } else { + assert!(r.is_err()); + } + } + } } From 9818cf71960c889425a6d822dd9be98f03adf4fe Mon Sep 17 00:00:00 2001 From: "James O. D. Hunt" Date: Wed, 26 Jan 2022 10:44:04 +0000 Subject: [PATCH 30/47] docs: Improve top-level and runtime README Various improvements to the top-level README file: - Moved the following sections from the runtime's README to the top-level README: - License - Platform support / Hardware requirements - Added the following sections to the top-level README: - Configuration - Hypervisors - Improved formatting of the Documentation section in the top-level README. - Removed some unused named links from the top-level README. Also improvements to the runtime README: - Removed confusing mention of the old 1.x runtime name. - Clarify the binary name for the 2.x runtime and the utility program. > **Note:** > > We cannot currently link to the AMD website as that site's > configuration causes the CI static checks to fail. See > https://github.com/kata-containers/tests/issues/4401 Fixes: #3557. Signed-off-by: James O. D. Hunt --- README.md | 73 ++++++++++++++++++++++---- src/runtime/README.md | 117 ++++++++++++++++++------------------------ 2 files changed, 114 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index e93c5f740..0d8c5d2b8 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,73 @@ standard implementation of lightweight Virtual Machines (VMs) that feel and perform like containers, but provide the workload isolation and security advantages of VMs. +## License + +The code is licensed under the Apache 2.0 license. +See [the license file](LICENSE) for further details. + +## Platform support + +Kata Containers currently runs on 64-bit systems supporting the following +technologies: + +| Architecture | Virtualization technology | +|-|-| +| `x86_64`, `amd64` | [Intel](https://www.intel.com) VT-x, AMD SVM | +| `aarch64` ("`arm64`")| [ARM](https://www.arm.com) Hyp | +| `ppc64le` | [IBM](https://www.ibm.com) Power | +| `s390x` | [IBM](https://www.ibm.com) Z & LinuxONE SIE | + +### Hardware requirements + +The [Kata Containers runtime](src/runtime) provides a command to +determine if your host system is capable of running and creating a +Kata Container: + +```bash +$ kata-runtime check +``` + +> **Notes:** +> +> - This command runs a number of checks including connecting to the +> network to determine if a newer release of Kata Containers is +> available on GitHub. If you do not wish this to check to run, add +> the `--no-network-checks` option. +> +> - By default, only a brief success / failure message is printed. +> If more details are needed, the `--verbose` flag can be used to display the +> list of all the checks performed. +> +> - If the command is run as the `root` user additional checks are +> run (including checking if another incompatible hypervisor is running). +> When running as `root`, network checks are automatically disabled. + ## Getting started See the [installation documentation](docs/install). ## Documentation -See the [official documentation](docs) -(including [installation guides](docs/install), -[the developer guide](docs/Developer-Guide.md), -[design documents](docs/design) and more). +See the [official documentation](docs) including: + +- [Installation guides](docs/install) +- [Developer guide](docs/Developer-Guide.md) +- [Design documents](docs/design) + - [Architecture overview](docs/design/architecture) + +## Configuration + +Kata Containers uses a single +[configuration file](src/runtime/README.md#configuration) +which contains a number of sections for various parts of the Kata +Containers system including the [runtime](src/runtime), the +[agent](src/agent) and the [hypervisor](#hypervisors). + +## Hypervisors + +See the [hypervisors document](docs/hypervisors.md) and the +[Hypervisor specific configuration details](src/runtime/README.md#hypervisor-specific-configuration). ## Community @@ -48,6 +105,8 @@ Please raise an issue ## Developers +See the [developer guide](docs/Developer-Guide.md). + ### Components ### Main components @@ -84,8 +143,4 @@ the [components](#components) section for further details. ## Glossary of Terms -See the [glossary of terms](Glossary.md) related to Kata Containers. ---- - -[kernel]: https://www.kernel.org -[github-katacontainers.io]: https://github.com/kata-containers/www.katacontainers.io +See the [glossary of terms](https://github.com/kata-containers/kata-containers/wiki/Glossary) related to Kata Containers. diff --git a/src/runtime/README.md b/src/runtime/README.md index 217cd2d44..fcffc238a 100644 --- a/src/runtime/README.md +++ b/src/runtime/README.md @@ -2,19 +2,25 @@ # Runtime -This repository contains the runtime for the -[Kata Containers](https://github.com/kata-containers) project. +## Binary names + +This repository contains the following components: + +| Binary name | Description | +|-|-| +| `containerd-shim-kata-v2` | The [shimv2 runtime](../../docs/design/architecture/README.md#runtime) | +| `kata-runtime` | [utility program](../../docs/design/architecture/README.md#utility-program) | For details of the other Kata Containers repositories, see the [repository summary](https://github.com/kata-containers/kata-containers). ## Introduction -`kata-runtime`, referred to as "the runtime", is the Command-Line Interface -(CLI) part of the Kata Containers runtime component. It leverages the +The `containerd-shim-kata-v2` [binary](#binary-names) is the Kata +Containers [shimv2](../../docs/design/architecture/README.md#shim-v2-architecture) runtime. It leverages the [virtcontainers](virtcontainers) package to provide a high-performance standards-compliant runtime that creates -hardware-virtualized [Linux](https://www.kernel.org/) containers running on Linux hosts. +hardware-virtualized [Linux](https://www.kernel.org) containers running on Linux hosts. The runtime is [OCI](https://github.com/opencontainers/runtime-spec)-compatible, @@ -23,39 +29,6 @@ The runtime is allowing it to work seamlessly with both Docker and Kubernetes respectively. -## License - -The code is licensed under an Apache 2.0 license. -See [the license file](../../LICENSE) for further details. - -## Platform support - -Kata Containers currently works on systems supporting the following -technologies: - -- [Intel](https://www.intel.com) VT-x technology. -- [ARM](https://www.arm.com) Hyp mode (virtualization extension). -- [IBM](https://www.ibm.com) Power Systems. -- [IBM](https://www.ibm.com) Z mainframes. -### Hardware requirements - -The runtime has a built-in command to determine if your host system is capable -of running and creating a Kata Container: - -```bash -$ kata-runtime check -``` - -> **Note:** -> -> - By default, only a brief success / failure message is printed. -> If more details are needed, the `--verbose` flag can be used to display the -> list of all the checks performed. -> -> - `root` permission is needed to check if the system is capable of running -> Kata containers. In this case, additional checks are performed (e.g., if another -> incompatible hypervisor is running). - ## Download and install [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/kata-containers) @@ -63,11 +36,6 @@ $ kata-runtime check See the [installation guides](../../docs/install/README.md) available for various operating systems. -## Quick start for developers - -See the -[developer guide](../../docs/Developer-Guide.md). - ## Architecture overview See the [architecture overview](../../docs/design/architecture) @@ -76,7 +44,11 @@ for details on the Kata Containers design. ## Configuration The runtime uses a TOML format configuration file called `configuration.toml`. -The file contains comments explaining all options. +The file is divided into sections for settings related to various +parts of the system including the runtime itself, the [agent](../agent) and +the [hypervisor](#hypervisor-specific-configuration). + +Each option has a comment explaining its use. > **Note:** > @@ -84,6 +56,36 @@ The file contains comments explaining all options. > You may need to modify this file to optimise or tailor your system, or if you have > specific requirements. +### Configuration file location + +#### Runtime configuration file location + +The shimv2 runtime looks for its configuration in the following places (in order): + +- The `io.data containers.config.config_path` annotation specified + in the OCI configuration file (`config.json` file) used to create the pod sandbox. + +- The containerd + [shimv2](/docs/design/architecture/README.md#shim-v2-architecture) + options passed to the runtime. + +- The value of the `KATA_CONF_FILE` environment variable. + +- The [default configuration paths](#stateless-systems). + +#### Utility program configuration file location + +The `kata-runtime` utility program looks for its configuration in the +following locations (in order): + +- The path specified by the `--config` command-line option. + +- The value of the `KATA_CONF_FILE` environment variable. + +- The [default configuration paths](#stateless-systems). + +> **Note:** For both binaries, the first path that exists will be used. + ### Hypervisor specific configuration Kata Containers supports multiple hypervisors so your `configuration.toml` @@ -108,13 +110,6 @@ runtime attempts to load. The first path that exists will be used: $ kata-runtime --show-default-config-paths ``` -Aside from the built-in locations, it is possible to specify the path to a -custom configuration file using the `--config` option: - -```bash -$ kata-runtime --config=/some/where/configuration.toml ... -``` - The runtime will log the full path to the configuration file it is using. See the [logging](#logging) section for further details. @@ -132,27 +127,15 @@ components, see the documentation for the [`kata-log-parser`](https://github.com/kata-containers/tests/tree/main/cmd/log-parser) tool. -For runtime logs, see the following sections for the CRI-O and containerd shimv2 based runtimes. - -### Kata OCI - -The Kata OCI runtime (including when used with CRI-O), provides `--log=` and `--log-format=` options. -However, the runtime also always logs to the system log (`syslog` or `journald`). - -To view runtime log output: - -```bash -$ sudo journalctl -t kata-runtime -``` - ### Kata containerd shimv2 The Kata containerd shimv2 runtime logs through `containerd`, and its logs will be sent to wherever the `containerd` logs are directed. However, the -shimv2 runtime also always logs to the system log (`syslog` or `journald`) under the -identifier name of `kata`. +shimv2 runtime also always logs to the system log (`syslog` or `journald`) using the `kata` identifier. -To view the `shimv2` runtime log output: +> **Note:** Kata logging [requires containerd debug to be enabled](../../docs/Developer-Guide.md#enabling-full-containerd-debug). + +To view the `shimv2` runtime logs: ```bash $ sudo journalctl -t kata From e6060cb7c0e4cc7adc1fdaacc1226e86169aa4de Mon Sep 17 00:00:00 2001 From: Carlos Venegas Date: Mon, 31 Jan 2022 19:38:14 +0000 Subject: [PATCH 31/47] versions: Linux 5.15.x Upgrade to new Linux kernel LTS version. Fixes: #3576 Signed-off-by: Carlos Venegas --- tools/packaging/kernel/configs/fragments/whitelist.conf | 3 +++ tools/packaging/kernel/patches/5.15.x/no_patches.txt | 1 + versions.yaml | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 tools/packaging/kernel/patches/5.15.x/no_patches.txt diff --git a/tools/packaging/kernel/configs/fragments/whitelist.conf b/tools/packaging/kernel/configs/fragments/whitelist.conf index 78c41613e..74d6a2ce4 100644 --- a/tools/packaging/kernel/configs/fragments/whitelist.conf +++ b/tools/packaging/kernel/configs/fragments/whitelist.conf @@ -12,3 +12,6 @@ CONFIG_CRYPTO_DEV_SP_PSP CONFIG_CRYPTO_DEV_CCP CONFIG_HAVE_NET_DSA CONFIG_NF_LOG_COMMON +CONFIG_MANDATORY_FILE_LOCKING +CONFIG_ARM64_UAO +CONFIG_VFIO_MDEV_DEVICE diff --git a/tools/packaging/kernel/patches/5.15.x/no_patches.txt b/tools/packaging/kernel/patches/5.15.x/no_patches.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/tools/packaging/kernel/patches/5.15.x/no_patches.txt @@ -0,0 +1 @@ + diff --git a/versions.yaml b/versions.yaml index f8154866c..0f3c23653 100644 --- a/versions.yaml +++ b/versions.yaml @@ -149,7 +149,7 @@ assets: kernel: description: "Linux kernel optimised for virtual machines" url: "https://cdn.kernel.org/pub/linux/kernel/v5.x/" - version: "v5.10.25" + version: "v5.15.23" tdx: description: "Linux kernel that supports TDX" url: "https://github.com/intel/tdx/archive/refs/tags" From 5816c132ec26f9659bb4c760c0e5eea280014b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Wed, 16 Feb 2022 13:58:33 +0100 Subject: [PATCH 32/47] tools: Build cloud-hypervisor with "--features tdx" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now TDx support on Cloud Hypervisor is gated behind a "--features tdx" flag. However, having TDx support enabled should not and does not impact on the general usability of cloud-hypervisor. As sooner than later we'll need kata-deploy binaries to be tested on a CI that's TDx capable, for the confidential containers effort, let's take the bullet and already enable it by default. By the way, touching kata-deploy-binaries.sh as it's ensure the change will be used in the following workflows: * kata-deploy-push * kata-deploy-test * release Fixes: #3688 Signed-off-by: Fabiano Fidêncio --- tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh index b5b1717a9..a9ef4e0b0 100755 --- a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh +++ b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh @@ -130,6 +130,7 @@ install_clh() { cloud_hypervisor_repo="$(yq r $versions_yaml assets.hypervisor.cloud_hypervisor.url)" cloud_hypervisor_version="$(yq r $versions_yaml assets.hypervisor.cloud_hypervisor.version)" + export extra_build_args="--features tdx" info "build static cloud-hypervisor" "${clh_builder}" From a6b40151300c4cef9b4c2af780fa199123290d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Wed, 16 Feb 2022 14:52:25 +0100 Subject: [PATCH 33/47] tools: clh: Remove unused variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now we're getting the info for the Cloud Hypervisor repo and version, but we don't do anything with them, as those are not passed down to the build script. Morever, the build script itself gets the info from exactly the same place when those are not passed, making those redundant. Signed-off-by: Fabiano Fidêncio --- .../kata-deploy/local-build/kata-deploy-binaries.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh index a9ef4e0b0..1864140e1 100755 --- a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh +++ b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh @@ -125,11 +125,6 @@ install_firecracker() { # Install static cloud-hypervisor asset install_clh() { - local cloud_hypervisor_repo - local cloud_hypervisor_version - - cloud_hypervisor_repo="$(yq r $versions_yaml assets.hypervisor.cloud_hypervisor.url)" - cloud_hypervisor_version="$(yq r $versions_yaml assets.hypervisor.cloud_hypervisor.version)" export extra_build_args="--features tdx" info "build static cloud-hypervisor" From 7241d618f1ac90869abebc79a95f8c83b32ff11c Mon Sep 17 00:00:00 2001 From: bin Date: Thu, 17 Feb 2022 14:09:20 +0800 Subject: [PATCH 34/47] versions: add nydus-snapshotter Add nydus-snapshotter to versions.yaml to install nydus-snapshotter from its own releases. Fixes: #3698 Signed-off-by: bin --- versions.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/versions.yaml b/versions.yaml index f8154866c..9fd3846a2 100644 --- a/versions.yaml +++ b/versions.yaml @@ -242,6 +242,11 @@ externals: url: "https://github.com/dragonflyoss/image-service" version: "v1.1.2" + nydus-snapshotter: + description: "Snapshotter for Nydus image acceleration service" + url: "https://github.com/containerd/nydus-snapshotter" + version: "v0.1.0" + languages: description: | Details of programming languages required to build system From 77c29bfd3bf13f8f8c0e28d9f9ad6055bbfe3b59 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 23 Nov 2021 13:57:59 +0100 Subject: [PATCH 35/47] container: Remove VFIO lazy attach handling With the recently added VFIO fixes and support, we should not need that anymore. Fixes #3108 Signed-off-by: Samuel Ortiz --- src/runtime/virtcontainers/container.go | 50 ++------- .../virtcontainers/device/manager/utils.go | 101 ------------------ .../device/manager/utils_test.go | 44 -------- src/runtime/virtcontainers/sandbox_test.go | 4 +- 4 files changed, 8 insertions(+), 191 deletions(-) diff --git a/src/runtime/virtcontainers/container.go b/src/runtime/virtcontainers/container.go index 87a2a23a5..13ec54855 100644 --- a/src/runtime/virtcontainers/container.go +++ b/src/runtime/virtcontainers/container.go @@ -904,38 +904,11 @@ func (c *Container) create(ctx context.Context) (err error) { } } - var ( - machineType = c.sandbox.config.HypervisorConfig.HypervisorMachineType - normalAttachedDevs []ContainerDevice //for q35: normally attached devices - delayAttachedDevs []ContainerDevice //for q35: delay attached devices, for example, large bar space device - ) - // Fix: https://github.com/kata-containers/runtime/issues/2460 - if machineType == QemuQ35 { - // add Large Bar space device to delayAttachedDevs - for _, device := range c.devices { - var isLargeBarSpace bool - isLargeBarSpace, err = manager.IsVFIOLargeBarSpaceDevice(device.ContainerPath) - if err != nil { - return - } - if isLargeBarSpace { - delayAttachedDevs = append(delayAttachedDevs, device) - } else { - normalAttachedDevs = append(normalAttachedDevs, device) - } - } - } else { - normalAttachedDevs = c.devices - } - c.Logger().WithFields(logrus.Fields{ - "machine_type": machineType, - "devices": normalAttachedDevs, - }).Info("normal attach devices") - if len(normalAttachedDevs) > 0 { - if err = c.attachDevices(ctx, normalAttachedDevs); err != nil { - return - } + "devices": c.devices, + }).Info("Attach devices") + if err = c.attachDevices(ctx); err != nil { + return } // Deduce additional system mount info that should be handled by the agent @@ -948,17 +921,6 @@ func (c *Container) create(ctx context.Context) (err error) { } c.process = *process - // lazy attach device after createContainer for q35 - if machineType == QemuQ35 && len(delayAttachedDevs) > 0 { - c.Logger().WithFields(logrus.Fields{ - "machine_type": machineType, - "devices": delayAttachedDevs, - }).Info("lazy attach devices") - if err = c.attachDevices(ctx, delayAttachedDevs); err != nil { - return - } - } - if err = c.setContainerState(types.StateReady); err != nil { return } @@ -1398,7 +1360,7 @@ func (c *Container) removeDrive(ctx context.Context) (err error) { return nil } -func (c *Container) attachDevices(ctx context.Context, devices []ContainerDevice) error { +func (c *Container) attachDevices(ctx context.Context) error { // there's no need to do rollback when error happens, // because if attachDevices fails, container creation will fail too, // and rollbackFailingContainerCreation could do all the rollbacks @@ -1406,7 +1368,7 @@ func (c *Container) attachDevices(ctx context.Context, devices []ContainerDevice // since devices with large bar space require delayed attachment, // the devices need to be split into two lists, normalAttachedDevs and delayAttachedDevs. // so c.device is not used here. See issue https://github.com/kata-containers/runtime/issues/2460. - for _, dev := range devices { + for _, dev := range c.devices { if err := c.sandbox.devManager.AttachDevice(ctx, dev.ID, c.sandbox); err != nil { return err } diff --git a/src/runtime/virtcontainers/device/manager/utils.go b/src/runtime/virtcontainers/device/manager/utils.go index ade0b6c9d..61488ef9f 100644 --- a/src/runtime/virtcontainers/device/manager/utils.go +++ b/src/runtime/virtcontainers/device/manager/utils.go @@ -7,16 +7,10 @@ package manager import ( - "fmt" - "os" "path/filepath" - "strconv" "strings" - "github.com/sirupsen/logrus" - "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/config" - "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/drivers" ) const ( @@ -42,101 +36,6 @@ func isBlock(devInfo config.DeviceInfo) bool { return devInfo.DevType == "b" } -// IsVFIOLargeBarSpaceDevice checks if the device is a large bar space device. -func IsVFIOLargeBarSpaceDevice(hostPath string) (bool, error) { - if !isVFIO(hostPath) { - return false, nil - } - - iommuDevicesPath := filepath.Join(config.SysIOMMUPath, filepath.Base(hostPath), "devices") - deviceFiles, err := os.ReadDir(iommuDevicesPath) - if err != nil { - return false, err - } - - // Pass all devices in iommu group - for _, deviceFile := range deviceFiles { - vfioDeviceType := drivers.GetVFIODeviceType(deviceFile.Name()) - var isLarge bool - switch vfioDeviceType { - case config.VFIODeviceNormalType: - sysfsResource := filepath.Join(iommuDevicesPath, deviceFile.Name(), "resource") - if isLarge, err = isLargeBarSpace(sysfsResource); err != nil { - return false, err - } - deviceLogger().WithFields(logrus.Fields{ - "device-file": deviceFile.Name(), - "device-type": vfioDeviceType, - "resource": sysfsResource, - "large-bar-space": isLarge, - }).Info("Detect large bar space device") - return isLarge, nil - case config.VFIODeviceMediatedType: - //TODO: support VFIODeviceMediatedType - deviceLogger().WithFields(logrus.Fields{ - "device-file": deviceFile.Name(), - "device-type": vfioDeviceType, - }).Warn("Detect large bar space device is not yet supported for VFIODeviceMediatedType") - default: - deviceLogger().WithFields(logrus.Fields{ - "device-file": deviceFile.Name(), - "device-type": vfioDeviceType, - }).Warn("Incorrect token found when detecting large bar space devices") - } - } - - return false, nil -} - -func isLargeBarSpace(resourcePath string) (bool, error) { - buf, err := os.ReadFile(resourcePath) - if err != nil { - return false, fmt.Errorf("failed to read sysfs resource: %v", err) - } - - // The resource file contains host addresses of PCI resources: - // For example: - // $ cat /sys/bus/pci/devices/0000:04:00.0/resource - // 0x00000000c6000000 0x00000000c6ffffff 0x0000000000040200 - // 0x0000383800000000 0x0000383bffffffff 0x000000000014220c - // Refer: - // resource format: https://github.com/torvalds/linux/blob/63623fd44972d1ed2bfb6e0fb631dfcf547fd1e7/drivers/pci/pci-sysfs.c#L145 - // calculate size : https://github.com/pciutils/pciutils/blob/61ecc14a327de030336f1ff3fea9c7e7e55a90ca/lspci.c#L388 - for rIdx, line := range strings.Split(string(buf), "\n") { - cols := strings.Fields(line) - // start and end columns are required to calculate the size - if len(cols) < 2 { - deviceLogger().WithField("resource-line", line).Debug("not enough columns to calculate PCI size") - continue - } - start, _ := strconv.ParseUint(cols[0], 0, 64) - end, _ := strconv.ParseUint(cols[1], 0, 64) - if start > end { - deviceLogger().WithFields(logrus.Fields{ - "start": start, - "end": end, - }).Debug("start is greater than end") - continue - } - // Use right shift to convert Bytes to GBytes - // This is equivalent to ((end - start + 1) / 1024 / 1024 / 1024) - gbSize := (end - start + 1) >> 30 - deviceLogger().WithFields(logrus.Fields{ - "resource": resourcePath, - "region": rIdx, - "start": cols[0], - "end": cols[1], - "gb-size": gbSize, - }).Debug("Check large bar space device") - //size is large than 4G - if gbSize > 4 { - return true, nil - } - } - - return false, nil -} - // isVhostUserBlk checks if the device is a VhostUserBlk device. func isVhostUserBlk(devInfo config.DeviceInfo) bool { return devInfo.DevType == "b" && devInfo.Major == config.VhostUserBlkMajor diff --git a/src/runtime/virtcontainers/device/manager/utils_test.go b/src/runtime/virtcontainers/device/manager/utils_test.go index 76239340f..ec518ce7a 100644 --- a/src/runtime/virtcontainers/device/manager/utils_test.go +++ b/src/runtime/virtcontainers/device/manager/utils_test.go @@ -7,7 +7,6 @@ package manager import ( - "os" "testing" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/config" @@ -104,46 +103,3 @@ func TestIsVhostUserSCSI(t *testing.T) { assert.Equal(t, d.expected, isVhostUserSCSI) } } - -func TestIsLargeBarSpace(t *testing.T) { - assert := assert.New(t) - - // File not exist - bs, err := isLargeBarSpace("/abc/xyz/123/rgb") - assert.Error(err) - assert.False(bs) - - f, err := os.CreateTemp("", "pci") - assert.NoError(err) - defer f.Close() - defer os.RemoveAll(f.Name()) - - type testData struct { - resourceInfo string - error bool - result bool - } - - for _, d := range []testData{ - {"", false, false}, - {"\t\n\t ", false, false}, - {"abc zyx", false, false}, - {"abc zyx rgb", false, false}, - {"abc\t zyx \trgb", false, false}, - {"0x00015\n0x0013", false, false}, - {"0x00000000c6000000 0x00000000c6ffffff 0x0000000000040200", false, false}, - {"0x0000383bffffffff 0x0000383800000000", false, false}, // start greater than end - {"0x0000383800000000 0x0000383bffffffff", false, true}, - {"0x0000383800000000 0x0000383bffffffff 0x000000000014220c", false, true}, - } { - f.WriteAt([]byte(d.resourceInfo), 0) - bs, err = isLargeBarSpace(f.Name()) - assert.NoError(f.Truncate(0)) - if d.error { - assert.Error(err, d.resourceInfo) - } else { - assert.NoError(err, d.resourceInfo) - } - assert.Equal(d.result, bs, d.resourceInfo) - } -} diff --git a/src/runtime/virtcontainers/sandbox_test.go b/src/runtime/virtcontainers/sandbox_test.go index eb3314857..9c64c8b22 100644 --- a/src/runtime/virtcontainers/sandbox_test.go +++ b/src/runtime/virtcontainers/sandbox_test.go @@ -582,7 +582,7 @@ func TestSandboxAttachDevicesVFIO(t *testing.T) { containers[c.id].sandbox = &sandbox - err = containers[c.id].attachDevices(context.Background(), c.devices) + err = containers[c.id].attachDevices(context.Background()) assert.Nil(t, err, "Error while attaching devices %s", err) err = containers[c.id].detachDevices(context.Background()) @@ -677,7 +677,7 @@ func TestSandboxAttachDevicesVhostUserBlk(t *testing.T) { containers[c.id].sandbox = &sandbox - err = containers[c.id].attachDevices(context.Background(), c.devices) + err = containers[c.id].attachDevices(context.Background()) assert.Nil(t, err, "Error while attaching vhost-user-blk devices %s", err) err = containers[c.id].detachDevices(context.Background()) From d47c488b58887a4990de9f471702b20b0f6ffdc2 Mon Sep 17 00:00:00 2001 From: Julio Montes Date: Thu, 17 Feb 2022 09:03:17 -0600 Subject: [PATCH 36/47] versions: add qemu tdx section define qemu tdx version and repo url fixes #3706 Signed-off-by: Julio Montes --- versions.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/versions.yaml b/versions.yaml index 8e8ee9b36..8a4b6db08 100644 --- a/versions.yaml +++ b/versions.yaml @@ -98,6 +98,10 @@ assets: uscan-url: >- https://github.com/qemu/qemu/tags .*/v?(\d\S+)\.tar\.gz + tdx: + description: "VMM that uses KVM and supports TDX" + url: "https://github.com/intel/qemu-tdx" + tag: "tdx-qemu-2021.11.29-v6.0.0-rc1-mvp" qemu-experimental: description: "QEMU with virtiofs support" From 7c4ee6ec48aa00f468b8633761a037fc56f17828 Mon Sep 17 00:00:00 2001 From: Julio Montes Date: Thu, 17 Feb 2022 09:10:31 -0600 Subject: [PATCH 37/47] packaging/qemu: create no_patches file for qemu-tdx create no_patches.txt file for qemu-tdx, this way we can build it using packaging scripts Signed-off-by: Julio Montes --- .../tag_patches/tdx-qemu-2021.11.29-v6.0.0-rc1-mvp/no_patches.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/packaging/qemu/patches/tag_patches/tdx-qemu-2021.11.29-v6.0.0-rc1-mvp/no_patches.txt diff --git a/tools/packaging/qemu/patches/tag_patches/tdx-qemu-2021.11.29-v6.0.0-rc1-mvp/no_patches.txt b/tools/packaging/qemu/patches/tag_patches/tdx-qemu-2021.11.29-v6.0.0-rc1-mvp/no_patches.txt new file mode 100644 index 000000000..e69de29bb From 6c1d149a5d311e10511cc82058cfe88f67d9cdec Mon Sep 17 00:00:00 2001 From: Gabriela Cervantes Date: Thu, 17 Feb 2022 18:58:41 +0000 Subject: [PATCH 38/47] docs: Update limitations document This PR updates the limitations document by removing the docker references belonged to kata 1.x and add as a limitation the docker and podman support for kata 2.0 Fixes #3709 Signed-off-by: Gabriela Cervantes --- docs/Limitations.md | 62 ++++++--------------------------------------- 1 file changed, 8 insertions(+), 54 deletions(-) diff --git a/docs/Limitations.md b/docs/Limitations.md index 9c2b44c27..d7b73776c 100644 --- a/docs/Limitations.md +++ b/docs/Limitations.md @@ -57,6 +57,13 @@ for advice on which repository to raise the issue against. This section lists items that might be possible to fix. +## OCI CLI commands + +### Docker and Podman support +Currently Kata Containers does not support Docker or Podman. + +See issue https://github.com/kata-containers/kata-containers/issues/722 for more information. + ## Runtime commands ### checkpoint and restore @@ -103,44 +110,6 @@ This section lists items that might not be fixed due to fundamental architectural differences between "soft containers" (i.e. traditional Linux* containers) and those based on VMs. -## Networking limitations - -### Support for joining an existing VM network - -Docker supports the ability for containers to join another containers -namespace with the `docker run --net=containers` syntax. This allows -multiple containers to share a common network namespace and the network -interfaces placed in the network namespace. Kata Containers does not -support network namespace sharing. If a Kata Container is setup to -share the network namespace of a `runc` container, the runtime -effectively takes over all the network interfaces assigned to the -namespace and binds them to the VM. Consequently, the `runc` container loses -its network connectivity. - -### docker --net=host - -Docker host network support (`docker --net=host run`) is not supported. -It is not possible to directly access the host networking configuration -from within the VM. - -The `--net=host` option can still be used with `runc` containers and -inter-mixed with running Kata Containers, thus enabling use of `--net=host` -when necessary. - -It should be noted, currently passing the `--net=host` option into a -Kata Container may result in the Kata Container networking setup -modifying, re-configuring and therefore possibly breaking the host -networking setup. Do not use `--net=host` with Kata Containers. - -### docker run --link - -The runtime does not support the `docker run --link` command. This -command is now deprecated by docker and we have no intention of adding support. -Equivalent functionality can be achieved with the newer docker networking commands. - -See more documentation at -[docs.docker.com](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/). - ## Storage limitations ### Kubernetes `volumeMounts.subPaths` @@ -151,15 +120,11 @@ moment. See [this issue](https://github.com/kata-containers/runtime/issues/2812) for more details. [Another issue](https://github.com/kata-containers/kata-containers/issues/1728) focuses on the case of `emptyDir`. - ## Host resource sharing -### docker run --privileged +### Privileged containers Privileged support in Kata is essentially different from `runc` containers. -Kata does support `docker run --privileged` command, but in this case full access -to the guest VM is provided in addition to some host access. - The container runs with elevated capabilities within the guest and is granted access to guest devices instead of the host devices. This is also true with using `securityContext privileged=true` with Kubernetes. @@ -169,17 +134,6 @@ The container may also be granted full access to a subset of host devices See [Privileged Kata Containers](how-to/privileged.md) for how to configure some of this behavior. -# Miscellaneous - -This section lists limitations where the possible solutions are uncertain. - -## Docker --security-opt option partially supported - -The `--security-opt=` option used by Docker is partially supported. -We only support `--security-opt=no-new-privileges` and `--security-opt seccomp=/path/to/seccomp/profile.json` -option as of today. - -Note: The `--security-opt apparmor=your_profile` is not yet supported. See https://github.com/kata-containers/runtime/issues/707. # Appendices ## The constraints challenge From 1cee0a94528fc03891fffe04e94b1b02b9010b75 Mon Sep 17 00:00:00 2001 From: zhanghj Date: Fri, 18 Feb 2022 16:42:42 +0800 Subject: [PATCH 39/47] virtcontainers: Remove duplicated assert messages in utils test code Remove duplicated strings in assert.Errorf() and assert.NoErrorf(). Fixes: #3714 Signed-off-by: zhanghj --- src/runtime/virtcontainers/utils/utils_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/runtime/virtcontainers/utils/utils_test.go b/src/runtime/virtcontainers/utils/utils_test.go index f37e0f222..838e72ef4 100644 --- a/src/runtime/virtcontainers/utils/utils_test.go +++ b/src/runtime/virtcontainers/utils/utils_test.go @@ -297,9 +297,9 @@ func TestBuildSocketPath(t *testing.T) { msg := fmt.Sprintf("test[%d]: %+v", i, d) if d.valid { - assert.NoErrorf(err, "test %d, data %+v", i, d, msg) + assert.NoError(err, msg) } else { - assert.Errorf(err, "test %d, data %+v", i, d, msg) + assert.Error(err, msg) } assert.NotNil(result, msg) From 27de212fe1dce7d93e3985225531886cf7304e37 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 17 Feb 2022 18:04:22 +0100 Subject: [PATCH 40/47] runtime: Always add network endpoints from the pod netns As the container runtime, we're never inspecting, adding or configuring host networking endpoints. Make sure we're always do that by wrapping addSingleEndpoint calls into the pod network namespace. Fixes #3661 Signed-off-by: Samuel Ortiz --- src/runtime/virtcontainers/network_linux.go | 67 +++++++++++---------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/src/runtime/virtcontainers/network_linux.go b/src/runtime/virtcontainers/network_linux.go index 378cd02e0..c4f2380e5 100644 --- a/src/runtime/virtcontainers/network_linux.go +++ b/src/runtime/virtcontainers/network_linux.go @@ -178,38 +178,32 @@ func (n *LinuxNetwork) addSingleEndpoint(ctx context.Context, s *Sandbox, netInf endpoint.SetProperties(netInfo) - if err := doNetNS(n.netNSPath, func(_ ns.NetNS) error { - networkLogger().WithField("endpoint-type", endpoint.Type()).WithField("hotplug", hotplug).Info("Attaching endpoint") - if hotplug { - if err := endpoint.HotAttach(ctx, s.hypervisor); err != nil { - return err - } - } else { - if err := endpoint.Attach(ctx, s); err != nil { - return err + networkLogger().WithField("endpoint-type", endpoint.Type()).WithField("hotplug", hotplug).Info("Attaching endpoint") + if hotplug { + if err := endpoint.HotAttach(ctx, s.hypervisor); err != nil { + return nil, err + } + } else { + if err := endpoint.Attach(ctx, s); err != nil { + return nil, err + } + } + + if !s.hypervisor.IsRateLimiterBuiltin() { + rxRateLimiterMaxRate := s.hypervisor.HypervisorConfig().RxRateLimiterMaxRate + if rxRateLimiterMaxRate > 0 { + networkLogger().Info("Add Rx Rate Limiter") + if err := addRxRateLimiter(endpoint, rxRateLimiterMaxRate); err != nil { + return nil, err } } - - if !s.hypervisor.IsRateLimiterBuiltin() { - rxRateLimiterMaxRate := s.hypervisor.HypervisorConfig().RxRateLimiterMaxRate - if rxRateLimiterMaxRate > 0 { - networkLogger().Info("Add Rx Rate Limiter") - if err := addRxRateLimiter(endpoint, rxRateLimiterMaxRate); err != nil { - return err - } - } - txRateLimiterMaxRate := s.hypervisor.HypervisorConfig().TxRateLimiterMaxRate - if txRateLimiterMaxRate > 0 { - networkLogger().Info("Add Tx Rate Limiter") - if err := addTxRateLimiter(endpoint, txRateLimiterMaxRate); err != nil { - return err - } + txRateLimiterMaxRate := s.hypervisor.HypervisorConfig().TxRateLimiterMaxRate + if txRateLimiterMaxRate > 0 { + networkLogger().Info("Add Tx Rate Limiter") + if err := addTxRateLimiter(endpoint, txRateLimiterMaxRate); err != nil { + return nil, err } } - - return nil - }); err != nil { - return nil, err } n.eps = append(n.eps, endpoint) @@ -298,10 +292,13 @@ func (n *LinuxNetwork) addAllEndpoints(ctx context.Context, s *Sandbox, hotplug continue } - _, err = n.addSingleEndpoint(ctx, s, netInfo, hotplug) - if err != nil { + if err := doNetNS(n.netNSPath, func(_ ns.NetNS) error { + _, err = n.addSingleEndpoint(ctx, s, netInfo, hotplug) + return err + }); err != nil { return err } + } sort.Slice(n.eps, func(i, j int) bool { @@ -335,8 +332,14 @@ func (n *LinuxNetwork) AddEndpoints(ctx context.Context, s *Sandbox, endpointsIn } } else { for _, ep := range endpointsInfo { - if _, err := n.addSingleEndpoint(ctx, s, ep, hotplug); err != nil { - n.eps = nil + if err := doNetNS(n.netNSPath, func(_ ns.NetNS) error { + if _, err := n.addSingleEndpoint(ctx, s, ep, hotplug); err != nil { + n.eps = nil + return err + } + + return nil + }); err != nil { return nil, err } } From 32e7845d31b6535f7947d1daa056fb89501f96bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Thu, 17 Feb 2022 08:29:31 +0100 Subject: [PATCH 41/47] snap: Build vanilla kernel for all arches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's no need to build an experimental kernel for x86_64 as all the bits which were part of the experimental one (SGX only, really) are now part of the vanilla one. Signed-off-by: Fabiano Fidêncio --- snap/snapcraft.yaml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index d8819736f..4f90329c1 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -204,14 +204,7 @@ parts: kernel_dir_prefix="kata-linux-" # Setup and build kernel - if [ "$(uname -m)" = "x86_64" ]; then - kernel_version="$(${yq} r $versions_file assets.kernel-experimental.tag)" - kernel_version=${kernel_version#v} - kernel_dir_prefix="kata-linux-experimental-" - ./build-kernel.sh -e -v ${kernel_version} -d setup - else - ./build-kernel.sh -v ${kernel_version} -d setup - fi + ./build-kernel.sh -v ${kernel_version} -d setup cd ${kernel_dir_prefix}* make -j $(($(nproc)-1)) EXTRAVERSION=".container" From 2c35d8cb8e167416d944c5a79c4dda71b3f2dd4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Thu, 17 Feb 2022 08:36:45 +0100 Subject: [PATCH 42/47] workflows: Stop building the experimental kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's stop building the experimental kernel as, currently, we have all the needed contents as part of the vanilla kernel. Signed-off-by: Fabiano Fidêncio --- .github/workflows/kata-deploy-push.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/kata-deploy-push.yaml b/.github/workflows/kata-deploy-push.yaml index 88030b8e9..54110d2c7 100644 --- a/.github/workflows/kata-deploy-push.yaml +++ b/.github/workflows/kata-deploy-push.yaml @@ -18,7 +18,6 @@ jobs: matrix: asset: - kernel - - kernel-experimental - shim-v2 - qemu - cloud-hypervisor From 5b3fb6f83df84a2b67ac882e92b3432c7980f64f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Wed, 16 Feb 2022 19:57:31 +0100 Subject: [PATCH 43/47] kernel: Build SGX as part of the vanilla kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Let's take advantage of the fact that we've bumped to our kernel version ot the 5.15 LTS and enable SGX by default, as it's present there. Fixes: #3692 Signed-off-by: Fabiano Fidêncio --- .../fragments/{build-type/experimental => x86_64}/sgx.conf | 0 tools/packaging/kernel/kata_config_version | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename tools/packaging/kernel/configs/fragments/{build-type/experimental => x86_64}/sgx.conf (100%) diff --git a/tools/packaging/kernel/configs/fragments/build-type/experimental/sgx.conf b/tools/packaging/kernel/configs/fragments/x86_64/sgx.conf similarity index 100% rename from tools/packaging/kernel/configs/fragments/build-type/experimental/sgx.conf rename to tools/packaging/kernel/configs/fragments/x86_64/sgx.conf diff --git a/tools/packaging/kernel/kata_config_version b/tools/packaging/kernel/kata_config_version index d22307c42..8643cf6de 100644 --- a/tools/packaging/kernel/kata_config_version +++ b/tools/packaging/kernel/kata_config_version @@ -1 +1 @@ -88 +89 From 5c9d2b413ffef440b235eb3e5d684cfb83af49ab Mon Sep 17 00:00:00 2001 From: Jakob Naucke Date: Wed, 16 Feb 2022 15:33:11 +0100 Subject: [PATCH 44/47] packaging: Use `patch` for applying patches `tools/packaging/scripts/apply_patches.sh` uses `git apply $patch`, but this will not apply to subdirectories. If one wanted to apply with `git apply`, they'd have to run it with `--directory=...` _relative to the Git tree's root_ (absolute will not work!). I suggest we just use `patch`, which will do what we expected `git apply` would do. `patch` is also added to build containers that require it. Fixes: #3690 Signed-off-by: Jakob Naucke --- tools/packaging/scripts/apply_patches.sh | 2 +- tools/packaging/static-build/kernel/Dockerfile | 3 ++- tools/packaging/static-build/qemu/Dockerfile | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/packaging/scripts/apply_patches.sh b/tools/packaging/scripts/apply_patches.sh index 68d3d4260..de8580845 100755 --- a/tools/packaging/scripts/apply_patches.sh +++ b/tools/packaging/scripts/apply_patches.sh @@ -40,7 +40,7 @@ if [ -d "$patches_dir" ]; then echo "INFO: Found ${#patches[@]} patches" for patch in ${patches[@]}; do echo "INFO: Apply $patch" - git apply "$patch" || \ + patch -p1 < "$patch" || \ { echo >&2 "ERROR: Not applied. Exiting..."; exit 1; } done else diff --git a/tools/packaging/static-build/kernel/Dockerfile b/tools/packaging/static-build/kernel/Dockerfile index cd1a59f2d..2595a08e7 100644 --- a/tools/packaging/static-build/kernel/Dockerfile +++ b/tools/packaging/static-build/kernel/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && \ flex \ git \ iptables \ - libelf-dev && \ + libelf-dev \ + patch && \ if [ "$(uname -m)" = "s390x" ]; then apt-get install -y --no-install-recommends libssl-dev; fi && \ apt-get clean && rm -rf /var/lib/lists/ diff --git a/tools/packaging/static-build/qemu/Dockerfile b/tools/packaging/static-build/qemu/Dockerfile index f32644fec..61cc6ce95 100644 --- a/tools/packaging/static-build/qemu/Dockerfile +++ b/tools/packaging/static-build/qemu/Dockerfile @@ -43,6 +43,7 @@ RUN apt-get update && apt-get upgrade -y && \ pkg-config \ libseccomp-dev \ libseccomp2 \ + patch \ python \ python-dev \ rsync \ From 8cc1b186362908c44fafb8f4f8a7216aaf89419e Mon Sep 17 00:00:00 2001 From: Amulyam24 Date: Fri, 18 Feb 2022 16:14:52 +0530 Subject: [PATCH 45/47] kernel: remove SYS_SUPPORTS_HUGETLBFS from powerpc fragments The name of SYS_SUPPORTS_HUGETLBFS has been changed to ARCH_SUPPORTS_HUGETLBFS which is being selected on default by another kernel config. More info- https://github.com/torvalds/linux/commit/855f9a8e87fe3912a1c00eb63f36880d1ad32e40 Change applicable from v5.13. Fixes: #3720 Signed-off-by: Amulyam24 --- tools/packaging/kernel/configs/fragments/powerpc/base.conf | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/packaging/kernel/configs/fragments/powerpc/base.conf b/tools/packaging/kernel/configs/fragments/powerpc/base.conf index f5d7abee6..080172c43 100644 --- a/tools/packaging/kernel/configs/fragments/powerpc/base.conf +++ b/tools/packaging/kernel/configs/fragments/powerpc/base.conf @@ -4,6 +4,5 @@ CONFIG_64BIT=y CONFIG_HW_RANDOM_PSERIES=y CONFIG_HAS_IOMEM=y -CONFIG_SYS_SUPPORTS_HUGETLBFS=y CONFIG_VIRTUALIZATION=y CONFIG_PPC_OF_BOOT_TRAMPOLINE=y From 3175aad5ba4522fcf7279aced5cb6f8a445f4079 Mon Sep 17 00:00:00 2001 From: "luodaowen.backend" Date: Wed, 16 Feb 2022 20:50:48 +0800 Subject: [PATCH 46/47] virtiofs-nydus: add lazyload support for kata with clh As kata with qemu has supported lazyload, so this pr aims to bring lazyload ability to kata with clh. Fixes #3654 Signed-off-by: luodaowen.backend --- .../how-to-use-virtio-fs-nydus-with-kata.md | 6 +- src/runtime/Makefile | 2 + src/runtime/config/configuration-clh.toml.in | 5 ++ src/runtime/pkg/katautils/config.go | 22 ++--- src/runtime/pkg/katautils/config_test.go | 4 + src/runtime/virtcontainers/clh.go | 89 ++++++++++++------- src/runtime/virtcontainers/clh_test.go | 8 +- src/runtime/virtcontainers/kata_agent.go | 23 +++-- src/runtime/virtcontainers/mount.go | 10 +-- src/runtime/virtcontainers/nydusd.go | 2 +- 10 files changed, 108 insertions(+), 63 deletions(-) diff --git a/docs/how-to/how-to-use-virtio-fs-nydus-with-kata.md b/docs/how-to/how-to-use-virtio-fs-nydus-with-kata.md index bbc177e0f..9b04d49cf 100644 --- a/docs/how-to/how-to-use-virtio-fs-nydus-with-kata.md +++ b/docs/how-to/how-to-use-virtio-fs-nydus-with-kata.md @@ -2,7 +2,7 @@ ## Introduction -Refer to [kata-`nydus`-design](../design/kata-nydus-design.md) +Refer to [kata-`nydus`-design](../design/kata-nydus-design.md) for introduction and `nydus` has supported Kata Containers with hypervisor `QEMU` and `CLH` currently. ## How to @@ -16,7 +16,7 @@ You can use Kata Containers with `nydus` as follows, 4. Use [kata-containers](https://github.com/kata-containers/kata-containers) `latest` branch to compile and build `kata-containers.img`; -5. Update `configuration-qemu.toml` to include: +5. Update `configuration-qemu.toml` or `configuration-clh.toml`to include: ```toml shared_fs = "virtio-fs-nydus" @@ -24,7 +24,7 @@ virtio_fs_daemon = "" virtio_fs_extra_args = [] ``` -6. run `crictl run -r kata-qemu nydus-container.yaml nydus-sandbox.yaml`; +6. run `crictl run -r kata nydus-container.yaml nydus-sandbox.yaml`; The `nydus-sandbox.yaml` looks like below: diff --git a/src/runtime/Makefile b/src/runtime/Makefile index f936bd796..45c1ff1b6 100644 --- a/src/runtime/Makefile +++ b/src/runtime/Makefile @@ -163,6 +163,7 @@ DEFENTROPYSOURCE := /dev/urandom DEFVALIDENTROPYSOURCES := [\"/dev/urandom\",\"/dev/random\",\"\"] DEFDISABLEBLOCK := false +DEFSHAREDFS_CLH_VIRTIOFS := virtio-fs DEFSHAREDFS_QEMU_VIRTIOFS := virtio-fs DEFVIRTIOFSDAEMON := $(LIBEXECDIR)/kata-qemu/virtiofsd DEFVALIDVIRTIOFSDAEMONPATHS := [\"$(DEFVIRTIOFSDAEMON)\"] @@ -437,6 +438,7 @@ USER_VARS += DEFDISABLEBLOCK USER_VARS += DEFBLOCKSTORAGEDRIVER_ACRN USER_VARS += DEFBLOCKSTORAGEDRIVER_FC USER_VARS += DEFBLOCKSTORAGEDRIVER_QEMU +USER_VARS += DEFSHAREDFS_CLH_VIRTIOFS USER_VARS += DEFSHAREDFS_QEMU_VIRTIOFS USER_VARS += DEFVIRTIOFSDAEMON USER_VARS += DEFVALIDVIRTIOFSDAEMONPATHS diff --git a/src/runtime/config/configuration-clh.toml.in b/src/runtime/config/configuration-clh.toml.in index 7f06dd8eb..07e3f31a4 100644 --- a/src/runtime/config/configuration-clh.toml.in +++ b/src/runtime/config/configuration-clh.toml.in @@ -70,6 +70,11 @@ default_memory = @DEFMEMSZ@ # This is will determine the times that memory will be hotadded to sandbox/VM. #memory_slots = @DEFMEMSLOTS@ +# Shared file system type: +# - virtio-fs (default) +# - virtio-fs-nydus +shared_fs = "@DEFSHAREDFS_CLH_VIRTIOFS@" + # Path to vhost-user-fs daemon. virtio_fs_daemon = "@DEFVIRTIOFSDAEMON@" diff --git a/src/runtime/pkg/katautils/config.go b/src/runtime/pkg/katautils/config.go index 06f6a6df0..a34c229ac 100644 --- a/src/runtime/pkg/katautils/config.go +++ b/src/runtime/pkg/katautils/config.go @@ -426,7 +426,7 @@ func (h hypervisor) sharedFS() (string, error) { supportedSharedFS := []string{config.Virtio9P, config.VirtioFS, config.VirtioFSNydus} if h.SharedFS == "" { - return config.Virtio9P, nil + return config.VirtioFS, nil } for _, fs := range supportedSharedFS { @@ -644,14 +644,9 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) { return vc.HypervisorConfig{}, err } - if sharedFS == config.VirtioFS && h.VirtioFSDaemon == "" { + if (sharedFS == config.VirtioFS || sharedFS == config.VirtioFSNydus) && h.VirtioFSDaemon == "" { return vc.HypervisorConfig{}, - errors.New("cannot enable virtio-fs without daemon path in configuration file") - } - - if sharedFS == config.VirtioFSNydus && h.VirtioFSDaemon == "" { - return vc.HypervisorConfig{}, - errors.New("cannot enable virtio nydus without nydusd daemon path in configuration file") + fmt.Errorf("cannot enable %s without daemon path in configuration file", sharedFS) } if vSock, err := utils.SupportsVsocks(); !vSock { @@ -822,11 +817,18 @@ func newClhHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) { return vc.HypervisorConfig{}, err } - sharedFS := config.VirtioFS + sharedFS, err := h.sharedFS() + if err != nil { + return vc.HypervisorConfig{}, err + } + + if sharedFS != config.VirtioFS && sharedFS != config.VirtioFSNydus { + return vc.HypervisorConfig{}, errors.New("clh only support virtio-fs or virtio-fs-nydus") + } if h.VirtioFSDaemon == "" { return vc.HypervisorConfig{}, - errors.New("virtio-fs daemon path is missing in configuration file") + fmt.Errorf("cannot enable %s without daemon path in configuration file", sharedFS) } return vc.HypervisorConfig{ diff --git a/src/runtime/pkg/katautils/config_test.go b/src/runtime/pkg/katautils/config_test.go index 5bfd61250..268e50276 100644 --- a/src/runtime/pkg/katautils/config_test.go +++ b/src/runtime/pkg/katautils/config_test.go @@ -633,6 +633,8 @@ func TestNewQemuHypervisorConfig(t *testing.T) { PCIeRootPort: pcieRootPort, RxRateLimiterMaxRate: rxRateLimiterMaxRate, TxRateLimiterMaxRate: txRateLimiterMaxRate, + SharedFS: "virtio-fs", + VirtioFSDaemon: filepath.Join(dir, "virtiofsd"), } files := []string{hypervisorPath, kernelPath, imagePath} @@ -1388,6 +1390,8 @@ func TestUpdateRuntimeConfigurationVMConfig(t *testing.T) { Image: "/", Firmware: "/", FirmwareVolume: "/", + SharedFS: "virtio-fs", + VirtioFSDaemon: "/usr/libexec/kata-qemu/virtiofsd", }, }, } diff --git a/src/runtime/virtcontainers/clh.go b/src/runtime/virtcontainers/clh.go index f08eba67f..4ab1400da 100644 --- a/src/runtime/virtcontainers/clh.go +++ b/src/runtime/virtcontainers/clh.go @@ -144,27 +144,27 @@ func (c *clhClientApi) VmRemoveDevicePut(ctx context.Context, vmRemoveDevice chc // Cloud hypervisor state // type CloudHypervisorState struct { - apiSocket string - PID int - VirtiofsdPID int - state clhState + apiSocket string + PID int + VirtiofsDaemonPid int + state clhState } func (s *CloudHypervisorState) reset() { s.PID = 0 - s.VirtiofsdPID = 0 + s.VirtiofsDaemonPid = 0 s.state = clhNotReady } type cloudHypervisor struct { - console console.Console - virtiofsd VirtiofsDaemon - APIClient clhClient - ctx context.Context - id string - vmconfig chclient.VmConfig - state CloudHypervisorState - config HypervisorConfig + console console.Console + virtiofsDaemon VirtiofsDaemon + APIClient clhClient + ctx context.Context + id string + vmconfig chclient.VmConfig + state CloudHypervisorState + config HypervisorConfig } var clhKernelParams = []Param{ @@ -198,6 +198,10 @@ func (clh *cloudHypervisor) setConfig(config *HypervisorConfig) error { return nil } +func (clh *cloudHypervisor) nydusdAPISocketPath(id string) (string, error) { + return utils.BuildSocketPath(clh.config.VMStorePath, id, nydusdAPISock) +} + // For cloudHypervisor this call only sets the internal structure up. // The VM will be created and started through StartVM(). func (clh *cloudHypervisor) CreateVM(ctx context.Context, id string, network Network, hypervisorConfig *HypervisorConfig) error { @@ -223,8 +227,8 @@ func (clh *cloudHypervisor) CreateVM(ctx context.Context, id string, network Net if clh.state.PID > 0 { clh.Logger().WithField("function", "CreateVM").Info("Sandbox already exist, loading from state") - clh.virtiofsd = &virtiofsd{ - PID: clh.state.VirtiofsdPID, + clh.virtiofsDaemon = &virtiofsd{ + PID: clh.state.VirtiofsDaemonPid, sourcePath: hypervisorConfig.SharedPath, debug: clh.config.Debug, socketPath: virtiofsdSocketPath, @@ -349,7 +353,7 @@ func (clh *cloudHypervisor) CreateVM(ctx context.Context, id string, network Net ApiInternal: chclient.NewAPIClient(cfg).DefaultApi, } - clh.virtiofsd = &virtiofsd{ + clh.virtiofsDaemon = &virtiofsd{ path: clh.config.VirtioFSDaemon, sourcePath: filepath.Join(GetSharePath(clh.id)), socketPath: virtiofsdSocketPath, @@ -358,6 +362,25 @@ func (clh *cloudHypervisor) CreateVM(ctx context.Context, id string, network Net cache: clh.config.VirtioFSCache, } + if clh.config.SharedFS == config.VirtioFSNydus { + apiSockPath, err := clh.nydusdAPISocketPath(clh.id) + if err != nil { + clh.Logger().WithError(err).Error("Invalid api socket path for nydusd") + return err + } + nd := &nydusd{ + path: clh.config.VirtioFSDaemon, + sockPath: virtiofsdSocketPath, + apiSockPath: apiSockPath, + sourcePath: filepath.Join(GetSharePath(clh.id)), + debug: clh.config.Debug, + extraArgs: clh.config.VirtioFSExtraArgs, + startFn: startInShimNS, + } + nd.setupShareDirFn = nd.setupPassthroughFS + clh.virtiofsDaemon = nd + } + if clh.config.SGXEPCSize > 0 { epcSection := chclient.NewSgxEpcConfig("kata-epc", clh.config.SGXEPCSize) epcSection.Prefault = func(b bool) *bool { return &b }(true) @@ -389,8 +412,8 @@ func (clh *cloudHypervisor) StartVM(ctx context.Context, timeout int) error { return err } - if clh.virtiofsd == nil { - return errors.New("Missing virtiofsd configuration") + if clh.virtiofsDaemon == nil { + return errors.New("Missing virtiofsDaemon configuration") } // This needs to be done as late as possible, just before launching @@ -402,23 +425,23 @@ func (clh *cloudHypervisor) StartVM(ctx context.Context, timeout int) error { } defer label.SetProcessLabel("") - if clh.config.SharedFS == config.VirtioFS { - clh.Logger().WithField("function", "StartVM").Info("Starting virtiofsd") - pid, err := clh.virtiofsd.Start(ctx, func() { + if clh.config.SharedFS == config.VirtioFS || clh.config.SharedFS == config.VirtioFSNydus { + clh.Logger().WithField("function", "StartVM").Info("Starting virtiofsDaemon") + pid, err := clh.virtiofsDaemon.Start(ctx, func() { clh.StopVM(ctx, false) }) if err != nil { return err } - clh.state.VirtiofsdPID = pid + clh.state.VirtiofsDaemonPid = pid } else { return errors.New("cloud-hypervisor only supports virtio based file sharing") } pid, err := clh.launchClh() if err != nil { - if shutdownErr := clh.virtiofsd.Stop(ctx); shutdownErr != nil { - clh.Logger().WithError(shutdownErr).Warn("error shutting down Virtiofsd") + if shutdownErr := clh.virtiofsDaemon.Stop(ctx); shutdownErr != nil { + clh.Logger().WithError(shutdownErr).Warn("error shutting down VirtiofsDaemon") } return fmt.Errorf("failed to launch cloud-hypervisor: %q", err) } @@ -759,14 +782,14 @@ func (clh *cloudHypervisor) toGrpc(ctx context.Context) ([]byte, error) { func (clh *cloudHypervisor) Save() (s hv.HypervisorState) { s.Pid = clh.state.PID s.Type = string(ClhHypervisor) - s.VirtiofsDaemonPid = clh.state.VirtiofsdPID + s.VirtiofsDaemonPid = clh.state.VirtiofsDaemonPid s.APISocket = clh.state.apiSocket return } func (clh *cloudHypervisor) Load(s hv.HypervisorState) { clh.state.PID = s.Pid - clh.state.VirtiofsdPID = s.VirtiofsDaemonPid + clh.state.VirtiofsDaemonPid = s.VirtiofsDaemonPid clh.state.apiSocket = s.APISocket } @@ -790,7 +813,7 @@ func (clh *cloudHypervisor) GetPids() []int { } func (clh *cloudHypervisor) GetVirtioFsPid() *int { - return &clh.state.VirtiofsdPID + return &clh.state.VirtiofsDaemonPid } func (clh *cloudHypervisor) AddDevice(ctx context.Context, devInfo interface{}, devType DeviceType) error { @@ -872,13 +895,13 @@ func (clh *cloudHypervisor) terminate(ctx context.Context, waitOnly bool) (err e return err } - if clh.virtiofsd == nil { - return errors.New("virtiofsd config is nil, failed to stop it") + if clh.virtiofsDaemon == nil { + return errors.New("virtiofsDaemon config is nil, failed to stop it") } - clh.Logger().Debug("stop virtiofsd") - if err = clh.virtiofsd.Stop(ctx); err != nil { - clh.Logger().WithError(err).Error("failed to stop virtiofsd") + clh.Logger().Debug("stop virtiofsDaemon") + if err = clh.virtiofsDaemon.Stop(ctx); err != nil { + clh.Logger().WithError(err).Error("failed to stop virtiofsDaemon") } return @@ -1181,7 +1204,7 @@ func (clh *cloudHypervisor) addNet(e Endpoint) error { // Add shared Volume using virtiofs func (clh *cloudHypervisor) addVolume(volume types.Volume) error { - if clh.config.SharedFS != config.VirtioFS { + if clh.config.SharedFS != config.VirtioFS && clh.config.SharedFS != config.VirtioFSNydus { return fmt.Errorf("shared fs method not supported %s", clh.config.SharedFS) } diff --git a/src/runtime/virtcontainers/clh_test.go b/src/runtime/virtcontainers/clh_test.go index d350dd9e9..7fbdd17fa 100644 --- a/src/runtime/virtcontainers/clh_test.go +++ b/src/runtime/virtcontainers/clh_test.go @@ -296,7 +296,7 @@ func TestClhCreateVM(t *testing.T) { assert.Exactly(clhConfig, clh.config) } -func TestClooudHypervisorStartSandbox(t *testing.T) { +func TestCloudHypervisorStartSandbox(t *testing.T) { assert := assert.New(t) clhConfig, err := newClhConfig() assert.NoError(err) @@ -308,9 +308,9 @@ func TestClooudHypervisorStartSandbox(t *testing.T) { clhConfig.RunStorePath = store.RunStoragePath() clh := &cloudHypervisor{ - config: clhConfig, - APIClient: &clhClientMock{}, - virtiofsd: &virtiofsdMock{}, + config: clhConfig, + APIClient: &clhClientMock{}, + virtiofsDaemon: &virtiofsdMock{}, } err = clh.StartVM(context.Background(), 10) diff --git a/src/runtime/virtcontainers/kata_agent.go b/src/runtime/virtcontainers/kata_agent.go index dc7b99817..74f35cf6c 100644 --- a/src/runtime/virtcontainers/kata_agent.go +++ b/src/runtime/virtcontainers/kata_agent.go @@ -1272,13 +1272,24 @@ func (k *kataAgent) rollbackFailingContainerCreation(ctx context.Context, c *Con } } -func (k *kataAgent) buildContainerRootfsWithNydus(sandbox *Sandbox, c *Container, rootPathParent string) (*grpc.Storage, error) { - if sandbox.GetHypervisorType() != string(QemuHypervisor) { - // qemu is supported first, other hypervisors will next - // https://github.com/kata-containers/kata-containers/issues/2724 +func getVirtiofsDaemonForNydus(sandbox *Sandbox) (VirtiofsDaemon, error) { + var virtiofsDaemon VirtiofsDaemon + switch sandbox.GetHypervisorType() { + case string(QemuHypervisor): + virtiofsDaemon = sandbox.hypervisor.(*qemu).virtiofsDaemon + case string(ClhHypervisor): + virtiofsDaemon = sandbox.hypervisor.(*cloudHypervisor).virtiofsDaemon + default: return nil, errNydusdNotSupport } - q, _ := sandbox.hypervisor.(*qemu) + return virtiofsDaemon, nil +} + +func (k *kataAgent) buildContainerRootfsWithNydus(sandbox *Sandbox, c *Container, rootPathParent string) (*grpc.Storage, error) { + virtiofsDaemon, err := getVirtiofsDaemonForNydus(sandbox) + if err != nil { + return nil, err + } extraOption, err := parseExtraOption(c.rootFs.Options) if err != nil { return nil, err @@ -1290,7 +1301,7 @@ func (k *kataAgent) buildContainerRootfsWithNydus(sandbox *Sandbox, c *Container } k.Logger().Infof("nydus option: %v", extraOption) // mount lowerdir to guest /run/kata-containers/shared/images//lowerdir - if err := q.virtiofsDaemon.Mount(*mountOpt); err != nil { + if err := virtiofsDaemon.Mount(*mountOpt); err != nil { return nil, err } rootfs := &grpc.Storage{} diff --git a/src/runtime/virtcontainers/mount.go b/src/runtime/virtcontainers/mount.go index b23bd0879..f7e65b69e 100644 --- a/src/runtime/virtcontainers/mount.go +++ b/src/runtime/virtcontainers/mount.go @@ -390,13 +390,11 @@ func bindUnmountContainerSnapshotDir(ctx context.Context, sharedDir, cID string) func nydusContainerCleanup(ctx context.Context, sharedDir string, c *Container) error { sandbox := c.sandbox - if sandbox.GetHypervisorType() != string(QemuHypervisor) { - // qemu is supported first, other hypervisors will next - // https://github.com/kata-containers/kata-containers/issues/2724 - return errNydusdNotSupport + virtiofsDaemon, err := getVirtiofsDaemonForNydus(sandbox) + if err != nil { + return err } - q, _ := sandbox.hypervisor.(*qemu) - if err := q.virtiofsDaemon.Umount(rafsMountPath(c.id)); err != nil { + if err := virtiofsDaemon.Umount(rafsMountPath(c.id)); err != nil { return errors.Wrap(err, "umount rafs failed") } if err := bindUnmountContainerSnapshotDir(ctx, sharedDir, c.id); err != nil { diff --git a/src/runtime/virtcontainers/nydusd.go b/src/runtime/virtcontainers/nydusd.go index 1a09b24b1..c9315ee37 100644 --- a/src/runtime/virtcontainers/nydusd.go +++ b/src/runtime/virtcontainers/nydusd.go @@ -68,7 +68,7 @@ var ( errNydusdSockPathInvalid = errors.New("nydusd sock path is invalid") errNydusdAPISockPathInvalid = errors.New("nydusd api sock path is invalid") errNydusdSourcePathInvalid = errors.New("nydusd resource path is invalid") - errNydusdNotSupport = errors.New("nydusd only supports the QEMU hypervisor currently (see https://github.com/kata-containers/kata-containers/issues/2724)") + errNydusdNotSupport = errors.New("nydusd only supports the QEMU/CLH hypervisor currently (see https://github.com/kata-containers/kata-containers/issues/3654)") ) type nydusd struct { From 11220f052f3a7e7c2efd9db188d5aaf26b152ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Mon, 21 Feb 2022 09:59:23 +0100 Subject: [PATCH 47/47] kata-deploy: Use (kata with) qemu as the default shim-v2 binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using kata-deploy, no `containerd-shim-kata-v2` binary is deployed, but we do deploy a `kata` runtime class, which seems very much incosistent. As the default configuration for kata-containers points to QEMU, let's also use kata with QEMU as the default shim-v2 binary. Fixes: #3228, #3734 Signed-off-by: Fabiano Fidêncio --- tools/packaging/kata-deploy/scripts/kata-deploy.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/packaging/kata-deploy/scripts/kata-deploy.sh b/tools/packaging/kata-deploy/scripts/kata-deploy.sh index 957feebec..ac8d1239f 100755 --- a/tools/packaging/kata-deploy/scripts/kata-deploy.sh +++ b/tools/packaging/kata-deploy/scripts/kata-deploy.sh @@ -19,6 +19,8 @@ shims=( "clh" ) +default_shim="qemu" + # If we fail for any reason a message will be displayed die() { msg="$*" @@ -97,6 +99,11 @@ function configure_different_shims_base() { KATA_CONF_FILE=/opt/kata/share/defaults/kata-containers/configuration-${shim}.toml /opt/kata/bin/containerd-shim-kata-v2 "\$@" EOT chmod +x "$shim_file" + + if [ "${shim}" == "${default_shim}" ]; then + echo "Creating the default shim-v2 binary" + ln -sf "${shim_file}" /usr/local/bin/containerd-shim-kata-v2 + fi done } @@ -112,6 +119,8 @@ function cleanup_different_shims_base() { mv "$shim_backup" "$shim_file" fi done + + rm /usr/local/bin/containerd-shim-kata-v2 } function configure_crio_runtime() {