netcfg: interface addr node.

This commit is contained in:
Egor Karavaev
2018-01-12 01:22:53 +03:00
parent 1e95808242
commit ae7d9b40f8
2 changed files with 172 additions and 94 deletions
+1 -1
View File
@@ -71,7 +71,7 @@ impl Smolnetd {
.expect("Can't parse the 'mac' cfg");
let local_ip =
IpAddress::from_str(getcfg("ip").unwrap().trim()).expect("Can't parse the 'ip' cfg.");
let protocol_addrs = [
let protocol_addrs = vec![
IpCidr::new(local_ip, 24),
IpCidr::new(IpAddress::v4(127, 0, 0, 1), 8),
];
+171 -93
View File
@@ -1,3 +1,4 @@
// use managed::ManagedSlice;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::fs::File;
@@ -5,8 +6,7 @@ use std::io::{Read, Write};
use std::str;
use std::str::FromStr;
use std::rc::Rc;
use std::iter::FromIterator;
use smoltcp::wire::{EthernetAddress, Ipv4Address};
use smoltcp::wire::{EthernetAddress, IpCidr, Ipv4Address};
use syscall::data::Stat;
use syscall::flag::{MODE_DIR, MODE_FILE};
use syscall::{Error as SyscallError, Packet as SyscallPacket, Result as SyscallResult, SchemeMut};
@@ -32,11 +32,11 @@ trait CfgNode {
true
}
fn read(&self) -> Vec<u8> {
vec![]
fn read(&self) -> String {
String::new()
}
fn write(&self, _buf: &[u8]) -> SyscallResult<usize> {
fn write(&self, _buf: &str) -> SyscallResult<usize> {
Ok(0)
}
@@ -47,23 +47,23 @@ trait CfgNode {
struct RONode<F>
where
F: Fn() -> Vec<u8>,
F: Fn() -> String,
{
read_fun: F,
}
impl<F> CfgNode for RONode<F>
where
F: Fn() -> Vec<u8>,
F: Fn() -> String,
{
fn read(&self) -> Vec<u8> {
fn read(&self) -> String {
(self.read_fun)()
}
}
impl<F> RONode<F>
where
F: 'static + Fn() -> Vec<u8>,
F: 'static + Fn() -> String,
{
fn new(read_fun: F) -> CfgNodeRef {
Rc::new(RefCell::new(RONode { read_fun }))
@@ -72,16 +72,16 @@ where
struct WONode<F>
where
F: Fn(&[u8]) -> SyscallResult<usize>,
F: Fn(&str) -> SyscallResult<usize>,
{
write_fun: F,
}
impl<F> CfgNode for WONode<F>
where
F: Fn(&[u8]) -> SyscallResult<usize>,
F: Fn(&str) -> SyscallResult<usize>,
{
fn write(&self, buf: &[u8]) -> SyscallResult<usize> {
fn write(&self, buf: &str) -> SyscallResult<usize> {
(self.write_fun)(buf)
}
@@ -92,7 +92,7 @@ where
impl<F> WONode<F>
where
F: 'static + Fn(&[u8]) -> SyscallResult<usize>,
F: 'static + Fn(&str) -> SyscallResult<usize>,
{
fn new(write_fun: F) -> CfgNodeRef {
Rc::new(RefCell::new(WONode { write_fun }))
@@ -101,8 +101,8 @@ where
struct RWNode<F, G>
where
F: Fn() -> Vec<u8>,
G: Fn(&[u8]) -> SyscallResult<usize>,
F: Fn() -> String,
G: Fn(&str) -> SyscallResult<usize>,
{
read_fun: F,
write_fun: G,
@@ -110,14 +110,14 @@ where
impl<F, G> CfgNode for RWNode<F, G>
where
F: Fn() -> Vec<u8>,
G: Fn(&[u8]) -> SyscallResult<usize>,
F: Fn() -> String,
G: Fn(&str) -> SyscallResult<usize>,
{
fn read(&self) -> Vec<u8> {
fn read(&self) -> String {
(self.read_fun)()
}
fn write(&self, buf: &[u8]) -> SyscallResult<usize> {
fn write(&self, buf: &str) -> SyscallResult<usize> {
(self.write_fun)(buf)
}
@@ -128,8 +128,8 @@ where
impl<F, G> RWNode<F, G>
where
F: 'static + Fn() -> Vec<u8>,
G: 'static + Fn(&[u8]) -> SyscallResult<usize>,
F: 'static + Fn() -> String,
G: 'static + Fn(&str) -> SyscallResult<usize>,
{
fn new(read_fun: F, write_fun: G) -> CfgNodeRef {
Rc::new(RefCell::new(RWNode {
@@ -148,13 +148,13 @@ impl CfgNode for StaticDirNode {
true
}
fn read(&self) -> Vec<u8> {
let mut files = vec![];
fn read(&self) -> String {
let mut files = String::new();
for child in self.child_nodes.keys() {
if !files.is_empty() {
files.push(b'\n');
files.push('\n');
}
files.extend(child.bytes());
files += child;
}
files
}
@@ -170,8 +170,45 @@ impl StaticDirNode {
}
}
fn parse_default_gw(buf: &[u8]) -> SyscallResult<Ipv4Address> {
let value = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
macro_rules! cfg_node {
(val $e:expr) => {
$e
};
(ro [ $($c:ident)* ] || $b:block ) => {
{
$(let $c = $c.clone();)*
RONode::new(move|| $b)
}
};
(wo [ $($c:ident)* ] |$i:ident| $b:block ) => {
{
$(let $c = $c.clone();)*
WONode::new(move |$i: &str| $b)
}
};
(rw [ $($c:ident)* ] || $rb:block |$i:ident| $wb:block ) => {
{
let read_fun = {
$(let $c = $c.clone();)*
move || $rb
};
let write_fun = {
$(let $c = $c.clone();)*
move |$i: &str| $wb
};
RWNode::new(read_fun, write_fun)
}
};
($($e:expr => { $($t:tt)* }),* $(,)*) => {
{
let mut children = BTreeMap::new();
$(children.insert($e.into(), cfg_node!($($t)*));)*
StaticDirNode::new(children)
}
};
}
fn parse_default_gw(value: &str) -> SyscallResult<Ipv4Address> {
let mut routes = value.lines();
if let Some(route) = routes.next() {
if !routes.next().is_none() {
@@ -190,71 +227,110 @@ fn parse_default_gw(buf: &[u8]) -> SyscallResult<Ipv4Address> {
Err(SyscallError::new(syscall::EINVAL))
}
fn mk_route_node(iface: &Interface) -> CfgNodeRef {
let iface_ = Rc::clone(iface);
let route_list_node = RONode::new(move || {
let default_route = if let Some(ip) = iface_.borrow().ipv4_gateway() {
format!("default via {}\n", ip)
} else {
String::new()
};
Vec::from_iter(default_route.bytes())
});
let iface_ = Rc::clone(iface);
let route_add_node = WONode::new(move |buf: &[u8]| -> SyscallResult<usize> {
let default_gw = parse_default_gw(buf)?;
iface_.borrow_mut().set_ipv4_gateway(Some(default_gw));
Ok(0)
});
let iface_ = Rc::clone(iface);
let route_rm_node = WONode::new(move |buf: &[u8]| -> SyscallResult<usize> {
let default_gw = parse_default_gw(buf)?;
let mut iface = iface_.borrow_mut();
if iface.ipv4_gateway() != Some(default_gw) {
return Err(SyscallError::new(syscall::EINVAL));
}
iface.set_ipv4_gateway(None);
Ok(0)
});
let mut route_child_nodes = BTreeMap::new();
route_child_nodes.insert("list".to_owned(), route_list_node);
route_child_nodes.insert("add".to_owned(), route_add_node);
route_child_nodes.insert("rm".to_owned(), route_rm_node);
StaticDirNode::new(route_child_nodes)
}
fn mk_iface_node(iface: &Interface) -> CfgNodeRef {
let iface_ = Rc::clone(iface);
let iface__ = Rc::clone(iface);
let iface_mac_node = RWNode::new(
move || Vec::from_iter(format!("{}\n", iface_.borrow().ethernet_addr()).bytes()),
move |buf: &[u8]| -> SyscallResult<usize> {
let value = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
let mac =
EthernetAddress::from_str(value).map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !mac.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
iface__.borrow_mut().set_ethernet_addr(mac);
Ok(0)
},
);
let mut iface_child_nodes = BTreeMap::new();
iface_child_nodes.insert("mac".to_owned(), iface_mac_node);
StaticDirNode::new(iface_child_nodes)
}
fn mk_root_node(iface: Interface) -> CfgNodeRef {
let route_node = mk_route_node(&iface);
let mut ifaces_nodes = BTreeMap::new();
ifaces_nodes.insert("eth0".to_owned(), mk_iface_node(&iface));
let ifaces_node = StaticDirNode::new(ifaces_nodes);
let mut root_child_nodes = BTreeMap::new();
root_child_nodes.insert("route".to_owned(), route_node);
root_child_nodes.insert("ifaces".to_owned(), ifaces_node);
StaticDirNode::new(root_child_nodes)
cfg_node!{
"route" => {
"list" => {
ro [iface] || {
if let Some(ip) = iface.borrow().ipv4_gateway() {
format!("default via {}\n", ip)
} else {
String::new()
}
}
},
"add" => {
wo [iface] |routes| {
let default_gw = parse_default_gw(routes)?;
iface.borrow_mut().set_ipv4_gateway(Some(default_gw));
Ok(0)
}
},
"rm" => {
wo [iface] |routes| {
let default_gw = parse_default_gw(routes)?;
let mut iface = iface.borrow_mut();
if iface.ipv4_gateway() != Some(default_gw) {
return Err(SyscallError::new(syscall::EINVAL));
}
iface.set_ipv4_gateway(None);
Ok(0)
}
}
},
"ifaces" => {
"eth0" => {
"mac" => {
rw [iface]
|| {
format!("{}\n", iface.borrow().ethernet_addr())
}
|mac| {
let mac = mac.lines().next()
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
let mac = EthernetAddress::from_str(mac).
map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !mac.is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
iface.borrow_mut().set_ethernet_addr(mac);
Ok(0)
}
},
"addr" => {
"list" => {
ro [iface] || {
let mut ips = String::new();
for cidr in iface.borrow().ip_addrs() {
ips += &format!("{}\n", cidr);
}
ips
}
},
"add" => {
wo [iface] |input| {
let mut iface = iface.borrow_mut();
let mut cidrs = iface.ip_addrs().iter().cloned().collect::<Vec<_>>();
for cidr in input.lines() {
let cidr = IpCidr::from_str(cidr)
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !cidr.address().is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
cidrs.insert(0, cidr);
}
iface.update_ip_addrs(|s| {
*s = From::from(cidrs);
});
Ok(0)
}
},
"rm" => {
wo [iface] |input| {
let mut iface = iface.borrow_mut();
let mut cidrs = iface.ip_addrs().iter().cloned().collect::<Vec<_>>();
for cidr in input.lines() {
let cidr = IpCidr::from_str(cidr)
.map_err(|_| SyscallError::new(syscall::EINVAL))?;
if !cidr.address().is_unicast() {
return Err(SyscallError::new(syscall::EINVAL));
}
let pre_retain_len = cidrs.len();
cidrs.retain(|&c| c != cidr);
if pre_retain_len == cidrs.len() {
return Err(SyscallError::new(syscall::EINVAL));
}
}
iface.update_ip_addrs(|s| {
*s = From::from(cidrs);
});
Ok(0)
}
},
}
}
}
}
}
struct NetCfgFile {
@@ -309,7 +385,7 @@ impl SchemeMut for NetCfgScheme {
.ok_or_else(|| SyscallError::new(syscall::EINVAL))?;
current_node = next_node;
}
let read_buf = current_node.borrow().read();
let read_buf = Vec::from(current_node.borrow().read());
let fd = self.next_fd;
self.next_fd += 1;
self.files.insert(
@@ -329,7 +405,9 @@ impl SchemeMut for NetCfgScheme {
let file = self.files
.get_mut(&fd)
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
file.cfg_node.borrow().write(&file.write_buf)
let value =
str::from_utf8(&file.write_buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
file.cfg_node.borrow().write(&value)
}
fn write(&mut self, fd: usize, buf: &[u8]) -> SyscallResult<usize> {