github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/hypervisor/metadatad/daemons.go (about) 1 // +build go1.10 2 3 package metadatad 4 5 import ( 6 "fmt" 7 "net" 8 "net/http" 9 "os/exec" 10 "runtime" 11 "strconv" 12 "time" 13 14 "github.com/Cloud-Foundations/Dominator/lib/log" 15 "github.com/Cloud-Foundations/Dominator/lib/log/prefixlogger" 16 "github.com/Cloud-Foundations/Dominator/lib/wsyscall" 17 proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 18 ) 19 20 type statusType struct { 21 namespaceFd int 22 threadId int 23 err error 24 } 25 26 func httpServe(listener net.Listener, handler http.Handler, 27 idleTimeout time.Duration) error { 28 httpServer := &http.Server{Handler: handler, IdleTimeout: idleTimeout} 29 return httpServer.Serve(listener) 30 } 31 32 func (s *server) startServer() error { 33 cmd := exec.Command("ebtables", "-t", "nat", "-F") 34 if output, err := cmd.CombinedOutput(); err != nil { 35 return fmt.Errorf("error running ebtables: %s: %s", err, string(output)) 36 } 37 runtime.LockOSThread() 38 defer runtime.UnlockOSThread() 39 for _, bridge := range s.bridges { 40 if err := s.startServerOnBridge(bridge); err != nil { 41 return err 42 } 43 } 44 return nil 45 } 46 47 func (s *server) startServerOnBridge(bridge net.Interface) error { 48 logger := prefixlogger.New(bridge.Name+": ", s.logger) 49 startChannel := make(chan struct{}) 50 statusChannel := make(chan statusType, 1) 51 go s.createNamespace(startChannel, statusChannel, logger) 52 status := <-statusChannel 53 if status.err != nil { 54 return status.err 55 } 56 if err := createInterface(bridge, status.threadId, logger); err != nil { 57 return err 58 } 59 startChannel <- struct{}{} 60 status = <-statusChannel 61 if status.err != nil { 62 return status.err 63 } 64 subnetChannel := s.manager.MakeSubnetChannel() 65 go s.addSubnets(bridge, status.namespaceFd, subnetChannel, logger) 66 return nil 67 } 68 69 func (s *server) addSubnets(bridge net.Interface, namespaceFd int, 70 subnetChannel <-chan proto.Subnet, logger log.DebugLogger) { 71 logger.Debugf(0, "waiting for subnet updates in namespaceFD=%d\n", 72 namespaceFd) 73 if err := wsyscall.SetNetNamespace(namespaceFd); err != nil { 74 logger.Println(err) 75 return 76 } 77 for subnet := range subnetChannel { 78 addRouteForBridge(bridge, subnet, logger) 79 } 80 } 81 82 func addRouteForBridge(bridge net.Interface, subnet proto.Subnet, 83 logger log.DebugLogger) { 84 if subnet.DisableMetadata { 85 logger.Debugf(0, "metadata service disabled for subnet: %s\n", 86 subnet.Id) 87 return 88 } 89 subnetMask := net.IPMask(subnet.IpMask) 90 subnetAddr := subnet.IpGateway.Mask(subnetMask) 91 addr := subnetAddr.String() 92 mask := fmt.Sprintf("%d.%d.%d.%d", 93 subnetMask[0], subnetMask[1], subnetMask[2], subnetMask[3]) 94 cmd := exec.Command("route", "add", "-net", addr, "netmask", mask, "eth0") 95 if output, err := cmd.CombinedOutput(); err != nil { 96 logger.Printf("error adding route: for subnet: %s: %s/%s: %s: %s", 97 subnet.Id, addr, mask, err, string(output)) 98 } else { 99 logger.Debugf(0, "added route for subnet: %s: %s/%s\n", 100 subnet.Id, addr, mask) 101 } 102 } 103 104 func (s *server) createNamespace(startChannel <-chan struct{}, 105 statusChannel chan<- statusType, logger log.DebugLogger) { 106 namespaceFd, threadId, err := wsyscall.UnshareNetNamespace() 107 if err != nil { 108 statusChannel <- statusType{err: err} 109 return 110 } 111 statusChannel <- statusType{namespaceFd: namespaceFd, threadId: threadId} 112 <-startChannel 113 cmd := exec.Command("ifconfig", "eth0", "169.254.169.254", "netmask", 114 "255.255.255.255", "up") 115 if err := cmd.Run(); err != nil { 116 statusChannel <- statusType{err: err} 117 return 118 } 119 hypervisorListener, err := net.Listen("tcp", 120 fmt.Sprintf("169.254.169.254:%d", s.hypervisorPortNum)) 121 if err != nil { 122 statusChannel <- statusType{err: err} 123 return 124 } 125 metadataListener, err := net.Listen("tcp", "169.254.169.254:80") 126 if err != nil { 127 statusChannel <- statusType{err: err} 128 return 129 } 130 statusChannel <- statusType{namespaceFd: namespaceFd, threadId: threadId} 131 logger.Printf("starting metadata server in thread: %d\n", threadId) 132 go httpServe(hypervisorListener, nil, time.Second*5) 133 httpServe(metadataListener, s, time.Second*5) 134 } 135 136 func createInterface(bridge net.Interface, threadId int, 137 logger log.DebugLogger) error { 138 localName := bridge.Name + "-ll" 139 remoteName := bridge.Name + "-lr" 140 if _, err := net.InterfaceByName(localName); err == nil { 141 exec.Command("ip", "link", "delete", localName).Run() 142 } 143 cmd := exec.Command("ip", "link", "add", localName, "type", "veth", 144 "peer", "name", remoteName) 145 if output, err := cmd.CombinedOutput(); err != nil { 146 return fmt.Errorf("error creating veth for bridge: %s: %s: %s", 147 bridge.Name, err, output) 148 } 149 cmd = exec.Command("ifconfig", localName, "up") 150 if output, err := cmd.CombinedOutput(); err != nil { 151 return fmt.Errorf("error bringing up local interface: %s: %s: %s", 152 localName, err, output) 153 } 154 remoteInterface, err := net.InterfaceByName(remoteName) 155 if err != nil { 156 return err 157 } 158 cmd = exec.Command("ip", "link", "set", remoteName, "netns", 159 strconv.FormatInt(int64(threadId), 10), "name", "eth0") 160 if output, err := cmd.CombinedOutput(); err != nil { 161 return fmt.Errorf("error moving interface to namespace: %s: %s: %s", 162 remoteName, err, output) 163 } 164 cmd = exec.Command("ip", "link", "set", localName, "master", bridge.Name) 165 if output, err := cmd.CombinedOutput(); err != nil { 166 return fmt.Errorf("error adding interface: %s to bridge: %s: %s: %s", 167 localName, bridge.Name, err, output) 168 } 169 hwAddr := remoteInterface.HardwareAddr.String() 170 cmd = exec.Command("ebtables", "-t", "nat", "-A", "PREROUTING", 171 "--logical-in", bridge.Name, "-p", "ip", 172 "--ip-dst", "169.254.0.0/16", "-j", "dnat", "--to-destination", 173 hwAddr) 174 if output, err := cmd.CombinedOutput(); err != nil { 175 return fmt.Errorf( 176 "error adding ebtables dnat to: %s to bridge: %s: %s: %s", 177 hwAddr, bridge.Name, err, output) 178 } 179 logger.Printf("created veth, remote addr: %s\n", hwAddr) 180 return nil 181 }