func (rb *HostgwBackend) handleSubnetEvents(batch []subnet.Event) { for _, evt := range batch { switch evt.Type { case subnet.SubnetAdded: log.Infof("Subnet added: %v via %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP) if evt.Lease.Attrs.BackendType != "host-gw" { log.Warningf("Ignoring non-host-gw subnet: type=%v", evt.Lease.Attrs.BackendType) continue } route := netlink.Route{ Dst: evt.Lease.Subnet.ToIPNet(), Gw: evt.Lease.Attrs.PublicIP.ToIP(), LinkIndex: rb.extIface.Index, } if rb.extIaddr.Equal(route.Gw) { continue } if err := netlink.RouteAdd(&route); err != nil { log.Errorf("Error adding route to %v via %v: %v", evt.Lease.Subnet, evt.Lease.Attrs.PublicIP, err) continue } rb.addToRouteList(route) case subnet.SubnetRemoved: log.Info("Subnet removed: ", evt.Lease.Subnet) if evt.Lease.Attrs.BackendType != "host-gw" { log.Warningf("Ignoring non-host-gw subnet: type=%v", evt.Lease.Attrs.BackendType) continue } route := netlink.Route{ Dst: evt.Lease.Subnet.ToIPNet(), Gw: evt.Lease.Attrs.PublicIP.ToIP(), LinkIndex: rb.extIface.Index, } if err := netlink.RouteDel(&route); err != nil { log.Errorf("Error deleting route to %v: %v", evt.Lease.Subnet, err) continue } rb.removeFromRouteList(route) default: log.Error("Internal error: unknown event type: ", int(evt.Type)) } } }
func (vb *VXLANBackend) handleInitialSubnetEvents(batch []subnet.Event) error { log.Infof("Handling initial subnet events") fdbTable, err := vb.dev.GetL2List() if err != nil { return fmt.Errorf("Error fetching L2 table: %v", err) } for _, fdbEntry := range fdbTable { log.Infof("fdb already populated with: %s %s ", fdbEntry.IP, fdbEntry.HardwareAddr) } evtMarker := make([]bool, len(batch)) leaseAttrsList := make([]vxlanLeaseAttrs, len(batch)) fdbEntryMarker := make([]bool, len(fdbTable)) for i, evt := range batch { if evt.Lease.Attrs.BackendType != "vxlan" { log.Warningf("Ignoring non-vxlan subnet: type=%v", evt.Lease.Attrs.BackendType) evtMarker[i] = true continue } if err := json.Unmarshal(evt.Lease.Attrs.BackendData, &leaseAttrsList[i]); err != nil { log.Error("Error decoding subnet lease JSON: ", err) evtMarker[i] = true continue } for j, fdbEntry := range fdbTable { if evt.Lease.Attrs.PublicIP.ToIP().Equal(fdbEntry.IP) && bytes.Equal([]byte(leaseAttrsList[i].VtepMAC), []byte(fdbEntry.HardwareAddr)) { evtMarker[i] = true fdbEntryMarker[j] = true break } } vb.rts.set(evt.Lease.Subnet, net.HardwareAddr(leaseAttrsList[i].VtepMAC)) } for j, marker := range fdbEntryMarker { if !marker && fdbTable[j].IP != nil { err := vb.dev.DelL2(neigh{IP: ip.FromIP(fdbTable[j].IP), MAC: fdbTable[j].HardwareAddr}) if err != nil { log.Error("Delete L2 failed: ", err) } } } for i, marker := range evtMarker { if !marker { err := vb.dev.AddL2(neigh{IP: batch[i].Lease.Attrs.PublicIP, MAC: net.HardwareAddr(leaseAttrsList[i].VtepMAC)}) if err != nil { log.Error("Add L2 failed: ", err) } } } return nil }
func (m *Manager) watchNetworks() { wg := sync.WaitGroup{} defer wg.Wait() events := make(chan []subnet.Event) wg.Add(1) go func() { subnet.WatchNetworks(m.ctx, m.sm, events) wg.Done() }() // skip over the initial snapshot <-events for { select { case <-m.ctx.Done(): return case evtBatch := <-events: for _, e := range evtBatch { netname := e.Network if !m.isNetAllowed(netname) { log.Infof("Network %q is not allowed", netname) continue } switch e.Type { case subnet.EventAdded: n := NewNetwork(m.ctx, m.sm, m.bm, netname, m.ipMasq) if err := m.addNetwork(n); err != nil { log.Infof("Network %q: %v", netname, err) continue } log.Infof("Network added: %v", netname) wg.Add(1) go func() { m.runNetwork(n) wg.Done() }() case subnet.EventRemoved: log.Infof("Network removed: %v", netname) n, ok := m.getNetwork(netname) if !ok { log.Warningf("Network %v unknown; ignoring EventRemoved", netname) continue } n.Cancel() } } } } }
func (vb *VXLANBackend) handleSubnetEvents(batch []subnet.Event) { for _, evt := range batch { switch evt.Type { case subnet.EventAdded: log.Info("Subnet added: ", evt.Lease.Subnet) if evt.Lease.Attrs.BackendType != "vxlan" { log.Warningf("Ignoring non-vxlan subnet: type=%v", evt.Lease.Attrs.BackendType) continue } var attrs vxlanLeaseAttrs if err := json.Unmarshal(evt.Lease.Attrs.BackendData, &attrs); err != nil { log.Error("Error decoding subnet lease JSON: ", err) continue } vb.rts.set(evt.Lease.Subnet, net.HardwareAddr(attrs.VtepMAC)) vb.dev.AddL2(neigh{IP: evt.Lease.Attrs.PublicIP, MAC: net.HardwareAddr(attrs.VtepMAC)}) case subnet.EventRemoved: log.Info("Subnet removed: ", evt.Lease.Subnet) if evt.Lease.Attrs.BackendType != "vxlan" { log.Warningf("Ignoring non-vxlan subnet: type=%v", evt.Lease.Attrs.BackendType) continue } var attrs vxlanLeaseAttrs if err := json.Unmarshal(evt.Lease.Attrs.BackendData, &attrs); err != nil { log.Error("Error decoding subnet lease JSON: ", err) continue } if len(attrs.VtepMAC) > 0 { vb.dev.DelL2(neigh{IP: evt.Lease.Attrs.PublicIP, MAC: net.HardwareAddr(attrs.VtepMAC)}) } vb.rts.remove(evt.Lease.Subnet) default: log.Error("Internal error: unknown event type: ", int(evt.Type)) } } }
func (m *Manager) runNetwork(n *Network) { n.Run(m.extIface, func(bn backend.Network) { if m.isMultiNetwork() { path := filepath.Join(opts.subnetDir, n.Name) + ".env" if err := writeSubnetFile(path, n.Config.Network, m.ipMasq, bn); err != nil { log.Warningf("%v failed to write subnet file: %s", n.Name, err) return } } else { if err := writeSubnetFile(opts.subnetFile, n.Config.Network, m.ipMasq, bn); err != nil { log.Warningf("%v failed to write subnet file: %s", n.Name, err) return } daemon.SdNotify("READY=1") } }) m.delNetwork(n) }
func (m *Manager) watchNetworks() { wg := sync.WaitGroup{} events := make(chan []subnet.Event) wg.Add(1) go func() { subnet.WatchNetworks(m.ctx, m.sm, events) wg.Done() }() // skip over the initial snapshot <-events for { select { case <-m.ctx.Done(): break case evtBatch := <-events: for _, e := range evtBatch { netname := e.Network if !m.isNetAllowed(netname) { continue } switch e.Type { case subnet.EventAdded: if _, ok := m.networks[netname]; ok { continue } net := NewNetwork(m.ctx, m.sm, netname, m.ipMasq) m.networks[netname] = net wg.Add(1) go func() { m.RunNetwork(net) wg.Done() }() case subnet.EventRemoved: net, ok := m.networks[netname] if !ok { log.Warningf("Network %v unknown; ignoring EventRemoved", netname) continue } net.Cancel() delete(m.networks, netname) } } } } wg.Wait() }
func (m *Manager) RunNetwork(net *Network) { sn := net.Init(m.extIface, m.iaddr, m.eaddr) if sn != nil { if m.isMultiNetwork() { path := filepath.Join(opts.subnetDir, net.Name) + ".env" if err := writeSubnetFile(path, net.Config.Network, m.ipMasq, sn); err != nil { log.Warningf("%v failed to write subnet file: %s", net.Name, err) return } } else { if err := writeSubnetFile(opts.subnetFile, net.Config.Network, m.ipMasq, sn); err != nil { log.Warningf("%v failed to write subnet file: %s", net.Name, err) return } daemon.SdNotify("READY=1") } log.Infof("Running network %v", net.Name) net.Run() log.Infof("%v exited", net.Name) } }
func ensureLink(vxlan *netlink.Vxlan) (*netlink.Vxlan, error) { err := netlink.LinkAdd(vxlan) if err == syscall.EEXIST { // it's ok if the device already exists as long as config is similar existing, err := netlink.LinkByName(vxlan.Name) if err != nil { return nil, err } incompat := vxlanLinksIncompat(vxlan, existing) if incompat == "" { return existing.(*netlink.Vxlan), nil } // delete existing log.Warningf("%q already exists with incompatable configuration: %v; recreating device", vxlan.Name, incompat) if err = netlink.LinkDel(existing); err != nil { return nil, fmt.Errorf("failed to delete interface: %v", err) } // create new if err = netlink.LinkAdd(vxlan); err != nil { return nil, fmt.Errorf("failed to create vxlan interface: %v", err) } } else if err != nil { return nil, err } ifindex := vxlan.Index link, err := netlink.LinkByIndex(vxlan.Index) if err != nil { return nil, fmt.Errorf("can't locate created vxlan device with index %v", ifindex) } var ok bool if vxlan, ok = link.(*netlink.Vxlan); !ok { return nil, fmt.Errorf("created vxlan device with index %v is not vxlan", ifindex) } return vxlan, nil }
func (ipt *IPTables) Exists(table string, args ...string) (bool, error) { checkPresent, err := getIptablesHasCheckCommand() if err != nil { log.Warningf("Error checking iptables version, assuming version at least 1.4.11: %v\n", err) checkPresent = true } if !checkPresent { cmd := append([]string{"-A"}, args...) return existsForOldIpTables(table, strings.Join(cmd, " ")) } else { cmd := append([]string{"-t", table, "-C"}, args...) err = exec.Command(ipt.path, cmd...).Run() } switch { case err == nil: return true, nil case err.(*exec.ExitError).Sys().(syscall.WaitStatus).ExitStatus() == 1: return false, nil default: return false, err } }
// getSubnets queries etcd to get a list of currently allocated leases for a given network. // It returns the leases along with the "as-of" etcd-index that can be used as the starting // point for etcd watch. func (esr *etcdSubnetRegistry) getSubnets(ctx context.Context, network string) ([]Lease, uint64, error) { key := path.Join(esr.etcdCfg.Prefix, network, "subnets") resp, err := esr.client().Get(ctx, key, &etcd.GetOptions{Recursive: true}) if err != nil { if etcdErr, ok := err.(etcd.Error); ok && etcdErr.Code == etcd.ErrorCodeKeyNotFound { // key not found: treat it as empty set return []Lease{}, etcdErr.Index, nil } return nil, 0, err } leases := []Lease{} for _, node := range resp.Node.Nodes { l, err := nodeToLease(node) if err != nil { log.Warningf("Ignoring bad subnet node: %v", err) continue } leases = append(leases, *l) } return leases, resp.Index, nil }