github.com/cilium/cilium@v1.16.2/pkg/maps/nat/cell.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package nat 5 6 import ( 7 "context" 8 "fmt" 9 10 "github.com/cilium/cilium/pkg/option" 11 "github.com/cilium/cilium/pkg/promise" 12 "github.com/cilium/cilium/pkg/time" 13 "github.com/cilium/cilium/pkg/tuple" 14 15 "github.com/cilium/hive/cell" 16 ) 17 18 // MapDisabled is the expected error will be if map was not created 19 // due to configuration. 20 var MapDisabled = fmt.Errorf("nat map is disabled") 21 22 // Cell exposes global nat maps via Hive. These maps depend on 23 // the final state of EnableNodePort, thus the maps are currently 24 // provided as promises. 25 // TODO: Once we have a way of finalizing this config prior to runtime 26 // we'll want to provide these using bpf.MapOut[T] (GH: #32557) 27 var Cell = cell.Module( 28 "nat-maps", 29 "NAT Maps", 30 cell.Provide(func(lc cell.Lifecycle, cfgPromise promise.Promise[*option.DaemonConfig]) (promise.Promise[NatMap4], promise.Promise[NatMap6]) { 31 var ipv4Nat, ipv6Nat *Map 32 res4, promise4 := promise.New[NatMap4]() 33 res6, promise6 := promise.New[NatMap6]() 34 35 lc.Append(cell.Hook{ 36 OnStart: func(hc cell.HookContext) error { 37 ctx, cancel := context.WithTimeout(context.Background(), time.Second*60) 38 defer cancel() 39 cfg, err := cfgPromise.Await(ctx) 40 if err != nil { 41 return fmt.Errorf("failed to wait for config promise: %w", err) 42 } 43 if !cfg.EnableNodePort { 44 res4.Reject(fmt.Errorf("nat IPv4: %w", MapDisabled)) 45 res6.Reject(fmt.Errorf("nat IPv6: %w", MapDisabled)) 46 return nil 47 } 48 49 ipv4Nat, ipv6Nat = GlobalMaps(cfg.EnableIPv4, 50 cfg.EnableIPv6, true) 51 52 // Maps are still created before DaemonConfig promise is resolved in 53 // daemon.initMaps(...) under the same circumstances 54 // so we just open them here so they can be provided to hive. 55 // 56 // TODO: Refactor ctmap gc Enable() such that it can use the map descriptors from 57 // here so we can move all nat map creation logic into here. 58 // NOTE: This code runs concurrently with startDaemon(), so if any dependency to 59 // daemon having finished endpoint restore, for example, is added, we should 60 // await for an appropriate promise. 61 if cfg.EnableIPv4 { 62 if err := ipv4Nat.Open(); err != nil { 63 return fmt.Errorf("open IPv4 nat map: %w", err) 64 } 65 res4.Resolve(ipv4Nat) 66 } else { 67 res4.Reject(MapDisabled) 68 } 69 if cfg.EnableIPv6 { 70 if err := ipv6Nat.Open(); err != nil { 71 return fmt.Errorf("open IPv6 nat map: %w", err) 72 } 73 res6.Resolve(ipv6Nat) 74 } else { 75 res6.Reject(MapDisabled) 76 } 77 return nil 78 }, 79 OnStop: func(hc cell.HookContext) error { 80 ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) 81 defer cancel() 82 cfg, err := cfgPromise.Await(ctx) 83 if err != nil { 84 return err 85 } 86 if !cfg.EnableNodePort { 87 return nil 88 } 89 90 if ipv4Nat != nil { 91 if err := ipv4Nat.Map.Close(); err != nil { 92 return err 93 } 94 } 95 if ipv6Nat != nil { 96 if err := ipv6Nat.Map.Close(); err != nil { 97 return err 98 } 99 } 100 return nil 101 }, 102 }) 103 104 return promise4, promise6 105 }), 106 ) 107 108 // NatMap4 describes ipv4 nat map behaviors, used for providing map 109 // to hive. 110 type NatMap4 interface { 111 NatMap 112 ApplyBatch4(func([]tuple.TupleKey4, []NatEntry4, int)) (count int, err error) 113 } 114 115 // NatMap6 describes ipv6 nat map behaviors, used for providing map 116 // to hive. 117 type NatMap6 interface { 118 NatMap 119 ApplyBatch6(func([]tuple.TupleKey6, []NatEntry6, int)) (count int, err error) 120 }