Merge pull request #2865 from rn/ucode

Vendor latest moby and update packet.net examples to include CPU ucode
This commit is contained in:
Rolf Neugebauer 2018-01-16 12:10:00 +00:00 committed by GitHub
commit 44dbf76b11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 131 additions and 44 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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()
}

View File

@ -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": {