xref: /openbmc/google-misc/acpi-power-state-daemon/subprojects/ncsid/src/net_config.cpp (revision 1285115c16180bd28a3cfe79d9db8d10c84fe2ed)
1*1285115cSWilliam A. Kennington III // Copyright 2021 Google LLC
2*1285115cSWilliam A. Kennington III //
3*1285115cSWilliam A. Kennington III // Licensed under the Apache License, Version 2.0 (the "License");
4*1285115cSWilliam A. Kennington III // you may not use this file except in compliance with the License.
5*1285115cSWilliam A. Kennington III // You may obtain a copy of the License at
6*1285115cSWilliam A. Kennington III //
7*1285115cSWilliam A. Kennington III //      http://www.apache.org/licenses/LICENSE-2.0
8*1285115cSWilliam A. Kennington III //
9*1285115cSWilliam A. Kennington III // Unless required by applicable law or agreed to in writing, software
10*1285115cSWilliam A. Kennington III // distributed under the License is distributed on an "AS IS" BASIS,
11*1285115cSWilliam A. Kennington III // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*1285115cSWilliam A. Kennington III // See the License for the specific language governing permissions and
13*1285115cSWilliam A. Kennington III // limitations under the License.
14*1285115cSWilliam A. Kennington III 
15*1285115cSWilliam A. Kennington III #include "net_config.h"
16*1285115cSWilliam A. Kennington III 
17*1285115cSWilliam A. Kennington III #include <fmt/format.h>
18*1285115cSWilliam A. Kennington III #include <sys/types.h>
19*1285115cSWilliam A. Kennington III #include <sys/wait.h>
20*1285115cSWilliam A. Kennington III #include <unistd.h>
21*1285115cSWilliam A. Kennington III 
22*1285115cSWilliam A. Kennington III #include <sdbusplus/bus.hpp>
23*1285115cSWilliam A. Kennington III #include <stdplus/util/string.hpp>
24*1285115cSWilliam A. Kennington III 
25*1285115cSWilliam A. Kennington III #include <cstdio>
26*1285115cSWilliam A. Kennington III #include <cstring>
27*1285115cSWilliam A. Kennington III #include <utility>
28*1285115cSWilliam A. Kennington III #include <variant>
29*1285115cSWilliam A. Kennington III 
30*1285115cSWilliam A. Kennington III /* Most of the code for interacting with DBus is from
31*1285115cSWilliam A. Kennington III  * phosphor-host-ipmid/utils.cpp
32*1285115cSWilliam A. Kennington III  */
33*1285115cSWilliam A. Kennington III 
34*1285115cSWilliam A. Kennington III namespace net
35*1285115cSWilliam A. Kennington III {
36*1285115cSWilliam A. Kennington III 
37*1285115cSWilliam A. Kennington III namespace
38*1285115cSWilliam A. Kennington III {
39*1285115cSWilliam A. Kennington III 
40*1285115cSWilliam A. Kennington III constexpr auto IFACE_ROOT = "/xyz/openbmc_project/network/";
41*1285115cSWilliam A. Kennington III constexpr auto MAC_FORMAT = "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx";
42*1285115cSWilliam A. Kennington III // 2 chars for every byte + 5 colons + Null byte
43*1285115cSWilliam A. Kennington III constexpr auto MAC_FORMAT_LENGTH = 6 * 2 + 5 + 1;
44*1285115cSWilliam A. Kennington III constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
45*1285115cSWilliam A. Kennington III constexpr auto NETWORK_SERVICE = "xyz.openbmc_project.Network";
46*1285115cSWilliam A. Kennington III constexpr auto PROP_INTERFACE = "org.freedesktop.DBus.Properties";
47*1285115cSWilliam A. Kennington III 
48*1285115cSWilliam A. Kennington III int parse_mac(const std::string& mac_addr, mac_addr_t* mac)
49*1285115cSWilliam A. Kennington III {
50*1285115cSWilliam A. Kennington III     int ret =
51*1285115cSWilliam A. Kennington III         sscanf(mac_addr.c_str(), MAC_FORMAT, mac->octet, mac->octet + 1,
52*1285115cSWilliam A. Kennington III                mac->octet + 2, mac->octet + 3, mac->octet + 4, mac->octet + 5);
53*1285115cSWilliam A. Kennington III 
54*1285115cSWilliam A. Kennington III     return ret < 6 ? -1 : 0;
55*1285115cSWilliam A. Kennington III }
56*1285115cSWilliam A. Kennington III 
57*1285115cSWilliam A. Kennington III std::string format_mac(const mac_addr_t& mac)
58*1285115cSWilliam A. Kennington III {
59*1285115cSWilliam A. Kennington III     // 2 chars for every byte + 5 colons + Null byte
60*1285115cSWilliam A. Kennington III     char mac_str[MAC_FORMAT_LENGTH];
61*1285115cSWilliam A. Kennington III     snprintf(mac_str, sizeof(mac_str), MAC_FORMAT, mac.octet[0], mac.octet[1],
62*1285115cSWilliam A. Kennington III              mac.octet[2], mac.octet[3], mac.octet[4], mac.octet[5]);
63*1285115cSWilliam A. Kennington III 
64*1285115cSWilliam A. Kennington III     return std::string{mac_str};
65*1285115cSWilliam A. Kennington III }
66*1285115cSWilliam A. Kennington III 
67*1285115cSWilliam A. Kennington III } // namespace
68*1285115cSWilliam A. Kennington III 
69*1285115cSWilliam A. Kennington III PhosphorConfig::PhosphorConfig(const std::string& iface_name) :
70*1285115cSWilliam A. Kennington III     iface_name_{iface_name}, iface_path_{std::string(IFACE_ROOT) + iface_name},
71*1285115cSWilliam A. Kennington III     shared_host_mac_(std::experimental::nullopt),
72*1285115cSWilliam A. Kennington III     bus(sdbusplus::bus::new_default())
73*1285115cSWilliam A. Kennington III {}
74*1285115cSWilliam A. Kennington III 
75*1285115cSWilliam A. Kennington III sdbusplus::message::message
76*1285115cSWilliam A. Kennington III     PhosphorConfig::new_networkd_call(sdbusplus::bus::bus* dbus, bool get) const
77*1285115cSWilliam A. Kennington III {
78*1285115cSWilliam A. Kennington III     auto networkd_call =
79*1285115cSWilliam A. Kennington III         dbus->new_method_call(NETWORK_SERVICE, iface_path_.c_str(),
80*1285115cSWilliam A. Kennington III                               PROP_INTERFACE, get ? "Get" : "Set");
81*1285115cSWilliam A. Kennington III 
82*1285115cSWilliam A. Kennington III     networkd_call.append(MAC_INTERFACE, "MACAddress");
83*1285115cSWilliam A. Kennington III 
84*1285115cSWilliam A. Kennington III     return networkd_call;
85*1285115cSWilliam A. Kennington III }
86*1285115cSWilliam A. Kennington III 
87*1285115cSWilliam A. Kennington III int PhosphorConfig::get_mac_addr(mac_addr_t* mac)
88*1285115cSWilliam A. Kennington III {
89*1285115cSWilliam A. Kennington III     if (mac == nullptr)
90*1285115cSWilliam A. Kennington III     {
91*1285115cSWilliam A. Kennington III         fmt::print(stderr, "mac is nullptr\n");
92*1285115cSWilliam A. Kennington III         return -1;
93*1285115cSWilliam A. Kennington III     }
94*1285115cSWilliam A. Kennington III 
95*1285115cSWilliam A. Kennington III     // Cache hit: we have stored host MAC.
96*1285115cSWilliam A. Kennington III     if (shared_host_mac_)
97*1285115cSWilliam A. Kennington III     {
98*1285115cSWilliam A. Kennington III         *mac = shared_host_mac_.value();
99*1285115cSWilliam A. Kennington III     }
100*1285115cSWilliam A. Kennington III     else // Cache miss: read MAC over DBus, and store in cache.
101*1285115cSWilliam A. Kennington III     {
102*1285115cSWilliam A. Kennington III         std::string mac_string;
103*1285115cSWilliam A. Kennington III         try
104*1285115cSWilliam A. Kennington III         {
105*1285115cSWilliam A. Kennington III             auto networkd_call = new_networkd_call(&bus, true);
106*1285115cSWilliam A. Kennington III             auto reply = bus.call(networkd_call);
107*1285115cSWilliam A. Kennington III             std::variant<std::string> result;
108*1285115cSWilliam A. Kennington III             reply.read(result);
109*1285115cSWilliam A. Kennington III             mac_string = std::get<std::string>(result);
110*1285115cSWilliam A. Kennington III         }
111*1285115cSWilliam A. Kennington III         catch (const sdbusplus::exception::SdBusError& ex)
112*1285115cSWilliam A. Kennington III         {
113*1285115cSWilliam A. Kennington III             fmt::print(stderr, "Failed to get MACAddress: {}\n", ex.what());
114*1285115cSWilliam A. Kennington III             return -1;
115*1285115cSWilliam A. Kennington III         }
116*1285115cSWilliam A. Kennington III 
117*1285115cSWilliam A. Kennington III         if (parse_mac(mac_string, mac) < 0)
118*1285115cSWilliam A. Kennington III         {
119*1285115cSWilliam A. Kennington III             fmt::print(stderr, "Failed to parse MAC Address `{}`\n",
120*1285115cSWilliam A. Kennington III                        mac_string);
121*1285115cSWilliam A. Kennington III             return -1;
122*1285115cSWilliam A. Kennington III         }
123*1285115cSWilliam A. Kennington III 
124*1285115cSWilliam A. Kennington III         shared_host_mac_ = *mac;
125*1285115cSWilliam A. Kennington III     }
126*1285115cSWilliam A. Kennington III 
127*1285115cSWilliam A. Kennington III     return 0;
128*1285115cSWilliam A. Kennington III }
129*1285115cSWilliam A. Kennington III 
130*1285115cSWilliam A. Kennington III int PhosphorConfig::set_mac_addr(const mac_addr_t& mac)
131*1285115cSWilliam A. Kennington III {
132*1285115cSWilliam A. Kennington III     auto networkd_call = new_networkd_call(&bus, false);
133*1285115cSWilliam A. Kennington III     std::variant<std::string> mac_value(format_mac(mac));
134*1285115cSWilliam A. Kennington III     networkd_call.append(mac_value);
135*1285115cSWilliam A. Kennington III 
136*1285115cSWilliam A. Kennington III     try
137*1285115cSWilliam A. Kennington III     {
138*1285115cSWilliam A. Kennington III         auto reply = bus.call(networkd_call);
139*1285115cSWilliam A. Kennington III     }
140*1285115cSWilliam A. Kennington III     catch (const sdbusplus::exception::SdBusError& ex)
141*1285115cSWilliam A. Kennington III     {
142*1285115cSWilliam A. Kennington III         fmt::print(stderr, "Failed to set MAC Addr `{}`: {}\n",
143*1285115cSWilliam A. Kennington III                    std::get<std::string>(mac_value), ex.what());
144*1285115cSWilliam A. Kennington III         return -1;
145*1285115cSWilliam A. Kennington III     }
146*1285115cSWilliam A. Kennington III 
147*1285115cSWilliam A. Kennington III     shared_host_mac_ = std::experimental::nullopt;
148*1285115cSWilliam A. Kennington III     return 0;
149*1285115cSWilliam A. Kennington III }
150*1285115cSWilliam A. Kennington III 
151*1285115cSWilliam A. Kennington III int PhosphorConfig::set_nic_hostless(bool is_nic_hostless)
152*1285115cSWilliam A. Kennington III {
153*1285115cSWilliam A. Kennington III     // Ensure that we don't trigger the target multiple times. This is
154*1285115cSWilliam A. Kennington III     // undesirable because it will cause any inactive services to re-trigger
155*1285115cSWilliam A. Kennington III     // every time we run this code. Since the loop calling this executes this
156*1285115cSWilliam A. Kennington III     // code every 1s, we don't want to keep re-executing services. A fresh
157*1285115cSWilliam A. Kennington III     // start of the daemon will always trigger the service to ensure system
158*1285115cSWilliam A. Kennington III     // consistency.
159*1285115cSWilliam A. Kennington III     if (was_nic_hostless_ && is_nic_hostless == *was_nic_hostless_)
160*1285115cSWilliam A. Kennington III     {
161*1285115cSWilliam A. Kennington III         return 0;
162*1285115cSWilliam A. Kennington III     }
163*1285115cSWilliam A. Kennington III 
164*1285115cSWilliam A. Kennington III     static constexpr auto systemdService = "org.freedesktop.systemd1";
165*1285115cSWilliam A. Kennington III     static constexpr auto systemdRoot = "/org/freedesktop/systemd1";
166*1285115cSWilliam A. Kennington III     static constexpr auto systemdInterface = "org.freedesktop.systemd1.Manager";
167*1285115cSWilliam A. Kennington III 
168*1285115cSWilliam A. Kennington III     auto method = bus.new_method_call(systemdService, systemdRoot,
169*1285115cSWilliam A. Kennington III                                       systemdInterface, "StartUnit");
170*1285115cSWilliam A. Kennington III     if (is_nic_hostless)
171*1285115cSWilliam A. Kennington III     {
172*1285115cSWilliam A. Kennington III         method.append(
173*1285115cSWilliam A. Kennington III             stdplus::util::strCat("nic-hostless@", iface_name_, ".target"));
174*1285115cSWilliam A. Kennington III     }
175*1285115cSWilliam A. Kennington III     else
176*1285115cSWilliam A. Kennington III     {
177*1285115cSWilliam A. Kennington III         method.append(
178*1285115cSWilliam A. Kennington III             stdplus::util::strCat("nic-hostful@", iface_name_, ".target"));
179*1285115cSWilliam A. Kennington III     }
180*1285115cSWilliam A. Kennington III 
181*1285115cSWilliam A. Kennington III     // Specify --job-mode (see systemctl(1) for detail).
182*1285115cSWilliam A. Kennington III     method.append("replace");
183*1285115cSWilliam A. Kennington III 
184*1285115cSWilliam A. Kennington III     try
185*1285115cSWilliam A. Kennington III     {
186*1285115cSWilliam A. Kennington III         bus.call_noreply(method);
187*1285115cSWilliam A. Kennington III         was_nic_hostless_ = is_nic_hostless;
188*1285115cSWilliam A. Kennington III         return 0;
189*1285115cSWilliam A. Kennington III     }
190*1285115cSWilliam A. Kennington III     catch (const sdbusplus::exception::SdBusError& ex)
191*1285115cSWilliam A. Kennington III     {
192*1285115cSWilliam A. Kennington III         fmt::print(stderr, "Failed to set systemd nic status: {}\n", ex.what());
193*1285115cSWilliam A. Kennington III         return 1;
194*1285115cSWilliam A. Kennington III     }
195*1285115cSWilliam A. Kennington III }
196*1285115cSWilliam A. Kennington III 
197*1285115cSWilliam A. Kennington III } // namespace net
198