@@ -828,19 +828,28 @@ impl DataStore {
828828 Ok ( results)
829829 }
830830
831+ /// Look up communities for a BGP peer.
832+ ///
833+ /// For numbered peers, pass `Some(addr)`. For unnumbered peers, pass `None`
834+ /// (the function will query using the sentinel value 0.0.0.0/32).
831835 pub async fn communities_for_peer (
832836 & self ,
833837 opctx : & OpContext ,
834838 port_settings_id : Uuid ,
835839 interface_name : & str ,
836- addr : IpNetwork ,
840+ addr : Option < IpNetwork > ,
837841 ) -> ListResultVec < SwitchPortBgpPeerConfigCommunity > {
838842 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config_communities:: dsl;
839843
844+ // For unnumbered peers (addr is None), use UNSPECIFIED as sentinel
845+ let db_addr: IpNetwork = addr. unwrap_or_else ( || {
846+ std:: net:: IpAddr :: V4 ( std:: net:: Ipv4Addr :: UNSPECIFIED ) . into ( )
847+ } ) ;
848+
840849 let results = dsl:: switch_port_settings_bgp_peer_config_communities
841850 . filter ( dsl:: port_settings_id. eq ( port_settings_id) )
842851 . filter ( dsl:: interface_name. eq ( interface_name. to_owned ( ) ) )
843- . filter ( dsl:: addr. eq ( addr ) )
852+ . filter ( dsl:: addr. eq ( db_addr ) )
844853 . load_async ( & * self . pool_connection_authorized ( opctx) . await ?)
845854 . await
846855 . map_err ( |e| {
@@ -852,43 +861,66 @@ impl DataStore {
852861 Ok ( results)
853862 }
854863
864+ /// Look up allowed exports for a BGP peer.
865+ ///
866+ /// For numbered peers, pass `Some(addr)`. For unnumbered peers, pass `None`.
855867 pub async fn allow_export_for_peer (
856868 & self ,
857869 opctx : & OpContext ,
858870 port_settings_id : Uuid ,
859871 interface_name : & str ,
860- addr : IpNetwork ,
872+ addr : Option < IpNetwork > ,
861873 ) -> LookupResult < Option < Vec < SwitchPortBgpPeerConfigAllowExport > > > {
862874 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config as db_peer;
863875 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config:: dsl as peer_dsl;
864876 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config_allow_export as db_allow;
865877 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config_allow_export:: dsl;
866878
879+ // For unnumbered peers (addr is None), use UNSPECIFIED as sentinel
880+ // for the allow_export table (which has non-nullable addr)
881+ let db_addr: IpNetwork = addr. unwrap_or_else ( || {
882+ std:: net:: IpAddr :: V4 ( std:: net:: Ipv4Addr :: UNSPECIFIED ) . into ( )
883+ } ) ;
884+
867885 let conn = self . pool_connection_authorized ( opctx) . await ?;
868886 let err = OptionalError :: new ( ) ;
869887 self . transaction_retry_wrapper ( "bgp_allow_export_for_peer" )
870888 . transaction ( & conn, |conn| {
871889 let err = err. clone ( ) ;
872890 async move {
873- let active = peer_dsl:: switch_port_settings_bgp_peer_config
874- . filter ( db_peer:: port_settings_id. eq ( port_settings_id) )
875- . filter ( db_peer:: addr. eq ( addr) )
876- . select ( db_peer:: allow_export_list_active)
877- . limit ( 1 )
878- . first_async :: < bool > ( & conn)
879- . await
880- . map_err ( |e| {
881- let msg = "failed to lookup export settings for peer" ;
882- error ! ( opctx. log, "{msg}" ; "error" => ?e) ;
891+ // Query the main peer config table. For unnumbered peers,
892+ // addr is NULL; for numbered peers, addr matches.
893+ let active = if addr. is_some ( ) {
894+ peer_dsl:: switch_port_settings_bgp_peer_config
895+ . filter ( db_peer:: port_settings_id. eq ( port_settings_id) )
896+ . filter ( db_peer:: addr. eq ( addr) )
897+ . select ( db_peer:: allow_export_list_active)
898+ . limit ( 1 )
899+ . first_async :: < bool > ( & conn)
900+ . await
901+ } else {
902+ peer_dsl:: switch_port_settings_bgp_peer_config
903+ . filter ( db_peer:: port_settings_id. eq ( port_settings_id) )
904+ . filter ( db_peer:: addr. is_null ( ) )
905+ . filter ( db_peer:: interface_name. eq ( interface_name. to_owned ( ) ) )
906+ . select ( db_peer:: allow_export_list_active)
907+ . limit ( 1 )
908+ . first_async :: < bool > ( & conn)
909+ . await
910+ } ;
883911
884- match e {
885- diesel:: result:: Error :: NotFound => {
886- let not_found_msg = format ! ( "peer with {addr} not found for port settings {port_settings_id}" ) ;
887- err. bail ( Error :: non_resourcetype_not_found ( not_found_msg) )
888- } ,
889- _ => err. bail ( Error :: internal_error ( msg) ) ,
890- }
891- } ) ?;
912+ let active = active. map_err ( |e| {
913+ let msg = "failed to lookup export settings for peer" ;
914+ error ! ( opctx. log, "{msg}" ; "error" => ?e) ;
915+
916+ match e {
917+ diesel:: result:: Error :: NotFound => {
918+ let not_found_msg = format ! ( "peer with {:?} not found for port settings {port_settings_id}" , addr) ;
919+ err. bail ( Error :: non_resourcetype_not_found ( not_found_msg) )
920+ } ,
921+ _ => err. bail ( Error :: internal_error ( msg) ) ,
922+ }
923+ } ) ?;
892924
893925 if !active {
894926 return Ok ( None ) ;
@@ -903,7 +935,7 @@ impl DataStore {
903935 db_allow:: interface_name
904936 . eq ( interface_name. to_owned ( ) ) ,
905937 )
906- . filter ( db_allow:: addr. eq ( addr ) )
938+ . filter ( db_allow:: addr. eq ( db_addr ) )
907939 . load_async ( & conn)
908940 . await ?;
909941
@@ -923,44 +955,67 @@ impl DataStore {
923955 } )
924956 }
925957
958+ /// Look up allowed imports for a BGP peer.
959+ ///
960+ /// For numbered peers, pass `Some(addr)`. For unnumbered peers, pass `None`.
926961 pub async fn allow_import_for_peer (
927962 & self ,
928963 opctx : & OpContext ,
929964 port_settings_id : Uuid ,
930965 interface_name : & str ,
931- addr : IpNetwork ,
966+ addr : Option < IpNetwork > ,
932967 ) -> LookupResult < Option < Vec < SwitchPortBgpPeerConfigAllowImport > > > {
933968 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config as db_peer;
934969 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config:: dsl as peer_dsl;
935970 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config_allow_import as db_allow;
936971 use nexus_db_schema:: schema:: switch_port_settings_bgp_peer_config_allow_import:: dsl;
937972
973+ // For unnumbered peers (addr is None), use UNSPECIFIED as sentinel
974+ // for the allow_import table (which has non-nullable addr)
975+ let db_addr: IpNetwork = addr. unwrap_or_else ( || {
976+ std:: net:: IpAddr :: V4 ( std:: net:: Ipv4Addr :: UNSPECIFIED ) . into ( )
977+ } ) ;
978+
938979 let err = OptionalError :: new ( ) ;
939980 let conn = self . pool_connection_authorized ( opctx) . await ?;
940981 self
941982 . transaction_retry_wrapper ( "bgp_allow_import_for_peer" )
942983 . transaction ( & conn, |conn| {
943984 let err = err. clone ( ) ;
944985 async move {
945- let active = peer_dsl:: switch_port_settings_bgp_peer_config
946- . filter ( db_peer:: port_settings_id. eq ( port_settings_id) )
947- . filter ( db_peer:: addr. eq ( addr) )
948- . select ( db_peer:: allow_import_list_active)
949- . limit ( 1 )
950- . first_async :: < bool > ( & conn)
951- . await
952- . map_err ( |e| {
953- let msg = "failed to lookup import settings for peer" ;
954- error ! ( opctx. log, "{msg}" ; "error" => ?e) ;
986+ // Query the main peer config table. For unnumbered peers,
987+ // addr is NULL; for numbered peers, addr matches.
988+ let active = if addr. is_some ( ) {
989+ peer_dsl:: switch_port_settings_bgp_peer_config
990+ . filter ( db_peer:: port_settings_id. eq ( port_settings_id) )
991+ . filter ( db_peer:: addr. eq ( addr) )
992+ . select ( db_peer:: allow_import_list_active)
993+ . limit ( 1 )
994+ . first_async :: < bool > ( & conn)
995+ . await
996+ } else {
997+ peer_dsl:: switch_port_settings_bgp_peer_config
998+ . filter ( db_peer:: port_settings_id. eq ( port_settings_id) )
999+ . filter ( db_peer:: addr. is_null ( ) )
1000+ . filter ( db_peer:: interface_name. eq ( interface_name. to_owned ( ) ) )
1001+ . select ( db_peer:: allow_import_list_active)
1002+ . limit ( 1 )
1003+ . first_async :: < bool > ( & conn)
1004+ . await
1005+ } ;
9551006
956- match e {
957- diesel:: result:: Error :: NotFound => {
958- let not_found_msg = format ! ( "peer with {addr} not found for port settings {port_settings_id}" ) ;
959- err. bail ( Error :: non_resourcetype_not_found ( not_found_msg) )
960- } ,
961- _ => err. bail ( Error :: internal_error ( msg) ) ,
962- }
963- } ) ?;
1007+ let active = active. map_err ( |e| {
1008+ let msg = "failed to lookup import settings for peer" ;
1009+ error ! ( opctx. log, "{msg}" ; "error" => ?e) ;
1010+
1011+ match e {
1012+ diesel:: result:: Error :: NotFound => {
1013+ let not_found_msg = format ! ( "peer with {:?} not found for port settings {port_settings_id}" , addr) ;
1014+ err. bail ( Error :: non_resourcetype_not_found ( not_found_msg) )
1015+ } ,
1016+ _ => err. bail ( Error :: internal_error ( msg) ) ,
1017+ }
1018+ } ) ?;
9641019
9651020 if !active {
9661021 return Ok ( None ) ;
@@ -975,7 +1030,7 @@ impl DataStore {
9751030 db_allow:: interface_name
9761031 . eq ( interface_name. to_owned ( ) ) ,
9771032 )
978- . filter ( db_allow:: addr. eq ( addr ) )
1033+ . filter ( db_allow:: addr. eq ( db_addr ) )
9791034 . load_async ( & conn)
9801035 . await ?;
9811036
0 commit comments