From 63ec7f58c0741069d46f516360b263f380867fcf Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Mon, 15 Jan 2018 17:28:58 +0000 Subject: [PATCH 1/3] vendor: Update moby tool to latest This includes support for CPU microcode handling Signed-off-by: Rolf Neugebauer --- src/cmd/linuxkit/vendor.conf | 2 +- .../github.com/moby/tool/src/initrd/initrd.go | 11 ++- .../github.com/moby/tool/src/moby/build.go | 56 ++++++++++---- .../github.com/moby/tool/src/moby/config.go | 4 + .../github.com/moby/tool/src/moby/linuxkit.go | 2 +- .../github.com/moby/tool/src/moby/output.go | 77 +++++++++++++------ .../github.com/moby/tool/src/moby/schema.go | 3 +- 7 files changed, 112 insertions(+), 43 deletions(-) diff --git a/src/cmd/linuxkit/vendor.conf b/src/cmd/linuxkit/vendor.conf index d88d035c3..10c267284 100644 --- a/src/cmd/linuxkit/vendor.conf +++ b/src/cmd/linuxkit/vendor.conf @@ -26,7 +26,7 @@ github.com/moby/datakit 97b3d230535397a813323902c23751e176481a86 github.com/moby/hyperkit a12cd7250bcd8d689078e3e42ae4a7cf6a0cbaf3 # When updating also: # curl -fsSL -o src/cmd/linuxkit/build.go https://raw.githubusercontent.com/moby/tool/«hash»/cmd/moby/build.go -github.com/moby/tool f816553d2fc58638f6904fddedd13c36d237b498 +github.com/moby/tool 57b6e2ab947104d47fd60e5af0e34d0edeb9421c github.com/moby/vpnkit 0e4293bb1058598c4b0a406ed171f52573ef414c github.com/opencontainers/go-digest 21dfd564fd89c944783d00d069f33e3e7123c448 github.com/opencontainers/image-spec v1.0.0 diff --git a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/initrd/initrd.go b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/initrd/initrd.go index d479fdf42..2a4a27a06 100644 --- a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/initrd/initrd.go +++ b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/initrd/initrd.go @@ -110,13 +110,13 @@ func CopyTar(w *Writer, r *tar.Reader) (written int64, err error) { } } -// CopySplitTar copies a tar stream into an initrd, but splits out kernel and cmdline -func CopySplitTar(w *Writer, r *tar.Reader) (kernel []byte, cmdline string, err error) { +// CopySplitTar copies a tar stream into an initrd, but splits out kernel, cmdline, and ucode +func CopySplitTar(w *Writer, r *tar.Reader) (kernel []byte, cmdline string, ucode []byte, err error) { for { var thdr *tar.Header thdr, err = r.Next() if err == io.EOF { - return kernel, cmdline, nil + return kernel, cmdline, ucode, nil } if err != nil { return @@ -134,6 +134,11 @@ func CopySplitTar(w *Writer, r *tar.Reader) (kernel []byte, cmdline string, err return } cmdline = string(buf) + case "boot/ucode.cpio": + ucode, err = ioutil.ReadAll(r) + if err != nil { + return + } case "boot": // skip this entry default: diff --git a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/build.go b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/build.go index 2575428d4..bdd8c79ea 100644 --- a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/build.go +++ b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/build.go @@ -176,9 +176,9 @@ func Build(m Moby, w io.Writer, pull bool, tp string) error { dupMap := map[string]string{} if m.Kernel.ref != nil { - // get kernel and initrd tarball from container + // get kernel and initrd tarball and ucode cpio archive from container log.Infof("Extract kernel image: %s", m.Kernel.ref) - kf := newKernelFilter(iw, m.Kernel.Cmdline, m.Kernel.Binary, m.Kernel.Tar) + kf := newKernelFilter(iw, m.Kernel.Cmdline, m.Kernel.Binary, m.Kernel.Tar, m.Kernel.UCode) err := ImageTar(m.Kernel.ref, "", kf, enforceContentTrust(m.Kernel.ref.String(), &m.Trust), pull, "") if err != nil { return fmt.Errorf("Failed to extract kernel image and tarball: %v", err) @@ -259,13 +259,15 @@ type kernelFilter struct { cmdline string kernel string tar string + ucode string discard bool foundKernel bool foundKTar bool + foundUCode bool } -func newKernelFilter(tw *tar.Writer, cmdline string, kernel string, tar *string) *kernelFilter { - tarName, kernelName := "kernel.tar", "kernel" +func newKernelFilter(tw *tar.Writer, cmdline string, kernel string, tar, ucode *string) *kernelFilter { + tarName, kernelName, ucodeName := "kernel.tar", "kernel", "" if tar != nil { tarName = *tar if tarName == "none" { @@ -275,7 +277,10 @@ func newKernelFilter(tw *tar.Writer, cmdline string, kernel string, tar *string) if kernel != "" { kernelName = kernel } - return &kernelFilter{tw: tw, cmdline: cmdline, kernel: kernelName, tar: tarName} + if ucode != nil { + ucodeName = *ucode + } + return &kernelFilter{tw: tw, cmdline: cmdline, kernel: kernelName, tar: tarName, ucode: ucodeName} } func (k *kernelFilter) finishTar() error { @@ -329,16 +334,19 @@ func (k *kernelFilter) WriteHeader(hdr *tar.Header) error { } k.foundKernel = true k.discard = false - whdr := &tar.Header{ - Name: "boot", - Mode: 0755, - Typeflag: tar.TypeDir, - } - if err := tw.WriteHeader(whdr); err != nil { - return err + // If we handled the ucode, /boot already exist. + if !k.foundUCode { + whdr := &tar.Header{ + Name: "boot", + Mode: 0755, + Typeflag: tar.TypeDir, + } + if err := tw.WriteHeader(whdr); err != nil { + return err + } } // add the cmdline in /boot/cmdline - whdr = &tar.Header{ + whdr := &tar.Header{ Name: "boot/cmdline", Mode: 0644, Size: int64(len(k.cmdline)), @@ -363,6 +371,28 @@ func (k *kernelFilter) WriteHeader(hdr *tar.Header) error { k.foundKTar = true k.discard = false k.buffer = new(bytes.Buffer) + case k.ucode: + k.foundUCode = true + k.discard = false + // If we handled the kernel, /boot already exist. + if !k.foundKernel { + whdr := &tar.Header{ + Name: "boot", + Mode: 0755, + Typeflag: tar.TypeDir, + } + if err := tw.WriteHeader(whdr); err != nil { + return err + } + } + whdr := &tar.Header{ + Name: "boot/ucode.cpio", + Mode: hdr.Mode, + Size: hdr.Size, + } + if err := tw.WriteHeader(whdr); err != nil { + return err + } default: k.discard = true } diff --git a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/config.go b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/config.go index ac2ef3884..fc1107d5a 100644 --- a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/config.go +++ b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/config.go @@ -36,6 +36,7 @@ type KernelConfig struct { Cmdline string `yaml:"cmdline,omitempty" json:"cmdline,omitempty"` Binary string `yaml:"binary,omitempty" json:"binary,omitempty"` Tar *string `yaml:"tar,omitempty" json:"tar,omitempty"` + UCode *string `yaml:"ucode,omitempty" json:"ucode,omitempty"` ref *reference.Spec } @@ -289,6 +290,9 @@ func AppendConfig(m0, m1 Moby) (Moby, error) { if m1.Kernel.Tar != nil { moby.Kernel.Tar = m1.Kernel.Tar } + if m1.Kernel.UCode != nil { + moby.Kernel.UCode = m1.Kernel.UCode + } if m1.Kernel.ref != nil { moby.Kernel.ref = m1.Kernel.ref } diff --git a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/linuxkit.go b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/linuxkit.go index 67449e372..bc15a0896 100644 --- a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/linuxkit.go +++ b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/linuxkit.go @@ -72,7 +72,7 @@ func ensureLinuxkitImage(name string) error { return err } defer image.Close() - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } diff --git a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/output.go b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/output.go index 5cd649104..e21a70b3a 100644 --- a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/output.go +++ b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/output.go @@ -27,22 +27,22 @@ const ( var outFuns = map[string]func(string, io.Reader, int) error{ "kernel+initrd": func(base string, image io.Reader, size int) error { - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, ucode, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } - err = outputKernelInitrd(base, kernel, initrd, cmdline) + err = outputKernelInitrd(base, kernel, initrd, cmdline, ucode) if err != nil { return fmt.Errorf("Error writing kernel+initrd output: %v", err) } return nil }, "tar-kernel-initrd": func(base string, image io.Reader, size int) error { - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, ucode, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } - if err := outputKernelInitrdTarball(base, kernel, initrd, cmdline); err != nil { + if err := outputKernelInitrdTarball(base, kernel, initrd, cmdline, ucode); err != nil { return fmt.Errorf("Error writing kernel+initrd tarball output: %v", err) } return nil @@ -62,10 +62,11 @@ var outFuns = map[string]func(string, io.Reader, int) error{ return nil }, "raw-bios": func(base string, image io.Reader, size int) error { - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } + // TODO: Handle ucode err = outputImg(rawBios, base+"-bios.img", kernel, initrd, cmdline) if err != nil { return fmt.Errorf("Error writing raw-bios output: %v", err) @@ -73,7 +74,7 @@ var outFuns = map[string]func(string, io.Reader, int) error{ return nil }, "raw-efi": func(base string, image io.Reader, size int) error { - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } @@ -86,7 +87,7 @@ var outFuns = map[string]func(string, io.Reader, int) error{ "aws": func(base string, image io.Reader, size int) error { filename := base + ".raw" log.Infof(" %s", filename) - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } @@ -97,7 +98,7 @@ var outFuns = map[string]func(string, io.Reader, int) error{ return nil }, "gcp": func(base string, image io.Reader, size int) error { - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } @@ -110,10 +111,11 @@ var outFuns = map[string]func(string, io.Reader, int) error{ "qcow2-bios": func(base string, image io.Reader, size int) error { filename := base + ".qcow2" log.Infof(" %s", filename) - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } + // TODO: Handle ucode err = outputLinuxKit("qcow2", filename, kernel, initrd, cmdline, size) if err != nil { return fmt.Errorf("Error writing qcow2 output: %v", err) @@ -121,7 +123,7 @@ var outFuns = map[string]func(string, io.Reader, int) error{ return nil }, "vhd": func(base string, image io.Reader, size int) error { - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } @@ -132,7 +134,7 @@ var outFuns = map[string]func(string, io.Reader, int) error{ return nil }, "dynamic-vhd": func(base string, image io.Reader, size int) error { - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } @@ -143,7 +145,7 @@ var outFuns = map[string]func(string, io.Reader, int) error{ return nil }, "vmdk": func(base string, image io.Reader, size int) error { - kernel, initrd, cmdline, err := tarToInitrd(image) + kernel, initrd, cmdline, _, err := tarToInitrd(image) if err != nil { return fmt.Errorf("Error converting to initrd: %v", err) } @@ -220,16 +222,16 @@ func Formats(base string, image string, formats []string, size int) error { return nil } -func tarToInitrd(r io.Reader) ([]byte, []byte, string, error) { +func tarToInitrd(r io.Reader) ([]byte, []byte, string, []byte, error) { w := new(bytes.Buffer) iw := initrd.NewWriter(w) tr := tar.NewReader(r) - kernel, cmdline, err := initrd.CopySplitTar(iw, tr) + kernel, cmdline, ucode, err := initrd.CopySplitTar(iw, tr) if err != nil { - return []byte{}, []byte{}, "", err + return []byte{}, []byte{}, "", []byte{}, err } iw.Close() - return kernel, w.Bytes(), cmdline, nil + return kernel, w.Bytes(), cmdline, ucode, nil } func tarInitrdKernel(kernel, initrd []byte, cmdline string) (*bytes.Buffer, error) { @@ -314,21 +316,35 @@ func outputRPi3(image, filename string, filesystem io.Reader) error { return dockerRun(filesystem, output, true, image) } -func outputKernelInitrd(base string, kernel []byte, initrd []byte, cmdline string) error { +func outputKernelInitrd(base string, kernel []byte, initrd []byte, cmdline string, ucode []byte) error { log.Debugf("output kernel/initrd: %s %s", base, cmdline) - log.Infof(" %s %s %s", base+"-kernel", base+"-initrd.img", base+"-cmdline") - err := ioutil.WriteFile(base+"-initrd.img", initrd, os.FileMode(0644)) - if err != nil { - return err + + if len(ucode) != 0 { + log.Infof(" %s ucode+%s %s", base+"-kernel", base+"-initrd.img", base+"-cmdline") + if err := ioutil.WriteFile(base+"-initrd.img", ucode, os.FileMode(0644)); err != nil { + return err + } + f, err := os.OpenFile(base+"-initrd.img", os.O_APPEND|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer f.Close() + if _, err = f.Write(initrd); err != nil { + return err + } + } else { + log.Infof(" %s %s %s", base+"-kernel", base+"-initrd.img", base+"-cmdline") + if err := ioutil.WriteFile(base+"-initrd.img", initrd, os.FileMode(0644)); err != nil { + return err + } } - err = ioutil.WriteFile(base+"-kernel", kernel, os.FileMode(0644)) - if err != nil { + if err := ioutil.WriteFile(base+"-kernel", kernel, os.FileMode(0644)); err != nil { return err } return ioutil.WriteFile(base+"-cmdline", []byte(cmdline), os.FileMode(0644)) } -func outputKernelInitrdTarball(base string, kernel []byte, initrd []byte, cmdline string) error { +func outputKernelInitrdTarball(base string, kernel []byte, initrd []byte, cmdline string, ucode []byte) error { log.Debugf("output kernel/initrd tarball: %s %s", base, cmdline) log.Infof(" %s", base+"-initrd.tar") f, err := os.Create(base + "-initrd.tar") @@ -370,5 +386,18 @@ func outputKernelInitrdTarball(base string, kernel []byte, initrd []byte, cmdlin if _, err := tw.Write([]byte(cmdline)); err != nil { return err } + if len(ucode) != 0 { + hdr := &tar.Header{ + Name: "ucode.cpio", + Mode: 0644, + Size: int64(len(ucode)), + } + if err := tw.WriteHeader(hdr); err != nil { + return err + } + if _, err := tw.Write(ucode); err != nil { + return err + } + } return tw.Close() } diff --git a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/schema.go b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/schema.go index 2ca2c3c4f..7c2771214 100644 --- a/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/schema.go +++ b/src/cmd/linuxkit/vendor/github.com/moby/tool/src/moby/schema.go @@ -13,7 +13,8 @@ var schema = string(` "image": {"type": "string"}, "cmdline": {"type": "string"}, "binary": {"type": "string"}, - "tar": {"type": "string"} + "tar": {"type": "string"}, + "ucode": {"type": "string"} } }, "file": { From 9f183f70126998b247e7c3724c63404f32077958 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Mon, 15 Jan 2018 17:42:47 +0000 Subject: [PATCH 2/3] packet: Add inte-ucode.cpio to packet example and override it for the arm64 add on Signed-off-by: Rolf Neugebauer --- examples/packet.arm64.yml | 10 ++++++++++ examples/packet.yml | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/packet.arm64.yml b/examples/packet.arm64.yml index 4ee5c3bfc..d15b44f62 100644 --- a/examples/packet.arm64.yml +++ b/examples/packet.arm64.yml @@ -1,3 +1,13 @@ +# This YAML snippet is to be used in conjunction with packet.yml to +# build a arm64 image for packet.net. It adds a modprobe of the NIC +# driver and overrides the kernel section to disable prepending the +# Intel CPU microcode to the initrd. If writing a YAML specifically +# for arm64 then the 'ucode' line in the kernel section can be left +# out. +kernel: + image: linuxkit/kernel:4.9.76 + cmdline: "console=ttyAMA0" + ucode: "" onboot: - name: modprobe image: linuxkit/modprobe:1a192d168adadec47afa860e3fc874fbc2a823ff diff --git a/examples/packet.yml b/examples/packet.yml index 2c5db6f88..ae1cd82a5 100644 --- a/examples/packet.yml +++ b/examples/packet.yml @@ -1,6 +1,7 @@ kernel: image: linuxkit/kernel:4.9.76 - cmdline: "console=ttyS1 console=ttyAMA0" + cmdline: console=ttyS1 + ucode: intel-ucode.cpio init: - linuxkit/init:f7a3d03face99e933626533a3381ae4476fbc8de - linuxkit/runc:7b15b00b4e3507d62e3ed8d44dfe650561cd35ff From a41ef21f73d5bf248ade4fd989318923c5f05708 Mon Sep 17 00:00:00 2001 From: Rolf Neugebauer Date: Mon, 15 Jan 2018 18:10:33 +0000 Subject: [PATCH 3/3] doc: Update packet.net doc wrt to Intel CPU microcode update Signed-off-by: Rolf Neugebauer --- docs/platform-packet.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/platform-packet.md b/docs/platform-packet.md index d830b1afe..56f32fb59 100644 --- a/docs/platform-packet.md +++ b/docs/platform-packet.md @@ -34,6 +34,13 @@ an additional YAML for [arm64](../examples/packet.arm64.yml) servers which provide both access to the serial console and via ssh and configures bonding for network devices via metadata (if supported). +For x86_64 builds for Intel servers we strongly recommend adding +`ucode: intel-ucode.cpio` to the kernel section in the YAML. This +updates the Intel CPU microcode to the latest by prepending it to the +generated initrd file. The `ucode` entry is only recommended when +booting on baremetal. It should be omitted (but is harmless) when +building images to boot in VMs. + **Note**: The update of the iPXE configuration sometimes may take some time and the first boot may fail. Hitting return on the console to retry the boot typically fixes this.