Skip to content

Commit

Permalink
virt2boundary (v2b) plumbing
Browse files Browse the repository at this point in the history
  • Loading branch information
rcgoodfellow committed Jun 30, 2023
1 parent 231043d commit d0a9cf6
Show file tree
Hide file tree
Showing 11 changed files with 309 additions and 80 deletions.
24 changes: 24 additions & 0 deletions bin/opteadm/src/bin/opteadm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ use oxide_vpc::api::RemFwRuleReq;
use oxide_vpc::api::RouterTarget;
use oxide_vpc::api::SNat4Cfg;
use oxide_vpc::api::SNat6Cfg;
use oxide_vpc::api::SetVirt2BoundaryReq;
use oxide_vpc::api::SetVirt2PhysReq;
use oxide_vpc::api::VpcCfg;
use oxide_vpc::engine::print::print_v2b;
use oxide_vpc::engine::print::print_v2p;

/// Administer the Oxide Packet Transformation Engine (OPTE)
Expand Down Expand Up @@ -82,6 +84,9 @@ enum Command {
/// Dump virtual to physical address mapping
DumpV2P,

/// Dump virtual to boundary address mapping
DumpV2B,

/// Add a firewall rule
AddFwRule {
#[structopt(short)]
Expand Down Expand Up @@ -203,6 +208,9 @@ enum Command {
/// Set a virtual-to-physical mapping
SetV2P { vpc_ip: IpAddr, vpc_mac: MacAddr, underlay_ip: Ipv6Addr, vni: Vni },

/// Set a virtual-to-boundary mapping
SetV2B { vpc_ip: IpAddr, vpc_mac: MacAddr, underlay_ip: Ipv6Addr },

/// Add a new router entry, either IPv4 or IPv6.
AddRouterEntry {
/// The OPTE port to which the route is added
Expand Down Expand Up @@ -312,6 +320,11 @@ fn main() -> anyhow::Result<()> {
print_v2p(&hdl.dump_v2p()?);
}

Command::DumpV2B => {
let hdl = opteadm::OpteAdm::open(OpteAdm::XDE_CTL)?;
print_v2b(&hdl.dump_v2b()?);
}

Command::AddFwRule { port, direction, filters, action, priority } => {
let hdl = opteadm::OpteAdm::open(OpteAdm::XDE_CTL)?;
let rule = FirewallRule {
Expand Down Expand Up @@ -478,6 +491,17 @@ fn main() -> anyhow::Result<()> {
hdl.set_v2p(&req)?;
}

Command::SetV2B { vpc_ip, vpc_mac, underlay_ip } => {
let hdl = opteadm::OpteAdm::open(OpteAdm::XDE_CTL)?;
let phys = PhysNet {
ether: vpc_mac,
ip: underlay_ip,
vni: Vni::new(99u32).unwrap(),
};
let req = SetVirt2BoundaryReq { vip: vpc_ip, phys };
hdl.set_v2b(&req)?;
}

Command::AddRouterEntry { port, dest, target } => {
let hdl = opteadm::OpteAdm::open(OpteAdm::XDE_CTL)?;
let req = AddRouterEntryReq { port_name: port, dest, target };
Expand Down
16 changes: 16 additions & 0 deletions bin/opteadm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use oxide_vpc::api::FirewallRule;
use oxide_vpc::api::ListPortsResp;
use oxide_vpc::api::RemFwRuleReq;
use oxide_vpc::api::SetFwRulesReq;
use oxide_vpc::api::SetVirt2BoundaryReq;
use oxide_vpc::api::SetVirt2PhysReq;
use oxide_vpc::api::VpcCfg;
use oxide_vpc::engine::overlay;
Expand Down Expand Up @@ -206,6 +207,21 @@ impl OpteAdm {
)
}

pub fn set_v2b(&self, req: &SetVirt2BoundaryReq) -> Result<NoResp, Error> {
let cmd = OpteCmd::SetVirt2Boundary;
run_cmd_ioctl(self.device.as_raw_fd(), cmd, Some(&req))
}

/// Dump the Virtual-to-Boundary mappings.
pub fn dump_v2b(&self) -> Result<overlay::DumpVirt2BoundaryResp, Error> {
let cmd = OpteCmd::DumpVirt2Boundary;
run_cmd_ioctl(
self.device.as_raw_fd(),
cmd,
Some(&overlay::DumpVirt2BoundaryReq { unused: 99 }),
)
}

pub fn add_router_entry(
&self,
req: &AddRouterEntryReq,
Expand Down
34 changes: 19 additions & 15 deletions crates/opte-api/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,23 @@ pub const XDE_IOC_OPTE_CMD: i32 = XDE_IOC as i32 | 0x01;
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub enum OpteCmd {
ListPorts = 1, // list all ports
AddFwRule = 20, // add firewall rule
RemFwRule = 21, // remove firewall rule
SetFwRules = 22, // set/replace all firewall rules at once
DumpTcpFlows = 30, // dump TCP flows
DumpLayer = 31, // dump the specified Layer
DumpUft = 32, // dump the Unified Flow Table
ListLayers = 33, // list the layers on a given port
ClearUft = 40, // clear the UFT
SetVirt2Phys = 50, // set a v2p mapping
DumpVirt2Phys = 51, // dump the v2p mappings
AddRouterEntry = 60, // add a router entry for IP dest
CreateXde = 70, // create a new xde device
DeleteXde = 71, // delete an xde device
SetXdeUnderlay = 72, // set xde underlay devices
ListPorts = 1, // list all ports
AddFwRule = 20, // add firewall rule
RemFwRule = 21, // remove firewall rule
SetFwRules = 22, // set/replace all firewall rules at once
DumpTcpFlows = 30, // dump TCP flows
DumpLayer = 31, // dump the specified Layer
DumpUft = 32, // dump the Unified Flow Table
ListLayers = 33, // list the layers on a given port
ClearUft = 40, // clear the UFT
SetVirt2Phys = 50, // set a v2p mapping
DumpVirt2Phys = 51, // dump the v2p mappings
SetVirt2Boundary = 52, // set a v2b mapping
DumpVirt2Boundary = 53, // dump the v2b mappings
AddRouterEntry = 60, // add a router entry for IP dest
CreateXde = 70, // create a new xde device
DeleteXde = 71, // delete an xde device
SetXdeUnderlay = 72, // set xde underlay devices
}

impl TryFrom<c_int> for OpteCmd {
Expand All @@ -60,6 +62,8 @@ impl TryFrom<c_int> for OpteCmd {
40 => Ok(Self::ClearUft),
50 => Ok(Self::SetVirt2Phys),
51 => Ok(Self::DumpVirt2Phys),
52 => Ok(Self::SetVirt2Boundary),
53 => Ok(Self::DumpVirt2Boundary),
60 => Ok(Self::AddRouterEntry),
70 => Ok(Self::CreateXde),
71 => Ok(Self::DeleteXde),
Expand Down
23 changes: 20 additions & 3 deletions lib/oxide-vpc/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ impl From<PhysNet> for GuestPhysAddr {
#[derive(Clone, Debug, Copy, Deserialize, Serialize)]
pub enum RouterTarget {
Drop,
InternetGateway,
InternetGateway(IpAddr),
Ip(IpAddr),
VpcSubnet(IpCidr),
}
Expand All @@ -418,8 +418,13 @@ impl FromStr for RouterTarget {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"drop" => Ok(Self::Drop),
"ig" => Ok(Self::InternetGateway),
lower => match lower.split_once('=') {
Some(("ig4", ip4s)) => {
let ip4 = ip4s
.parse::<std::net::Ipv4Addr>()
.map_err(|e| format!("bad IP: {}", e))?;
Ok(Self::InternetGateway(IpAddr::Ip4(ip4.into())))
}
Some(("ip4", ip4s)) => {
let ip4 = ip4s
.parse::<std::net::Ipv4Addr>()
Expand All @@ -436,6 +441,10 @@ impl FromStr for RouterTarget {
ip6s.parse().map(|x| Self::Ip(IpAddr::Ip6(x)))
}

Some(("ig6", ip6s)) => {
ip6s.parse().map(|x| Self::InternetGateway(IpAddr::Ip6(x)))
}

Some(("sub6", cidr6s)) => {
cidr6s.parse().map(|x| Self::VpcSubnet(IpCidr::Ip6(x)))
}
Expand All @@ -450,7 +459,8 @@ impl Display for RouterTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Drop => write!(f, "Drop"),
Self::InternetGateway => write!(f, "IG"),
Self::InternetGateway(IpAddr::Ip4(ip4)) => write!(f, "ig4={}", ip4),
Self::InternetGateway(IpAddr::Ip6(ip6)) => write!(f, "ig6={}", ip6),
Self::Ip(IpAddr::Ip4(ip4)) => write!(f, "ip4={}", ip4),
Self::Ip(IpAddr::Ip6(ip6)) => write!(f, "ip6={}", ip6),
Self::VpcSubnet(IpCidr::Ip4(sub4)) => write!(f, "sub4={}", sub4),
Expand Down Expand Up @@ -529,6 +539,13 @@ pub struct SetVirt2PhysReq {
pub phys: PhysNet,
}

/// Set mapping from VPC IP to boundary tunnel endpoint destination.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SetVirt2BoundaryReq {
pub vip: IpAddr,
pub phys: PhysNet,
}

/// Add an entry to the router. Addresses may be either IPv4 or IPv6, though the
/// destination and target must match in protocol version.
#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down
15 changes: 11 additions & 4 deletions lib/oxide-vpc/src/engine/nat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use opte::api::Direction;
use opte::api::OpteError;
use opte::engine::ether::ETHER_TYPE_IPV4;
use opte::engine::ether::ETHER_TYPE_IPV6;
use opte::engine::headers::IpAddr;
use opte::engine::layer::DefaultAction;
use opte::engine::layer::Layer;
use opte::engine::layer::LayerActions;
Expand Down Expand Up @@ -87,7 +88,7 @@ fn setup_ipv4_nat(
]));
out_nat.add_predicate(Predicate::Meta(
RouterTargetInternal::KEY.to_string(),
RouterTargetInternal::InternetGateway.as_meta(),
RouterTargetInternal::InternetGateway(IpAddr::Ip4(ip4)).as_meta(),
));
layer.add_rule(Direction::Out, out_nat.finalize());

Expand Down Expand Up @@ -116,7 +117,10 @@ fn setup_ipv4_nat(
]));
rule.add_predicate(Predicate::Meta(
RouterTargetInternal::KEY.to_string(),
RouterTargetInternal::InternetGateway.as_meta(),
RouterTargetInternal::InternetGateway(IpAddr::Ip4(
snat_cfg.external_ip,
))
.as_meta(),
));
layer.add_rule(Direction::Out, rule.finalize());
}
Expand All @@ -141,7 +145,7 @@ fn setup_ipv6_nat(
]));
out_nat.add_predicate(Predicate::Meta(
RouterTargetInternal::KEY.to_string(),
RouterTargetInternal::InternetGateway.as_meta(),
RouterTargetInternal::InternetGateway(IpAddr::Ip6(ip6)).as_meta(),
));
layer.add_rule(Direction::Out, out_nat.finalize());

Expand Down Expand Up @@ -170,7 +174,10 @@ fn setup_ipv6_nat(
]));
rule.add_predicate(Predicate::Meta(
RouterTargetInternal::KEY.to_string(),
RouterTargetInternal::InternetGateway.as_meta(),
RouterTargetInternal::InternetGateway(IpAddr::Ip6(
snat_cfg.external_ip,
))
.as_meta(),
));
layer.add_rule(Direction::Out, rule.finalize());
}
Expand Down
Loading

0 comments on commit d0a9cf6

Please sign in to comment.