@@ -56,10 +56,15 @@ func (m *managedLinux) BuildTaskNetworkConfiguration(
5656 return nil , errors .Wrap (err , "failed to translate network configuration" )
5757 }
5858 case types .NetworkModeHost :
59- netNSs , err = m .buildDefaultNetworkNamespace (taskID )
59+ netNSs , err = m .buildDefaultNetworkNamespaceConfig (taskID )
6060 if err != nil {
6161 return nil , errors .Wrap (err , "failed to create network namespace with host eni" )
6262 }
63+ case "daemon-bridge" :
64+ netNSs , err = m .buildHostDaemonNamespaceConfig (taskID )
65+ if err != nil {
66+ return nil , errors .Wrap (err , "failed to create daemon host namespace" )
67+ }
6368 default :
6469 return nil , errors .New ("invalid network mode: " + string (mode ))
6570 }
@@ -205,7 +210,7 @@ func (m *managedLinux) ConfigureServiceConnect(
205210}
206211
207212// buildDefaultNetworkNamespace return default network namespace of host ENI for host mode.
208- func (m * managedLinux ) buildDefaultNetworkNamespace (taskID string ) ([]* tasknetworkconfig.NetworkNamespace , error ) {
213+ func (m * managedLinux ) buildDefaultNetworkNamespaceConfig (taskID string ) ([]* tasknetworkconfig.NetworkNamespace , error ) {
209214 macAddress , err1 := m .client .GetMetadata (MacResource )
210215 ec2ID , err2 := m .client .GetMetadata (InstanceIDResource )
211216 macToNames , err3 := m .common .interfacesMACToName ()
@@ -306,3 +311,147 @@ func (m *managedLinux) buildDefaultNetworkNamespace(taskID string) ([]*tasknetwo
306311func (m * managedLinux ) HandleHostMode () error {
307312 return nil
308313}
314+
315+ func (m * managedLinux ) buildHostDaemonNamespaceConfig (taskID string ) ([]* tasknetworkconfig.NetworkNamespace , error ) {
316+ macAddress , err1 := m .client .GetMetadata (MacResource )
317+ ec2ID , err2 := m .client .GetMetadata (InstanceIDResource )
318+ macToNames , err3 := m .common .interfacesMACToName ()
319+ if err := goErr .Join (err1 , err2 , err3 ); err != nil {
320+ logger .Error ("Error fetching fields for default ENI" , logger.Fields {
321+ loggerfield .Error : err ,
322+ })
323+ return nil , err
324+ }
325+
326+ hostENI := & ecsacs.ElasticNetworkInterface {
327+ AttachmentArn : aws .String ("arn" ),
328+ Ec2Id : aws .String (ec2ID ),
329+ MacAddress : aws .String (macAddress ),
330+ DomainNameServers : []* string {},
331+ DomainName : []* string {},
332+ PrivateDnsName : aws .String (DefaultArg ),
333+ InterfaceAssociationProtocol : aws .String (DefaultArg ),
334+ Index : aws .Int64 (64 ),
335+ }
336+
337+ ipComp , err := net .DetermineIPCompatibility (m .netlink , macAddress )
338+ if err != nil {
339+ logger .Error ("Failed to determine IP compatibility of host ENI" , logger.Fields {
340+ loggerfield .Error : err ,
341+ })
342+ return nil , err
343+ }
344+
345+ if ! ipComp .IsIPv4Compatible () && ! ipComp .IsIPv6Compatible () {
346+ return nil , errors .New ("Failed to build the default network namespace because the host ENI is neither " +
347+ "IPv4 enabled nor IPv6 enabled" )
348+ }
349+
350+ if ipComp .IsIPv6Compatible () {
351+ privateIpv6 , err1 := m .client .GetMetadata (PrivateIPv6Address )
352+ ipv6SubNet , err2 := m .client .GetMetadata (fmt .Sprintf (IPv6SubNetCidrBlock , macAddress ))
353+ if err := goErr .Join (err1 , err2 ); err != nil {
354+ logger .Error ("Error fetching IPv6 fields for default ENI" , logger.Fields {
355+ loggerfield .Error : err ,
356+ })
357+ return nil , err
358+ }
359+
360+ hostENI .Ipv6Addresses = []* ecsacs.IPv6AddressAssignment {
361+ {
362+ Primary : aws .Bool (true ),
363+ Address : aws .String (privateIpv6 ),
364+ },
365+ }
366+ hostENI .SubnetGatewayIpv6Address = aws .String (ipv6SubNet )
367+ }
368+
369+ if ipComp .IsIPv4Compatible () {
370+ privateIpv4 , err1 := m .client .GetMetadata (PrivateIPv4Address )
371+ ipv4SubNet , err2 := m .client .GetMetadata (fmt .Sprintf (IPv4SubNetCidrBlock , macAddress ))
372+ if err := goErr .Join (err1 , err2 ); err != nil {
373+ logger .Error ("Error fetching IPv4 fields for default ENI" , logger.Fields {
374+ loggerfield .Error : err ,
375+ })
376+ return nil , err
377+ }
378+
379+ hostENI .Ipv4Addresses = []* ecsacs.IPv4AddressAssignment {
380+ {
381+ Primary : aws .Bool (true ),
382+ PrivateAddress : aws .String (privateIpv4 ),
383+ },
384+ }
385+ hostENI .SubnetGatewayIpv4Address = aws .String (ipv4SubNet )
386+ }
387+
388+ netNSName := "host-daemon"
389+ netNSPath := m .common .GetNetNSPath (netNSName )
390+ netInt , err := networkinterface .New (hostENI , DefaultArg , nil , macToNames )
391+ if err != nil {
392+ logger .Error ("Failed to create the network interface" , logger.Fields {
393+ loggerfield .Error : err ,
394+ })
395+ return nil , err
396+ }
397+
398+ netInt .Default = true
399+ netInt .DesiredStatus = status .NetworkReady
400+ netInt .KnownStatus = status .NetworkReady
401+ daemonNamespace , err := tasknetworkconfig .NewNetworkNamespace (netNSName , netNSPath , 0 , nil , netInt )
402+ if err != nil {
403+ logger .Error ("Error building default network namespace for host mode" , logger.Fields {
404+ loggerfield .Error : err ,
405+ })
406+ return nil , err
407+ }
408+ daemonNamespace .KnownState = status .NetworkReady
409+ daemonNamespace .DesiredState = status .NetworkReady
410+ return []* tasknetworkconfig.NetworkNamespace {daemonNamespace }, nil
411+ }
412+
413+ func (m * managedLinux ) configureDaemonNetNS (ctx context.Context , taskID string , netNS * tasknetworkconfig.NetworkNamespace ) error {
414+ var err error
415+ if netNS .DesiredState == status .NetworkDeleted {
416+ return errors .New ("invalid transition state encountered: " + netNS .DesiredState .String ())
417+ }
418+
419+ // Create the network namespace and setup DNS configuration within the netns.
420+ // This has to happen before any CNI plugin is executed.
421+ if netNS .KnownState == status .NetworkNone &&
422+ netNS .DesiredState == status .NetworkReadyPull {
423+
424+ logger .Debug ("Creating netns: " + netNS .Path )
425+ // Create network namespace on the host.
426+ err = m .CreateNetNS (netNS .Path )
427+ if err != nil {
428+ return err
429+ }
430+
431+ logger .Debug ("Creating DNS config files" )
432+
433+ // Create necessary DNS config files for the netns.
434+ err = m .CreateDNSConfig (taskID , netNS )
435+ if err != nil {
436+ return err
437+ }
438+ }
439+
440+ // Create MI-Bridge
441+ var cniNetConf []ecscni.PluginConfig
442+ cniNetConf = append (cniNetConf , createDaemonBridgePluginConfig (netNS .Path ))
443+ add := true
444+
445+ _ , err = m .common .executeCNIPlugin (ctx , add , cniNetConf ... )
446+ if err != nil {
447+ err = errors .Wrap (err , "failed to setup deamon network namespace bridge" )
448+ }
449+
450+ return err
451+ }
452+
453+ // ConfigureDaemonNetNS will create a network namespace using the host ENI and host dns configuration.
454+ // It will contain a loopback interface and a bridge to the internal ECS subnet.
455+ func (m * managedLinux ) ConfigureDaemonNetNS (netNS * tasknetworkconfig.NetworkNamespace ) error {
456+ return m .configureDaemonNetNS (context .Background (), netNS .Path , netNS )
457+ }
0 commit comments