当前位置: 首页 > news >正文

【openbmc3】时间相关

文章目录

  • 1.时间转换
    • 1.1 案例
  • 2.sel时间设置
  • 3.rtc&ntp
    • 3.1 rtc时间异常
    • 3.2 ntp
  • 4.sel时区设置
  • 5.phosphor-time-manager模块
  • 6.deadline_timer(闹钟)与steady_timer(秒表)


1.时间转换

reboot启动systemd时systemd/src/core/main.c文件中initialize_clock函数会将系统时间改变,所以要注释掉。如下时间戳=time_t,typedef long time_t(time_t编译时被替换成long):time_t不符合习惯需转成表示时间结构体即struct_time=struct tm。
在这里插入图片描述
如下time函数作用是将当前时间的时间戳赋值给tnow变量。
在这里插入图片描述

struct tm   //time.h
{int tm_sec;          /* 秒,范围从 0 到 59    */int tm_min;          /* 分,范围从 0 到 59    */int tm_hour;         /* 小时,范围从 0 到 23  */int tm_mday;         /* 一月中的第几天,范围从 1 到 31  */int tm_mon;          /* 月,范围从 0 到 11,  0代表1月*/int tm_year;         /* 自 1900 年起的年数   */int tm_wday;         /* 一周中的第几天,范围从 0 到 6,0代表星期天 */int tm_yday;         /* 一年中的第几天,范围从 0 到 365,0代表1月1日 */int tm_isdst;        /* 夏令时 */long int tm_gmtoff;  /*指定了日期变更线东面时区中UTC东部时区正秒数或UTC西部时区的负秒数*/const char *tm_zone; /*当前时区的名字(与环境变量TZ有关)*/
};

在这里插入图片描述

bmc_sys_data = remote.command("date +%s")
bmc_date_string = remote.command("hwclock | awk '{print $1, $2, $3, $4, $5}'")
bmc_date_obj = datetime.datetime.strptime(bmc_date_string.strip(), "%a %b %d %H:%M:%S %Y")
bmc_rtc_data = int(time.mktime(bmc_date_obj.timetuple()))
if abs(int(bmc_sys_data) - bmc_rtc_data) > 5:ret = E.EFAILself.fail_reason.append("bmc sys time is {}s and bmc rtc time is is {}s, the difference is over 5 seconds.".format(bmc_sys_data, bmc_rtc_data))
elif abs(int(time.time()) - int(bmc_sys_data)) > 5:ret = E.EFAILself.fail_reason.append("cpu sys time is {}s and bmc sys time is is {}s, the difference is over 5 seconds.".format(int(time.time()), bmc_sys_data))
else:self.logger.log_info("bmc sys time ({}s) and bmc rtc time ({}s) and cpu sys time ({}s) is normal, the difference is less than 5 seconds.".format(bmc_sys_data, bmc_rtc_data , int(time.time())), also_print_console)

1.1 案例

# ln -s /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime 修改为CST(reboot后恢复)。
# UTC【比GMT正式】和GMT都是世界标准时(0经度线【竖】)。 北京时间(CST)位于东八区=世界时+8小时。  
# date -s 2022.05.05-09:47:00    # date -s "2021-01-01 1:00:00"    # date +%w 星期几 
# busctl get-property xyz.openbmc_project.Time.Manager /xyz/openbmc_project/time/bmc xyz.openbmc_project.Time.EpochTime Elapsed
# t 1651744027250894 (去除6个0就是时间戳即秒)# date +"%Y %m %d %H %M %S" (加号前面有空格,后面没有)  # 2022(年) 08(月) 05(日)  02(小时) 43(分) 56(秒)
# date +"%s"  # 1659667469(转换时间时注意选择转成北京时还是标准时)
# date -d @1686908998  # Fri Jun 16 09:49:58 UTC 2023
# date(date命令默认将时间戳转为UTC显示)#include<stdio.h>
#include<time.h>
int main()
{struct tm *info;time_t curtime;time( &curtime ); # 返回当前时间戳printf("时间戳: %ld\n",curtime);info = localtime( &curtime );  # 时间戳转为tm结构体指针printf("结构体:时:%d\n",info->tm_hour);char tmp[64];strftime(tmp, sizeof(tmp), "%Y-%m-%d %H:%M:%S",info); # 将tm结构体转换为时间字符串printf("时间字符串:%s\n",tmp);struct tm mytm;char tmp1[50] = "2022-02-16 15:20:00";# strptime:将时间字符串转换为tm结构体  # 如果不匹配"%Y%m-%d %H:%M:%S" ,返回0int ret=strptime(tmp1, "%Y-%m-%d %H:%M:%S", &mytm); printf("strptime返回值: %d\n",ret);printf("结构体:时:%d\n",mytm.tm_hour);
}

在这里插入图片描述

// time.cpp
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <unistd.h>void GetSystemTime(char *buffer)
{struct tm *td;struct tm tdres;struct timeval now;  // 包含秒数和微秒数gettimeofday(&now, 0);td = localtime_r((time_t *)&(now.tv_sec), &tdres);if(td == NULL){return;}sprintf(buffer, "%2.2d—%2.2d—%2.2d %2.2d:%2.2d:%2.2d:3.3d", (td->tm_year+1900), (td->tm_mon+1), td->tmday, td->tm_hour, td->tm_min, td->tm_sec, (long)(now.tv_usec/1000));
}int main()
{while(1) {char dataTime[1024] = {0};GetSystemTime(dataTime);printf("dataTime:%s\n", dataTime);sleep(1); //每隔一秒打印一次当前时间}return 0;
}

在这里插入图片描述

#include <stdio.h>
#include <time.h>
int main() {time_t timestamp = time(NULL);char buffer[26];ctime_r(&timestamp, buffer);printf("Current time: %s", buffer);  // Current time: Mon Jul 31 13:24:49 2023return 0;
}void writeTimestampToBuffer(bufStore *buf) {struct tm *info;time_t cur_time;int years;char dateBuff[10];time(&cur_time);info = localtime( &cur_time );years = 1900 + info->tm_year;sprintf(dateBuff, "%d ", years);  // 只记录年,因为映射成local3时用rsyslog.conf中template中没有年 (local3.* :omfile:$consolefile_channel 【/var/log/console.log】;)writeData(buf->buf_fd, dateBuff, strlen(dateBuff), "xxxx");  // buf->buf_fd = /var/log/console.log,将dateBuff写入文件
}

2.sel时间设置

Network Function Codes:  // RAW Commands:  raw <netfn> <cmd> [data]VAL   HEX     STRING0     0x00    Chassis2     0x02    Bridge4     0x04    SensorEvent6     0x06    Application8     0x08    Firmware10    0x0a    Storage12    0x0c    Transport
// ipmitool sel time set "12/25/2024 13:41:08"  (UTC)
// ipmitool 【-I lanplus -C 17 -U root -P 0penBmc -H ip】 sel time get
// ipmitool sel time set "now"
// 出现Set SEL Time command failed: Invalid command说明用的ipmi-oem包并删除build下tmp(或bin替换)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// ipmi_sel.c
static int ipmi_sel_set_time(struct ipmi_intf * intf, const char * time_string)  
{struct ipmi_rs *rsp;struct ipmi_rq req;struct tm tm = {0};  // tm结构体time_t           t;  // 时间戳time_t始终是UTC时间uint32_t      timei;const char * time_format = "%m/%d/%Y %H:%M:%S";memset(&req, 0, sizeof(req));req.msg.netfn    = IPMI_NETFN_STORAGE;  // 0xareq.msg.cmd      = IPMI_SET_SEL_TIME;  // 0x49if (strncasecmp(time_string, "now", 3) == 0) {t = time(NULL); // 当前时间的时间戳}else {if (strptime(time_string, time_format, &tm) == 0) {lprintf(LOG_ERR, "Specified time could not be parsed");return -1;}tm.tm_isdst = (-1); // 结合下一行,自动处理时区t = mktime(&tm);  // t就是UTC时间戳if (t < 0) {lprintf(LOG_ERR, "Specified time could not be parsed");return -1;}}timei = (uint32_t)t;
#if WORDS_BIGENDIANtimei = BSWAP_32(timei);
#endifreq.msg.data = (void *)&timei;req.msg.data_len = 4; // ipmitool -I lanplus -C 17  -U root -P 0penBmc -H 10.75.137.81 raw 0x0a 0x49 0xce 0x8c 0xeb 0x62  # 时间戳62EB8CCE转十进制rsp = intf->sendrecv(intf, &req);if (!rsp || rsp->ccode) {lprintf(LOG_ERR, "Set SEL Time command failed: %s",rsp? val2str(rsp->ccode, completion_code_vals): "Unknown");  // rsp不为空则将rsp->ccode转换为相应字符串,否则打印Unknownreturn -1;}ipmi_sel_get_time(intf);return 0;
}// ipmi_strings.c
const struct valstr completion_code_vals[] = {{ 0x00, "Command completed normally" },{ 0xc0, "Node busy" },{ 0xc1, "Invalid command" }...// storagecommands.cpp
ipmi::RspType<> ipmiStorageSetSELTime(uint32_t selTime)  // selTime是传来的时间戳,一定要加这参数,不然ipmitool返回有问题
{struct timespec ts = {};ts.tv_sec = selTime;  // 秒数即时间戳ts.tv_nsec = 0;if (clock_settime(CLOCK_REALTIME, &ts) < 0)  // == 0 成功{return ipmi::responseUnspecifiedError();}return ipmi::responseSuccess();
}
time_t str2stamp(std::string str_time)
{time_t t;struct tm tm = {0}; strptime....tm.tm_isdst = (-1);t = mktime(&tm);struct tm *tm_tmp = {0};int gt_year,gt_yday,gt_hour,gt_min,lt_year,lt_yday,lt_hour,lt_min;int delta_hour;tm_tmp=gmtime(&t);  // 返回的是 UTC时间的结构体gt_year=tm_tmp->tm_year;gt_yday=tm_tmp->tm_yday;gt_hour=tm_tmp->tm_hour;gt_min=tm_tmp->tm_min;memset(&*tm_tmp,0,sizeof(struct tm));tm_tmp=localtime(&t);  // 返回的是 UTC时间的结构体lt_year=tm_tmp->tm_year;lt_yday=tm_tmp->tm_yday;lt_hour=tm_tmp->tm_hour;lt_min=tm_tmp->tm_min;delta_hour=lt_hour - gt_hour;if ( (lt_year > gt_year) || ((lt_year == gt_year) && (lt_yday > gt_yday)) )delta_hour += 24;if (  (lt_year < gt_year) || ((lt_year == gt_year) && (lt_yday < gt_yday)) )delta_hour -= 24;t += (delta_hour * 60 * 60) + (lt_min -gt_min) * 60; // 当前UTC时间是1622505600(对应2021-06-01 00:00:00 UTC),而用户位于UTC+8时区,本地时间戳应该是1622505600 + 8*3600 = 1622534400return t;
}

在这里插入图片描述

3.rtc&ntp

不加驱动hwclock -f /dev/rtc查不了硬件时间,timedatectl show,如下上电注册RTC驱动时probe会将RTC时间写入系统时间,后面系统时间NTP同步并写入RTC。
在这里插入图片描述

&i2c2 {status = "okay";rtc@51{  # rtc随便命名compatible = "nxp,pcf85063";reg = <0x51>;};
};

/etc/ntp.conf:restrict (什么可访问我并可修改我的时间)10.75.92.0 mask 255.255.255.0 nomodify(nomodify不能修改我,只能访问同步走)。修改后隔10分钟才去同步一次,重启ntp进程立马同步。
在这里插入图片描述
在这里插入图片描述
ntp协议在linux-aspeed/drivers/rtc/systohc.c中rtc_set_ntp_time函数将系统时间写入rtc ,不用下面write_rtc。

write_rtc()
{if [ ! -d /etc/cron/crontabs ];thenmkdir -p /etc/cron/crontabsfiecho "0 0 * * * hwclock --systohc" >> /etc/cron/crontabs/root  # 同hwclock -w:将系统时间写入RTC   # hwclock --hctosys:将RTC写入系统时间/usr/sbin/crond -c /etc/cron/crontabs &
}

当系统时间和rtc一致时,systemd-timesyncd失效,如下关闭timesyncd,新基线如下_改为
在这里插入图片描述
如下是bmc内部rtc。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下如果系统是UTC时区,则不用加-u(UTC)。
在这里插入图片描述

3.1 rtc时间异常

越界异常,导致主备来回切换,不能进系统。info等级改为debug。
在这里插入图片描述
在这里插入图片描述
如下模拟时间戳就是上面2040年,出现上面打印,因为时间戳超出32位整数范围。
在这里插入图片描述
RTC芯片手册,如下就是2040年,芯片里异常时间来源问厂家。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如下对越界的时间会做异常处理。
在这里插入图片描述

3.2 ntp

第一个ntp server ip生效后,第二个和后面不生效,依此类推(无法手动设置时间)。
在这里插入图片描述
在这里插入图片描述
根据web前端提示” Error saving date and time settings.”定位到如下代码:
openbmc-ocp/build/sr6115/workspace/sources/webui-vue/src/locales/en-US.json。

    "toast": {"errorSaveDateTime": "Error saving date and time settings.","successSaveDateTime": "Successfully saved date and time settings."}

搜索errorSaveDateTime 定位到如下代码:
openbmc-ocp/build/sr6115/workspace/sources/webui-vue/src/store/modules/Settings/DateTimeStore.js。

const DateTimeStore = {...actions: {async getNtpData({ commit }) {return await api.get('/redfish/v1/Managers/bmc/NetworkProtocol').then((response) => {const ntpServers = response.data.NTP.NTPServers;const isNtpProtocolEnabled = response.data.NTP.ProtocolEnabled;commit('setNtpServers', ntpServers);commit('setIsNtpProtocolEnabled', isNtpProtocolEnabled);}).catch((error) => {console.log(error);});},async updateDateTime({ state }, dateTimeForm) {const ntpData = {NTP: {ProtocolEnabled: dateTimeForm.ntpProtocolEnabled,},};// console.log(dateTimeForm.ntpProtocolEnabled); // 前端按Fn + F12看到控制台打印为trueif (dateTimeForm.ntpProtocolEnabled) {  ntpData.NTP.NTPServers = dateTimeForm.ntpServersArray;// console.log(ntpData.NTP.NTPServers);  //打印出['10.10.10.1', '10.10.10.2'] 即web页面填写的ntp server ip}return await api.patch(`/redfish/v1/Managers/bmc/NetworkProtocol`, ntpData).then(async () => {if (!dateTimeForm.ntpProtocolEnabled) {  // web页面手动设置时间// ...下面包含errorSaveDateTime 

根据/redfish/v1/Managers/bmc/NetworkProtocol定位到如下代码:
openbmc-ocp/build/sr6115/workspace/sources/bmcweb/redfish-core/lib/network_protocol.hpp。

inline void requestRoutesNetworkProtocol(App& app)
{BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/NetworkProtocol/").privileges(redfish::privileges::patchManagerNetworkProtocol).methods(boost::beast::http::verb::patch)([&app](const crow::Request& req,  // patch方法const std::shared_ptr<bmcweb::AsyncResp>&asyncResp) {std::optional<std::vector<std::string>> ntpServers;  // 注意是optional// sprintf(temp_log_0, " '%s' ", ntpServers?"true":"false");  不为空则为truestd::optional<bool> ntpEnabled;std::optional<bool> ipmiEnabled;std::optional<bool> sshEnabled;// clang-format offif (!json_util::readJsonPatch(req, asyncResp->res,"HostName", newHostName,"NTP/NTPServers", ntpServers,"NTP/ProtocolEnabled", ntpEnabled,"IPMI/ProtocolEnabled", ipmiEnabled,"SSH/ProtocolEnabled", sshEnabled)){return;}...std::vector<std::string>& ntpServers_t = *ntpServers;  // 注意是vectorfor (unsigned int ii=0;ii<ntpServers_t.size();ii++){char temp_log_0[100] = {0};sprintf(temp_log_0, " %s ", ntpServers_t[ii].c_str()); char temp_log_1[100] = "echo ";strcat(temp_log_1, temp_log_0);char temp_log_2[100] = " >> /var/log/a.log";   //server ipstrcat(temp_log_1, temp_log_2);if(-1 == std::system(temp_log_1)){};}if (ntpServers){stl_utils::removeDuplicate(*ntpServers);handleNTPServersPatch(asyncResp, *ntpServers);   // patch方法具体调用的函数}...BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/NetworkProtocol/").privileges(redfish::privileges::getManagerNetworkProtocol).methods(boost::beast::http::verb::get)(    // 这里是get方法 [&app](const crow::Request& req,const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)){return;}getNetworkData(asyncResp, req);});
}
} // namespace redfish// 定位到如下具体的方法:
inline void handleNTPServersPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,std::vector<std::string>& ntpServers)
{...crow::connections::systemBus->async_method_call([asyncResp,ntpServers](boost::system::error_code ec,const dbus::utility::MapperGetSubTreeResponse& subtree) {if (ec){BMCWEB_LOG_WARNING << "D-Bus error: " << ec << ", "<< ec.message();messages::internalError(asyncResp->res);return;}for (const auto& [objectPath, serviceMap] : subtree){for (const auto& [service, interfaces] : serviceMap){for (const auto& interface : interfaces){if (interface !="xyz.openbmc_project.Network.EthernetInterface"){continue;}/* char temp_log_0[100] = {0};sprintf(temp_log_0, " %s  %s", service.c_str(), objectPath.c_str());char temp_log_1[100] = "echo ";strcat(temp_log_1, temp_log_0);char temp_log_2[100] = " >> /var/log/b.log";strcat(temp_log_1, temp_log_2);if(-1 == std::system(temp_log_1)){};   // xyz.openbmc_project.Network   /xyz/openbmc_project/network/eth0 */crow::connections::systemBus->async_method_call([asyncResp](const boost::system::error_code ec) {if (ec){messages::internalError(asyncResp->res);return;}},service, objectPath,"org.freedesktop.DBus.Properties", "Set", interface,   // set方法"NTPServers",dbus::utility::DbusVariantType{ntpServers});}}}},"xyz.openbmc_project.ObjectMapper","/xyz/openbmc_project/object_mapper","xyz.openbmc_project.ObjectMapper", "GetSubTree",  // get方法"/xyz/openbmc_project", 0,std::array<const char*, 1>{"xyz.openbmc_project.Network.EthernetInterface"});
}
root@sr6115:~# busctl introspect xyz.openbmc_project.Network  /xyz/openbmc_project/network/eth0  xyz.openbmc_project.Network.EthernetInterface
...
.NICEnabled                                   property  b         true                                     emits-change writable
.NTPServers                                   property  as                                                 emits-change
.Nameservers                                  property  as        2 "192.168.130.50" "192.168.30.50"       emits-change writable.StaticNTPServers                             property  as        0                                        emits-change writable
.StaticNameServers                            property  as        0                                        emits-change writable

发现NTPServers属性是没办法writable,无法写,github搜索EthernetInterface定位到如下phosphor-networkd模块,devtool modify phosphor-networkd发现无法下载,search network相关模块后devtool modify phosphor-network可下载该模块。

如下发现web前端填写ntp server ip后并保存触发,并没有调用到ntpServers函数,但是当上电启动后会调用getNTPServersFromConf函数,打印出confpath为/etc/systemd/network/00-bmc-eth0.network,发现getNTPServersFromConf函数里和writeConfigurationFile函数里的组成confPath代码段相同,手动改这文件,增加[Network] NTP=10.10.10.1 字段后systemctl restart systemd-networkd.service,date查看时间后后发现时间已同步到远程时间。

// phosphor-network/src/ethernet_interface.hpp
ServerList EthernetInterface::getNTPServersFromConf()
{fs::path confPath = manager.getConfDir();std::string fileName = systemd::config::networkFilePrefix +interfaceName() + systemd::config::networkFileSuffix;confPath /= fileName;ServerList servers;config::Parser parser(confPath.string());auto rc = config::ReturnCode::SUCCESS;std::tie(rc, servers) = parser.getValues("Network", "NTP");if (rc != config::ReturnCode::SUCCESS){log<level::DEBUG>("Unable to get the value for Network[NTP]",entry("rc=%d", rc));}return servers;
}ServerList EthernetInterface::ntpServers(ServerList servers)
{auto ntpServers = EthernetInterfaceIntf::ntpServers(servers);writeConfigurationFile();manager.reloadConfigs();return ntpServers;
}void EthernetInterface::writeConfigurationFile()
{
...fs::path confPath = manager.getConfDir();std::string fileName = systemd::config::networkFilePrefix +interfaceName() + systemd::config::networkFileSuffix;confPath /= fileName;std::fstream stream;
...// Add the NTP server  ////////////////////////////////////for (const auto& ntp : EthernetInterfaceIntf::ntpServers()){stream << "NTP=" << ntp << "\n";}
...
}

在这里插入图片描述
浏览器登录https://10.75.137.56/#/settings/date-time,ip地址改为开发板ip,如下设置NTP服务ip地址。设置完后点击下Save settings按钮,到开发板上date命令或ipmitool sel time get命令查看时间是否与NTP server 时间一样。

// redfish接口调用测试方法:
root@sr:~# curl -k -H "Content-Type: application/json" -X POST https://10.75.137.51/login -d '{"username" :  "root", "password" :  "0penBmc"}' | grep token | awk '{print $2;}' | tr -d '"'% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100    84  100    37  100    47    111    141 --:--:-- --:--:-- --:--:--   253
uMaeeLkbARcYgINNx7kFroot@sr:~# curl -k -H "X-Auth-Token: uMaeeLkbARcYgINNx7kF" -X GET https://10.75.137.51/redfish/v1/Managers/bmc/NetworkProtocol/
{
..."NTP": {"NTPServers": [],"ProtocolEnabled": true},
...
}root@sr:~# curl -k -H "X-Auth-Token: uMaeeLkbARcYgINNx7kF" -X PATCH -d '{"NTP":{"NTPServers": ["10.10.10.1"], "ProtocolEnabled": true}}'  https://10.75.137.51/redfish/v1/Managers/bmc/NetworkProtocol/   root@sr:~# curl -k -H "X-Auth-Token: uMaeeLkbARcYgINNx7kF" -X GET https://10.75.137.51/redfish/v1/Managers/bmc/NetworkProtocol/
{"@odata.id": "/redfish/v1/Managers/bmc/NetworkProtocol","@odata.type": "#ManagerNetworkProtocol.v1_5_0.ManagerNetworkProtocol","Description": "Manager Network Service","FQDN": "sr6115","HTTP": {"Port": 0,"ProtocolEnabled": false},"HTTPS": {"Certificates": {"@odata.id": "/redfish/v1/Managers/bmc/NetworkProtocol/HTTPS/Certificates"},"Port": 443,"ProtocolEnabled": true},"HostName": "sr6115","IPMI": {"Port": 623,"ProtocolEnabled": true},"Id": "NetworkProtocol","NTP": {  ///////////"NTPServers": ["10.10.10.1"],"ProtocolEnabled": true},"Name": "Manager Network Protocol","SSH": {"Port": 22,"ProtocolEnabled": true},"Status": {"Health": "OK","HealthRollup": "OK","State": "Enabled"}
}

4.sel时区设置

改完时区,rtc和系统的时区和时间都会变。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// workspace/sources/phosphor-ipmi-host/include/ipmid/api-types.hpp
constexpr Cmd cmdGetSelTimeUtcOffset = 0x5C;
constexpr Cmd cmdSetSelTimeUtcOffset = 0x5D;// workspace/sources/phosphor-ipmi-host/dbus-sdr/storagecommands.cpp
void registerStorageFunctions() {// <Set SEL Time>// <Get SEL Time UTC OFFSET>ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,ipmi::storage::cmdGetSelTimeUtcOffset, ipmi::Privilege::User,ipmiStorageGetSelTimeUtcOffset);// <Set SEL Time UTC OFFSET>ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnStorage,ipmi::storage::cmdSetSelTimeUtcOffset,ipmi::Privilege::Operator, ipmiStorageSetSelTimeUtcOffset); }

Yocto添加时区软件包在image.bb添加tzdata,产生/usr/share/zoneinfo对应文件夹,注意在openbmc-ocp/build/sr6115/conf/local.conf 或openbmc-ocp/meta-huaqin/meta-sr6115/conf/local.conf.sample添加DEFAULT_TIMEZONE = “Asia/Shanghai” 都无法产生时区相关文件。

// workspace/sources/phosphor-ipmi-host
#define TIME_ZONE_PATH  "/usr/share/zoneinfo/"
#define ZONEINFO_DIR    "/usr/share/zoneinfo/Etc"
#define LOCALTIME       "/etc/localtime"
#define ZONEINFO_FILENAME_LEN   128
#define SEL_UTC_MIN_RANGE       -1440  
#define SEL_UTC_MAX_RANGE       1440  // 1440min/60=24hipmi::RspType<int16_t> ipmiStorageGetSelTimeUtcOffset()
{time_t timep;struct tm* gmTime;struct tm* localTime;time(&timep);localTime = localtime(&timep);  // 时间戳转换为本地时间auto validLocalTime = mktime(localTime);gmTime = gmtime(&timep);  // 时间戳转换为协调世界时(UTC)auto validGmTime = mktime(gmTime);auto timeEquation = (validLocalTime - validGmTime) / 60; // 计算本地时间和UTC时间之间的偏移量, 秒/60 = minreturn ipmi::responseSuccess(timeEquation);
}ipmi::RspType<> ipmiStorageSetSelTimeUtcOffset(int16_t offsetTime) // offsetTime:min: 8*60
{int hrs = 0;char ZoneInfoFile[ZONEINFO_FILENAME_LEN], file[32];if ((SEL_UTC_MIN_RANGE > offsetTime) || (SEL_UTC_MAX_RANGE < offsetTime)){return ipmi::responseUnspecifiedError();}hrs = offsetTime / 60;  // 小时if (0 > offsetTime){if (snprintf(file,sizeof(file), "GMT+%d", -hrs) >= (long int)sizeof(file)){return ipmi::responseUnspecifiedError();}}else{if (snprintf(file,sizeof(file), "GMT-%d", hrs) >= (long int)sizeof(file)){return ipmi::responseUnspecifiedError();}}if (snprintf (ZoneInfoFile, ZONEINFO_FILENAME_LEN, "%s/%s", ZONEINFO_DIR, file) >= ZONEINFO_FILENAME_LEN){return ipmi::responseUnspecifiedError();}if((unlink(LOCALTIME)) < 0){return ipmi::responseUnspecifiedError();}if(symlink(ZoneInfoFile, LOCALTIME) < 0){return ipmi::responseUnspecifiedError();}return ipmi::responseSuccess();
}

5.phosphor-time-manager模块

busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/time/sync_method xyz.openbmc_project.Time.Synchronization TimeSyncMethod s “xyz.openbmc_project.Time.Synchronization.Method.Manual”

# 注意必须是换成Manual模式(还有ntp模式),否则下面无法设置。
busctl set-property xyz.openbmc_project.Time.Manager /xyz/openbmc_project/time/bmc xyz.openbmc_project.Time.EpochTime Elapsed t 微秒(比秒多6个0)

在这里插入图片描述
在这里插入图片描述

6.deadline_timer(闹钟)与steady_timer(秒表)

系统时间调整导致deadline_timer失效,替换用steady_timer。如下dbus-sensors中cpusensor app一直保持在一个固定值,可以响应 IO 事件(dbus)即进程处于alive状态。peci读取没有出现异常数据。
在这里插入图片描述

cat /proc/460/stack  # 查看进程stack, 进程停留在poll地方, 并且可以正常使用dbus访问, 表示进程io正常, 没卡在奇怪的地方
[<0>] do_epoll_wait+0x5dc/0x710
[<0>] sys_epoll_wait+0x68/0xa4
[<0>] __sys_trace_return_nosave+0x10/0x10
[<0>] 0x7ea400d8# 分析代码不存在逻辑陷阱导致读取的timer被取消了,用strace查看进程的系统调用是否正常,是不是有访问驱动文件出错
strace -p 460 -tttT -s 2048 -o ./strace.log
# 等待了1min 左右(代码里最长的timer大概10s), log如下: 发现没有任何系统调用, 很奇怪因为如果timer还活着的话会产生io的系统调用事件, 用于触发回调
1686908998.016880 epoll_wait(5,  <detached ...>
# 初步结论: timer被设置的时间特别长或者timer被取消了(strace中无timerfd相关调用:定时器未正确初始化或已取消)
http://www.dtcms.com/a/281888.html

相关文章:

  • 代码随想录算法训练营第五十一天|图论part2
  • 【FreeRTOS】03任务管理
  • 工业相机GigE数据接口的优势及应用
  • django安装、跨域、缓存、令牌、路由、中间件等配置
  • Jenkins全方位CI/CD实战指南
  • LabVIEW Occurrence功能
  • 嵌入式Linux(RV1126)系统定制中的编译与引导问题调试报告
  • 【RTSP从零实践】12、TCP传输H264格式RTP包(RTP_over_TCP)的RTSP服务器(附带源码)
  • 基于WebRTC技术实现一个在线课堂系统
  • el-input 回显怎么用符号¥和变量拼接展示?
  • Spring Boot 解决跨域问题
  • Spring Boot - Spring Boot 集成 MyBatis 分页实现 手写 SQL 分页
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(5):语法+单词
  • Buffer Pool
  • css 如何实现大屏4个占位 中屏2个 小屏幕1个
  • Samba服务器
  • Git版本控制完全指南:从入门到精通
  • 网络编程/Java面试/TCPUDP区别
  • 基于spring boot养老院老人健康监护平台设计与实现
  • SFT:大型语言模型专业化定制的核心技术体系——原理、创新与应用全景
  • docker run elasticsearch 报错
  • JAVA面试宝典 -《分布式ID生成器:Snowflake优化变种》
  • 详解SPFA算法-单源最短路径求解
  • C++ - 仿 RabbitMQ 实现消息队列--sqlite与gtest快速上手
  • 基于springboot+vue的酒店管理系统设计与实现
  • 一叶障目不见森林
  • 身份证号码姓名认证解决方案-身份证三要素API接口
  • Apache IoTDB(1):时序数据库介绍与单机版安装部署指南
  • 更灵活方便的初始化、清除方法——fixture【pytest】
  • QT跨平台应用程序开发框架(9)—— 容器类控件