ПРИЛОЖЕНИЕ 3
ПМ АУС
1. Основной файл кода ПМ АУС 3
2. Файл кода для консольного интерфейса ПМ АУС 14
Основополагающие фрагменты кода ПМ АУС:
#define _GNU_SOURCE
#include <unistd.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <assert.h>
#include <netinet/ether.h>
#include <net/ethernet.h>
#include <fcntl.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/link.h>
#include <event2/event.h>
#include <libubox/list.h>
#include </avl-cmp.h>
#include <libubox/avl.h>
#include <jansson.h>
#include <mstpd/ctl_functions.h>
#include <mstpd/mstp_ctl.h>
#include "linux-switch.h"
#define LSW_LOG_NAME "stp"
#include "log.h"
#define PORT_XPATH "/ietf-interfaces:interfaces/interface/" \
"ieee802-dot1q-bridge:bridge-port/angtel-stp:spanning-tree"
#define BRIDGE_XPATH "/ieee802-dot1q-bridge:bridges/bridge/component"
#define BRIDGE_STP_XPATH BRIDGE_XPATH"/angtel-stp:spanning-tree"
#ifndef GET_NUM_FROM_PRIO
#define GET_NUM_FROM_PRIO(p) (__be16_to_cpu(p) & 0x0FFF)
#endif
#define GET_BRIDGE_PRIO(p) (__be16_to_cpu(p) & 0xF000)
#ifndef SYSFS_PATH_MAX
#define SYSFS_PATH_MAX 256
#endif //SYSFS_PATH_MAX
#ifndef SYSFS_CLASS_NET
#define SYSFS_CLASS_NET "/sys/class/net"
#endif //SYSFS_CLASS_NET
#define STP_STATUS_POLL_PERIOD 3 /* 3 seconds */
enum rcv_data_type {
CTL_MESSAGE,
BRIDGE_DATA,
PORT_DATA
};
struct rcv_data {
enum rcv_data_type type;
union {
struct stp_port *port;
struct stp_bridge *br;
};
bool wait;
};
enum return_codes {
RC_OK = 0,
RC_FATAL = -1,
RC_SOCK_ERR = -2,
};
struct stp_port {
char *name;
struct avl_node entry;
bool deleted;
struct {
CIST_PortStatus portstat;
bool obsolete;
bool status_changed;
bool status_in_db;
bool counters_changed;
bool counters_in_db;
} status;
struct {
bool enable;
bool enable_changed;
struct stp_bridge *br;
bool admin_edge_port;
bool auto_edge_port;
CIST_PortConfig cist;
bool cist_changed;
MSTI_PortConfig msti;
bool msti_changed;
} conf;
};
struct stp_bridge {
char *name;
struct avl_node entry;
bool applied;
bool deleted;
struct {
CIST_BridgeStatus bridgestat;
bool obsolete;
bool changed;
bool in_database;
} status;
struct {
bool enable;
bool enable_changed;
uint8_t bridge_priority;
bool bridge_priority_changed;
CIST_BridgeConfig bridgeconf;
bool bridgeconf_changed;
} conf;
};
struct stp_priv {
struct lsw_module *mod;
evutil_socket_t fd;
struct event *connect_event;
struct event *read_event;
struct event *set_config_event;
struct event *status_poll_timer;
struct avl_tree bridges;
struct avl_tree ports;
bool mstpd_is_on;
bool set_config;
bool get_status;
bool status_changed;
bool pending_deletions;
struct rcv_data rcv_data;
struct nl_cache *nl_cache;
struct {
int cmd;
int lin;
int lout;
} send_recv_params;
};
static int connect_to_daemon(struct stp_priv *stp);
static char *mac_to_str(const uint8_t mac[6])
{
struct ether_addr e = {0};
memcpy(e.ether_addr_octet, mac, 6*sizeof(uint8_t));
return strdup(ether_ntoa(&e));
}
static inline int get_index(struct nl_cache *nl_cache, const char *ifname)
{
return rtnl_link_name2i(nl_cache, ifname);
}
static int send_ctl_message(struct stp_priv *stp, void *inbuf)
{
int cmd = stp->send_recv_params.cmd;
int lin = stp->send_recv_params.lin;
int lout = stp->send_recv_params.lout;
struct ctl_msg_hdr mhdr;
struct msghdr msg;
struct iovec iov[3];
int l;
LogString logs = { .buf = "" };
LogString *log = &logs;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 3;
msg.msg_control = NULL;
msg.msg_controllen = 0;
mhdr.cmd = cmd;
mhdr.lin = lin;
mhdr.lout = lout;
mhdr.llog = sizeof(log->buf) - 1;
iov[0].iov_base = &mhdr;
iov[0].iov_len = sizeof(mhdr);
iov[1].iov_base = (void *)inbuf;
iov[1].iov_len = lin;
iov[2].iov_base = log->buf;
iov[2].iov_len = 0;
l = sendmsg(stp->fd, &msg, 0);
if (0 > l) {
DLOG_ERR("Error sending message to server: %m");
return RC_SOCK_ERR;
}
if (l != sizeof(mhdr) + lin) {
DLOG_ERR("Error sending message to server: Partial write");
return RC_SOCK_ERR;
}
return RC_OK;
}
static int recv_ctl_message(struct stp_priv *stp, void *outbuf)
{
int cmd = stp->send_recv_params.cmd;
int lin = stp->send_recv_params.lin;
int lout = stp->send_recv_params.lout;
struct ctl_msg_hdr mhdr;
struct msghdr msg;
struct iovec iov[3];
int l;
LogString logs = { .buf = "" };
LogString *log = &logs;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = iov;
msg.msg_iovlen = 3;
msg.msg_control = NULL;
msg.msg_controllen = 0;
mhdr.cmd = cmd;
mhdr.lin = lin;
mhdr.lout = lout;
mhdr.llog = sizeof(log->buf) - 1;
iov[0].iov_base = &mhdr;
iov[0].iov_len = sizeof(mhdr);
iov[1].iov_base = outbuf;
iov[1].iov_len = lout;
iov[2].iov_base = log->buf;
iov[2].iov_len = sizeof(log->buf);
l = recvmsg(stp->fd, &msg, 0);
if (0 >= l) {
DLOG_ERR("Error getting message from server: %m");
return RC_SOCK_ERR;
}
if ((sizeof(mhdr) > l)
|| (l != sizeof(mhdr) + mhdr.lout + mhdr.llog)
|| (mhdr.cmd != cmd)
) {
DLOG_ERR("Error getting message from server: Bad format");
return RC_FATAL;
}
if (mhdr.lout != lout) {
DLOG_ERR("Error, unexpected result length %d, expected %d\n",
mhdr.lout, lout);
return RC_FATAL;
}
if (sizeof(log->buf) <= mhdr.llog) {
DLOG_ERR("Invalid log message length %d", mhdr.llog);
return RC_FATAL;
}
if (mhdr.res) {
if (mhdr.llog != 0) {
log->buf[mhdr.llog] = 0;
DLOG_FUNC(STDLOG_ERR, "%s", log->buf);
} else {
DLOG(STDLOG_ERR, "Error receiving ctl message response");
}
return RC_FATAL;
}
return RC_OK;
}
static int not_dot_dotdot(const struct dirent *entry)
{
const char *n = entry->d_name;
return !('.' == n[0] && (0 == n[1] || ('.' == n[1] && 0 == n[2])));
}
static int get_port_list(const char *br_ifname, struct dirent ***namelist)
{
int res;
char buf[SYSFS_PATH_MAX];
snprintf(buf, sizeof(buf), SYSFS_CLASS_NET "/%.230s/brif", br_ifname);
if (0 > (res = scandir(buf, namelist, not_dot_dotdot, versionsort)))
DLOG_FUNC(STDLOG_ERR, "Error getting list of all ports of bridge %s", br_ifname);
return res;
}
static int _CTL_set_cist_bridge_config(struct stp_priv *stp, int br_index, CIST_BridgeConfig *cfg)
{
struct set_cist_bridge_config_IN in0, *in = &in0;
in->br_index = br_index;
in->cfg = *cfg;
stp->send_recv_params.cmd = CMD_CODE_set_cist_bridge_config;
stp->send_recv_params.lin = sizeof(*in);
stp->send_recv_params.lout = 0;
return send_ctl_message(stp, in);
}
static int _CTL_set_msti_bridge_config(struct stp_priv *stp,
int br_index,
__u16 mstid,
__u8 bridge_priority)
{
struct set_msti_bridge_config_IN in0, *in = &in0;
in->br_index = br_index;
in->mstid = mstid;
in->bridge_priority = bridge_priority;
stp->send_recv_params.cmd = CMD_CODE_set_msti_bridge_config;
stp->send_recv_params.lin = sizeof(*in);
stp->send_recv_params.lout = 0;
return send_ctl_message(stp, in);
}
static int _CTL_set_cist_port_config(struct stp_priv *stp,
int br_index,
int port_index,
CIST_PortConfig *cfg)
{
struct set_cist_port_config_IN in0, *in = &in0;
in->br_index = br_index;
in->port_index = port_index;
in->cfg = *cfg;
stp->send_recv_params.cmd = CMD_CODE_set_cist_port_config;
stp->send_recv_params.lin = sizeof(*in);
stp->send_recv_params.lout = 0;
return send_ctl_message(stp, in);
}
static int _CTL_set_msti_port_config(struct stp_priv *stp,
int br_index,
int port_index,
__u16 mstid,
MSTI_PortConfig *cfg)
{
struct set_msti_port_config_IN in0, *in = &in0;
in->br_index = br_index;
in->port_index = port_index;
in->mstid = mstid;
in->cfg = *cfg;
stp->send_recv_params.cmd = CMD_CODE_set_msti_port_config;
stp->send_recv_params.lin = sizeof(*in);
stp->send_recv_params.lout = 0;
return send_ctl_message(stp, in);
}
static int _CTL_get_cist_bridge_status(struct stp_priv *stp, int br_index)
{
struct get_cist_bridge_status_IN in0, *in = &in0;
in->br_index = br_index;
stp->send_recv_params.cmd = CMD_CODE_get_cist_bridge_status;
stp->send_recv_params.lin = sizeof(*in);
stp->send_recv_params.lout = sizeof(struct get_cist_bridge_status_OUT);
return send_ctl_message(stp, in);
}
static int _CTL_get_cist_port_status(struct stp_priv *stp, int br_index, int port_index)
{
struct get_cist_port_status_IN in0, *in = &in0;
in->br_index = br_index;
in->port_index = port_index;
stp->send_recv_params.cmd = CMD_CODE_get_cist_port_status;
stp->send_recv_params.lin = sizeof(*in);
stp->send_recv_params.lout = sizeof(struct get_cist_port_status_OUT);
return send_ctl_message(stp, in);
}
local c = require('cdb_cli')
local mod = {}
local function get_iface_compl(s)
local t = {}
for k, v in pairs(s["stp_br_ports"]) do
table.insert(t, v["name"])
end
return t
end
local function get_port_id(port_prio, port_num, pad)
if not port_prio or not port_num then
return nil
end
local s = ""
if pad == -math.huge then pad = nil end
if pad then s = "0" .. tostring(pad) end
return ("%d.%" .. s .. "d"):format(port_prio, port_num)
end
local switch_commands = {
["spanning-tree"] = {
description = "Enable spanning tree protocol",
usage_info = "",
handler = function(s, args)
local p = {
operation = "replace",
target = "/ieee802-dot1q-bridge:bridges/bridge[name='br0']/" ..
"component[name='angtel-component']/" ..
"angtel-stp:spanning-tree/enable",
value = {
enable = true
}
}
s:cdb_edit_config(p)
end
},
["spanning-tree forward-time"] = {
description = "Configure the spanning-tree bridge forward time",
usage_info = "seconds",
parameters = {
"seconds\tSpecifies the forward time in seconds. Range: 4-30. Default is 15.\n"
},
args = {
{
type = "positional",
name = "forward-time",
vtype = "int",
nvalues = "1",
description = "Forward time in seconds",
required = true
}
},
handler = function(s, args)
local max_age = c.strip_cdb_data(s:cdb_get("/ieee802-dot1q-bridge:bridges/bridge[name='br0']/" ..
"component[name='angtel-component']/angtel-stp:spanning-tree/max-age"))
if 2*(args["forward-time"] - 1) < max_age[1] then
s:output("Wrong value! 2 * (Bridge Forward Delay - 1 second) must be >= Bridge Max Age")
return
end
local p = {
operation = "replace",
target = "/ieee802-dot1q-bridge:bridges/bridge[name='br0']/" ..
"component[name='angtel-component']/" ..
"angtel-stp:spanning-tree/forwarding-delay",
value = {
["forwarding-delay"] = args["forward-time"]
}
}
s:cdb_edit_config(p)
end
},
["spanning-tree max-age"] = {
description = "Configure the STP maximum age",
usage_info = "max-age",
parameters = {
"max-age\tSpecifies the bridge maximum age in seconds. Range: 6-40. Default is 20.\n"
},
args = {
{
type = "positional",
name = "max-age",
vtype = "int",
nvalues = "1",
description = "Maximum age in seconds",
required = true
}
},
handler = function(s, args)
local fwd = c.strip_cdb_data(s:cdb_get("/ieee802-dot1q-bridge:bridges/bridge[name='br0']/" ..