summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey V.Kosteltsev <AKosteltsev@IBS.RU>2022-07-17 19:37:13 +0300
committerAndrey V.Kosteltsev <AKosteltsev@IBS.RU>2022-07-21 16:24:01 +0300
commit4f4e9c898a078be194f449838addbfb04aca7e88 (patch)
treec7072fcd8d42c19cea70322b6d834a599fe83d71
parentff5831df9d6f272c255fdbf3d60ebc82bc7cb338 (diff)
downloadopenbmc-4f4e9c898a078be194f449838addbfb04aca7e88.tar.xz
IBS: SNMP Support (First Approx)
-rw-r--r--meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend10
-rw-r--r--meta-ibs/meta-common/recipes-ibs/packagegroups/packagegroup-ibs-apps.bb2
-rw-r--r--meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp/0001-config_os_libs2-no-pci-lookup.patch16
-rw-r--r--meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp/snmpd.conf34
-rw-r--r--meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp_%.bbappend10
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-phosphor/network/obmc-sila-snmp_git.bb65
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0001-main-Use-sdeventplus.patch123
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0002-main-Add-UNIX-signals-handler.patch102
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0003-conf_manager-use-snmpd-as-a-clients-storage.patch859
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/snmpd-dependency.conf3
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp_%.bbappend23
11 files changed, 1247 insertions, 0 deletions
diff --git a/meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend b/meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend
index cd56e009b3..914444cfb1 100644
--- a/meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend
+++ b/meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend
@@ -13,6 +13,16 @@ IMAGE_INSTALL += " openssl-bin \
smbios-mdrv2 \
"
+IMAGE_INSTALL += " net-snmp-lib-agent \
+ net-snmp-lib-helpers \
+ net-snmp-lib-mibs \
+ net-snmp-lib-netsnmp \
+ net-snmp-lib-trapd \
+ net-snmp-mibs \
+ net-snmp-server-snmpd \
+ net-snmp-server-snmptrapd \
+ "
+
OBMC_IMAGE_EXTRA_INSTALL += " "
fix_shadow_perms() {
diff --git a/meta-ibs/meta-common/recipes-ibs/packagegroups/packagegroup-ibs-apps.bb b/meta-ibs/meta-common/recipes-ibs/packagegroups/packagegroup-ibs-apps.bb
index 35ee6c8459..92f95a235d 100644
--- a/meta-ibs/meta-common/recipes-ibs/packagegroups/packagegroup-ibs-apps.bb
+++ b/meta-ibs/meta-common/recipes-ibs/packagegroups/packagegroup-ibs-apps.bb
@@ -59,6 +59,8 @@ RDEPENDS:${PN}-interface = " \
webui-vue \
phosphor-ipmi-ipmb \
phosphor-snmp \
+ obmc-sila-snmp-agent \
+ obmc-sila-snmp-cfg-manager \
"
SUMMARY:${PN}-cli = "CLI utils"
diff --git a/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp/0001-config_os_libs2-no-pci-lookup.patch b/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp/0001-config_os_libs2-no-pci-lookup.patch
new file mode 100644
index 0000000000..1ac465b28d
--- /dev/null
+++ b/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp/0001-config_os_libs2-no-pci-lookup.patch
@@ -0,0 +1,16 @@
+diff -bu -Nr net-snmp-5.9.1-orig/configure.d/config_os_libs2 net-snmp-5.9.1/configure.d/config_os_libs2
+--- net-snmp-5.9.1-orig/configure.d/config_os_libs2 2022-07-16 18:27:39.958781773 +0300
++++ net-snmp-5.9.1/configure.d/config_os_libs2 2022-07-16 20:07:49.846845832 +0300
+@@ -185,9 +185,9 @@
+ # libpci
+ # (for if-mib description)
+ #
+-NETSNMP_SEARCH_LIBS(pci_lookup_name, pci,
+- AC_DEFINE(HAVE_PCI_LOOKUP_NAME, 1,
+- [define if you have pci_lookup_name()]),,,LMIBLIBS)
++#NETSNMP_SEARCH_LIBS(pci_lookup_name, pci,
++# AC_DEFINE(HAVE_PCI_LOOKUP_NAME, 1,
++# [define if you have pci_lookup_name()]),,,LMIBLIBS)
+
+ # LM-SENSORS-MIB support
+ #
diff --git a/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp/snmpd.conf b/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp/snmpd.conf
new file mode 100644
index 0000000000..9244009421
--- /dev/null
+++ b/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp/snmpd.conf
@@ -0,0 +1,34 @@
+
+rwcommunity private localhost
+
+# sec.name source community
+com2sec readonly default public
+com2sec rwsink localhost private
+
+# sec.model sec.name
+group MyROGroup v1 readonly
+group MyROGroup v2c readonly
+group MyROGroup usm readonly
+group MyRWGroup usm root
+group MyRwGroup v2c rwsink
+
+# incl/excl subtree mask
+view readonly included .1.3.6.1.2.1.1
+view readonly included .1.3.6.1.2.1.25.1.1
+view readonly included .1.3.6.1.4.1.49769
+view rwsink included .1.3.6.1.6.3
+
+# context sec.model sec.level match read write notif
+access MyROGroup "" any noauth exact readonly none none
+access MyRWGroup "" any priv exact all all none
+access MyRwGroup "" v2c noauth exact all rwsink none
+
+###############################################################################
+# System contact information
+#
+
+syslocation Solar System, Earth (configure /etc/snmp/snmpd.conf)
+syscontact Root <root@localhost> (configure /etc/snmp/snmpd.conf)
+
+# -----------------------------------------------------------------------------
+master agentx
diff --git a/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp_%.bbappend b/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp_%.bbappend
new file mode 100644
index 0000000000..71b972804c
--- /dev/null
+++ b/meta-ibs/meta-common/recipes-protocols/net-snmp/net-snmp_%.bbappend
@@ -0,0 +1,10 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+#
+# meta-openembedded/meta-networking/recipes-protocols/net-snmp:
+#
+
+SRC_URI += " \
+ file://snmpd.conf \
+ file://0001-config_os_libs2-no-pci-lookup.patch \
+ "
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/network/obmc-sila-snmp_git.bb b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/obmc-sila-snmp_git.bb
new file mode 100644
index 0000000000..ef817d170c
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/obmc-sila-snmp_git.bb
@@ -0,0 +1,65 @@
+SUMMARY = "Sila SNMP agent for OpenBMC"
+DESCRIPTION = "The project provides a snmp subagent and configuration manager."
+HOMEPAGE = "http://git.sila.ru/openbmc/obmc-sila-snmp.git/"
+
+PR = "r1"
+PV = "1.0+git${SRCPV}"
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e3fc50a88d0a364313df4b21ef20c29e"
+
+SRC_URI = "git://git@git.sila.ru/srv/pub/scm/git/openbmc/obmc-sila-snmp.git;branch=master;protocol=ssh"
+SRCREV = "771d61bc4849de8c6af38a71dfa4e1740721fc12"
+
+
+inherit autotools pkgconfig python3native
+inherit obmc-phosphor-dbus-service
+
+S = "${WORKDIR}/git"
+
+DEPENDS += " autoconf-archive-native"
+DEPENDS += " net-snmp"
+DEPENDS += " systemd"
+DEPENDS += " sdbusplus"
+DEPENDS += " sdeventplus"
+DEPENDS += " ${PYTHON_PN}-sdbus++-native"
+DEPENDS += " phosphor-logging"
+DEPENDS += " phosphor-dbus-interfaces"
+
+
+# Package configuration
+SNMP_PACKAGES = " \
+ ${PN}-agent \
+ ${PN}-cfg-manager \
+ "
+
+ALLOW_EMPTY_${PN} = "1"
+PACKAGE_BEFORE_PN += "${SNMP_PACKAGES}"
+PACKAGECONFIG ?= "agent cfg-manager"
+SYSTEMD_PACKAGES = "${PN}-agent"
+DBUS_PACKAGES = "${PN}-cfg-manager"
+
+# --------------------------------------
+# ${PN}-agent specific configuration:
+# --------------------------------------
+PACKAGECONFIG[agent] = "--enable-agent,--disable-agent,,"
+RDEPENDS_${PN}-agent += " sdbusplus net-snmp-libs net-snmp-server-snmpd"
+FILES:${PN}-agent = " \
+ ${bindir}/sila-snmp-agent \
+ ${datadir}/snmp/mibs/SILA-MIB.txt \
+ "
+
+SYSTEMD_SERVICE:${PN}-agent += "sila-snmp-agent.service"
+
+# --------------------------------------
+# ${PN}-cfg-manager specific configuration
+PACKAGECONFIG[cfg-manager] = "--enable-cfg-manager,--disable-cfg-manager,,"
+RDEPENDS:${PN}-cfg-manager += " sdbusplus"
+FILES:${PN}-cfg-manager = "${bindir}/sila-snmpcfg"
+DBUS_SERVICE:${PN}-cfg-manager += "sila-snmp-cfg-manager.service"
+
+# Makes the MIB-file available over https by bmcweb
+FILES:${PN}-agent += " ${datadir}/www/mibs/SILA-MIB.txt "
+do_install:append () {
+ mkdir -p ${D}${datadir}/www/mibs
+ ln -s ${datadir}/snmp/mibs/SILA-MIB.txt ${D}${datadir}/www/mibs/SILA-MIB.txt
+}
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0001-main-Use-sdeventplus.patch b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0001-main-Use-sdeventplus.patch
new file mode 100644
index 0000000000..e38befa7d6
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0001-main-Use-sdeventplus.patch
@@ -0,0 +1,123 @@
+From d07ee811792a8440fc0cc99d7f51aa4121e50928 Mon Sep 17 00:00:00 2001
+From: "Andrey V.Kosteltsev" <AKosteltsev@IBS.RU>
+Date: Sun, 17 Jul 2022 12:25:14 +0300
+Subject: [PATCH 1/3] main: Use sdeventplus
+
+Makes use sdeventplus instead custom wrapper around the sd_event library calls.
+
+Signed-off-by: Andrey V.Kosteltsev <AKosteltsev@IBS.RU>
+---
+ meson.build | 8 +++++++-
+ snmp_main.cpp | 27 ++++-----------------------
+ subprojects/sdeventplus.wrap | 6 ++++++
+ 3 files changed, 17 insertions(+), 24 deletions(-)
+ create mode 100644 subprojects/sdeventplus.wrap
+
+diff --git a/meson.build b/meson.build
+index 73ca4a6..8a82752 100644
+--- a/meson.build
++++ b/meson.build
+@@ -17,6 +17,7 @@ conf_data.set_quoted('SNMP_CONF_PERSIST_PATH', '/var/lib/phosphor-snmp/managers/
+ conf_data.set('CLASS_VERSION', 1)
+
+ sdbusplus_dep = dependency('sdbusplus')
++sdeventplus_dep = dependency('sdeventplus')
+ phosphor_dbus_interfaces_dep = dependency('phosphor-dbus-interfaces')
+ phosphor_logging_dep = dependency('phosphor-logging')
+ libsystemd_dep = dependency('libsystemd')
+@@ -30,6 +31,7 @@ deps = [
+ phosphor_dbus_interfaces_dep,
+ phosphor_logging_dep,
+ sdbusplus_dep,
++ sdeventplus_dep,
+ ]
+
+ sources = [
+@@ -55,6 +57,7 @@ executable(
+
+ libsnmp_deps = [
+ sdbusplus_dep,
++ sdeventplus_dep,
+ phosphor_logging_dep,
+ phosphor_dbus_interfaces_dep,
+ netsnmp_dep,
+@@ -85,7 +88,10 @@ import('pkgconfig').generate(
+ libsnmp_lib,
+ name: meson.project_name(),
+ version: meson.project_version(),
+- requires: sdbusplus_dep,
++ requires: [
++ sdbusplus_dep,
++ sdeventplus_dep,
++ ],
+ description: 'Phosphor snmp utilities',
+ )
+
+diff --git a/snmp_main.cpp b/snmp_main.cpp
+index be4bea1..ab3c4b6 100644
+--- a/snmp_main.cpp
++++ b/snmp_main.cpp
+@@ -4,38 +4,19 @@
+
+ #include <phosphor-logging/lg2.hpp>
+ #include <sdbusplus/bus.hpp>
++#include <sdeventplus/event.hpp>
+ #include <sdbusplus/server/manager.hpp>
+
+ #include <memory>
+
+-/* Need a custom deleter for freeing up sd_event */
+-struct EventDeleter
+-{
+- void operator()(sd_event* event) const
+- {
+- sd_event_unref(event);
+- }
+-};
+-
+-using EventPtr = std::unique_ptr<sd_event, EventDeleter>;
+-
+ int main(int /*argc*/, char** /*argv[]*/)
+ {
+ auto bus = sdbusplus::bus::new_default();
+
+- sd_event* event = nullptr;
+- auto r = sd_event_default(&event);
+- if (r < 0)
+- {
+- lg2::error("Error creating a default sd_event handler: {RC}", "RC", r);
+- return r;
+- }
+-
+- EventPtr eventPtr{event};
+- event = nullptr;
++ auto event = sdeventplus::Event::get_default();
+
+ // Attach the bus to sd_event to service user requests
+- bus.attach_event(eventPtr.get(), SD_EVENT_PRIORITY_NORMAL);
++ bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
+
+ // Add sdbusplus Object Manager for the 'root' path of the snmp.
+ sdbusplus::server::manager::manager objManager(bus, OBJ_NETWORK_SNMP);
+@@ -46,5 +27,5 @@ int main(int /*argc*/, char** /*argv[]*/)
+
+ manager->restoreClients();
+
+- return sd_event_loop(eventPtr.get());
++ return event.loop();
+ }
+diff --git a/subprojects/sdeventplus.wrap b/subprojects/sdeventplus.wrap
+new file mode 100644
+index 0000000..f871ac0
+--- /dev/null
++++ b/subprojects/sdeventplus.wrap
+@@ -0,0 +1,6 @@
++[wrap-git]
++url = https://github.com/openbmc/sdeventplus.git
++revision = HEAD
++
++[provide]
++sdeventplus = sdeventplus_dep
+--
+2.35.1
+
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0002-main-Add-UNIX-signals-handler.patch b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0002-main-Add-UNIX-signals-handler.patch
new file mode 100644
index 0000000000..9ff1e35897
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0002-main-Add-UNIX-signals-handler.patch
@@ -0,0 +1,102 @@
+From 81daf0a592fdcb0df22476621e3202e9932a867e Mon Sep 17 00:00:00 2001
+From: "Andrey V.Kosteltsev" <AKosteltsev@IBS.RU>
+Date: Sun, 17 Jul 2022 12:55:01 +0300
+Subject: [PATCH 2/3] main: Add UNIX signals handler
+
+This commit adds a handler for SIGTERM and SIGINT signals that is the normal service stop.
+
+Signed-off-by: Andrey V.Kosteltsev <AKosteltsev@IBS.RU>
+---
+ meson.build | 4 ++++
+ snmp_main.cpp | 15 +++++++++++++++
+ subprojects/stdplus.wrap | 6 ++++++
+ 3 files changed, 25 insertions(+)
+ create mode 100644 subprojects/stdplus.wrap
+
+diff --git a/meson.build b/meson.build
+index 8a82752..4ed6094 100644
+--- a/meson.build
++++ b/meson.build
+@@ -18,6 +18,7 @@ conf_data.set('CLASS_VERSION', 1)
+
+ sdbusplus_dep = dependency('sdbusplus')
+ sdeventplus_dep = dependency('sdeventplus')
++stdplus_dep = dependency('stdplus')
+ phosphor_dbus_interfaces_dep = dependency('phosphor-dbus-interfaces')
+ phosphor_logging_dep = dependency('phosphor-logging')
+ libsystemd_dep = dependency('libsystemd')
+@@ -32,6 +33,7 @@ deps = [
+ phosphor_logging_dep,
+ sdbusplus_dep,
+ sdeventplus_dep,
++ stdplus_dep,
+ ]
+
+ sources = [
+@@ -58,6 +60,7 @@ executable(
+ libsnmp_deps = [
+ sdbusplus_dep,
+ sdeventplus_dep,
++ stdplus_dep,
+ phosphor_logging_dep,
+ phosphor_dbus_interfaces_dep,
+ netsnmp_dep,
+@@ -91,6 +94,7 @@ import('pkgconfig').generate(
+ requires: [
+ sdbusplus_dep,
+ sdeventplus_dep,
++ stdplus_dep,
+ ],
+ description: 'Phosphor snmp utilities',
+ )
+diff --git a/snmp_main.cpp b/snmp_main.cpp
+index ab3c4b6..df5850b 100644
+--- a/snmp_main.cpp
++++ b/snmp_main.cpp
+@@ -5,10 +5,18 @@
+ #include <phosphor-logging/lg2.hpp>
+ #include <sdbusplus/bus.hpp>
+ #include <sdeventplus/event.hpp>
++#include <sdeventplus/source/signal.hpp>
+ #include <sdbusplus/server/manager.hpp>
++#include <stdplus/signal.hpp>
+
+ #include <memory>
+
++static void cleanExit(sdeventplus::source::Signal& source,
++ const struct signalfd_siginfo*)
++{
++ source.get_event().exit(EXIT_SUCCESS);
++}
++
+ int main(int /*argc*/, char** /*argv[]*/)
+ {
+ auto bus = sdbusplus::bus::new_default();
+@@ -27,5 +35,12 @@ int main(int /*argc*/, char** /*argv[]*/)
+
+ manager->restoreClients();
+
++ // Clean exit by unix signal
++ stdplus::signal::block(SIGTERM);
++ stdplus::signal::block(SIGINT);
++
++ sdeventplus::source::Signal sigTerm(event, SIGTERM, cleanExit);
++ sdeventplus::source::Signal sigInt(event, SIGINT, cleanExit);
++
+ return event.loop();
+ }
+diff --git a/subprojects/stdplus.wrap b/subprojects/stdplus.wrap
+new file mode 100644
+index 0000000..2f8a5f4
+--- /dev/null
++++ b/subprojects/stdplus.wrap
+@@ -0,0 +1,6 @@
++[wrap-git]
++url = https://github.com/openbmc/stdplus.git
++revision = HEAD
++
++[provide]
++stdplus = stdplus_dep
+--
+2.35.1
+
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0003-conf_manager-use-snmpd-as-a-clients-storage.patch b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0003-conf_manager-use-snmpd-as-a-clients-storage.patch
new file mode 100644
index 0000000000..e13de7ba74
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/0003-conf_manager-use-snmpd-as-a-clients-storage.patch
@@ -0,0 +1,859 @@
+From 22a0736aa2613f0821e762e76db0efac17a0b7b1 Mon Sep 17 00:00:00 2001
+From: "Andrey V.Kosteltsev" <AKosteltsev@IBS.RU>
+Date: Sun, 17 Jul 2022 19:05:14 +0300
+Subject: [PATCH 3/3] conf_manager: use snmpd as a clients storage
+
+This commit brings the alternative of storage of clients. It's able now to communicate with snmpd and manage the built-in list of snmp trap receivers.
+
+Signed-off-by: Andrey V.Kosteltsev <AKosteltsev@IBS.RU>
+---
+ meson.build | 9 ++
+ meson_options.txt | 19 ++++
+ snmp/exceptions.hpp | 71 ++++++++++++++
+ snmp/notify_tables.hpp | 58 ++++++++++++
+ snmp/oid.hpp | 42 +++++++++
+ snmp/pdu.hpp | 150 +++++++++++++++++++++++++++++
+ snmp/session.hpp | 110 ++++++++++++++++++++++
+ snmp_conf_manager.cpp | 207 +++++++++++++++++++++++++++++++++++++++++
+ snmp_conf_manager.hpp | 8 ++
+ snmp_main.cpp | 11 +++
+ 10 files changed, 685 insertions(+)
+ create mode 100644 snmp/exceptions.hpp
+ create mode 100644 snmp/notify_tables.hpp
+ create mode 100644 snmp/oid.hpp
+ create mode 100644 snmp/pdu.hpp
+ create mode 100644 snmp/session.hpp
+
+diff --git a/meson.build b/meson.build
+index 4ed6094..ad07caa 100644
+--- a/meson.build
++++ b/meson.build
+@@ -44,6 +44,15 @@ sources = [
+ 'snmp_serialize.cpp',
+ ]
+
++if get_option('snmpd-support').enabled()
++ conf_data.set('USE_SNMPD', 1)
++ deps += [
++ netsnmp_dep,
++ ]
++ conf_data.set_quoted('SNMPD_ADDRESS', get_option('snmpd-address'))
++ conf_data.set_quoted('SNMPD_COMMUNITY', get_option('snmpd-community'))
++endif
++
+ configure_file(output: 'config.h',
+ configuration: conf_data
+ )
+diff --git a/meson_options.txt b/meson_options.txt
+index f1c7bd8..8b26686 100644
+--- a/meson_options.txt
++++ b/meson_options.txt
+@@ -1 +1,20 @@
++
++option('snmpd-support',
++ type: 'feature',
++ value: 'disabled',
++ description: 'Enable snmpd as a client storage.'
++)
++
++option('snmpd-address',
++ type: 'string',
++ value: 'localhost',
++ description: 'Address of snmpd.'
++)
++
++option('snmpd-community',
++ type: 'string',
++ value: 'private',
++ description: 'Community name to communicate with snmpd.'
++)
++
+ option('tests', type : 'feature', description : 'Build tests')
+\ No newline at end of file
+diff --git a/snmp/exceptions.hpp b/snmp/exceptions.hpp
+new file mode 100644
+index 0000000..9f1d858
+--- /dev/null
++++ b/snmp/exceptions.hpp
+@@ -0,0 +1,71 @@
++#pragma once
++
++#include <net-snmp/net-snmp-config.h>
++#include <net-snmp/net-snmp-includes.h>
++
++#include <stdexcept>
++
++namespace snmp
++{
++namespace exception
++{
++
++class SnmpError : public std::runtime_error
++{
++ public:
++ using std::runtime_error::runtime_error;
++};
++
++class SnmpSessionError : public SnmpError
++{
++ public:
++ using SnmpError::SnmpError;
++
++ SnmpSessionError(netsnmp_session* sp, const std::string& name) :
++ SnmpError(makeError(sp, name))
++ {
++ }
++
++ protected:
++ static std::string makeError(netsnmp_session* sp, const std::string& name)
++ {
++ char* msg = nullptr;
++ snmp_error(sp, nullptr, nullptr, &msg);
++ std::string error = name + " failed, ";
++ error += msg;
++ SNMP_FREE(msg);
++
++ return error;
++ }
++};
++
++class SnmpTimeout : public SnmpError
++{
++ public:
++ using SnmpError::SnmpError;
++
++ SnmpTimeout() : SnmpError("Connection timed out!")
++ {
++ }
++};
++
++class SnmpPacketError : public SnmpError
++{
++ public:
++ using SnmpError::SnmpError;
++
++ SnmpPacketError(int ec) : SnmpError(makeError(ec))
++ {
++ }
++
++ protected:
++ static std::string makeError(int ec)
++ {
++ std::string error("Error in packet, ");
++ error += snmp_errstring(ec);
++ return error;
++ }
++};
++
++} // namespace exception
++} // namespace snmp
+diff --git a/snmp/notify_tables.hpp b/snmp/notify_tables.hpp
+new file mode 100644
+index 0000000..7d23c0f
+--- /dev/null
++++ b/snmp/notify_tables.hpp
+@@ -0,0 +1,58 @@
++/*
++ * SPDX-License-Identifier: Apache-2.0
++ * Copyright (C) 2021 YADRO.
++ */
++#include "oid.hpp"
++
++namespace snmp
++{
++namespace table
++{
++
++/**
++ * @brief SNMP-NOTIFICATION-MIB::snmpNotifyTable fields
++ */
++namespace notify
++{
++ // clang-format off
++static const snmp::OID tag = {1,3,6,1,6,3,13,1,1,1,2};
++static const snmp::OID type = {1,3,6,1,6,3,13,1,1,1,3};
++static const snmp::OID storageType = {1,3,6,1,6,3,13,1,1,1,4};
++static const snmp::OID rowStatus = {1,3,6,1,6,3,13,1,1,1,5};
++ // clang-format on
++} // namespace notify
++
++/**
++ * @brief SNMP-TARGET-MIB::snmpTargetParamsTable fields
++ */
++namespace targetParams
++{
++ // clang-format off
++static const snmp::OID mpModel = {1,3,6,1,6,3,12,1,3,1,2};
++static const snmp::OID securityModel = {1,3,6,1,6,3,12,1,3,1,3};
++static const snmp::OID securityName = {1,3,6,1,6,3,12,1,3,1,4};
++static const snmp::OID securityLevel = {1,3,6,1,6,3,12,1,3,1,5};
++static const snmp::OID storageType = {1,3,6,1,6,3,12,1,3,1,6};
++static const snmp::OID rowStatus = {1,3,6,1,6,3,12,1,3,1,7};
++ // clang-format on
++} // namespace targetParams
++
++/**
++ * @brief SNMP-TARGET-MIB::snmpTargetAddrTable fields
++ */
++namespace targetAddr
++{
++ // clang-format off
++static const snmp::OID tDomain = {1,3,6,1,6,3,12,1,2,1,2};
++static const snmp::OID tAddress = {1,3,6,1,6,3,12,1,2,1,3};
++static const snmp::OID timeout = {1,3,6,1,6,3,12,1,2,1,4};
++static const snmp::OID retryCount = {1,3,6,1,6,3,12,1,2,1,5};
++static const snmp::OID tagList = {1,3,6,1,6,3,12,1,2,1,6};
++static const snmp::OID params = {1,3,6,1,6,3,12,1,2,1,7};
++static const snmp::OID storageType = {1,3,6,1,6,3,12,1,2,1,8};
++static const snmp::OID rowStatus = {1,3,6,1,6,3,12,1,2,1,9};
++ // clang-format on
++} // namespace targetAddr
++
++} // namespace table
++} // namespace snmp
+diff --git a/snmp/oid.hpp b/snmp/oid.hpp
+new file mode 100644
+index 0000000..5394873
+--- /dev/null
++++ b/snmp/oid.hpp
+@@ -0,0 +1,42 @@
++#pragma once
++
++#include <net-snmp/net-snmp-config.h>
++#include <net-snmp/net-snmp-includes.h>
++
++#include <string>
++#include <vector>
++
++namespace snmp
++{
++
++struct OID : public std::vector<oid>
++{
++ using std::vector<oid>::vector;
++
++ static std::string dump(const oid* objid, const size_t length)
++ {
++ std::string ret(length * 11 + 1, '\0');
++ size_t offset = 0;
++ for (size_t i = 0; i < length; ++i)
++ {
++ offset += snprintf(ret.data() + offset, ret.size() - offset, ".%lu",
++ objid[i]);
++ }
++ ret.resize(offset);
++ return std::forward<std::string>(ret);
++ }
++
++ std::string dump() const
++ {
++ return std::forward<std::string>(dump(data(), size()));
++ }
++
++ template <typename T> OID operator+(const T& tail) const
++ {
++ OID res = *this;
++ res.insert(res.end(), tail.begin(), tail.end());
++ return std::forward<OID>(res);
++ }
++};
++
++} // namespace snmp
+diff --git a/snmp/pdu.hpp b/snmp/pdu.hpp
+new file mode 100644
+index 0000000..5487da0
+--- /dev/null
++++ b/snmp/pdu.hpp
+@@ -0,0 +1,150 @@
++#pragma once
++
++#include "oid.hpp"
++
++#include <net-snmp/net-snmp-config.h>
++#include <net-snmp/net-snmp-includes.h>
++
++#include <iterator>
++#include <memory>
++
++namespace snmp
++{
++
++class session;
++
++namespace details
++{
++
++struct PduDeleter
++{
++ void operator()(netsnmp_pdu* pduPtr) const
++ {
++ snmp_free_pdu(pduPtr);
++ }
++};
++
++using PduPtr = std::unique_ptr<netsnmp_pdu, PduDeleter>;
++} // namespace details
++
++class pdu
++{
++ public:
++ pdu() = delete;
++ pdu(const pdu&) = delete;
++ pdu& operator=(const pdu&) = delete;
++
++ pdu(pdu&&) = default;
++ pdu& operator=(pdu&&) = default;
++ ~pdu() = default;
++
++ netsnmp_pdu* get() const
++ {
++ return pduPtr.get();
++ }
++
++ static pdu create(const int command)
++ {
++ return std::forward<pdu>(pdu(snmp_pdu_create(command)));
++ }
++
++ void addVar(const OID& oid)
++ {
++ snmp_add_null_var(pduPtr.get(), oid.data(), oid.size());
++ }
++
++ void addVar(const OID& oid, const int& value)
++ {
++ snmp_pdu_add_variable(pduPtr.get(), oid.data(), oid.size(), ASN_INTEGER,
++ &value, sizeof(value));
++ }
++
++ void addVar(const OID& oid, const std::string& value)
++ {
++ snmp_pdu_add_variable(pduPtr.get(), oid.data(), oid.size(),
++ ASN_OCTET_STR, value.c_str(), value.size());
++ }
++
++ void addVar(const OID& oid, const OID& value)
++ {
++ snmp_pdu_add_variable(pduPtr.get(), oid.data(), oid.size(),
++ ASN_OBJECT_ID, value.data(),
++ value.size() * sizeof(OID::value_type));
++ }
++
++ void addVar(const OID& oid, const std::vector<uint8_t>& value)
++ {
++ snmp_pdu_add_variable(pduPtr.get(), oid.data(), oid.size(),
++ ASN_OCTET_STR, value.data(), value.size());
++ }
++
++ netsnmp_pdu* operator->() const
++ {
++ return pduPtr.get();
++ }
++
++ struct iterator
++ {
++ using value_type = netsnmp_variable_list;
++ using reference = netsnmp_variable_list&;
++ using pointer = netsnmp_variable_list*;
++ using iterator_category = std::forward_iterator_tag;
++
++ iterator(netsnmp_variable_list* vp) : vp(vp)
++ {
++ }
++
++ reference operator*()
++ {
++ return *vp;
++ }
++
++ pointer operator->()
++ {
++ return vp;
++ }
++
++ iterator& operator++()
++ {
++ vp = vp->next_variable;
++ return *this;
++ }
++
++ friend bool operator==(const iterator& a, const iterator& b)
++ {
++ return a.vp == b.vp;
++ };
++ friend bool operator!=(const iterator& a, const iterator& b)
++ {
++ return a.vp != b.vp;
++ };
++
++ private:
++ pointer vp;
++ };
++
++ iterator begin() const
++ {
++ return iterator(pduPtr->variables);
++ }
++ iterator end() const
++ {
++ return iterator(nullptr);
++ }
++
++ protected:
++ explicit pdu(netsnmp_pdu* rawPtr) : pduPtr(rawPtr)
++ {
++ if (pduPtr->command == SNMP_MSG_GETBULK)
++ {
++ pduPtr->non_repeaters = 0;
++ pduPtr->max_repetitions = 10;
++ }
++ }
++
++ private:
++ friend class snmp::session;
++ details::PduPtr pduPtr;
++};
++
++} // namespace snmp
+diff --git a/snmp/session.hpp b/snmp/session.hpp
+new file mode 100644
+index 0000000..6665882
+--- /dev/null
++++ b/snmp/session.hpp
+@@ -0,0 +1,110 @@
++#pragma once
++
++#include "exceptions.hpp"
++#include "pdu.hpp"
++
++#include <net-snmp/net-snmp-config.h>
++#include <net-snmp/net-snmp-includes.h>
++
++#include <memory>
++#include <string>
++
++namespace snmp
++{
++
++namespace details
++{
++
++struct SessionDeleter
++{
++ void operator()(netsnmp_session* sessionPtr) const
++ {
++ snmp_close(sessionPtr);
++ }
++};
++
++using SessionPtr = std::unique_ptr<netsnmp_session, SessionDeleter>;
++
++} // namespace details
++
++class session
++{
++ public:
++ session() = delete;
++ session(const session&) = delete;
++ session& operator=(const session&) = delete;
++
++ session(session&&) = default;
++ session& operator=(session&&) = default;
++ ~session() = default;
++
++ netsnmp_session* get() const
++ {
++ return sessionPtr.get();
++ }
++
++ static session open(const std::string& peername,
++ const std::string& community,
++ const int version = SNMP_VERSION_2c,
++ const int retryAttempts = 3,
++ const int timeout = 1000000)
++ {
++ netsnmp_session ss{};
++
++ snmp_sess_init(&ss);
++ ss.version = version;
++ ss.retries = retryAttempts;
++ ss.timeout = timeout;
++ ss.peername = const_cast<char*>(peername.c_str());
++ ss.community = const_cast<u_char*>(
++ reinterpret_cast<const u_char*>(community.c_str()));
++ ss.community_len = community.size();
++
++ netsnmp_session* sp = snmp_open(&ss);
++
++ if (!sp)
++ {
++ throw snmp::exception::SnmpSessionError(&ss, "snmp_open()");
++ }
++
++ return std::forward<session>(session(sp));
++ }
++
++ void send(pdu& pdu) const
++ {
++ netsnmp_pdu* rsp = nullptr;
++ auto status = snmp_synch_response(sessionPtr.get(), pdu.get(), &rsp);
++ pdu.pduPtr.release();
++ pdu.pduPtr.reset(rsp);
++
++ switch (status)
++ {
++ case STAT_TIMEOUT:
++ throw snmp::exception::SnmpTimeout();
++ break;
++
++ case STAT_ERROR:
++ throw snmp::exception::SnmpSessionError(
++ sessionPtr.get(), "snmp_synch_response()");
++ break;
++
++ default:
++ break;
++ }
++
++ if (pdu->errstat != SNMP_ERR_NOERROR)
++ {
++ throw snmp::exception::SnmpPacketError(pdu->errstat);
++ }
++ }
++
++ protected:
++ explicit session(netsnmp_session* sp) : sessionPtr(sp)
++ {
++ }
++
++ private:
++ details::SessionPtr sessionPtr;
++};
++
++} // namespace snmp
+diff --git a/snmp_conf_manager.cpp b/snmp_conf_manager.cpp
+index 4ddace1..2a631b7 100644
+--- a/snmp_conf_manager.cpp
++++ b/snmp_conf_manager.cpp
+@@ -6,6 +6,11 @@
+ #include "snmp_util.hpp"
+ #include "xyz/openbmc_project/Common/error.hpp"
+
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++#include "snmp/pdu.hpp"
++#include "snmp/notify_tables.hpp"
++#endif
++
+ #include <arpa/inet.h>
+
+ #include <phosphor-logging/elog-errors.hpp>
+@@ -29,14 +34,97 @@ ConfManager::ConfManager(sdbusplus::bus::bus& bus, const char* objPath) :
+ details::CreateIface::action::defer_emit),
+ dbusPersistentLocation(SNMP_CONF_PERSIST_PATH), bus(bus),
+ objectPath(objPath)
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++ ,
++ session(::snmp::session::open(SNMPD_ADDRESS, SNMPD_COMMUNITY))
++#endif
+ {}
+
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++static std::vector<uint8_t> encodeAddr(const std::string& addr, uint16_t port)
++{
++ std::vector<uint8_t> data;
++
++ addrinfo hints;
++ addrinfo* ptr = nullptr;
++
++ memset(&hints, 0, sizeof hints);
++ hints.ai_family = AF_UNSPEC;
++ hints.ai_socktype = SOCK_STREAM;
++ hints.ai_flags |= AI_CANONNAME;
++
++ auto result =
++ getaddrinfo(addr.c_str(), std::to_string(port).c_str(), &hints, &ptr);
++ if (result)
++ {
++ log<level::ERR>("getaddrinfo failed",
++ entry("ADDRESS=%s", addr.c_str()));
++ elog<InternalFailure>();
++ }
++
++ AddrPtr addrPtr{ptr};
++ ptr = nullptr;
++
++ auto sa = reinterpret_cast<const sockaddr_in*>(addrPtr->ai_addr);
++ auto begin = reinterpret_cast<const uint8_t*>(&(sa->sin_addr));
++ data.insert(data.end(), begin, begin + sizeof(sa->sin_addr));
++
++ begin = reinterpret_cast<const uint8_t*>(&(sa->sin_port));
++ data.insert(data.end(), begin, begin + sizeof(sa->sin_port));
++
++ return data;
++}
++#endif
++
+ std::string ConfManager::client(std::string address, uint16_t port)
+ {
+ // will throw exception if it is already configured.
+ checkClientConfigured(address, port);
+
+ lastClientId++;
++
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++ auto data = encodeAddr(address, port);
++ try
++ {
++ auto pdu = ::snmp::pdu::create(SNMP_MSG_SET);
++ auto index = std::to_string(lastClientId);
++
++ constexpr int noAuthNoPriv = 1;
++ constexpr int createAndGo = 4;
++
++ using namespace ::snmp::table;
++
++ pdu.addVar(targetParams::mpModel + index, 1 /* SNMPv2c */);
++ pdu.addVar(targetParams::securityModel + index, 2 /* SNMPv2c */);
++ pdu.addVar(targetParams::securityName + index, "public");
++ pdu.addVar(targetParams::securityLevel + index, noAuthNoPriv);
++ pdu.addVar(targetParams::rowStatus + index, createAndGo);
++
++ const ::snmp::OID snmpUDPDomain = {1, 3, 6, 1, 6, 1, 1};
++
++ pdu.addVar(targetAddr::tDomain + index, snmpUDPDomain);
++ pdu.addVar(targetAddr::tAddress + index, data);
++ pdu.addVar(targetAddr::tagList + index, index);
++ pdu.addVar(targetAddr::params + index, index);
++ pdu.addVar(targetAddr::rowStatus + index, createAndGo);
++
++ constexpr int trap = 1;
++
++ pdu.addVar(notify::tag + index, index);
++ pdu.addVar(notify::type + index, trap);
++ pdu.addVar(notify::rowStatus + index, createAndGo);
++
++ session.send(pdu);
++ }
++ catch (const ::snmp::exception::SnmpError& ex)
++ {
++ log<level::ERR>("Sending client data to snmpd failed",
++ entry("ERROR=%s", ex.what()),
++ entry("ADDRESS=%s", address.c_str()));
++ elog<InternalFailure>();
++ }
++#else
+ try
+ {
+ // just to check whether given address is valid or not.
+@@ -48,6 +136,7 @@ std::string ConfManager::client(std::string address, uint16_t port)
+ elog<InvalidArgument>(Argument::ARGUMENT_NAME("Address"),
+ Argument::ARGUMENT_VALUE(address.c_str()));
+ }
++#endif
+
+ // create the D-Bus object
+ std::filesystem::path objPath;
+@@ -57,8 +146,10 @@ std::string ConfManager::client(std::string address, uint16_t port)
+ auto client = std::make_unique<phosphor::network::snmp::Client>(
+ bus, objPath.string().c_str(), *this, address, port);
+
++#if ! defined( USE_SNMPD ) || ( USE_SNMPD == 0 )
+ // save the D-Bus object
+ serialize(lastClientId, *client, dbusPersistentLocation);
++#endif
+
+ this->clients.emplace(lastClientId, std::move(client));
+ return objPath.string();
+@@ -98,6 +189,27 @@ void ConfManager::deleteSNMPClient(Id id)
+ return;
+ }
+
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++ try
++ {
++ using namespace ::snmp::table;
++
++ constexpr int destroy = 6;
++ auto pdu = ::snmp::pdu::create(SNMP_MSG_SET);
++ auto index = std::to_string(id);
++ pdu.addVar(notify::rowStatus + index, destroy);
++ pdu.addVar(targetAddr::rowStatus + index, destroy);
++ pdu.addVar(targetParams::rowStatus + index, destroy);
++ session.send(pdu);
++ }
++ catch (const ::snmp::exception::SnmpError& ex)
++ {
++ log<level::ERR>("Deleting client data from snmpd failed",
++ entry("ERROR=%s", ex.what()),
++ entry("CLIENT_UD=%zu", id));
++ elog<InternalFailure>();
++ }
++#else
+ std::error_code ec;
+ // remove the persistent file
+ fs::path fileName = dbusPersistentLocation;
+@@ -115,12 +227,106 @@ void ConfManager::deleteSNMPClient(Id id)
+ {
+ lg2::error("{FILE} doesn't exist", "FILE", fileName);
+ }
++#endif
++
+ // remove the D-Bus Object.
+ this->clients.erase(it);
+ }
+
+ void ConfManager::restoreClients()
+ {
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++ using SnmpClient = std::tuple<std::string, uint16_t>;
++ using SnmpClients = std::map<Id, SnmpClient>;
++ SnmpClients snmpClients;
++
++ try
++ {
++ using namespace ::snmp::table;
++ auto root = targetAddr::tAddress;
++
++ while (!root.empty())
++ {
++ auto pdu = ::snmp::pdu::create(SNMP_MSG_GETBULK);
++ pdu.addVar(root);
++ session.send(pdu);
++
++ for (const auto& var : pdu)
++ {
++ if (var.name_length <= targetAddr::tAddress.size() ||
++ !std::equal(targetAddr::tAddress.begin(),
++ targetAddr::tAddress.end(), var.name))
++ {
++ // End of table reached.
++ root.clear();
++ break;
++ }
++
++ std::string index(var.name + targetAddr::tAddress.size(),
++ var.name + var.name_length);
++ Id idNum = std::stol(index);
++
++ char ipaddress[INET6_ADDRSTRLEN];
++ if (inet_ntop(AF_INET, var.val.string, ipaddress,
++ sizeof(ipaddress)))
++ {
++ auto& snmpClient = snmpClients[idNum];
++ std::get<0>(snmpClient) = ipaddress;
++ std::get<1>(snmpClient) =
++ ntohs(*(reinterpret_cast<uint16_t*>(
++ var.val.string + sizeof(in_addr_t))));
++ }
++
++ if (!var.next_variable)
++ {
++ // Following request should contain the last OID
++ root.assign(var.name, var.name + var.name_length);
++ }
++ }
++ }
++ }
++ catch (const ::snmp::exception::SnmpError& ex)
++ {
++ log<level::ERR>("Receiving list of clients from snmpd failed",
++ entry("ERROR=%s", ex.what()));
++ elog<InternalFailure>();
++ }
++
++ // Remove excess clients
++ for (auto it = clients.begin(); it != clients.end();)
++ {
++ auto snmpIt = snmpClients.find(it->first);
++ if (snmpIt == snmpClients.end())
++ {
++ it = clients.erase(it);
++ }
++ else
++ {
++ it++;
++ }
++ }
++
++ // Add missing clients
++ for (const auto& [id, snmpClient] : snmpClients)
++ {
++ auto it = clients.find(id);
++ if (it == clients.end())
++ {
++ fs::path objPath = objectPath;
++ objPath /= std::to_string(id);
++
++ auto client = std::make_unique<Client>(
++ bus, objPath.string().c_str(), *this, std::get<0>(snmpClient),
++ std::get<1>(snmpClient));
++ clients.emplace(id, std::move(client));
++
++ if (id > lastClientId)
++ {
++ lastClientId = id;
++ }
++ }
++ }
++#else
+ if (!fs::exists(dbusPersistentLocation) ||
+ fs::is_empty(dbusPersistentLocation))
+ {
+@@ -152,6 +358,7 @@ void ConfManager::restoreClients()
+ }
+ }
+ }
++#endif
+ }
+
+ } // namespace snmp
+diff --git a/snmp_conf_manager.hpp b/snmp_conf_manager.hpp
+index afbfad8..10ed4dd 100644
+--- a/snmp_conf_manager.hpp
++++ b/snmp_conf_manager.hpp
+@@ -1,6 +1,9 @@
+ #pragma once
+
+ #include "snmp_client.hpp"
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++#include "snmp/session.hpp"
++#endif
+
+ #include <sdbusplus/bus.hpp>
+ #include <xyz/openbmc_project/Network/Client/Create/server.hpp>
+@@ -84,6 +87,11 @@ class ConfManager : public details::CreateIface
+ /** @brief map of SNMP Client dbus objects and their ID */
+ ClientList clients;
+
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++ /** @brief SNMP client session */
++ ::snmp::session session;
++#endif
++
+ /** @brief Id of the last SNMP manager entry */
+ Id lastClientId = 0;
+
+diff --git a/snmp_main.cpp b/snmp_main.cpp
+index df5850b..d6e6646 100644
+--- a/snmp_main.cpp
++++ b/snmp_main.cpp
+@@ -42,5 +42,16 @@ int main(int /*argc*/, char** /*argv[]*/)
+ sdeventplus::source::Signal sigTerm(event, SIGTERM, cleanExit);
+ sdeventplus::source::Signal sigInt(event, SIGINT, cleanExit);
+
++#if defined( USE_SNMPD ) && ( USE_SNMPD == 1 )
++ // Reload list of clients
++ stdplus::signal::block(SIGHUP);
++ sdeventplus::source::Signal sigHup(
++ event, SIGHUP,
++ [&manager](sdeventplus::source::Signal&,
++ const struct signalfd_siginfo*) {
++ manager->restoreClients();
++ });
++#endif
++
+ return event.loop();
+ }
+--
+2.35.1
+
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/snmpd-dependency.conf b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/snmpd-dependency.conf
new file mode 100644
index 0000000000..1fcd359e10
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp/snmpd-dependency.conf
@@ -0,0 +1,3 @@
+[Unit]
+Requires=snmpd.service
+After=snmpd.service \ No newline at end of file
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp_%.bbappend b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp_%.bbappend
new file mode 100644
index 0000000000..a784b2510b
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/network/phosphor-snmp_%.bbappend
@@ -0,0 +1,23 @@
+FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
+
+SRC_URI += " \
+ file://0001-main-Use-sdeventplus.patch \
+ file://0002-main-Add-UNIX-signals-handler.patch \
+ file://0003-conf_manager-use-snmpd-as-a-clients-storage.patch \
+ file://snmpd-dependency.conf \
+ "
+
+EXTRA_OEMESON:append = " -Dsnmpd-support=enabled -Dsnmpd-address=localhost -Dsnmpd-community=private"
+
+DEPENDS += "sdeventplus"
+DEPENDS += "stdplus"
+
+RDEPENDS:${PN} += " \
+ net-snmp \
+ phosphor-logging \
+ phosphor-dbus-interfaces \
+ "
+
+SYSTEMD_OVERRIDE:${PN}:append = " \
+ snmpd-dependency.conf:xyz.openbmc_project.Network.SNMP.service.d/snmpd-dependency.conf \
+ "