Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat : Added cidr manipulation functions to net module #1798

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions kclvm/runtime/src/_kclvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,14 @@ kclvm_value_ref_t* kclvm_net_is_IPv4(kclvm_context_t* ctx, kclvm_value_ref_t* ar

kclvm_value_ref_t* kclvm_net_is_global_unicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs);

kclvm_value_ref_t* kclvm_net_parse_CIDR (kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs);

kclvm_value_ref_t* kclvm_net_hosts_in_CIDR (kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs);

kclvm_value_ref_t* kclvm_net_subnets_from_CIDR (kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs);

kclvm_value_ref_t* kclvm_net_is_IP_in_CIDR (kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs);

kclvm_value_ref_t* kclvm_net_is_interface_local_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs);

kclvm_value_ref_t* kclvm_net_is_link_local_multicast_IP(kclvm_context_t* ctx, kclvm_value_ref_t* args, kclvm_value_ref_t* _kwargs);
Expand Down
4 changes: 4 additions & 0 deletions kclvm/runtime/src/_kclvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ pub enum ApiFunc {
kclvm_net_is_IP,
kclvm_net_is_IPv4,
kclvm_net_is_global_unicast_IP,
kclvm_net_parse_CIDR,
kclvm_net_hosts_in_CIDR,
kclvm_net_subnets_from_CIDR,
kclvm_net_is_IP_in_CIDR,
kclvm_net_is_interface_local_multicast_IP,
kclvm_net_is_link_local_multicast_IP,
kclvm_net_is_link_local_unicast_IP,
Expand Down
4 changes: 4 additions & 0 deletions kclvm/runtime/src/_kclvm_addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ pub fn _kclvm_get_fn_ptr_by_name(name: &str) -> u64 {
"kclvm_net_is_loopback_IP" => crate::kclvm_net_is_loopback_IP as *const () as u64,
"kclvm_net_is_multicast_IP" => crate::kclvm_net_is_multicast_IP as *const () as u64,
"kclvm_net_is_unspecified_IP" => crate::kclvm_net_is_unspecified_IP as *const () as u64,
"kclvm_net_parse_CIDR" => crate::kclvm_net_parse_CIDR as *const () as u64,
"kclvm_net_hosts_in_CIDR" => crate::kclvm_net_hosts_in_CIDR as *const () as u64,
"kclvm_net_subnets_from_CIDR" => crate::kclvm_net_subnets_from_CIDR as *const () as u64,
"kclvm_net_is_IP_in_CIDR" => crate::kclvm_net_is_IP_in_CIDR as *const () as u64,
"kclvm_net_join_host_port" => crate::kclvm_net_join_host_port as *const () as u64,
"kclvm_net_parse_IP" => crate::kclvm_net_parse_IP as *const () as u64,
"kclvm_net_split_host_port" => crate::kclvm_net_split_host_port as *const () as u64,
Expand Down
135 changes: 135 additions & 0 deletions kclvm/runtime/src/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,141 @@ pub extern "C" fn kclvm_net_is_global_unicast_IP(
panic!("is_global_unicast_IP() missing 1 required positional argument: 'ip'");
}

#[no_mangle]
#[runtime_fn]
pub extern "C" fn kclvm_net_parse_CIDR(
ctx: *mut kclvm_context_t,
args: *const kclvm_value_ref_t,
kwargs: *const kclvm_value_ref_t,
) -> *const kclvm_value_ref_t {
let args = ptr_as_ref(args);
let kwargs = ptr_as_ref(kwargs);
let ctx = mut_ptr_as_ref(ctx);

if let Some(cidr) = get_call_arg_str(args, kwargs, 0, Some("cidr")) {
let parts: Vec<&str> = cidr.split('/').collect();
if parts.len() == 2 {
let ip = parts[0];
let mask = parts[1];
if let Ok(ip) = Ipv4Addr::from_str(ip) {
if let Ok(mask) = mask.parse::<u8>() {
let ip_value = ValueRef::str(ip.to_string().as_str());
let mask_value = ValueRef::int(mask as i64);
return ValueRef::dict(Some(&[("ip", &ip_value), ("mask", &mask_value)]))
.into_raw(ctx);
}
}
}
return ValueRef::dict(None).into_raw(ctx);
}

panic!("parse_CIDR() missing 1 required positional argument: 'cidr'");
}

#[no_mangle]
#[runtime_fn]
pub extern "C" fn kclvm_net_hosts_in_CIDR(
ctx: *mut kclvm_context_t,
args: *const kclvm_value_ref_t,
kwargs: *const kclvm_value_ref_t,
) -> *const kclvm_value_ref_t {
let args = ptr_as_ref(args);
let kwargs = ptr_as_ref(kwargs);
let ctx = mut_ptr_as_ref(ctx);

if let Some(cidr) = get_call_arg_str(args, kwargs, 0, Some("cidr")) {
let parts: Vec<&str> = cidr.split('/').collect();
if parts.len() == 2 {
let ip = parts[0];
let mask = parts[1];
if let Ok(ip) = Ipv4Addr::from_str(ip) {
if let Ok(mask) = mask.parse::<u8>() {
let mask = u32::from_be_bytes(ip.octets()) & !((1 << (32 - mask)) - 1);
let mut hosts = vec![];
for i in 1..(1 << (32 - mask)) - 1 {
let ip = u32::from_be_bytes(ip.octets()) + i;
hosts.push(ValueRef::str(Ipv4Addr::from(ip).to_string().as_str()));
}
let hosts_refs: Vec<&ValueRef> = hosts.iter().collect();
return ValueRef::list(Some(&hosts_refs[..])).into_raw(ctx);
}
}
}
return ValueRef::list(None).into_raw(ctx);
}

panic!("hosts_in_CIDR() missing 1 required positional argument: 'cidr'");
}

#[no_mangle]
#[runtime_fn]
pub extern "C" fn kclvm_net_subnets_from_CIDR(
ctx: *mut kclvm_context_t,
args: *const kclvm_value_ref_t,
kwargs: *const kclvm_value_ref_t,
) -> *const kclvm_value_ref_t {
let args = ptr_as_ref(args);
let kwargs = ptr_as_ref(kwargs);
let ctx = mut_ptr_as_ref(ctx);

if let Some(cidr) = get_call_arg_str(args, kwargs, 0, Some("cidr")) {
let parts: Vec<&str> = cidr.split('/').collect();
if parts.len() == 2 {
let ip = parts[0];
let mask = parts[1];
if let Ok(ip) = Ipv4Addr::from_str(ip) {
if let Ok(mask) = mask.parse::<u8>() {
let mask = u32::from_be_bytes(ip.octets()) & !((1 << (32 - mask)) - 1);
let mut subnets = vec![];
for i in 1..(1 << (32 - mask)) - 1 {
let ip = u32::from_be_bytes(ip.octets()) + i;
subnets.push(ValueRef::str(
format!("{}/{}", Ipv4Addr::from(ip), mask).as_str(),
));
}
let subnets_refs: Vec<&ValueRef> = subnets.iter().collect();
return ValueRef::list(Some(&subnets_refs)).into_raw(ctx);
}
}
}
return ValueRef::list(None).into_raw(ctx);
}

panic!("subnets_from_CIDR() missing 1 required positional argument: 'cidr'");
}

#[no_mangle]
#[runtime_fn]
pub extern "C" fn kclvm_net_is_IP_in_CIDR(
ctx: *mut kclvm_context_t,
args: *const kclvm_value_ref_t,
kwargs: *const kclvm_value_ref_t,
) -> *const kclvm_value_ref_t {
let args = ptr_as_ref(args);
let kwargs = ptr_as_ref(kwargs);

if let Some(ip) = get_call_arg_str(args, kwargs, 0, Some("ip")) {
if let Some(cidr) = get_call_arg_str(args, kwargs, 1, Some("cidr")) {
let parts: Vec<&str> = cidr.split('/').collect();
if parts.len() == 2 {
let ip = parts[0];
let mask = parts[1];
if let Ok(ip) = Ipv4Addr::from_str(ip) {
if let Ok(mask) = mask.parse::<u8>() {
let mask = u32::from_be_bytes(ip.octets()) & !((1 << (32 - mask)) - 1);
let ip = u32::from_be_bytes(ip.octets());
let x = (ip & mask) == mask;
return kclvm_value_Bool(ctx, x as i8);
}
}
}
}
return kclvm_value_False(ctx);
}

panic!("is_IP_in_CIDR() missing 2 required positional arguments: 'ip' and 'cidr'");
}

#[allow(non_camel_case_types, non_snake_case)]
fn Ipv4Addr_is_global(_self: &std::net::Ipv4Addr) -> bool {
// check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two
Expand Down
78 changes: 78 additions & 0 deletions kclvm/sema/src/builtin/system_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,84 @@ register_net_member! {
false,
None,
)
parse_CIDR => Type::function(
None,
Type::dict_ref(Type::str_ref(), Type::str_ref()),
&[
Parameter {
name: "cidr".to_string(),
ty: Type::str_ref(),
has_default: false,
default_value: None,
range: dummy_range(),
},
],
r#"Parse a CIDR block into network, prefix, minHost, and maxHost."#,
false,
None,
)
hosts_in_CIDR => Type::function(
None,
Type::list_ref(Type::str_ref()),
&[
Parameter {
name: "cidr".to_string(),
ty: Type::str_ref(),
has_default: false,
default_value: None,
range: dummy_range(),
},
],
r#"Generate a list of all IP addresses in a CIDR block."#,
false,
None,
)
subnets_from_CIDR => Type::function(
None,
Type::list_ref(Type::str_ref()),
&[
Parameter {
name: "cidr".to_string(),
ty: Type::str_ref(),
has_default: false,
default_value: None,
range: dummy_range(),
},
Parameter {
name: "new_prefix".to_string(),
ty: Type::int_ref(),
has_default: false,
default_value: None,
range: dummy_range(),
},
],
r#"Split a CIDR block into smaller subnets with a given prefix."#,
false,
None,
)
is_IP_in_CIDR => Type::function(
None,
Type::bool_ref(),
&[
Parameter {
name: "ip".to_string(),
ty: Type::str_ref(),
has_default: false,
default_value: None,
range: dummy_range(),
},
Parameter {
name: "cidr".to_string(),
ty: Type::str_ref(),
has_default: false,
default_value: None,
range: dummy_range(),
},
],
r#"Check if an IP address is within a given CIDR block."#,
false,
None,
)
}

// ------------------------------
Expand Down
5 changes: 5 additions & 0 deletions test/grammar/builtins/net/is_ip_2/main.k
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ isip2 = net.is_link_local_multicast_IP("224.0.0.0")
isip3 = net.is_link_local_unicast_IP("fe80::2012:1")
isip4 = net.is_global_unicast_IP("220.181.108.89")
isip5 = net.is_unspecified_IP("0.0.0.0")
isip6 = net.parse_CIDR("192.168.1.0/24")
isip7 = net.hosts_in_CIDR("192.168.1.0/24")
isip8 = net.subnets_from_CIDR("192.168.1.0/24")
isip9 = net.is_IP_in_CIDR("192.168.1.1", "192.168.1.0/24")

Loading