github.com/containerd/nerdctl@v1.7.7/pkg/containerutil/container_network_manager_windows.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package containerutil 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/containerd/containerd" 24 "github.com/containerd/containerd/oci" 25 "github.com/containerd/containerd/pkg/netns" 26 gocni "github.com/containerd/go-cni" 27 28 "github.com/containerd/nerdctl/pkg/api/types" 29 "github.com/containerd/nerdctl/pkg/netutil" 30 "github.com/containerd/nerdctl/pkg/ocihook" 31 ) 32 33 type cniNetworkManagerPlatform struct { 34 netNs *netns.NetNS 35 } 36 37 // Verifies that the internal network settings are correct. 38 func (m *cniNetworkManager) VerifyNetworkOptions(_ context.Context) error { 39 e, err := netutil.NewCNIEnv(m.globalOptions.CNIPath, m.globalOptions.CNINetConfPath, netutil.WithDefaultNetwork()) 40 if err != nil { 41 return err 42 } 43 44 // NOTE: only currently supported network type on Windows is nat: 45 validNetworkTypes := []string{"nat"} 46 if _, err := verifyNetworkTypes(e, m.netOpts.NetworkSlice, validNetworkTypes); err != nil { 47 return err 48 } 49 50 nonZeroArgs := nonZeroMapValues(map[string]interface{}{ 51 "--hostname": m.netOpts.Hostname, 52 "--uts": m.netOpts.UTSNamespace, 53 // NOTE: IP and MAC settings are currently ignored on Windows. 54 "--ip-address": m.netOpts.IPAddress, 55 "--mac-address": m.netOpts.MACAddress, 56 // NOTE: zero-length slices count as a non-zero-value so we explicitly check length: 57 "--dns-opt/--dns-option": len(m.netOpts.DNSResolvConfOptions) != 0, 58 "--dns-servers": len(m.netOpts.DNSServers) != 0, 59 "--dns-search": len(m.netOpts.DNSSearchDomains) != 0, 60 "--add-host": len(m.netOpts.AddHost) != 0, 61 }) 62 if len(nonZeroArgs) != 0 { 63 return fmt.Errorf("the following networking arguments are not supported on Windows: %+v", nonZeroArgs) 64 } 65 66 return nil 67 } 68 69 func (m *cniNetworkManager) getCNI() (gocni.CNI, error) { 70 e, err := netutil.NewCNIEnv(m.globalOptions.CNIPath, m.globalOptions.CNINetConfPath, netutil.WithDefaultNetwork()) 71 if err != nil { 72 return nil, fmt.Errorf("failed to instantiate CNI env: %s", err) 73 } 74 75 cniOpts := []gocni.Opt{ 76 gocni.WithPluginDir([]string{m.globalOptions.CNIPath}), 77 gocni.WithPluginConfDir(m.globalOptions.CNINetConfPath), 78 } 79 80 if netMap, err := verifyNetworkTypes(e, m.netOpts.NetworkSlice, nil); err == nil { 81 for _, netConf := range netMap { 82 cniOpts = append(cniOpts, gocni.WithConfListBytes(netConf.Bytes)) 83 } 84 } else { 85 return nil, err 86 } 87 88 return gocni.New(cniOpts...) 89 } 90 91 // Performs setup actions required for the container with the given ID. 92 func (m *cniNetworkManager) SetupNetworking(ctx context.Context, containerID string) error { 93 cni, err := m.getCNI() 94 if err != nil { 95 return fmt.Errorf("failed to get container networking for setup: %s", err) 96 } 97 98 netNs, err := m.setupNetNs() 99 if err != nil { 100 return err 101 } 102 103 _, err = cni.Setup(ctx, containerID, netNs.GetPath(), m.getCNINamespaceOpts()...) 104 return err 105 } 106 107 // Performs any required cleanup actions for the given container. 108 // Should only be called to revert any setup steps performed in setupNetworking. 109 func (m *cniNetworkManager) CleanupNetworking(ctx context.Context, container containerd.Container) error { 110 containerID := container.ID() 111 cni, err := m.getCNI() 112 if err != nil { 113 return fmt.Errorf("failed to get container networking for cleanup: %s", err) 114 } 115 116 spec, err := container.Spec(ctx) 117 if err != nil { 118 return fmt.Errorf("failed to get container specs for networking cleanup: %s", err) 119 } 120 121 netNsId, found := spec.Annotations[ocihook.NetworkNamespace] 122 if !found { 123 return fmt.Errorf("no %q annotation present on container with ID %s", ocihook.NetworkNamespace, containerID) 124 } 125 126 return cni.Remove(ctx, containerID, netNsId, m.getCNINamespaceOpts()...) 127 } 128 129 // Returns the set of NetworkingOptions which should be set as labels on the container. 130 func (m *cniNetworkManager) InternalNetworkingOptionLabels(_ context.Context) (types.NetworkOptions, error) { 131 return m.netOpts, nil 132 } 133 134 // Returns a slice of `oci.SpecOpts` and `containerd.NewContainerOpts` which represent 135 // the network specs which need to be applied to the container with the given ID. 136 func (m *cniNetworkManager) ContainerNetworkingOpts(_ context.Context, containerID string) ([]oci.SpecOpts, []containerd.NewContainerOpts, error) { 137 ns, err := m.setupNetNs() 138 if err != nil { 139 return nil, nil, err 140 } 141 142 opts := []oci.SpecOpts{ 143 oci.WithWindowNetworksAllowUnqualifiedDNSQuery(), 144 oci.WithWindowsNetworkNamespace(ns.GetPath()), 145 } 146 147 cOpts := []containerd.NewContainerOpts{ 148 containerd.WithAdditionalContainerLabels( 149 map[string]string{ 150 ocihook.NetworkNamespace: ns.GetPath(), 151 }, 152 ), 153 } 154 155 return opts, cOpts, nil 156 } 157 158 // Returns the string path to a network namespace. 159 func (m *cniNetworkManager) setupNetNs() (*netns.NetNS, error) { 160 if m.netNs != nil { 161 return m.netNs, nil 162 } 163 164 // NOTE: the baseDir argument to NewNetNS is ignored on Windows. 165 ns, err := netns.NewNetNS("") 166 if err != nil { 167 return nil, err 168 } 169 170 m.netNs = ns 171 return ns, err 172 } 173 174 // Returns the []gocni.NamespaceOpts to be used for CNI setup/teardown. 175 func (m *cniNetworkManager) getCNINamespaceOpts() []gocni.NamespaceOpts { 176 opts := []gocni.NamespaceOpts{ 177 gocni.WithLabels(map[string]string{ 178 // allow loose CNI argument verification 179 // FYI: https://github.com/containernetworking/cni/issues/560 180 "IgnoreUnknown": "1", 181 }), 182 } 183 184 if m.netOpts.MACAddress != "" { 185 opts = append(opts, gocni.WithArgs("MAC", m.netOpts.MACAddress)) 186 } 187 188 if m.netOpts.IPAddress != "" { 189 opts = append(opts, gocni.WithArgs("IP", m.netOpts.IPAddress)) 190 } 191 192 if m.netOpts.PortMappings != nil { 193 opts = append(opts, gocni.WithCapabilityPortMap(m.netOpts.PortMappings)) 194 } 195 196 return opts 197 }