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) }
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 }
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) }
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) }
// 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 }
// 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 }
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() }
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) }
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) }
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) }
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) }
// 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 }
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) }
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) }
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) }
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 }
// 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 } }
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 }
// 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 }
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() }
// 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 }
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) }
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) }
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) }