github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/edgemesh/pkg/listener/listener.go (about) 1 package listener 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net" 7 "strconv" 8 "strings" 9 "sync" 10 "syscall" 11 "unsafe" 12 13 "github.com/kubeedge/beehive/pkg/core/model" 14 v1 "k8s.io/api/core/v1" 15 "k8s.io/klog" 16 17 "github.com/kubeedge/kubeedge/common/constants" 18 "github.com/kubeedge/kubeedge/edge/pkg/metamanager/client" 19 "github.com/kubeedge/kubeedge/edgemesh/pkg/cache" 20 "github.com/kubeedge/kubeedge/edgemesh/pkg/config" 21 "github.com/kubeedge/kubeedge/edgemesh/pkg/protocol" 22 "github.com/kubeedge/kubeedge/edgemesh/pkg/protocol/http" 23 ) 24 25 type SvcDescription struct { 26 sync.RWMutex 27 SvcPortsByIP map[string]string // key: fakeIP, value: SvcPorts 28 IPBySvc map[string]string // key: svcName.svcNamespace, value: fakeIP 29 } 30 31 type sockAddr struct { 32 family uint16 33 data [14]byte 34 } 35 36 const ( 37 defaultNetworkPrefix = "9.251." 38 maxPoolSize = 65534 39 40 SO_ORIGINAL_DST = 80 41 ) 42 43 var ( 44 svcDesc *SvcDescription 45 unused []string 46 indexOfPool uint16 47 metaClient client.CoreInterface 48 once sync.Once 49 ) 50 51 func Init() { 52 once.Do(func() { 53 unused = make([]string, 0) 54 svcDesc = &SvcDescription{ 55 SvcPortsByIP: make(map[string]string), 56 IPBySvc: make(map[string]string), 57 } 58 // init meta client 59 metaClient = client.New() 60 // init fakeIP pool 61 initPool() 62 // recover listener meta from edge db 63 recoverFromDB() 64 }) 65 } 66 67 // getSubNet converts uint16 to "uint8.uint8" 68 func getSubNet(subNet uint16) string { 69 arg1 := uint64(subNet & 0x00ff) 70 arg2 := uint64((subNet & 0xff00) >> 8) 71 return strconv.FormatUint(arg2, 10) + "." + strconv.FormatUint(arg1, 10) 72 } 73 74 // initPool initializes fakeIP pool with size of 256 75 func initPool() { 76 // avoid 0.0 77 indexOfPool = uint16(1) 78 for ; indexOfPool <= uint16(255); indexOfPool++ { 79 ip := defaultNetworkPrefix + getSubNet(indexOfPool) 80 unused = append(unused, ip) 81 } 82 } 83 84 // expandPool expands fakeIP pool, each time with size of 256 85 func expandPool() { 86 end := indexOfPool + uint16(255) 87 for ; indexOfPool <= end; indexOfPool++ { 88 // avoid 255.255 89 if indexOfPool > maxPoolSize { 90 return 91 } 92 ip := defaultNetworkPrefix + getSubNet(indexOfPool) 93 // if ip is not used, append it to unused 94 if svcDesc.getSvcPorts(ip) == "" { 95 unused = append(unused, ip) 96 } 97 } 98 } 99 100 // reserveIp reserves used fakeIP 101 func reserveIP(ip string) { 102 for i, value := range unused { 103 if ip == value { 104 unused = append(unused[:i], unused[i+1:]...) 105 break 106 } 107 } 108 } 109 110 // recoverFromDB gets fakeIP from edge db and assigns them to services after EdgeMesh starts 111 func recoverFromDB() { 112 svcs, err := metaClient.Services("all").ListAll() 113 if err != nil { 114 klog.Errorf("[EdgeMesh] list all services from edge db error: %v", err) 115 return 116 } 117 for _, svc := range svcs { 118 svcName := svc.Namespace + "." + svc.Name 119 value, err := metaClient.Listener().Get(svcName) 120 if err != nil { 121 klog.Errorf("[EdgeMesh] get listener of svc %s from edge db error: %v", svcName, err) 122 continue 123 } 124 ip, ok := value.([]string) 125 if !ok { 126 klog.Errorf("[EdgeMesh] value %+v is not a string", value) 127 continue 128 } 129 if len(ip) == 0 { 130 svcPorts := getSvcPorts(svc, svcName) 131 addServer(svcName, svcPorts) 132 klog.Warningf("[EdgeMesh] listener %s from edge db with no ip", svcName) 133 continue 134 } 135 svcPorts := getSvcPorts(svc, svcName) 136 reserveIP(ip[0][1 : len(ip[0])-1]) 137 svcDesc.set(svcName, ip[0][1:len(ip[0])-1], svcPorts) 138 klog.Infof("[EdgeMesh] get listener %s from edge db: %s", svcName, ip[0][1:len(ip[0])-1]) 139 } 140 } 141 142 // Start starts the EdgeMesh listener 143 func Start() { 144 for { 145 conn, err := config.Config.Listener.Accept() 146 if err != nil { 147 klog.Warningf("[EdgeMesh] get tcp conn error: %v", err) 148 continue 149 } 150 ip, port, err := realServerAddress(&conn) 151 if err != nil { 152 klog.Warningf("[EdgeMesh] get real destination of tcp conn error: %v", err) 153 conn.Close() 154 continue 155 } 156 proto, err := newProtocolFromSock(ip, port, conn) 157 if err != nil { 158 klog.Warningf("[EdgeMesh] get protocol from sock err: %v", err) 159 conn.Close() 160 continue 161 } 162 163 go proto.Process() 164 } 165 } 166 167 // newProtocolFromSock returns a protocol.Protocol interface if the ip is in proxy list 168 func newProtocolFromSock(ip string, port int, conn net.Conn) (proto protocol.Protocol, err error) { 169 svcPorts := svcDesc.getSvcPorts(ip) 170 protoName, svcName := getProtocol(svcPorts, port) 171 if protoName == "" || svcName == "" { 172 return nil, fmt.Errorf("protocol name: %s or svcName: %s is invalid", protoName, svcName) 173 } 174 175 svcNameSets := strings.Split(svcName, ".") 176 if len(svcNameSets) != 2 { 177 return nil, fmt.Errorf("invalid length %d after splitting svc name %s", len(svcNameSets), svcName) 178 } 179 namespace := svcNameSets[0] 180 name := svcNameSets[1] 181 182 switch protoName { 183 case "http": 184 proto = &http.HTTP{ 185 Conn: conn, 186 SvcName: name, 187 SvcNamespace: namespace, 188 Port: port, 189 } 190 err = nil 191 default: 192 proto = nil 193 err = fmt.Errorf("protocol: %s is not supported yet", protoName) 194 } 195 return 196 } 197 198 // getProtocol gets protocol name 199 func getProtocol(svcPorts string, port int) (string, string) { 200 var protoName string 201 sub := strings.Split(svcPorts, "|") 202 n := len(sub) 203 if n < 2 { 204 return "", "" 205 } 206 svcName := sub[n-1] 207 208 pstr := strconv.Itoa(port) 209 if pstr == "" { 210 return "", "" 211 } 212 for _, s := range sub { 213 if strings.Contains(s, pstr) { 214 protoName = strings.Split(s, ",")[0] 215 break 216 } 217 } 218 return protoName, svcName 219 } 220 221 // realServerAddress returns an intercepted connection's original destination. 222 func realServerAddress(conn *net.Conn) (string, int, error) { 223 tcpConn, ok := (*conn).(*net.TCPConn) 224 if !ok { 225 return "", -1, fmt.Errorf("not a TCPConn") 226 } 227 228 file, err := tcpConn.File() 229 if err != nil { 230 return "", -1, err 231 } 232 233 // To avoid potential problems from making the socket non-blocking. 234 tcpConn.Close() 235 *conn, err = net.FileConn(file) 236 if err != nil { 237 return "", -1, err 238 } 239 240 defer file.Close() 241 fd := file.Fd() 242 243 var addr sockAddr 244 size := uint32(unsafe.Sizeof(addr)) 245 err = getSockOpt(int(fd), syscall.SOL_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&addr)), &size) 246 if err != nil { 247 return "", -1, err 248 } 249 250 var ip net.IP 251 switch addr.family { 252 case syscall.AF_INET: 253 ip = addr.data[2:6] 254 default: 255 return "", -1, fmt.Errorf("unrecognized address family") 256 } 257 258 port := int(addr.data[0])<<8 + int(addr.data[1]) 259 syscall.SetNonblock(int(fd), true) 260 261 return ip.String(), port, nil 262 } 263 264 func getSockOpt(s int, level int, name int, val uintptr, vallen *uint32) (err error) { 265 _, _, e1 := syscall.Syscall6(syscall.SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0) 266 if e1 != 0 { 267 err = e1 268 } 269 return 270 } 271 272 // filterResourceTypeService implements msg filter for "Service" and "ServiceList" resource 273 func filterResourceTypeService(msg model.Message) []v1.Service { 274 svcs := make([]v1.Service, 0) 275 content, err := json.Marshal(msg.GetContent()) 276 if err != nil || len(content) == 0 { 277 return svcs 278 } 279 switch getResourceType(msg.GetResource()) { 280 case constants.ResourceTypeService: 281 s, err := handleServiceMessage(content) 282 if err != nil { 283 break 284 } 285 svcs = append(svcs, *s) 286 case constants.ResourceTypeServiceList: 287 ss, err := handleServiceListMessage(content) 288 if err != nil { 289 break 290 } 291 svcs = append(svcs, ss...) 292 default: 293 break 294 } 295 296 return svcs 297 } 298 299 func getSvcPorts(svc v1.Service, svcName string) string { 300 svcPorts := "" 301 for _, p := range svc.Spec.Ports { 302 pro := strings.Split(p.Name, "-") 303 sub := fmt.Sprintf("%s,%d,%d|", pro[0], p.Port, p.TargetPort.IntVal) 304 svcPorts = svcPorts + sub 305 } 306 svcPorts += svcName 307 return svcPorts 308 } 309 310 // MsgProcess processes messages from metaManager 311 func MsgProcess(msg model.Message) { 312 // process services 313 if svcs := filterResourceTypeService(msg); len(svcs) != 0 { 314 klog.Infof("[EdgeMesh] %s services: %d resource: %s", msg.GetOperation(), len(svcs), msg.Router.Resource) 315 for _, svc := range svcs { 316 svcName := svc.Namespace + "." + svc.Name 317 svcPorts := getSvcPorts(svc, svcName) 318 switch msg.GetOperation() { 319 case "insert": 320 cache.GetMeshCache().Add("service"+"."+svcName, &svc) 321 klog.Infof("[EdgeMesh] insert svc %s.%s into cache", svc.Namespace, svc.Name) 322 addServer(svcName, svcPorts) 323 case "update": 324 cache.GetMeshCache().Add("service"+"."+svcName, &svc) 325 klog.Infof("[EdgeMesh] update svc %s.%s in cache", svc.Namespace, svc.Name) 326 updateServer(svcName, svcPorts) 327 case "delete": 328 cache.GetMeshCache().Remove("service" + "." + svcName) 329 klog.Infof("[EdgeMesh] delete svc %s.%s from cache", svc.Namespace, svc.Name) 330 delServer(svcName) 331 default: 332 klog.Warningf("[EdgeMesh] invalid %s operation on services", msg.GetOperation()) 333 } 334 } 335 return 336 } 337 // process pods 338 if getResourceType(msg.GetResource()) == model.ResourceTypePodlist { 339 klog.Infof("[EdgeMesh] %s podlist, resource: %s", msg.GetOperation(), msg.Router.Resource) 340 pods := make([]v1.Pod, 0) 341 content, err := json.Marshal(msg.GetContent()) 342 if err != nil { 343 klog.Errorf("[EdgeMesh] marshal podlist msg content err: %v", err) 344 return 345 } 346 pods, err = handlePodListMessage(content) 347 if err != nil { 348 return 349 } 350 podListName := getResourceName(msg.GetResource()) 351 podListNamespace := getResourceNamespace(msg.GetResource()) 352 switch msg.GetOperation() { 353 case "insert", "update": 354 cache.GetMeshCache().Add("pods"+"."+podListNamespace+"."+podListName, pods) 355 klog.Infof("[EdgeMesh] insert/update pods %s.%s into cache", podListNamespace, podListName) 356 case "delete": 357 cache.GetMeshCache().Remove("pods" + "." + podListNamespace + "." + podListName) 358 klog.Infof("[EdgeMesh] delete pods %s.%s from cache", podListNamespace, podListName) 359 default: 360 klog.Warningf("[EdgeMesh] invalid %s operation on podlist", msg.GetOperation()) 361 } 362 } 363 return 364 } 365 366 // addServer adds a server 367 func addServer(svcName, svcPorts string) { 368 ip := svcDesc.getIP(svcName) 369 if ip != "" { 370 svcDesc.set(svcName, ip, svcPorts) 371 return 372 } else { 373 if len(unused) == 0 { 374 // try to expand 375 expandPool() 376 if len(unused) == 0 { 377 klog.Warningf("[EdgeMesh] insufficient fake IP !!") 378 return 379 } 380 } 381 ip = unused[0] 382 unused = unused[1:] 383 } 384 svcDesc.set(svcName, ip, svcPorts) 385 err := metaClient.Listener().Add(svcName, ip) 386 if err != nil { 387 klog.Errorf("[EdgeMesh] add listener %s to edge db error: %v", svcName, err) 388 return 389 } 390 return 391 } 392 393 // updateServer updates a server 394 func updateServer(svcName, svcPorts string) { 395 ip := svcDesc.getIP(svcName) 396 if ip == "" { 397 if len(unused) == 0 { 398 // try to expand 399 expandPool() 400 if len(unused) == 0 { 401 klog.Warningf("[EdgeMesh] insufficient fake IP !!") 402 return 403 } 404 } 405 ip = unused[0] 406 unused = unused[1:] 407 err := metaClient.Listener().Add(svcName, ip) 408 if err != nil { 409 klog.Errorf("[EdgeMesh] add listener %s to edge db error: %v", svcName, err) 410 } 411 } 412 svcDesc.set(svcName, ip, svcPorts) 413 } 414 415 // delServer deletes a server 416 func delServer(svcName string) { 417 ip := svcDesc.getIP(svcName) 418 if ip == "" { 419 return 420 } 421 svcDesc.del(svcName, ip) 422 err := metaClient.Listener().Del(svcName) 423 if err != nil { 424 klog.Errorf("[EdgeMesh] delete listener from edge db error: %v", err) 425 } 426 // recycling fakeIP 427 unused = append(unused, ip) 428 } 429 430 // handleServiceMessage converts bytes to k8s service meta 431 func handleServiceMessage(content []byte) (*v1.Service, error) { 432 var s v1.Service 433 err := json.Unmarshal(content, &s) 434 if err != nil { 435 klog.Errorf("[EdgeMesh] unmarshal message to k8s service failed, err: %v", err) 436 return nil, err 437 } 438 return &s, nil 439 } 440 441 // handleServiceListMessage converts bytes to k8s service list meta 442 func handleServiceListMessage(content []byte) ([]v1.Service, error) { 443 var ss []v1.Service 444 err := json.Unmarshal(content, &ss) 445 if err != nil { 446 klog.Errorf("[EdgeMesh] unmarshal message to k8s service list failed, err: %v", err) 447 return nil, err 448 } 449 return ss, nil 450 } 451 452 // handlePodListMessage converts bytes to k8s pod list meta 453 func handlePodListMessage(content []byte) ([]v1.Pod, error) { 454 var pp []v1.Pod 455 err := json.Unmarshal(content, &pp) 456 if err != nil { 457 klog.Errorf("[EdgeMesh] unmarshal message to k8s pod list failed, err: %v", err) 458 return nil, err 459 } 460 return pp, nil 461 } 462 463 // getResourceType returns the resource type as a string 464 func getResourceType(resource string) string { 465 str := strings.Split(resource, "/") 466 if len(str) == 3 { 467 return str[1] 468 } else if len(str) == 5 { 469 return str[3] 470 } else { 471 return resource 472 } 473 } 474 475 // getResourceName returns the resource name as a string 476 func getResourceName(resource string) string { 477 str := strings.Split(resource, "/") 478 if len(str) == 3 { 479 return str[2] 480 } else if len(str) == 5 { 481 return str[4] 482 } else { 483 return resource 484 } 485 } 486 487 // getResourceNamespace returns the resource namespace as a string 488 func getResourceNamespace(resource string) string { 489 str := strings.Split(resource, "/") 490 if len(str) == 3 { 491 return str[0] 492 } else if len(str) == 5 { 493 return str[2] 494 } else { 495 return resource 496 } 497 } 498 499 // set is a thread-safe operation to add to map 500 func (sd *SvcDescription) set(svcName, ip, svcPorts string) { 501 sd.Lock() 502 defer sd.Unlock() 503 sd.IPBySvc[svcName] = ip 504 sd.SvcPortsByIP[ip] = svcPorts 505 } 506 507 // del is a thread-safe operation to del from map 508 func (sd *SvcDescription) del(svcName, ip string) { 509 sd.Lock() 510 defer sd.Unlock() 511 delete(sd.IPBySvc, svcName) 512 delete(sd.SvcPortsByIP, ip) 513 } 514 515 // getIP is a thread-safe operation to get from map 516 func (sd *SvcDescription) getIP(svcName string) string { 517 sd.RLock() 518 defer sd.RUnlock() 519 ip := sd.IPBySvc[svcName] 520 return ip 521 } 522 523 // getSvcPorts is a thread-safe operation to get from map 524 func (sd *SvcDescription) getSvcPorts(ip string) string { 525 sd.RLock() 526 defer sd.RUnlock() 527 svcPorts := sd.SvcPortsByIP[ip] 528 return svcPorts 529 } 530 531 // GetServiceServer returns the proxy IP by given service name 532 func GetServiceServer(svcName string) string { 533 ip := svcDesc.getIP(svcName) 534 return ip 535 }