func NewNetlinkMonitor(g canvas.Graph, r *Renderer, modules *bpf.BpfTable) (res *NetlinkMonitor, err error) { nlmon := &NetlinkMonitor{ updates: make(chan netlink.LinkUpdate), done: make(chan struct{}), flush: make(chan struct{}), nodes: make(map[int]*ExtInterface), g: g, r: r, modules: modules, } err = netlink.LinkSubscribe(nlmon.updates, nlmon.done) defer func() { if err != nil { nlmon.Close() } }() if err != nil { return } links, err := netlink.LinkList() if err != nil { return } for _, link := range links { nlmon.handleNewlink(link) } Debug.Println("NewNetlinkMonitor DONE") go nlmon.ParseLinkUpdates() res = nlmon return }
// monitorPort watches for link flap events func (vl *VlanBridge) monitorPort(ifname string) { vl.nlCloser = make(chan struct{}) updChan := make(chan netlink.LinkUpdate) if err := netlink.LinkSubscribe(updChan, vl.nlCloser); err != nil { log.Errorf("Error listening on netlink: %v", err) return } go vl.handlePortUp(updChan, ifname) }
func ensureInterface(ifaceName string) (*net.Interface, error) { if iface, err := findInterface(ifaceName); err == nil { return iface, nil } ch := make(chan netlink.LinkUpdate) done := make(chan struct{}) defer close(done) if err := netlink.LinkSubscribe(ch, done); err != nil { return nil, err } for update := range ch { if ifaceName == update.Link.Attrs().Name && update.IfInfomsg.Flags&syscall.IFF_UP != 0 { break } } iface, err := findInterface(ifaceName) return iface, err }
func ensureInterface(ifaceName string) (*net.Interface, error) { ch := make(chan netlink.LinkUpdate) // NB: We do not supply (and eventually close) a 'done' channel // here since that can cause incorrect file descriptor // re-usage. See https://github.com/weaveworks/weave/issues/2120 if err := netlink.LinkSubscribe(ch, nil); err != nil { return nil, err } // check for currently-existing interface after subscribing, to avoid race if iface, err := findInterface(ifaceName); err == nil { return iface, nil } for update := range ch { if ifaceName == update.Link.Attrs().Name && update.IfInfomsg.Flags&syscall.IFF_UP != 0 { break } } iface, err := findInterface(ifaceName) return iface, err }
// This function should be put into the main process or somewhere that can be // use to init the network namespace trap. func setupNetworkNsTrap(netNs2Containerd func(supervisor.NetlinkUpdate)) { // Subscribe for links change event chLink := make(chan netlink.LinkUpdate) doneLink := make(chan struct{}) defer close(doneLink) if err := netlink.LinkSubscribe(chLink, doneLink); err != nil { glog.Fatal(err) } // Subscribe for addresses change event chAddr := make(chan netlink.AddrUpdate) doneAddr := make(chan struct{}) defer close(doneAddr) if err := netlink.AddrSubscribe(chAddr, doneAddr); err != nil { glog.Fatal(err) } // Subscribe for route change event chRoute := make(chan netlink.RouteUpdate) doneRoute := make(chan struct{}) defer close(doneRoute) if err := netlink.RouteSubscribe(chRoute, doneRoute); err != nil { glog.Fatal(err) } for { select { case updateLink := <-chLink: handleLink(updateLink, netNs2Containerd) case updateAddr := <-chAddr: handleAddr(updateAddr, netNs2Containerd) case updateRoute := <-chRoute: handleRoute(updateRoute, netNs2Containerd) } } }
func main() { var err error var buf []byte var data map[string]string if *flagVersion { fmt.Printf("%s build %s\n", Version, BuildTime) os.Exit(0) } if *flagInstall { if err = installService(); err != nil { log.Fatalf("failed to install service: %s\n", err.Error()) os.Exit(1) } os.Exit(0) } l, err = syslog.Dial("", "", syslog.LOG_DAEMON|syslog.LOG_INFO, filepath.Base(os.Args[0])) if err != nil { log.Fatalf("Failed to connect to syslog: %s\n", err.Error()) os.Exit(1) } defer l.Close() for _, fname := range []string{"svirtnet.yml", "cloudmeta.yaml"} { if buf, err = ioutil.ReadFile(filepath.Join("/etc", fname)); err == nil { if err = yaml.Unmarshal(buf, &data); err == nil { if val, ok := data["interface"]; ok && val != "" { master_iface = val } if val, ok := data["ipset_support"]; ok { if val == "false" { ipset_support = false } } if val, ok := data["xmlnsuri"]; ok && val != "" { xmlnsuri = val } } } } l.Info("ListenAndServeTCPv4") go ListenAndServeTCPv4() lnkupdate := make(chan netlink.LinkUpdate) lnkdone := make(chan struct{}) err = netlink.LinkSubscribe(lnkupdate, lnkdone) if err != nil { l.Err(err.Error()) os.Exit(1) } defer close(lnkdone) ifaces, err := net.Interfaces() if err != nil { l.Err(err.Error()) os.Exit(1) } for _, iface := range ifaces { name := iface.Name l.Info("Check iface " + name) if !strings.HasPrefix(name, "tap") { continue } servers.Lock() if _, ok := servers.Get(name[3:]); !ok { s := &Server{name: name[3:]} servers.Add(name[3:], s) l.Info(name[3:] + " start serving") wait := make(chan struct{}) go func() { defer func() { if r := recover(); r != nil { err, ok := r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } fmt.Printf(err.Error()) } }() if err := s.Start(); err != nil { panic(err) } close(wait) }() <-wait } servers.Unlock() } sg := make(chan os.Signal, 1) signal.Notify(sg, unix.SIGINT, unix.SIGQUIT, unix.SIGTERM, unix.SIGHUP) tk := time.NewTicker(2 * time.Minute) defer tk.Stop() for { select { case <-tk.C: servers.Lock() for _, s := range servers.List() { t := time.Now().Add(5 * time.Minute) if !s.downtime.IsZero() && t.After(s.downtime) { servers.Del(s.name) } } servers.Unlock() case signame := <-sg: fmt.Println("Got signal:", signame) switch signame { case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM: servers.Lock() for _, s := range servers.List() { wait := make(chan struct{}) go func() { defer func() { if r := recover(); r != nil { err, ok := r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } fmt.Printf(err.Error()) } }() if err := s.Stop(false); err != nil { panic(err) } close(wait) }() <-wait servers.Del(s.name) } servers.Unlock() os.Exit(0) } case msg := <-lnkupdate: if !strings.HasPrefix(msg.Attrs().Name, "tap") { continue } switch msg.Header.Type { case unix.RTM_NEWLINK: if msg.Change == unix.IFF_UP { // fmt.Printf("newlink %#+v\n", msg) name := msg.Attrs().Name[3:] servers.Lock() if s, ok := servers.Get(name); !ok { s = &Server{name: name} servers.Add(name, s) go func() { defer func() { if r := recover(); r != nil { err, ok := r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } fmt.Printf(err.Error()) } }() if err := s.Start(); err != nil { panic(err) } }() } else { go func() { defer func() { if r := recover(); r != nil { err, ok := r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } fmt.Printf(err.Error()) } }() if err := s.Start(); err != nil { panic(err) } }() } servers.Unlock() } case unix.RTM_DELLINK: // if msg.Change == unix.IFF_UP { // fmt.Printf("dellink %#+v\n", msg) servers.Lock() name := msg.Attrs().Name[3:] if s, ok := servers.Get(name); ok { go func() { defer func() { if r := recover(); r != nil { err, ok := r.(error) if !ok { err = fmt.Errorf("pkg: %v", r) } fmt.Printf(err.Error()) } }() if err := s.Stop(true); err != nil { panic(err) } }() } servers.Unlock() // } } } } }
func TestInterfaces(t *testing.T) { hoverServer := hover.NewServer() defer hoverServer.Close() hover := httptest.NewServer(hoverServer.Handler()) defer hover.Close() upstream := httptest.NewServer(newMockUpstream()) defer upstream.Close() g, err := NewServer(upstream.URL, hover.URL) if err != nil { t.Fatal(err) } srv := httptest.NewServer(g.Handler()) defer srv.Close() // launch one policy dataplane testOne(t, testCase{ url: srv.URL + "/policies/", body: strings.NewReader(`{"resolved-policy-uri": "` + basicResolvedPolicyUri + `"}`), code: http.StatusOK, }, nil) // set up docker prereqs runTestCommand(t, "bash -ex", strings.NewReader(dockerSetup)) // monitor for netlink updates to find docker veth ch, done := make(chan netlink.LinkUpdate), make(chan struct{}) defer close(done) if err := netlink.LinkSubscribe(ch, done); err != nil { t.Error(err) } id1, id2 := "TestInterfaces-1", "TestInterfaces-2" // spawn one test server process runTestCommand(t, "docker run --name="+id1+" -d moutten/iperf", nil) defer runCommand("docker rm -f "+id1, nil) link1 := gatherOneLink(t, ch) testOne(t, testCase{ url: fmt.Sprintf("%s/modules/host/interfaces/%s/policies/", hover.URL, link1.Attrs().Name), body: strings.NewReader(fmt.Sprintf(`{"module": "%s"}`, g.dataplane.Id())), code: http.StatusOK, }, nil) // find the ip of the test server ip1 := runTestCommand(t, "docker inspect -f {{.NetworkSettings.IPAddress}} "+id1, nil) // start a test client clientCmd, clientStdin, clientOutput := startCommand(t, "docker run -i --name="+id2+" --entrypoint /bin/sh moutten/iperf -ex") defer runCommand("docker rm -f "+id2, nil) link2 := gatherOneLink(t, ch) ip2 := runTestCommand(t, "docker inspect -f {{.NetworkSettings.IPAddress}} "+id2, nil) Debug.Printf("ip2=%s\n", ip2) testOne(t, testCase{ url: fmt.Sprintf("%s/modules/host/interfaces/%s/policies/", hover.URL, link2.Attrs().Name), body: strings.NewReader(fmt.Sprintf(`{"module": "%s"}`, g.dataplane.Id())), code: http.StatusOK, }, nil) if err := g.dataplane.AddEndpoint(ip1, "pepsi", "webservers"); err != nil { t.Fatal(err) } if err := g.dataplane.AddEndpoint(ip2, "pepsi", "clients"); err != nil { t.Fatal(err) } Debug.Println("Endpoints:") for endpoint := range g.dataplane.Endpoints() { Debug.Printf("%v\n", *endpoint) } clientStdin.Write([]byte("iperf -t 2 -c " + ip1 + "\n")) clientStdin.Close() if err := clientCmd.Wait(); err != nil { Error.Print(clientOutput.String()) t.Fatal(err) } Debug.Print(clientOutput.String()) }