// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may // not use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. package main import ( "fmt" "net" "time" "github.com/firecracker-microvm/firecracker-go-sdk" models "github.com/firecracker-microvm/firecracker-go-sdk/client/models" "github.com/firecracker-microvm/firecracker-containerd/config" "github.com/firecracker-microvm/firecracker-containerd/proto" ) const ( defaultMemSizeMb = 128 defaultCPUCount = 1 ) func machineConfigurationFromProto(cfg *config.Config, req *proto.FirecrackerMachineConfiguration) models.MachineConfiguration { config := models.MachineConfiguration{ CPUTemplate: models.CPUTemplate(cfg.CPUTemplate), VcpuCount: firecracker.Int64(defaultCPUCount), MemSizeMib: firecracker.Int64(defaultMemSizeMb), Smt: firecracker.Bool(cfg.SmtEnabled), } if req == nil { return config } if name := req.CPUTemplate; name != "" { config.CPUTemplate = models.CPUTemplate(name) } if count := req.VcpuCount; count > 0 { config.VcpuCount = firecracker.Int64(int64(count)) } if size := req.MemSizeMib; size > 0 { config.MemSizeMib = firecracker.Int64(int64(size)) } config.Smt = firecracker.Bool(req.HtEnabled) return config } // networkConfigFromProto creates a firecracker NetworkInterface object from // the protobuf FirecrackerNetworkInterface message. func networkConfigFromProto(nwIface *proto.FirecrackerNetworkInterface, vmID string) (*firecracker.NetworkInterface, error) { result := &firecracker.NetworkInterface{ AllowMMDS: nwIface.AllowMMDS, } if nwIface.InRateLimiter != nil { result.InRateLimiter = rateLimiterFromProto(nwIface.InRateLimiter) } if nwIface.OutRateLimiter != nil { result.OutRateLimiter = rateLimiterFromProto(nwIface.OutRateLimiter) } if staticConf := nwIface.StaticConfig; staticConf != nil { result.StaticConfiguration = &firecracker.StaticNetworkConfiguration{ HostDevName: staticConf.HostDevName, MacAddress: staticConf.MacAddress, } if ipConf := staticConf.IPConfig; ipConf != nil { ip, ipNet, err := net.ParseCIDR(ipConf.PrimaryAddr) if err != nil { return nil, fmt.Errorf("failed to parse CIDR from %q: %w", ipConf.PrimaryAddr, err) } result.StaticConfiguration.IPConfiguration = &firecracker.IPConfiguration{ IPAddr: net.IPNet{ IP: ip, Mask: ipNet.Mask, }, Gateway: net.ParseIP(ipConf.GatewayAddr), Nameservers: ipConf.Nameservers, } } } if cniConf := nwIface.CNIConfig; cniConf != nil { result.CNIConfiguration = &firecracker.CNIConfiguration{ NetworkName: cniConf.NetworkName, IfName: cniConf.InterfaceName, BinPath: cniConf.BinPath, ConfDir: cniConf.ConfDir, CacheDir: cniConf.CacheDir, } for _, cniArg := range cniConf.Args { var kv [2]string kv[0] = cniArg.Key kv[1] = cniArg.Value result.CNIConfiguration.Args = append(result.CNIConfiguration.Args, kv) } } return result, nil } // rateLimiterFromProto creates a firecracker RateLimiter object from the // protobuf message. func rateLimiterFromProto(rl *proto.FirecrackerRateLimiter) *models.RateLimiter { if rl == nil { return nil } result := models.RateLimiter{} if rl.Bandwidth != nil { result.Bandwidth = tokenBucketFromProto(rl.Bandwidth) } if rl.Ops != nil { result.Ops = tokenBucketFromProto(rl.Ops) } return &result } func withRateLimiterFromProto(rl *proto.FirecrackerRateLimiter) firecracker.DriveOpt { if rl == nil { return func(d *models.Drive) { // no-op } } return firecracker.WithRateLimiter(*rateLimiterFromProto(rl)) } // tokenBucketFromProto creates a firecracker TokenBucket object from the // protobuf message. func tokenBucketFromProto(bucket *proto.FirecrackerTokenBucket) *models.TokenBucket { builder := firecracker.TokenBucketBuilder{} if bucket.OneTimeBurst > 0 { builder = builder.WithInitialSize(bucket.OneTimeBurst) } if bucket.RefillTime > 0 { builder = builder.WithRefillDuration(time.Duration(bucket.RefillTime) * time.Millisecond) } if bucket.Capacity > 0 { builder = builder.WithBucketSize(bucket.Capacity) } res := builder.Build() return &res } func cacheTypeFromProto(cacheType string) *string { // protobuf 'string' type default to empty string if the encoded message // does not contain a value for that field. if cacheType == "" { return nil } return firecracker.String(cacheType) } func withCacheTypeFromProto(cacheType string) firecracker.DriveOpt { // protobuf 'string' type default to empty string if the encoded message // does not contain a value for that field. if cacheType == "" { return func(d *models.Drive) { // no-op } } return firecracker.WithCacheType(cacheType) }