diff --git a/dpd/src/nat.rs b/dpd/src/nat.rs index b2227722..7d654f10 100644 --- a/dpd/src/nat.rs +++ b/dpd/src/nat.rs @@ -11,7 +11,8 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::ops::Bound; use crate::Switch; -use crate::table::nat; +use crate::table; +use crate::table::nat::{add_entry, delete_entry}; use crate::types::{DpdError, DpdResult}; use common::nat::{Ipv4Nat, Ipv6Nat}; use common::network::NatTarget; @@ -45,6 +46,14 @@ impl PortRange { fn overlaps(self, other: PortRange) -> bool { self.low <= other.high && self.high >= other.low } + + pub(crate) fn low(self) -> u16 { + self.low + } + + pub(crate) fn high(self) -> u16 { + self.high + } } impl fmt::Display for PortRange { @@ -277,7 +286,7 @@ pub fn set_ipv6_mapping( } }; - match nat::add_ipv6_entry(switch, nat_ip, low, high, tgt) { + match add_entry(switch, nat_ip, l4_ports, tgt) { Err(e) => { error!(switch.log, "failed to add {}: {:?}", full, e); Err(e) @@ -311,12 +320,7 @@ pub fn clear_ipv6_mapping( nat.ipv6_mappings.remove(&nat_ip); } let full = ipv6_entry(nat_ip, &ent); - return match nat::delete_ipv6_entry( - switch, - nat_ip, - ent.l4_ports.low, - ent.l4_ports.high, - ) { + return match delete_entry(switch, nat_ip, ent.l4_ports) { Err(e) => { error!(switch.log, "failed to clear {}: {:?}", full, e); Err(e) @@ -452,7 +456,7 @@ pub fn set_ipv4_mapping( } }; - match nat::add_ipv4_entry(switch, nat_ip, low, high, tgt) { + match add_entry(switch, nat_ip, l4_ports, tgt) { Err(e) => { error!(switch.log, "failed to add nat entry {}: {:?}", full, e); Err(e) @@ -501,12 +505,7 @@ pub fn clear_ipv4_mapping( nat.ipv4_mappings.remove(&nat_ip); } let full = ipv4_entry(nat_ip, &ent); - return match nat::delete_ipv4_entry( - switch, - nat_ip, - ent.l4_ports.low, - ent.l4_ports.high, - ) { + return match delete_entry(switch, nat_ip, ent.l4_ports) { Err(e) => { error!(switch.log, "failed to clear {}: {:?}", full, e); Err(e) @@ -561,12 +560,7 @@ pub fn clear_overlapping_mappings_v4( for idx in mappings_to_delete { let ent = mappings.remove(idx); let full = ipv4_entry(nat_ip, &ent); - match nat::delete_ipv4_entry( - switch, - nat_ip, - ent.l4_ports.low, - ent.l4_ports.high, - ) { + match delete_entry(switch, nat_ip, ent.l4_ports) { Err(e) => { error!(switch.log, "failed to clear {}: {:?}", full, e); return Err(e); @@ -606,12 +600,7 @@ pub fn clear_overlapping_mappings_v6( for idx in mappings_to_delete { let ent = mappings.remove(idx); let full = ipv6_entry(nat_ip, &ent); - match nat::delete_ipv6_entry( - switch, - nat_ip, - ent.l4_ports.low, - ent.l4_ports.high, - ) { + match delete_entry(switch, nat_ip, ent.l4_ports) { Err(e) => { error!(switch.log, "failed to clear {}: {:?}", full, e); return Err(e); @@ -632,27 +621,15 @@ pub fn clear_overlapping_mappings_v6( pub fn reset_ipv6(switch: &Switch) -> DpdResult<()> { let mut nat = switch.nat.lock().unwrap(); - debug!(switch.log, "resetting ipv6 nat tables"); nat.ipv6_mappings.clear(); - if let Err(e) = nat::reset_ipv6(switch) { - error!(switch.log, "failed to reset ipv6 nat table: {:?}", e); - Err(e) - } else { - Ok(()) - } + table::nat::reset::(switch) } pub fn reset_ipv4(switch: &Switch) -> DpdResult<()> { let mut nat = switch.nat.lock().unwrap(); - debug!(switch.log, "resetting ipv4 nat tables"); nat.ipv4_mappings.clear(); - if let Err(e) = nat::reset_ipv4(switch) { - error!(switch.log, "failed to reset ipv4 nat table: {:?}", e); - Err(e) - } else { - Ok(()) - } + table::nat::reset::(switch) } pub fn set_nat_generation(switch: &Switch, generation: i64) { diff --git a/dpd/src/table/mod.rs b/dpd/src/table/mod.rs index 3afbd8cc..5a98e7fc 100644 --- a/dpd/src/table/mod.rs +++ b/dpd/src/table/mod.rs @@ -6,6 +6,7 @@ use std::convert::TryFrom; use std::hash::Hash; +use std::net::{Ipv4Addr, Ipv6Addr}; use common::table; use slog::debug; @@ -233,10 +234,10 @@ pub fn get_entries( } TableType::ArpIpv4 => arp_ipv4::table_dump(switch, from_hardware), TableType::NatIngressIpv4 => { - nat::ipv4_table_dump(switch, from_hardware) + nat::table_dump::(switch, from_hardware) } TableType::NatIngressIpv6 => { - nat::ipv6_table_dump(switch, from_hardware) + nat::table_dump::(switch, from_hardware) } TableType::AttachedSubnetIpv4 => { attached_subnet_v4::table_dump(switch, from_hardware) @@ -329,10 +330,10 @@ pub fn get_counters( TableType::ArpIpv4 => arp_ipv4::counter_fetch(switch, force_sync), TableType::PortMacAddress => mac::counter_fetch(switch, force_sync), TableType::NatIngressIpv4 => { - nat::ipv4_counter_fetch(switch, force_sync) + nat::counter_fetch::(switch, force_sync) } TableType::NatIngressIpv6 => { - nat::ipv6_counter_fetch(switch, force_sync) + nat::counter_fetch::(switch, force_sync) } TableType::PortAddrIpv4 => { port_ip::ipv4_counter_fetch(switch, force_sync) diff --git a/dpd/src/table/nat.rs b/dpd/src/table/nat.rs index 5d15f3ca..b09b3210 100644 --- a/dpd/src/table/nat.rs +++ b/dpd/src/table/nat.rs @@ -7,19 +7,114 @@ use dpd_types::table; use std::convert::TryInto; use std::fmt; +use std::hash::Hash; use std::net::{Ipv4Addr, Ipv6Addr}; -use slog::debug; +use slog::{debug, error}; use aal::{ActionParse, MatchParse, MatchRange}; use aal_macros::*; use crate::Switch; +use crate::nat::PortRange; use crate::table::*; use common::network::{MacAddr, NatTarget}; +pub(crate) trait NatAddress: Copy + Ord + fmt::Display { + const TABLE: TableType; + const NAME: &'static str; + + type MatchKey: MatchParse + Hash + fmt::Display; + type Action: ActionParse; + + fn match_key(self, ports: PortRange) -> Self::MatchKey; + fn action(tgt: NatTarget) -> Self::Action; +} + +pub(crate) fn add_entry( + s: &Switch, + nat_ip: A, + ports: PortRange, + tgt: NatTarget, +) -> DpdResult<()> { + let key = nat_ip.match_key(ports); + debug!(s.log, "add nat entry {} -> {:?}", key, tgt); + s.table_entry_add(A::TABLE, &key, &A::action(tgt)) +} + +pub(crate) fn delete_entry( + s: &Switch, + nat_ip: A, + ports: PortRange, +) -> DpdResult<()> { + let key = nat_ip.match_key(ports); + debug!(s.log, "remove nat entry {}", key); + s.table_entry_del(A::TABLE, &key) +} + +pub(crate) fn table_dump( + s: &Switch, + from_hardware: bool, +) -> DpdResult { + s.table_dump::(A::TABLE, from_hardware) +} + +pub(crate) fn counter_fetch( + s: &Switch, + force_sync: bool, +) -> DpdResult> { + s.counter_fetch::(force_sync, A::TABLE) +} + +pub(crate) fn reset(s: &Switch) -> DpdResult<()> { + debug!(s.log, "resetting {} nat table", A::NAME); + s.table_clear(A::TABLE).inspect_err(|e| { + error!(s.log, "failed to reset {} nat table: {:?}", A::NAME, e); + }) +} + +impl NatAddress for Ipv4Addr { + const TABLE: TableType = TableType::NatIngressIpv4; + const NAME: &'static str = "ipv4"; + + type MatchKey = Ipv4MatchKey; + type Action = Ipv4Action; + + fn match_key(self, ports: PortRange) -> Ipv4MatchKey { + Ipv4MatchKey::new(self, ports.low(), ports.high()) + } + + fn action(tgt: NatTarget) -> Ipv4Action { + Ipv4Action::Forward { + target: tgt.internal_ip, + inner_mac: tgt.inner_mac, + vni: tgt.vni.as_u32(), + } + } +} + +impl NatAddress for Ipv6Addr { + const TABLE: TableType = TableType::NatIngressIpv6; + const NAME: &'static str = "ipv6"; + + type MatchKey = Ipv6MatchKey; + type Action = Ipv6Action; + + fn match_key(self, ports: PortRange) -> Ipv6MatchKey { + Ipv6MatchKey::new(self, ports.low(), ports.high()) + } + + fn action(tgt: NatTarget) -> Ipv6Action { + Ipv6Action::Forward { + target: tgt.internal_ip, + inner_mac: tgt.inner_mac, + vni: tgt.vni.as_u32(), + } + } +} + #[derive(MatchParse, Hash)] -struct Ipv6MatchKey { +pub(crate) struct Ipv6MatchKey { dst_addr: Ipv6Addr, #[match_xlate(name = "l4_dst_port", type = "range")] @@ -27,7 +122,7 @@ struct Ipv6MatchKey { } impl Ipv6MatchKey { - pub fn new(dst_addr: Ipv6Addr, low: T, high: T) -> Self + fn new(dst_addr: Ipv6Addr, low: T, high: T) -> Self where T: std::convert::Into, { @@ -45,7 +140,7 @@ impl fmt::Display for Ipv6MatchKey { } #[derive(MatchParse, Hash)] -struct Ipv4MatchKey { +pub(crate) struct Ipv4MatchKey { dst_addr: Ipv4Addr, #[match_xlate(name = "l4_dst_port", type = "range")] @@ -53,7 +148,7 @@ struct Ipv4MatchKey { } impl Ipv4MatchKey { - pub fn new(dst_addr: Ipv4Addr, low: T, high: T) -> Self + fn new(dst_addr: Ipv4Addr, low: T, high: T) -> Self where T: std::convert::Into, { @@ -71,116 +166,13 @@ impl fmt::Display for Ipv4MatchKey { } #[derive(ActionParse)] -enum Ipv6Action { +pub(crate) enum Ipv6Action { #[action_xlate(name = "forward_ipv6_to")] Forward { target: Ipv6Addr, inner_mac: MacAddr, vni: u32 }, } #[derive(ActionParse)] -enum Ipv4Action { +pub(crate) enum Ipv4Action { #[action_xlate(name = "forward_ipv4_to")] Forward { target: Ipv6Addr, inner_mac: MacAddr, vni: u32 }, } - -pub fn add_ipv6_entry( - s: &Switch, - nat_ip: Ipv6Addr, - nat_port_low: u16, - nat_port_high: u16, - tgt: NatTarget, -) -> DpdResult<()> { - let match_key = Ipv6MatchKey::new(nat_ip, nat_port_low, nat_port_high); - let action_key = Ipv6Action::Forward { - target: tgt.internal_ip, - inner_mac: tgt.inner_mac, - vni: tgt.vni.as_u32(), - }; - - debug!(s.log, "add nat entry {} -> {:?}", match_key, tgt); - - s.table_entry_add(TableType::NatIngressIpv6, &match_key, &action_key) -} - -pub fn delete_ipv6_entry( - s: &Switch, - nat_ip: Ipv6Addr, - nat_port_low: u16, - nat_port_high: u16, -) -> DpdResult<()> { - let match_key = Ipv6MatchKey::new(nat_ip, nat_port_low, nat_port_high); - debug!(s.log, "remove nat entry {}", match_key); - s.table_entry_del(TableType::NatIngressIpv6, &match_key) -} - -pub fn reset_ipv6(s: &Switch) -> DpdResult<()> { - s.table_clear(TableType::NatIngressIpv6) -} - -pub fn add_ipv4_entry( - s: &Switch, - nat_ip: Ipv4Addr, - nat_port_low: u16, - nat_port_high: u16, - tgt: NatTarget, -) -> DpdResult<()> { - let match_key = Ipv4MatchKey::new(nat_ip, nat_port_low, nat_port_high); - let action_key = Ipv4Action::Forward { - target: tgt.internal_ip, - inner_mac: tgt.inner_mac, - vni: tgt.vni.as_u32(), - }; - - debug!(s.log, "add nat entry {} -> {:?}", match_key, tgt); - - s.table_entry_add(TableType::NatIngressIpv4, &match_key, &action_key) -} - -pub fn delete_ipv4_entry( - s: &Switch, - nat_ip: Ipv4Addr, - nat_port_low: u16, - nat_port_high: u16, -) -> DpdResult<()> { - let match_key = Ipv4MatchKey::new(nat_ip, nat_port_low, nat_port_high); - debug!(s.log, "remove nat entry {}", match_key); - s.table_entry_del(TableType::NatIngressIpv4, &match_key) -} - -pub fn ipv4_table_dump( - s: &Switch, - from_hardware: bool, -) -> DpdResult { - s.table_dump::( - TableType::NatIngressIpv4, - from_hardware, - ) -} - -pub fn ipv6_table_dump( - s: &Switch, - from_hardware: bool, -) -> DpdResult { - s.table_dump::( - TableType::NatIngressIpv6, - from_hardware, - ) -} - -pub fn ipv4_counter_fetch( - s: &Switch, - force_sync: bool, -) -> DpdResult> { - s.counter_fetch::(force_sync, TableType::NatIngressIpv4) -} - -pub fn ipv6_counter_fetch( - s: &Switch, - force_sync: bool, -) -> DpdResult> { - s.counter_fetch::(force_sync, TableType::NatIngressIpv6) -} - -/// Delete many IPv6 address from the ASIC tables. -pub fn reset_ipv4(s: &Switch) -> DpdResult<()> { - s.table_clear(TableType::NatIngressIpv4) -}