Skip to content

Commit

Permalink
feat: cli to display ipcache by labels
Browse files Browse the repository at this point in the history
Added new CLI to display ipcache entries by cidr and labels.

Display IP Cache information

Usage:
cilium-dbg ip get ( <cidr> |-l <identity labels> ) [flags]

Flags: -h, --help help for get
-l, --labels strings list of labels
-o, --output string json| yaml| jsonpath='{}'
-v, --verbose Print all fields of ipcache

Fixes: #34632
Signed-off-by: Vasu Dasari <[email protected]>
  • Loading branch information
vasu-dasari authored and aanm committed Nov 4, 2024
1 parent c345a69 commit dc295a8
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 3 deletions.
1 change: 1 addition & 0 deletions Documentation/cmdref/cilium-dbg_ip.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions Documentation/cmdref/cilium-dbg_ip_get.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 25 additions & 0 deletions api/v1/client/policy/get_ip_parameters.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions api/v1/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,7 @@ paths:
- policy
parameters:
- "$ref": "#/parameters/cidr"
- "$ref": "#/parameters/labels"
responses:
'200':
description: Success
Expand Down
11 changes: 11 additions & 0 deletions api/v1/server/embedded_spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions api/v1/server/restapi/policy/get_ip_parameters.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

105 changes: 105 additions & 0 deletions cilium-dbg/cmd/ip_get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package cmd

import (
"fmt"
"net"
"os"
"sort"
"text/tabwriter"

"github.com/spf13/cobra"

ipapi "github.com/cilium/cilium/api/v1/client/policy"
"github.com/cilium/cilium/api/v1/models"
"github.com/cilium/cilium/pkg/api"
pkg "github.com/cilium/cilium/pkg/client"
"github.com/cilium/cilium/pkg/command"
ipcachetypes "github.com/cilium/cilium/pkg/ipcache/types"
"github.com/cilium/cilium/pkg/labels"
)

var (
ipQueryLabels []string
)

var ipGetCmd = &cobra.Command{
Use: "get ( <cidr> |-l <identity labels> )",
Short: "Display IP Cache information",
Run: func(cmd *cobra.Command, args []string) {
if len(ipQueryLabels) > 0 && len(args) > 0 {
Usagef(cmd, "Cannot provide both cidr and labels arguments concurrently")
}

if len(ipQueryLabels) > 0 {
lbls := labels.NewLabelsFromModel(ipQueryLabels).GetModel()
if len(lbls) <= 0 {
Fatalf("Labels cannot be empty %v", ipQueryLabels)
}
displayByLabels(lbls)
} else {
if len(args) < 1 || args[0] == "" {
Usagef(cmd, "Missing cidr argument")
}
if _, _, err := net.ParseCIDR(args[0]); err != nil {
Fatalf("Unable to parse CIDR %q: %v", args[0], err)
}
params := ipapi.NewGetIPParams().WithTimeout(api.ClientTimeout).WithCidr(&args[0])
ipcache, err := client.Policy.GetIP(params)
if err != nil {
Fatalf("Cannot get ipcache entries. err: %s", pkg.Hint(err))
}
im := ipcachetypes.IPListEntrySlice(ipcache.Payload)
sort.Slice(im, im.Less)
printIPcacheEntries(ipcache.Payload)
}
},
}

func init() {
IPCmd.AddCommand(ipGetCmd)
command.AddOutputOption(ipGetCmd)
flags := ipGetCmd.Flags()
flags.StringSliceVarP(&ipQueryLabels, "labels", "l", []string{}, "list of labels")
flags.BoolVarP(&verbose, "verbose", "v", false, "Print all fields of ipcache")
vp.BindPFlags(flags)
}

func displayByLabels(lbls models.Labels) {
params := ipapi.NewGetIPParams().WithLabels(lbls).WithTimeout(api.ClientTimeout)
fmt.Printf("===========================\n")
fmt.Printf("Labels:\n")
for _, label := range lbls {
fmt.Printf(" %s\n", label)
}
fmt.Printf("===========================\n")
result, err := client.Policy.GetIP(params)
if err != nil {
Fatalf("Cannot get ipcache entries. err: %s", pkg.Hint(err))
}
im := ipcachetypes.IPListEntrySlice(result.Payload)
sort.Slice(im, im.Less)
if verbose {
printIPcacheEntries(result.Payload)
} else {
printIPcacheEntriesBrief(result.Payload)
}
}

func printIPcacheEntriesBrief(entries []*models.IPListEntry) {
if command.OutputOption() {
if err := command.PrintOutput(entries); err != nil {
Fatalf("Unable to provide %s output: %s", command.OutputOptionString(), err)
}
return
}

w := tabwriter.NewWriter(os.Stdout, 5, 0, 3, ' ', 0)
fmt.Fprintf(w, "IP\tHOST\tIDENTITY\tPOD\tNAMESPACE\n")
for _, entry := range entries {
fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\n", *entry.Cidr, entry.HostIP, *entry.Identity, entry.Metadata.Name, entry.Metadata.Namespace)
}
w.Flush()
}
37 changes: 34 additions & 3 deletions daemon/cmd/ipcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
package cmd

import (
"context"
"errors"
"fmt"
"io/fs"
"net"
"net/netip"
Expand Down Expand Up @@ -34,14 +36,19 @@ var (
)

func getIPHandler(d *Daemon, params GetIPParams) middleware.Responder {
listener := &ipCacheDumpListener{}
listener := &ipCacheDumpListener{
d: d,
}
if params.Cidr != nil {
_, cidrFilter, err := net.ParseCIDR(*params.Cidr)
if err != nil {
return api.Error(GetIPBadRequestCode, err)
}
listener.cidrFilter = cidrFilter
}
if params.Labels != nil {
listener.labelsFilter = labels.NewLabelsFromModel(params.Labels)
}
d.ipcache.DumpToListener(listener)
if len(listener.entries) == 0 {
return NewGetIPNotFound()
Expand All @@ -51,8 +58,20 @@ func getIPHandler(d *Daemon, params GetIPParams) middleware.Responder {
}

type ipCacheDumpListener struct {
cidrFilter *net.IPNet
entries []*models.IPListEntry
cidrFilter *net.IPNet
labelsFilter labels.Labels
d *Daemon
entries []*models.IPListEntry
}

// getIdentity implements IdentityGetter. It looks up identity by ID from
// Cilium's identity cache.
func (ipc *ipCacheDumpListener) getIdentity(securityIdentity uint32) (*identity.Identity, error) {
ident := ipc.d.identityAllocator.LookupIdentityByID(context.Background(), identity.NumericIdentity(securityIdentity))
if ident == nil {
return nil, fmt.Errorf("identity %d not found", securityIdentity)
}
return ident, nil
}

// OnIPIdentityCacheChange is called by DumpToListenerLocked
Expand All @@ -65,6 +84,18 @@ func (ipc *ipCacheDumpListener) OnIPIdentityCacheChange(modType ipcache.CacheMod
if ipc.cidrFilter != nil && !containsSubnet(*ipc.cidrFilter, cidr) {
return
}
// Only capture identities with requested labels
if ipc.labelsFilter != nil {
id, err := ipc.getIdentity(newID.ID.Uint32())
if err != nil {
return
}
for _, label := range ipc.labelsFilter {
if !id.Labels.Has(label) {
return
}
}
}

cidrStr := cidr.String()
identity := int64(newID.ID.Uint32())
Expand Down

0 comments on commit dc295a8

Please sign in to comment.