Skip to content

Commit 34133a3

Browse files
committed
diff: add missing socket comparison logic
Signed-off-by: Hamza Dogar <hxadogar@gmail.com>
1 parent 34f655f commit 34133a3

File tree

1 file changed

+180
-1
lines changed

1 file changed

+180
-1
lines changed

cmd/diff.go

Lines changed: 180 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ func Diff() *cobra.Command {
1818
Long: `Compare two CRIU checkpoints and show differences in:
1919
- Process tree (new/removed/modified processes)
2020
- File descriptors (opened/closed files)
21+
- Sockets (new/removed network sockets)
2122
- Memory usage (size changes)
2223
2324
Example:
2425
checkpointctl diff checkpoint1.tar checkpoint2.tar
2526
checkpointctl diff --format json checkpoint1.tar checkpoint2.tar
26-
checkpointctl diff --files --ps-tree-cmd checkpoint1.tar checkpoint2.tar`,
27+
checkpointctl diff --files --ps-tree-cmd checkpoint1.tar checkpoint2.tar
28+
checkpointctl diff --files --sockets checkpoint1.tar checkpoint2.tar`,
2729
Args: cobra.ExactArgs(2),
2830
RunE: diff,
2931
}
@@ -216,6 +218,7 @@ type CheckpointMetadata struct {
216218
CheckpointSize CheckpointSize `json:"checkpoint_size"`
217219
ProcessTree *ProcessTree `json:"process_tree,omitempty"`
218220
FileDescriptors []FileDescriptorEntry `json:"file_descriptors,omitempty"`
221+
Sockets []SkNode `json:"sockets,omitempty"`
219222
}
220223

221224
type CheckpointSize struct {
@@ -241,6 +244,29 @@ type OpenFile struct {
241244
Path string `json:"path"`
242245
}
243246

247+
// Socket types (mirroring internal/json.go)
248+
type SkNode struct {
249+
PID uint32 `json:"pid"`
250+
OpenSockets []SocketNode `json:"open_sockets,omitempty"`
251+
}
252+
253+
type SocketNode struct {
254+
Protocol string `json:"protocol,omitempty"`
255+
Data SkData `json:"data,omitempty"`
256+
}
257+
258+
type SkData struct {
259+
Type string `json:"type,omitempty"`
260+
Address string `json:"address,omitempty"`
261+
State string `json:"state,omitempty"`
262+
Source string `json:"src,omitempty"`
263+
SourcePort uint32 `json:"src_port,omitempty"`
264+
Dest string `json:"dst,omitempty"`
265+
DestPort uint32 `json:"dst_port,omitempty"`
266+
SendBuf string `json:"send_buf,omitempty"`
267+
RecvBuf string `json:"recv_buf,omitempty"`
268+
}
269+
244270
// Diff result structures
245271
type DiffResult struct {
246272
ContainerID string `json:"container_id"`
@@ -251,6 +277,7 @@ type DiffResult struct {
251277
ProcessChanges *ProcessDiff `json:"process_changes,omitempty"`
252278
FileChanges *FileDiff `json:"file_changes,omitempty"`
253279
MemoryChanges *MemoryDiff `json:"memory_changes"`
280+
SocketChanges *SocketDiff `json:"socket_changes,omitempty"`
254281
Summary string `json:"summary"`
255282
}
256283

@@ -290,6 +317,24 @@ type MemoryDiff struct {
290317
SizeChangeMB float64 `json:"size_change_mb"`
291318
}
292319

320+
type SocketDiff struct {
321+
Added []SocketInfo `json:"added,omitempty"`
322+
Removed []SocketInfo `json:"removed,omitempty"`
323+
Unchanged int `json:"unchanged"`
324+
}
325+
326+
type SocketInfo struct {
327+
PID int `json:"pid"`
328+
Protocol string `json:"protocol"`
329+
Type string `json:"type"`
330+
Address string `json:"address,omitempty"`
331+
State string `json:"state,omitempty"`
332+
Source string `json:"source,omitempty"`
333+
SrcPort uint32 `json:"src_port,omitempty"`
334+
Dest string `json:"dest,omitempty"`
335+
DstPort uint32 `json:"dst_port,omitempty"`
336+
}
337+
293338
func computeDiff(metadataA, metadataB CheckpointMetadata) *DiffResult {
294339
result := &DiffResult{
295340
ContainerID: metadataA.ID,
@@ -313,6 +358,11 @@ func computeDiff(metadataA, metadataB CheckpointMetadata) *DiffResult {
313358
result.FileChanges = compareFileDescriptors(metadataA.FileDescriptors, metadataB.FileDescriptors)
314359
}
315360

361+
// Compare sockets if requested
362+
if *sockets {
363+
result.SocketChanges = compareSockets(metadataA.Sockets, metadataB.Sockets)
364+
}
365+
316366
// Compare memory
317367
sizeChange := metadataB.CheckpointSize.MemoryPagesSize - metadataA.CheckpointSize.MemoryPagesSize
318368
result.MemoryChanges = &MemoryDiff{
@@ -444,6 +494,82 @@ func compareFileDescriptors(fdsA, fdsB []FileDescriptorEntry) *FileDiff {
444494
return diff
445495
}
446496

497+
func compareSockets(sksA, sksB []SkNode) *SocketDiff {
498+
diff := &SocketDiff{}
499+
500+
// Build socket maps
501+
// Key format: PID:Protocol:Type:Address:SrcPort:Dest:DstPort
502+
mapA := make(map[string]SocketInfo)
503+
mapB := make(map[string]SocketInfo)
504+
505+
for _, entry := range sksA {
506+
for _, socket := range entry.OpenSockets {
507+
key := fmt.Sprintf("%d:%s:%s:%s:%d:%s:%d",
508+
entry.PID,
509+
socket.Protocol,
510+
socket.Data.Type,
511+
socket.Data.Address,
512+
socket.Data.SourcePort,
513+
socket.Data.Dest,
514+
socket.Data.DestPort,
515+
)
516+
mapA[key] = SocketInfo{
517+
PID: int(entry.PID),
518+
Protocol: socket.Protocol,
519+
Type: socket.Data.Type,
520+
Address: socket.Data.Address,
521+
State: socket.Data.State,
522+
Source: socket.Data.Source,
523+
SrcPort: socket.Data.SourcePort,
524+
Dest: socket.Data.Dest,
525+
DstPort: socket.Data.DestPort,
526+
}
527+
}
528+
}
529+
530+
for _, entry := range sksB {
531+
for _, socket := range entry.OpenSockets {
532+
key := fmt.Sprintf("%d:%s:%s:%s:%d:%s:%d",
533+
entry.PID,
534+
socket.Protocol,
535+
socket.Data.Type,
536+
socket.Data.Address,
537+
socket.Data.SourcePort,
538+
socket.Data.Dest,
539+
socket.Data.DestPort,
540+
)
541+
mapB[key] = SocketInfo{
542+
PID: int(entry.PID),
543+
Protocol: socket.Protocol,
544+
Type: socket.Data.Type,
545+
Address: socket.Data.Address,
546+
State: socket.Data.State,
547+
Source: socket.Data.Source,
548+
SrcPort: socket.Data.SourcePort,
549+
Dest: socket.Data.Dest,
550+
DstPort: socket.Data.DestPort,
551+
}
552+
}
553+
}
554+
555+
// Find differences
556+
for key, socketB := range mapB {
557+
if _, exists := mapA[key]; !exists {
558+
diff.Added = append(diff.Added, socketB)
559+
} else {
560+
diff.Unchanged++
561+
}
562+
}
563+
564+
for key, socketA := range mapA {
565+
if _, exists := mapB[key]; !exists {
566+
diff.Removed = append(diff.Removed, socketA)
567+
}
568+
}
569+
570+
return diff
571+
}
572+
447573
func generateSummary(result *DiffResult) string {
448574
summary := fmt.Sprintf("Checkpoint comparison for container %s", result.ContainerName)
449575

@@ -466,6 +592,15 @@ func generateSummary(result *DiffResult) string {
466592
}
467593
}
468594

595+
if result.SocketChanges != nil {
596+
added := len(result.SocketChanges.Added)
597+
removed := len(result.SocketChanges.Removed)
598+
599+
if added > 0 || removed > 0 {
600+
summary += fmt.Sprintf("\nSockets: +%d -%d", added, removed)
601+
}
602+
}
603+
469604
if result.MemoryChanges != nil && result.MemoryChanges.SizeChangeBytes != 0 {
470605
summary += fmt.Sprintf("\nMemory: %+.2f MB", result.MemoryChanges.SizeChangeMB)
471606
}
@@ -564,6 +699,50 @@ func renderTreeDiff(result *DiffResult) {
564699
fmt.Println("└──────────────────────────────────────────────────────────────┘")
565700
}
566701

702+
// Socket changes
703+
if result.SocketChanges != nil {
704+
fmt.Println("┌─ Socket Changes ─────────────────────────────────────────────┐")
705+
706+
if len(result.SocketChanges.Added) > 0 {
707+
fmt.Println("│ Added:")
708+
for _, socket := range result.SocketChanges.Added {
709+
fmt.Printf("│ + PID %-5d %-8s", socket.PID, socket.Protocol)
710+
switch socket.Type {
711+
case "UNIX":
712+
fmt.Printf("%s\n", truncate(socket.Address, 40))
713+
case "TCP", "UDP":
714+
fmt.Printf("%s:%d -> %s:%d\n",
715+
socket.Source, socket.SrcPort,
716+
socket.Dest, socket.DstPort)
717+
default:
718+
fmt.Printf("%s\n", truncate(socket.Address, 40))
719+
}
720+
}
721+
}
722+
723+
if len(result.SocketChanges.Removed) > 0 {
724+
fmt.Println("│ Removed:")
725+
for _, socket := range result.SocketChanges.Removed {
726+
fmt.Printf("│ - PID %-5d %-8s", socket.PID, socket.Protocol)
727+
switch socket.Type {
728+
case "UNIX":
729+
fmt.Printf("%s\n", truncate(socket.Address, 40))
730+
case "TCP", "UDP":
731+
fmt.Printf("%s:%d -> %s:%d\n",
732+
socket.Source, socket.SrcPort,
733+
socket.Dest, socket.DstPort)
734+
default:
735+
fmt.Printf("%s\n", truncate(socket.Address, 40))
736+
}
737+
}
738+
}
739+
740+
if result.SocketChanges.Unchanged > 0 {
741+
fmt.Printf("│ Unchanged: %d\n", result.SocketChanges.Unchanged)
742+
}
743+
fmt.Println("└──────────────────────────────────────────────────────────────┘")
744+
}
745+
567746
// Summary
568747
fmt.Println("Summary:")
569748
fmt.Println(result.Summary)

0 commit comments

Comments
 (0)