github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/nfqdatapath/autoport.go (about) 1 package nfqdatapath 2 3 import ( 4 "path/filepath" 5 "sync" 6 "time" 7 8 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/ipsetmanager" 9 "go.aporeto.io/enforcerd/trireme-lib/controller/pkg/pucontext" 10 "go.aporeto.io/enforcerd/trireme-lib/utils/portspec" 11 "go.uber.org/zap" 12 ) 13 14 type readSystemFiles interface { 15 readOpenSockFD(pid string) []string 16 readProcNetTCP() (inodeMap map[string]string, userMap map[string]map[string]bool, err error) 17 getCgroupList() []string 18 listCgroupProcesses(cgroupname string) ([]string, error) 19 } 20 21 type defaultRead struct{} 22 23 var readFiles readSystemFiles 24 var d *defaultRead 25 var lock sync.RWMutex 26 27 func init() { 28 lock.Lock() 29 readFiles = d 30 lock.Unlock() 31 } 32 33 func (d *Datapath) autoPortDiscovery() { 34 for { 35 d.findPorts() 36 time.Sleep(2 * time.Second) 37 } 38 } 39 40 // resync adds new port for the PU and removes the stale ports 41 func (d *Datapath) resync(newPortMap map[string]map[string]bool) { 42 43 for k, vs := range d.puToPortsMap { 44 m := newPortMap[k] 45 46 for v := range vs { 47 if m == nil || !m[v] { 48 err := ipsetmanager.V4().DeletePortFromServerPortSet(k, v) 49 if err != nil { 50 zap.L().Debug("autoPortDiscovery: Delete port set returned error", zap.Error(err)) 51 } 52 err = ipsetmanager.V6().DeletePortFromServerPortSet(k, v) 53 if err != nil { 54 zap.L().Debug("autoPortDiscovery: Delete port set returned error", zap.Error(err)) 55 } 56 // delete the port from contextIDFromTCPPort cache 57 err = d.contextIDFromTCPPort.RemoveStringPorts(v) 58 if err != nil { 59 zap.L().Debug("autoPortDiscovery: can not remove port from cache", zap.Error(err)) 60 } 61 } 62 } 63 } 64 65 for k, vs := range newPortMap { 66 m := d.puToPortsMap[k] 67 for v := range vs { 68 if m == nil || !m[v] { 69 portSpec, err := portspec.NewPortSpecFromString(v, k) 70 if err != nil { 71 continue 72 } 73 d.contextIDFromTCPPort.AddPortSpec(portSpec) 74 err = ipsetmanager.V4().AddPortToServerPortSet(k, v) 75 if err != nil { 76 zap.L().Error("autoPortDiscovery: Failed to add port to portset", zap.String("context", k), zap.String("port", v)) 77 } 78 err = ipsetmanager.V6().AddPortToServerPortSet(k, v) 79 if err != nil { 80 zap.L().Error("autoPortDiscovery: Failed to add port to portset", zap.String("context", k), zap.String("port", v)) 81 } 82 } 83 } 84 } 85 86 d.puToPortsMap = newPortMap 87 } 88 89 var lastRun time.Time 90 91 func (d *Datapath) findPorts() { 92 lock.Lock() 93 defer lock.Unlock() 94 95 // Rate limit this function to run every 5 milliseconds 96 if time.Since(lastRun) <= 5*time.Millisecond { 97 return 98 } 99 100 lastRun = time.Now() 101 102 cgroupList := readFiles.getCgroupList() 103 104 newPUToPortsMap := map[string]map[string]bool{} 105 inodeMap, _, err := readFiles.readProcNetTCP() 106 if err != nil { 107 zap.L().Error("autoPortDiscovery: /proc/net/tcp read failed with error", zap.Error(err)) 108 return 109 } 110 111 for _, cgroupPath := range cgroupList { 112 /* cgroup is also the contextID */ 113 newMap := map[string]bool{} 114 115 cgroup := filepath.Base(cgroupPath) 116 117 // check if a PU exists with that contextID and is marked with auto port 118 pu, err := d.puFromContextID.Get(cgroup) 119 if err != nil { 120 continue 121 } 122 p := pu.(*pucontext.PUContext) 123 124 // we skip AutoPort discovery if it is not enabled 125 if !p.Autoport() { 126 continue 127 } 128 129 procs, err := readFiles.listCgroupProcesses(cgroupPath) 130 if err != nil { 131 zap.L().Warn("autoPortDiscovery: Cgroup processes could not be retrieved", zap.String("cgroupPath", cgroupPath), zap.String("cgroup", cgroup), zap.Error(err)) 132 continue 133 } 134 zap.L().Debug("autoPortDiscovery: processes for cgroup detected", zap.String("cgroupPath", cgroupPath), zap.String("cgroup", cgroup), zap.String("id", p.ID()), zap.Strings("procs", procs)) 135 136 for _, proc := range procs { 137 openSockFDs := readFiles.readOpenSockFD(proc) 138 for _, sock := range openSockFDs { 139 if inodeMap[sock] != "" { 140 newMap[inodeMap[sock]] = true 141 } 142 } 143 } 144 145 newPUToPortsMap[cgroup] = newMap 146 } 147 148 d.resync(newPUToPortsMap) 149 }