Skip to content

Commit

Permalink
feat(crit): add crit x sk for sockets
Browse files Browse the repository at this point in the history
Signed-off-by: Prajwal S N <[email protected]>
  • Loading branch information
snprajwal committed Jul 18, 2023
1 parent 8b1fc77 commit 6754b04
Show file tree
Hide file tree
Showing 4 changed files with 231 additions and 10 deletions.
8 changes: 5 additions & 3 deletions crit/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ var infoCmd = &cobra.Command{

// The `crit x` command
var xCmd = &cobra.Command{
Use: "x DIR {ps|fd|mem|rss}",
Use: "x DIR {ps|fd|mem|rss|sk}",
Short: "Explore the image directory",
Long: "Explore the image directory with one of (ps, fd, mem, rss) options",
Long: "Explore the image directory with one of (ps, fd, mem, rss, sk) options",
// Exactly two arguments are required:
// * Path of the input directory
// * Explore type
Expand All @@ -248,8 +248,10 @@ var xCmd = &cobra.Command{
xData, err = c.ExploreMems()
case "rss":
xData, err = c.ExploreRss()
case "sk":
xData, err = c.ExploreSk()

Check warning on line 252 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L251-L252

Added lines #L251 - L252 were not covered by tests
default:
err = errors.New("invalid explore type (supported: {ps|fd|mem|rss})")
err = errors.New("invalid explore type (supported: {ps|fd|mem|rss|sk})")

Check warning on line 254 in crit/cli/cli.go

View check run for this annotation

Codecov / codecov/patch

crit/cli/cli.go#L254

Added line #L254 was not covered by tests
}
if err != nil {
log.Fatal(fmt.Errorf("error exploring directory: %w", err))
Expand Down
1 change: 1 addition & 0 deletions crit/crit.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Critter interface {
ExploreFds() ([]*Fd, error)
ExploreMems() ([]*MemMap, error)
ExploreRss() ([]*RssMap, error)
ExploreSk() ([]*Sk, error)
}

// crit implements the Critter interface. It contains:
Expand Down
118 changes: 118 additions & 0 deletions crit/explore.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,121 @@ func (c *crit) ExploreRss() ([]*RssMap, error) {

return rssMaps, nil
}

// Sk represents the sockets associated with a single process
type Sk struct {
PId uint32 `json:"pId"`
Sockets []*Socket `json:"sockets"`
}

// Socket represents a single socket
type Socket struct {
Fd uint32 `json:"fd"`
Type string `json:"type"`
Family string `json:"family,omitempty"`
Protocol string `json:"protocol,omitempty"`
State string `json:"state,omitempty"`
SourceAddr string `json:"sourceAddr,omitempty"`
SourcePort uint32 `json:"sourcePort,omitempty"`
DestAddr string `json:"destAddr,omitempty"`
DestPort uint32 `json:"destPort,omitempty"`
SendBuf string `json:"sendBuf,omitempty"`
RecvBuf string `json:"recvBuf,omitempty"`
}

// ExploreSk searches the process tree for sockets
// and returns a list of PIDs with the associated sockets
func (c *crit) ExploreSk() ([]*Sk, error) {
psTreeImg, err := getImg(filepath.Join(c.inputDirPath, "pstree.img"), &pstree.PstreeEntry{})
if err != nil {
return nil, err
}

Check warning on line 404 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L400-L404

Added lines #L400 - L404 were not covered by tests

sks := make([]*Sk, 0)
for _, entry := range psTreeImg.Entries {
process := entry.Message.(*pstree.PstreeEntry)
pID := process.GetPid()
// Get file with object IDs
idsImg, err := getImg(filepath.Join(c.inputDirPath, fmt.Sprintf("ids-%d.img", pID)), &criu_core.TaskKobjIdsEntry{})
if err != nil {
return nil, err
}
filesID := idsImg.Entries[0].Message.(*criu_core.TaskKobjIdsEntry).GetFilesId()
// Get open file descriptors
fdInfoImg, err := getImg(filepath.Join(c.inputDirPath, fmt.Sprintf("fdinfo-%d.img", filesID)), &fdinfo.FdinfoEntry{})
if err != nil {
return nil, err
}
skEntry := Sk{PId: pID}
for _, fdInfoEntry := range fdInfoImg.Entries {
fdInfo := fdInfoEntry.Message.(*fdinfo.FdinfoEntry)
socket := Socket{
Fd: fdInfo.GetFd(),
Type: fdInfo.GetType().String(),
}
switch fdInfo.GetType() {
case fdinfo.FdTypes_INETSK:
file, err := getFile(c.inputDirPath, fdInfo.GetId())
if err != nil {
return nil, err
}
if isk := file.GetIsk(); isk != nil {
socket.State = getSkState(isk.GetState())
socket.Family = getSkFamily(isk.GetFamily())
socket.Protocol = getSkProtocol(isk.GetType())
socket.SourceAddr = processIP(isk.GetSrcAddr())
socket.SourcePort = isk.GetSrcPort()
socket.DestAddr = processIP(isk.GetDstAddr())
socket.DestPort = isk.GetDstPort()
socket.SendBuf = countBytes(int64(isk.GetOpts().GetSoSndbuf()))
socket.RecvBuf = countBytes(int64(isk.GetOpts().GetSoRcvbuf()))
}
case fdinfo.FdTypes_UNIXSK:
file, err := getFile(c.inputDirPath, fdInfo.GetId())
if err != nil {
return nil, err
}
if usk := file.GetUsk(); usk != nil {
socket.State = getSkState(usk.GetState())
socket.Protocol = getSkProtocol(usk.GetType())
socket.SendBuf = countBytes(int64(usk.GetOpts().GetSoSndbuf()))
socket.RecvBuf = countBytes(int64(usk.GetOpts().GetSoRcvbuf()))
}
case fdinfo.FdTypes_PACKETSK:
file, err := getFile(c.inputDirPath, fdInfo.GetId())
if err != nil {
return nil, err
}
if psk := file.GetPsk(); psk != nil {
socket.Protocol = getSkProtocol(psk.GetProtocol())
socket.SendBuf = countBytes(int64(psk.GetOpts().GetSoSndbuf()))
socket.RecvBuf = countBytes(int64(psk.GetOpts().GetSoRcvbuf()))
}
case fdinfo.FdTypes_NETLINKSK:
file, err := getFile(c.inputDirPath, fdInfo.GetId())
if err != nil {
return nil, err
}
if nlsk := file.GetNlsk(); nlsk != nil {
socket.State = getSkState(nlsk.GetState())
socket.Protocol = getSkProtocol(nlsk.GetProtocol())
socket.SendBuf = countBytes(int64(nlsk.GetOpts().GetSoSndbuf()))
socket.RecvBuf = countBytes(int64(nlsk.GetOpts().GetSoRcvbuf()))
}
default:
continue

Check warning on line 478 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L406-L478

Added lines #L406 - L478 were not covered by tests
}

skEntry.Sockets = append(skEntry.Sockets, &socket)

Check warning on line 481 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L481

Added line #L481 was not covered by tests
}

// Omit if the process has no associated sockets
if len(skEntry.Sockets) == 0 {
continue

Check warning on line 486 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L485-L486

Added lines #L485 - L486 were not covered by tests
}

sks = append(sks, &skEntry)

Check warning on line 489 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L489

Added line #L489 was not covered by tests
}

return sks, nil

Check warning on line 492 in crit/explore.go

View check run for this annotation

Codecov / codecov/patch

crit/explore.go#L492

Added line #L492 was not covered by tests
}
114 changes: 107 additions & 7 deletions crit/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"strconv"
"strings"

"github.com/checkpoint-restore/go-criu/v6/crit/images/fdinfo"
"github.com/checkpoint-restore/go-criu/v6/crit/images/pipe"
Expand Down Expand Up @@ -110,27 +111,37 @@ var (
filesImg, regImg, pipeImg, unixSkImg *CriuImage
)

// Helper to get file path for exploring file descriptors
func getFilePath(dir string, fID uint32, fType fdinfo.FdTypes) (string, error) {
var filePath string
// Helper to fetch a file if it exists in files.img
func getFile(dir string, fID uint32) (*fdinfo.FileEntry, error) {
var err error
// Get open files
if filesImg == nil {
filesImg, err = getImg(filepath.Join(dir, "files.img"), &fdinfo.FileEntry{})
if err != nil {
return "", err
return nil, err

Check warning on line 120 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L120

Added line #L120 was not covered by tests
}
}

// Check if file entry is present
var file *fdinfo.FileEntry
for _, entry := range filesImg.Entries {
file = entry.Message.(*fdinfo.FileEntry)
if file.GetId() == fID {
break
return file, nil
}
}

return nil, nil

Check warning on line 132 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L132

Added line #L132 was not covered by tests
}

// Helper to get file path for exploring file descriptors
func getFilePath(dir string, fID uint32, fType fdinfo.FdTypes) (string, error) {
var filePath string
var err error
// Fetch the file, if it exists in file.img
file, err := getFile(dir, fID)
if err != nil {
return "", err
}

Check warning on line 143 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L142-L143

Added lines #L142 - L143 were not covered by tests

switch fType {
case fdinfo.FdTypes_REG:
filePath, err = getRegFilePath(dir, file, fID)
Expand Down Expand Up @@ -232,3 +243,92 @@ func getUnixSkFilePath(dir string, file *fdinfo.FileEntry, fID uint32) (string,

return "unix[?]", nil
}

// Helper to convert slice of uint32 into IP address string
func processIP(parts []uint32) string {
// Create string slice from integer parts
partStrings := make([]string, 0, len(parts))
for _, part := range parts {
partStrings = append(partStrings, strconv.FormatUint(uint64(part), 10))
}

Check warning on line 253 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L248-L253

Added lines #L248 - L253 were not covered by tests
// IPv4
if len(parts) == 4 {
return strings.Join(partStrings, ".")
}

Check warning on line 257 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L255-L257

Added lines #L255 - L257 were not covered by tests
// IPv6
if len(parts) > 4 && len(parts) <= 8 {
return strings.Join(partStrings, ":")
}
return "unknown"

Check warning on line 262 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L259-L262

Added lines #L259 - L262 were not covered by tests
}

// Helper to identify socket state
func getSkState(state uint32) string {
switch state {
case 0:
return "ESTABLISHED"
case 1:
return "SYN_SENT"
case 2:
return "SYN_RECV"
case 3:
return "FIN_WAIT1"
case 4:
return "FIN_WAIT2"
case 5:
return "TIME_WAIT"
case 6:
return "CLOSE"
case 7:
return "CLOSE_WAIT"
case 8:
return "LAST_ACK"
case 9:
return "LISTEN"
case 10:
return "CLOSING"
default:
// State cannot be empty, hence we use unknown
return "UNKNOWN"

Check warning on line 292 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L266-L292

Added lines #L266 - L292 were not covered by tests
}
}

// Helper to identify socket family
func getSkFamily(family uint32) string {
switch family {
case 0:
return "UNIX"
case 1:
return "BRIDGE"
case 2:
return "KEY"
case 3:
return "PACKET"
default:
return ""

Check warning on line 308 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L297-L308

Added lines #L297 - L308 were not covered by tests
}
}

// Helper to identify socket protocol
func getSkProtocol(protocol uint32) string {
switch protocol {
case 0:
return "IP"
case 1:
return "IGMP"
case 2:
return "TCP"
case 3:
return "UDP"
case 4:
return "IPV6"
case 5:
return "GRE"
case 6:
return "AH"
case 7:
return "RAW"
default:
return ""

Check warning on line 332 in crit/utils.go

View check run for this annotation

Codecov / codecov/patch

crit/utils.go#L313-L332

Added lines #L313 - L332 were not covered by tests
}
}

0 comments on commit 6754b04

Please sign in to comment.