Skip to content

Commit

Permalink
WIP: finish roughing out bgp import/export/community endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
internet-diglett committed Aug 30, 2024
1 parent 1360445 commit a392a80
Show file tree
Hide file tree
Showing 4 changed files with 312 additions and 17 deletions.
26 changes: 26 additions & 0 deletions common/src/api/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2596,6 +2596,32 @@ pub struct BgpPeerRemove {
pub addr: IpAddr,
}

/// A BGP allowed prefix entry
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq)]
pub struct BgpAllowedPrefix {
/// Parent switch port configuration
pub port_settings_id: Uuid,
/// Interface peer is reachable on
pub interface_name: String,
/// Peer Address
pub addr: oxnet::IpNet,
/// Allowed Prefix
pub prefix: oxnet::IpNet,
}

/// A BGP community
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq)]
pub struct BgpCommunity {
/// Parent switch port configuration
pub port_settings_id: Uuid,
/// Interface peer is reachable on
pub interface_name: String,
/// Peer Address
pub addr: oxnet::IpNet,
/// Community
pub community: u32,
}

/// A base BGP configuration.
#[derive(
ObjectIdentity, Clone, Debug, Deserialize, JsonSchema, Serialize, PartialEq,
Expand Down
35 changes: 34 additions & 1 deletion nexus/db-model/src/switch_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use diesel::AsChangeset;
use ipnetwork::IpNetwork;
use nexus_types::external_api::params;
use nexus_types::identity::Resource;
use omicron_common::api::external;
use omicron_common::api::external::{self, BgpAllowedPrefix, BgpCommunity};
use omicron_common::api::external::{BgpPeer, ImportExportPolicy};
use omicron_common::api::internal::shared::{PortFec, PortSpeed};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -638,6 +638,17 @@ pub struct SwitchPortBgpPeerConfigCommunity {
pub community: SqlU32,
}

impl Into<BgpCommunity> for SwitchPortBgpPeerConfigCommunity {
fn into(self) -> BgpCommunity {
BgpCommunity {
port_settings_id: self.port_settings_id,
interface_name: self.interface_name,
addr: self.addr.into(),
community: self.community.into(),
}
}
}

#[derive(
Queryable,
Insertable,
Expand All @@ -660,6 +671,17 @@ pub struct SwitchPortBgpPeerConfigAllowExport {
pub prefix: IpNetwork,
}

impl Into<BgpAllowedPrefix> for SwitchPortBgpPeerConfigAllowExport {
fn into(self) -> BgpAllowedPrefix {
BgpAllowedPrefix {
port_settings_id: self.port_settings_id,
interface_name: self.interface_name,
addr: self.addr.into(),
prefix: self.prefix.into(),
}
}
}

#[derive(
Queryable,
Insertable,
Expand Down Expand Up @@ -721,6 +743,17 @@ impl SwitchPortBgpPeerConfig {
}
}

impl Into<BgpAllowedPrefix> for SwitchPortBgpPeerConfigAllowImport {
fn into(self) -> BgpAllowedPrefix {
BgpAllowedPrefix {
port_settings_id: self.port_settings_id,
interface_name: self.interface_name,
addr: self.addr.into(),
prefix: self.prefix.into(),
}
}
}

#[derive(
Queryable,
Insertable,
Expand Down
236 changes: 234 additions & 2 deletions nexus/db-queries/src/db/datastore/switch_port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2107,6 +2107,83 @@ impl DataStore {
})
}

pub async fn switch_port_configuration_bgp_peer_allow_import_remove(
&self,
opctx: &OpContext,
configuration: NameOrId,
bgp_peer: IpAddr,
prefix: AllowedPrefixAddRemove,
) -> DeleteResult {
let conn = self.pool_connection_authorized(opctx).await?;
let err = OptionalError::new();

self.transaction_retry_wrapper(
"switch_port_configuration_bgp_peer_allow_import_remove",
)
.transaction(&conn, |conn| {
let parent_configuration = configuration.clone();
let settings_to_remove = prefix.clone();
let err = err.clone();

async move {
// resolve id of port_settings record
let port_settings_id = switch_port_configuration_id(&conn, parent_configuration.clone())
.await
.map_err(|e: diesel::result::Error| {
match e {
diesel::result::Error::NotFound => {
err.bail(
Error::non_resourcetype_not_found(
format!("unable to lookup configuration with identifier {parent_configuration}")
)
)
},
_ => {
err.bail(Error::internal_error(
"error while looking up configuration for interface bgp peer"
))
},
}
})?;

// delete allowed import
// PRIMARY KEY (port_settings_id, interface_name, addr, prefix)
use db::schema::switch_port_settings_bgp_peer_config_allow_import as allow_import;
diesel::delete(allow_import::table)
.filter(allow_import::port_settings_id.eq(port_settings_id))
.filter(allow_import::interface_name.eq(settings_to_remove.interface.to_string()))
.filter(allow_import::addr.eq(IpNetwork::from(bgp_peer)))
.filter(allow_import::prefix.eq(IpNetwork::from(settings_to_remove.prefix)))
.execute_async(&conn)
.await
.map_err(|e| {
let message = "error while deleting import list entry for bgp peer";
error!(opctx.log, "{message}"; "error" => ?e);
err.bail(Error::internal_error(message))
})?;
Ok(())

}
})
.await
.map_err(|e| {
let message =
"switch_port_configuration_bgp_peer_allow_import_remove failed";
match err.take() {
Some(external_error) => {
error!(opctx.log, "{message}"; "error" => ?external_error);
external_error
}
None => {
error!(opctx.log, "{message}"; "error" => ?e);
Error::internal_error(
"error while removing entry from allow import list",
)
}
}
})
}

pub async fn switch_port_configuration_bgp_peer_allow_export_list(
&self,
opctx: &OpContext,
Expand Down Expand Up @@ -2220,6 +2297,83 @@ impl DataStore {
})
}

pub async fn switch_port_configuration_bgp_peer_allow_export_remove(
&self,
opctx: &OpContext,
configuration: NameOrId,
bgp_peer: IpAddr,
prefix: AllowedPrefixAddRemove,
) -> DeleteResult {
let conn = self.pool_connection_authorized(opctx).await?;
let err = OptionalError::new();

self.transaction_retry_wrapper(
"switch_port_configuration_bgp_peer_allow_export_remove",
)
.transaction(&conn, |conn| {
let parent_configuration = configuration.clone();
let settings_to_remove = prefix.clone();
let err = err.clone();

async move {
// resolve id of port_settings record
let port_settings_id = switch_port_configuration_id(&conn, parent_configuration.clone())
.await
.map_err(|e: diesel::result::Error| {
match e {
diesel::result::Error::NotFound => {
err.bail(
Error::non_resourcetype_not_found(
format!("unable to lookup configuration with identifier {parent_configuration}")
)
)
},
_ => {
err.bail(Error::internal_error(
"error while looking up configuration for interface bgp peer"
))
},
}
})?;

// delete allowed export
// PRIMARY KEY (port_settings_id, interface_name, addr, prefix)
use db::schema::switch_port_settings_bgp_peer_config_allow_export as allow_export;
diesel::delete(allow_export::table)
.filter(allow_export::port_settings_id.eq(port_settings_id))
.filter(allow_export::interface_name.eq(settings_to_remove.interface.to_string()))
.filter(allow_export::addr.eq(IpNetwork::from(bgp_peer)))
.filter(allow_export::prefix.eq(IpNetwork::from(settings_to_remove.prefix)))
.execute_async(&conn)
.await
.map_err(|e| {
let message = "error while deleting export list entry for bgp peer";
error!(opctx.log, "{message}"; "error" => ?e);
err.bail(Error::internal_error(message))
})?;
Ok(())

}
})
.await
.map_err(|e| {
let message =
"switch_port_configuration_bgp_peer_allow_export_remove failed";
match err.take() {
Some(external_error) => {
error!(opctx.log, "{message}"; "error" => ?external_error);
external_error
}
None => {
error!(opctx.log, "{message}"; "error" => ?e);
Error::internal_error(
"error while removing entry from allow export list",
)
}
}
})
}

pub async fn switch_port_configuration_bgp_peer_community_list(
&self,
opctx: &OpContext,
Expand Down Expand Up @@ -2264,7 +2418,7 @@ impl DataStore {
opctx: &OpContext,
configuration: NameOrId,
bgp_peer: IpAddr,
prefix: BgpCommunityAddRemove,
community: BgpCommunityAddRemove,
) -> CreateResult<SwitchPortBgpPeerConfigCommunity> {
use db::schema::switch_port_settings_bgp_peer_config_communities as communities;

Expand All @@ -2276,7 +2430,7 @@ impl DataStore {
)
.transaction(&conn, |conn| {
let parent_configuration = configuration.clone();
let new_settings = prefix.clone();
let new_settings = community.clone();
let err = err.clone();

async move {
Expand Down Expand Up @@ -2333,6 +2487,84 @@ impl DataStore {
})
}

pub async fn switch_port_configuration_bgp_peer_community_remove(
&self,
opctx: &OpContext,
configuration: NameOrId,
bgp_peer: IpAddr,
community: BgpCommunityAddRemove,
) -> DeleteResult {
let conn = self.pool_connection_authorized(opctx).await?;
let err = OptionalError::new();

self.transaction_retry_wrapper(
"switch_port_configuration_bgp_peer_community_remove",
)
.transaction(&conn, |conn| {
let parent_configuration = configuration.clone();
let settings_to_remove = community.clone();
let err = err.clone();

async move {
// resolve id of port_settings record
let port_settings_id = switch_port_configuration_id(&conn, parent_configuration.clone())
.await
.map_err(|e: diesel::result::Error| {
match e {
diesel::result::Error::NotFound => {
err.bail(
Error::non_resourcetype_not_found(
format!("unable to lookup configuration with identifier {parent_configuration}")
)
)
},
_ => {
err.bail(Error::internal_error(
"error while looking up configuration for interface bgp peer"
))
},
}
})?;

// delete communities
// PRIMARY KEY (port_settings_id, interface_name, addr, community)
use db::schema::switch_port_settings_bgp_peer_config_communities as peer_communities;
diesel::delete(peer_communities::table)
.filter(peer_communities::port_settings_id.eq(port_settings_id))
.filter(peer_communities::interface_name.eq(settings_to_remove.interface.to_string()))
.filter(peer_communities::addr.eq(IpNetwork::from(bgp_peer)))
.filter(peer_communities::community.eq(SqlU32::from(settings_to_remove.community)))
.execute_async(&conn)
.await
.map_err(|e| {
let message = "error while deleting community entry for bgp peer";
error!(opctx.log, "{message}"; "error" => ?e);
err.bail(Error::internal_error(message))
})?;

Ok(())

}
})
.await
.map_err(|e| {
let message =
"switch_port_configuration_bgp_peer_community_remove failed";
match err.take() {
Some(external_error) => {
error!(opctx.log, "{message}"; "error" => ?external_error);
external_error
}
None => {
error!(opctx.log, "{message}"; "error" => ?e);
Error::internal_error(
"error while removing entry from community list",
)
}
}
})
}

// switch ports

pub async fn switch_port_create(
Expand Down
Loading

0 comments on commit a392a80

Please sign in to comment.