Example #1
0
func (s *DaemonSuite) TestEndpointLabelsAddOK(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:          HardAddr,
		IPv6:            IPv6Addr,
		IPv4:            IPv4Addr,
		NodeMAC:         HardAddr,
		NodeIP:          NodeAddr,
		IfName:          "ifname",
		DockerNetworkID: "dockernetwork",
		SecLabel:        SecLabel,
	}
	ep.SetID()

	wantedLabels := labels.LabelOp{
		labels.AddLabelsOp: labels.Labels{
			"foo": labels.NewLabel("foo", "bar", "cilium"),
		},
	}

	s.d.OnEndpointLabelsUpdate = func(epID uint16, lbls labels.LabelOp) error {
		c.Assert(ep.ID, DeepEquals, epID)
		c.Assert(wantedLabels, DeepEquals, lbls)
		return nil
	}

	err := s.c.EndpointLabelsUpdate(ep.ID, wantedLabels)
	c.Assert(err, IsNil)
}
Example #2
0
func (d *Daemon) regenerateEndpointPolicy(e *endpoint.Endpoint, regenerateEndpoint bool) error {
	if e.Consumable != nil {
		if err := d.regenerateConsumable(e); err != nil {
			return err
		}

		opts := make(option.OptionMap)

		d.checkEgressAccess(e, opts, uint32(labels.ID_HOST), endpoint.OptionAllowToHost)
		d.checkEgressAccess(e, opts, uint32(labels.ID_WORLD), endpoint.OptionAllowToWorld)

		if !e.ApplyOpts(opts) {
			// No changes have been applied, skip update
			return nil
		}

		if regenerateEndpoint {
			err := d.regenerateEndpoint(e)
			if err != nil {
				log.Warningf("Error while updating endpoint: %s\n", err)
			}
			return err
		}
	}

	return nil
}
Example #3
0
func (s *DaemonSuite) TestEndpointLabelsAddFail(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:          HardAddr,
		IPv6:            IPv6Addr,
		IPv4:            IPv4Addr,
		NodeMAC:         HardAddr,
		NodeIP:          NodeAddr,
		IfName:          "ifname",
		DockerNetworkID: "dockernetwork",
		SecLabel:        SecLabel,
	}
	ep.SetID()

	wantedLabels := labels.LabelOp{
		labels.AddLabelsOp: labels.Labels{
			"foo": labels.NewLabel("foo", "bar", "cilium"),
		},
	}

	s.d.OnEndpointLabelsUpdate = func(epID uint16, labelOp labels.LabelOp) error {
		c.Assert(ep.ID, DeepEquals, epID)
		c.Assert(labelOp, DeepEquals, wantedLabels)
		return errors.New("invalid endpoint")
	}

	err := s.c.EndpointLabelsUpdate(ep.ID, wantedLabels)
	c.Assert(strings.Contains(err.Error(), "invalid endpoint"), Equals, true)
}
Example #4
0
func (s *DaemonSuite) TestEndpointLabelsGetOK(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:          HardAddr,
		IPv6:            IPv6Addr,
		IPv4:            IPv4Addr,
		NodeMAC:         HardAddr,
		NodeIP:          NodeAddr,
		IfName:          "ifname",
		DockerNetworkID: "dockernetwork",
		SecLabel:        SecLabel,
	}
	ep.SetID()

	epLbls := labels.Labels{
		"foo": labels.NewLabel("foo", "bar", "cilium"),
	}
	ciliumLbls := labels.Labels{
		"bar": labels.NewLabel("bar", "foo", "cilium"),
	}
	wantedLbls := labels.OpLabels{
		AllLabels:      ciliumLbls,
		EndpointLabels: epLbls,
	}

	s.d.OnEndpointLabelsGet = func(epID uint16) (*labels.OpLabels, error) {
		c.Assert(ep.ID, DeepEquals, epID)
		return &wantedLbls, nil
	}

	lbls, err := s.c.EndpointLabelsGet(ep.ID)
	c.Assert(err, IsNil)
	c.Assert(wantedLbls, DeepEquals, *lbls)
}
Example #5
0
// EndpointJoin sets up the endpoint working directory.
func (d *Daemon) EndpointJoin(ep endpoint.Endpoint) error {
	lxcDir := filepath.Join(".", strconv.Itoa(int(ep.ID)))

	if err := os.MkdirAll(lxcDir, 0777); err != nil {
		log.Warningf("Failed to create container temporary directory: %s", err)
		return fmt.Errorf("failed to create temporary directory: %s", err)
	}

	d.conf.OptsMU.RLock()
	ep.SetDefaultOpts(d.conf.Opts)
	d.conf.OptsMU.RUnlock()

	d.InsertEndpoint(&ep)

	return nil
}
Example #6
0
// Sets the given secLabel on the endpoint with the given endpointID. Returns a pointer of
// a copy endpoint if the endpoint was found, nil otherwise.
func (d *Daemon) setEndpointSecLabel(endpointID *uint16, dockerID, dockerEPID string, labels *labels.SecCtxLabel) *endpoint.Endpoint {
	var (
		ep *endpoint.Endpoint
		ok bool
	)

	setIfNotEmpty := func(receiver *string, provider string) {
		if receiver != nil && *receiver == "" && provider != "" {
			*receiver = provider
		}
	}

	setIfNotEmptyUint16 := func(receiver *uint16, provider *uint16) {
		if receiver != nil && *receiver == 0 && provider != nil && *provider != 0 {
			*receiver = *provider
		}
	}

	d.endpointsMU.Lock()
	defer d.endpointsMU.Unlock()

	if endpointID != nil {
		ep, ok = d.endpoints[*endpointID]
	} else if dockerID != "" {
		ep, ok = d.endpointsDocker[dockerID]
	} else if dockerEPID != "" {
		ep, ok = d.endpointsDockerEP[dockerEPID]
	} else {
		return nil
	}

	if ok {
		setIfNotEmpty(&ep.DockerID, dockerID)
		setIfNotEmpty(&ep.DockerEndpointID, dockerEPID)
		setIfNotEmptyUint16(&ep.ID, endpointID)

		ep.SetSecLabel(labels)
		// Update all IDs in respective MAPs
		d.insertEndpoint(ep)
		return ep.DeepCopy()
	}

	return nil
}
Example #7
0
func runGC(e *endpoint.Endpoint, prefix string, ctType ctmap.CtType) {
	file := prefix + strconv.Itoa(int(e.ID))
	fd, err := bpf.ObjGet(file)
	if err != nil {
		log.Warningf("Unable to open CT map %s: %s\n", file, err)
		e.LogStatus(endpoint.Warning, fmt.Sprintf("Unable to open CT map %s: %s", file, err))
		return
	}

	f := os.NewFile(uintptr(fd), file)
	m := ctmap.CtMap{Fd: fd, Type: ctType}

	deleted := m.GC(uint16(GcInterval))
	if deleted > 0 {
		log.Debugf("Deleted %d entries from map %s", deleted, file)
	}

	f.Close()
}
Example #8
0
func (s *DaemonSuite) TestEndpointJoinOK(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:          HardAddr,
		IPv6:            IPv6Addr,
		IPv4:            IPv4Addr,
		NodeMAC:         HardAddr,
		NodeIP:          NodeAddr,
		IfName:          "ifname",
		DockerNetworkID: "dockernetwork",
		SecLabel:        SecLabel,
	}
	ep.SetID()

	s.d.OnEndpointJoin = func(receivedEp endpoint.Endpoint) error {
		c.Assert(ep, DeepEquals, receivedEp)
		return nil
	}

	err := s.c.EndpointJoin(ep)
	c.Assert(err, Equals, nil)
}
Example #9
0
func (s *DaemonSuite) TestEndpointLeaveFail(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:          HardAddr,
		IPv6:            IPv6Addr,
		IPv4:            IPv4Addr,
		NodeMAC:         HardAddr,
		NodeIP:          NodeAddr,
		IfName:          "ifname",
		DockerNetworkID: "dockernetwork",
		SecLabel:        SecLabel,
	}
	ep.SetID()

	s.d.OnEndpointLeave = func(epID uint16) error {
		c.Assert(ep.ID, Equals, epID)
		return errors.New("invalid endpoint")
	}

	err := s.c.EndpointLeave(ep.ID)
	c.Assert(strings.Contains(err.Error(), "invalid endpoint"), Equals, true)
}
Example #10
0
func (s *DaemonSuite) TestEndpointJoinFail(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:          HardAddr,
		IPv6:            IPv6Addr,
		IPv4:            IPv4Addr,
		NodeMAC:         HardAddr,
		NodeIP:          NodeAddr,
		IfName:          "ifname",
		DockerNetworkID: "dockernetwork",
		SecLabel:        SecLabel,
	}
	ep.SetID()

	s.d.OnEndpointJoin = func(receivedEp endpoint.Endpoint) error {
		c.Assert(ep, DeepEquals, receivedEp)
		return errors.New("invalid endpoint")
	}

	err := s.c.EndpointJoin(ep)
	c.Assert(strings.Contains(err.Error(), "invalid endpoint"), Equals, true)
}
Example #11
0
func (s *DaemonSuite) TestEndpointLeaveOK(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:          HardAddr,
		IPv6:            IPv6Addr,
		IPv4:            IPv4Addr,
		NodeMAC:         HardAddr,
		NodeIP:          NodeAddr,
		IfName:          "ifname",
		DockerNetworkID: "dockernetwork",
		SecLabel:        SecLabel,
	}
	ep.SetID()

	s.d.OnEndpointLeave = func(epID uint16) error {
		c.Assert(ep.ID, Equals, epID)
		return nil
	}

	err := s.c.EndpointLeave(ep.ID)
	c.Assert(err, Equals, nil)
}
Example #12
0
// syncLabels syncs the labels from the labels' database for the given endpoint. To be
// used with endpointsMU locked.
func (d *Daemon) syncLabels(ep *endpoint.Endpoint) error {
	if ep.SecLabel == nil {
		return fmt.Errorf("Endpoint doesn't have a security label.")
	}

	sha256sum, err := ep.SecLabel.Labels.SHA256Sum()
	if err != nil {
		return fmt.Errorf("Unable to get the sha256sum of labels: %+v\n", ep.SecLabel.Labels)
	}

	labels, err := d.GetLabelsBySHA256(sha256sum)
	if err != nil {
		return fmt.Errorf("Unable to get labels of sha256sum:%s: %+v\n", sha256sum, err)
	}

	if ep.DockerID == "" {
		return nil
	}

	if labels == nil {
		labels, _, err = d.PutLabels(ep.SecLabel.Labels, ep.DockerID)
		if err != nil {
			return fmt.Errorf("Unable to put labels %+v: %s\n", ep.SecLabel.Labels, err)
		}
	}

	if !reflect.DeepEqual(labels.Labels, ep.SecLabel.Labels) {
		return fmt.Errorf("The set of labels should be the same for " +
			"the endpoint being restored and the labels stored")
	}

	if labels.ID != ep.SecLabel.ID {
		log.Infof("Security label ID for endpoint %d is different "+
			"that the one stored, updating from %d to %d\n",
			ep.ID, ep.SecLabel.ID, labels.ID)
	}
	ep.SetSecLabel(labels)

	return nil
}
Example #13
0
func (s *DaemonSuite) EndpointLeaveByDockerEPIDFail(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:           HardAddr,
		IPv6:             IPv6Addr,
		IPv4:             IPv4Addr,
		NodeMAC:          HardAddr,
		NodeIP:           NodeAddr,
		IfName:           "ifname",
		DockerNetworkID:  "dockernetwork",
		DockerEndpointID: "123abc",
		SecLabel:         SecLabel,
	}
	ep.SetID()

	s.d.OnEndpointLeaveByDockerEPID = func(dockerEPIDreceived string) error {
		c.Assert(ep.DockerEndpointID, Equals, dockerEPIDreceived)
		return errors.New("invalid endpoint")
	}

	err := s.c.EndpointLeaveByDockerEPID(ep.DockerEndpointID)
	c.Assert(strings.Contains(err.Error(), "invalid endpoint"), Equals, true)
}
Example #14
0
func (s *DaemonSuite) EndpointLeaveByDockerEPIDOK(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:           HardAddr,
		IPv6:             IPv6Addr,
		IPv4:             IPv4Addr,
		NodeMAC:          HardAddr,
		NodeIP:           NodeAddr,
		IfName:           "ifname",
		DockerNetworkID:  "dockernetwork",
		DockerEndpointID: "123abc",
		SecLabel:         SecLabel,
	}
	ep.SetID()

	s.d.OnEndpointLeaveByDockerEPID = func(dockerEPIDreceived string) error {
		c.Assert(ep.DockerEndpointID, Equals, dockerEPIDreceived)
		return nil
	}

	err := s.c.EndpointLeaveByDockerEPID(ep.DockerEndpointID)
	c.Assert(err, Equals, nil)
}
Example #15
0
func (s *DaemonSuite) TestEndpointLabelsGetFail(c *C) {
	ep := endpoint.Endpoint{
		LXCMAC:          HardAddr,
		IPv6:            IPv6Addr,
		IPv4:            IPv4Addr,
		NodeMAC:         HardAddr,
		NodeIP:          NodeAddr,
		IfName:          "ifname",
		DockerNetworkID: "dockernetwork",
		SecLabel:        SecLabel,
	}
	ep.SetID()

	s.d.OnEndpointLabelsGet = func(epID uint16) (*labels.OpLabels, error) {
		c.Assert(ep.ID, DeepEquals, epID)
		return nil, errors.New("invalid endpoint")
	}

	lbls, err := s.c.EndpointLabelsGet(ep.ID)
	c.Assert(strings.Contains(err.Error(), "invalid endpoint"), Equals, true)
	c.Assert(lbls, IsNil)
}
Example #16
0
func (d *Daemon) regenerateEndpoint(ep *endpoint.Endpoint) error {
	// This is the temporary directory to store the generated headers,
	// the original existing directory is not overwritten until all
	// generation has succeeded.
	origDir := filepath.Join(".", strconv.Itoa(int(ep.ID)))
	tmpDir := origDir + "_update"
	backupDir := origDir + "_backup"

	if err := d.regenerateBPF(ep, tmpDir); err != nil {
		return err
	}

	// Attempt to move the original endpoint directory to a backup location
	if err := os.Rename(origDir, backupDir); err != nil {
		os.RemoveAll(tmpDir)
		return fmt.Errorf("Unable to create backup of endpoint directory: %s", err)
	}

	// Move new endpoint directory in place, upon failure, restore backup
	if err := os.Rename(tmpDir, origDir); err != nil {
		os.RemoveAll(tmpDir)

		if err2 := os.Rename(backupDir, origDir); err2 != nil {
			log.Warningf("Restoring the backup directory for %s for endpoint "+
				"%s did not succeed, the endpoint is now in an inconsistent state",
				backupDir, ep.String())
			return err2
		}

		return fmt.Errorf("Restored original endpoint directory, atomic replace failed: %s", err)
	}

	os.RemoveAll(backupDir)
	log.Infof("Successfully regenerated program for endpoint %s", ep.String())

	return nil
}
Example #17
0
// insertEndpoint inserts the ep in the endpoints map. To be used with endpointsMU locked.
func (d *Daemon) insertEndpoint(ep *endpoint.Endpoint) {
	if ep.Status == nil {
		ep.Status = &endpoint.EndpointStatus{}
	}

	d.endpoints[ep.ID] = ep

	if ep.DockerID != "" {
		d.endpointsDocker[ep.DockerID] = ep
	}

	if ep.DockerEndpointID != "" {
		d.endpointsDockerEP[ep.DockerEndpointID] = ep
	}
}
Example #18
0
func (d *Daemon) allocateIPs(ep *endpoint.Endpoint) error {
	allocateIP := func(ep *endpoint.Endpoint, ipamReq ipam.IPAMReq) (resp *ipam.IPAMRep, err error) {
		if ep.IsCNI() {
			resp, err = d.AllocateIP(ipam.CNIIPAMType, ipamReq)
		} else if ep.IsLibnetwork() {
			resp, err = d.AllocateIP(ipam.LibnetworkIPAMType, ipamReq)
		}
		return
	}
	releaseIP := func(ep *endpoint.Endpoint, ipamReq ipam.IPAMReq) (err error) {
		if ep.IsCNI() {
			err = d.ReleaseIP(ipam.CNIIPAMType, ipamReq)
		} else if ep.IsLibnetwork() {
			err = d.ReleaseIP(ipam.LibnetworkIPAMType, ipamReq)
		}
		return
	}

	_, err := allocateIP(ep, ep.IPv6.IPAMReq())
	if err != nil {
		// TODO if allocation failed reallocate a new IP address and setup veth
		// pair accordingly
		return fmt.Errorf("unable to reallocate IPv6 address: %s", err)
	} else {
		log.Infof("EP %d's IPv6 successfully reallocated", ep.ID)
	}
	defer func(ep *endpoint.Endpoint) {
		if err != nil {
			releaseIP(ep, ep.IPv6.IPAMReq())
		}
	}(ep)

	if d.conf.IPv4Enabled {
		if ep.IPv4 != nil {
			_, err := allocateIP(ep, ep.IPv4.IPAMReq())
			if err != nil {
				return fmt.Errorf("unable to reallocate IPv4 address: %s", err)
			} else {
				log.Infof("EP %d's IPv4 successfully reallocated", ep.ID)
			}
		}
	}
	return nil
}
Example #19
0
// regenerateBPF rewrites all headers and updates all BPF maps to reflect the
// specified endpoint.
//
// If endpointSuffix is set, it will be appended to the container directory to
// allow writing to a temporary directory and then atomically rename it.
func (d *Daemon) regenerateBPF(ep *endpoint.Endpoint, lxcDir string) error {
	var err error
	createdPolicyMap := false

	policyMapPath := ep.PolicyMapPath()

	// Cleanup on failure
	defer func() {
		if err != nil {
			if createdPolicyMap {
				// Remove policy map file only if it was created
				// in this update cycle
				if ep.Consumable != nil {
					ep.Consumable.RemoveMap(ep.PolicyMap)
				}

				os.RemoveAll(policyMapPath)
				ep.PolicyMap = nil
			}

			// Always remove endpoint directory, if this was a subsequent
			// update call, it was the responsibility of the updater to
			// to provide an endpoint suffix to not bluntly overwrite the
			// existing directory.
			os.RemoveAll(lxcDir)
		}
	}()

	if !d.conf.DryMode {
		if ep.PolicyMap == nil {
			ep.PolicyMap, createdPolicyMap, err = policymap.OpenMap(policyMapPath)
			if err != nil {
				return err
			}
		}
	}

	// Only generate & populate policy map if a seclabel and consumer model is set up
	if ep.Consumable != nil {
		if !d.conf.DryMode {
			ep.Consumable.AddMap(ep.PolicyMap)
		}

		// The policy is only regenerated but the endpoint is not
		// regenerated as we regenerate below anyway.
		if err := d.regenerateEndpointPolicy(ep, false); err != nil {
			return fmt.Errorf("Unable to regenerate policy for '%s': %s",
				ep.PolicyMap.String(), err)
		}
	}

	if err := os.MkdirAll(lxcDir, 0777); err != nil {
		return fmt.Errorf("Failed to create endpoint directory: %s", err)
	}

	geneveOpts, err := writeGeneve(lxcDir, ep)
	if err != nil {
		return err
	}

	err = d.writeBPFHeader(lxcDir, ep, geneveOpts)
	if err != nil {
		return fmt.Errorf("failed to create temporary directory: %s", err)
	}

	if !d.conf.DryMode {
		if err := d.conf.LXCMap.WriteEndpoint(ep); err != nil {
			return fmt.Errorf("Unable to update eBPF map: %s", err)
		}

		args := []string{d.conf.LibDir, d.conf.RunDir, lxcDir, ep.IfName}
		out, err := exec.Command(filepath.Join(d.conf.LibDir, "join_ep.sh"), args...).CombinedOutput()
		if err != nil {
			log.Warningf("Command execution failed: %s", err)
			log.Warningf("Command output:\n%s", out)
			return fmt.Errorf("error: %q command output: %q", err, out)
		}

		log.Infof("Command successful:\n%s", out)
	}

	return nil
}
Example #20
0
func (d *Daemon) writeBPFHeader(lxcDir string, ep *endpoint.Endpoint, geneveOpts []byte) error {
	headerPath := filepath.Join(lxcDir, common.CHeaderFileName)
	f, err := os.Create(headerPath)
	if err != nil {
		return fmt.Errorf("failed to open file %s for writing: %s", headerPath, err)

	}
	defer f.Close()

	fw := bufio.NewWriter(f)

	fmt.Fprint(fw, "/*\n")

	if epStr64, err := ep.Base64(); err == nil {
		fmt.Fprintf(fw, " * %s%s:%s\n * \n", common.CiliumCHeaderPrefix,
			common.Version, epStr64)
	} else {
		ep.LogStatus(endpoint.Warning, fmt.Sprintf("Unable to create a base64: %s", err))
	}

	if ep.DockerID == "" {
		fmt.Fprintf(fw, " * Docker Network ID: %s\n", ep.DockerNetworkID)
		fmt.Fprintf(fw, " * Docker Endpoint ID: %s\n", ep.DockerEndpointID)
	} else {
		fmt.Fprintf(fw, " * Docker Container ID: %s\n", ep.DockerID)
	}

	fmt.Fprintf(fw, ""+
		" * MAC: %s\n"+
		" * IPv6 address: %s\n"+
		" * IPv4 address: %s\n"+
		" * SecLabelID: %#x\n"+
		" * PolicyMap: %s\n"+
		" * NodeMAC: %s\n"+
		" */\n\n",
		ep.LXCMAC, ep.IPv6.String(), ep.IPv4.String(),
		ep.SecLabel.ID, path.Base(ep.PolicyMapPath()), ep.NodeMAC)

	fw.WriteString("/*\n")
	fw.WriteString(" * Labels:\n")
	if len(ep.SecLabel.Labels) == 0 {
		fmt.Fprintf(fw, " * - %s\n", "(no labels)")
	} else {
		for _, v := range ep.SecLabel.Labels {
			fmt.Fprintf(fw, " * - %s\n", v)
		}
	}
	fw.WriteString(" */\n\n")

	fw.WriteString(common.FmtDefineAddress("LXC_MAC", ep.LXCMAC))
	fw.WriteString(common.FmtDefineAddress("LXC_IP", ep.IPv6))
	if ep.IPv4 != nil {
		fmt.Fprintf(fw, "#define LXC_IPV4 %#x\n", binary.BigEndian.Uint32(ep.IPv4))
	}
	fw.WriteString(common.FmtDefineAddress("NODE_MAC", ep.NodeMAC))
	fw.WriteString(common.FmtDefineArray("GENEVE_OPTS", geneveOpts))
	fmt.Fprintf(fw, "#define LXC_ID %#x\n", ep.ID)
	fmt.Fprintf(fw, "#define LXC_ID_NB %#x\n", common.Swab16(ep.ID))
	fmt.Fprintf(fw, "#define SECLABEL_NB %#x\n", common.Swab32(ep.SecLabel.ID))
	fmt.Fprintf(fw, "#define SECLABEL %#x\n", ep.SecLabel.ID)
	fmt.Fprintf(fw, "#define POLICY_MAP %s\n", path.Base(ep.PolicyMapPath()))
	fmt.Fprintf(fw, "#define CT_MAP_SIZE 512000\n")
	fmt.Fprintf(fw, "#define CT_MAP6 %s\n", path.Base(common.BPFMapCT6+strconv.Itoa(int(ep.ID))))
	fmt.Fprintf(fw, "#define CT_MAP4 %s\n", path.Base(common.BPFMapCT4+strconv.Itoa(int(ep.ID))))

	// Always enable L4 and L3 load balancer for now
	fw.WriteString("#define LB_L3\n")
	fw.WriteString("#define LB_L4\n")

	// Endpoint options
	fw.WriteString(ep.Opts.GetFmtList())

	fw.WriteString("#define LXC_PORT_MAPPINGS ")
	for _, m := range ep.PortMap {
		// Write mappings directly in network byte order so we don't have
		// to convert it in the fast path
		fmt.Fprintf(fw, "{%#x,%#x},", common.Swab16(m.From), common.Swab16(m.To))
	}
	fw.WriteString("\n")

	return fw.Flush()
}
Example #21
0
// SetupVeth sets up the net interface, the temporary interface and fills up some endpoint
// fields such as LXCMAC, NodeMac, IfIndex and IfName. Returns a pointer for the created
// veth, a pointer for the temporary link, the name of the temporary link and error if
// something fails.
func SetupVeth(id string, mtu int, ep *endpoint.Endpoint) (*netlink.Veth, *netlink.Link, string, error) {

	lxcIfName := Endpoint2IfName(id)
	tmpIfName := temporaryInterfacePrefix + id[:5]

	veth := &netlink.Veth{
		LinkAttrs: netlink.LinkAttrs{Name: lxcIfName},
		PeerName:  tmpIfName,
	}

	if err := netlink.LinkAdd(veth); err != nil {
		return nil, nil, "", fmt.Errorf("unable to create veth pair: %s", err)
	}
	var err error
	defer func() {
		if err != nil {
			if err = netlink.LinkDel(veth); err != nil {
				log.Warningf("failed to clean up veth %q: %s", veth.Name, err)
			}
		}
	}()

	log.Debugf("Created veth pair %s <-> %s", lxcIfName, veth.PeerName)

	// Disable reverse path filter on the host side veth peer to allow
	// container addresses to be used as source address when the linux
	// stack performs routing.
	args := []string{"-w", "net.ipv4.conf." + lxcIfName + ".rp_filter=0"}
	_, err = exec.Command("sysctl", args...).CombinedOutput()
	if err != nil {
		return nil, nil, "", fmt.Errorf("unable to disable rp_filter on %s: %s",
			lxcIfName, err)
	}

	peer, err := netlink.LinkByName(tmpIfName)
	if err != nil {
		return nil, nil, "", fmt.Errorf("unable to lookup veth peer just created: %s", err)
	}

	if err = netlink.LinkSetMTU(peer, mtu); err != nil {
		return nil, nil, "", fmt.Errorf("unable to set MTU to %q: %s", tmpIfName, err)
	}

	hostVeth, err := netlink.LinkByName(lxcIfName)
	if err != nil {
		return nil, nil, "", fmt.Errorf("unable to lookup veth just created: %s", err)
	}

	if err = netlink.LinkSetMTU(hostVeth, mtu); err != nil {
		return nil, nil, "", fmt.Errorf("unable to set MTU to %q: %s", lxcIfName, err)
	}

	if err = netlink.LinkSetUp(veth); err != nil {
		return nil, nil, "", fmt.Errorf("unable to bring up veth pair: %s", err)
	}

	ep.LXCMAC = mac.MAC(peer.Attrs().HardwareAddr)
	ep.NodeMAC = mac.MAC(hostVeth.Attrs().HardwareAddr)
	ep.IfIndex = hostVeth.Attrs().Index
	ep.IfName = lxcIfName

	return veth, &peer, tmpIfName, nil
}
Example #22
0
func (ds *DaemonSuite) TestUpdateConsumerMap(c *C) {
	lblProd := labels.NewLabel("io.cilium.Prod", "", common.CiliumLabelSource)
	lblQA := labels.NewLabel("io.cilium.QA", "", common.CiliumLabelSource)
	lblFoo := labels.NewLabel("io.cilium.foo", "", common.CiliumLabelSource)
	lblBar := labels.NewLabel("io.cilium.bar", "", common.CiliumLabelSource)
	lblJoe := labels.NewLabel("io.cilium.user", "joe", common.CiliumLabelSource)
	lblPete := labels.NewLabel("io.cilium.user", "pete", common.CiliumLabelSource)

	rootNode := policy.Node{
		Name: common.GlobalLabelPrefix,
		Rules: []policy.PolicyRule{
			&policy.PolicyRuleConsumers{
				Coverage: []labels.Label{*lblBar},
				Allow: []policy.AllowRule{
					// always-allow: user=joe
					{Action: policy.ALWAYS_ACCEPT, Label: *lblJoe},
					// allow:  user=pete
					{Action: policy.ACCEPT, Label: *lblPete},
				},
			},
			&policy.PolicyRuleRequires{ // coverage qa, requires qa
				Coverage: []labels.Label{*lblQA},
				Requires: []labels.Label{*lblQA},
			},
			&policy.PolicyRuleRequires{ // coverage prod, requires: prod
				Coverage: []labels.Label{*lblProd},
				Requires: []labels.Label{*lblProd},
			},
		},
		Children: map[string]*policy.Node{
			"foo": {},
			"bar": {
				Rules: []policy.PolicyRule{
					&policy.PolicyRuleConsumers{
						Allow: []policy.AllowRule{
							{ // allow: foo
								Action: policy.ACCEPT,
								Label:  *lblFoo,
							},
							{Action: policy.DENY, Label: *lblJoe},
							{Action: policy.DENY, Label: *lblPete},
						},
					},
				},
			},
		},
	}

	c.Assert(rootNode.ResolveTree(), Equals, nil)

	err := ds.d.PolicyAdd("io.cilium", &rootNode)
	c.Assert(err, Equals, nil)

	qaBarLbls := labels.Labels{lblBar.Key: lblBar, lblQA.Key: lblQA}
	qaBarSecLblsCtx, _, err := ds.d.PutLabels(qaBarLbls, "cc08ff400e355f736dce1c291a6a4007ab9f2d56d42e1f3630ba87b861d45307")
	c.Assert(err, Equals, nil)

	prodBarLbls := labels.Labels{lblBar.Key: lblBar, lblProd.Key: lblProd}
	prodBarSecLblsCtx, _, err := ds.d.PutLabels(prodBarLbls, "cc08ff400e355f736dce1c291a6a4007ab9f2d56d42e1f3630ba87b861d45307")
	c.Assert(err, Equals, nil)

	qaFooLbls := labels.Labels{lblFoo.Key: lblFoo, lblQA.Key: lblQA}
	qaFooSecLblsCtx, _, err := ds.d.PutLabels(qaFooLbls, "cc08ff400e355f736dce1c291a6a4007ab9f2d56d42e1f3630ba87b861d45307")
	c.Assert(err, Equals, nil)

	prodFooLbls := labels.Labels{lblFoo.Key: lblFoo, lblProd.Key: lblProd}
	prodFooSecLblsCtx, _, err := ds.d.PutLabels(prodFooLbls, "cc08ff400e355f736dce1c291a6a4007ab9f2d56d42e1f3630ba87b861d45307")
	c.Assert(err, Equals, nil)

	prodFooJoeLbls := labels.Labels{lblFoo.Key: lblFoo, lblProd.Key: lblProd, lblJoe.Key: lblJoe}
	prodFooJoeSecLblsCtx, _, err := ds.d.PutLabels(prodFooJoeLbls, "cc08ff400e355f736dce1c291a6a4007ab9f2d56d42e1f3630ba87b861d45307")
	c.Assert(err, Equals, nil)

	e := endpoint.Endpoint{
		ID:      1,
		IfName:  "dummy1",
		IPv6:    IPv6Addr,
		IPv4:    IPv4Addr,
		LXCMAC:  HardAddr,
		NodeMAC: HardAddr,
	}
	e.Opts = option.NewBoolOptions(&DaemonOptionLibrary)
	e.Opts.SetIfUnset(endpoint.OptionLearnTraffic, false)
	err = os.Mkdir("1", 755)
	c.Assert(err, IsNil)
	defer func() {
		err = os.RemoveAll("1/geneve_opts.cfg")
		err = os.RemoveAll("1/lxc_config.h")
		time.Sleep(1 * time.Second)
		err = os.RemoveAll("1")
		err = os.RemoveAll("1_backup")
	}()
	e.SetSecLabel(qaBarSecLblsCtx)
	err = ds.d.regenerateEndpoint(&e)
	c.Assert(err, Equals, nil)
	c.Assert(e.Allows(qaBarSecLblsCtx.ID), Equals, false)
	c.Assert(e.Allows(prodBarSecLblsCtx.ID), Equals, false)
	c.Assert(e.Allows(qaFooSecLblsCtx.ID), Equals, true)
	c.Assert(e.Allows(prodFooSecLblsCtx.ID), Equals, false)
	c.Assert(e.Allows(prodFooJoeSecLblsCtx.ID), Equals, true)

	e = endpoint.Endpoint{
		ID:      1,
		IfName:  "dummy1",
		IPv6:    IPv6Addr,
		IPv4:    IPv4Addr,
		LXCMAC:  HardAddr,
		NodeMAC: HardAddr,
	}
	e.Opts = option.NewBoolOptions(&DaemonOptionLibrary)
	e.Opts.SetIfUnset(endpoint.OptionLearnTraffic, false)
	e.SetSecLabel(prodBarSecLblsCtx)
	err = ds.d.regenerateEndpoint(&e)
	c.Assert(err, Equals, nil)
	c.Assert(e.Allows(0), Equals, false)
	c.Assert(e.Allows(qaBarSecLblsCtx.ID), Equals, false)
	c.Assert(e.Allows(prodBarSecLblsCtx.ID), Equals, false)
	c.Assert(e.Allows(qaFooSecLblsCtx.ID), Equals, false)
	c.Assert(e.Allows(prodFooSecLblsCtx.ID), Equals, true)
	c.Assert(e.Allows(prodFooJoeSecLblsCtx.ID), Equals, true)

	err = ds.d.PolicyDelete("io.cilium")
	c.Assert(err, Equals, nil)
}
Example #23
0
func (driver *driver) createEndpoint(w http.ResponseWriter, r *http.Request) {
	var create CreateEndpointRequest
	if err := json.NewDecoder(r.Body).Decode(&create); err != nil {
		sendError(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
		return
	}
	log.Debugf("Create endpoint request: %+v", &create)

	endID := create.EndpointID
	ipv6Address := create.Interface.AddressIPv6
	ipv4Address := create.Interface.Address

	if ipv4Address == "" {
		log.Warningf("No IPv4 address provided in CreateEndpoint request")
	}

	if ipv6Address == "" {
		sendError(w, "No IPv6 address provided (required)", http.StatusBadRequest)
		return
	}

	maps := make([]endpoint.PortMap, 0, 32)

	for key, val := range create.Options {
		switch key {
		case "com.docker.network.portmap":
			var portmap []lnTypes.PortBinding
			if err := json.Unmarshal(val, &portmap); err != nil {
				sendError(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
				return
			}
			log.Debugf("PortBinding: %+v", &portmap)

			// FIXME: Host IP is ignored for now
			for _, m := range portmap {
				maps = append(maps, endpoint.PortMap{
					From:  m.HostPort,
					To:    m.Port,
					Proto: uint8(m.Proto),
				})
			}

		case "com.docker.network.endpoint.exposedports":
			var tp []lnTypes.TransportPort
			if err := json.Unmarshal(val, &tp); err != nil {
				sendError(w, "Unable to decode JSON payload: "+err.Error(), http.StatusBadRequest)
				return
			}
			log.Debugf("ExposedPorts: %+v", &tp)
			// TODO: handle exposed ports
		}
	}

	ep, err := driver.client.EndpointGetByDockerEPID(endID)
	if err != nil {
		sendError(w, fmt.Sprintf("Error retrieving endpoint %s", err), http.StatusBadRequest)
		return
	}
	if ep != nil {
		sendError(w, "Endpoint already exists", http.StatusBadRequest)
		return
	}

	endpoint := endpoint.Endpoint{
		NodeIP:           driver.nodeAddress,
		DockerNetworkID:  create.NetworkID,
		DockerEndpointID: endID,
		PortMap:          maps,
	}

	if ipv6Address != "" {
		ip6, _, err := net.ParseCIDR(ipv6Address)
		if err != nil {
			sendError(w, fmt.Sprintf("Invalid IPv6 address: %s", err), http.StatusBadRequest)
			return
		}
		endpoint.IPv6 = addressing.DeriveCiliumIPv6(ip6)
	}

	if ipv4Address != "" {
		ip4, _, err := net.ParseCIDR(ipv4Address)
		if err != nil {
			sendError(w, fmt.Sprintf("Invalid IPv4 address: %s", err), http.StatusBadRequest)
			return
		}
		endpoint.IPv4 = addressing.DeriveCiliumIPv4(ip4)
	}

	endpoint.SetID()

	if err = driver.client.EndpointSave(endpoint); err != nil {
		sendError(w, fmt.Sprintf("Error retrieving endpoint %s", err), http.StatusBadRequest)
		return
	}

	log.Debugf("Created Endpoint: %+v", endpoint)

	log.Infof("New endpoint %s with IPv6: %s, IPv4: %s", endID, ipv6Address, ipv4Address)

	respIface := &api.EndpointInterface{
		// Fixme: the lxcmac is an empty string at this point and we only know the
		// mac address at the end of joinEndpoint
		// There's no problem in the setup but docker inspect will show an empty mac address
		MacAddress: endpoint.LXCMAC.String(),
	}
	resp := &api.CreateEndpointResponse{
		Interface: respIface,
	}
	log.Debugf("Create endpoint response: %+v", resp)
	objectResponse(w, resp)
}
Example #24
0
func cmdAdd(args *skel.CmdArgs) error {
	n, err := loadNetConf(args.StdinData)
	if err != nil {
		return err
	}

	log.Debugf("Args %s", args)

	c, err := cnc.NewDefaultClient()
	if err != nil {
		return fmt.Errorf("error while starting cilium-client: %s", err)
	}

	netNs, err := ns.GetNS(args.Netns)
	if err != nil {
		return fmt.Errorf("failed to open netns %q: %s", args.Netns, err)
	}
	defer netNs.Close()

	if err := removeIfFromNSIfExists(netNs, args.IfName); err != nil {
		return fmt.Errorf("failed removing interface %q from namespace %q: %s",
			args.IfName, args.Netns, err)
	}

	var ep endpoint.Endpoint
	veth, peer, tmpIfName, err := plugins.SetupVeth(args.ContainerID, n.MTU, &ep)
	if err != nil {
		return err
	}
	defer func() {
		if err != nil {
			if err = netlink.LinkDel(veth); err != nil {
				log.Warningf("failed to clean up veth %q: %s", veth.Name, err)
			}
		}
	}()

	if err = netlink.LinkSetNsFd(*peer, int(netNs.Fd())); err != nil {
		return fmt.Errorf("unable to move veth pair %q to netns: %s", peer, err)
	}

	err = netNs.Do(func(_ ns.NetNS) error {
		err := renameLink(tmpIfName, args.IfName)
		if err != nil {
			return fmt.Errorf("failed to rename %q to %q: %s", tmpIfName, args.IfName, err)
		}
		return nil
	})

	req := ipam.IPAMReq{}
	ipamConf, err := c.AllocateIP(ipam.CNIIPAMType, req)
	if err != nil {
		return err
	}
	defer func() {
		if err != nil && ipamConf != nil {
			if ipamConf.IP6 != nil {
				req := ipam.IPAMReq{IP: &ipamConf.IP6.IP.IP}
				if err = c.ReleaseIP(ipam.CNIIPAMType, req); err != nil {
					log.Warningf("failed to release allocated IPv6 of container ID %q: %s", args.ContainerID, err)
				}
			}
			if ipamConf.IP4 != nil {
				req := ipam.IPAMReq{IP: &ipamConf.IP4.IP.IP}
				if err = c.ReleaseIP(ipam.CNIIPAMType, req); err != nil {
					log.Warningf("failed to release allocated IPv4 of container ID %q: %s", args.ContainerID, err)
				}
			}
		}
	}()

	if err = netNs.Do(func(_ ns.NetNS) error {
		return configureIface(args.IfName, ipamConf)
	}); err != nil {
		return err
	}

	ep.IPv6 = addressing.DeriveCiliumIPv6(ipamConf.IP6.IP.IP)
	if ipamConf.IP4 != nil {
		ep.IPv4 = addressing.DeriveCiliumIPv4(ipamConf.IP4.IP.IP)
	}
	ep.NodeIP = ipamConf.IP6.Gateway
	ep.DockerID = args.ContainerID
	ep.SetID()
	if err = c.EndpointJoin(ep); err != nil {
		return fmt.Errorf("unable to create eBPF map: %s", err)
	}

	return createCNIReply(ipamConf)
}