// This file demonstrates the type checking capabilities
// Type definitions for comprehensive type checking
include "xdp.kh"
type IpAddress = u32
type PacketSize = u16
struct PacketHeader {
src_ip: IpAddress,
dst_ip: IpAddress,
protocol: u8,
length: PacketSize,
}
enum ProtocolType {
TCP = 6,
UDP = 17,
ICMP = 1
}
enum FilterDecision {
Allow = 0,
Block = 1,
Log = 2
}
// Global map for demonstration
pin var connection_stats : hash(1024)
@helper
fn extract_header(ctx: *xdp_md) -> *PacketHeader {
// Type checker validates context parameter access
var data = ctx->data
var data_end = ctx->data_end
// Type checker ensures arithmetic operations are on numeric types
var packet_len = data_end - data
if (packet_len < 20) {
return null
}
// Type checker validates struct field types
var header: PacketHeader = PacketHeader {
src_ip: 0xC0A80001, // Type checked as u32 (IpAddress)
dst_ip: 0xC0A80002, // Type checked as u32 (IpAddress)
protocol: 6, // Type checked as u8
length: packet_len // Type promoted from arithmetic to u16
}
return &header
}
@helper
fn classify_protocol(proto: u8) -> ProtocolType {
// Type checker validates enum constant access
return match (proto) {
6: TCP,
17: UDP,
1: ICMP,
default: TCP // Default to TCP for unknown protocols
}
}
@helper
fn update_statistics(header: PacketHeader) {
// Type checker validates map operations and key/value types
if (var current_count = connection_stats[header.src_ip]) {
// Type checker ensures arithmetic on compatible types
connection_stats[header.src_ip] = current_count + 1
} else {
// Type checker validates map insert operation
connection_stats[header.src_ip] = 1
}
}
@helper
fn make_decision(header: PacketHeader) -> FilterDecision {
// Type checker validates function call signatures
var proto_type = classify_protocol(header.protocol)
return match (proto_type) {
TCP: {
// Type checker validates field access on struct types
if (header.length > 1500) {
Block
} else {
Allow
}
},
UDP: Allow,
ICMP: Log,
default: Block
}
}
@xdp fn packet_analyzer(ctx: *xdp_md) -> xdp_action {
// Type checker validates context parameter and return type
var packet_header = extract_header(ctx)
if (packet_header == null) {
// Type checker validates return type compatibility
return XDP_DROP
}
// Type checker validates function calls with correct types
update_statistics(*packet_header)
var decision = make_decision(*packet_header)
// Type checker validates match expressions and enum types
return match (decision) {
Allow: XDP_PASS,
Block: XDP_DROP,
Log: {
// Type checker validates built-in function signatures
print("Logging packet", 14)
XDP_PASS
}
}
}
// Additional function demonstrating type inference
fn calculate_bandwidth(packet_count: u64, packet_size: u16) -> u64 {
// Type checker infers result type from operand types
var total_bytes = packet_count * packet_size // u64 * u16 -> u64
var bandwidth = total_bytes * 8 // u64 * literal -> u64
return bandwidth
}
// Function demonstrating error detection
fn type_error_examples() {
// The following would be caught by the type checker:
// 1. Type mismatch in assignment
// var x: u32 = true // ERROR: cannot assign bool to u32
// 2. Invalid field access
// var header: PacketHeader = get_header()
// var invalid = header.nonexistent_field // ERROR: field not found
// 3. Function call with wrong types
// var result = calculate_bandwidth(true, "hello") // ERROR: wrong argument types
// 4. Arithmetic on incompatible types
// var bad_math = 42 + true // ERROR: cannot add u32 and bool
// 5. Missing return in non-void function
// fn missing_return() -> u32 {
// var x = 42
// // ERROR: missing return statement
// }
}
fn main() -> i32 {
var prog = load(packet_analyzer)
attach(prog, "eth0", 0)
print("Type checking demo program attached to eth0")
print("Demonstrating comprehensive type checking capabilities...")
// Show type checking working properly
detach(prog)
print("Type checking demo program detached")
return 0
}