mirror of
https://github.com/Telecominfraproject/ols-ucentral-client.git
synced 2026-03-20 03:39:28 +00:00
Compare commits
189 Commits
next
...
larch-plat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa325f283a | ||
|
|
ff381be8b5 | ||
|
|
e3ae4b0324 | ||
|
|
0a0820e169 | ||
|
|
2bc20dab60 | ||
|
|
22781547a1 | ||
|
|
dc80301aee | ||
|
|
cfcbc2b724 | ||
|
|
ece8a6833f | ||
|
|
1d3f947f89 | ||
|
|
98abb522eb | ||
|
|
1599ecceeb | ||
|
|
708b753f70 | ||
|
|
c03231213d | ||
|
|
7a9d2b19df | ||
|
|
7fc85d481c | ||
|
|
5180f1e9da | ||
|
|
caef6ad4c3 | ||
|
|
57595fa5ae | ||
|
|
82cec0550a | ||
|
|
8205ee7a0a | ||
|
|
43fd03ebb7 | ||
|
|
6d46db300d | ||
|
|
4d8ca0d9eb | ||
|
|
fc1fecbb29 | ||
|
|
abee1977fc | ||
|
|
bf1ca8fe89 | ||
|
|
f8c61adac1 | ||
|
|
1ac8d8cfa8 | ||
|
|
2bc70cc145 | ||
|
|
f6a56a6a57 | ||
|
|
7b4947508d | ||
|
|
f6bfadad3e | ||
|
|
ddba3d5652 | ||
|
|
565a32fe74 | ||
|
|
2c367ed818 | ||
|
|
3c9f3c56cf | ||
|
|
d4efe7e596 | ||
|
|
ea5edeaa60 | ||
|
|
9f28fa135f | ||
|
|
0667d9e4bd | ||
|
|
ec69be8141 | ||
|
|
bd52b8b658 | ||
|
|
0bc7d0a373 | ||
|
|
9a76bfadff | ||
|
|
f8b293dbb8 | ||
|
|
b2b24f8e07 | ||
|
|
1cc4e44a19 | ||
|
|
2102f4e3c4 | ||
|
|
3621e48411 | ||
|
|
6080da5a05 | ||
|
|
6a5f77f6fc | ||
|
|
bd31fdef3e | ||
|
|
0aee7a3c74 | ||
|
|
f1ffaedf0a | ||
|
|
e53ccaf9b7 | ||
|
|
dffe061778 | ||
|
|
1b869b9d9d | ||
|
|
5aacf9a82d | ||
|
|
7da9ce52d4 | ||
|
|
4536be8e09 | ||
|
|
3a8dd3666a | ||
|
|
c1d128a64b | ||
|
|
7265aa1e70 | ||
|
|
570b2ff1cc | ||
|
|
72fa3f794e | ||
|
|
7120faa622 | ||
|
|
afda76f04d | ||
|
|
c482e56767 | ||
|
|
0ad4d6e0ef | ||
|
|
38edc8b513 | ||
|
|
c01e0a08ed | ||
|
|
ce744a589b | ||
|
|
3f14c324a0 | ||
|
|
fc646e5daf | ||
|
|
d5291ec1cc | ||
|
|
9e2abdcd35 | ||
|
|
f4e37d67e5 | ||
|
|
54b15ebbc8 | ||
|
|
11caedb29c | ||
|
|
9b6c77a6dc | ||
|
|
25b95decbb | ||
|
|
7b20f06aef | ||
|
|
93360f91ac | ||
|
|
6642f0b060 | ||
|
|
5ffa368c60 | ||
|
|
af365a7479 | ||
|
|
f53624d25a | ||
|
|
74bcf8604a | ||
|
|
39b58f3faf | ||
|
|
c7c038f04b | ||
|
|
0137a3e87a | ||
|
|
3c5cd07084 | ||
|
|
2a96865f52 | ||
|
|
69dab0a2fc | ||
|
|
22ed337904 | ||
|
|
afd6e10a14 | ||
|
|
9f83e79568 | ||
|
|
c88fa3515a | ||
|
|
fb4bdd5cf4 | ||
|
|
78cc463fe9 | ||
|
|
14073ecb83 | ||
|
|
cac8e861ab | ||
|
|
af79b86980 | ||
|
|
51dab835bc | ||
|
|
31cd55935f | ||
|
|
ed64b97bf2 | ||
|
|
dda06db648 | ||
|
|
4feb498fa0 | ||
|
|
83f9155f4c | ||
|
|
088f12dd89 | ||
|
|
99b0f6b797 | ||
|
|
caf9199379 | ||
|
|
2a8e2338bf | ||
|
|
2537609e91 | ||
|
|
40f3f78a72 | ||
|
|
ddd8b96c19 | ||
|
|
a4398e8588 | ||
|
|
88aed5461d | ||
|
|
c0f92db209 | ||
|
|
58d32190a8 | ||
|
|
0d7a532f53 | ||
|
|
9ba671834d | ||
|
|
5936fbed88 | ||
|
|
0aea2e273c | ||
|
|
6e8ccbf40c | ||
|
|
80f01f977c | ||
|
|
145f8aba82 | ||
|
|
e53d618a33 | ||
|
|
0799cec723 | ||
|
|
24143fc5bc | ||
|
|
15b9868322 | ||
|
|
54141e0af6 | ||
|
|
9034123c2e | ||
|
|
d0189eaad6 | ||
|
|
c349f3f9a4 | ||
|
|
5832ecdf36 | ||
|
|
4911cab05e | ||
|
|
7442bb79c3 | ||
|
|
f972987312 | ||
|
|
783368dd7b | ||
|
|
dc60bab84b | ||
|
|
681efcabfc | ||
|
|
6f6bd4dfd0 | ||
|
|
04e80e1650 | ||
|
|
a8e2b18733 | ||
|
|
2e5499c375 | ||
|
|
0f64807cfb | ||
|
|
215d4dab4a | ||
|
|
e13a8fac52 | ||
|
|
049fef08d9 | ||
|
|
2bd145e09f | ||
|
|
732b4e1bc7 | ||
|
|
559776ba06 | ||
|
|
b6c03319d3 | ||
|
|
05d06592cc | ||
|
|
ebf160fa06 | ||
|
|
ace64ef341 | ||
|
|
5acd35237c | ||
|
|
d9fae8097b | ||
|
|
ee4ff0ee3a | ||
|
|
6efdcb7eb5 | ||
|
|
bca8160f67 | ||
|
|
3d2b3295e7 | ||
|
|
15e4f7a580 | ||
|
|
1afbc126fe | ||
|
|
a2c49e8ab5 | ||
|
|
2a8d2c18ce | ||
|
|
4549ef61c3 | ||
|
|
5710119746 | ||
|
|
cedf998260 | ||
|
|
963120f2b4 | ||
|
|
8b4a63fb66 | ||
|
|
60abb9a7e6 | ||
|
|
0b683379b4 | ||
|
|
a328cd6b7a | ||
|
|
7afff76db1 | ||
|
|
0d9af851b4 | ||
|
|
b8c952cf1c | ||
|
|
8636487247 | ||
|
|
ac20c4c276 | ||
|
|
ee4b0ca66b | ||
|
|
977c651079 | ||
|
|
3beb5f314b | ||
|
|
a84bfa8e04 | ||
|
|
289c74a81d | ||
|
|
be1138ebc6 | ||
|
|
764e9f93ab | ||
|
|
12117ebfc8 |
@@ -1,4 +1,4 @@
|
||||
FROM debian:buster
|
||||
FROM arm64v8/debian:buster
|
||||
LABEL Description="Ucentral client (Build) environment"
|
||||
|
||||
ARG HOME /root
|
||||
@@ -15,13 +15,16 @@ RUN apt-get update -q -y && apt-get -q -y --no-install-recommends install \
|
||||
libcurl4-openssl-dev \
|
||||
libev-dev \
|
||||
libssl-dev \
|
||||
libnl-route-3-dev \
|
||||
libnl-3-dev \
|
||||
apt-utils \
|
||||
git \
|
||||
wget \
|
||||
autoconf \
|
||||
libtool \
|
||||
pkg-config \
|
||||
libjsoncpp-dev
|
||||
libjsoncpp-dev \
|
||||
libhiredis-dev
|
||||
|
||||
RUN git config --global http.sslverify false
|
||||
RUN git clone https://github.com/DaveGamble/cJSON.git ${HOME}/ucentral-external-libs/cJSON/
|
||||
|
||||
28
LICENSE
Normal file
28
LICENSE
Normal file
@@ -0,0 +1,28 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2024, Telecom Infra Project
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
50
Makefile
50
Makefile
@@ -7,8 +7,10 @@ IMG_ID := "ucentral-client-build-env"
|
||||
IMG_TAG := $(shell cat Dockerfile | sha1sum | awk '{print substr($$1,0,11);}')
|
||||
CONTAINER_NAME := "ucentral_client_build_env"
|
||||
|
||||
.PHONY: all clean build-host-env build-final-deb build-ucentral-docker-img run-host-env run-ucentral-docker-img \
|
||||
plat-ec plat-ec-clean
|
||||
DPKG_IMAGE := "dpkg-builder:latest"
|
||||
DPKG_CONTAINER_NAME := "dpkg_build_env"
|
||||
|
||||
.PHONY: all clean build-host-env build-final-deb build-ucentral-docker-img run-host-env run-ucentral-docker-img
|
||||
|
||||
all: build-host-env build-ucentral-app build-ucentral-docker-img build-final-deb
|
||||
|
||||
@@ -33,6 +35,7 @@ run-host-env: build-host-env
|
||||
docker run -d -t --name ${CONTAINER_NAME} \
|
||||
-v $(realpath ./):/root/ols-nos \
|
||||
--env UCENTRAL_PLATFORM=$(UCENTRAL_PLATFORM) \
|
||||
--env PLATFORM_REVISION="$(PLATFORM_REVISION)" \
|
||||
${IMG_ID}:${IMG_TAG} \
|
||||
bash
|
||||
|
||||
@@ -59,7 +62,7 @@ build-ucentral-docker-img: build-ucentral-app
|
||||
cp docker/deliverables/ucentral-client docker/
|
||||
cp docker/deliverables/rtty docker/
|
||||
OLDIMG=$$(docker images --format "{{.ID}}" ucentral-client:latest)
|
||||
docker build --file docker/Dockerfile --tag ucentral-client:latest docker
|
||||
docker build --file docker/Dockerfile --tag ucentral-client:latest docker --label com.azure.sonic.manifest="$$(cat docker/manifest.json)"
|
||||
NEWIMG=$$(docker images --format "{{.ID}}" ucentral-client:latest)
|
||||
if [ -n "$$OLDIMG" ] && [ ! "$$OLDIMG" = "$$NEWIMG" ]; then
|
||||
docker image rm $$OLDIMG
|
||||
@@ -81,14 +84,39 @@ build-final-deb: build-ucentral-docker-img
|
||||
@echo
|
||||
@echo "ucentral client deb pkg is available under ./output/ dir"
|
||||
|
||||
plat-ec:
|
||||
src/ec-private/build.sh
|
||||
build-arm64-deb: build-ucentral-docker-img
|
||||
docker inspect --type=image ${DPKG_IMAGE} >/dev/null 2>&1 || \
|
||||
docker build --file dpkg-builder.Dockerfile --tag ${DPKG_IMAGE} .
|
||||
|
||||
docker container stop ${DPKG_CONTAINER_NAME} > /dev/null 2>&1 || true;
|
||||
docker container rm ${DPKG_CONTAINER_NAME} > /dev/null 2>&1 || true;
|
||||
|
||||
docker container run -d -t \
|
||||
--name ${DPKG_CONTAINER_NAME} \
|
||||
--platform linux/arm64 \
|
||||
-v $(realpath ./):$(realpath ./) \
|
||||
-w $(realpath ./src/) \
|
||||
--user $(shell id -u):$(shell id -g) \
|
||||
--tmpfs /tmp \
|
||||
${DPKG_IMAGE} \
|
||||
bash
|
||||
|
||||
docker exec -t ${DPKG_CONTAINER_NAME} dpkg-buildpackage -rfakeroot -b -us -uc -j
|
||||
|
||||
mv ucentral-client*deb ./output/
|
||||
mv src/docker-ucentral-client.gz ./output/
|
||||
|
||||
docker container stop ${DPKG_CONTAINER_NAME} > /dev/null 2>&1 || true;
|
||||
docker container rm ${DPKG_CONTAINER_NAME} > /dev/null 2>&1 || true;
|
||||
|
||||
clean:
|
||||
docker container stop ${CONTAINER_NAME} > /dev/null 2>&1 || true;
|
||||
docker container rm ${CONTAINER_NAME} > /dev/null 2>&1 || true;
|
||||
docker container stop ${DPKG_CONTAINER_NAME} > /dev/null 2>&1 || true;
|
||||
docker container rm ${DPKG_CONTAINER_NAME} > /dev/null 2>&1 || true;
|
||||
docker rmi ucentral-client 2>/dev/null || true;
|
||||
docker rmi ${IMG_ID}:${IMG_TAG} 2>/dev/null || true;
|
||||
docker rmi ${DPKG_IMAGE} 2>/dev/null || true;
|
||||
rm -rf output 2>/dev/null || true;
|
||||
rm -rf docker 2>/dev/null || true;
|
||||
rm -rf src/docker/deliverables || true;
|
||||
@@ -99,14 +127,4 @@ clean:
|
||||
rm -rf src/debian/.debhelper src/debian/ucentral-client 2>/dev/null || true;
|
||||
rm -rf src/debian/shasta-ucentral-client* 2>/dev/null || true;
|
||||
rm -rf src/debian/debhelper-build-stamp* 2>/dev/null || true;
|
||||
rm -rf src/debian/files shasta_1.0_amd64.changes shasta_1.0_amd64.buildinfo 2>/dev/null || true;
|
||||
|
||||
plat-ec-clean:
|
||||
rm -rf src/ec-private/cjson
|
||||
rm -rf src/ec-private/curl
|
||||
rm -rf src/ec-private/libwebsockets
|
||||
rm -rf src/ec-private/openssl
|
||||
rm -rf src/ec-private/openssl
|
||||
rm -rf src/ec-private/ecapi/build
|
||||
rm -rf src/ec-private/ucentral
|
||||
rm -rf output
|
||||
rm -rf src/debian/files shasta_1.0_arm64.changes shasta_1.0_arm64.buildinfo 2>/dev/null || true;
|
||||
|
||||
@@ -11,7 +11,7 @@ cfg2:
|
||||
cfg3:
|
||||
Bring ports 1 up, 2 up (Ethernet1, Ethernet2) (admin state);
|
||||
Destroy any VLAN that is not in the list (in this particular CFG - create VLAN 10,
|
||||
destroye any other, except for MGMT VLAN 1 - it's not being altered by the
|
||||
destroy any other, except for MGMT VLAN 1 - it's not being altered by the
|
||||
uCentral app itself);
|
||||
Create VLAN 10;
|
||||
Set VLAN 10 memberlist with the following ports: Ethernet1, Ethernet2;
|
||||
@@ -39,6 +39,7 @@ cfg5_poe:
|
||||
- detection mode is 4pt-dot3af;
|
||||
- power limit is 99900mW (e.g. max per port);
|
||||
- priority is LOW;
|
||||
|
||||
cfg7_ieee80211x.json:
|
||||
Following json file configures the given topology:
|
||||
+-----------------+
|
||||
@@ -64,3 +65,33 @@ cfg7_ieee80211x.json:
|
||||
to be the same for the given (10.10.20.0/24) network.
|
||||
.1x client also must have a valid credentials data (both client and radius server
|
||||
must have same clients credentials configured).
|
||||
|
||||
cfg_igmp.json:
|
||||
Configure igmp snooping and querier on VLAN 1.
|
||||
Configure igmp static groups:
|
||||
- 230.1.1.1 with egress port Ethernet1
|
||||
- 230.2.2.2 with egress ports Ethernet2 & Ethernet3
|
||||
|
||||
cfg_rpvstp.json:
|
||||
Configure VLAN 1;
|
||||
Configure VLAN 2;
|
||||
Configure rapid per-vlan STP on VLAN 1 with priority 32768;
|
||||
Disable STP on VLAN 2.
|
||||
|
||||
cfg_port_isolation.json:
|
||||
Configure port isolation with Ethernet1 as uplink and
|
||||
Ethernet2 & Ethernet3 as downlink
|
||||
|
||||
cfg_services_log.json:
|
||||
Enable syslog with these parameters:
|
||||
- remote host addr
|
||||
- remote host port
|
||||
- log severity (priority):
|
||||
* emerg: 0
|
||||
* alert: 1
|
||||
* crit: 2
|
||||
* error: 3
|
||||
* warning: 4
|
||||
* notice: 5
|
||||
* info: 6
|
||||
* debug: 7
|
||||
|
||||
@@ -1,70 +1,70 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": false,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet0",
|
||||
"Ethernet1",
|
||||
"Ethernet2",
|
||||
"Ethernet3",
|
||||
"Ethernet4",
|
||||
"Ethernet5",
|
||||
"Ethernet6",
|
||||
"Ethernet7",
|
||||
"Ethernet8",
|
||||
"Ethernet9",
|
||||
"Ethernet10",
|
||||
"Ethernet11",
|
||||
"Ethernet12",
|
||||
"Ethernet13",
|
||||
"Ethernet14",
|
||||
"Ethernet15",
|
||||
"Ethernet16",
|
||||
"Ethernet17",
|
||||
"Ethernet18",
|
||||
"Ethernet19",
|
||||
"Ethernet20",
|
||||
"Ethernet21",
|
||||
"Ethernet22",
|
||||
"Ethernet23",
|
||||
"Ethernet24",
|
||||
"Ethernet25",
|
||||
"Ethernet26",
|
||||
"Ethernet27",
|
||||
"Ethernet28",
|
||||
"Ethernet29",
|
||||
"Ethernet30",
|
||||
"Ethernet31",
|
||||
"Ethernet32",
|
||||
"Ethernet33",
|
||||
"Ethernet34",
|
||||
"Ethernet35",
|
||||
"Ethernet36",
|
||||
"Ethernet37",
|
||||
"Ethernet38",
|
||||
"Ethernet39",
|
||||
"Ethernet40",
|
||||
"Ethernet41",
|
||||
"Ethernet42",
|
||||
"Ethernet43",
|
||||
"Ethernet44",
|
||||
"Ethernet45",
|
||||
"Ethernet46",
|
||||
"Ethernet47",
|
||||
"Ethernet48",
|
||||
"Ethernet52",
|
||||
"Ethernet56",
|
||||
"Ethernet60",
|
||||
"Ethernet64",
|
||||
"Ethernet68",
|
||||
"Ethernet72",
|
||||
"Ethernet76"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interfaces": [],
|
||||
"services": {},
|
||||
"uuid": 1
|
||||
}
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": false,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet0",
|
||||
"Ethernet1",
|
||||
"Ethernet2",
|
||||
"Ethernet3",
|
||||
"Ethernet4",
|
||||
"Ethernet5",
|
||||
"Ethernet6",
|
||||
"Ethernet7",
|
||||
"Ethernet8",
|
||||
"Ethernet9",
|
||||
"Ethernet10",
|
||||
"Ethernet11",
|
||||
"Ethernet12",
|
||||
"Ethernet13",
|
||||
"Ethernet14",
|
||||
"Ethernet15",
|
||||
"Ethernet16",
|
||||
"Ethernet17",
|
||||
"Ethernet18",
|
||||
"Ethernet19",
|
||||
"Ethernet20",
|
||||
"Ethernet21",
|
||||
"Ethernet22",
|
||||
"Ethernet23",
|
||||
"Ethernet24",
|
||||
"Ethernet25",
|
||||
"Ethernet26",
|
||||
"Ethernet27",
|
||||
"Ethernet28",
|
||||
"Ethernet29",
|
||||
"Ethernet30",
|
||||
"Ethernet31",
|
||||
"Ethernet32",
|
||||
"Ethernet33",
|
||||
"Ethernet34",
|
||||
"Ethernet35",
|
||||
"Ethernet36",
|
||||
"Ethernet37",
|
||||
"Ethernet38",
|
||||
"Ethernet39",
|
||||
"Ethernet40",
|
||||
"Ethernet41",
|
||||
"Ethernet42",
|
||||
"Ethernet43",
|
||||
"Ethernet44",
|
||||
"Ethernet45",
|
||||
"Ethernet46",
|
||||
"Ethernet47",
|
||||
"Ethernet48",
|
||||
"Ethernet52",
|
||||
"Ethernet56",
|
||||
"Ethernet60",
|
||||
"Ethernet64",
|
||||
"Ethernet68",
|
||||
"Ethernet72",
|
||||
"Ethernet76"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interfaces": [],
|
||||
"services": {},
|
||||
"uuid": 1
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet1",
|
||||
"Ethernet2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interfaces": [],
|
||||
"services": {},
|
||||
"uuid": 1
|
||||
}
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet1",
|
||||
"Ethernet2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interfaces": [],
|
||||
"services": {},
|
||||
"uuid": 1
|
||||
}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": false,
|
||||
"select-ports": [
|
||||
"Ethernet2"
|
||||
],
|
||||
"speed": 1000
|
||||
}
|
||||
],
|
||||
"interfaces": [],
|
||||
"services": {},
|
||||
"uuid": 2
|
||||
}
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": false,
|
||||
"select-ports": [
|
||||
"Ethernet2"
|
||||
],
|
||||
"speed": 1000
|
||||
}
|
||||
],
|
||||
"interfaces": [],
|
||||
"services": {},
|
||||
"uuid": 2
|
||||
}
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet1",
|
||||
"Ethernet2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"vlan": {
|
||||
"id": 10,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet1",
|
||||
"Ethernet2"
|
||||
],
|
||||
"vlan-tag": "tagged"
|
||||
}
|
||||
],
|
||||
"name": "mgmt",
|
||||
"role": "upstream",
|
||||
"services": []
|
||||
}
|
||||
],
|
||||
"services": {},
|
||||
"uuid": 3
|
||||
}
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet1",
|
||||
"Ethernet2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"vlan": {
|
||||
"id": 10,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet1",
|
||||
"Ethernet2"
|
||||
],
|
||||
"vlan-tag": "tagged"
|
||||
}
|
||||
],
|
||||
"name": "mgmt",
|
||||
"role": "upstream",
|
||||
"services": []
|
||||
}
|
||||
],
|
||||
"services": {},
|
||||
"uuid": 3
|
||||
}
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet1",
|
||||
"Ethernet2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"vlan": {
|
||||
"id": 10,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet1"
|
||||
],
|
||||
"vlan-tag": "tagged"
|
||||
}
|
||||
],
|
||||
"name": "mgmt",
|
||||
"role": "upstream",
|
||||
"services": []
|
||||
},
|
||||
{
|
||||
"vlan": {
|
||||
"id": 100,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet2"
|
||||
],
|
||||
"vlan-tag": "tagged"
|
||||
}
|
||||
],
|
||||
"name": "mgmt",
|
||||
"role": "upstream",
|
||||
"services": []
|
||||
}
|
||||
],
|
||||
"services": {},
|
||||
"uuid": 3
|
||||
}
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"speed": 1000,
|
||||
"select-ports": [
|
||||
"Ethernet1",
|
||||
"Ethernet2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"vlan": {
|
||||
"id": 10,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet1"
|
||||
],
|
||||
"vlan-tag": "tagged"
|
||||
}
|
||||
],
|
||||
"name": "mgmt",
|
||||
"role": "upstream",
|
||||
"services": []
|
||||
},
|
||||
{
|
||||
"vlan": {
|
||||
"id": 100,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet2"
|
||||
],
|
||||
"vlan-tag": "tagged"
|
||||
}
|
||||
],
|
||||
"name": "mgmt",
|
||||
"role": "upstream",
|
||||
"services": []
|
||||
}
|
||||
],
|
||||
"services": {},
|
||||
"uuid": 3
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
{
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"subnet": "20.20.20.20/24",
|
||||
"subnet": [
|
||||
{
|
||||
"prefix": "20.20.20.20/24"
|
||||
}
|
||||
],
|
||||
"dhcp": {
|
||||
"relay-server": "172.20.254.8",
|
||||
"circuit-id-format": "{Name}:{VLAN-ID}"
|
||||
@@ -44,7 +48,11 @@
|
||||
{
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"subnet": "30.30.30.30/24",
|
||||
"subnet": [
|
||||
{
|
||||
"prefix": "30.30.30.30/24"
|
||||
}
|
||||
],
|
||||
"dhcp": {
|
||||
"relay-server": "172.20.10.12",
|
||||
"circuit-id-format": "{Name}:{VLAN-ID}"
|
||||
@@ -71,7 +79,11 @@
|
||||
{
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"subnet": "172.20.10.181/24"
|
||||
"subnet": [
|
||||
{
|
||||
"prefix": "172.20.10.181/24"
|
||||
}
|
||||
]
|
||||
},
|
||||
"vlan": {
|
||||
"id": 20,
|
||||
|
||||
@@ -50,7 +50,11 @@
|
||||
},
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"subnet": "10.10.20.100/24"
|
||||
"subnet": [
|
||||
{
|
||||
"prefix": "10.10.20.100/24"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
@@ -70,7 +74,11 @@
|
||||
},
|
||||
"ipv4": {
|
||||
"addressing": "static",
|
||||
"subnet": "10.10.50.100/24"
|
||||
"subnet": [
|
||||
{
|
||||
"prefix": "10.10.50.100/24"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
|
||||
64
config-samples/cfg_igmp.json
Normal file
64
config-samples/cfg_igmp.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"speed": 1000,
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"poe": {
|
||||
"admin-mode": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"vlan": {
|
||||
"id": 1,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"vlan-tag": "un-tagged"
|
||||
}
|
||||
],
|
||||
"ipv4": {
|
||||
"multicast": {
|
||||
"igmp": {
|
||||
"querier-enable": true,
|
||||
"query-interval": 60,
|
||||
"snooping-enable": true,
|
||||
"version": 3,
|
||||
"static-mcast-groups": [
|
||||
{
|
||||
"address": "230.1.1.1",
|
||||
"egress-ports": [
|
||||
"Ethernet1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"address": "230.2.2.2",
|
||||
"egress-ports": [
|
||||
"Ethernet2",
|
||||
"Ethernet3"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"subnet": [
|
||||
{
|
||||
"prefix": "1.1.1.1/24"
|
||||
}
|
||||
]
|
||||
},
|
||||
"role": "upstream",
|
||||
"name": "mgmt-vlan"
|
||||
}
|
||||
],
|
||||
"uuid": 1
|
||||
}
|
||||
54
config-samples/cfg_port_isolation.json
Normal file
54
config-samples/cfg_port_isolation.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"speed": 1000,
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"poe": {
|
||||
"admin-mode": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"vlan": {
|
||||
"id": 1,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"vlan-tag": "un-tagged"
|
||||
}
|
||||
],
|
||||
"role": "upstream",
|
||||
"name": "mgmt-vlan"
|
||||
}
|
||||
],
|
||||
"switch": {
|
||||
"port-isolation": {
|
||||
"sessions": [
|
||||
{
|
||||
"id": 1,
|
||||
"uplink": {
|
||||
"interface-list": [
|
||||
"Ethernet1"
|
||||
]
|
||||
},
|
||||
"downlink": {
|
||||
"interface-list": [
|
||||
"Ethernet2",
|
||||
"Ethernet3"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"uuid": 1
|
||||
}
|
||||
66
config-samples/cfg_rpvstp.json
Normal file
66
config-samples/cfg_rpvstp.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"speed": 1000,
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"poe": {
|
||||
"admin-mode": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"vlan": {
|
||||
"id": 1,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"vlan-tag": "un-tagged"
|
||||
}
|
||||
],
|
||||
"role": "upstream",
|
||||
"name": "mgmt-vlan"
|
||||
},
|
||||
{
|
||||
"vlan": {
|
||||
"id": 2,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"vlan-tag": "tagged"
|
||||
}
|
||||
],
|
||||
"role": "upstream",
|
||||
"name": "mgmt-vlan"
|
||||
}
|
||||
],
|
||||
"switch": {
|
||||
"loop-detection": {
|
||||
"protocol": "rpvstp",
|
||||
"instances": [
|
||||
{
|
||||
"id": 1,
|
||||
"enabled": true,
|
||||
"priority": 32768
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"enabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"uuid": 1
|
||||
}
|
||||
43
config-samples/cfg_services_log.json
Normal file
43
config-samples/cfg_services_log.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"speed": 1000,
|
||||
"duplex": "full",
|
||||
"enabled": true,
|
||||
"poe": {
|
||||
"admin-mode": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"vlan": {
|
||||
"id": 1,
|
||||
"proto": "802.1q"
|
||||
},
|
||||
"ethernet": [
|
||||
{
|
||||
"select-ports": [
|
||||
"Ethernet*"
|
||||
],
|
||||
"vlan-tag": "un-tagged"
|
||||
}
|
||||
],
|
||||
"role": "upstream",
|
||||
"name": "mgmt-vlan"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"log": {
|
||||
"port": 2000,
|
||||
"priority": 7,
|
||||
"size": 1000,
|
||||
"host": "192.168.1.10",
|
||||
"proto": "udp"
|
||||
}
|
||||
},
|
||||
"uuid": 1
|
||||
}
|
||||
8
dpkg-builder.Dockerfile
Normal file
8
dpkg-builder.Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
||||
FROM arm64v8/debian:buster
|
||||
|
||||
RUN apt-get update -q -y && apt-get -q -y --no-install-recommends install \
|
||||
build-essential \
|
||||
fakeroot \
|
||||
dpkg-dev \
|
||||
dh-exec \
|
||||
debhelper
|
||||
@@ -8,7 +8,7 @@ export DH_VERBOSE = 1
|
||||
export DH_BUILD_DDEBS=1
|
||||
export DEB_BUILD_OPTIONS=autodbgsym
|
||||
|
||||
CONFIGURED_ARCH ?= amd64
|
||||
CONFIGURED_ARCH ?= arm64
|
||||
UCENTRAL_CLIENT_VERSION ?= 1.0
|
||||
DPKG_EXPORT_BUILDFLAGS = 1
|
||||
INSTALL ?= debian/ucentral-client/
|
||||
@@ -36,6 +36,7 @@ override_dh_install:
|
||||
# home folder.
|
||||
mkdir -p ${INSTALL}/home/admin
|
||||
cp scripts/OLS_NOS_fixups.script ${INSTALL}/usr/local/lib
|
||||
cp scripts/OLS_NOS_upgrade_override.script ${INSTALL}/usr/local/lib
|
||||
cp docker-ucentral-client.gz ${INSTALL}/usr/local/lib
|
||||
# Install Vlan1 in-band management configuration
|
||||
mkdir -p ${INSTALL}/etc/network/interfaces.d/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:buster
|
||||
FROM arm64v8/debian:buster
|
||||
|
||||
RUN echo "uCentral client support"
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
@@ -9,6 +9,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
curl \
|
||||
libjsoncpp-dev \
|
||||
busybox \
|
||||
libhiredis0.14 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN ln -s /bin/busybox /usr/local/bin/nslookup
|
||||
@@ -21,6 +22,11 @@ COPY /ucentral-client /usr/local/bin/ucentral-client
|
||||
COPY /rtty /usr/local/bin/
|
||||
COPY /lib* /usr/local/lib/
|
||||
|
||||
# Install root CA certificate for development purposes
|
||||
COPY /ca-cert.pem /usr/local/share/ca-certificates/ca-cert.crt
|
||||
COPY /tip-cert.pem /usr/local/share/ca-certificates/tip-cert.crt
|
||||
RUN update-ca-certificates
|
||||
|
||||
RUN ldconfig
|
||||
RUN ls -l /usr/local/bin/ucentral-client
|
||||
|
||||
|
||||
35
src/docker/ca-cert.pem
Normal file
35
src/docker/ca-cert.pem
Normal file
@@ -0,0 +1,35 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGHzCCBAegAwIBAgIUe4hxamQ8YDS/GuFPIN+uqH4BgMswDQYJKoZIhvcNAQEL
|
||||
BQAwgZ4xCzAJBgNVBAYTAlVBMRQwEgYDVQQIDAtLeWl2IE9ibGFzdDENMAsGA1UE
|
||||
BwwES3lpdjEbMBkGA1UECgwSTGFyY2ggTmV0d29ya3MgTHRkMREwDwYDVQQLDAhT
|
||||
b2Z0d2FyZTERMA8GA1UEAwwIY2EubGFyY2gxJzAlBgkqhkiG9w0BCQEWGGFkbWlu
|
||||
QGxhcmNoLW5ldHdvcmtzLmNvbTAeFw0yNDA0MDQwNzUxMDlaFw0zNDA0MDIwNzUx
|
||||
MDlaMIGeMQswCQYDVQQGEwJVQTEUMBIGA1UECAwLS3lpdiBPYmxhc3QxDTALBgNV
|
||||
BAcMBEt5aXYxGzAZBgNVBAoMEkxhcmNoIE5ldHdvcmtzIEx0ZDERMA8GA1UECwwI
|
||||
U29mdHdhcmUxETAPBgNVBAMMCGNhLmxhcmNoMScwJQYJKoZIhvcNAQkBFhhhZG1p
|
||||
bkBsYXJjaC1uZXR3b3Jrcy5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQDG5kue5pYz+PC/NBZpBesN2NjWzpcTAunzFnQQ/XAMY9XLcUdyrXLz6r2p
|
||||
bFbmUiW1am+2TZMg6sQbBPId7vjuHZykXavgUd8ybUoQ2GHnWVsCCy8b/Fn2WF2r
|
||||
Zc14ffRncZ4BsHCPJsWboCmYVsgNgr1nmDT6Le5VIRJ2MJksuTz+55bK9qCIIWWC
|
||||
PFBpGjMHpEdybvwa5gzv2Do9vwb0m76LKL5ygyle4hFoI54JwRV8O7g8FishTrmI
|
||||
oSDmapB7+K9egK2wXhbHQ6pIc4qvs9YdSPaTkLV/tRa3Oyw+vUGDW5Bg5UezPJNf
|
||||
U9yCZIjKZXYXbqaZRgtcXJfqBGFlmuVX44zfjpEe2ovHXrb7HokZxEcJA/yooxzw
|
||||
3eZXDxsdVXU02jA9jSQjX1Q44lwxUn1wVZlTdr9AUJM6JiEujITy2fwyfaeTwCyS
|
||||
Y4xU7qgMr9Wml0kHPPFnlsTWo+dswpztRt5BKCKMcsyLETiLkapsI784ameiEgpA
|
||||
3klYJsMh/2+Q9ABuK5BQOuHCPvalNoEKn4rUyQgdTL/ay3oqlvNf4r08hgHA72Aj
|
||||
oM60Ldq2gJeuaEh6l3fV182qd4funDgrMpQpfRcIKDJcDRuN8vKzqmTXLNY8zgNY
|
||||
xharAsEm3CdBwbpTF4E1yDCH8seuj3TCcMwJAWGq73QRgu0DwQIDAQABo1MwUTAd
|
||||
BgNVHQ4EFgQUwqiRcQgGkVIdKjDjA3KCVTl0rTwwHwYDVR0jBBgwFoAUwqiRcQgG
|
||||
kVIdKjDjA3KCVTl0rTwwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
|
||||
AgEAwUEtLkinQmWmRqQfKZayUDjKl0B7HZy9en0LI6WzKppfj9OwZcAxWNqavDwp
|
||||
WRCEmzt27NPF42C6lr/i0ZBOT5V1qDoP8/JR3QW/dsEIS2wW61803pw77U8SyfKP
|
||||
tEwbQsCuw7jBCSDjDKI5k9aBlltHzTzSKjo1nBTwMYHho1dR5Th6mOXr9soyNopU
|
||||
l7SlvC5UWuCYxhxjWlZnxaupbKdPNt88SPWDLWa6HLBil2XSu/5wMVdubyCZrlN/
|
||||
8SajdHtev9lk3pucnLmqxCq6sChim9EzDcVVRPNzR59H6dbyMec16e0XrnNcd9ch
|
||||
2Zo2HQm3jyIh4YL1iRrHyqJgVfmI1hKlvqUOfAxVCV8pSec40EQD2sd1Ges5QTiH
|
||||
LCk2osPvDjV1JyFKcr5Pf50+S02MViU8tza+VfUwozRa6A9qR/JlBTBlCrDEYexm
|
||||
CK7I11Qln26vvtlnJTC7OzXTaOSYQ1NlJCwLwsMOvhYVm0skxL1HX1AYHKZ0t0QW
|
||||
PAQYij2QP1YK4SU68MlXiE3D5N7vZ+42pfHx0DNZXlsudM7kRmkT3FBIh54mh4xt
|
||||
0a5nUDjd3IBPcVAeVJZqbxglAwKlue+MhJRKSFxehE3qEKurmH1tGUTb5NnmMllC
|
||||
6G51ZGoyb64oGejymIc2IB5rXH5+Uu2HUsyoVLt0wihgU7E=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -4,7 +4,8 @@
|
||||
"package": {
|
||||
"version": "1.0.0",
|
||||
"depends": [],
|
||||
"name": "ucentral_client"
|
||||
"name": "ucentral_client",
|
||||
"description": "SONiC uCentral client package"
|
||||
},
|
||||
"service": {
|
||||
"name": "ucentral_client",
|
||||
@@ -25,12 +26,24 @@
|
||||
},
|
||||
"container": {
|
||||
"privileged": false,
|
||||
"volumes": [],
|
||||
"volumes": ["/var/lib/ucentral:/var/lib/ucentral"],
|
||||
"mounts": [
|
||||
{
|
||||
"source": "TCA",
|
||||
"target": "/etc/ucentral",
|
||||
"type": "volume",
|
||||
"volume-opt": {
|
||||
"device": "/dev/disk/by-label/ONIE-TIP-CA-CERT",
|
||||
"type": "ext4",
|
||||
"o": "ro"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tmpfs": []
|
||||
},
|
||||
"cli": {
|
||||
"config": "",
|
||||
"show": "",
|
||||
"clear": ""
|
||||
"config": [],
|
||||
"show": [],
|
||||
"clear": []
|
||||
}
|
||||
}
|
||||
|
||||
49
src/docker/tip-cert.pem
Normal file
49
src/docker/tip-cert.pem
Normal file
@@ -0,0 +1,49 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEnDCCA4SgAwIBAgIUVpyCUx1MUeUwxg+7I1BvGFTz7HkwDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjUxMjZaFw0yNjA0MTMyMjM4NDZaMGwx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEpMCcGA1UEAxMgVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IElzc3VpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDtKBrq
|
||||
qd2aKVSk25KfL5xHu8X7/8rJrz3IvyPuVKWhk/N1zabot3suBcGaYNKjnRHxg78R
|
||||
yKwKzajKYWtiQFqztu24g16LQeAnoUxZnF6a0z3JkkRPsz14A2y8TUhdEe1tx+UU
|
||||
4VGsk3n+FMmOQHL+79FO57zQC1LwylgfLSltrI6mF3jowVUQvnwzKhUzT87AJ6EO
|
||||
ndK/q0T/Bgi+aI39zfVOjJjsTJwghvrmYW3iarP1THSKxeib2s02bZKrvvHa5HL4
|
||||
UI8+LvREpVZl4mzt1z6Nl344Y6f+UeJlYa/Ci0jJqaXJmyVnUbAz+c0i5JfwAVn3
|
||||
YQzfC4eLnZCmdF8zAgMBAAGjggE3MIIBMzAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
|
||||
DgQWBBSzG1S44EerPfM4gOQ85f0AYW3R6DAfBgNVHSMEGDAWgBQCRpZgebFT9qny
|
||||
98WfIUDk6ZEB+jAOBgNVHQ8BAf8EBAMCAYYwgYMGCCsGAQUFBwEBBHcwdTAoBggr
|
||||
BgEFBQcwAYYcaHR0cDovL29jc3Aub25lLmRpZ2ljZXJ0LmNvbTBJBggrBgEFBQcw
|
||||
AoY9aHR0cDovL2NhY2VydHMub25lLmRpZ2ljZXJ0LmNvbS9UZWxlY29tSW5mcmFQ
|
||||
cm9qZWN0Um9vdENBLmNydDBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vY3JsLm9u
|
||||
ZS5kaWdpY2VydC5jb20vVGVsZWNvbUluZnJhUHJvamVjdFJvb3RDQS5jcmwwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAFbz+K94bHIkBMJqps0dApniUmOn0pO6Q6cGh47UP/kX
|
||||
IiPIsnYgG+hqYD/qtsiqJhaWi0hixRWn38UmvZxMRk27aSTGE/TWx0JTC3qDGsSe
|
||||
XkUagumbSfmS0ZyiTwMPeGAjXwyzGorqZWeA95eKfImntMiOf3E7//GK0K7HpCx8
|
||||
IPCnLZsZD2q/mLyBsduImFIRQJbLAhwIxpcd1qYJk+BlGFL+HtBpEbq6JxW2Xy+v
|
||||
DpNWc2WIsUTle0rTc9JNJrLX4ChUJmKqf8obKHap3Xh3//qw/jDB9pOAinA33FLJ
|
||||
EmCnwBvQr9mfNmPBGMYZVU8cPruDQJ57GjmmvdisbJY=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDojCCAoqgAwIBAgIUPVYBpqNbcLYygF6Mx+qxSWwQyFowDQYJKoZIhvcNAQEL
|
||||
BQAwaTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG1RlbGVjb20gSW5mcmEgUHJvamVj
|
||||
dCwgSW5jLjEMMAoGA1UECxMDVElQMSYwJAYDVQQDEx1UZWxlY29tIEluZnJhIFBy
|
||||
b2plY3QgUm9vdCBDQTAeFw0yMTA0MTMyMjQyNDRaFw0zMTA0MTMyMjM4NDZaMGkx
|
||||
CzAJBgNVBAYTAlVTMSQwIgYDVQQKExtUZWxlY29tIEluZnJhIFByb2plY3QsIElu
|
||||
Yy4xDDAKBgNVBAsTA1RJUDEmMCQGA1UEAxMdVGVsZWNvbSBJbmZyYSBQcm9qZWN0
|
||||
IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDIGCibwf5u
|
||||
AAwZ+1H8U0e3u2V+0d2gSctucoK86XwUmfe1V2a/qlCYZd29r80IuN1IIeB0naIm
|
||||
KnK/MzXW87clF6tFd1+HzEvmlY/W4KyIXalVCTEzirFSvBEG2oZpM0yC3AefytAO
|
||||
aOpA00LaM3xTfTqMKIRhJBuLy0I4ANUVG6ixVebbGuc78IodleqiLoWy2Q9QHyEO
|
||||
t/7hZndJhiVogh0PveRhho45EbsACu7ymDY+JhlIleevqwlE3iQoq0YcmYADHno6
|
||||
Eq8vcwLpZFxihupUafkd1T3WJYQAJf9coCjBu2qIhNgrcrGD8R9fGswwNRzMRMpX
|
||||
720+GjcDW3bJAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAJG
|
||||
lmB5sVP2qfL3xZ8hQOTpkQH6MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAVjl9dm4epG9NUYnagT9sg7scVQEPfz3Lt6w1NXJXgD8mAUlK0jXmEyvM
|
||||
dCPD4514n+8+lM7US8fh+nxc7jO//LwK17Wm9FblgjNFR7+anv0Q99T9fP19DLlF
|
||||
PSNHL2emogy1bl1lLTAoj8nxg2wVKPDSHBGviQ5LR9fsWUIJDv9Bs5k0qWugWYSj
|
||||
19S6qnHeskRDB8MqRLhKMG82oDVLerSnhD0P6HjySBHgTTU7/tYS/OZr1jI6MPbG
|
||||
L+/DtiR5fDVMNdBSGU89UNTi0wHY9+RFuNlIuvZC+x/swF0V9R5mN+ywquTPtDLA
|
||||
5IOM7ItsRmen6u3qu+JXros54e4juQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,33 +0,0 @@
|
||||
# Ucentral for EC
|
||||
|
||||
Ucentral solution for EC is made of the following parts:
|
||||
* `ecapi`: a library to communicate with EC via SNMP
|
||||
|
||||
# Compiling
|
||||
|
||||
## EC Build for Target Device
|
||||
|
||||
First build the full EC image for your target device:
|
||||
* `cd EC_VOB/project_build_environment/<target device>`
|
||||
* `./make_all`
|
||||
|
||||
If this is successful, you can proceed to the next step.
|
||||
|
||||
## Build Environment
|
||||
|
||||
To successfully build required components the build environments variables must be prepared:
|
||||
* `cd EC_VOB/project_build_environment/<target device>`
|
||||
* `cd utils`
|
||||
* `. build_env_init`
|
||||
|
||||
## Building All Components
|
||||
|
||||
Presumably you have checked out the [ols-ucentral-src]:
|
||||
* `cd [ols-ucentral-src]`
|
||||
* Run `make plat-ec`, which should successfully compile all components
|
||||
|
||||
## Creating EC Firmware with Ucentral
|
||||
|
||||
After building everything up:
|
||||
* Check the `output` directory, it should contain all required binaries in appropriate subdirectories
|
||||
* Copy over these directories to your `EC_VOB/project_build_environment/<target device>/user/thirdpty/ucentral`
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,141 +0,0 @@
|
||||
#!/bin/bash
|
||||
UCENTRAL_DIR=${PWD}
|
||||
EC_BUILD_DIR=${PWD}/src/ec-private
|
||||
OUT_DIR=${UCENTRAL_DIR}/output
|
||||
BIN_DIR=${OUT_DIR}/usr/sbin
|
||||
LIB_DIR=${OUT_DIR}/lib
|
||||
|
||||
LIB_OPENSSL=openssl-1.1.1q
|
||||
LIB_WEBSOCKETS=libwebsockets-4.1.4
|
||||
LIB_CURL=curl-7.83.1
|
||||
LIB_CJSON=cJSON-1.7.15
|
||||
|
||||
echo "+++++++++++++++++ check EC build environment +++++++++++++++++"
|
||||
if [ ! "${PROJECT_NAME}" ] || [ ! "${SOURCE_PATH}" ]; then
|
||||
echo "Error! Please source 'build_env_init' for your build environment."
|
||||
exit
|
||||
fi
|
||||
|
||||
cp -af ${UCENTRAL_DIR}/src/ucentral-client/* ${EC_BUILD_DIR}/ucentral-client
|
||||
|
||||
rm -rf ${OUT_DIR}
|
||||
|
||||
if [ ! -d output ]; then
|
||||
mkdir -p ${BIN_DIR}
|
||||
mkdir -p ${LIB_DIR}
|
||||
fi
|
||||
|
||||
C_COMPILER="${TOOLCHAIN_PATH}/${CROSS_COMPILE}gcc ."
|
||||
|
||||
echo "+++++++++++++++++ openssl +++++++++++++++++"
|
||||
cd ${EC_BUILD_DIR}
|
||||
if [ ! -d openssl ]; then
|
||||
tar -xf ./archive/${LIB_OPENSSL}.tar.gz
|
||||
mv ${LIB_OPENSSL} openssl
|
||||
fi
|
||||
|
||||
model_name=${D_MODEL_NAME}
|
||||
|
||||
if [ "$model_name" == 'ECS4130_AC5' ]; then
|
||||
platform=linux-aarch64
|
||||
elif [ "$model_name" == 'ECS4125_10P' ]; then
|
||||
platform=linux-mips32
|
||||
else
|
||||
echo "Error! The model ${model_name} is not in the support lists, please check."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd openssl
|
||||
./Configure ${platform} --cross-compile-prefix=${CROSS_COMPILE} no-idea no-mdc2 no-rc5 no-ssl2 no-ssl3
|
||||
make -j${nproc}
|
||||
|
||||
if [ "$?" -eq "0" ]; then
|
||||
cp -af libssl.so.1.1 libcrypto.so.1.1 ${LIB_DIR}
|
||||
fi
|
||||
|
||||
echo "+++++++++++++++++ libwebsockets +++++++++++++++++"
|
||||
cd ${EC_BUILD_DIR}
|
||||
if [ ! -d libwebsockets ]; then
|
||||
tar -xf ./archive/${LIB_WEBSOCKETS}.tar.gz
|
||||
mv ${LIB_WEBSOCKETS} libwebsockets
|
||||
patch -s -N -p1 -d libwebsockets/lib < ./patch/libwebsockets/${LIB_WEBSOCKETS}.patch
|
||||
fi
|
||||
|
||||
cd libwebsockets
|
||||
cmake \
|
||||
-DOPENSSL_ROOT_DIR=${EC_BUILD_DIR}/openssl \
|
||||
-DCMAKE_C_COMPILER=${C_COMPILER}
|
||||
make -j${nproc}
|
||||
|
||||
if [ "$?" -eq "0" ]; then
|
||||
cp -af lib/libwebsockets.so.17 ${LIB_DIR}
|
||||
fi
|
||||
|
||||
echo "+++++++++++++++++ curl +++++++++++++++++"
|
||||
cd ${EC_BUILD_DIR}
|
||||
|
||||
if [ ! -d curl ]; then
|
||||
tar -xf ./archive/${LIB_CURL}.tar.xz
|
||||
mv ${LIB_CURL} curl
|
||||
patch -s -N -p1 -d curl < ./patch/curl/${LIB_CURL}.patch
|
||||
fi
|
||||
|
||||
cd curl
|
||||
cmake -DCMAKE_C_COMPILER=${C_COMPILER} -DCMAKE_SHARED_LINKER_FLAGS=-L${EC_BUILD_DIR}/openssl
|
||||
make
|
||||
|
||||
if [ "$?" -eq "0" ]; then
|
||||
cp -af ./lib/libcurl.so ${LIB_DIR}
|
||||
cp -af ./src/curl ${BIN_DIR}
|
||||
fi
|
||||
|
||||
echo "+++++++++++++++++ cjson +++++++++++++++++"
|
||||
cd ${EC_BUILD_DIR}
|
||||
|
||||
if [ ! -d cjson ]; then
|
||||
tar -xf ./archive/${LIB_CJSON}.tar.gz
|
||||
mv ${LIB_CJSON} cjson
|
||||
fi
|
||||
|
||||
cd cjson
|
||||
cmake -DCMAKE_C_COMPILER=${C_COMPILER}
|
||||
make
|
||||
|
||||
if [ "$?" -eq "0" ]; then
|
||||
cp -af ./libcjson.so.1.7.15 ${LIB_DIR}
|
||||
cd ${LIB_DIR}
|
||||
mv libcjson.so.1.7.15 libcjson.so.1
|
||||
fi
|
||||
|
||||
echo "+++++++++++++++++ ecapi +++++++++++++++++"
|
||||
cd ${EC_BUILD_DIR}/ecapi
|
||||
mkdir ${EC_BUILD_DIR}/ecapi/build
|
||||
cd ${EC_BUILD_DIR}/ecapi/build
|
||||
|
||||
cmake -DCMAKE_C_COMPILER=${C_COMPILER} ..
|
||||
make
|
||||
|
||||
if [ "$?" -eq "0" ]; then
|
||||
cp -af libecapi.so ${LIB_DIR}
|
||||
fi
|
||||
|
||||
echo "+++++++++++++++++ ucentral-client +++++++++++++++++"
|
||||
if [ ! -d ucentral ]; then
|
||||
mkdir -p ${EC_BUILD_DIR}/ucentral
|
||||
fi
|
||||
|
||||
cp -af ${UCENTRAL_DIR}/src/ucentral-client ${EC_BUILD_DIR}/ucentral/ucentral-client
|
||||
cp -af ${EC_BUILD_DIR}/patch/ucentral/* ${EC_BUILD_DIR}/ucentral
|
||||
mkdir -p ${EC_BUILD_DIR}/ucentral/build
|
||||
cd ${EC_BUILD_DIR}/ucentral/build
|
||||
|
||||
cmake -DCMAKE_C_COMPILER=${C_COMPILER} ..
|
||||
make
|
||||
|
||||
if [ "$?" -eq "0" ]; then
|
||||
cp -af ucentral-client ${BIN_DIR}
|
||||
fi
|
||||
|
||||
echo "+++++++++++++++++ Strip target binaries +++++++++++++++++"
|
||||
${TOOLCHAIN_PATH}/${CROSS_COMPILE}strip ${BIN_DIR}/*
|
||||
${TOOLCHAIN_PATH}/${CROSS_COMPILE}strip ${LIB_DIR}/*
|
||||
@@ -1,31 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
PROJECT(ecapi C)
|
||||
ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations)
|
||||
|
||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
INCLUDE_DIRECTORIES($ENV{SOURCE_PATH}/sysinclude)
|
||||
INCLUDE_DIRECTORIES($ENV{SOURCE_PATH}/sysinclude/mibconstants)
|
||||
INCLUDE_DIRECTORIES($ENV{SOURCE_PATH}/sysinclude/oem/$ENV{PROJECT_NAME})
|
||||
|
||||
INCLUDE_DIRECTORIES($ENV{PROJECT_PATH}/user/thirdpty/lua/net-snmp-5.4.4/include)
|
||||
INCLUDE_DIRECTORIES($ENV{PROJECT_PATH}/user/thirdpty/lua/net-snmp-5.4.4/agent/mibgroup)
|
||||
#LINK_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/src/snmp)
|
||||
|
||||
|
||||
FIND_LIBRARY(netsnmp_library netsnmp $ENV{PROJECT_PATH}/user/thirdpty/lua/net-snmp-5.4.4/snmplib/.libs)
|
||||
#INCLUDE (CheckSymbolExists)
|
||||
#CHECK_SYMBOL_EXISTS(SYS_getrandom syscall.h getrandom)
|
||||
|
||||
if ($ENV{D_MODEL_NAME} STREQUAL ECS4130_AC5)
|
||||
add_definitions(-DENDIANNESS_ADJUST)
|
||||
endif()
|
||||
|
||||
INCLUDE(snmp/CMakeLists.txt)
|
||||
INCLUDE(generic/CMakeLists.txt)
|
||||
|
||||
ADD_LIBRARY(ecapi SHARED ${LIB_SOURCES})
|
||||
TARGET_LINK_LIBRARIES(ecapi ${netsnmp_library})
|
||||
@@ -1,3 +0,0 @@
|
||||
list(APPEND LIB_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/api_print.c
|
||||
)
|
||||
@@ -1,27 +0,0 @@
|
||||
// #include <stdarg.h>
|
||||
|
||||
#include "api_print.h"
|
||||
|
||||
static bool debug_on = false;
|
||||
|
||||
void print_set_debug(bool on) {
|
||||
debug_on = on;
|
||||
}
|
||||
|
||||
bool print_is_debug(void) {
|
||||
return debug_on;
|
||||
}
|
||||
/*
|
||||
void print_debug(char *fmt, ...) {
|
||||
if (print_is_debug()) {
|
||||
va_list args; va_start(args, fmt);
|
||||
vfprintf(stdout, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
void print_err(char *fmt, ...) {
|
||||
va_list args; va_start(args, fmt);
|
||||
vfprintf(stderr, fmt, args);
|
||||
va_end(args);
|
||||
}*/
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef API_CONFIG_H
|
||||
#define API_CONFIG_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
DPX_HALF = 0,
|
||||
DPX_FULL,
|
||||
} duplex_t;
|
||||
|
||||
typedef enum {
|
||||
M_NONE = 1,
|
||||
M_SFP_FORCED_1000 = 7,
|
||||
M_SFP_FORCED_10G = 8,
|
||||
} media_t;
|
||||
|
||||
typedef enum {
|
||||
VL_NONE = 0,
|
||||
VL_TAGGED,
|
||||
VL_UNTAGGED,
|
||||
VL_FORBIDDEN
|
||||
} vlan_membership_t;
|
||||
|
||||
void *open_config_transaction();
|
||||
void commit_config_transaction(void *tr);
|
||||
|
||||
void add_eth_speed(void *tr, uint16_t eth_num, uint32_t speed, duplex_t duplex);
|
||||
void add_eth_media(void *tr, uint16_t eth_num, media_t media);
|
||||
|
||||
void add_l2_vlan(void *tr, uint16_t vlan_id,
|
||||
uint16_t *tagged_members, // NULL terminated array / NULL if not required
|
||||
uint16_t *un_tagged_members, // NULL terminated array / NULL if not required
|
||||
uint16_t *forbidden_members, // NULL terminated array / NULL if not required
|
||||
uint16_t *pvid_ports // NULL terminated array / NULL if not required
|
||||
);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef API_CONSTS_H
|
||||
#define API_CONSTS_H
|
||||
|
||||
#define STATUS_SUCCESS 0
|
||||
#define STATUS_ERROR 1
|
||||
#define STATUS_TIMEOUT 2
|
||||
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef API_DEVICEID_H
|
||||
#define API_DEVICEID_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "api_consts.h"
|
||||
|
||||
int dev_get_main_mac(char *mac, int mac_len);
|
||||
int dev_get_serial(char *serial, int serial_len);
|
||||
int dev_get_fw_version(char *fw, int fw_len);
|
||||
int dev_get_uptime(uint32_t *up);
|
||||
int dev_get_vlan_list(int *vlan_arr, int *num);
|
||||
int dev_get_vlan_mask_len(int *len);
|
||||
int dev_get_poe_port_num(int *num);
|
||||
int dev_get_port_capabilities_val_len(int *len);
|
||||
#endif
|
||||
@@ -1,13 +0,0 @@
|
||||
#ifndef API_PRINT_H
|
||||
#define API_PRINT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void print_set_debug(bool on);
|
||||
bool print_is_debug(void);
|
||||
|
||||
#define print_debug(...) if (print_is_debug()) { fprintf(stdout, __VA_ARGS__); }
|
||||
#define print_err(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef API_SESSION_H
|
||||
#define API_SESSION_H
|
||||
|
||||
#include "api_consts.h"
|
||||
|
||||
int session_start(void);
|
||||
void session_close(void);
|
||||
|
||||
#endif
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef API_STATS_H
|
||||
#define API_STATS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "api_consts.h"
|
||||
|
||||
#define IF_LOCATION_SIZE 16
|
||||
#define IF_NAME_SIZE 32
|
||||
|
||||
typedef struct {
|
||||
uint32_t collisions;
|
||||
uint64_t multicast ;
|
||||
uint64_t rx_bytes;
|
||||
uint32_t rx_dropped;
|
||||
uint32_t rx_errors;
|
||||
uint64_t rx_packets;
|
||||
uint64_t tx_bytes;
|
||||
uint32_t tx_dropped;
|
||||
uint32_t tx_errors;
|
||||
uint64_t tx_packets;
|
||||
} counters_t;
|
||||
|
||||
typedef struct {
|
||||
char location[IF_LOCATION_SIZE];
|
||||
char name[IF_NAME_SIZE];
|
||||
uint32_t uptime;
|
||||
uint32_t speed_dpx_status;
|
||||
counters_t counters;
|
||||
} interface_t;
|
||||
|
||||
int get_ethernet_count(int *eth_count);
|
||||
int get_ethernet_stats(interface_t *eths, int eth_count);
|
||||
int get_vlans(uint16_t **vlans, int *vlan_count);
|
||||
|
||||
#endif
|
||||
@@ -1,41 +0,0 @@
|
||||
#ifndef OID_DEFINE_H
|
||||
#define OID_DEFINE_H
|
||||
|
||||
#include <sys_adpt.h>
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
|
||||
const static oid O_MAIN_MAC[] = { SYS_ADPT_PRIVATEMIB_OID, 1, 5, 6, 1, 0 };
|
||||
const static oid O_SERIAL[] = { SYS_ADPT_PRIVATEMIB_OID, 1, 1, 3, 1, 10, 1 };
|
||||
const static oid O_OPCODE_VERSION[] = { SYS_ADPT_PRIVATEMIB_OID, 1, 1, 5, 4, 0 };
|
||||
const static oid O_SYS_UPTIME[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
|
||||
const static oid O_VLAN_STATUS[] = { 1, 3, 6, 1, 2, 1, 17, 7, 1, 4, 3, 1, 5};
|
||||
const static oid O_POE_PORT_ENABLE[] ={1, 3, 6, 1, 2, 1, 105, 1, 1, 1, 3, 1};
|
||||
const static oid O_PORT_CPAPBILITIES[] = { SYS_ADPT_PRIVATEMIB_OID, 1, 2, 1, 1, 6, 1 };
|
||||
|
||||
#define O_FACTORY_DEFAULT SYSTEM_OID"1.24.2.1.1.4.1.70.97.99.116.111.114.121.95.68.101.102.97.117.108.116.95.67.111.110.102.105.103.46.99.102.103"
|
||||
#define O_FW_UPGRADE_MGMT SYSTEM_OID"1.24.6.1.0"
|
||||
#define O_DEVICE_MODEL SYSTEM_OID"1.1.5.1.0"
|
||||
#define O_DEVICE_COMPANY SYSTEM_OID"1.1.5.2.0"
|
||||
#define O_STR_POE_PORT_ENABLE "1.3.6.1.2.1.105.1.1.1.3.1"
|
||||
#define O_STR_POE_MAX_POWER SYSTEM_OID"1.28.6.1.13.1"
|
||||
#define O_STR_POE_USAGE_THRESHOLD "1.3.6.1.2.1.105.1.3.1.1.5.1"
|
||||
#define O_STR_IF_ADMIN_STATUS "1.3.6.1.2.1.2.2.1.7"
|
||||
#define O_STR_PORT_CPAPBILITIES SYSTEM_OID"1.2.1.1.6"
|
||||
#define O_STR_PVID "1.3.6.1.2.1.17.7.1.4.5.1.1"
|
||||
#define O_STR_VLAN_NAME "1.3.6.1.2.1.17.7.1.4.3.1.1"
|
||||
#define O_STR_VLAN_EGRESS "1.3.6.1.2.1.17.7.1.4.3.1.2"
|
||||
#define O_STR_VLAN_STATUS "1.3.6.1.2.1.17.7.1.4.3.1.5"
|
||||
#define O_STR_VLAN_UNTAGGED "1.3.6.1.2.1.17.7.1.4.3.1.4"
|
||||
#define O_STR_COPY_SRC_TYPE SYSTEM_OID"1.24.1.1.0"
|
||||
#define O_STR_COPY_DST_TYPE SYSTEM_OID"1.24.1.3.0"
|
||||
#define O_STR_COPY_DST_NAME SYSTEM_OID"1.24.1.4.0"
|
||||
#define O_STR_COPY_FILE_TYPE SYSTEM_OID"1.24.1.5.0"
|
||||
#define O_STR_COPY_ACTION SYSTEM_OID"1.24.1.8.0"
|
||||
#define O_NTP_STATUS SYSTEM_OID"1.23.5.1.0"
|
||||
#define O_SNTP_STATUS SYSTEM_OID"1.23.1.1.0"
|
||||
#define O_SNTP_INTERVAL SYSTEM_OID"1.23.1.3.0"
|
||||
#define O_SNTP_SERVER_TYPE SYSTEM_OID"1.23.1.4.1.4"
|
||||
#define O_SNTP_SERVER_ADDR SYSTEM_OID"1.23.1.4.1.5"
|
||||
|
||||
#endif
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef SNMP_HELPER_H
|
||||
#define SNMP_HELPER_H
|
||||
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#include "oid_define.h"
|
||||
|
||||
int snmph_session_start(void);
|
||||
void snmph_session_close(void);
|
||||
|
||||
int snmph_get(const oid *req_oid, size_t req_oid_len, struct snmp_pdu **response);
|
||||
int snmph_get_argstr(const char *oid_str, struct snmp_pdu **response);
|
||||
int snmph_get_single_string(const oid *req_oid, size_t req_oid_len, char *buf, int buf_len);
|
||||
int snmph_get_bulk(const oid *req_oid, size_t req_oid_len, int max, struct snmp_pdu **response);
|
||||
int snmph_set(const char *oid_str, char type, char *value);
|
||||
int snmph_set_array(const char *oid_str, char type, const u_char *value, size_t len);
|
||||
int snmph_walk(const char *oid_str, void *buf, int *num);
|
||||
|
||||
enum snmp_walk_node {
|
||||
SNMP_WALK_NODE_NONE,
|
||||
SNMP_WALK_NODE_VLAN_STATUS,
|
||||
SNMP_WALK_NODE_POE_PORT_ENABLE,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
list(APPEND LIB_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/device.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/helper.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/session.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/stats.c
|
||||
)
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
#include <sys_adpt.h>
|
||||
|
||||
#include "api_device.h"
|
||||
#include "snmp_helper.h"
|
||||
|
||||
int dev_get_main_mac(char *mac, int mac_len) {
|
||||
int status = snmph_get_single_string(O_MAIN_MAC, OID_LENGTH(O_MAIN_MAC), mac, mac_len);
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
int i = 0, j = 2;
|
||||
|
||||
for (i = 3; i < 17; i += 3) {
|
||||
mac[j++] = mac[i];
|
||||
mac[j++] = mac[i + 1];
|
||||
}
|
||||
|
||||
mac[12] = 0;
|
||||
|
||||
char *c;
|
||||
|
||||
for (c = mac; *c; c++) {
|
||||
if (*c >= 'A' && *c <= 'Z') {
|
||||
*c += 32;
|
||||
}
|
||||
}
|
||||
|
||||
return STAT_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int dev_get_serial(char *serial, int serial_len) {
|
||||
return snmph_get_single_string(O_SERIAL, OID_LENGTH(O_SERIAL), serial, serial_len);
|
||||
}
|
||||
|
||||
int dev_get_fw_version(char *fw, int fw_len) {
|
||||
return snmph_get_single_string(O_OPCODE_VERSION, OID_LENGTH(O_OPCODE_VERSION), fw, fw_len);
|
||||
}
|
||||
|
||||
int dev_get_uptime(uint32_t *up) {
|
||||
struct snmp_pdu *response = NULL;
|
||||
int status = snmph_get(O_SYS_UPTIME, OID_LENGTH(O_SYS_UPTIME), &response);
|
||||
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
|
||||
*up = (uint32_t) (response->variables->val.integer[0] / 100 + 0.5);
|
||||
snmp_free_pdu(response);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int dev_get_vlan_list(int *vlan_arr, int *num) {
|
||||
int status;
|
||||
|
||||
status = snmph_walk(O_STR_VLAN_STATUS, vlan_arr, num);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int dev_get_vlan_mask_len(int *len) {
|
||||
char oidstr[MAX_OID_LEN];
|
||||
struct snmp_pdu *response;
|
||||
|
||||
sprintf(oidstr, "%s.%d", O_STR_VLAN_EGRESS, 1);
|
||||
int status = snmph_get_argstr(oidstr, &response);
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
fprintf(stderr, "Could not retrieve vlan mask length.\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
*len = response->variables->val_len;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int dev_get_poe_port_num(int *num) {
|
||||
int status;
|
||||
|
||||
status = snmph_walk(O_STR_POE_PORT_ENABLE, 0, num);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int dev_get_port_capabilities_val_len(int *len) {
|
||||
int status;
|
||||
struct snmp_pdu *response = NULL;
|
||||
|
||||
status = snmph_get(O_PORT_CPAPBILITIES, OID_LENGTH(O_PORT_CPAPBILITIES), &response);
|
||||
if (status == STATUS_SUCCESS)
|
||||
*len = response->variables->val_len;
|
||||
snmp_free_pdu(response);
|
||||
return status;
|
||||
}
|
||||
@@ -1,340 +0,0 @@
|
||||
/* MODULE NAME: snmp_helper.c
|
||||
* PURPOSE:
|
||||
* for ucentral middleware process.
|
||||
*
|
||||
* NOTES:
|
||||
*
|
||||
* REASON:
|
||||
* Description:
|
||||
* HISTORY
|
||||
* 2023/02/03 - Saulius P., Created
|
||||
*
|
||||
* Copyright(C) Accton Corporation, 2023
|
||||
*/
|
||||
/* INCLUDE FILE DECLARATIONS
|
||||
*/
|
||||
#include <math.h>
|
||||
#include "snmp_helper.h"
|
||||
#include "api_print.h"
|
||||
|
||||
static struct snmp_session session, *ss;
|
||||
|
||||
int snmph_session_start(void) {
|
||||
init_snmp("ucmw_snmp");
|
||||
snmp_sess_init( &session );
|
||||
|
||||
session.peername = "127.0.0.1";
|
||||
session.version = SNMP_VERSION_2c;
|
||||
session.community = (unsigned char*)"private";
|
||||
session.community_len = strlen((char*)session.community);
|
||||
|
||||
ss = snmp_open(&session);
|
||||
|
||||
if (ss) {
|
||||
return STAT_SUCCESS;
|
||||
} else {
|
||||
return STAT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
int snmph_set(const char *oid_str, char type, char *value) {
|
||||
netsnmp_pdu *pdu, *response = NULL;
|
||||
size_t name_length;
|
||||
oid name[MAX_OID_LEN];
|
||||
int status, exitval = 0;
|
||||
|
||||
pdu = snmp_pdu_create(SNMP_MSG_SET);
|
||||
name_length = MAX_OID_LEN;
|
||||
if (snmp_parse_oid(oid_str, name, &name_length) == NULL){
|
||||
snmp_perror(oid_str);
|
||||
return -1;
|
||||
} else{
|
||||
if (snmp_add_var(pdu, name, name_length, type, value)) {
|
||||
snmp_perror(oid_str);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
status = snmp_synch_response(ss, pdu, &response);
|
||||
if (status == STAT_SUCCESS) {
|
||||
if (response->errstat != SNMP_ERR_NOERROR) {
|
||||
fprintf(stderr, "Error in packet.\nReason: %s\n",
|
||||
snmp_errstring(response->errstat));
|
||||
exitval = 2;
|
||||
}
|
||||
} else if (status == STAT_TIMEOUT) {
|
||||
fprintf(stderr, "Timeout: No Response from %s\n",
|
||||
session.peername);
|
||||
exitval = 1;
|
||||
} else { /* status == STAT_ERROR */
|
||||
snmp_sess_perror("snmpset", ss);
|
||||
exitval = 1;
|
||||
}
|
||||
|
||||
if (response)
|
||||
snmp_free_pdu(response);
|
||||
|
||||
return exitval;
|
||||
}
|
||||
|
||||
int snmph_set_array(const char *oid_str, char type, const u_char *value, size_t len) {
|
||||
netsnmp_pdu *pdu, *response = NULL;
|
||||
size_t name_length;
|
||||
oid name[MAX_OID_LEN];
|
||||
int status, exitval = 0;
|
||||
|
||||
pdu = snmp_pdu_create(SNMP_MSG_SET);
|
||||
name_length = MAX_OID_LEN;
|
||||
if (snmp_parse_oid(oid_str, name, &name_length) == NULL){
|
||||
snmp_perror(oid_str);
|
||||
return -1;
|
||||
} else{
|
||||
if (!snmp_pdu_add_variable(pdu, name, name_length, type, value, len)) {
|
||||
snmp_perror(oid_str);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
status = snmp_synch_response(ss, pdu, &response);
|
||||
if (status == STAT_SUCCESS) {
|
||||
if (response->errstat != SNMP_ERR_NOERROR) {
|
||||
fprintf(stderr, "Error in packet.\nReason: %s\n",
|
||||
snmp_errstring(response->errstat));
|
||||
exitval = 2;
|
||||
}
|
||||
} else if (status == STAT_TIMEOUT) {
|
||||
fprintf(stderr, "Timeout: No Response from %s\n",
|
||||
session.peername);
|
||||
exitval = 1;
|
||||
} else { /* status == STAT_ERROR */
|
||||
snmp_sess_perror("snmpset", ss);
|
||||
exitval = 1;
|
||||
}
|
||||
|
||||
if (response)
|
||||
snmp_free_pdu(response);
|
||||
|
||||
return exitval;
|
||||
}
|
||||
|
||||
int snmph_get(const oid *req_oid, size_t req_oid_len, struct snmp_pdu **response) {
|
||||
struct snmp_pdu *request = snmp_pdu_create(SNMP_MSG_GET);
|
||||
snmp_add_null_var(request, req_oid, req_oid_len);
|
||||
|
||||
int status = snmp_synch_response(ss, request, response);
|
||||
|
||||
if (*response && (*response)->errstat != SNMP_ERR_NOERROR) {
|
||||
print_err("Error 1, response with error: %d, %ld\n", status, (*response)->errstat);
|
||||
snmp_free_pdu(*response);
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
if (!(*response)) {
|
||||
print_err("Error 2: empty SNMP response\n");
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
print_err("Error 3: bad response status: %d\n", status);
|
||||
snmp_free_pdu(*response);
|
||||
}
|
||||
|
||||
if (!(*response)->variables) {
|
||||
print_err("Error 4: empty variable list in response\n");
|
||||
snmp_free_pdu(*response);
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
print_debug("Default return: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
int snmph_get_argstr(const char *oid_str, struct snmp_pdu **response) {
|
||||
oid name[MAX_OID_LEN];
|
||||
size_t name_length = MAX_OID_LEN;
|
||||
|
||||
if (snmp_parse_oid(oid_str, name, &name_length) == NULL) {
|
||||
snmp_perror(oid_str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct snmp_pdu *request = snmp_pdu_create(SNMP_MSG_GET);
|
||||
snmp_add_null_var(request, name, name_length);
|
||||
|
||||
int status = snmp_synch_response(ss, request, response);
|
||||
|
||||
if (*response && (*response)->errstat != SNMP_ERR_NOERROR) {
|
||||
print_err("Error 1, response with error: %d, %ld\n", status, (*response)->errstat);
|
||||
snmp_free_pdu(*response);
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
if (!(*response)) {
|
||||
print_err("Error 2: empty SNMP response\n");
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
print_err("Error 3: bad response status: %d\n", status);
|
||||
snmp_free_pdu(*response);
|
||||
}
|
||||
|
||||
if (!(*response)->variables) {
|
||||
print_err("Error 4: empty variable list in response\n");
|
||||
snmp_free_pdu(*response);
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
print_debug("Default return: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
int snmph_get_single_string(const oid *req_oid, size_t req_oid_len, char *buf, int buf_len) {
|
||||
struct snmp_pdu *response = NULL;
|
||||
int status = snmph_get(req_oid, req_oid_len, &response);
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
memset(buf, 0, buf_len);
|
||||
strncpy(buf, (char*)response->variables->val.string, (int) fmin(buf_len, response->variables->val_len));
|
||||
|
||||
// if (response)
|
||||
snmp_free_pdu(response);
|
||||
|
||||
return STAT_SUCCESS;
|
||||
}
|
||||
|
||||
int snmph_get_bulk(const oid *req_oid, size_t req_oid_len, int max, struct snmp_pdu **response) {
|
||||
struct snmp_pdu *request = snmp_pdu_create(SNMP_MSG_GETBULK);
|
||||
request->non_repeaters = 0;
|
||||
request->max_repetitions = max;
|
||||
snmp_add_null_var(request, req_oid, req_oid_len);
|
||||
|
||||
int status = snmp_synch_response(ss, request, response);
|
||||
|
||||
// printf("Bulk status: %d\n", status);
|
||||
|
||||
if (status == 1) {
|
||||
snmp_sess_perror("snmpbulkget", ss);
|
||||
}
|
||||
|
||||
if (*response && (*response)->errstat != SNMP_ERR_NOERROR) {
|
||||
print_err("Error 1, bulk response error: %d, %ld\n", status, (*response)->errstat);
|
||||
snmp_free_pdu(*response);
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
if (!(*response)) {
|
||||
print_err("Error 2: empty bulk response\n");
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
print_err("Error 3, bad bulk status: %d\n", status);
|
||||
snmp_free_pdu(*response);
|
||||
}
|
||||
|
||||
if (!(*response)->variables) {
|
||||
print_err("Error 4, empty bulk variables\n");
|
||||
snmp_free_pdu(*response);
|
||||
return STAT_ERROR;
|
||||
}
|
||||
|
||||
print_debug("Default bulk return: %d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
int snmph_walk(const char *oid_str, void *buf, int *num) {
|
||||
netsnmp_pdu *pdu, *response = NULL;
|
||||
netsnmp_variable_list *vars;
|
||||
oid name[MAX_OID_LEN];
|
||||
size_t name_length = MAX_OID_LEN;
|
||||
int running = 1;
|
||||
int status = 0;
|
||||
enum snmp_walk_node node = SNMP_WALK_NODE_NONE;
|
||||
|
||||
if (snmp_parse_oid(oid_str, name, &name_length) == NULL) {
|
||||
snmp_perror(oid_str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp(oid_str, O_STR_VLAN_STATUS))
|
||||
node = SNMP_WALK_NODE_VLAN_STATUS;
|
||||
else if (!strcmp(oid_str, O_STR_POE_PORT_ENABLE))
|
||||
node = SNMP_WALK_NODE_POE_PORT_ENABLE;
|
||||
|
||||
*num = 0;
|
||||
|
||||
while (running) {
|
||||
/*
|
||||
* create PDU for GETNEXT request and add object name to request
|
||||
*/
|
||||
pdu = snmp_pdu_create(SNMP_MSG_GETNEXT);
|
||||
snmp_add_null_var(pdu, name, name_length);
|
||||
|
||||
/*
|
||||
* do the request
|
||||
*/
|
||||
status = snmp_synch_response(ss, pdu, &response);
|
||||
|
||||
if (status == STAT_SUCCESS) {
|
||||
if (response->errstat == SNMP_ERR_NOERROR) {
|
||||
/*
|
||||
* check resulting variables
|
||||
*/
|
||||
for (vars = response->variables; vars;
|
||||
vars = vars->next_variable) {
|
||||
|
||||
if (node == SNMP_WALK_NODE_VLAN_STATUS)
|
||||
{
|
||||
if ((vars->name[12]==O_VLAN_STATUS[12]) && (vars->name_length==(OID_LENGTH(O_VLAN_STATUS)+1)))
|
||||
{
|
||||
((int*)buf)[(*num)++] = vars->name[13];
|
||||
}
|
||||
else
|
||||
running = 0;
|
||||
}
|
||||
else if (node == SNMP_WALK_NODE_POE_PORT_ENABLE)
|
||||
{
|
||||
if ((vars->name[10]==O_POE_PORT_ENABLE[10]) && (vars->name_length==(OID_LENGTH(O_POE_PORT_ENABLE)+1)))
|
||||
{
|
||||
(*num)++;
|
||||
}
|
||||
else
|
||||
running = 0;
|
||||
}
|
||||
else
|
||||
running = 0;
|
||||
|
||||
memmove((char *) name, (char *) vars->name, vars->name_length * sizeof(oid));
|
||||
name_length = vars->name_length;
|
||||
|
||||
//print_variable(vars->name, vars->name_length, vars);
|
||||
}
|
||||
} else {
|
||||
running = 0;
|
||||
}
|
||||
} else if (status == STAT_TIMEOUT) {
|
||||
fprintf(stderr, "Timeout: No Response from %s\n",
|
||||
session.peername);
|
||||
running = 0;
|
||||
status = 1;
|
||||
|
||||
} else { /* status == STAT_ERROR */
|
||||
snmp_sess_perror("snmpwalk", ss);
|
||||
running = 0;
|
||||
status = 1;
|
||||
}
|
||||
if (response)
|
||||
snmp_free_pdu(response);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void snmph_session_close(void) {
|
||||
snmp_close(ss);
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "api_session.h"
|
||||
#include "snmp_helper.h"
|
||||
|
||||
int session_start() {
|
||||
return snmph_session_start();
|
||||
}
|
||||
|
||||
void session_close() {
|
||||
snmph_session_close();
|
||||
}
|
||||
@@ -1,250 +0,0 @@
|
||||
#include <sys_adpt.h>
|
||||
|
||||
#include "api_device.h"
|
||||
#include "api_stats.h"
|
||||
|
||||
#include "snmp_helper.h"
|
||||
|
||||
#include "if-mib/ifTable/ifTable_constants.h"
|
||||
|
||||
const static oid O_IF_COUNT[] = { 1, 3, 6, 1, 2, 1, 2, 1, 0 };
|
||||
const static oid O_IF_TYPE[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 3 };
|
||||
// const static oid O_IF_LAST_CHANGE[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 9 };
|
||||
const static oid O_IF_UPTIME[] = { SYS_ADPT_PRIVATEMIB_OID, 1, 2, 1, 1, 19 };
|
||||
const static oid O_SPEED_DPX_STATUS[] = { SYS_ADPT_PRIVATEMIB_OID, 1, 2, 1, 1, 8 };
|
||||
const static oid OID_IF_NAME[] = { SYS_ADPT_PRIVATEMIB_OID, 1, 2, 1, 1, 2 };
|
||||
|
||||
const static oid O_IF_RX_BYTES_64[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 6 };
|
||||
const static oid O_IF_RX_DISCARD_PKTS[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 13 };
|
||||
const static oid O_IF_RX_ERROR_PKTS[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 14 };
|
||||
const static oid O_IF_RX_U_PKTS_64[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 7 }; // Unicast packets
|
||||
const static oid O_IF_RX_MUL_PKTS_64[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 8 }; // Multicast packets
|
||||
const static oid O_IF_RX_BR_PKTS_64[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 9 };
|
||||
|
||||
const static oid O_IF_TX_BYTES_64[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 10 };
|
||||
const static oid O_IF_TX_DISCARD_PKTS[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 19 };
|
||||
const static oid O_IF_TX_ERROR_PKTS[] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 20 };
|
||||
const static oid O_IF_TX_U_PKTS_64[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 11 }; // Unicast packets
|
||||
const static oid O_IF_TX_MUL_PKTS_64[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 12 }; // Multicast packets
|
||||
const static oid O_IF_TX_BR_PKTS_64[] = { 1, 3, 6, 1, 2, 1, 31, 1, 1, 1, 13 };
|
||||
|
||||
int get_ethernet_count(int *eth_count) {
|
||||
struct snmp_pdu *response;
|
||||
|
||||
// printf("Try to retrieve IF count...\n");
|
||||
|
||||
int status = snmph_get(O_IF_COUNT, OID_LENGTH(O_IF_COUNT), &response);
|
||||
|
||||
// printf("Retrieved: %d\n", status);
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
// printf("Could not retrieve interfaces count\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
// printf("Interfaces: %ld\n", response->variables->val.integer[0]);
|
||||
long int max_if = response->variables->val.integer[0];
|
||||
|
||||
snmp_free_pdu(response);
|
||||
|
||||
struct variable_list *vars;
|
||||
|
||||
status = snmph_get_bulk(O_IF_TYPE, OID_LENGTH(O_IF_TYPE), max_if, &response);
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
// printf("Could not retrieve types\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
*eth_count = 0;
|
||||
|
||||
for(vars = response->variables; vars; vars = vars->next_variable) {
|
||||
// print_variable(vars->name, vars->name_length, vars);
|
||||
|
||||
if (vars->val.integer[0] == IANAIFTYPE_ETHERNETCSMACD) {
|
||||
(*eth_count)++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snmp_free_pdu(response);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int fill_ethernet_stats_32(const oid *req_oid, size_t req_oid_len, int max, uint32_t *val, bool aggregate) {
|
||||
struct snmp_pdu *response;
|
||||
struct variable_list *vars;
|
||||
int status = snmph_get_bulk(req_oid, req_oid_len, max, &response);
|
||||
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
uint32_t *addr = val;
|
||||
uint32_t local_val = 0;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(vars = response->variables; vars; vars = vars->next_variable) {
|
||||
memcpy(&local_val, &vars->val.integer[0], sizeof(uint32_t));
|
||||
|
||||
addr = (uint32_t *) ((char *) val + (sizeof(interface_t) * (i++)));
|
||||
|
||||
if (aggregate) {
|
||||
*addr += local_val;
|
||||
} else {
|
||||
*addr = local_val;
|
||||
}
|
||||
// addr = (uint32_t *) ((char *) addr + sizeof(interface_t));
|
||||
}
|
||||
|
||||
snmp_free_pdu(response);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int fill_ethernet_stats_64(const oid *req_oid, size_t req_oid_len, int max, uint64_t *val, bool aggregate) {
|
||||
struct snmp_pdu *response;
|
||||
struct variable_list *vars;
|
||||
int status = snmph_get_bulk(req_oid, req_oid_len, max, &response);
|
||||
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
uint64_t *addr = val;
|
||||
uint64_t local_val = 0;
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(vars = response->variables; vars; vars = vars->next_variable) {
|
||||
#ifdef ENDIANNESS_ADJUST
|
||||
memcpy(&local_val, &vars->val.counter64[0].low, sizeof(uint64_t));
|
||||
#else
|
||||
memcpy(&local_val, &vars->val.counter64[0], sizeof(uint64_t));
|
||||
#endif
|
||||
addr = (uint64_t *) ((char *) val + (sizeof(interface_t) * (i++)));
|
||||
if (aggregate) {
|
||||
*addr += local_val;
|
||||
} else {
|
||||
*addr = local_val;
|
||||
}
|
||||
// addr = (uint64_t *) ((char *) addr + sizeof(interface_t));
|
||||
}
|
||||
|
||||
snmp_free_pdu(response);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int get_ethernet_stats(interface_t *eths, int eth_count) {
|
||||
uint32_t uptime;
|
||||
|
||||
if (dev_get_uptime(&uptime) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
/***************** Interface uptime *****************/
|
||||
if (fill_ethernet_stats_32(O_IF_UPTIME, OID_LENGTH(O_IF_UPTIME), eth_count, ðs[0].uptime, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
if (fill_ethernet_stats_32(O_SPEED_DPX_STATUS, OID_LENGTH(O_SPEED_DPX_STATUS), eth_count, ðs[0].speed_dpx_status, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
|
||||
int i;
|
||||
|
||||
for (i = 0; i < eth_count; i++) {
|
||||
if (eths[i].uptime) {
|
||||
eths[i].uptime /= 100;// uptime - (eths[i].uptime / 100);
|
||||
}
|
||||
|
||||
snprintf(eths[i].location, IF_LOCATION_SIZE, "%d", i);
|
||||
}
|
||||
|
||||
struct snmp_pdu *response;
|
||||
struct variable_list *vars;
|
||||
int status = snmph_get_bulk(OID_IF_NAME, OID_LENGTH(OID_IF_NAME), eth_count, &response);
|
||||
|
||||
if (status != STATUS_SUCCESS) return status;
|
||||
|
||||
i = 0;
|
||||
for(vars = response->variables; vars || i < eth_count; vars = vars->next_variable) {
|
||||
strncpy(eths[i].name, (char *)vars->val.string, IF_NAME_SIZE > vars->val_len ? vars->val_len : IF_NAME_SIZE);
|
||||
i++;
|
||||
}
|
||||
|
||||
snmp_free_pdu(response);
|
||||
|
||||
/***************** Bytes (octets) *****************/
|
||||
if (fill_ethernet_stats_64(O_IF_RX_BYTES_64, OID_LENGTH(O_IF_RX_BYTES_64), eth_count, ðs[0].counters.rx_bytes, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
if (fill_ethernet_stats_64(O_IF_TX_BYTES_64, OID_LENGTH(O_IF_TX_BYTES_64), eth_count, ðs[0].counters.tx_bytes, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
|
||||
/***************** Packets *****************/
|
||||
if (fill_ethernet_stats_64(O_IF_RX_MUL_PKTS_64, OID_LENGTH(O_IF_RX_MUL_PKTS_64), eth_count, ðs[0].counters.rx_packets, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
if (fill_ethernet_stats_64(O_IF_TX_MUL_PKTS_64, OID_LENGTH(O_IF_TX_MUL_PKTS_64), eth_count, ðs[0].counters.tx_packets, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
|
||||
// "Multicast is the sum of rx+tx multicast packets"
|
||||
for (i = 0; i < eth_count; i++) {
|
||||
eths[i].counters.multicast = eths[i].counters.rx_packets + eths[i].counters.tx_packets;
|
||||
}
|
||||
|
||||
// All packets is a sum (aggregate == true) of unicast, multicast and broadcast packets
|
||||
if (fill_ethernet_stats_64(O_IF_RX_U_PKTS_64, OID_LENGTH(O_IF_RX_U_PKTS_64), eth_count, ðs[0].counters.rx_packets, true) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
if (fill_ethernet_stats_64(O_IF_RX_BR_PKTS_64, OID_LENGTH(O_IF_RX_BR_PKTS_64), eth_count, ðs[0].counters.rx_packets, true) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
|
||||
if (fill_ethernet_stats_64(O_IF_TX_U_PKTS_64, OID_LENGTH(O_IF_TX_U_PKTS_64), eth_count, ðs[0].counters.tx_packets, true) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
if (fill_ethernet_stats_64(O_IF_TX_BR_PKTS_64, OID_LENGTH(O_IF_TX_BR_PKTS_64), eth_count, ðs[0].counters.tx_packets, true) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
|
||||
|
||||
/***************** Errors *****************/
|
||||
if (fill_ethernet_stats_32(O_IF_RX_ERROR_PKTS, OID_LENGTH(O_IF_RX_ERROR_PKTS), eth_count, ðs[0].counters.rx_errors, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
if (fill_ethernet_stats_32(O_IF_TX_ERROR_PKTS, OID_LENGTH(O_IF_TX_ERROR_PKTS), eth_count, ðs[0].counters.tx_errors, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
|
||||
/***************** Dropped *****************/
|
||||
if (fill_ethernet_stats_32(O_IF_RX_DISCARD_PKTS, OID_LENGTH(O_IF_RX_DISCARD_PKTS), eth_count, ðs[0].counters.rx_dropped, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
if (fill_ethernet_stats_32(O_IF_TX_DISCARD_PKTS, OID_LENGTH(O_IF_TX_DISCARD_PKTS), eth_count, ðs[0].counters.tx_dropped, false) != STATUS_SUCCESS) return STATUS_ERROR;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int get_vlans(uint16_t **vlans, int *vlan_count) {
|
||||
struct snmp_pdu *response;
|
||||
struct variable_list *vars;
|
||||
|
||||
// printf("Try to retrieve IF count...\n");
|
||||
|
||||
int status = snmph_get(O_IF_COUNT, OID_LENGTH(O_IF_COUNT), &response);
|
||||
|
||||
// printf("Retrieved: %d\n", status);
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
printf("Could not retrieve interfaces count\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
// printf("Interfaces: %ld\n", response->variables->val.integer[0]);
|
||||
long int max_if = response->variables->val.integer[0];
|
||||
|
||||
status = snmph_get_bulk(O_IF_TYPE, OID_LENGTH(O_IF_TYPE), max_if, &response);
|
||||
|
||||
if (status != STAT_SUCCESS) {
|
||||
// printf("VLANS: could not retrieve types\n");
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
*vlan_count = 0;
|
||||
|
||||
for(vars = response->variables; vars; vars = vars->next_variable) {
|
||||
// print_variable(vars->name, vars->name_length, vars);
|
||||
|
||||
if (vars->val.integer[0] == IANAIFTYPE_L2VLAN || vars->val.integer[0] == IANAIFTYPE_L3IPVLAN) {
|
||||
// printf("Found VLAN: %d\n", (int) vars->name[vars->name_length - 1]);
|
||||
(*vlan_count)++;
|
||||
}
|
||||
}
|
||||
|
||||
(*vlans) = malloc(sizeof(uint16_t) * (*vlan_count));
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(vars = response->variables; vars; vars = vars->next_variable) {
|
||||
// print_variable(vars->name, vars->name_length, vars);
|
||||
|
||||
if (vars->val.integer[0] == IANAIFTYPE_L2VLAN || vars->val.integer[0] == IANAIFTYPE_L3IPVLAN) {
|
||||
(*vlans)[i++] = (uint16_t) ((int) vars->name[vars->name_length - 1] - 1000);
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
diff -Nuar a/CMakeLists.txt b/CMakeLists.txt
|
||||
--- a/CMakeLists.txt 2023-07-21 09:53:57.450424222 +0800
|
||||
+++ b/CMakeLists.txt 2023-07-21 11:36:15.395258277 +0800
|
||||
@@ -1,4 +1,4 @@
|
||||
-#***************************************************************************
|
||||
+#***************************************************************************
|
||||
# _ _ ____ _
|
||||
# Project ___| | | | _ \| |
|
||||
# / __| | | | |_) | |
|
||||
@@ -185,9 +185,9 @@
|
||||
mark_as_advanced(CURL_DISABLE_HTTP_AUTH)
|
||||
option(CURL_DISABLE_IMAP "disables IMAP" OFF)
|
||||
mark_as_advanced(CURL_DISABLE_IMAP)
|
||||
-option(CURL_DISABLE_LDAP "disables LDAP" OFF)
|
||||
+option(CURL_DISABLE_LDAP "disables LDAP" ON)
|
||||
mark_as_advanced(CURL_DISABLE_LDAP)
|
||||
-option(CURL_DISABLE_LDAPS "disables LDAPS" OFF)
|
||||
+option(CURL_DISABLE_LDAPS "disables LDAPS" ON)
|
||||
mark_as_advanced(CURL_DISABLE_LDAPS)
|
||||
option(CURL_DISABLE_LIBCURL_OPTION "disables --libcurl option from the curl tool" OFF)
|
||||
mark_as_advanced(CURL_DISABLE_LIBCURL_OPTION)
|
||||
@@ -433,7 +433,7 @@
|
||||
endif()
|
||||
|
||||
if(CURL_USE_OPENSSL)
|
||||
- find_package(OpenSSL REQUIRED)
|
||||
+ #find_package(OpenSSL REQUIRED)
|
||||
set(SSL_ENABLED ON)
|
||||
set(USE_OPENSSL ON)
|
||||
|
||||
@@ -441,7 +441,7 @@
|
||||
# version of CMake. This allows our dependents to get our dependencies
|
||||
# transitively.
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.4)
|
||||
- list(APPEND CURL_LIBS OpenSSL::SSL OpenSSL::Crypto)
|
||||
+ #list(APPEND CURL_LIBS OpenSSL::SSL OpenSSL::Crypto)
|
||||
else()
|
||||
list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
|
||||
include_directories(${OPENSSL_INCLUDE_DIR})
|
||||
@@ -595,7 +595,7 @@
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
|
||||
check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP)
|
||||
check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER)
|
||||
-
|
||||
+
|
||||
set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES})
|
||||
set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
|
||||
if(CMAKE_LDAP_INCLUDE_DIR)
|
||||
@@ -1369,12 +1369,16 @@
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
|
||||
+INCLUDE_DIRECTORIES(../openssl/include)
|
||||
+FIND_LIBRARY(openssl ssl ../openssl)
|
||||
+
|
||||
add_subdirectory(lib)
|
||||
|
||||
if(BUILD_CURL_EXE)
|
||||
add_subdirectory(src)
|
||||
endif()
|
||||
|
||||
+
|
||||
cmake_dependent_option(BUILD_TESTING "Build tests"
|
||||
ON "PERL_FOUND;NOT CURL_DISABLE_TESTS"
|
||||
OFF)
|
||||
diff -Nuar a/src/CMakeLists.txt b/src/CMakeLists.txt
|
||||
--- a/src/CMakeLists.txt 2023-07-21 13:47:10.160906907 +0800
|
||||
+++ b/src/CMakeLists.txt 2023-07-21 13:49:45.205682320 +0800
|
||||
@@ -98,6 +98,9 @@
|
||||
|
||||
#Build curl executable
|
||||
target_link_libraries(${EXE_NAME} libcurl ${CURL_LIBS})
|
||||
+target_link_libraries(${EXE_NAME} -lssl)
|
||||
+target_link_libraries(${EXE_NAME} -lcrypto)
|
||||
+target_link_libraries(${EXE_NAME} ${CMAKE_SHARED_LINKER_FLAGS})
|
||||
|
||||
################################################################################
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
--- a/CMakeLists.txt 2020-10-26 04:31:31.000000000 -0700
|
||||
+++ b/CMakeLists.txt 2023-04-10 20:15:13.399705011 -0700
|
||||
@@ -102,8 +102,9 @@
|
||||
|
||||
|
||||
# ideally we want to use pipe2()
|
||||
-
|
||||
-CHECK_C_SOURCE_COMPILES("#define _GNU_SOURCE\n#include <unistd.h>\nint main(void) {int fd[2];\n return pipe2(fd, 0);\n}\n" LWS_HAVE_PIPE2)
|
||||
+# jacky
|
||||
+# comment out this line, use pipe() instead of pipe2()
|
||||
+#CHECK_C_SOURCE_COMPILES("#define _GNU_SOURCE\n#include <unistd.h>\nint main(void) {int fd[2];\n return pipe2(fd, 0);\n}\n" LWS_HAVE_PIPE2)
|
||||
|
||||
# tcp keepalive needs this on linux to work practically... but it only exists
|
||||
# after kernel 2.6.37
|
||||
@@ -1,49 +0,0 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
PROJECT(ucentral-client C)
|
||||
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "-Wl,--copy-dt-needed-entries")
|
||||
SET(LDFLAGS -fopenmp -Wl,--copy-dt-needed-entries)
|
||||
|
||||
INCLUDE_DIRECTORIES(src/include)
|
||||
INCLUDE_DIRECTORIES(../)
|
||||
INCLUDE_DIRECTORIES(../curl/include)
|
||||
INCLUDE_DIRECTORIES(../libwebsockets/include)
|
||||
INCLUDE_DIRECTORIES(../openssl/include)
|
||||
INCLUDE_DIRECTORIES(ucentral-client/include)
|
||||
INCLUDE_DIRECTORIES(ucentral-client)
|
||||
|
||||
INCLUDE_DIRECTORIES(src/include)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/../ecapi/include)
|
||||
INCLUDE_DIRECTORIES($ENV{SOURCE_PATH}/sysinclude)
|
||||
INCLUDE_DIRECTORIES($ENV{SOURCE_PATH}/sysinclude/mibconstants)
|
||||
INCLUDE_DIRECTORIES($ENV{SOURCE_PATH}/sysinclude/oem/$ENV{PROJECT_NAME})
|
||||
INCLUDE_DIRECTORIES($ENV{PROJECT_PATH}/user/thirdpty/lua/net-snmp-5.4.4/include)
|
||||
|
||||
add_definitions(-DPLAT_EC)
|
||||
|
||||
if ($ENV{D_MODEL_NAME} STREQUAL ECS4130_AC5)
|
||||
add_definitions(-DENDIANNESS_ADJUST)
|
||||
add_definitions(-DNOT_SUPPORT_CAP_2500)
|
||||
add_definitions(-DNOT_SUPPORT_NTP_DOMAIN_NAME)
|
||||
add_definitions(-DSYSTEM_OID="1.3.6.1.4.1.259.10.1.55.")
|
||||
elseif ($ENV{D_MODEL_NAME} STREQUAL ECS4125_10P)
|
||||
add_definitions(-DSYSTEM_OID="1.3.6.1.4.1.259.10.1.57.")
|
||||
else()
|
||||
message(FATAL_ERROR "not support $ENV{D_MODEL_NAME}")
|
||||
endif()
|
||||
|
||||
INCLUDE(ucentral-client/CMakeLists.txt)
|
||||
INCLUDE(ucentral-client/platform/ec/CMakeLists.txt)
|
||||
|
||||
FIND_LIBRARY(cjson cjson ../cjson)
|
||||
FIND_LIBRARY(curl curl ../curl/lib)
|
||||
FIND_LIBRARY(openssl ssl ../openssl)
|
||||
FIND_LIBRARY(websockets websockets ../libwebsockets/lib)
|
||||
FIND_LIBRARY(crypto crypto ../openssl)
|
||||
|
||||
FIND_LIBRARY(ecapi_library ecapi ../ecapi/build)
|
||||
FIND_LIBRARY(netsnmp_library netsnmp $ENV{PROJECT_PATH}/user/thirdpty/lua/net-snmp-5.4.4/snmplib/.libs)
|
||||
|
||||
ADD_EXECUTABLE(ucentral-client ${UC_SOURCES} ${PLAT_SOURCES})
|
||||
|
||||
TARGET_LINK_LIBRARIES(ucentral-client ${cjson} ${curl} ${openssl} ${crypto} ${websockets} ${netsnmp_library} ${ecapi_library})
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
list(APPEND UC_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/proto.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/router-utils.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/ucentral-json-parser.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/ucentral-log.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/ucentral-client.c
|
||||
${CMAKE_CURRENT_LIST_DIR}/inet_net_pton.c
|
||||
)
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1996,1999 by Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef SPRINTF_CHAR
|
||||
# define SPRINTF(x) strlen(sprintf/**/x)
|
||||
#else
|
||||
# define SPRINTF(x) ((size_t)sprintf x)
|
||||
#endif
|
||||
|
||||
static int inet_net_pton_ipv4 (const char *src, u_char *dst,
|
||||
size_t size) __THROW;
|
||||
|
||||
# define __rawmemchr strchr
|
||||
|
||||
/*
|
||||
* static int
|
||||
* inet_net_pton(af, src, dst, size)
|
||||
* convert network number from presentation to network format.
|
||||
* accepts hex octets, hex strings, decimal octets, and /CIDR.
|
||||
* "size" is in bytes and describes "dst".
|
||||
* return:
|
||||
* number of bits, either imputed classfully or specified with /CIDR,
|
||||
* or -1 if some failure occurred (check errno). ENOENT means it was
|
||||
* not a valid network specification.
|
||||
* author:
|
||||
* Paul Vixie (ISC), June 1996
|
||||
*/
|
||||
int
|
||||
inet_net_pton (int af, const char *src, void *dst, size_t size)
|
||||
{
|
||||
switch (af) {
|
||||
case AF_INET:
|
||||
return (inet_net_pton_ipv4(src, dst, size));
|
||||
default:
|
||||
//__set_errno (EAFNOSUPPORT);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* static int
|
||||
* inet_net_pton_ipv4(src, dst, size)
|
||||
* convert IPv4 network number from presentation to network format.
|
||||
* accepts hex octets, hex strings, decimal octets, and /CIDR.
|
||||
* "size" is in bytes and describes "dst".
|
||||
* return:
|
||||
* number of bits, either imputed classfully or specified with /CIDR,
|
||||
* or -1 if some failure occurred (check errno). ENOENT means it was
|
||||
* not an IPv4 network specification.
|
||||
* note:
|
||||
* network byte order assumed. this means 192.5.5.240/28 has
|
||||
* 0b11110000 in its fourth octet.
|
||||
* author:
|
||||
* Paul Vixie (ISC), June 1996
|
||||
*/
|
||||
static int
|
||||
inet_net_pton_ipv4 (const char *src, u_char *dst, size_t size)
|
||||
{
|
||||
static const char xdigits[] = "0123456789abcdef";
|
||||
int n, ch, tmp, dirty, bits;
|
||||
const u_char *odst = dst;
|
||||
|
||||
ch = *src++;
|
||||
if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
|
||||
&& isascii(src[1]) && isxdigit(src[1])) {
|
||||
/* Hexadecimal: Eat nybble string. */
|
||||
if (size <= 0)
|
||||
goto emsgsize;
|
||||
dirty = 0;
|
||||
tmp = 0; /* To calm down gcc. */
|
||||
src++; /* skip x or X. */
|
||||
while (isxdigit((ch = *src++))) {
|
||||
ch = _tolower(ch);
|
||||
n = (const char *) __rawmemchr(xdigits, ch) - xdigits;
|
||||
assert(n >= 0 && n <= 15);
|
||||
if (dirty == 0)
|
||||
tmp = n;
|
||||
else
|
||||
tmp = (tmp << 4) | n;
|
||||
if (++dirty == 2) {
|
||||
if (size-- <= 0)
|
||||
goto emsgsize;
|
||||
*dst++ = (u_char) tmp;
|
||||
dirty = 0;
|
||||
}
|
||||
}
|
||||
if (dirty) { /* Odd trailing nybble? */
|
||||
if (size-- <= 0)
|
||||
goto emsgsize;
|
||||
*dst++ = (u_char) (tmp << 4);
|
||||
}
|
||||
} else if (isascii(ch) && isdigit(ch)) {
|
||||
/* Decimal: eat dotted digit string. */
|
||||
for (;;) {
|
||||
tmp = 0;
|
||||
do {
|
||||
n = ((const char *) __rawmemchr(xdigits, ch)
|
||||
- xdigits);
|
||||
assert(n >= 0 && n <= 9);
|
||||
tmp *= 10;
|
||||
tmp += n;
|
||||
if (tmp > 255)
|
||||
goto enoent;
|
||||
} while (isascii((ch = *src++)) && isdigit(ch));
|
||||
if (size-- <= 0)
|
||||
goto emsgsize;
|
||||
*dst++ = (u_char) tmp;
|
||||
if (ch == '\0' || ch == '/')
|
||||
break;
|
||||
if (ch != '.')
|
||||
goto enoent;
|
||||
ch = *src++;
|
||||
if (!isascii(ch) || !isdigit(ch))
|
||||
goto enoent;
|
||||
}
|
||||
} else
|
||||
goto enoent;
|
||||
|
||||
bits = -1;
|
||||
if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
|
||||
/* CIDR width specifier. Nothing can follow it. */
|
||||
ch = *src++; /* Skip over the /. */
|
||||
bits = 0;
|
||||
do {
|
||||
n = (const char *) __rawmemchr(xdigits, ch) - xdigits;
|
||||
assert(n >= 0 && n <= 9);
|
||||
bits *= 10;
|
||||
bits += n;
|
||||
} while (isascii((ch = *src++)) && isdigit(ch));
|
||||
if (ch != '\0')
|
||||
goto enoent;
|
||||
if (bits > 32)
|
||||
goto emsgsize;
|
||||
}
|
||||
|
||||
/* Firey death and destruction unless we prefetched EOS. */
|
||||
if (ch != '\0')
|
||||
goto enoent;
|
||||
|
||||
/* If nothing was written to the destination, we found no address. */
|
||||
if (dst == odst)
|
||||
goto enoent;
|
||||
/* If no CIDR spec was given, infer width from net class. */
|
||||
if (bits == -1) {
|
||||
if (*odst >= 240) /* Class E */
|
||||
bits = 32;
|
||||
else if (*odst >= 224) /* Class D */
|
||||
bits = 4;
|
||||
else if (*odst >= 192) /* Class C */
|
||||
bits = 24;
|
||||
else if (*odst >= 128) /* Class B */
|
||||
bits = 16;
|
||||
else /* Class A */
|
||||
bits = 8;
|
||||
/* If imputed mask is narrower than specified octets, widen. */
|
||||
if (bits >= 8 && bits < ((dst - odst) * 8))
|
||||
bits = (dst - odst) * 8;
|
||||
}
|
||||
/* Extend network to cover the actual mask. */
|
||||
while (bits > ((dst - odst) * 8)) {
|
||||
if (size-- <= 0)
|
||||
goto emsgsize;
|
||||
*dst++ = '\0';
|
||||
}
|
||||
return (bits);
|
||||
|
||||
enoent:
|
||||
//__set_errno (ENOENT);
|
||||
return (-1);
|
||||
|
||||
emsgsize:
|
||||
//__set_errno (EMSGSIZE);
|
||||
return (-1);
|
||||
}
|
||||
@@ -4,3 +4,8 @@ ntp server 1.pool.ntp.org prefer true
|
||||
ntp server 2.pool.ntp.org prefer true
|
||||
ntp server 3.pool.ntp.org prefer true
|
||||
ntp authenticate
|
||||
ip dhcp snooping
|
||||
ip dhcp snooping Vlan1
|
||||
ntp source-interface Vlan 1
|
||||
interface range Ethernet 0-100
|
||||
no ip dhcp snooping trust
|
||||
|
||||
2
src/scripts/OLS_NOS_upgrade_override.script
Normal file
2
src/scripts/OLS_NOS_upgrade_override.script
Normal file
@@ -0,0 +1,2 @@
|
||||
configure terminal
|
||||
no ip vrf mgmt
|
||||
@@ -11,6 +11,7 @@ start() {
|
||||
fi
|
||||
|
||||
cp /usr/local/lib/OLS_NOS_fixups.script /home/admin/OLS_NOS_fixups.script
|
||||
cp /usr/local/lib/OLS_NOS_upgrade_override.script /home/admin/OLS_NOS_upgrade_override.script
|
||||
|
||||
if [ $(systemctl is-active config-setup.service) == "active" ]; then
|
||||
# do nothing on service restart
|
||||
@@ -29,11 +30,23 @@ start() {
|
||||
}
|
||||
|
||||
wait() {
|
||||
test -d /var/lib/ucentral || mkdir /var/lib/ucentral
|
||||
|
||||
# Wait for at least one Vlan to be created - a signal that telemetry is up.
|
||||
# Even if vlan table is empty, private 3967 will be allocated with all
|
||||
# ports in it.
|
||||
while ! ls /sys/class/net/Vlan* &>/dev/null; do sleep 1; done
|
||||
|
||||
# Detect first boot on this version
|
||||
# Run upgrade overrides before fixups
|
||||
conf_upgrade_md5sum=$(md5sum /home/admin/OLS_NOS_upgrade_override.script | cut -d ' ' -f1)
|
||||
if test "$conf_upgrade_md5sum" != "$(test -f /var/lib/ucentral/upgrade-override.md5sum && cat /var/lib/ucentral/upgrade-override.md5sum)"; then
|
||||
sudo -u admin -- bash "sonic-cli" "/home/admin/OLS_NOS_upgrade_override.script"
|
||||
echo -n "$conf_upgrade_md5sum" >/var/lib/ucentral/upgrade-override.md5sum
|
||||
fi
|
||||
|
||||
sudo touch /etc/default/in-band-dhcp
|
||||
|
||||
# Temporary NTP fixup / WA: configure a list of default NTP servers.
|
||||
# Should mature into a default-config option to make sure board has right
|
||||
# time upon any boot (especially first time).
|
||||
@@ -48,6 +61,8 @@ wait() {
|
||||
# NOTE: alternatively we could use ifplugd. This also handle del/add scenario
|
||||
ifup Vlan1 || true
|
||||
|
||||
config vlan dhcp 1 enable
|
||||
|
||||
# There's an issue with containers starting before DNS server is configured:
|
||||
# resolf.conf file get copied from host to container upon container start.
|
||||
# This means, that if resolf.conf gets altered (on host) after container's been
|
||||
@@ -63,9 +78,19 @@ wait() {
|
||||
# This also means, that we won't start up untill this URI is accessible.
|
||||
while ! curl clientauth.one.digicert.com &>/dev/null; do sleep 1; done
|
||||
|
||||
# Enable DHCP trusting for uplink (Vlan1) iface
|
||||
# It's needed to forward DHCP Discover (and replies) from/to DHCP server
|
||||
# of (untrusted) port clients (EthernetX) of the same Vlan (Vlan1).
|
||||
# Without this fix underlying Vlan members wouldn't be able to receive
|
||||
# DHCP-lease IP
|
||||
trusted_dhcp_if=`sudo -u admin -- bash "sonic-cli" "-c" "show ip arp" | grep -Eo "Ethernet[0-9]+"`
|
||||
sudo -u admin -- "echo" "configure terminal" > /home/admin/fixup_scr.script
|
||||
sudo -u admin -- "echo" "interface $trusted_dhcp_if" >> /home/admin/fixup_scr.script
|
||||
sudo -u admin -- "echo" "ip dhcp snooping trust" >> /home/admin/fixup_scr.script
|
||||
sudo -u admin -- bash "sonic-cli" "/home/admin/fixup_scr.script"
|
||||
|
||||
# change admin password
|
||||
# NOTE: This could lead to access escalation, if you got image from running device
|
||||
test -d /var/lib/ucentral || mkdir /var/lib/ucentral
|
||||
if ! test -f /var/lib/ucentral/admin-cred.changed; then
|
||||
#ADMIN_PASSWD=`openssl rand -hex 10`
|
||||
ADMIN_PASSWD=broadcom
|
||||
|
||||
@@ -154,6 +154,11 @@
|
||||
"vlanid": "1"
|
||||
}
|
||||
},
|
||||
"VLAN_INTERFACE": {
|
||||
"Vlan1": {
|
||||
"dhcp": "enable"
|
||||
}
|
||||
},
|
||||
"VLAN_MEMBER": {
|
||||
{% for port in PORT %}
|
||||
"Vlan1|{{port}}": {
|
||||
@@ -164,11 +169,6 @@
|
||||
"INTERFACE": {
|
||||
"Vlan1": {}
|
||||
},
|
||||
"MGMT_VRF_CONFIG": {
|
||||
"vrf_global": {
|
||||
"mgmtVrfEnabled": "true"
|
||||
}
|
||||
},
|
||||
"VRF": {
|
||||
"default": {
|
||||
"enabled": "true"
|
||||
|
||||
@@ -19,7 +19,7 @@ platform/plat.a:
|
||||
|
||||
ucentral-client: ucentral-client.o proto.o platform/plat.a \
|
||||
ucentral-json-parser.o ucentral-log.o router-utils.o base64.o
|
||||
g++ -o $@ $^ -lcurl -lwebsockets -lcjson -lssl -lcrypto -lpthread -ljsoncpp -lresolv
|
||||
g++ -g -o $@ $^ -lcurl -lwebsockets -lcjson -lssl -lcrypto -lpthread -ljsoncpp -lresolv -lhiredis
|
||||
|
||||
test:
|
||||
@echo "========= running unit tests ========="
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
#ifndef ROUTER_UTILS_H
|
||||
#define ROUTER_UTILS_H
|
||||
|
||||
/* Defines router types and utils for them (lookup/etc) */
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct ucentral_router_fib_key {
|
||||
/* TODO vrf */
|
||||
struct in_addr prefix;
|
||||
int prefix_len;
|
||||
} key;
|
||||
};
|
||||
|
||||
struct ucentral_router_fib_info { /* Destination info */
|
||||
enum {
|
||||
@@ -46,16 +53,16 @@ struct ucentral_router {
|
||||
|
||||
struct ucentral_router_fib_db_apply_args {
|
||||
/* plat whould check info to determine if node channged */
|
||||
int (*upd_cb)(const struct ucentral_router_fib_node *old,
|
||||
int (*upd_cb)(const struct ucentral_router_fib_node *old_node,
|
||||
int olen,
|
||||
const struct ucentral_router_fib_node *new,
|
||||
const struct ucentral_router_fib_node *new_node,
|
||||
int nlen,
|
||||
void *arg);
|
||||
/* prefix = new, info = new */
|
||||
int (*add_cb)(const struct ucentral_router_fib_node *new,
|
||||
int (*add_cb)(const struct ucentral_router_fib_node *new_node,
|
||||
int len, void *arg);
|
||||
/* prefix = none */
|
||||
int (*del_cb)(const struct ucentral_router_fib_node *old,
|
||||
int (*del_cb)(const struct ucentral_router_fib_node *old_node,
|
||||
int len, void *arg);
|
||||
void *arg;
|
||||
};
|
||||
@@ -69,26 +76,32 @@ int ucentral_router_fib_db_append(struct ucentral_router *r,
|
||||
struct ucentral_router_fib_node *n);
|
||||
int ucentral_router_fib_key_cmp(const struct ucentral_router_fib_key *a,
|
||||
const struct ucentral_router_fib_key *b);
|
||||
bool ucentral_router_fib_info_cmp(const struct ucentral_router_fib_info *a,
|
||||
const struct ucentral_router_fib_info *b);
|
||||
int ucentral_router_fib_info_cmp(const struct ucentral_router_fib_info *a,
|
||||
const struct ucentral_router_fib_info *b);
|
||||
|
||||
#define router_db_get(R, I) (I < (R)->len ? &(R)->arr[(I)] : NULL)
|
||||
|
||||
#define for_router_db_diff_CASE_UPD(DIFF) if (!(DIFF))
|
||||
#define for_router_db_diff_CASE_DEL(DIFF) if ((DIFF) > 0)
|
||||
#define for_router_db_diff_CASE_ADD(DIFF) if ((DIFF) < 0)
|
||||
#define diff_case_upd(DIFF) (!(DIFF))
|
||||
#define diff_case_del(DIFF) ((DIFF) > 0)
|
||||
#define diff_case_add(DIFF) ((DIFF) < 0)
|
||||
#define router_db_diff_get(NEW, OLD, INEW, IOLD) \
|
||||
(IOLD) == (OLD)->len \
|
||||
? -1 \
|
||||
: (INEW) == (NEW)->len \
|
||||
? 1 \
|
||||
: ucentral_router_fib_key_cmp(&(NEW)->arr[(INEW)].key, &(OLD)->arr[(IOLD)].key)
|
||||
#define for_router_db_diff(NEW, OLD, INEW, IOLD, DIFF) \
|
||||
for ((INEW) = 0, (IOLD) = 0, (NEW)->sorted ? 0 : ucentral_router_fib_db_sort((NEW)), (OLD)->sorted ? 0 : ucentral_router_fib_db_sort((OLD)); \
|
||||
((IOLD) != (OLD)->len || (INEW) != (NEW)->len) && \
|
||||
(( \
|
||||
(DIFF) = (IOLD) == (OLD)->len ? -1 : (INEW) == (NEW)->len ? 1 : ucentral_router_fib_key_cmp(&(NEW)->arr[(INEW)].key, &(OLD)->arr[(IOLD)].key) \
|
||||
) || 1); \
|
||||
(DIFF) == 0 ? ++(INEW) && ++(IOLD) : 0, (DIFF) > 0 ? ++(IOLD) : 0, (DIFF) < 0 ? ++(INEW) : 0\
|
||||
for ((INEW) = 0, (IOLD) = 0, (DIFF) = 0; \
|
||||
\
|
||||
((IOLD) != (OLD)->len || (INEW) != (NEW)->len); \
|
||||
\
|
||||
(DIFF) == 0 ? ++(INEW) && ++(IOLD) : 0, \
|
||||
(DIFF) > 0 ? ++(IOLD) : 0, \
|
||||
(DIFF) < 0 ? ++(INEW) : 0 \
|
||||
)
|
||||
|
||||
/*
|
||||
* ((DIFF) == 0 && ++(INEW) && ++(IOLD)) || \
|
||||
* ((DIFF) > 0 && ++(IOLD)) || \
|
||||
* ((DIFF) < 0 && ++(INEW)) \
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef UC_LOG_COMPONENT
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_UNKNOWN
|
||||
#endif
|
||||
@@ -28,37 +32,6 @@ void uc_log_send_cb_register(void (*cb)(const char *, int sv));
|
||||
void uc_log_severity_set(enum uc_log_component c, int sv);
|
||||
void uc_log(enum uc_log_component c, int sv, const char *fmt, ...);
|
||||
|
||||
#ifdef PLAT_EC
|
||||
#define UC_LOG_INFO(...) \
|
||||
do { \
|
||||
syslog(LOG_INFO, __VA_ARGS__); \
|
||||
uc_log(UC_LOG_COMPONENT, UC_LOG_SV_INFO, __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define UC_LOG_DBG(FMT, ...) \
|
||||
do { \
|
||||
syslog(LOG_DEBUG, "%s:%u: " FMT, __func__, \
|
||||
(unsigned)__LINE__, ##__VA_ARGS__); \
|
||||
uc_log(UC_LOG_COMPONENT, UC_LOG_SV_DEBUG, \
|
||||
FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define UC_LOG_ERR(FMT, ...) \
|
||||
do { \
|
||||
syslog(LOG_ERR, "%s:%u: " FMT, __func__, \
|
||||
(unsigned)__LINE__, ##__VA_ARGS__); \
|
||||
uc_log(UC_LOG_COMPONENT, UC_LOG_SV_ERR, \
|
||||
FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define UC_LOG_CRIT(FMT, ...) \
|
||||
do { \
|
||||
syslog(LOG_CRIT, "%s:%u: " FMT, __func__, \
|
||||
(unsigned)__LINE__, ##__VA_ARGS__); \
|
||||
uc_log(UC_LOG_COMPONENT, UC_LOG_SV_CRIT, \
|
||||
FMT, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define UC_LOG_INFO(...) \
|
||||
do { \
|
||||
syslog(LOG_INFO, __VA_ARGS__); \
|
||||
@@ -88,6 +61,9 @@ void uc_log(enum uc_log_component c, int sv, const char *fmt, ...);
|
||||
uc_log(UC_LOG_COMPONENT, UC_LOG_SV_CRIT, \
|
||||
FMT __VA_OPT__(, ) __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifndef UCENTRAL_PLATFORM_H
|
||||
#define UCENTRAL_PLATFORM_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
@@ -22,18 +25,18 @@ extern "C" {
|
||||
#define MAX_NUM_OF_PORTS (100)
|
||||
|
||||
#define PORT_MAX_NAME_LEN (32)
|
||||
#ifdef PLAT_EC
|
||||
#define VLAN_MAX_NAME_LEN PORT_MAX_NAME_LEN
|
||||
#endif
|
||||
#define RTTY_CFG_FIELD_STR_MAX_LEN (64)
|
||||
#define PLATFORM_INFO_STR_MAX_LEN (96)
|
||||
#define SYSLOG_CFG_FIELD_STR_MAX_LEN (64)
|
||||
#define NTP_CFG_HOSTNAME_STR_MAX_LEN (64)
|
||||
#define RADIUS_CFG_HOSTNAME_STR_MAX_LEN (64)
|
||||
#define RADIUS_CFG_PASSKEY_STR_MAX_LEN (64)
|
||||
#define RADIUS_CFG_DEFAULT_PORT (1812)
|
||||
#define RADIUS_CFG_DEFAULT_PRIO (1)
|
||||
#define HEALTHCHEK_MESSAGE_MAX_COUNT (10)
|
||||
#define HEALTHCHEK_MESSAGE_MAX_LEN (100)
|
||||
#define PLATFORM_MAC_STR_SIZE (18)
|
||||
#define METRICS_WIRED_CLIENTS_MAX_NUM (2000)
|
||||
|
||||
/*
|
||||
* TODO(vb) likely we need to parse interfaces in proto to understand
|
||||
@@ -42,6 +45,8 @@ extern "C" {
|
||||
*/
|
||||
#define PID_TO_NAME(p, name) sprintf(name, "Ethernet%hu", p)
|
||||
#define NAME_TO_PID(p, name) sscanf((name), "Ethernet%hu", (p))
|
||||
#define VLAN_TO_NAME(v, name) sprintf((name), "Vlan%hu", (v))
|
||||
#define NAME_TO_VLAN(v, name) sscanf((name), "Vlan%hu", (v))
|
||||
|
||||
struct plat_vlan_memberlist;
|
||||
struct plat_port_vlan;
|
||||
@@ -65,6 +70,18 @@ enum plat_ieee8021x_port_host_mode {
|
||||
PLAT_802_1X_PORT_HOST_MODE_SINGLE_HOST,
|
||||
};
|
||||
|
||||
enum plat_ieee8021x_das_auth_type {
|
||||
PLAT_802_1X_DAS_AUTH_TYPE_ANY,
|
||||
PLAT_802_1X_DAS_AUTH_TYPE_ALL,
|
||||
PLAT_802_1X_DAS_AUTH_TYPE_SESSION_KEY,
|
||||
};
|
||||
|
||||
enum plat_igmp_version {
|
||||
PLAT_IGMP_VERSION_1,
|
||||
PLAT_IGMP_VERSION_2,
|
||||
PLAT_IGMP_VERSION_3
|
||||
};
|
||||
|
||||
#define UCENTRAL_PORT_LLDP_PEER_INFO_MAX_MGMT_IPS (2)
|
||||
/* Interface LLDP peer's data, as defined in interface.lldp.yml*/
|
||||
struct plat_port_lldp_peer_info {
|
||||
@@ -78,7 +95,7 @@ struct plat_port_lldp_peer_info {
|
||||
/* The chassis name that our neighbour is announcing */
|
||||
char name[64];
|
||||
/* The chassis MAC that our neighbour is announcing */
|
||||
char mac[18];
|
||||
char mac[PLATFORM_MAC_STR_SIZE];
|
||||
/* The chassis description that our neighbour is announcing */
|
||||
char description[512];
|
||||
/* The management IPs that our neighbour is announcing */
|
||||
@@ -116,7 +133,7 @@ struct plat_poe_port_state {
|
||||
|
||||
struct plat_ieee8021x_authenticated_client_info {
|
||||
char auth_method[32];
|
||||
char mac_addr[18];
|
||||
char mac_addr[PLATFORM_MAC_STR_SIZE];
|
||||
size_t session_time;
|
||||
char username[64];
|
||||
char vlan_type[32];
|
||||
@@ -253,15 +270,29 @@ struct plat_port_l2 {
|
||||
struct plat_ipv4 ipv4;
|
||||
};
|
||||
|
||||
struct plat_igmp {
|
||||
bool exist;
|
||||
bool snooping_enabled;
|
||||
bool querier_enabled;
|
||||
bool fast_leave_enabled;
|
||||
uint32_t query_interval;
|
||||
uint32_t last_member_query_interval;
|
||||
uint32_t max_response_time;
|
||||
enum plat_igmp_version version;
|
||||
size_t num_groups;
|
||||
struct {
|
||||
struct in_addr addr;
|
||||
struct plat_ports_list *egress_ports_list;
|
||||
} *groups;
|
||||
};
|
||||
|
||||
struct plat_port_vlan {
|
||||
struct plat_vlan_memberlist *members_list_head;
|
||||
struct plat_ipv4 ipv4;
|
||||
struct plat_dhcp dhcp;
|
||||
struct plat_igmp igmp;
|
||||
uint16_t id;
|
||||
uint16_t mstp_instance;
|
||||
#ifdef PLAT_EC
|
||||
char name[VLAN_MAX_NAME_LEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
struct plat_vlans_list {
|
||||
@@ -275,9 +306,6 @@ struct plat_vlan_memberlist {
|
||||
uint16_t fp_id;
|
||||
} port;
|
||||
bool tagged;
|
||||
#ifdef PLAT_EC
|
||||
bool pvid;
|
||||
#endif
|
||||
struct plat_vlan_memberlist *next;
|
||||
};
|
||||
|
||||
@@ -289,6 +317,27 @@ struct plat_syslog_cfg {
|
||||
char host[SYSLOG_CFG_FIELD_STR_MAX_LEN];
|
||||
};
|
||||
|
||||
struct plat_enabled_service_cfg {
|
||||
struct {
|
||||
bool enabled;
|
||||
} ssh;
|
||||
struct telnet {
|
||||
bool enabled;
|
||||
} telnet;
|
||||
struct {
|
||||
bool enabled;
|
||||
} http;
|
||||
};
|
||||
|
||||
struct plat_ntp_server {
|
||||
char hostname[NTP_CFG_HOSTNAME_STR_MAX_LEN];
|
||||
struct plat_ntp_server *next;
|
||||
};
|
||||
|
||||
struct plat_ntp_cfg {
|
||||
struct plat_ntp_server *servers;
|
||||
};
|
||||
|
||||
struct plat_rtty_cfg {
|
||||
char id[RTTY_CFG_FIELD_STR_MAX_LEN];
|
||||
char passwd[RTTY_CFG_FIELD_STR_MAX_LEN];
|
||||
@@ -331,6 +380,7 @@ struct plat_metrics_cfg {
|
||||
int lldp_enabled;
|
||||
int clients_enabled;
|
||||
size_t interval;
|
||||
unsigned max_mac_count;
|
||||
/* IE GET max length. Should be enoug. */
|
||||
char public_ip_lookup[2048];
|
||||
} state;
|
||||
@@ -343,8 +393,16 @@ struct plat_unit_poe_cfg {
|
||||
bool is_usage_threshold_set;
|
||||
};
|
||||
|
||||
struct plat_unit_system_cfg {
|
||||
char password[64];
|
||||
bool password_changed;
|
||||
};
|
||||
|
||||
struct plat_unit {
|
||||
struct plat_unit_poe_cfg poe;
|
||||
struct plat_unit_system_cfg system;
|
||||
bool mc_flood_control;
|
||||
bool querier_enable;
|
||||
};
|
||||
|
||||
enum plat_stp_mode {
|
||||
@@ -376,6 +434,31 @@ struct plat_radius_hosts_list {
|
||||
struct plat_radius_host host;
|
||||
};
|
||||
|
||||
struct plat_ieee8021x_dac_host {
|
||||
char hostname[RADIUS_CFG_HOSTNAME_STR_MAX_LEN];
|
||||
char passkey[RADIUS_CFG_PASSKEY_STR_MAX_LEN];
|
||||
};
|
||||
|
||||
struct plat_ieee8021x_dac_list {
|
||||
struct plat_ieee8021x_dac_list *next;
|
||||
struct plat_ieee8021x_dac_host host;
|
||||
};
|
||||
|
||||
struct plat_port_isolation_session_ports {
|
||||
struct plat_ports_list *ports_list;
|
||||
};
|
||||
|
||||
struct plat_port_isolation_session {
|
||||
uint64_t id;
|
||||
struct plat_port_isolation_session_ports uplink;
|
||||
struct plat_port_isolation_session_ports downlink;
|
||||
};
|
||||
|
||||
struct plat_port_isolation_cfg {
|
||||
struct plat_port_isolation_session *sessions;
|
||||
size_t sessions_num;
|
||||
};
|
||||
|
||||
struct plat_cfg {
|
||||
struct plat_unit unit;
|
||||
/* Alloc all ports, but access them only if bit is set. */
|
||||
@@ -385,6 +468,8 @@ struct plat_cfg {
|
||||
BITMAP_DECLARE(vlans_to_cfg, MAX_VLANS);
|
||||
struct plat_metrics_cfg metrics;
|
||||
struct plat_syslog_cfg *log_cfg;
|
||||
struct plat_enabled_service_cfg enabled_services_cfg;
|
||||
struct plat_ntp_cfg ntp_cfg;
|
||||
/* Port's interfaces (provide l2 iface w/o bridge caps) */
|
||||
struct plat_port_l2 portsl2[MAX_NUM_OF_PORTS];
|
||||
struct ucentral_router router;
|
||||
@@ -393,9 +478,25 @@ struct plat_cfg {
|
||||
/* Instance zero is for global instance (like common values in rstp) */
|
||||
struct plat_stp_instance_cfg stp_instances[MAX_VLANS];
|
||||
struct plat_radius_hosts_list *radius_hosts_list;
|
||||
bool ieee8021x_is_auth_ctrl_enabled;
|
||||
struct {
|
||||
bool is_auth_ctrl_enabled;
|
||||
bool bounce_port_ignore;
|
||||
bool disable_port_ignore;
|
||||
bool ignore_server_key;
|
||||
bool ignore_session_key;
|
||||
char server_key[RADIUS_CFG_PASSKEY_STR_MAX_LEN];
|
||||
enum plat_ieee8021x_das_auth_type das_auth_type;
|
||||
struct plat_ieee8021x_dac_list *das_dac_list;
|
||||
} ieee8021x;
|
||||
struct plat_port_isolation_cfg port_isolation_cfg;
|
||||
bool jumbo_frames;
|
||||
};
|
||||
|
||||
struct plat_learned_mac_addr {
|
||||
char port[PORT_MAX_NAME_LEN];
|
||||
int vid;
|
||||
char mac[PLATFORM_MAC_STR_SIZE];
|
||||
};
|
||||
|
||||
typedef void (*plat_alarm_cb)(struct plat_alarm *);
|
||||
|
||||
@@ -457,9 +558,6 @@ typedef void (*plat_run_script_cb)(int err, struct plat_run_script_result *,
|
||||
void *ctx);
|
||||
|
||||
enum {
|
||||
#ifdef PLAT_EC
|
||||
UCENTRAL_PORT_SPEED_NONE,
|
||||
#endif
|
||||
UCENTRAL_PORT_SPEED_10_E,
|
||||
UCENTRAL_PORT_SPEED_100_E,
|
||||
UCENTRAL_PORT_SPEED_1000_E,
|
||||
@@ -472,9 +570,6 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
#ifdef PLAT_EC
|
||||
UCENTRAL_PORT_DUPLEX_NONE,
|
||||
#endif
|
||||
UCENTRAL_PORT_DUPLEX_HALF_E,
|
||||
UCENTRAL_PORT_DUPLEX_FULL_E,
|
||||
};
|
||||
@@ -501,17 +596,60 @@ enum {
|
||||
PLAT_REBOOT_CAUSE_REBOOT_CMD,
|
||||
PLAT_REBOOT_CAUSE_POWERLOSS,
|
||||
PLAT_REBOOT_CAUSE_CRASH,
|
||||
PLAT_REBOOT_CAUSE_UNAVAILABLE,
|
||||
};
|
||||
|
||||
enum sfp_form_factor {
|
||||
UCENTRAL_SFP_FORM_FACTOR_NA = 0,
|
||||
|
||||
UCENTRAL_SFP_FORM_FACTOR_SFP,
|
||||
UCENTRAL_SFP_FORM_FACTOR_SFP_PLUS,
|
||||
UCENTRAL_SFP_FORM_FACTOR_SFP_28,
|
||||
UCENTRAL_SFP_FORM_FACTOR_SFP_DD,
|
||||
UCENTRAL_SFP_FORM_FACTOR_QSFP,
|
||||
UCENTRAL_SFP_FORM_FACTOR_QSFP_PLUS,
|
||||
UCENTRAL_SFP_FORM_FACTOR_QSFP_28,
|
||||
UCENTRAL_SFP_FORM_FACTOR_QSFP_DD
|
||||
};
|
||||
|
||||
enum sfp_link_mode {
|
||||
UCENTRAL_SFP_LINK_MODE_NA = 0,
|
||||
|
||||
UCENTRAL_SFP_LINK_MODE_1000_X,
|
||||
UCENTRAL_SFP_LINK_MODE_2500_X,
|
||||
UCENTRAL_SFP_LINK_MODE_4000_SR,
|
||||
UCENTRAL_SFP_LINK_MODE_10G_SR,
|
||||
UCENTRAL_SFP_LINK_MODE_25G_SR,
|
||||
UCENTRAL_SFP_LINK_MODE_40G_SR,
|
||||
UCENTRAL_SFP_LINK_MODE_50G_SR,
|
||||
UCENTRAL_SFP_LINK_MODE_100G_SR,
|
||||
};
|
||||
|
||||
struct plat_port_transceiver_info {
|
||||
char vendor_name[64];
|
||||
char part_number[64];
|
||||
char serial_number[64];
|
||||
char revision[64];
|
||||
enum sfp_form_factor form_factor;
|
||||
enum sfp_link_mode *supported_link_modes;
|
||||
size_t num_supported_link_modes;
|
||||
float temperature;
|
||||
float tx_optical_power;
|
||||
float rx_optical_power;
|
||||
float max_module_power;
|
||||
};
|
||||
|
||||
struct plat_port_info {
|
||||
struct plat_port_counters stats;
|
||||
struct plat_port_lldp_peer_info lldp_peer_info;
|
||||
struct plat_ieee8021x_port_info ieee8021x_info;
|
||||
struct plat_port_transceiver_info transceiver_info;
|
||||
uint32_t uptime;
|
||||
uint32_t speed;
|
||||
uint8_t carrier_up;
|
||||
uint8_t duplex;
|
||||
uint8_t has_lldp_peer_info;
|
||||
uint8_t has_transceiver_info;
|
||||
char name[PORT_MAX_NAME_LEN];
|
||||
};
|
||||
|
||||
@@ -525,6 +663,24 @@ struct plat_system_info {
|
||||
double load_average[3]; /* 1, 5, 15 minutes load average */
|
||||
};
|
||||
|
||||
struct plat_iee8021x_coa_counters {
|
||||
uint64_t coa_req_received;
|
||||
uint64_t coa_ack_sent;
|
||||
uint64_t coa_nak_sent;
|
||||
uint64_t coa_ignored;
|
||||
uint64_t coa_wrong_attr;
|
||||
uint64_t coa_wrong_attr_value;
|
||||
uint64_t coa_wrong_session_context;
|
||||
uint64_t coa_administratively_prohibited_req;
|
||||
};
|
||||
|
||||
struct plat_gw_address {
|
||||
struct in_addr ip;
|
||||
uint32_t metric;
|
||||
char port[PORT_MAX_NAME_LEN];
|
||||
char mac[PLATFORM_MAC_STR_SIZE];
|
||||
};
|
||||
|
||||
struct plat_state_info {
|
||||
struct plat_poe_state poe_state;
|
||||
struct plat_poe_port_state poe_ports_state[MAX_NUM_OF_PORTS];
|
||||
@@ -532,8 +688,15 @@ struct plat_state_info {
|
||||
|
||||
struct plat_port_info *port_info;
|
||||
int port_info_count;
|
||||
struct plat_port_vlan *vlan_info;
|
||||
size_t vlan_info_count;
|
||||
struct plat_learned_mac_addr *learned_mac_list;
|
||||
size_t learned_mac_list_size;
|
||||
struct plat_gw_address *gw_addr_list;
|
||||
size_t gw_addr_list_size;
|
||||
|
||||
struct plat_system_info system_info;
|
||||
struct plat_iee8021x_coa_counters ieee8021x_global_coa_counters;
|
||||
};
|
||||
|
||||
struct plat_upgrade_info {
|
||||
@@ -559,7 +722,14 @@ struct plat_event_callbacks {
|
||||
plat_poe_link_faultcode_cb poe_link_faultcode_cb;
|
||||
};
|
||||
|
||||
enum plat_script_type {
|
||||
PLAT_SCRIPT_TYPE_NA = 0,
|
||||
PLAT_SCRIPT_TYPE_SHELL = 1,
|
||||
PLAT_SCRIPT_TYPE_DIAGNOSTICS = 2,
|
||||
};
|
||||
|
||||
struct plat_run_script_result {
|
||||
enum plat_script_type type;
|
||||
const char *stdout_string;
|
||||
size_t stdout_string_len;
|
||||
int exit_status;
|
||||
@@ -567,7 +737,7 @@ struct plat_run_script_result {
|
||||
};
|
||||
|
||||
struct plat_run_script {
|
||||
const char *type;
|
||||
enum plat_script_type type;
|
||||
const char *script_base64;
|
||||
plat_run_script_cb cb;
|
||||
void *ctx;
|
||||
@@ -586,11 +756,7 @@ int plat_metrics_save(const struct plat_metrics_cfg *cfg);
|
||||
int plat_metrics_restore(struct plat_metrics_cfg *cfg);
|
||||
int plat_saved_config_id_get(uint64_t *id);
|
||||
void plat_config_destroy(struct plat_cfg *cfg);
|
||||
#ifdef PLAT_EC
|
||||
int plat_factory_default(bool keep_redirector);
|
||||
#else
|
||||
int plat_factory_default(void);
|
||||
#endif
|
||||
int plat_rtty(struct plat_rtty_cfg *rtty_cfg);
|
||||
int plat_upgrade(char *uri, char *signature);
|
||||
|
||||
@@ -621,15 +787,12 @@ int plat_run_script(struct plat_run_script *);
|
||||
int plat_port_list_get(uint16_t list_size, struct plat_ports_list *ports);
|
||||
int plat_port_num_get(uint16_t *num_of_active_ports);
|
||||
int plat_running_img_name_get(char *str, size_t str_max_len);
|
||||
int plat_revision_get(char *str, size_t str_max_len);
|
||||
int
|
||||
plat_reboot_cause_get(struct plat_reboot_cause *cause);
|
||||
|
||||
int plat_diagnostic(char *res_path);
|
||||
|
||||
#ifdef PLAT_EC
|
||||
void clean_stats();
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
plat.a: plat.o
|
||||
ar crs $@ $^
|
||||
|
||||
plat.o: plat-gnma.o gnma/gnma.full.a
|
||||
plat.o: plat-gnma.o gnma/gnma.full.a netlink/netlink.full.a
|
||||
# TODO(vb) get back to this
|
||||
gcc -r -nostdlib -o $@ $^
|
||||
|
||||
gnma/gnma.full.a:
|
||||
$(MAKE) -C $(dir $@) $(notdir $@)
|
||||
|
||||
netlink/netlink.full.a:
|
||||
$(MAKE) -C $(dir $@) $(notdir $@)
|
||||
|
||||
%.o: %.c
|
||||
ifdef PLATFORM_REVISION
|
||||
gcc -c -o $@ ${CFLAGS} -I ./ -I ../../include -D PLATFORM_REVISION='"$(PLATFORM_REVISION)"' $^
|
||||
else
|
||||
gcc -c -o $@ ${CFLAGS} -I ./ -I ../../include $^
|
||||
endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
all: gnma.a
|
||||
|
||||
%.o: %.c
|
||||
gcc -c -o $@ ${CFLAGS} -I ./ -I../../../include $<
|
||||
gcc -c -o $@ ${CFLAGS} -I ./ -I../../../include -I../netlink $<
|
||||
|
||||
gnma.a: gnma_common.o
|
||||
ar crs $@ $^
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@
|
||||
#define GNMA_RADIUS_CFG_HOSTNAME_STR_MAX_LEN (64)
|
||||
#define GNMA_RADIUS_CFG_PASSKEY_STR_MAX_LEN (64)
|
||||
|
||||
#define GNMA_OK 0
|
||||
#define GNMA_ERR_COMMON -1
|
||||
#define GNMA_ERR_OVERFLOW -2
|
||||
|
||||
@@ -26,6 +27,16 @@ struct gnma_radius_host_key {
|
||||
char hostname[GNMA_RADIUS_CFG_HOSTNAME_STR_MAX_LEN];
|
||||
};
|
||||
|
||||
struct gnma_das_dac_host_key {
|
||||
char hostname[GNMA_RADIUS_CFG_HOSTNAME_STR_MAX_LEN];
|
||||
};
|
||||
|
||||
typedef enum _gnma_das_auth_type_t {
|
||||
GNMA_802_1X_DAS_AUTH_TYPE_ANY,
|
||||
GNMA_802_1X_DAS_AUTH_TYPE_ALL,
|
||||
GNMA_802_1X_DAS_AUTH_TYPE_SESSION_KEY,
|
||||
} gnma_das_auth_type_t;
|
||||
|
||||
struct gnma_metadata {
|
||||
char platform[GNMA_METADATA_STR_MAX_LEN];
|
||||
char hwsku[GNMA_METADATA_STR_MAX_LEN];
|
||||
@@ -58,6 +69,17 @@ typedef enum _gnma_port_stat_type_t {
|
||||
|
||||
} gnma_port_stat_type_t;
|
||||
|
||||
typedef enum _gnma_ieee8021x_das_dac_stat_type_t {
|
||||
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_PKTS,
|
||||
GNMA_IEEE8021X_DAS_DAC_STAT_OUT_COA_ACK_PKTS,
|
||||
GNMA_IEEE8021X_DAS_DAC_STAT_OUT_COA_NAK_PKTS,
|
||||
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_IGNORED_PKTS,
|
||||
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_ATTR_PKTS,
|
||||
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_ATTR_VALUE_PKTS,
|
||||
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_WRONG_SESSION_CONTEXT_PKTS,
|
||||
GNMA_IEEE8021X_DAS_DAC_STAT_IN_COA_ADMINISTRATIVELY_PROHIBITED_REQ_PKTS,
|
||||
} gnma_ieee8021x_das_dac_stat_type_t;
|
||||
|
||||
struct gnma_alarm {
|
||||
const char *id;
|
||||
const char *resource;
|
||||
@@ -129,7 +151,9 @@ struct gnma_route_attrs {
|
||||
} connected;
|
||||
struct {
|
||||
uint16_t vid;
|
||||
uint32_t metric;
|
||||
struct in_addr gw;
|
||||
struct gnma_port_key egress_port;
|
||||
} nexthop;
|
||||
};
|
||||
};
|
||||
@@ -256,6 +280,47 @@ struct gnma_vlan_member_bmap {
|
||||
} vlan[GNMA_MAX_VLANS];
|
||||
};
|
||||
|
||||
typedef enum _gnma_fdb_entry_type_t {
|
||||
GNMA_FDB_ENTRY_TYPE_STATIC,
|
||||
GNMA_FDB_ENTRY_TYPE_DYNAMIC,
|
||||
} gnma_fdb_entry_type_t;
|
||||
|
||||
struct gnma_fdb_entry {
|
||||
struct gnma_port_key port;
|
||||
gnma_fdb_entry_type_t type;
|
||||
int vid;
|
||||
char mac[18];
|
||||
};
|
||||
|
||||
typedef enum _gnma_igmp_version_t {
|
||||
GNMA_IGMP_VERSION_NA = 0,
|
||||
GNMA_IGMP_VERSION_1 = 1,
|
||||
GNMA_IGMP_VERSION_2 = 2,
|
||||
GNMA_IGMP_VERSION_3 = 3
|
||||
} gnma_igmp_version_t;
|
||||
|
||||
struct gnma_igmp_snoop_attr {
|
||||
bool enabled;
|
||||
bool querier_enabled;
|
||||
bool fast_leave_enabled;
|
||||
uint32_t query_interval;
|
||||
uint32_t last_member_query_interval;
|
||||
uint32_t max_response_time;
|
||||
gnma_igmp_version_t version;
|
||||
};
|
||||
|
||||
struct gnma_igmp_static_group_attr {
|
||||
struct in_addr address;
|
||||
size_t num_ports;
|
||||
struct gnma_port_key *egress_ports;
|
||||
};
|
||||
|
||||
struct gnma_vlan_ip_t {
|
||||
uint16_t vid;
|
||||
uint16_t prefixlen;
|
||||
struct in_addr address;
|
||||
};
|
||||
|
||||
int gnma_switch_create(/* TODO id */ /* TODO: attr (adr, login, psw) */);
|
||||
int gnma_port_admin_state_set(struct gnma_port_key *port_key, bool up);
|
||||
int gnma_port_speed_set(struct gnma_port_key *port_key, const char *speed);
|
||||
@@ -380,6 +445,9 @@ int gnma_route_remove(uint16_t vr_id /* 0 - default */,
|
||||
int gnma_route_list_get(uint16_t vr_id, uint32_t *list_size,
|
||||
struct gnma_ip_prefix *prefix_list,
|
||||
struct gnma_route_attrs *attr_list);
|
||||
int gnma_dyn_route_list_get(size_t *list_size,
|
||||
struct gnma_ip_prefix *prefix_list,
|
||||
struct gnma_route_attrs *attr_list);
|
||||
|
||||
int gnma_stp_mode_set(gnma_stp_mode_t mode, struct gnma_stp_attr *attr);
|
||||
int gnma_stp_mode_get(gnma_stp_mode_t *mode, struct gnma_stp_attr *attr);
|
||||
@@ -390,23 +458,53 @@ int gnma_stp_ports_enable(uint32_t list_size, struct gnma_port_key *ports_list);
|
||||
int gnma_stp_instance_set(uint16_t instance, uint16_t prio,
|
||||
uint32_t list_size, uint16_t *vid_list);
|
||||
|
||||
int gnma_stp_vids_enable(uint32_t list_size, uint16_t *vid_list);
|
||||
int gnma_stp_vids_enable_all(void);
|
||||
int gnma_stp_vids_set(uint32_t list_size, uint16_t *vid_list, bool enable);
|
||||
int gnma_stp_vids_set_all(bool enable);
|
||||
int gnma_stp_vid_set(uint16_t vid, struct gnma_stp_attr *attr);
|
||||
int gnma_stp_vid_bulk_get(struct gnma_stp_attr *list, ssize_t size);
|
||||
|
||||
int gnma_ieee8021x_system_auth_control_set(bool is_enabled);
|
||||
int gnma_ieee8021x_system_auth_control_get(bool *is_enabled);
|
||||
int gnma_ieee8021x_system_auth_clients_get(char *buf, size_t buf_size);
|
||||
int gnma_ieee8021x_das_bounce_port_ignore_set(bool bounce_port_ignore);
|
||||
int gnma_ieee8021x_das_bounce_port_ignore_get(bool *bounce_port_ignore);
|
||||
int gnma_ieee8021x_das_disable_port_ignore_set(bool disable_port_ignore);
|
||||
int gnma_ieee8021x_das_disable_port_ignore_get(bool *disable_port_ignore);
|
||||
int gnma_ieee8021x_das_ignore_server_key_set(bool ignore_server_key);
|
||||
int gnma_ieee8021x_das_ignore_server_key_get(bool *ignore_server_key);
|
||||
int gnma_ieee8021x_das_ignore_session_key_set(bool ignore_session_key);
|
||||
int gnma_ieee8021x_das_ignore_session_key_get(bool *ignore_session_key);
|
||||
int gnma_ieee8021x_das_auth_type_key_set(gnma_das_auth_type_t auth_type);
|
||||
int gnma_ieee8021x_das_auth_type_key_get(gnma_das_auth_type_t *auth_type);
|
||||
int gnma_ieee8021x_das_dac_hosts_list_get(size_t *list_size,
|
||||
struct gnma_das_dac_host_key *das_dac_keys_arr);
|
||||
int gnma_ieee8021x_das_dac_host_add(struct gnma_das_dac_host_key *key,
|
||||
const char *passkey);
|
||||
int gnma_ieee8021x_das_dac_host_remove(struct gnma_das_dac_host_key *key);
|
||||
int
|
||||
gnma_iee8021x_das_dac_global_stats_get(uint32_t num_of_counters,
|
||||
gnma_ieee8021x_das_dac_stat_type_t *counter_ids,
|
||||
uint64_t *counters);
|
||||
|
||||
int gnma_radius_hosts_list_get(size_t *list_size,
|
||||
struct gnma_radius_host_key *hosts_list);
|
||||
int gnma_radius_host_add(struct gnma_radius_host_key *key, const char *passkey,
|
||||
uint16_t auth_port, uint8_t prio);
|
||||
int gnma_radius_host_remove(struct gnma_radius_host_key *key);
|
||||
int gnma_mac_address_list_get(size_t *list_size, struct gnma_fdb_entry *list);
|
||||
int gnma_system_password_set(char *password);
|
||||
int gnma_igmp_snooping_set(uint16_t vid, struct gnma_igmp_snoop_attr *attr);
|
||||
int gnma_igmp_static_groups_set(uint16_t vid, size_t num_groups,
|
||||
struct gnma_igmp_static_group_attr *groups);
|
||||
int gnma_nei_addr_get(struct gnma_port_key *iface, struct in_addr *ip,
|
||||
char *mac, size_t buf_size);
|
||||
|
||||
int gnma_igmp_iface_groups_get(struct gnma_port_key *iface,
|
||||
char *buf, size_t *buf_size);
|
||||
|
||||
struct gnma_change *gnma_change_create(void);
|
||||
void gnma_change_destory(struct gnma_change *);
|
||||
int gnma_change_exec(struct gnma_change *);
|
||||
|
||||
int gnma_techsupport_start(char *res_path);
|
||||
int gnma_ip_iface_addr_get(struct gnma_vlan_ip_t *address_list, size_t *list_size);
|
||||
|
||||
10
src/ucentral-client/platform/brcm-sonic/netlink/Makefile
Normal file
10
src/ucentral-client/platform/brcm-sonic/netlink/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
all: netlink.a
|
||||
|
||||
%.o: %.c
|
||||
gcc -c -o $@ ${CFLAGS} -I ./ -I/usr/include/libnl3 -lnl-3 -lnl-route-3 $<
|
||||
|
||||
netlink.a: netlink_common.o
|
||||
ar crs $@ $^
|
||||
|
||||
netlink.full.a: netlink.a
|
||||
ar crsT $@ $^
|
||||
220
src/ucentral-client/platform/brcm-sonic/netlink/netlink_common.c
Normal file
220
src/ucentral-client/platform/brcm-sonic/netlink/netlink_common.c
Normal file
@@ -0,0 +1,220 @@
|
||||
#include <sys/socket.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <netlink/netlink.h>
|
||||
#include <netlink/route/link.h>
|
||||
#include <netlink/route/route.h>
|
||||
#include <netlink/route/addr.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <netlink_common.h>
|
||||
|
||||
#define BUFFER_SIZE 4096
|
||||
|
||||
#define likely(x) __builtin_expect(!!(x), 1)
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
|
||||
#define for_each_nlmsg(n, buf, len) \
|
||||
for (n = (struct nlmsghdr*)buf; \
|
||||
NLMSG_OK(n, (uint32_t)len) && n->nlmsg_type != NLMSG_DONE; \
|
||||
n = NLMSG_NEXT(n, len))
|
||||
|
||||
#define for_each_rattr(n, buf, len) \
|
||||
for (n = (struct rtattr*)buf; RTA_OK(n, len); n = RTA_NEXT(n, len))
|
||||
|
||||
|
||||
static int _nl_connect(int *sock)
|
||||
{
|
||||
int s;
|
||||
|
||||
s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
|
||||
*sock = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _nl_disconnect(int sock)
|
||||
{
|
||||
close(sock);
|
||||
}
|
||||
|
||||
static int _nl_request_ip_send(int sock)
|
||||
{
|
||||
struct sockaddr_nl sa = {.nl_family = AF_NETLINK};
|
||||
char buf[BUFFER_SIZE];
|
||||
struct ifaddrmsg *ifa;
|
||||
struct nlmsghdr *nl;
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
int res;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(buf, 0, BUFFER_SIZE);
|
||||
|
||||
nl = (struct nlmsghdr*)buf;
|
||||
nl->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
|
||||
nl->nlmsg_type = RTM_GETADDR;
|
||||
nl->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
|
||||
|
||||
iov.iov_base = nl;
|
||||
iov.iov_len = nl->nlmsg_len;
|
||||
|
||||
ifa = (struct ifaddrmsg*)NLMSG_DATA(nl);
|
||||
ifa->ifa_family = AF_INET; /* IPv4 */
|
||||
|
||||
msg.msg_name = &sa;
|
||||
msg.msg_namelen = sizeof(sa);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
res = sendmsg(sock, &msg, 0);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nl_response_get(int sock, void *buf, size_t *len)
|
||||
{
|
||||
struct iovec iov = {.iov_base = buf, .iov_len = *len};
|
||||
struct sockaddr_nl sa = {.nl_family = AF_NETLINK};
|
||||
struct msghdr msg = {
|
||||
.msg_name = &sa,
|
||||
.msg_namelen = sizeof(sa),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1
|
||||
};
|
||||
int res;
|
||||
|
||||
res = recvmsg(sock, &msg, 0);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
*len = res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nl_iface_addr_parse(uint32_t vid, void *buf, size_t len,
|
||||
unsigned char prefixlen, struct nl_vid_addr *addr)
|
||||
{
|
||||
struct rtattr *rta = NULL;
|
||||
|
||||
for_each_rattr(rta, buf, len) {
|
||||
if (rta->rta_type == IFA_LOCAL) {
|
||||
memcpy(&addr->address, RTA_DATA(rta), sizeof(addr->address));
|
||||
addr->vid = vid;
|
||||
addr->prefixlen = prefixlen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _nl_response_addr_parse(void *buf,
|
||||
size_t len,
|
||||
struct nl_vid_addr *addr_list,
|
||||
size_t *list_size)
|
||||
{
|
||||
struct ifaddrmsg *iface_addr;
|
||||
struct nlmsghdr *nl = NULL;
|
||||
char ifname[IF_NAMESIZE];
|
||||
size_t num_addrs = 0;
|
||||
uint32_t vid;
|
||||
int err = 0;
|
||||
|
||||
for_each_nlmsg(nl, buf, len) {
|
||||
if (nl->nlmsg_type == NLMSG_ERROR)
|
||||
return -1;
|
||||
|
||||
if (nl->nlmsg_type != RTM_NEWADDR) /* only care for addr */
|
||||
continue;
|
||||
|
||||
iface_addr = (struct ifaddrmsg*)NLMSG_DATA(nl);
|
||||
|
||||
if (!if_indextoname(iface_addr->ifa_index, ifname))
|
||||
return -1;
|
||||
|
||||
if (sscanf(ifname, "Vlan%u", &vid) != 1)
|
||||
continue;
|
||||
|
||||
if (!addr_list || *list_size == 0) {
|
||||
num_addrs++;
|
||||
continue;
|
||||
}
|
||||
if (num_addrs > *list_size)
|
||||
return -EOVERFLOW;
|
||||
|
||||
err = _nl_iface_addr_parse(vid, IFA_RTA(iface_addr), IFA_PAYLOAD(nl),
|
||||
iface_addr->ifa_prefixlen,
|
||||
&addr_list[num_addrs++]);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_addrs > *list_size)
|
||||
err = -EOVERFLOW;
|
||||
*list_size = num_addrs;
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return nl->nlmsg_type == NLMSG_DONE? -ENODATA : 0;
|
||||
}
|
||||
|
||||
int nl_get_ip_list(struct nl_vid_addr *addr_list, size_t *list_size)
|
||||
{
|
||||
size_t buf_len = BUFFER_SIZE, batch_size = 0, num_addrs = 0;
|
||||
char buf[BUFFER_SIZE];
|
||||
int sock = 0;
|
||||
int err;
|
||||
|
||||
err = _nl_connect(&sock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = _nl_request_ip_send(sock);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
while (1) {
|
||||
err = _nl_response_get(sock, buf, &buf_len);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = _nl_response_addr_parse(buf, buf_len, NULL, &batch_size);
|
||||
if (err == -ENODATA) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
if (err && err != -EOVERFLOW) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
num_addrs += batch_size;
|
||||
if (!addr_list || *list_size == 0)
|
||||
continue;
|
||||
if (num_addrs > *list_size) {
|
||||
err = -EOVERFLOW;
|
||||
break;
|
||||
}
|
||||
|
||||
err = _nl_response_addr_parse(buf, buf_len, &addr_list[num_addrs - batch_size], &batch_size);
|
||||
if (unlikely(err == -ENODATA)) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
if (num_addrs > *list_size)
|
||||
err = -EOVERFLOW;
|
||||
*list_size = num_addrs;
|
||||
out:
|
||||
_nl_disconnect(sock);
|
||||
return err;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef _NETLINK_COMMON
|
||||
#define _NETLINK_COMMON
|
||||
|
||||
struct nl_vid_addr {
|
||||
uint16_t vid;
|
||||
uint16_t prefixlen;
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
int nl_get_ip_list(struct nl_vid_addr *addr_list, size_t *list_size);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
14
src/ucentral-client/platform/brcm-sonic/plat-revision.h
Normal file
14
src/ucentral-client/platform/brcm-sonic/plat-revision.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _PLAT_REVISION
|
||||
#define _PLAT_REVISION
|
||||
|
||||
#define XSTR(x) STR(x)
|
||||
#define STR(x) #x
|
||||
|
||||
#define PLATFORM_REL_NUM 2.2
|
||||
#define PLATFORM_BUILD_NUM 5
|
||||
|
||||
#ifndef PLATFORM_REVISION
|
||||
#define PLATFORM_REVISION "Rel " XSTR(PLATFORM_REL_NUM) " build " XSTR(PLATFORM_BUILD_NUM)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,3 +0,0 @@
|
||||
list(APPEND PLAT_SOURCES
|
||||
${CMAKE_CURRENT_LIST_DIR}/plat-ec.c
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
52
src/ucentral-client/platform/larch-sonic/.clang-format
Normal file
52
src/ucentral-client/platform/larch-sonic/.clang-format
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
BasedOnStyle: LLVM
|
||||
IndentWidth: 4
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignOperands: Align
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: false
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
ColumnLimit: 120
|
||||
DerivePointerAlignment: false
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: BeforeHash
|
||||
NamespaceIndentation: Inner
|
||||
PackConstructorInitializers: CurrentLine
|
||||
PointerAlignment: Right
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
UseTab: Never
|
||||
...
|
||||
118
src/ucentral-client/platform/larch-sonic/CMakeLists.txt
Normal file
118
src/ucentral-client/platform/larch-sonic/CMakeLists.txt
Normal file
@@ -0,0 +1,118 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(larch-sonic VERSION 0.1.0 LANGUAGES C CXX)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||
include(grpc)
|
||||
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(json URL https://github.com/nlohmann/json/releases/download/v3.11.3/json.tar.xz)
|
||||
FetchContent_MakeAvailable(json)
|
||||
|
||||
set(REDIS_PLUS_PLUS_BUILD_TEST OFF)
|
||||
set(REDIS_PLUS_PLUS_BUILD_SHARED OFF)
|
||||
FetchContent_Declare(redis-plus-plus URL https://github.com/sewenew/redis-plus-plus/archive/refs/tags/1.3.12.zip)
|
||||
FetchContent_MakeAvailable(redis-plus-plus)
|
||||
|
||||
add_subdirectory(protos)
|
||||
|
||||
add_library(larch-sonic
|
||||
STATIC
|
||||
"fdb.cpp"
|
||||
"igmp.cpp"
|
||||
"metrics.cpp"
|
||||
"plat-larch.cpp"
|
||||
"port.cpp"
|
||||
"route.cpp"
|
||||
"sai_redis.cpp"
|
||||
"services.cpp"
|
||||
"state.cpp"
|
||||
"stp.cpp"
|
||||
"syslog.cpp"
|
||||
"utils.cpp"
|
||||
"vlan.cpp"
|
||||
)
|
||||
|
||||
target_compile_features(larch-sonic PRIVATE cxx_std_17)
|
||||
|
||||
target_link_libraries(larch-sonic
|
||||
PRIVATE
|
||||
proto-objects
|
||||
nlohmann_json::nlohmann_json
|
||||
redis++::redis++_static
|
||||
)
|
||||
|
||||
target_include_directories(larch-sonic
|
||||
PRIVATE
|
||||
${PROJECT_SOURCE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/../../include
|
||||
)
|
||||
|
||||
set_target_properties(larch-sonic PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
)
|
||||
|
||||
add_custom_target(plat.a
|
||||
DEPENDS larch-sonic
|
||||
COMMAND ${CMAKE_AR} rcsT ${PROJECT_SOURCE_DIR}/plat.a
|
||||
$<TARGET_FILE:larch-sonic>
|
||||
$<TARGET_FILE:redis++::redis++_static>
|
||||
/usr/local/lib/libabsl_bad_optional_access.a
|
||||
/usr/local/lib/libabsl_bad_variant_access.a
|
||||
/usr/local/lib/libabsl_base.a
|
||||
/usr/local/lib/libabsl_city.a
|
||||
/usr/local/lib/libabsl_civil_time.a
|
||||
/usr/local/lib/libabsl_cord.a
|
||||
/usr/local/lib/libabsl_cord_internal.a
|
||||
/usr/local/lib/libabsl_cordz_functions.a
|
||||
/usr/local/lib/libabsl_cordz_handle.a
|
||||
/usr/local/lib/libabsl_cordz_info.a
|
||||
/usr/local/lib/libabsl_debugging_internal.a
|
||||
/usr/local/lib/libabsl_demangle_internal.a
|
||||
/usr/local/lib/libabsl_exponential_biased.a
|
||||
/usr/local/lib/libabsl_graphcycles_internal.a
|
||||
/usr/local/lib/libabsl_hash.a
|
||||
/usr/local/lib/libabsl_hashtablez_sampler.a
|
||||
/usr/local/lib/libabsl_int128.a
|
||||
/usr/local/lib/libabsl_log_severity.a
|
||||
/usr/local/lib/libabsl_low_level_hash.a
|
||||
/usr/local/lib/libabsl_malloc_internal.a
|
||||
/usr/local/lib/libabsl_random_distributions.a
|
||||
/usr/local/lib/libabsl_random_internal_platform.a
|
||||
/usr/local/lib/libabsl_random_internal_pool_urbg.a
|
||||
/usr/local/lib/libabsl_random_internal_randen.a
|
||||
/usr/local/lib/libabsl_random_internal_randen_hwaes.a
|
||||
/usr/local/lib/libabsl_random_internal_randen_hwaes_impl.a
|
||||
/usr/local/lib/libabsl_random_internal_randen_slow.a
|
||||
/usr/local/lib/libabsl_random_internal_seed_material.a
|
||||
/usr/local/lib/libabsl_random_seed_gen_exception.a
|
||||
/usr/local/lib/libabsl_random_seed_sequences.a
|
||||
/usr/local/lib/libabsl_raw_hash_set.a
|
||||
/usr/local/lib/libabsl_raw_logging_internal.a
|
||||
/usr/local/lib/libabsl_spinlock_wait.a
|
||||
/usr/local/lib/libabsl_stacktrace.a
|
||||
/usr/local/lib/libabsl_status.a
|
||||
/usr/local/lib/libabsl_statusor.a
|
||||
/usr/local/lib/libabsl_str_format_internal.a
|
||||
/usr/local/lib/libabsl_strerror.a
|
||||
/usr/local/lib/libabsl_strings.a
|
||||
/usr/local/lib/libabsl_strings_internal.a
|
||||
/usr/local/lib/libabsl_symbolize.a
|
||||
/usr/local/lib/libabsl_synchronization.a
|
||||
/usr/local/lib/libabsl_throw_delegate.a
|
||||
/usr/local/lib/libabsl_time.a
|
||||
/usr/local/lib/libabsl_time_zone.a
|
||||
/usr/local/lib/libaddress_sorting.a
|
||||
/usr/local/lib/libcares.a
|
||||
/usr/local/lib/libcrypto.a
|
||||
/usr/local/lib/libgpr.a
|
||||
/usr/local/lib/libgrpc++.a
|
||||
/usr/local/lib/libgrpc++_reflection.a
|
||||
/usr/local/lib/libgrpc.a
|
||||
/usr/local/lib/libprotobuf.a
|
||||
/usr/local/lib/libre2.a
|
||||
/usr/local/lib/libssl.a
|
||||
/usr/local/lib/libupb.a
|
||||
/usr/local/lib/libz.a
|
||||
VERBATIM
|
||||
)
|
||||
22
src/ucentral-client/platform/larch-sonic/Makefile
Normal file
22
src/ucentral-client/platform/larch-sonic/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# This is a connector between ucentral-client Makefile and larch-sonic platform CMake.
|
||||
# When `plat.a` target is requested, CMake generates the underlying build system files
|
||||
# (i.e. Makefile) and make is run there.
|
||||
|
||||
CMAKE_FILE := CMakeLists.txt
|
||||
CMAKE_BUILD_DIR := build
|
||||
|
||||
MACHINE_ARCH := $(shell arch)
|
||||
CMAKE_VERSION := 3.29.3
|
||||
CMAKE_DIR := cmake-$(CMAKE_VERSION)-linux-$(MACHINE_ARCH)
|
||||
CMAKE_BINARY := $(CMAKE_DIR)/bin/cmake
|
||||
|
||||
plat.a: $(CMAKE_BUILD_DIR)/Makefile
|
||||
$(MAKE) -C $(<D) $@
|
||||
|
||||
# <D - directory part (i.e. path without file) of the first prerequisite
|
||||
# @D - directory part of the target
|
||||
$(CMAKE_BUILD_DIR)/Makefile: $(CMAKE_BINARY) $(CMAKE_FILE)
|
||||
$(CMAKE_BINARY) -S $(dir $(CMAKE_FILE)) -B $(@D) -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug
|
||||
|
||||
$(CMAKE_BINARY):
|
||||
wget -qO- --no-check-certificate "https://github.com/Kitware/CMake/releases/download/v$(CMAKE_VERSION)/cmake-$(CMAKE_VERSION)-linux-$(MACHINE_ARCH).tar.gz" | tar -xz
|
||||
14
src/ucentral-client/platform/larch-sonic/cmake/grpc.cmake
Normal file
14
src/ucentral-client/platform/larch-sonic/cmake/grpc.cmake
Normal file
@@ -0,0 +1,14 @@
|
||||
# Find Protobuf
|
||||
find_package(Protobuf CONFIG REQUIRED)
|
||||
message(STATUS "Using Protobuf ${Protobuf_VERSION}")
|
||||
|
||||
set(_PROTOBUF_LIBPROTOBUF protobuf::libprotobuf)
|
||||
set(_REFLECTION gRPC::grpc++_reflection)
|
||||
set(_PROTOBUF_PROTOC $<TARGET_FILE:protobuf::protoc>)
|
||||
|
||||
# Find gRPC
|
||||
find_package(gRPC CONFIG REQUIRED)
|
||||
message(STATUS "Using gRPC ${gRPC_VERSION}")
|
||||
|
||||
set(_GRPC_GRPCPP gRPC::grpc++)
|
||||
set(_GRPC_CPP_PLUGIN_EXECUTABLE $<TARGET_FILE:gRPC::grpc_cpp_plugin>)
|
||||
143
src/ucentral-client/platform/larch-sonic/fdb.cpp
Normal file
143
src/ucentral-client/platform/larch-sonic/fdb.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
#include <fdb.hpp>
|
||||
#include <sai_redis.hpp>
|
||||
#include <state.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <sw/redis++/redis++.h>
|
||||
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio> // std::snprintf
|
||||
#include <iterator> // std:inserter
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace larch {
|
||||
|
||||
std::vector<plat_learned_mac_addr> get_learned_mac_addrs()
|
||||
{
|
||||
const auto bridge_mapping = sai::get_bridge_port_mapping();
|
||||
const auto port_name_mapping = sai::get_port_name_mapping();
|
||||
std::unordered_map<sai::object_id, std::uint16_t> vlan_cache;
|
||||
|
||||
std::vector<plat_learned_mac_addr> learned_mac_addrs;
|
||||
|
||||
std::int64_t cursor = 0;
|
||||
std::unordered_set<std::string> keys;
|
||||
|
||||
do
|
||||
{
|
||||
constexpr std::string_view pattern =
|
||||
"ASIC_STATE:SAI_OBJECT_TYPE_FDB_ENTRY:*";
|
||||
|
||||
keys.clear();
|
||||
|
||||
cursor = state->redis_asic->scan(
|
||||
cursor,
|
||||
pattern,
|
||||
std::inserter(keys, keys.begin()));
|
||||
|
||||
for (const auto &key : keys)
|
||||
{
|
||||
plat_learned_mac_addr learned_entry{};
|
||||
std::unordered_map<std::string, std::string> entry;
|
||||
|
||||
// Get port name
|
||||
state->redis_asic->hgetall(
|
||||
key,
|
||||
std::inserter(entry, entry.begin()));
|
||||
|
||||
if (entry.at("SAI_FDB_ENTRY_ATTR_TYPE")
|
||||
== "SAI_FDB_ENTRY_TYPE_STATIC")
|
||||
continue;
|
||||
|
||||
const auto port_it = bridge_mapping.find(
|
||||
entry.at("SAI_FDB_ENTRY_ATTR_BRIDGE_PORT_ID")
|
||||
.substr(sai::oid_prefix.size()));
|
||||
|
||||
if (port_it == bridge_mapping.cend())
|
||||
continue;
|
||||
|
||||
const auto interface_it =
|
||||
port_name_mapping.find(port_it->second);
|
||||
|
||||
const std::string interface_name =
|
||||
(interface_it != port_name_mapping.cend())
|
||||
? interface_it->second
|
||||
: port_it->second;
|
||||
|
||||
// Get VLAN ID
|
||||
std::uint16_t vlan_id{};
|
||||
|
||||
const json fdb_json =
|
||||
json::parse(key.substr(pattern.size() - 1));
|
||||
|
||||
if (fdb_json.contains("vlan"))
|
||||
{
|
||||
vlan_id = static_cast<std::uint16_t>(std::stoul(
|
||||
fdb_json.at("vlan")
|
||||
.template get<std::string>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!fdb_json.contains("bvid"))
|
||||
continue;
|
||||
|
||||
std::string vlan_oid =
|
||||
fdb_json.at("bvid")
|
||||
.template get<std::string>()
|
||||
.substr(sai::oid_prefix.size());
|
||||
|
||||
const auto vlan_it = vlan_cache.find(vlan_oid);
|
||||
|
||||
if (vlan_it != vlan_cache.cend())
|
||||
{
|
||||
// VLAN is found in cache, using it
|
||||
vlan_id = vlan_it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto vlan_id_opt =
|
||||
sai::get_vlan_by_oid(vlan_oid);
|
||||
|
||||
if (!vlan_id_opt)
|
||||
continue;
|
||||
|
||||
vlan_id = *vlan_id_opt;
|
||||
|
||||
vlan_cache.try_emplace(
|
||||
std::move(vlan_oid),
|
||||
std::move(*vlan_id_opt));
|
||||
}
|
||||
}
|
||||
|
||||
std::snprintf(
|
||||
learned_entry.port,
|
||||
PORT_MAX_NAME_LEN,
|
||||
"%s",
|
||||
interface_name.c_str());
|
||||
|
||||
learned_entry.vid = vlan_id;
|
||||
|
||||
std::snprintf(
|
||||
learned_entry.mac,
|
||||
PLATFORM_MAC_STR_SIZE,
|
||||
"%s",
|
||||
fdb_json.at("mac")
|
||||
.template get<std::string>()
|
||||
.c_str());
|
||||
|
||||
learned_mac_addrs.push_back(learned_entry);
|
||||
}
|
||||
} while (cursor != 0);
|
||||
|
||||
return learned_mac_addrs;
|
||||
}
|
||||
|
||||
} // namespace larch
|
||||
14
src/ucentral-client/platform/larch-sonic/fdb.hpp
Normal file
14
src/ucentral-client/platform/larch-sonic/fdb.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef LARCH_PLATFORM_FDB_HPP_
|
||||
#define LARCH_PLATFORM_FDB_HPP_
|
||||
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace larch {
|
||||
|
||||
std::vector<plat_learned_mac_addr> get_learned_mac_addrs();
|
||||
|
||||
} // namespace larch
|
||||
|
||||
#endif // !LARCH_PLATFORM_FDB_HPP_
|
||||
136
src/ucentral-client/platform/larch-sonic/igmp.cpp
Normal file
136
src/ucentral-client/platform/larch-sonic/igmp.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#include <igmp.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_PLAT
|
||||
#include <ucentral-log.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using nlohmann::json;
|
||||
using namespace std;
|
||||
|
||||
namespace larch {
|
||||
|
||||
typedef enum {
|
||||
GNMI_IGMP_VERSION_NA = 0,
|
||||
GNMI_IGMP_VERSION_1 = 1,
|
||||
GNMI_IGMP_VERSION_2 = 2,
|
||||
GNMI_IGMP_VERSION_3 = 3
|
||||
} gnmi_igmp_version_t;
|
||||
|
||||
static void disable_igmp_snooping(uint16_t vid)
|
||||
{
|
||||
gnmi_operation op;
|
||||
|
||||
const auto igmp_snooping_list
|
||||
= gnmi_get ("/sonic-igmp-snooping:sonic-igmp-snooping/CFG_L2MC_TABLE/"
|
||||
"CFG_L2MC_TABLE_LIST");
|
||||
const json igmp_snooping_list_json = json::parse(igmp_snooping_list);
|
||||
|
||||
/* There are no IGMP-snoooping */
|
||||
if (!igmp_snooping_list_json.contains("sonic-igmp-snooping:CFG_L2MC_TABLE_LIST"))
|
||||
return;
|
||||
|
||||
/* Delete igmp-snooping config for specific VLAN. */
|
||||
op.add_delete("/sonic-igmp-snooping:sonic-igmp-snooping/CFG_L2MC_TABLE/CFG_L2MC_TABLE_LIST[vlan-name=Vlan" + to_string(vid) + "]");
|
||||
|
||||
op.execute();
|
||||
}
|
||||
|
||||
static void set_igmp_snooping(uint16_t vid, struct plat_igmp *igmp)
|
||||
{
|
||||
bool enabled = igmp->snooping_enabled || igmp->querier_enabled;
|
||||
gnmi_igmp_version_t gnmi_igmp_version = GNMI_IGMP_VERSION_NA;
|
||||
gnmi_operation op;
|
||||
|
||||
if (!enabled)
|
||||
{
|
||||
disable_igmp_snooping(vid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (igmp->version == PLAT_IGMP_VERSION_1)
|
||||
gnmi_igmp_version = GNMI_IGMP_VERSION_1;
|
||||
else if (igmp->version == PLAT_IGMP_VERSION_2)
|
||||
gnmi_igmp_version = GNMI_IGMP_VERSION_2;
|
||||
else if (igmp->version == PLAT_IGMP_VERSION_3)
|
||||
gnmi_igmp_version = GNMI_IGMP_VERSION_3;
|
||||
else
|
||||
{
|
||||
UC_LOG_ERR("Failed IGMP version");
|
||||
throw std::runtime_error{"Failed IGMP version"};
|
||||
}
|
||||
|
||||
/* Config IGMP-snooping */
|
||||
json igmp_snooping_list_json;
|
||||
|
||||
igmp_snooping_list_json["vlan-name"] = "Vlan" + to_string(vid);
|
||||
igmp_snooping_list_json["enabled"] = igmp->snooping_enabled;
|
||||
igmp_snooping_list_json["querier"] = igmp->querier_enabled;
|
||||
|
||||
if (igmp->querier_enabled)
|
||||
{
|
||||
igmp_snooping_list_json["query-interval"] = igmp->query_interval;
|
||||
igmp_snooping_list_json["query-max-response-time"] = igmp->max_response_time;
|
||||
igmp_snooping_list_json["last-member-query-interval"] = igmp->last_member_query_interval;
|
||||
if (gnmi_igmp_version != GNMI_IGMP_VERSION_NA)
|
||||
{
|
||||
igmp_snooping_list_json["version"] = igmp->version;
|
||||
}
|
||||
}
|
||||
|
||||
if (igmp->snooping_enabled) {
|
||||
igmp_snooping_list_json["fast-leave"] = igmp->fast_leave_enabled;
|
||||
}
|
||||
|
||||
json add_igmp_snooping_list_json;
|
||||
add_igmp_snooping_list_json["sonic-igmp-snooping:CFG_L2MC_TABLE_LIST"] = {igmp_snooping_list_json};
|
||||
|
||||
op.add_update("/sonic-igmp-snooping:sonic-igmp-snooping/CFG_L2MC_TABLE/CFG_L2MC_TABLE_LIST", add_igmp_snooping_list_json.dump());
|
||||
|
||||
op.execute();
|
||||
}
|
||||
|
||||
static void set_igmp_static_groups(uint16_t vid, struct plat_igmp *igmp)
|
||||
{
|
||||
struct plat_ports_list *port_node = NULL;
|
||||
size_t group_idx;
|
||||
gnmi_operation op;
|
||||
|
||||
for (group_idx = 0; group_idx < igmp->num_groups; group_idx++)
|
||||
{
|
||||
const std::string ip_addr = addr_to_str(igmp->groups[group_idx].addr);
|
||||
|
||||
json igmp_static_group_json;
|
||||
|
||||
igmp_static_group_json["vlan-name"] = "Vlan" + to_string(vid);
|
||||
igmp_static_group_json["group-addr"] = ip_addr;
|
||||
|
||||
json out_intf_list_json = json::array();
|
||||
UCENTRAL_LIST_FOR_EACH_MEMBER(port_node, &igmp->groups[group_idx].egress_ports_list)
|
||||
{
|
||||
out_intf_list_json.push_back(port_node->name);
|
||||
}
|
||||
igmp_static_group_json["out-intf"] = out_intf_list_json;
|
||||
|
||||
json add_igmp_static_group_json;
|
||||
add_igmp_static_group_json["sonic-igmp-snooping:CFG_L2MC_STATIC_GROUP_TABLE_LIST"] = {igmp_static_group_json};
|
||||
|
||||
op.add_update("/sonic-igmp-snooping:sonic-igmp-snooping/CFG_L2MC_STATIC_GROUP_TABLE/CFG_L2MC_STATIC_GROUP_TABLE_LIST", add_igmp_static_group_json.dump());
|
||||
}
|
||||
|
||||
op.execute();
|
||||
}
|
||||
|
||||
void apply_igmp_config(uint16_t vid, struct plat_igmp *igmp)
|
||||
{
|
||||
set_igmp_snooping(vid, igmp);
|
||||
if (igmp->num_groups > 0)
|
||||
{
|
||||
set_igmp_static_groups(vid, igmp);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
src/ucentral-client/platform/larch-sonic/igmp.hpp
Normal file
12
src/ucentral-client/platform/larch-sonic/igmp.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef LARCH_PLATFORM_IGMP_HPP_
|
||||
#define LARCH_PLATFORM_IGMP_HPP_
|
||||
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
namespace larch {
|
||||
|
||||
void apply_igmp_config(uint16_t vid, struct plat_igmp *igmp);
|
||||
|
||||
}
|
||||
|
||||
#endif // !LARCH_PLATFORM_IGMP_HPP_
|
||||
307
src/ucentral-client/platform/larch-sonic/metrics.cpp
Normal file
307
src/ucentral-client/platform/larch-sonic/metrics.cpp
Normal file
@@ -0,0 +1,307 @@
|
||||
#include <fdb.hpp>
|
||||
#include <metrics.hpp>
|
||||
#include <port.hpp>
|
||||
#include <route.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_PLAT
|
||||
#include <ucentral-log.h>
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <sys/sysinfo.h>
|
||||
|
||||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip> // std::setw
|
||||
#include <iterator> // std::begin, std::size
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility> // std::move
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace larch {
|
||||
|
||||
namespace {
|
||||
const std::string metrics_config_path =
|
||||
"/var/lib/ucentral/metrics_cfg.json";
|
||||
}
|
||||
|
||||
static plat_system_info get_system_info()
|
||||
{
|
||||
plat_system_info system_info{};
|
||||
|
||||
// Get load average
|
||||
std::array<double, std::size(system_info.load_average)> load_average{};
|
||||
|
||||
if (getloadavg(load_average.data(), load_average.size()) < 0)
|
||||
{
|
||||
UC_LOG_ERR("Failed to get load average");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (double &elem : load_average)
|
||||
elem /= 100.0;
|
||||
|
||||
std::copy(
|
||||
load_average.cbegin(),
|
||||
load_average.cend(),
|
||||
std::begin(system_info.load_average));
|
||||
}
|
||||
|
||||
// Get RAM cached
|
||||
std::ifstream is{"/proc/meminfo"};
|
||||
if (!is)
|
||||
{
|
||||
UC_LOG_ERR("Failed to get memory info");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string line;
|
||||
std::uint64_t cached = 0;
|
||||
bool found = false;
|
||||
|
||||
while (std::getline(is, line))
|
||||
{
|
||||
if (std::sscanf(line.c_str(), "Cached:%lu", &cached)
|
||||
== 1)
|
||||
{
|
||||
system_info.ram_cached = cached * 1024;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
UC_LOG_ERR("Can't find Cached entry in /proc/meminfo");
|
||||
}
|
||||
}
|
||||
|
||||
// Get other system information
|
||||
struct sysinfo sys_info = {};
|
||||
|
||||
if (sysinfo(&sys_info) < 0)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Failed to get system info: %s",
|
||||
std::strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
system_info.localtime =
|
||||
static_cast<std::uint64_t>(std::time(nullptr));
|
||||
system_info.uptime = sys_info.uptime;
|
||||
system_info.ram_buffered =
|
||||
sys_info.bufferram * sys_info.mem_unit;
|
||||
system_info.ram_free =
|
||||
(sys_info.freeram + sys_info.freeswap) * sys_info.mem_unit;
|
||||
system_info.ram_total = sys_info.totalram * sys_info.mem_unit;
|
||||
}
|
||||
|
||||
return system_info;
|
||||
}
|
||||
|
||||
std::pair<plat_state_info, state_data> get_state_info()
|
||||
{
|
||||
plat_state_info state_info{};
|
||||
state_data data{};
|
||||
|
||||
state_info.system_info = get_system_info();
|
||||
|
||||
// Get port info
|
||||
try
|
||||
{
|
||||
data.port_info = get_port_info();
|
||||
state_info.port_info = data.port_info.data();
|
||||
state_info.port_info_count = data.port_info.size();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to get port info: %s", ex.what());
|
||||
}
|
||||
|
||||
// Get learned MAC addresses
|
||||
try
|
||||
{
|
||||
data.learned_mac_addrs = get_learned_mac_addrs();
|
||||
state_info.learned_mac_list = data.learned_mac_addrs.data();
|
||||
state_info.learned_mac_list_size =
|
||||
data.learned_mac_addrs.size();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Failed to get learned MAC addresses: %s",
|
||||
ex.what());
|
||||
}
|
||||
|
||||
// Get GW addresses
|
||||
try
|
||||
{
|
||||
data.gw_addresses = get_gw_addresses();
|
||||
state_info.gw_addr_list = data.gw_addresses.data();
|
||||
state_info.gw_addr_list_size = data.gw_addresses.size();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to get GW addresses: %s", ex.what());
|
||||
}
|
||||
|
||||
return {std::move(state_info), std::move(data)};
|
||||
}
|
||||
|
||||
void save_metrics_config(const plat_metrics_cfg *cfg)
|
||||
{
|
||||
json metrics_cfg;
|
||||
|
||||
json &telemetry_cfg = metrics_cfg["telemetry"];
|
||||
telemetry_cfg["enabled"] = static_cast<bool>(cfg->telemetry.enabled);
|
||||
telemetry_cfg["interval"] = cfg->telemetry.interval;
|
||||
|
||||
json &healthcheck_cfg = metrics_cfg["healthcheck"];
|
||||
healthcheck_cfg["enabled"] =
|
||||
static_cast<bool>(cfg->healthcheck.enabled);
|
||||
healthcheck_cfg["interval"] = cfg->healthcheck.interval;
|
||||
|
||||
json &state_cfg = metrics_cfg["state"];
|
||||
state_cfg["enabled"] = static_cast<bool>(cfg->state.enabled);
|
||||
state_cfg["lldp_enabled"] = static_cast<bool>(cfg->state.lldp_enabled);
|
||||
state_cfg["clients_enabled"] =
|
||||
static_cast<bool>(cfg->state.clients_enabled);
|
||||
state_cfg["interval"] = cfg->state.interval;
|
||||
state_cfg["max_mac_count"] = cfg->state.max_mac_count;
|
||||
state_cfg["public_ip_lookup"] = cfg->state.public_ip_lookup;
|
||||
|
||||
std::ofstream os{metrics_config_path};
|
||||
os << std::setw(4) << metrics_cfg << std::endl;
|
||||
|
||||
if (!os)
|
||||
{
|
||||
throw std::runtime_error{
|
||||
"Failed to write metrics config to the file"};
|
||||
}
|
||||
}
|
||||
|
||||
void load_metrics_config(plat_metrics_cfg *cfg)
|
||||
{
|
||||
std::ifstream is{metrics_config_path};
|
||||
|
||||
// Metrics configuration doesn't exist yet, return silently without any
|
||||
// error
|
||||
if (!is.is_open())
|
||||
return;
|
||||
|
||||
json metrics_cfg = json::parse(is);
|
||||
|
||||
if (metrics_cfg.contains("telemetry"))
|
||||
{
|
||||
const json &telemetry_cfg = metrics_cfg.at("telemetry");
|
||||
cfg->telemetry.enabled =
|
||||
telemetry_cfg.at("enabled").template get<bool>();
|
||||
cfg->telemetry.interval =
|
||||
telemetry_cfg.at("interval").template get<std::size_t>();
|
||||
}
|
||||
|
||||
if (metrics_cfg.contains("healthcheck"))
|
||||
{
|
||||
const json &healthcheck_cfg = metrics_cfg.at("healthcheck");
|
||||
cfg->healthcheck.enabled =
|
||||
healthcheck_cfg.at("enabled").template get<bool>();
|
||||
cfg->healthcheck.interval =
|
||||
healthcheck_cfg.at("interval").template get<std::size_t>();
|
||||
}
|
||||
|
||||
if (metrics_cfg.contains("state"))
|
||||
{
|
||||
const json &state_cfg = metrics_cfg.at("state");
|
||||
cfg->state.enabled =
|
||||
state_cfg.at("enabled").template get<bool>();
|
||||
cfg->state.lldp_enabled =
|
||||
state_cfg.at("lldp_enabled").template get<bool>();
|
||||
cfg->state.clients_enabled =
|
||||
state_cfg.at("clients_enabled").template get<bool>();
|
||||
cfg->state.interval =
|
||||
state_cfg.at("interval").template get<std::size_t>();
|
||||
cfg->state.max_mac_count =
|
||||
state_cfg.at("max_mac_count").template get<std::size_t>();
|
||||
|
||||
std::strncpy(
|
||||
cfg->state.public_ip_lookup,
|
||||
state_cfg.at("public_ip_lookup")
|
||||
.template get<std::string>()
|
||||
.c_str(),
|
||||
std::size(cfg->state.public_ip_lookup) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
periodic::~periodic()
|
||||
{
|
||||
if (thread_ && thread_->joinable())
|
||||
thread_->join();
|
||||
}
|
||||
|
||||
void periodic::start(
|
||||
std::function<void()> callback,
|
||||
std::chrono::seconds period)
|
||||
{
|
||||
if (thread_)
|
||||
stop();
|
||||
|
||||
callback_ = std::move(callback);
|
||||
period_ = std::move(period);
|
||||
|
||||
thread_ =
|
||||
std::make_unique<std::thread>(std::bind(&periodic::worker, this));
|
||||
}
|
||||
|
||||
void periodic::stop()
|
||||
{
|
||||
if (!thread_)
|
||||
return;
|
||||
|
||||
{
|
||||
std::scoped_lock lk{mut_};
|
||||
stop_signal_ = true;
|
||||
}
|
||||
cv_.notify_one();
|
||||
|
||||
if (thread_->joinable())
|
||||
thread_->join();
|
||||
|
||||
thread_.reset();
|
||||
stop_signal_ = false;
|
||||
}
|
||||
|
||||
void periodic::worker()
|
||||
{
|
||||
std::unique_lock lk{mut_};
|
||||
|
||||
while (!stop_signal_)
|
||||
{
|
||||
try
|
||||
{
|
||||
callback_();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Error occurred during periodic task execution: %s",
|
||||
ex.what());
|
||||
}
|
||||
|
||||
cv_.wait_for(lk, period_, [this] { return stop_signal_; });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace larch
|
||||
62
src/ucentral-client/platform/larch-sonic/metrics.hpp
Normal file
62
src/ucentral-client/platform/larch-sonic/metrics.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
#ifndef LARCH_PLATFORM_METRICS_HPP_
|
||||
#define LARCH_PLATFORM_METRICS_HPP_
|
||||
|
||||
#include <state.hpp>
|
||||
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility> // std::pair
|
||||
#include <vector>
|
||||
|
||||
namespace larch {
|
||||
|
||||
struct state_data {
|
||||
std::vector<plat_port_info> port_info;
|
||||
std::vector<plat_learned_mac_addr> learned_mac_addrs;
|
||||
std::vector<plat_gw_address> gw_addresses;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get state information.
|
||||
*
|
||||
* @return A pair of @c plat_state_info and @c state_data. The latter is used as
|
||||
* an actual storage for all the gathered information, while the former
|
||||
* references the data in it. Pay attention to the fact that @c state_data must
|
||||
* outlive @c plat_state_info.
|
||||
*/
|
||||
std::pair<plat_state_info, state_data> get_state_info();
|
||||
|
||||
void save_metrics_config(const plat_metrics_cfg *cfg);
|
||||
|
||||
void load_metrics_config(plat_metrics_cfg *cfg);
|
||||
|
||||
class periodic {
|
||||
public:
|
||||
periodic() = default;
|
||||
~periodic();
|
||||
|
||||
void start(std::function<void()> callback, std::chrono::seconds period);
|
||||
void stop();
|
||||
|
||||
protected:
|
||||
void worker();
|
||||
|
||||
std::unique_ptr<std::thread> thread_;
|
||||
std::condition_variable cv_;
|
||||
std::mutex mut_;
|
||||
bool stop_signal_ = false;
|
||||
|
||||
std::chrono::seconds period_{};
|
||||
std::function<void()> callback_;
|
||||
};
|
||||
|
||||
} // namespace larch
|
||||
|
||||
#endif // !LARCH_PLATFORM_METRICS_HPP_
|
||||
631
src/ucentral-client/platform/larch-sonic/plat-larch.cpp
Normal file
631
src/ucentral-client/platform/larch-sonic/plat-larch.cpp
Normal file
@@ -0,0 +1,631 @@
|
||||
#include <metrics.hpp>
|
||||
#include <port.hpp>
|
||||
#include <route.hpp>
|
||||
#include <services.hpp>
|
||||
#include <state.hpp>
|
||||
#include <stp.hpp>
|
||||
#include <syslog.hpp>
|
||||
#include <utils.hpp>
|
||||
#include <vlan.hpp>
|
||||
|
||||
#include <gnmi.grpc.pb.h>
|
||||
#include <gnmi.pb.h>
|
||||
|
||||
#include <grpc++/create_channel.h>
|
||||
#include <grpc++/security/credentials.h>
|
||||
#include <grpc/grpc.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <sw/redis++/redis++.h>
|
||||
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_PLAT
|
||||
#include <ucentral-log.h>
|
||||
#include <ucentral-platform.h>
|
||||
#include <router-utils.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility> // std::move
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define UNUSED_PARAM(param) (void)((param))
|
||||
|
||||
#define RTTY_SESS_MAX (10)
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace {
|
||||
const std::string config_id_path = "/var/lib/ucentral/saved_config_id";
|
||||
}
|
||||
|
||||
int plat_init(void)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
state = std::make_unique<platform_state>();
|
||||
|
||||
auto verifier = grpc::experimental::ExternalCertificateVerifier::Create<certificate_verifier>();
|
||||
grpc::experimental::TlsChannelCredentialsOptions options;
|
||||
options.set_verify_server_certs(false);
|
||||
options.set_certificate_verifier(verifier);
|
||||
options.set_check_call_host(false);
|
||||
auto credentials = grpc::experimental::TlsCredentials(options);
|
||||
|
||||
state->channel = grpc::CreateChannel("127.0.0.1:8080", credentials);
|
||||
state->gnmi_stub = gnmi::gNMI::NewStub(state->channel);
|
||||
|
||||
// created new channel for gnoi
|
||||
state->system_gnoi_stub = gnoi::system::System::NewStub(grpc::CreateChannel("127.0.0.1:8080", credentials));
|
||||
state->stub_gnoi_sonic = gnoi::sonic::SonicService::NewStub(grpc::CreateChannel("127.0.0.1:8080", credentials));
|
||||
|
||||
state->telemetry_periodic = std::make_unique<periodic>();
|
||||
state->state_periodic = std::make_unique<periodic>();
|
||||
state->health_periodic = std::make_unique<periodic>();
|
||||
|
||||
state->redis_asic = std::make_unique<sw::redis::Redis>("tcp://127.0.0.1:6379/1");
|
||||
state->redis_counters = std::make_unique<sw::redis::Redis>("tcp://127.0.0.1:6379/2");
|
||||
|
||||
/*
|
||||
* Workaround to fix the issue when ucentral-client starts too early
|
||||
* (before gNMI container or before ports are up)
|
||||
*/
|
||||
UC_LOG_INFO("Trying to get initial port list...");
|
||||
|
||||
std::vector<port> ports;
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
ports = get_port_list();
|
||||
|
||||
if (ports.empty())
|
||||
{
|
||||
UC_LOG_DBG("Port list is empty");
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_DBG(
|
||||
"Failed to get initial port list: %s",
|
||||
ex.what());
|
||||
}
|
||||
|
||||
UC_LOG_DBG("Retrying in 10 seconds...");
|
||||
std::this_thread::sleep_for(std::chrono::seconds{10});
|
||||
}
|
||||
|
||||
UC_LOG_INFO("Successfully got the port list, continuing platform "
|
||||
"initialization");
|
||||
|
||||
try
|
||||
{
|
||||
/*
|
||||
* Get the state of interfaces addresses
|
||||
*/
|
||||
const plat_ipv4 no_address{false};
|
||||
|
||||
for (port &p : get_port_list())
|
||||
{
|
||||
const auto addresses = get_port_addresses(p);
|
||||
|
||||
state->interfaces_addrs.push_back(
|
||||
addresses.empty() ? no_address : addresses[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the router
|
||||
*/
|
||||
ucentral_router_fib_db_free(&state->router);
|
||||
|
||||
auto routes = get_routes(0);
|
||||
|
||||
if (ucentral_router_fib_db_alloc(&state->router, routes.size())
|
||||
!= 0)
|
||||
{
|
||||
UC_LOG_CRIT("Failed to allocate FIB DB");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (auto &node : routes)
|
||||
{
|
||||
if (ucentral_router_fib_db_append(&state->router, &node)
|
||||
!= 0)
|
||||
{
|
||||
UC_LOG_CRIT("Failed to append entry to FIB DB");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_CRIT("Platform initialization failed: %s", ex.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_info_get(struct plat_platform_info *info)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
try
|
||||
{
|
||||
const json metadata_json =
|
||||
json::parse(
|
||||
gnmi_get("/sonic-device_metadata:sonic-device_metadata/"
|
||||
"DEVICE_METADATA/localhost"))
|
||||
.at("sonic-device_metadata:localhost");
|
||||
|
||||
auto copy_from_json =
|
||||
[](const json &obj, char *dest, std::size_t dest_size) {
|
||||
std::strncpy(
|
||||
dest,
|
||||
obj.template get<std::string>().c_str(),
|
||||
dest_size > 0 ? dest_size - 1 : 0);
|
||||
};
|
||||
|
||||
copy_from_json(
|
||||
metadata_json.at("platform"),
|
||||
info->platform,
|
||||
std::size(info->platform));
|
||||
|
||||
copy_from_json(
|
||||
metadata_json.at("hwsku"),
|
||||
info->hwsku,
|
||||
std::size(info->hwsku));
|
||||
|
||||
copy_from_json(
|
||||
metadata_json.at("mac"),
|
||||
info->mac,
|
||||
std::size(info->mac));
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to get device metadata: %s", ex.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_reboot(void)
|
||||
{
|
||||
grpc::Status status;
|
||||
gnoi::system::RebootResponse gres;
|
||||
gnoi::system::RebootRequest greq;
|
||||
|
||||
grpc::ClientContext context;
|
||||
status = (larch::state->system_gnoi_stub)->Reboot(&context, greq, &gres);
|
||||
|
||||
if (!status.ok()) {
|
||||
UC_LOG_ERR("Request failed");
|
||||
UC_LOG_ERR("Code: %d", status.error_code());
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_config_apply(struct plat_cfg *cfg, uint32_t id)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
UNUSED_PARAM(id);
|
||||
|
||||
try
|
||||
{
|
||||
apply_vlan_config(cfg);
|
||||
apply_port_config(cfg);
|
||||
apply_route_config(cfg);
|
||||
apply_stp_config(cfg);
|
||||
apply_services_config(cfg);
|
||||
apply_vlan_ipv4_config(cfg);
|
||||
/* apply_syslog_config() call must always be the last one */
|
||||
apply_syslog_config(cfg->log_cfg, cfg->log_cfg_cnt);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to apply config: %s", ex.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_config_save(uint64_t id)
|
||||
{
|
||||
// TO-DO: actually save the config, not only config id
|
||||
|
||||
std::ofstream os{config_id_path};
|
||||
|
||||
if (!os)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Failed to save config id - can't open the file: %s",
|
||||
std::strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
os << id << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_config_restore(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_metrics_save(const struct plat_metrics_cfg *cfg)
|
||||
{
|
||||
try
|
||||
{
|
||||
larch::save_metrics_config(cfg);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to save metrics config: %s", ex.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_metrics_restore(struct plat_metrics_cfg *cfg)
|
||||
{
|
||||
try
|
||||
{
|
||||
larch::load_metrics_config(cfg);
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to load metrics config: %s", ex.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_saved_config_id_get(uint64_t *id)
|
||||
{
|
||||
std::ifstream is{config_id_path};
|
||||
|
||||
if (!is)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Failed to get saved config id - can't open the file: %s",
|
||||
std::strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
is >> *id;
|
||||
|
||||
if (!is.good())
|
||||
{
|
||||
UC_LOG_ERR("Failed to get saved config id - read failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void plat_config_destroy(struct plat_cfg *cfg)
|
||||
{
|
||||
UNUSED_PARAM(cfg);
|
||||
}
|
||||
|
||||
int plat_factory_default(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_rtty(struct plat_rtty_cfg *rtty_cfg)
|
||||
{
|
||||
static pid_t child[RTTY_SESS_MAX];
|
||||
int n, i, e;
|
||||
|
||||
/* wait the dead children */
|
||||
for (i = 0; i < RTTY_SESS_MAX;) {
|
||||
n = 0;
|
||||
if (child[i] > 0) {
|
||||
while ((n = waitpid(child[i], 0, WNOHANG)) < 0 && errno == EINTR);
|
||||
}
|
||||
if (n <= 0) {
|
||||
++i;
|
||||
} else {
|
||||
if (RTTY_SESS_MAX > 1)
|
||||
memmove(&child[i], &child[i+1], (RTTY_SESS_MAX-i-1)*sizeof(pid_t));
|
||||
child[RTTY_SESS_MAX - 1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* find a place for a new session */
|
||||
for (i = 0; i < RTTY_SESS_MAX && child[i] > 0; ++i);
|
||||
|
||||
/* if there are RTTY_SESS_MAX sessions, kill the oldest */
|
||||
if (i == RTTY_SESS_MAX) {
|
||||
if (child[0] <= 0) {
|
||||
UC_LOG_CRIT("child[0]==%jd", (intmax_t)child[0]);
|
||||
} else {
|
||||
if (kill(child[0], SIGKILL)) {
|
||||
UC_LOG_CRIT("kill failed: %s", strerror(errno));
|
||||
} else {
|
||||
while ((n = waitpid(child[0], 0, 0)) < 0 && errno == EINTR);
|
||||
if (n < 0)
|
||||
UC_LOG_CRIT("waitpid failed: %s", strerror(errno));
|
||||
}
|
||||
if (RTTY_SESS_MAX > 1)
|
||||
memmove(&child[0], &child[1], (RTTY_SESS_MAX - 1) * sizeof(pid_t));
|
||||
}
|
||||
i = RTTY_SESS_MAX - 1;
|
||||
}
|
||||
child[i] = fork();
|
||||
|
||||
if (!child[i]) {
|
||||
char argv[][128] = {
|
||||
"--id=",
|
||||
"--host=",
|
||||
"--port=",
|
||||
"--token="
|
||||
};
|
||||
|
||||
setsid();
|
||||
strcat(argv[0], rtty_cfg->id);
|
||||
strcat(argv[1], rtty_cfg->server);
|
||||
sprintf(argv[2], "--port=%u", rtty_cfg->port);
|
||||
strcat(argv[3], rtty_cfg->token);
|
||||
execl("/usr/local/bin/rtty", "rtty", argv[0], argv[1], argv[2], argv[3], "-d Larch Switch device", "-v", "-s", NULL);
|
||||
e = errno;
|
||||
UC_LOG_DBG("execv failed %d\n", e);
|
||||
|
||||
/* If we got to this line, that means execl failed, and
|
||||
* currently, due to simple design (fork/exec), it's impossible
|
||||
* to notify <main> process, that forked child failed to execl.
|
||||
* TBD: notify about execl fail.
|
||||
*/
|
||||
_exit(e);
|
||||
}
|
||||
|
||||
if (child[i] < (pid_t)0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_upgrade(char *uri, char *signature)
|
||||
{
|
||||
UNUSED_PARAM(signature);
|
||||
UNUSED_PARAM(uri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *plat_log_pop(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void plat_log_flush(void)
|
||||
{
|
||||
}
|
||||
|
||||
char *plat_log_pop_concatenate(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int plat_event_subscribe(const struct plat_event_callbacks *cbs)
|
||||
{
|
||||
UNUSED_PARAM(cbs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void plat_event_unsubscribe(void)
|
||||
{
|
||||
}
|
||||
|
||||
void plat_health_poll(void (*cb)(struct plat_health_info *), int period_sec)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
try
|
||||
{
|
||||
state->health_periodic->stop();
|
||||
state->health_periodic->start(
|
||||
[cb] {
|
||||
plat_health_info health_info{100};
|
||||
cb(&health_info);
|
||||
},
|
||||
std::chrono::seconds{period_sec});
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to start health poll: %s", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void plat_health_poll_stop(void)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
try
|
||||
{
|
||||
state->health_periodic->stop();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to stop health poll: %s", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void plat_telemetry_poll(void (*cb)(struct plat_state_info *), int period_sec)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
try
|
||||
{
|
||||
state->telemetry_periodic->stop();
|
||||
state->telemetry_periodic->start(
|
||||
[cb] {
|
||||
auto [state_info, data] = get_state_info();
|
||||
cb(&state_info);
|
||||
},
|
||||
std::chrono::seconds{period_sec});
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to start telemetry poll: %s", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void plat_telemetry_poll_stop(void)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
try
|
||||
{
|
||||
state->telemetry_periodic->stop();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to stop telemetry poll: %s", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void plat_state_poll(void (*cb)(struct plat_state_info *), int period_sec)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
try
|
||||
{
|
||||
state->state_periodic->stop();
|
||||
state->state_periodic->start(
|
||||
[cb] {
|
||||
auto [state_info, data] = get_state_info();
|
||||
cb(&state_info);
|
||||
},
|
||||
std::chrono::seconds{period_sec});
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to start state poll: %s", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void plat_state_poll_stop(void)
|
||||
{
|
||||
using namespace larch;
|
||||
|
||||
try
|
||||
{
|
||||
state->state_periodic->stop();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to stop state poll: %s", ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void plat_upgrade_poll(int (*cb)(struct plat_upgrade_info *), int period_sec)
|
||||
{
|
||||
UNUSED_PARAM(period_sec);
|
||||
UNUSED_PARAM(cb);
|
||||
}
|
||||
|
||||
void plat_upgrade_poll_stop(void)
|
||||
{
|
||||
}
|
||||
|
||||
int plat_run_script(struct plat_run_script *)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_port_list_get(uint16_t list_size, struct plat_ports_list *ports)
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto port_list = larch::get_port_list();
|
||||
|
||||
if (port_list.size() < list_size)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Too much ports requested (requested %hu, while "
|
||||
"only %zu available)",
|
||||
list_size,
|
||||
port_list.size());
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto it = port_list.cbegin();
|
||||
for (plat_ports_list *node = ports; node; node = node->next)
|
||||
{
|
||||
std::strncpy(
|
||||
node->name,
|
||||
it++->name.c_str(),
|
||||
sizeof(node->name) - 1);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to get list of ports: %s", ex.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_port_num_get(uint16_t *num_of_active_ports)
|
||||
{
|
||||
try
|
||||
{
|
||||
*num_of_active_ports = larch::get_port_list().size();
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_ERR("Failed to get count of ports: %s", ex.what());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_running_img_name_get(char *str, size_t str_max_len)
|
||||
{
|
||||
UNUSED_PARAM(str_max_len);
|
||||
UNUSED_PARAM(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_revision_get(char *str, size_t str_max_len)
|
||||
{
|
||||
UNUSED_PARAM(str_max_len);
|
||||
UNUSED_PARAM(str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_reboot_cause_get(struct plat_reboot_cause *cause)
|
||||
{
|
||||
UNUSED_PARAM(cause);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_diagnostic(char *res_path)
|
||||
{
|
||||
UNUSED_PARAM(res_path);
|
||||
return 0;
|
||||
}
|
||||
528
src/ucentral-client/platform/larch-sonic/port.cpp
Normal file
528
src/ucentral-client/platform/larch-sonic/port.cpp
Normal file
@@ -0,0 +1,528 @@
|
||||
#include <port.hpp>
|
||||
#include <state.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <bitmap.h>
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_PLAT
|
||||
#include <ucentral-log.h>
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <algorithm> // std::find_if
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio> // std::snprintf, std::sscanf
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility> // std::move
|
||||
#include <vector>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace larch {
|
||||
|
||||
std::vector<port> get_port_list()
|
||||
{
|
||||
const json port_list_json =
|
||||
json::parse(gnmi_get("/sonic-port:sonic-port/PORT/PORT_LIST"));
|
||||
|
||||
std::vector<port> port_list;
|
||||
|
||||
for (const auto port_json :
|
||||
port_list_json.value("sonic-port:PORT_LIST", json::array()))
|
||||
{
|
||||
port &p = port_list.emplace_back();
|
||||
p.name = port_json.at("name").template get<std::string>();
|
||||
}
|
||||
|
||||
return port_list;
|
||||
}
|
||||
|
||||
static bool get_port_oper_status(const std::string &port_name)
|
||||
{
|
||||
std::string port_status_data;
|
||||
|
||||
try
|
||||
{
|
||||
port_status_data = gnmi_get(
|
||||
"/openconfig-interfaces:interfaces/interface[name="
|
||||
+ port_name + "]/state/oper-status");
|
||||
}
|
||||
catch (const gnmi_exception &ex)
|
||||
{
|
||||
// For some reason there's no oper-status field in the gNMI
|
||||
// response when carrier is down
|
||||
return false;
|
||||
}
|
||||
|
||||
const json port_status_json = json::parse(port_status_data);
|
||||
|
||||
const std::string port_status_str =
|
||||
port_status_json.at("openconfig-interfaces:oper-status")
|
||||
.template get<std::string>();
|
||||
|
||||
if (port_status_str == "UP")
|
||||
return true;
|
||||
else if (port_status_str == "DOWN")
|
||||
return false;
|
||||
else
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Unknown port oper status: %s",
|
||||
port_status_str.c_str());
|
||||
throw std::runtime_error{
|
||||
"Unknown oper status: " + port_status_str};
|
||||
}
|
||||
}
|
||||
|
||||
static void set_port_admin_state(const std::string &port_name, bool state)
|
||||
{
|
||||
json port_state_json;
|
||||
port_state_json["openconfig-interfaces:config"]["enabled"] = state;
|
||||
|
||||
gnmi_set(
|
||||
"/openconfig-interfaces:interfaces/interface[name=" + port_name
|
||||
+ "]/config",
|
||||
port_state_json.dump());
|
||||
}
|
||||
|
||||
static std::uint32_t get_port_speed(const std::string &port_name)
|
||||
{
|
||||
const json port_speed_json = json::parse(gnmi_get(
|
||||
"/sonic-port:sonic-port/PORT/PORT_LIST[name=" + port_name
|
||||
+ "]/speed"));
|
||||
|
||||
return port_speed_json["sonic-port:speed"]
|
||||
.template get<std::uint32_t>();
|
||||
}
|
||||
|
||||
static void set_port_speed(const std::string &port_name, std::uint32_t speed)
|
||||
{
|
||||
auto speed_to_num = [](std::uint32_t speed) -> std::uint32_t {
|
||||
switch (speed)
|
||||
{
|
||||
case UCENTRAL_PORT_SPEED_10_E:
|
||||
return 10;
|
||||
case UCENTRAL_PORT_SPEED_100_E:
|
||||
return 100;
|
||||
case UCENTRAL_PORT_SPEED_1000_E:
|
||||
return 1000;
|
||||
case UCENTRAL_PORT_SPEED_2500_E:
|
||||
return 2500;
|
||||
case UCENTRAL_PORT_SPEED_5000_E:
|
||||
return 5000;
|
||||
case UCENTRAL_PORT_SPEED_10000_E:
|
||||
return 10000;
|
||||
case UCENTRAL_PORT_SPEED_25000_E:
|
||||
return 25000;
|
||||
case UCENTRAL_PORT_SPEED_40000_E:
|
||||
return 40000;
|
||||
case UCENTRAL_PORT_SPEED_100000_E:
|
||||
return 100000;
|
||||
|
||||
default:
|
||||
{
|
||||
UC_LOG_ERR("Unknown port speed");
|
||||
throw std::runtime_error{"Unknown port speed"};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
json port_speed_json;
|
||||
port_speed_json["name"] = port_name;
|
||||
port_speed_json["speed"] = speed_to_num(speed);
|
||||
|
||||
json set_port_speed_json;
|
||||
set_port_speed_json["sonic-port:PORT_LIST"] = {port_speed_json};
|
||||
|
||||
gnmi_set(
|
||||
"/sonic-port:sonic-port/PORT/PORT_LIST[name=" + port_name + "]",
|
||||
set_port_speed_json.dump());
|
||||
}
|
||||
|
||||
static void set_port_mtu(const std::string &port_name, std::uint16_t mtu)
|
||||
{
|
||||
json port_mtu_json;
|
||||
port_mtu_json["name"] = port_name;
|
||||
port_mtu_json["mtu"] = mtu;
|
||||
|
||||
json set_port_mtu_json;
|
||||
set_port_mtu_json["sonic-port:PORT_LIST"] = {port_mtu_json};
|
||||
|
||||
gnmi_set(
|
||||
"/sonic-port:sonic-port/PORT/PORT_LIST[name=" + port_name + "]",
|
||||
set_port_mtu_json.dump());
|
||||
}
|
||||
|
||||
static std::unordered_map<std::string, std::uint64_t>
|
||||
get_port_counters(const std::string &port_name)
|
||||
{
|
||||
const json port_counters_json = json::parse(gnmi_get(
|
||||
"/openconfig-interfaces:interfaces/interface[name=" + port_name
|
||||
+ "]/state/counters"));
|
||||
|
||||
std::unordered_map<std::string, std::uint64_t> counters;
|
||||
|
||||
if (!port_counters_json.contains("openconfig-interfaces:counters"))
|
||||
return counters;
|
||||
|
||||
for (const auto &item :
|
||||
port_counters_json["openconfig-interfaces:counters"].items())
|
||||
{
|
||||
counters[item.key()] =
|
||||
std::stoull(item.value().template get<std::string>());
|
||||
}
|
||||
|
||||
return counters;
|
||||
}
|
||||
|
||||
static std::optional<plat_port_lldp_peer_info>
|
||||
get_lldp_peer_info(const std::string &port_name)
|
||||
{
|
||||
/*
|
||||
* Actually, more specific YANG path should be used here
|
||||
* (/openconfig-lldp:lldp/interfaces/interface[name=<interface>]/neighbors/neighbor[id=<interface>])
|
||||
* but for some reason gNMI response for this path is empty, so the
|
||||
* workaround is to make more generic request and filter the response
|
||||
* and find necessary data.
|
||||
*/
|
||||
const json lldp_json = json::parse(gnmi_get(
|
||||
"/openconfig-lldp:lldp/interfaces/interface[name=" + port_name
|
||||
+ "]"));
|
||||
|
||||
const auto &neighbors = lldp_json.at("openconfig-lldp:interface")
|
||||
.at(0)
|
||||
.at("neighbors")
|
||||
.at("neighbor");
|
||||
|
||||
const auto neighbor_it = std::find_if(
|
||||
neighbors.cbegin(),
|
||||
neighbors.cend(),
|
||||
[&port_name](const auto &neighbor) {
|
||||
return neighbor.at("id").template get<std::string>()
|
||||
== port_name;
|
||||
});
|
||||
|
||||
if (neighbor_it == neighbors.cend())
|
||||
{
|
||||
throw std::runtime_error{"Failed to find LLDP neighbor"};
|
||||
}
|
||||
|
||||
if (!neighbor_it->contains("capabilities"))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
plat_port_lldp_peer_info peer_info{};
|
||||
|
||||
for (const auto &cap : neighbor_it->at("capabilities").at("capability"))
|
||||
{
|
||||
const std::string name =
|
||||
cap.at("name").template get<std::string>();
|
||||
|
||||
const bool enabled =
|
||||
cap.at("state").at("enabled").template get<bool>();
|
||||
|
||||
if (name == "openconfig-lldp-types:MAC_BRIDGE")
|
||||
peer_info.capabilities.is_bridge = enabled;
|
||||
else if (name == "openconfig-lldp-types:ROUTER")
|
||||
peer_info.capabilities.is_router = enabled;
|
||||
else if (name == "openconfig-lldp-types:WLAN_ACCESS_POINT")
|
||||
peer_info.capabilities.is_wlan_ap = enabled;
|
||||
else if (name == "openconfig-lldp-types:STATION_ONLY")
|
||||
peer_info.capabilities.is_station = enabled;
|
||||
}
|
||||
|
||||
const json &state = neighbor_it->at("state");
|
||||
|
||||
std::strncpy(
|
||||
peer_info.name,
|
||||
state.at("system-name").template get<std::string>().c_str(),
|
||||
std::size(peer_info.name) - 1);
|
||||
std::strncpy(
|
||||
peer_info.description,
|
||||
state.at("system-description").template get<std::string>().c_str(),
|
||||
std::size(peer_info.description) - 1);
|
||||
std::strncpy(
|
||||
peer_info.mac,
|
||||
state.at("chassis-id").template get<std::string>().c_str(),
|
||||
std::size(peer_info.mac) - 1);
|
||||
std::strncpy(
|
||||
peer_info.port,
|
||||
neighbor_it->at("id").template get<std::string>().c_str(),
|
||||
std::size(peer_info.port) - 1);
|
||||
|
||||
// Parse management addresses
|
||||
const auto addresses = split_string(
|
||||
state.at("management-address").template get<std::string>(),
|
||||
",");
|
||||
|
||||
for (std::size_t i = 0; i < UCENTRAL_PORT_LLDP_PEER_INFO_MAX_MGMT_IPS;
|
||||
++i)
|
||||
{
|
||||
if (i >= addresses.size())
|
||||
break;
|
||||
|
||||
const char *address = addresses[i].c_str();
|
||||
|
||||
// Verify that retrieved address is either valid IPv4 or IPv6
|
||||
// address. If so - copy it to peer_info.
|
||||
bool success = false;
|
||||
std::array<unsigned char, sizeof(in6_addr)> addr_buf{};
|
||||
|
||||
if (inet_pton(AF_INET, address, addr_buf.data()) == 1)
|
||||
success = true;
|
||||
else if (inet_pton(AF_INET6, address, addr_buf.data()) == 1)
|
||||
success = true;
|
||||
|
||||
if (success)
|
||||
std::strncpy(
|
||||
peer_info.mgmt_ips[i],
|
||||
address,
|
||||
INET6_ADDRSTRLEN);
|
||||
}
|
||||
|
||||
return peer_info;
|
||||
}
|
||||
|
||||
std::vector<plat_ipv4> get_port_addresses(const port &p)
|
||||
{
|
||||
// TO-DO: should gnmi_exception be caught (this would mean that there're
|
||||
// no addresses assigned to interface)?
|
||||
const json addresses_json = json::parse(gnmi_get(
|
||||
"/openconfig-interfaces:interfaces/interface[name=" + p.name
|
||||
+ "]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/"
|
||||
"addresses"));
|
||||
|
||||
if (!addresses_json.contains("openconfig-if-ip:addresses"))
|
||||
return {};
|
||||
|
||||
std::vector<plat_ipv4> addresses;
|
||||
|
||||
for (const auto &address_json :
|
||||
addresses_json.at("openconfig-if-ip:addresses")
|
||||
.value("address", json::array()))
|
||||
{
|
||||
const json &config_json = address_json.at("config");
|
||||
|
||||
const std::string address_str =
|
||||
config_json.at("ip").template get<std::string>();
|
||||
|
||||
plat_ipv4 address{};
|
||||
|
||||
if (inet_pton(AF_INET, address_str.c_str(), &address.subnet)
|
||||
!= 1)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Failed to parse interface IP address: %s",
|
||||
address_str.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
address.subnet_len = config_json.at("prefix-length")
|
||||
.template get<std::int32_t>();
|
||||
|
||||
if (address.subnet_len < 0 || address.subnet_len > 32)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Incorrect subnet length: %d (address %s)",
|
||||
address.subnet_len,
|
||||
address_str.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
address.exist = true;
|
||||
|
||||
addresses.push_back(std::move(address));
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
static void
|
||||
add_port_address(const std::string &port_name, const plat_ipv4 &address)
|
||||
{
|
||||
const std::string addr_str = addr_to_str(address.subnet);
|
||||
|
||||
json address_json;
|
||||
address_json["ip"] = addr_str;
|
||||
address_json["config"]["ip"] = addr_str;
|
||||
address_json["config"]["prefix-length"] = address.subnet_len;
|
||||
|
||||
json port_json;
|
||||
port_json["index"] = 0;
|
||||
port_json["openconfig-if-ip:ipv4"]["addresses"]["address"] = {
|
||||
address_json};
|
||||
|
||||
json add_port_json;
|
||||
add_port_json["openconfig-interfaces:subinterface"] = {port_json};
|
||||
|
||||
gnmi_set(
|
||||
"/openconfig-interfaces:interfaces/interface[name=" + port_name
|
||||
+ "]/subinterfaces/subinterface",
|
||||
add_port_json.dump());
|
||||
}
|
||||
|
||||
static void
|
||||
delete_port_address(const std::string &port_name, const plat_ipv4 &address)
|
||||
{
|
||||
const std::string addr_str = addr_to_str(address.subnet);
|
||||
|
||||
gnmi_operation op;
|
||||
|
||||
op.add_delete(
|
||||
"/openconfig-interfaces:interfaces/interface[name=" + port_name
|
||||
+ "]/subinterfaces/subinterface[index=0]/openconfig-if-ip:ipv4/"
|
||||
"addresses/address[ip="
|
||||
+ addr_str + "]");
|
||||
|
||||
op.execute();
|
||||
}
|
||||
|
||||
void apply_port_config(plat_cfg *cfg)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
|
||||
BITMAP_FOR_EACH_BIT_SET(i, cfg->ports_to_cfg, MAX_NUM_OF_PORTS)
|
||||
{
|
||||
const plat_port &port = cfg->ports[i];
|
||||
|
||||
const std::string port_name = "Ethernet" + std::to_string(i);
|
||||
const bool admin_state = port.state == UCENTRAL_PORT_ENABLED_E;
|
||||
|
||||
set_port_admin_state(port_name, admin_state);
|
||||
|
||||
if (admin_state)
|
||||
{
|
||||
set_port_speed(port_name, port.speed);
|
||||
set_port_mtu(
|
||||
port_name,
|
||||
cfg->jumbo_frames ? 9216 : 1500);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure the interface address
|
||||
*/
|
||||
const plat_ipv4 &address = cfg->portsl2[i].ipv4;
|
||||
plat_ipv4 &port_addr = state->interfaces_addrs.at(i);
|
||||
|
||||
if (address.exist)
|
||||
{
|
||||
if (!port_addr.exist
|
||||
|| port_addr.subnet.s_addr != address.subnet.s_addr
|
||||
|| port_addr.subnet_len != address.subnet_len)
|
||||
{
|
||||
if (port_addr.exist)
|
||||
{
|
||||
delete_port_address(
|
||||
port_name,
|
||||
port_addr);
|
||||
}
|
||||
|
||||
add_port_address(port_name, address);
|
||||
|
||||
port_addr = address;
|
||||
}
|
||||
}
|
||||
else if (port_addr.exist)
|
||||
{
|
||||
delete_port_address(port_name, port_addr);
|
||||
|
||||
port_addr = plat_ipv4{false};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<plat_port_info> get_port_info()
|
||||
{
|
||||
std::vector<port> ports = get_port_list();
|
||||
|
||||
std::vector<plat_port_info> ports_info(ports.size());
|
||||
|
||||
std::size_t i = 0;
|
||||
for (auto &port_info : ports_info)
|
||||
{
|
||||
const std::string &port_name = ports[i++].name;
|
||||
|
||||
std::snprintf(
|
||||
port_info.name,
|
||||
PORT_MAX_NAME_LEN,
|
||||
"%s",
|
||||
port_name.c_str());
|
||||
|
||||
port_info.speed = get_port_speed(port_name);
|
||||
port_info.duplex = true;
|
||||
port_info.carrier_up = get_port_oper_status(port_name);
|
||||
|
||||
// Get port counters
|
||||
std::unordered_map<std::string, std::uint64_t> counters;
|
||||
|
||||
try
|
||||
{
|
||||
counters = get_port_counters(port_name);
|
||||
}
|
||||
catch (const gnmi_exception &ex)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Couldn't get counters for port %s: %s",
|
||||
port_name.c_str(),
|
||||
ex.what());
|
||||
}
|
||||
|
||||
auto get_counter =
|
||||
[&counters](const std::string &counter) -> std::uint64_t {
|
||||
const auto it = counters.find(counter);
|
||||
|
||||
return it != counters.cend() ? it->second : 0;
|
||||
};
|
||||
|
||||
auto &stats = port_info.stats;
|
||||
|
||||
stats.collisions = 0;
|
||||
stats.multicast = 0;
|
||||
|
||||
stats.rx_bytes = get_counter("in-octets");
|
||||
stats.rx_dropped = get_counter("in-discards");
|
||||
stats.rx_error = get_counter("in-errors");
|
||||
stats.rx_packets = get_counter("in-unicast-pkts")
|
||||
+ get_counter("in-multicast-pkts")
|
||||
+ get_counter("in-broadcast-pkts");
|
||||
|
||||
stats.tx_bytes = get_counter("out-octets");
|
||||
stats.tx_dropped = get_counter("out-discards");
|
||||
stats.tx_error = get_counter("out-errors");
|
||||
stats.tx_packets = get_counter("out-unicast-pkts")
|
||||
+ get_counter("out-multicast-pkts")
|
||||
+ get_counter("out-broadcast-pkts");
|
||||
|
||||
try
|
||||
{
|
||||
auto peer_info_opt = get_lldp_peer_info(port_name);
|
||||
|
||||
if (peer_info_opt)
|
||||
{
|
||||
port_info.lldp_peer_info =
|
||||
std::move(*peer_info_opt);
|
||||
|
||||
port_info.has_lldp_peer_info = 1;
|
||||
}
|
||||
}
|
||||
catch (const std::exception &ex)
|
||||
{
|
||||
UC_LOG_DBG(
|
||||
"Couldn't get LLDP peer info: %s",
|
||||
ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
return ports_info;
|
||||
}
|
||||
|
||||
} // namespace larch
|
||||
26
src/ucentral-client/platform/larch-sonic/port.hpp
Normal file
26
src/ucentral-client/platform/larch-sonic/port.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef LARCH_PLATFORM_PORT_HPP_
|
||||
#define LARCH_PLATFORM_PORT_HPP_
|
||||
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace larch {
|
||||
|
||||
struct port {
|
||||
std::string name;
|
||||
};
|
||||
|
||||
std::vector<port> get_port_list();
|
||||
|
||||
std::vector<plat_ipv4> get_port_addresses(const port &p);
|
||||
|
||||
void apply_port_config(plat_cfg *cfg);
|
||||
|
||||
std::vector<plat_port_info> get_port_info();
|
||||
|
||||
} // namespace larch
|
||||
|
||||
#endif // !LARCH_PLATFORM_PORT_HPP_
|
||||
@@ -0,0 +1,27 @@
|
||||
file(GLOB proto_files CONFIGURE_DEPENDS "*.proto")
|
||||
|
||||
add_library(proto-objects OBJECT ${proto_files})
|
||||
|
||||
target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf gRPC::grpc++)
|
||||
|
||||
set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||
set(PROTO_IMPORT_DIRS "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>")
|
||||
|
||||
file(MAKE_DIRECTORY ${PROTO_BINARY_DIR})
|
||||
|
||||
protobuf_generate(
|
||||
TARGET proto-objects
|
||||
IMPORT_DIRS ${PROTO_IMPORT_DIRS}
|
||||
PROTOC_OUT_DIR "${PROTO_BINARY_DIR}"
|
||||
)
|
||||
|
||||
protobuf_generate(
|
||||
TARGET proto-objects
|
||||
LANGUAGE grpc
|
||||
GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc
|
||||
PLUGIN "protoc-gen-grpc=\$<TARGET_FILE:gRPC::grpc_cpp_plugin>"
|
||||
IMPORT_DIRS ${PROTO_IMPORT_DIRS}
|
||||
PROTOC_OUT_DIR "${PROTO_BINARY_DIR}"
|
||||
)
|
||||
49
src/ucentral-client/platform/larch-sonic/protos/common.proto
Normal file
49
src/ucentral-client/platform/larch-sonic/protos/common.proto
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Copyright 2018 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package gnoi.common;
|
||||
|
||||
import "types.proto";
|
||||
|
||||
option go_package = "github.com/openconfig/gnoi/common";
|
||||
|
||||
// RemoteDownload defines the details for a device to initiate a file transfer
|
||||
// from or to a remote location.
|
||||
message RemoteDownload {
|
||||
// The path information containing where to download the data from or to.
|
||||
// For HTTP(S), this will be the URL (i.e. foo.com/file.tbz2).
|
||||
// For SFTP and SCP, this will be the address:/path/to/file
|
||||
// (i.e. host.foo.com:/bar/baz).
|
||||
string path = 1;
|
||||
|
||||
enum Protocol {
|
||||
UNKNOWN = 0;
|
||||
SFTP = 1;
|
||||
HTTP = 2;
|
||||
HTTPS = 3;
|
||||
SCP = 4;
|
||||
}
|
||||
Protocol protocol = 2;
|
||||
|
||||
types.Credentials credentials = 3;
|
||||
|
||||
// Optional source address used to initiate connections from the device.
|
||||
// It can be either an IPv4 address or an IPv6 address, depending on the
|
||||
// connection's destination address.
|
||||
string source_address = 4;
|
||||
}
|
||||
457
src/ucentral-client/platform/larch-sonic/protos/gnmi.proto
Normal file
457
src/ucentral-client/platform/larch-sonic/protos/gnmi.proto
Normal file
@@ -0,0 +1,457 @@
|
||||
//
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/descriptor.proto";
|
||||
import "gnmi_ext.proto";
|
||||
|
||||
// Package gNMI defines a service specification for the gRPC Network Management
|
||||
// Interface. This interface is defined to be a standard interface via which
|
||||
// a network management system ("client") can subscribe to state values,
|
||||
// retrieve snapshots of state information, and manipulate the state of a data
|
||||
// tree supported by a device ("target").
|
||||
//
|
||||
// This document references the gNMI Specification which can be found at
|
||||
// http://github.com/openconfig/reference/blob/master/rpc/gnmi
|
||||
package gnmi;
|
||||
|
||||
// Define a protobuf FileOption that defines the gNMI service version.
|
||||
extend google.protobuf.FileOptions {
|
||||
// The gNMI service semantic version.
|
||||
string gnmi_service = 1001;
|
||||
}
|
||||
|
||||
// gNMI_service is the current version of the gNMI service, returned through
|
||||
// the Capabilities RPC.
|
||||
option (gnmi_service) = "0.7.0";
|
||||
|
||||
|
||||
service gNMI {
|
||||
// Capabilities allows the client to retrieve the set of capabilities that
|
||||
// is supported by the target. This allows the target to validate the
|
||||
// service version that is implemented and retrieve the set of models that
|
||||
// the target supports. The models can then be specified in subsequent RPCs
|
||||
// to restrict the set of data that is utilized.
|
||||
// Reference: gNMI Specification Section 3.2
|
||||
rpc Capabilities(CapabilityRequest) returns (CapabilityResponse);
|
||||
// Retrieve a snapshot of data from the target. A Get RPC requests that the
|
||||
// target snapshots a subset of the data tree as specified by the paths
|
||||
// included in the message and serializes this to be returned to the
|
||||
// client using the specified encoding.
|
||||
// Reference: gNMI Specification Section 3.3
|
||||
rpc Get(GetRequest) returns (GetResponse);
|
||||
// Set allows the client to modify the state of data on the target. The
|
||||
// paths to modified along with the new values that the client wishes
|
||||
// to set the value to.
|
||||
// Reference: gNMI Specification Section 3.4
|
||||
rpc Set(SetRequest) returns (SetResponse);
|
||||
// Subscribe allows a client to request the target to send it values
|
||||
// of particular paths within the data tree. These values may be streamed
|
||||
// at a particular cadence (STREAM), sent one off on a long-lived channel
|
||||
// (POLL), or sent as a one-off retrieval (ONCE).
|
||||
// Reference: gNMI Specification Section 3.5
|
||||
rpc Subscribe(stream SubscribeRequest) returns (stream SubscribeResponse);
|
||||
}
|
||||
|
||||
// Notification is a re-usable message that is used to encode data from the
|
||||
// target to the client. A Notification carries two types of changes to the data
|
||||
// tree:
|
||||
// - Deleted values (delete) - a set of paths that have been removed from the
|
||||
// data tree.
|
||||
// - Updated values (update) - a set of path-value pairs indicating the path
|
||||
// whose value has changed in the data tree.
|
||||
// Reference: gNMI Specification Section 2.1
|
||||
message Notification {
|
||||
int64 timestamp = 1; // Timestamp in nanoseconds since Epoch.
|
||||
Path prefix = 2; // Prefix used for paths in the message.
|
||||
// An alias for the path specified in the prefix field.
|
||||
// Reference: gNMI Specification Section 2.4.2
|
||||
string alias = 3;
|
||||
repeated Update update = 4; // Data elements that have changed values.
|
||||
repeated Path delete = 5; // Data elements that have been deleted.
|
||||
// This notification contains a set of paths that are always updated together
|
||||
// referenced by a globally unique prefix.
|
||||
bool atomic = 6;
|
||||
}
|
||||
|
||||
// Update is a re-usable message that is used to store a particular Path,
|
||||
// Value pair.
|
||||
// Reference: gNMI Specification Section 2.1
|
||||
message Update {
|
||||
Path path = 1; // The path (key) for the update.
|
||||
Value value = 2 [deprecated=true]; // The value (value) for the update.
|
||||
TypedValue val = 3; // The explicitly typed update value.
|
||||
uint32 duplicates = 4; // Number of coalesced duplicates.
|
||||
}
|
||||
|
||||
// TypedValue is used to encode a value being sent between the client and
|
||||
// target (originated by either entity).
|
||||
message TypedValue {
|
||||
// One of the fields within the val oneof is populated with the value
|
||||
// of the update. The type of the value being included in the Update
|
||||
// determines which field should be populated. In the case that the
|
||||
// encoding is a particular form of the base protobuf type, a specific
|
||||
// field is used to store the value (e.g., json_val).
|
||||
oneof value {
|
||||
string string_val = 1; // String value.
|
||||
int64 int_val = 2; // Integer value.
|
||||
uint64 uint_val = 3; // Unsigned integer value.
|
||||
bool bool_val = 4; // Bool value.
|
||||
bytes bytes_val = 5; // Arbitrary byte sequence value.
|
||||
float float_val = 6; // Floating point value.
|
||||
Decimal64 decimal_val = 7; // Decimal64 encoded value.
|
||||
ScalarArray leaflist_val = 8; // Mixed type scalar array value.
|
||||
google.protobuf.Any any_val = 9; // protobuf.Any encoded bytes.
|
||||
bytes json_val = 10; // JSON-encoded text.
|
||||
bytes json_ietf_val = 11; // JSON-encoded text per RFC7951.
|
||||
string ascii_val = 12; // Arbitrary ASCII text.
|
||||
// Protobuf binary encoded bytes. The message type is not included.
|
||||
// See the specification at
|
||||
// github.com/openconfig/reference/blob/master/rpc/gnmi/protobuf-vals.md
|
||||
// for a complete specification.
|
||||
bytes proto_bytes = 13;
|
||||
}
|
||||
}
|
||||
|
||||
// Path encodes a data tree path as a series of repeated strings, with
|
||||
// each element of the path representing a data tree node name and the
|
||||
// associated attributes.
|
||||
// Reference: gNMI Specification Section 2.2.2.
|
||||
message Path {
|
||||
// Elements of the path are no longer encoded as a string, but rather within
|
||||
// the elem field as a PathElem message.
|
||||
repeated string element = 1 [deprecated=true];
|
||||
string origin = 2; // Label to disambiguate path.
|
||||
repeated PathElem elem = 3; // Elements of the path.
|
||||
string target = 4; // The name of the target
|
||||
// (Sec. 2.2.2.1)
|
||||
}
|
||||
|
||||
// PathElem encodes an element of a gNMI path, along with any attributes (keys)
|
||||
// that may be associated with it.
|
||||
// Reference: gNMI Specification Section 2.2.2.
|
||||
message PathElem {
|
||||
string name = 1; // The name of the element in the path.
|
||||
map<string, string> key = 2; // Map of key (attribute) name to value.
|
||||
}
|
||||
|
||||
// Value encodes a data tree node's value - along with the way in which
|
||||
// the value is encoded. This message is deprecated by gNMI 0.3.0.
|
||||
// Reference: gNMI Specification Section 2.2.3.
|
||||
message Value {
|
||||
option deprecated = true;
|
||||
bytes value = 1; // Value of the variable being transmitted.
|
||||
Encoding type = 2; // Encoding used for the value field.
|
||||
}
|
||||
|
||||
// Encoding defines the value encoding formats that are supported by the gNMI
|
||||
// protocol. These encodings are used by both the client (when sending Set
|
||||
// messages to modify the state of the target) and the target when serializing
|
||||
// data to be returned to the client (in both Subscribe and Get RPCs).
|
||||
// Reference: gNMI Specification Section 2.3
|
||||
enum Encoding {
|
||||
JSON = 0; // JSON encoded text.
|
||||
BYTES = 1; // Arbitrarily encoded bytes.
|
||||
PROTO = 2; // Encoded according to out-of-band agreed Protobuf.
|
||||
ASCII = 3; // ASCII text of an out-of-band agreed format.
|
||||
JSON_IETF = 4; // JSON encoded text as per RFC7951.
|
||||
}
|
||||
|
||||
// Error message previously utilised to return errors to the client. Deprecated
|
||||
// in favour of using the google.golang.org/genproto/googleapis/rpc/status
|
||||
// message in the RPC response.
|
||||
// Reference: gNMI Specification Section 2.5
|
||||
message Error {
|
||||
option deprecated = true;
|
||||
uint32 code = 1; // Canonical gRPC error code.
|
||||
string message = 2; // Human readable error.
|
||||
google.protobuf.Any data = 3; // Optional additional information.
|
||||
}
|
||||
|
||||
// Decimal64 is used to encode a fixed precision decimal number. The value
|
||||
// is expressed as a set of digits with the precision specifying the
|
||||
// number of digits following the decimal point in the digit set.
|
||||
message Decimal64 {
|
||||
int64 digits = 1; // Set of digits.
|
||||
uint32 precision = 2; // Number of digits following the decimal point.
|
||||
}
|
||||
|
||||
// ScalarArray is used to encode a mixed-type array of values.
|
||||
message ScalarArray {
|
||||
// The set of elements within the array. Each TypedValue message should
|
||||
// specify only elements that have a field identifier of 1-7 (i.e., the
|
||||
// values are scalar values).
|
||||
repeated TypedValue element = 1;
|
||||
}
|
||||
|
||||
// SubscribeRequest is the message sent by the client to the target when
|
||||
// initiating a subscription to a set of paths within the data tree. The
|
||||
// request field must be populated and the initial message must specify a
|
||||
// SubscriptionList to initiate a subscription. The message is subsequently
|
||||
// used to define aliases or trigger polled data to be sent by the target.
|
||||
// Reference: gNMI Specification Section 3.5.1.1
|
||||
message SubscribeRequest {
|
||||
oneof request {
|
||||
SubscriptionList subscribe = 1; // Specify the paths within a subscription.
|
||||
Poll poll = 3; // Trigger a polled update.
|
||||
AliasList aliases = 4; // Aliases to be created.
|
||||
}
|
||||
// Extension messages associated with the SubscribeRequest. See the
|
||||
// gNMI extension specification for further definition.
|
||||
repeated gnmi_ext.Extension extension = 5;
|
||||
}
|
||||
|
||||
// Poll is sent within a SubscribeRequest to trigger the device to
|
||||
// send telemetry updates for the paths that are associated with the
|
||||
// subscription.
|
||||
// Reference: gNMI Specification Section Section 3.5.1.4
|
||||
message Poll {
|
||||
}
|
||||
|
||||
// SubscribeResponse is the message used by the target within a Subscribe RPC.
|
||||
// The target includes a Notification message which is used to transmit values
|
||||
// of the path(s) that are associated with the subscription. The same message
|
||||
// is to indicate that the target has sent all data values once (is
|
||||
// synchronized).
|
||||
// Reference: gNMI Specification Section 3.5.1.4
|
||||
message SubscribeResponse {
|
||||
oneof response {
|
||||
Notification update = 1; // Changed or sampled value for a path.
|
||||
// Indicate target has sent all values associated with the subscription
|
||||
// at least once.
|
||||
bool sync_response = 3;
|
||||
// Deprecated in favour of google.golang.org/genproto/googleapis/rpc/status
|
||||
Error error = 4 [deprecated=true];
|
||||
}
|
||||
// Extension messages associated with the SubscribeResponse. See the
|
||||
// gNMI extension specification for further definition.
|
||||
repeated gnmi_ext.Extension extension = 5;
|
||||
}
|
||||
|
||||
// SubscriptionList is used within a Subscribe message to specify the list of
|
||||
// paths that the client wishes to subscribe to. The message consists of a
|
||||
// list of (possibly prefixed) paths, and options that relate to the
|
||||
// subscription.
|
||||
// Reference: gNMI Specification Section 3.5.1.2
|
||||
message SubscriptionList {
|
||||
Path prefix = 1; // Prefix used for paths.
|
||||
repeated Subscription subscription = 2; // Set of subscriptions to create.
|
||||
// Whether target defined aliases are allowed within the subscription.
|
||||
bool use_aliases = 3;
|
||||
QOSMarking qos = 4; // DSCP marking to be used.
|
||||
// Mode of the subscription.
|
||||
enum Mode {
|
||||
STREAM = 0; // Values streamed by the target (Sec. 3.5.1.5.2).
|
||||
ONCE = 1; // Values sent once-off by the target (Sec. 3.5.1.5.1).
|
||||
POLL = 2; // Values sent in response to a poll request (Sec. 3.5.1.5.3).
|
||||
}
|
||||
Mode mode = 5;
|
||||
// Whether elements of the schema that are marked as eligible for aggregation
|
||||
// should be aggregated or not.
|
||||
bool allow_aggregation = 6;
|
||||
// The set of schemas that define the elements of the data tree that should
|
||||
// be sent by the target.
|
||||
repeated ModelData use_models = 7;
|
||||
// The encoding that the target should use within the Notifications generated
|
||||
// corresponding to the SubscriptionList.
|
||||
Encoding encoding = 8;
|
||||
// An optional field to specify that only updates to current state should be
|
||||
// sent to a client. If set, the initial state is not sent to the client but
|
||||
// rather only the sync message followed by any subsequent updates to the
|
||||
// current state. For ONCE and POLL modes, this causes the server to send only
|
||||
// the sync message (Sec. 3.5.2.3).
|
||||
bool updates_only = 9;
|
||||
}
|
||||
|
||||
// Subscription is a single request within a SubscriptionList. The path
|
||||
// specified is interpreted (along with the prefix) as the elements of the data
|
||||
// tree that the client is subscribing to. The mode determines how the target
|
||||
// should trigger updates to be sent.
|
||||
// Reference: gNMI Specification Section 3.5.1.3
|
||||
message Subscription {
|
||||
Path path = 1; // The data tree path.
|
||||
SubscriptionMode mode = 2; // Subscription mode to be used.
|
||||
uint64 sample_interval = 3; // ns between samples in SAMPLE mode.
|
||||
// Indicates whether values that have not changed should be sent in a SAMPLE
|
||||
// subscription.
|
||||
bool suppress_redundant = 4;
|
||||
// Specifies the maximum allowable silent period in nanoseconds when
|
||||
// suppress_redundant is in use. The target should send a value at least once
|
||||
// in the period specified.
|
||||
uint64 heartbeat_interval = 5;
|
||||
}
|
||||
|
||||
// SubscriptionMode is the mode of the subscription, specifying how the
|
||||
// target must return values in a subscription.
|
||||
// Reference: gNMI Specification Section 3.5.1.3
|
||||
enum SubscriptionMode {
|
||||
TARGET_DEFINED = 0; // The target selects the relevant mode for each element.
|
||||
ON_CHANGE = 1; // The target sends an update on element value change.
|
||||
SAMPLE = 2; // The target samples values according to the interval.
|
||||
}
|
||||
|
||||
// QOSMarking specifies the DSCP value to be set on transmitted telemetry
|
||||
// updates from the target.
|
||||
// Reference: gNMI Specification Section 3.5.1.2
|
||||
message QOSMarking {
|
||||
uint32 marking = 1;
|
||||
}
|
||||
|
||||
// Alias specifies a data tree path, and an associated string which defines an
|
||||
// alias which is to be used for this path in the context of the RPC. The alias
|
||||
// is specified as a string which is prefixed with "#" to disambiguate it from
|
||||
// data tree element paths.
|
||||
// Reference: gNMI Specification Section 2.4.2
|
||||
message Alias {
|
||||
Path path = 1; // The path to be aliased.
|
||||
string alias = 2; // The alias value, a string prefixed by "#".
|
||||
}
|
||||
|
||||
// AliasList specifies a list of aliases. It is used in a SubscribeRequest for
|
||||
// a client to create a set of aliases that the target is to utilize.
|
||||
// Reference: gNMI Specification Section 3.5.1.6
|
||||
message AliasList {
|
||||
repeated Alias alias = 1; // The set of aliases to be created.
|
||||
}
|
||||
|
||||
// SetRequest is sent from a client to the target to update values in the data
|
||||
// tree. Paths are either deleted by the client, or modified by means of being
|
||||
// updated, or replaced. Where a replace is used, unspecified values are
|
||||
// considered to be replaced, whereas when update is used the changes are
|
||||
// considered to be incremental. The set of changes that are specified within
|
||||
// a single SetRequest are considered to be a transaction.
|
||||
// Reference: gNMI Specification Section 3.4.1
|
||||
message SetRequest {
|
||||
Path prefix = 1; // Prefix used for paths in the message.
|
||||
repeated Path delete = 2; // Paths to be deleted from the data tree.
|
||||
repeated Update replace = 3; // Updates specifying elements to be replaced.
|
||||
repeated Update update = 4; // Updates specifying elements to updated.
|
||||
// Extension messages associated with the SetRequest. See the
|
||||
// gNMI extension specification for further definition.
|
||||
repeated gnmi_ext.Extension extension = 5;
|
||||
}
|
||||
|
||||
// SetResponse is the response to a SetRequest, sent from the target to the
|
||||
// client. It reports the result of the modifications to the data tree that were
|
||||
// specified by the client. Errors for this RPC should be reported using the
|
||||
// https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto
|
||||
// message in the RPC return. The gnmi.Error message can be used to add additional
|
||||
// details where required.
|
||||
// Reference: gNMI Specification Section 3.4.2
|
||||
message SetResponse {
|
||||
Path prefix = 1; // Prefix used for paths.
|
||||
// A set of responses specifying the result of the operations specified in
|
||||
// the SetRequest.
|
||||
repeated UpdateResult response = 2;
|
||||
Error message = 3 [deprecated=true]; // The overall status of the transaction.
|
||||
int64 timestamp = 4; // Timestamp of transaction (ns since epoch).
|
||||
// Extension messages associated with the SetResponse. See the
|
||||
// gNMI extension specification for further definition.
|
||||
repeated gnmi_ext.Extension extension = 5;
|
||||
}
|
||||
|
||||
// UpdateResult is used within the SetResponse message to communicate the
|
||||
// result of an operation specified within a SetRequest message.
|
||||
// Reference: gNMI Specification Section 3.4.2
|
||||
message UpdateResult {
|
||||
// The operation that was associated with the Path specified.
|
||||
enum Operation {
|
||||
INVALID = 0;
|
||||
DELETE = 1; // The result relates to a delete of Path.
|
||||
REPLACE = 2; // The result relates to a replace of Path.
|
||||
UPDATE = 3; // The result relates to an update of Path.
|
||||
}
|
||||
// Deprecated timestamp for the UpdateResult, this field has been
|
||||
// replaced by the timestamp within the SetResponse message, since
|
||||
// all mutations effected by a set should be applied as a single
|
||||
// transaction.
|
||||
int64 timestamp = 1 [deprecated=true];
|
||||
Path path = 2; // Path associated with the update.
|
||||
Error message = 3 [deprecated=true]; // Status of the update operation.
|
||||
Operation op = 4; // Update operation type.
|
||||
}
|
||||
|
||||
// GetRequest is sent when a client initiates a Get RPC. It is used to specify
|
||||
// the set of data elements for which the target should return a snapshot of
|
||||
// data. The use_models field specifies the set of schema modules that are to
|
||||
// be used by the target - where use_models is not specified then the target
|
||||
// must use all schema models that it has.
|
||||
// Reference: gNMI Specification Section 3.3.1
|
||||
message GetRequest {
|
||||
Path prefix = 1; // Prefix used for paths.
|
||||
repeated Path path = 2; // Paths requested by the client.
|
||||
// Type of elements within the data tree.
|
||||
enum DataType {
|
||||
ALL = 0; // All data elements.
|
||||
CONFIG = 1; // Config (rw) only elements.
|
||||
STATE = 2; // State (ro) only elements.
|
||||
// Data elements marked in the schema as operational. This refers to data
|
||||
// elements whose value relates to the state of processes or interactions
|
||||
// running on the device.
|
||||
OPERATIONAL = 3;
|
||||
}
|
||||
DataType type = 3; // The type of data being requested.
|
||||
Encoding encoding = 5; // Encoding to be used.
|
||||
repeated ModelData use_models = 6; // The schema models to be used.
|
||||
// Extension messages associated with the GetRequest. See the
|
||||
// gNMI extension specification for further definition.
|
||||
repeated gnmi_ext.Extension extension = 7;
|
||||
}
|
||||
|
||||
// GetResponse is used by the target to respond to a GetRequest from a client.
|
||||
// The set of Notifications corresponds to the data values that are requested
|
||||
// by the client in the GetRequest.
|
||||
// Reference: gNMI Specification Section 3.3.2
|
||||
message GetResponse {
|
||||
repeated Notification notification = 1; // Data values.
|
||||
Error error = 2 [deprecated=true]; // Errors that occurred in the Get.
|
||||
// Extension messages associated with the GetResponse. See the
|
||||
// gNMI extension specification for further definition.
|
||||
repeated gnmi_ext.Extension extension = 3;
|
||||
}
|
||||
|
||||
// CapabilityRequest is sent by the client in the Capabilities RPC to request
|
||||
// that the target reports its capabilities.
|
||||
// Reference: gNMI Specification Section 3.2.1
|
||||
message CapabilityRequest {
|
||||
// Extension messages associated with the CapabilityRequest. See the
|
||||
// gNMI extension specification for further definition.
|
||||
repeated gnmi_ext.Extension extension = 1;
|
||||
}
|
||||
|
||||
// CapabilityResponse is used by the target to report its capabilities to the
|
||||
// client within the Capabilities RPC.
|
||||
// Reference: gNMI Specification Section 3.2.2
|
||||
message CapabilityResponse {
|
||||
repeated ModelData supported_models = 1; // Supported schema models.
|
||||
repeated Encoding supported_encodings = 2; // Supported encodings.
|
||||
string gNMI_version = 3; // Supported gNMI version.
|
||||
// Extension messages associated with the CapabilityResponse. See the
|
||||
// gNMI extension specification for further definition.
|
||||
repeated gnmi_ext.Extension extension = 4;
|
||||
}
|
||||
|
||||
// ModelData is used to describe a set of schema modules. It can be used in a
|
||||
// CapabilityResponse where a target reports the set of modules that it
|
||||
// supports, and within the SubscribeRequest and GetRequest messages to specify
|
||||
// the set of models from which data tree elements should be reported.
|
||||
// Reference: gNMI Specification Section 3.2.3
|
||||
message ModelData {
|
||||
string name = 1; // Name of the model.
|
||||
string organization = 2; // Organization publishing the model.
|
||||
string version = 3; // Semantic version of the model.
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Copyright 2018 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
syntax = "proto3";
|
||||
|
||||
// Package gnmi_ext defines a set of extensions messages which can be optionally
|
||||
// included with the request and response messages of gNMI RPCs. A set of
|
||||
// well-known extensions are defined within this file, along with a registry for
|
||||
// extensions defined outside of this package.
|
||||
package gnmi_ext;
|
||||
|
||||
// The Extension message contains a single gNMI extension.
|
||||
message Extension {
|
||||
oneof ext {
|
||||
RegisteredExtension registered_ext = 1; // A registered extension.
|
||||
// Well known extensions.
|
||||
MasterArbitration master_arbitration = 2; // Master arbitration extension.
|
||||
History history = 3; // History extension.
|
||||
}
|
||||
}
|
||||
|
||||
// The RegisteredExtension message defines an extension which is defined outside
|
||||
// of this file.
|
||||
message RegisteredExtension {
|
||||
ExtensionID id = 1; // The unique ID assigned to this extension.
|
||||
bytes msg = 2; // The binary-marshalled protobuf extension payload.
|
||||
}
|
||||
|
||||
// RegisteredExtension is an enumeration acting as a registry for extensions
|
||||
// defined by external sources.
|
||||
enum ExtensionID {
|
||||
EID_UNSET = 0;
|
||||
// New extensions are to be defined within this enumeration - their definition
|
||||
// MUST link to a reference describing their implementation.
|
||||
|
||||
// An experimental extension that may be used during prototyping of a new
|
||||
// extension.
|
||||
EID_EXPERIMENTAL = 999;
|
||||
}
|
||||
|
||||
// MasterArbitration is used to select the master among multiple gNMI clients
|
||||
// with the same Roles. The client with the largest election_id is honored as
|
||||
// the master.
|
||||
// The document about gNMI master arbitration can be found at
|
||||
// https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-master-arbitration.md
|
||||
message MasterArbitration {
|
||||
Role role = 1;
|
||||
Uint128 election_id = 2;
|
||||
}
|
||||
|
||||
// Representation of unsigned 128-bit integer.
|
||||
message Uint128 {
|
||||
uint64 high = 1;
|
||||
uint64 low = 2;
|
||||
}
|
||||
|
||||
// There can be one master for each role. The role is identified by its id.
|
||||
message Role {
|
||||
string id = 1;
|
||||
// More fields can be added if needed, for example, to specify what paths the
|
||||
// role can read/write.
|
||||
}
|
||||
|
||||
// The History extension allows clients to request historical data. Its
|
||||
// spec can be found at
|
||||
// https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-history.md
|
||||
message History {
|
||||
oneof request {
|
||||
int64 snapshot_time = 1; // Nanoseconds since the epoch
|
||||
TimeRange range = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message TimeRange {
|
||||
int64 start = 1; // Nanoseconds since the epoch
|
||||
int64 end = 2; // Nanoseconds since the epoch
|
||||
}
|
||||
315
src/ucentral-client/platform/larch-sonic/protos/sonic_gnoi.proto
Normal file
315
src/ucentral-client/platform/larch-sonic/protos/sonic_gnoi.proto
Normal file
@@ -0,0 +1,315 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package gnoi.sonic;
|
||||
|
||||
|
||||
//option (types.gnoi_version) = "0.1.0";
|
||||
|
||||
service SonicService {
|
||||
rpc ShowTechsupport (TechsupportRequest) returns (TechsupportResponse) {}
|
||||
rpc ShowTechsupportCancel (TechsupportCancelRequest) returns (TechsupportCancelResponse) {}
|
||||
rpc Sum (SumRequest) returns (SumResponse) {}
|
||||
|
||||
rpc ImageInstall(ImageInstallRequest) returns (ImageInstallResponse) {}
|
||||
rpc ImageRemove(ImageRemoveRequest) returns (ImageRemoveResponse) {}
|
||||
rpc ImageDefault(ImageDefaultRequest) returns (ImageDefaultResponse) {}
|
||||
|
||||
rpc Authenticate(AuthenticateRequest) returns (AuthenticateResponse) {}
|
||||
rpc Refresh(RefreshRequest) returns (RefreshResponse) {}
|
||||
rpc ClearNeighbors(ClearNeighborsRequest) returns (ClearNeighborsResponse) {}
|
||||
rpc VlanReplace(VlanReplaceRequest) returns (VlanReplaceResponse) {}
|
||||
|
||||
rpc GetAuditLog (GetAuditLogRequest) returns (GetAuditLogResponse) {}
|
||||
rpc ClearAuditLog (ClearAuditLogRequest) returns (ClearAuditLogResponse) {}
|
||||
rpc ShowSysLog(ShowSysLogRequest) returns (GetShowSysLogResponse) {}
|
||||
|
||||
rpc GetEvents (GetEventsRequest) returns (GetEventsResponse) {}
|
||||
rpc GetAlarms (GetAlarmsRequest) returns (GetAlarmsResponse) {}
|
||||
rpc AckAlarms (AckAlarmsRequest) returns (AckAlarmsResponse) {}
|
||||
rpc UnackAlarms (UnackAlarmsRequest) returns (UnackAlarmsResponse) {}
|
||||
rpc GetEventProfile (GetEventProfileRequest) returns (GetEventProfileResponse) {}
|
||||
rpc SetEventProfile (SetEventProfileRequest) returns (SetEventProfileResponse) {}
|
||||
|
||||
}
|
||||
|
||||
|
||||
message SonicOutput {
|
||||
int32 status = 1;
|
||||
string status_detail = 2;
|
||||
}
|
||||
|
||||
message GetEventProfileRequest {
|
||||
}
|
||||
|
||||
message GetEventProfileResponse {
|
||||
message Output {
|
||||
string file_name = 1;
|
||||
repeated string file_list = 2;
|
||||
}
|
||||
Output output = 1;
|
||||
}
|
||||
|
||||
message SetEventProfileRequest {
|
||||
message Input {
|
||||
string filename =1;
|
||||
}
|
||||
Input input =1;
|
||||
}
|
||||
|
||||
message SetEventProfileResponse {
|
||||
SonicOutput output = 1;
|
||||
}
|
||||
|
||||
message AckAlarmsRequest {
|
||||
message Input {
|
||||
repeated string id = 1;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
|
||||
message AckAlarmsResponse {
|
||||
SonicOutput output = 1;
|
||||
}
|
||||
|
||||
message UnackAlarmsRequest {
|
||||
message Input {
|
||||
repeated string id = 1;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
|
||||
message UnackAlarmsResponse {
|
||||
SonicOutput output = 1;
|
||||
}
|
||||
|
||||
message EventTimeFilter {
|
||||
string begin = 1;
|
||||
string end = 2;
|
||||
}
|
||||
|
||||
message EventId {
|
||||
string begin = 1;
|
||||
string end = 2;
|
||||
}
|
||||
|
||||
message EventsFilter {
|
||||
EventTimeFilter time = 1;
|
||||
string interval = 2;
|
||||
string severity = 3;
|
||||
EventId id = 4;
|
||||
}
|
||||
|
||||
message GetEventsRequest {
|
||||
EventsFilter input = 1;
|
||||
}
|
||||
|
||||
message Event {
|
||||
string id = 1;
|
||||
string resource = 2;
|
||||
string text = 3;
|
||||
string time_created = 4;
|
||||
string type_id = 5;
|
||||
string severity = 6;
|
||||
string action = 7;
|
||||
}
|
||||
|
||||
message Events {
|
||||
repeated Event EVENT_LIST = 1;
|
||||
}
|
||||
|
||||
message EventsResponse {
|
||||
int32 status = 1;
|
||||
string status_detail = 2;
|
||||
Events EVENT =3;
|
||||
}
|
||||
|
||||
message GetEventsResponse {
|
||||
EventsResponse output = 1;
|
||||
}
|
||||
|
||||
message Alarm {
|
||||
string id = 1;
|
||||
string resource = 2;
|
||||
string text = 3;
|
||||
string time_created = 4;
|
||||
string type_id = 5;
|
||||
string severity = 6;
|
||||
bool acknowledged = 7;
|
||||
string acknowledge_time = 8;
|
||||
}
|
||||
|
||||
message GetAlarmsRequest {
|
||||
EventsFilter input = 1;
|
||||
}
|
||||
|
||||
message Alarms {
|
||||
repeated Alarm ALARM_LIST = 1;
|
||||
}
|
||||
|
||||
message AlarmsResponse {
|
||||
int32 status = 1;
|
||||
string status_detail = 2;
|
||||
Alarms ALARM =3;
|
||||
}
|
||||
|
||||
message GetAlarmsResponse {
|
||||
AlarmsResponse output = 1;
|
||||
}
|
||||
|
||||
|
||||
message TechsupportRequest {
|
||||
message Input {
|
||||
string date = 1;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
|
||||
message TechsupportResponse {
|
||||
message Output {
|
||||
uint32 status = 1;
|
||||
string status_detail = 2;
|
||||
string output_filename = 3;
|
||||
}
|
||||
Output output = 1;
|
||||
}
|
||||
|
||||
message TechsupportCancelRequest {
|
||||
}
|
||||
|
||||
message TechsupportCancelResponse {
|
||||
message Output {
|
||||
uint32 status = 1;
|
||||
string status_detail = 2;
|
||||
}
|
||||
Output output = 1;
|
||||
}
|
||||
|
||||
message ClearNeighborsRequest {
|
||||
message Input {
|
||||
bool force = 1;
|
||||
string family = 2;
|
||||
string ip = 3;
|
||||
string ifname = 4;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
|
||||
message ClearNeighborsResponse {
|
||||
message Output {
|
||||
string response = 1;
|
||||
}
|
||||
Output output = 1;
|
||||
}
|
||||
|
||||
message VlanReplaceRequest {
|
||||
message Input {
|
||||
string ifname = 1;
|
||||
string vlanlist = 2;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
|
||||
message VlanReplaceResponse {
|
||||
message Output {
|
||||
string response = 1;
|
||||
}
|
||||
Output output = 1;
|
||||
}
|
||||
|
||||
message SumRequest {
|
||||
message Input {
|
||||
int32 left = 1;
|
||||
int32 right = 2;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
message SumResponse {
|
||||
message Output {
|
||||
int32 result = 1;
|
||||
}
|
||||
Output output = 1;
|
||||
}
|
||||
|
||||
message ImageInstallRequest {
|
||||
message Input {
|
||||
string imagename = 1;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
message ImageInstallResponse {
|
||||
SonicOutput output = 1;
|
||||
}
|
||||
message ImageRemoveRequest {
|
||||
message Input {
|
||||
string imagename = 1;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
message ImageRemoveResponse {
|
||||
SonicOutput output = 1;
|
||||
}
|
||||
message ImageDefaultRequest {
|
||||
message Input {
|
||||
string imagename = 1;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
message ImageDefaultResponse {
|
||||
SonicOutput output = 1;
|
||||
}
|
||||
|
||||
message GetAuditLogRequest {
|
||||
message Input {
|
||||
string content_type = 1;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
|
||||
message GetAuditLogResponse {
|
||||
message AuditOutput {
|
||||
repeated string audit_content = 1;
|
||||
}
|
||||
AuditOutput output = 1;
|
||||
}
|
||||
|
||||
message ClearAuditLogRequest {
|
||||
}
|
||||
|
||||
message ClearAuditLogResponse {
|
||||
SonicOutput output = 1;
|
||||
}
|
||||
|
||||
message ShowSysLogRequest {
|
||||
message Input {
|
||||
int32 num_lines = 1 ;
|
||||
}
|
||||
Input input = 1;
|
||||
}
|
||||
|
||||
message ShowSysLogResponse {
|
||||
repeated string status_detail = 1;
|
||||
}
|
||||
message GetShowSysLogResponse {
|
||||
ShowSysLogResponse output = 1;
|
||||
}
|
||||
|
||||
message JwtToken {
|
||||
string access_token = 1;
|
||||
string type = 2;
|
||||
int64 expires_in = 3;
|
||||
}
|
||||
message AuthenticateRequest {
|
||||
string username = 1;
|
||||
string password = 2;
|
||||
}
|
||||
|
||||
message AuthenticateResponse {
|
||||
JwtToken Token = 1;
|
||||
}
|
||||
|
||||
message RefreshRequest {
|
||||
}
|
||||
|
||||
message RefreshResponse {
|
||||
JwtToken Token = 1;
|
||||
}
|
||||
339
src/ucentral-client/platform/larch-sonic/protos/system.proto
Normal file
339
src/ucentral-client/platform/larch-sonic/protos/system.proto
Normal file
@@ -0,0 +1,339 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
// Generic Network Operation Interface, GNOI, defines a set of RPC's used for
|
||||
// the operational aspects of network targets. These services are meant to be
|
||||
// used in conjunction with GNMI for all target state and operational aspects
|
||||
// of a network target. The gnoi.system.Service is the only mandatory vendor
|
||||
// implementation.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package gnoi.system;
|
||||
|
||||
import "common.proto";
|
||||
import "types.proto";
|
||||
|
||||
option (types.gnoi_version) = "1.0.0";
|
||||
|
||||
// The gNOI service is a collection of operational RPC's that allow for the
|
||||
// management of a target outside of the configuration and telemetry pipeline.
|
||||
service System {
|
||||
// Ping executes the ping command on the target and streams back
|
||||
// the results. Some targets may not stream any results until all
|
||||
// results are in. The stream should provide single ping packet responses
|
||||
// and must provide summary statistics.
|
||||
rpc Ping(PingRequest) returns (stream PingResponse) {}
|
||||
|
||||
// Traceroute executes the traceroute command on the target and streams back
|
||||
// the results. Some targets may not stream any results until all
|
||||
// results are in. If a hop count is not explicitly provided,
|
||||
// 30 is used.
|
||||
rpc Traceroute(TracerouteRequest) returns (stream TracerouteResponse) {}
|
||||
|
||||
// Time returns the current time on the target. Time is typically used to
|
||||
// test if a target is actually responding.
|
||||
rpc Time(TimeRequest) returns (TimeResponse) {}
|
||||
|
||||
// SetPackage places a software package (possibly including bootable images)
|
||||
// on the target. The file is sent in sequential messages, each message
|
||||
// up to 64KB of data. A final message must be sent that includes the hash
|
||||
// of the data sent. An error is returned if the location does not exist or
|
||||
// there is an error writing the data. If no checksum is received, the target
|
||||
// must assume the operation is incomplete and remove the partially
|
||||
// transmitted file. The target should initially write the file to a temporary
|
||||
// location so a failure does not destroy the original file.
|
||||
rpc SetPackage(stream SetPackageRequest) returns (SetPackageResponse) {}
|
||||
|
||||
// SwitchControlProcessor will switch from the current route processor to the
|
||||
// provided route processor. If the current route processor is the same as the
|
||||
// one provided it is a NOOP. If the target does not exist an error is
|
||||
// returned.
|
||||
rpc SwitchControlProcessor(SwitchControlProcessorRequest)
|
||||
returns (SwitchControlProcessorResponse) {}
|
||||
|
||||
// Reboot causes the target to reboot, possibly at some point in the future.
|
||||
// If the method of reboot is not supported then the Reboot RPC will fail.
|
||||
// If the reboot is immediate the command will block until the subcomponents
|
||||
// have restarted.
|
||||
// If a reboot on the active control processor is pending the service must
|
||||
// reject all other reboot requests.
|
||||
// If a reboot request for active control processor is initiated with other
|
||||
// pending reboot requests it must be rejected.
|
||||
rpc Reboot(RebootRequest) returns (RebootResponse) {}
|
||||
|
||||
// RebootStatus returns the status of reboot for the target.
|
||||
rpc RebootStatus(RebootStatusRequest) returns (RebootStatusResponse) {}
|
||||
|
||||
// CancelReboot cancels any pending reboot request.
|
||||
rpc CancelReboot(CancelRebootRequest) returns (CancelRebootResponse) {}
|
||||
|
||||
// KillProcess kills an OS process and optionally restarts it.
|
||||
rpc KillProcess(KillProcessRequest) returns (KillProcessResponse) {}
|
||||
|
||||
// TODO(hines): Add RotateCertificate workflow
|
||||
// TODO(hines): Add SetSSHPrivateKey
|
||||
}
|
||||
|
||||
message SwitchControlProcessorRequest {
|
||||
types.Path control_processor = 1;
|
||||
}
|
||||
|
||||
message SwitchControlProcessorResponse {
|
||||
types.Path control_processor = 1;
|
||||
string version = 2; // Current software version.
|
||||
int64 uptime = 3; // Uptime in nanoseconds since epoch.
|
||||
}
|
||||
|
||||
// A RebootRequest requests the specified target be rebooted using the specified
|
||||
// method after the specified delay. Only the DEFAULT method with a delay of 0
|
||||
// is guaranteed to be accepted for all target types.
|
||||
message RebootRequest {
|
||||
RebootMethod method = 1;
|
||||
// Delay in nanoseconds before issuing reboot.
|
||||
uint64 delay = 2;
|
||||
// Informational reason for the reboot.
|
||||
string message = 3;
|
||||
// Optional sub-components to reboot.
|
||||
repeated types.Path subcomponents = 4;
|
||||
// Force reboot if sanity checks fail. (ex. uncommited configuration)
|
||||
bool force = 5;
|
||||
}
|
||||
|
||||
message RebootResponse {
|
||||
}
|
||||
|
||||
// A RebootMethod determines what should be done with a target when a Reboot is
|
||||
// requested. Only the COLD method is required to be supported by all
|
||||
// targets. Methods the target does not support should result in failure.
|
||||
//
|
||||
// It is vendor defined if a WARM reboot is the same as an NSF reboot.
|
||||
enum RebootMethod {
|
||||
UNKNOWN = 0; // Invalid default method.
|
||||
COLD = 1; // Shutdown and restart OS and all hardware.
|
||||
POWERDOWN = 2; // Halt and power down, if possible.
|
||||
HALT = 3; // Halt, if possible.
|
||||
WARM = 4; // Reload configuration but not underlying hardware.
|
||||
NSF = 5; // Non-stop-forwarding reboot, if possible.
|
||||
// RESET method is deprecated in favor of the gNOI FactoryReset.Start().
|
||||
reserved 6;
|
||||
POWERUP = 7; // Apply power, no-op if power is already on.
|
||||
}
|
||||
|
||||
// A CancelRebootRequest requests the cancelation of any outstanding reboot
|
||||
// request.
|
||||
message CancelRebootRequest {
|
||||
string message = 1; // informational reason for the cancel
|
||||
repeated types.Path subcomponents = 2; // optional sub-components.
|
||||
}
|
||||
|
||||
message CancelRebootResponse {
|
||||
}
|
||||
|
||||
message RebootStatusRequest {
|
||||
repeated types.Path subcomponents = 1; // optional sub-component.
|
||||
}
|
||||
|
||||
message RebootStatusResponse {
|
||||
bool active = 1; // If reboot is active.
|
||||
uint64 wait = 2; // Time left until reboot.
|
||||
uint64 when = 3; // Time to reboot in nanoseconds since the epoch.
|
||||
string reason = 4; // Reason for reboot.
|
||||
uint32 count = 5; // Number of reboots since active.
|
||||
}
|
||||
|
||||
// A TimeRequest requests the current time accodring to the target.
|
||||
message TimeRequest {
|
||||
}
|
||||
|
||||
message TimeResponse {
|
||||
uint64 time = 1; // Current time in nanoseconds since epoch.
|
||||
}
|
||||
|
||||
// A PingRequest describes the ping operation to perform. Only the destination
|
||||
// fields is required. Any field not specified is set to a reasonable server
|
||||
// specified value. Not all fields are supported by all vendors.
|
||||
//
|
||||
// A count of 0 defaults to a vendor specified value, typically 5. A count of
|
||||
// -1 means continue until the RPC times out or is canceled.
|
||||
//
|
||||
// If the interval is -1 then a flood ping is issued.
|
||||
//
|
||||
// If the size is 0, the vendor default size will be used (typically 56 bytes).
|
||||
message PingRequest {
|
||||
string destination = 1; // Destination address to ping. required.
|
||||
string source = 2; // Source address to ping from.
|
||||
int32 count = 3; // Number of packets.
|
||||
int64 interval = 4; // Nanoseconds between requests.
|
||||
int64 wait = 5; // Nanoseconds to wait for a response.
|
||||
int32 size = 6; // Size of request packet. (excluding ICMP header)
|
||||
bool do_not_fragment = 7; // Set the do not fragment bit. (IPv4 destinations)
|
||||
bool do_not_resolve = 8; // Do not try resolve the address returned.
|
||||
types.L3Protocol l3protocol = 9; // Layer3 protocol requested for the ping.
|
||||
}
|
||||
|
||||
// A PingResponse represents either the reponse to a single ping packet
|
||||
// (the bytes field is non-zero) or the summary statistics (sent is non-zero).
|
||||
//
|
||||
// For a single ping packet, time is the round trip time, in nanoseconds. For
|
||||
// summary statistics, it is the time spent by the ping operation. The time is
|
||||
// not always present in summary statistics. The std_dev is not always present
|
||||
// in summary statistics.
|
||||
message PingResponse {
|
||||
string source = 1; // Source of received bytes.
|
||||
int64 time = 2;
|
||||
|
||||
int32 sent = 3; // Total packets sent.
|
||||
int32 received = 4; // Total packets received.
|
||||
int64 min_time = 5; // Minimum round trip time in nanoseconds.
|
||||
int64 avg_time = 6; // Average round trip time in nanoseconds.
|
||||
int64 max_time = 7; // Maximum round trip time in nanoseconds.
|
||||
int64 std_dev = 8; // Standard deviation in round trip time.
|
||||
|
||||
int32 bytes = 11; // Bytes received.
|
||||
int32 sequence = 12; // Sequence number of received packet.
|
||||
int32 ttl = 13; // Remaining time to live value.
|
||||
}
|
||||
|
||||
// A TracerouteRequest describes the traceroute operation to perform. Only the
|
||||
// destination field is required. Any field not specified is set to a
|
||||
// reasonable server specified value. Not all fields are supported by all
|
||||
// vendors.
|
||||
//
|
||||
// If the hop_count is -1 the traceroute will continue forever.
|
||||
//
|
||||
message TracerouteRequest {
|
||||
string source = 1; // Source address to ping from.
|
||||
string destination = 2; // Destination address to ping.
|
||||
uint32 initial_ttl = 3; // Initial TTL. (default=1)
|
||||
int32 max_ttl = 4; // Maximum number of hops. (default=30)
|
||||
int64 wait = 5; // Nanoseconds to wait for a response.
|
||||
bool do_not_fragment = 6; // Set the do not fragment bit. (IPv4 destinations)
|
||||
bool do_not_resolve = 7; // Do not try resolve the address returned.
|
||||
types.L3Protocol l3protocol = 8; // Layer-3 protocol requested for the ping.
|
||||
enum L4Protocol {
|
||||
ICMP = 0; // Use ICMP ECHO for probes.
|
||||
TCP = 1; // Use TCP SYN for probes.
|
||||
UDP = 2; // Use UDP for probes.
|
||||
}
|
||||
L4Protocol l4protocol = 9;
|
||||
bool do_not_lookup_asn = 10; // Do not try to lookup ASN
|
||||
}
|
||||
|
||||
// A TraceRouteResponse contains the result of a single traceoute packet.
|
||||
//
|
||||
// There may be an optional initial response that provides information about the
|
||||
// traceroute request itself and contains at least one of the fields in the the
|
||||
// initial block of fields and none of the fields following that block. All
|
||||
// subsequent responses should not contain any of these fields.
|
||||
//
|
||||
// Typically multiple responses are received for each hop, as the packets are
|
||||
// received.
|
||||
//
|
||||
// The mpls field maps names to values. Example names include "Label", "CoS",
|
||||
// "TTL", "S", and "MRU".
|
||||
// [Perhaps we should list the canonical names that must be used when
|
||||
// applicable].
|
||||
message TracerouteResponse {
|
||||
// The following fields are only filled in for the first message.
|
||||
// If any of these fields are specified, all fields following this
|
||||
// block are left unspecified.
|
||||
string destination_name = 1;
|
||||
string destination_address = 2;
|
||||
int32 hops = 3;
|
||||
int32 packet_size = 4;
|
||||
|
||||
// State is the resulting state of a single traceoroute packet.
|
||||
enum State {
|
||||
DEFAULT = 0; // Normal hop response.
|
||||
NONE = 1; // No response.
|
||||
UNKNOWN = 2; // Unknown response state.
|
||||
ICMP = 3; // See icmp_code field.
|
||||
HOST_UNREACHABLE = 4; // Host unreachable.
|
||||
NETWORK_UNREACHABLE = 5; // Network unreachable.
|
||||
PROTOCOL_UNREACHABLE = 6; // Protocol unreachable.
|
||||
SOURCE_ROUTE_FAILED = 7; // Source route failed.
|
||||
FRAGMENTATION_NEEDED = 8; // Fragmentation needed.
|
||||
PROHIBITED = 9; // Communication administratively prohibited.
|
||||
PRECEDENCE_VIOLATION = 10; // Host precedence violation.
|
||||
PRECEDENCE_CUTOFF = 11; // Precedence cutoff in effect.
|
||||
}
|
||||
|
||||
// The following fields provide the disposition of a single traceroute
|
||||
// packet.
|
||||
int32 hop = 5; // Hop number. required.
|
||||
string address = 6; // Address of responding hop. required.
|
||||
string name = 7; // Name of responding hop.
|
||||
int64 rtt = 8; // Round trip time in nanoseconds.
|
||||
State state = 9; // State of this hop.
|
||||
int32 icmp_code = 10; // Code terminating hop.
|
||||
map<string, string> mpls = 11; // MPLS key/value pairs.
|
||||
repeated int32 as_path = 12; // AS path.
|
||||
}
|
||||
|
||||
// Package defines a single package file to be placed on the target.
|
||||
message Package {
|
||||
// Destination path and filename of the package.
|
||||
string filename = 1;
|
||||
// Version of the package. (vendor internal name)
|
||||
string version = 4;
|
||||
// Indicates that the package should be made active after receipt on
|
||||
// the device. For system image packages, the new image is expected to
|
||||
// be active after a reboot.
|
||||
bool activate = 5;
|
||||
// Details for the device to download the package from a remote location.
|
||||
common.RemoteDownload remote_download = 6;
|
||||
}
|
||||
|
||||
// SetPackageRequest will place the package onto the target and optionally mark
|
||||
// it as the next bootable image. The initial message must be a package
|
||||
// message containing the filename and information about the file. Following the
|
||||
// initial message the contents are then streamed in maximum 64k chunks. The
|
||||
// final message must be a hash message contains the hash of the file contents.
|
||||
message SetPackageRequest {
|
||||
oneof request {
|
||||
Package package = 1;
|
||||
bytes contents = 2;
|
||||
types.HashType hash = 3; // Verification hash of data.
|
||||
}
|
||||
}
|
||||
|
||||
message SetPackageResponse {
|
||||
}
|
||||
|
||||
// KillProcessRequest describes the process kill operation. Either a pid or
|
||||
// process name must be specified, and a termination signal must be specified.
|
||||
message KillProcessRequest {
|
||||
// Process ID of the process to be killed.
|
||||
uint32 pid = 1;
|
||||
// Name of the process to be killed.
|
||||
string name = 2;
|
||||
// Termination signal sent to the process.
|
||||
enum Signal {
|
||||
SIGNAL_UNSPECIFIED = 0; // Invalid default.
|
||||
SIGNAL_TERM = 1; // Terminate the process gracefully.
|
||||
SIGNAL_KILL = 2; // Terminate the process immediately.
|
||||
SIGNAL_HUP = 3; // Reload the process configuration.
|
||||
}
|
||||
Signal signal = 3;
|
||||
// Whether the process should be restarted after termination.
|
||||
// This value is ignored when the termination signal is SIGHUP.
|
||||
bool restart = 4;
|
||||
}
|
||||
|
||||
// KillProcessResponse describes the result of the process kill operation.
|
||||
message KillProcessResponse {
|
||||
}
|
||||
75
src/ucentral-client/platform/larch-sonic/protos/types.proto
Normal file
75
src/ucentral-client/platform/larch-sonic/protos/types.proto
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package gnoi.types;
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "github.com/openconfig/gnoi/types";
|
||||
|
||||
// Define a protobuf FileOption that defines the gNOI service version.
|
||||
extend google.protobuf.FileOptions {
|
||||
// The gNOI service semantic version.
|
||||
string gnoi_version = 1002;
|
||||
}
|
||||
|
||||
// Generic Layer 3 Protocol enumeration.
|
||||
enum L3Protocol {
|
||||
UNSPECIFIED = 0;
|
||||
IPV4 = 1;
|
||||
IPV6 = 2;
|
||||
}
|
||||
|
||||
// HashType defines the valid hash methods for data verification. UNSPECIFIED
|
||||
// should be treated an error.
|
||||
message HashType {
|
||||
enum HashMethod {
|
||||
UNSPECIFIED = 0;
|
||||
SHA256 = 1;
|
||||
SHA512 = 2;
|
||||
MD5 = 3;
|
||||
}
|
||||
HashMethod method = 1;
|
||||
bytes hash = 2;
|
||||
}
|
||||
|
||||
// Path encodes a data tree path as a series of repeated strings, with
|
||||
// each element of the path representing a data tree node name and the
|
||||
// associated attributes.
|
||||
// Reference: gNMI Specification Section 2.2.2.
|
||||
message Path {
|
||||
string origin = 2; // Label to disambiguate path.
|
||||
repeated PathElem elem = 3; // Elements of the path.
|
||||
}
|
||||
|
||||
// PathElem encodes an element of a gNMI path, along with any attributes (keys)
|
||||
// that may be associated with it.
|
||||
// Reference: gNMI Specification Section 2.2.2.
|
||||
message PathElem {
|
||||
string name = 1; // The name of the element in the path.
|
||||
map<string, string> key = 2; // Map of key (attribute) name to value.
|
||||
}
|
||||
|
||||
// Credentials defines credentials needed to perform authentication on a device.
|
||||
message Credentials {
|
||||
string username = 1;
|
||||
oneof password {
|
||||
string cleartext = 2;
|
||||
HashType hashed = 3;
|
||||
}
|
||||
}
|
||||
408
src/ucentral-client/platform/larch-sonic/route.cpp
Normal file
408
src/ucentral-client/platform/larch-sonic/route.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
#include <route.hpp>
|
||||
#include <sai_redis.hpp>
|
||||
#include <state.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <sw/redis++/redis++.h>
|
||||
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_PLAT
|
||||
#include <router-utils.h>
|
||||
#include <ucentral-log.h>
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <algorithm> // std::find_if
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iterator> // std::inserter
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace larch {
|
||||
|
||||
static std::string fib_key_to_str(const ucentral_router_fib_key &fib_key)
|
||||
{
|
||||
std::array<char, INET_ADDRSTRLEN + 1> ip_buf{};
|
||||
|
||||
if (!inet_ntop(AF_INET, &fib_key.prefix, ip_buf.data(), ip_buf.size()))
|
||||
throw std::runtime_error{
|
||||
"Failed to convert FIB prefix from binary to text form"};
|
||||
|
||||
std::string ip{ip_buf.data()};
|
||||
ip += "/" + std::to_string(fib_key.prefix_len);
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
||||
void create_route(
|
||||
std::uint16_t router_id,
|
||||
const ucentral_router_fib_key &fib_key,
|
||||
const ucentral_router_fib_info &fib_info)
|
||||
{
|
||||
// VRF is not supported
|
||||
if (router_id != 0)
|
||||
return;
|
||||
|
||||
json route_json;
|
||||
|
||||
route_json["prefix"] = fib_key_to_str(fib_key);
|
||||
route_json["vrf-name"] = "default";
|
||||
|
||||
switch (fib_info.type)
|
||||
{
|
||||
case ucentral_router_fib_info::UCENTRAL_ROUTE_BLACKHOLE:
|
||||
{
|
||||
route_json["blackhole"] = "true,false";
|
||||
break;
|
||||
}
|
||||
|
||||
case ucentral_router_fib_info::UCENTRAL_ROUTE_CONNECTED:
|
||||
{
|
||||
route_json["ifname"] =
|
||||
"Vlan" + std::to_string(fib_info.connected.vid);
|
||||
break;
|
||||
}
|
||||
|
||||
case ucentral_router_fib_info::UCENTRAL_ROUTE_NH:
|
||||
{
|
||||
route_json["ifname"] =
|
||||
"Vlan" + std::to_string(fib_info.nh.vid);
|
||||
|
||||
std::array<char, INET_ADDRSTRLEN + 1> ip_buf{};
|
||||
|
||||
if (!inet_ntop(
|
||||
AF_INET,
|
||||
&fib_info.nh.gw,
|
||||
ip_buf.data(),
|
||||
ip_buf.size()))
|
||||
{
|
||||
throw std::runtime_error{
|
||||
"Failed to convert gateway address from "
|
||||
"binary to text form"};
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
json add_route_json;
|
||||
add_route_json["sonic-static-route:sonic-static-route"]["STATIC_ROUTE"]
|
||||
["STATIC_ROUTE_LIST"] = {route_json};
|
||||
|
||||
gnmi_set(
|
||||
"/sonic-static-route:sonic-static-route/",
|
||||
add_route_json.dump());
|
||||
}
|
||||
|
||||
void remove_route(
|
||||
std::uint16_t router_id,
|
||||
const ucentral_router_fib_key &fib_key)
|
||||
{
|
||||
// VRF is not supported
|
||||
if (router_id != 0)
|
||||
return;
|
||||
|
||||
gnmi_operation op;
|
||||
|
||||
op.add_delete(
|
||||
"/sonic-static-route:sonic-static-route/STATIC_ROUTE/"
|
||||
"STATIC_ROUTE_LIST[prefix="
|
||||
+ fib_key_to_str(fib_key) + "][vrf-name=default]");
|
||||
|
||||
op.execute();
|
||||
}
|
||||
|
||||
std::vector<ucentral_router_fib_node> get_routes(std::uint16_t router_id)
|
||||
{
|
||||
// VRF is not supported
|
||||
if (router_id != 0)
|
||||
return {};
|
||||
|
||||
const json static_routes_json =
|
||||
json::parse(gnmi_get("/sonic-static-route:sonic-static-route/"
|
||||
"STATIC_ROUTE/STATIC_ROUTE_LIST"));
|
||||
|
||||
std::vector<ucentral_router_fib_node> routes;
|
||||
|
||||
for (const auto &route_json : static_routes_json.value(
|
||||
"sonic-static-route:STATIC_ROUTE_LIST",
|
||||
json::array()))
|
||||
{
|
||||
if (route_json.contains("vrf-name")
|
||||
&& route_json.at("vrf-name").template get<std::string>()
|
||||
!= "default")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!route_json.contains("prefix"))
|
||||
continue;
|
||||
|
||||
ucentral_router_fib_info fib_info{};
|
||||
|
||||
// For now only blackhole is supported
|
||||
if (route_json.contains("blackhole"))
|
||||
fib_info.type =
|
||||
ucentral_router_fib_info::UCENTRAL_ROUTE_BLACKHOLE;
|
||||
else
|
||||
continue;
|
||||
|
||||
ucentral_router_fib_key fib_key{};
|
||||
|
||||
const int ret = inet_net_pton(
|
||||
AF_INET,
|
||||
route_json.at("prefix").template get<std::string>().c_str(),
|
||||
&fib_key.prefix,
|
||||
sizeof(fib_key.prefix));
|
||||
|
||||
if (ret == -1)
|
||||
continue;
|
||||
|
||||
fib_key.prefix_len = ret;
|
||||
|
||||
routes.push_back({fib_key, fib_info});
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
struct router_interface {
|
||||
std::string mac;
|
||||
sai::object_id port_oid;
|
||||
};
|
||||
|
||||
static std::optional<router_interface>
|
||||
parse_router_interface(const sai::object_id &oid)
|
||||
{
|
||||
router_interface router_if{};
|
||||
|
||||
std::unordered_map<std::string, std::string> entry;
|
||||
|
||||
state->redis_asic->hgetall(
|
||||
"ASIC_STATE:SAI_OBJECT_TYPE_ROUTER_INTERFACE:" + oid,
|
||||
std::inserter(entry, entry.begin()));
|
||||
|
||||
try
|
||||
{
|
||||
if (entry.at("SAI_ROUTER_INTERFACE_ATTR_TYPE")
|
||||
!= "SAI_ROUTER_INTERFACE_TYPE_PORT")
|
||||
{
|
||||
// Other types are not supported
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
router_if.mac =
|
||||
entry.at("SAI_ROUTER_INTERFACE_ATTR_SRC_MAC_ADDRESS");
|
||||
router_if.port_oid =
|
||||
entry.at("SAI_ROUTER_INTERFACE_ATTR_PORT_ID");
|
||||
}
|
||||
catch (const std::out_of_range &ex)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return router_if;
|
||||
}
|
||||
|
||||
std::vector<plat_gw_address> get_gw_addresses()
|
||||
{
|
||||
// TO-DO: remove this and use state->interfaces_addrs after mergin
|
||||
// interface-addresses PR
|
||||
std::vector<plat_ipv4> interfaces_addrs;
|
||||
|
||||
const auto port_name_mapping = sai::get_port_name_mapping();
|
||||
|
||||
std::vector<plat_gw_address> gw_addresses;
|
||||
|
||||
std::int64_t cursor = 0;
|
||||
std::unordered_set<std::string> keys;
|
||||
|
||||
do
|
||||
{
|
||||
constexpr std::string_view pattern =
|
||||
"ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY:*";
|
||||
|
||||
keys.clear();
|
||||
|
||||
cursor = state->redis_asic->scan(
|
||||
cursor,
|
||||
pattern,
|
||||
std::inserter(keys, keys.begin()));
|
||||
|
||||
for (const auto &key : keys)
|
||||
{
|
||||
const json route_json =
|
||||
json::parse(key.substr(pattern.size() - 1));
|
||||
|
||||
plat_gw_address gw_addr{};
|
||||
|
||||
// Get IP
|
||||
cidr gw_ip_range = parse_cidr(
|
||||
route_json.at("dest").template get<std::string>());
|
||||
|
||||
if (inet_pton(
|
||||
AF_INET,
|
||||
gw_ip_range.ip_address.c_str(),
|
||||
&gw_addr.ip)
|
||||
!= 1)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Failed to parse GW IP address %s",
|
||||
gw_ip_range.ip_address.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto *static_routes_begin = state->router.arr;
|
||||
const auto *static_routes_end =
|
||||
static_routes_begin + state->router.len;
|
||||
|
||||
if (std::find_if(
|
||||
static_routes_begin,
|
||||
static_routes_end,
|
||||
[&gw_addr](const auto &fib_node) {
|
||||
// TO-DO: uncomment after merging
|
||||
// interface-addresses PR return
|
||||
// addr_to_str(fib_node.key.prefix)
|
||||
// == addr_to_str(gw_addr.ip);
|
||||
|
||||
return false;
|
||||
})
|
||||
!= static_routes_end)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::find_if(
|
||||
interfaces_addrs.cbegin(),
|
||||
interfaces_addrs.cend(),
|
||||
[&gw_addr](const auto &interface_addr) {
|
||||
// TO-DO: uncomment after merging
|
||||
// interface-addresses PR return
|
||||
// addr_to_str(interface_addr.subnet)
|
||||
// == addr_to_str(gw_addr.ip);
|
||||
|
||||
return false;
|
||||
})
|
||||
!= interfaces_addrs.cend())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> entry;
|
||||
|
||||
state->redis_asic->hgetall(
|
||||
key,
|
||||
std::inserter(entry, entry.begin()));
|
||||
|
||||
const auto router_it =
|
||||
entry.find("SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID");
|
||||
|
||||
if (router_it == entry.cend())
|
||||
continue;
|
||||
|
||||
auto router_if_opt =
|
||||
parse_router_interface(router_it->second);
|
||||
|
||||
if (!router_if_opt)
|
||||
continue;
|
||||
|
||||
// Get MAC
|
||||
std::strncpy(
|
||||
gw_addr.mac,
|
||||
router_if_opt->mac.c_str(),
|
||||
std::size(gw_addr.mac) - 1);
|
||||
|
||||
// Get port name
|
||||
const auto port_name_it =
|
||||
port_name_mapping.find(router_if_opt->port_oid);
|
||||
|
||||
if (port_name_it == port_name_mapping.cend())
|
||||
continue;
|
||||
|
||||
std::strncpy(
|
||||
gw_addr.port,
|
||||
port_name_it->second.c_str(),
|
||||
std::size(gw_addr.port) - 1);
|
||||
|
||||
gw_addresses.push_back(gw_addr);
|
||||
}
|
||||
} while (cursor != 0);
|
||||
|
||||
return gw_addresses;
|
||||
}
|
||||
|
||||
void apply_route_config(plat_cfg *cfg)
|
||||
{
|
||||
ucentral_router old_router{}, new_router{};
|
||||
|
||||
// Save the old router
|
||||
old_router = state->router;
|
||||
|
||||
// Load new router, this also does the necessary allocations
|
||||
if (ucentral_router_fib_db_copy(&cfg->router, &new_router) != 0)
|
||||
throw std::runtime_error{"Failed to copy FIB DB"};
|
||||
|
||||
if (!old_router.sorted)
|
||||
ucentral_router_fib_db_sort(&old_router);
|
||||
if (!new_router.sorted)
|
||||
ucentral_router_fib_db_sort(&new_router);
|
||||
|
||||
std::size_t old_idx = 0, new_idx = 0;
|
||||
int diff = 0;
|
||||
|
||||
for_router_db_diff(&new_router, &old_router, new_idx, old_idx, diff)
|
||||
{
|
||||
diff = router_db_diff_get(
|
||||
&new_router,
|
||||
&old_router,
|
||||
new_idx,
|
||||
old_idx);
|
||||
|
||||
if (diff_case_upd(diff))
|
||||
{
|
||||
if (!ucentral_router_fib_info_cmp(
|
||||
&router_db_get(&old_router, old_idx)->info,
|
||||
&router_db_get(&new_router, new_idx)->info))
|
||||
continue;
|
||||
|
||||
const auto &node = *router_db_get(&new_router, new_idx);
|
||||
|
||||
remove_route(0, node.key);
|
||||
create_route(0, node.key, node.info);
|
||||
}
|
||||
|
||||
if (diff_case_del(diff))
|
||||
{
|
||||
remove_route(
|
||||
0,
|
||||
router_db_get(&old_router, old_idx)->key);
|
||||
}
|
||||
|
||||
if (diff_case_add(diff))
|
||||
{
|
||||
const auto &node = *router_db_get(&new_router, new_idx);
|
||||
create_route(0, node.key, node.info);
|
||||
}
|
||||
}
|
||||
|
||||
ucentral_router_fib_db_free(&old_router);
|
||||
state->router = new_router;
|
||||
}
|
||||
|
||||
} // namespace larch
|
||||
29
src/ucentral-client/platform/larch-sonic/route.hpp
Normal file
29
src/ucentral-client/platform/larch-sonic/route.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef LARCH_PLATFORM_ROUTE_HPP_
|
||||
#define LARCH_PLATFORM_ROUTE_HPP_
|
||||
|
||||
#include <router-utils.h>
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace larch {
|
||||
|
||||
void create_route(
|
||||
std::uint16_t router_id,
|
||||
const ucentral_router_fib_key &fib_key,
|
||||
const ucentral_router_fib_info &fib_info);
|
||||
|
||||
void remove_route(
|
||||
std::uint16_t router_id,
|
||||
const ucentral_router_fib_key &fib_key);
|
||||
|
||||
std::vector<ucentral_router_fib_node> get_routes(std::uint16_t router_id);
|
||||
|
||||
std::vector<plat_gw_address> get_gw_addresses();
|
||||
|
||||
void apply_route_config(plat_cfg *cfg);
|
||||
|
||||
} // namespace larch
|
||||
|
||||
#endif // !LARCH_PLATFORM_ROUTE_HPP_
|
||||
139
src/ucentral-client/platform/larch-sonic/sai_redis.cpp
Normal file
139
src/ucentral-client/platform/larch-sonic/sai_redis.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
#include <sai_redis.hpp>
|
||||
#include <state.hpp>
|
||||
|
||||
#include <sw/redis++/redis++.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator> // std::inserter
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace larch::sai {
|
||||
|
||||
std::unordered_map<object_id, object_id> get_bridge_port_mapping()
|
||||
{
|
||||
std::unordered_map<object_id, object_id> mapping;
|
||||
|
||||
std::int64_t cursor = 0;
|
||||
std::unordered_set<std::string> keys;
|
||||
|
||||
do
|
||||
{
|
||||
constexpr std::string_view pattern =
|
||||
"ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT:*";
|
||||
|
||||
// Example key is
|
||||
// ASIC_STATE:SAI_OBJECT_TYPE_BRIDGE_PORT:oid:0x3a000000000616
|
||||
// and we need to get only the 3a00... part. -1 here is for the
|
||||
// trailing '*' at the end of the pattern.
|
||||
constexpr std::size_t offset =
|
||||
pattern.size() - 1 + oid_prefix.size();
|
||||
|
||||
keys.clear();
|
||||
|
||||
cursor = state->redis_asic->scan(
|
||||
cursor,
|
||||
pattern,
|
||||
std::inserter(keys, keys.begin()));
|
||||
|
||||
for (const auto &key : keys)
|
||||
{
|
||||
std::unordered_map<std::string, std::string> entry;
|
||||
|
||||
state->redis_asic->hgetall(
|
||||
key,
|
||||
std::inserter(entry, entry.begin()));
|
||||
|
||||
const auto it =
|
||||
entry.find("SAI_BRIDGE_PORT_ATTR_PORT_ID");
|
||||
|
||||
if (it != entry.cend())
|
||||
{
|
||||
mapping[key.substr(offset)] =
|
||||
it->second.substr(oid_prefix.size());
|
||||
}
|
||||
}
|
||||
} while (cursor != 0);
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
std::unordered_map<object_id, std::string> get_port_name_mapping()
|
||||
{
|
||||
std::unordered_map<std::string, std::string> entry;
|
||||
|
||||
state->redis_counters->hgetall(
|
||||
"COUNTERS_PORT_NAME_MAP",
|
||||
std::inserter(entry, entry.begin()));
|
||||
|
||||
state->redis_counters->hgetall(
|
||||
"COUNTERS_LAG_NAME_MAP",
|
||||
std::inserter(entry, entry.begin()));
|
||||
|
||||
std::unordered_map<object_id, std::string> mapping;
|
||||
|
||||
for (auto it = entry.cbegin(); it != entry.cend();)
|
||||
{
|
||||
// TO-DO: validate interface name?
|
||||
auto node = entry.extract(it++);
|
||||
|
||||
mapping.try_emplace(
|
||||
node.mapped().substr(oid_prefix.size()),
|
||||
std::move(node.key()));
|
||||
}
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
std::optional<std::uint16_t> get_vlan_by_oid(const object_id &oid)
|
||||
{
|
||||
std::int64_t cursor = 0;
|
||||
std::unordered_set<std::string> keys;
|
||||
|
||||
const std::string pattern =
|
||||
"ASIC_STATE:SAI_OBJECT_TYPE_VLAN:" + std::string{oid_prefix} + oid;
|
||||
|
||||
// There is no guarantee that the necessary key will be found during the
|
||||
// first scan, so we need to scan until we find it
|
||||
do
|
||||
{
|
||||
keys.clear();
|
||||
|
||||
cursor = state->redis_asic->scan(
|
||||
cursor,
|
||||
pattern,
|
||||
std::inserter(keys, keys.begin()));
|
||||
|
||||
if (keys.empty())
|
||||
continue;
|
||||
|
||||
std::unordered_map<std::string, std::string> entry;
|
||||
|
||||
state->redis_asic->hgetall(
|
||||
*keys.begin(),
|
||||
std::inserter(entry, entry.begin()));
|
||||
|
||||
const auto it = entry.find("SAI_VLAN_ATTR_VLAN_ID");
|
||||
|
||||
if (it == entry.cend())
|
||||
return std::nullopt;
|
||||
|
||||
try
|
||||
{
|
||||
return static_cast<std::uint16_t>(
|
||||
std::stoul(it->second));
|
||||
}
|
||||
catch (const std::logic_error &)
|
||||
{
|
||||
throw std::runtime_error{"Failed to parse VLAN ID"};
|
||||
}
|
||||
{}
|
||||
} while (cursor != 0);
|
||||
|
||||
throw std::runtime_error{"Failed to get VLAN by object ID"};
|
||||
}
|
||||
|
||||
} // namespace larch::sai
|
||||
46
src/ucentral-client/platform/larch-sonic/sai_redis.hpp
Normal file
46
src/ucentral-client/platform/larch-sonic/sai_redis.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file sai_redis.hpp
|
||||
* @brief Commonly used functions to interact with SAI via Redis DB.
|
||||
*
|
||||
* Note, that object IDs (OIDs) are used without "oid:0x" prefix.
|
||||
*/
|
||||
|
||||
#ifndef LARCH_PLATFORM_SAI_REDIS_HPP_
|
||||
#define LARCH_PLATFORM_SAI_REDIS_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace larch::sai {
|
||||
|
||||
using object_id = std::string;
|
||||
|
||||
inline constexpr std::string_view oid_prefix = "oid:0x";
|
||||
|
||||
/**
|
||||
* @brief Get mapping of bridge port OIDs to port OIDs.
|
||||
*
|
||||
* @return Map with bridge port OID as a key and port OID as a value.
|
||||
*/
|
||||
std::unordered_map<object_id, object_id> get_bridge_port_mapping();
|
||||
|
||||
/**
|
||||
* @brief Get mapping of port OIDs to port names.
|
||||
*
|
||||
* @return Map with port OID and port name as a value.
|
||||
*/
|
||||
std::unordered_map<object_id, std::string> get_port_name_mapping();
|
||||
|
||||
/**
|
||||
* @brief Get VLAN ID by its OID.
|
||||
*
|
||||
* @throw std::runtime_error If VLAN can't be found
|
||||
*/
|
||||
std::optional<std::uint16_t> get_vlan_by_oid(const object_id &oid);
|
||||
|
||||
} // namespace larch::sai
|
||||
|
||||
#endif // !LARCH_PLATFORM_SAI_REDIS_HPP_
|
||||
114
src/ucentral-client/platform/larch-sonic/services.cpp
Normal file
114
src/ucentral-client/platform/larch-sonic/services.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <services.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_PLAT
|
||||
#include <ucentral-log.h>
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace larch {
|
||||
|
||||
static std::unordered_set<std::string> get_existing_ntp_servers()
|
||||
{
|
||||
const json existing_servers_json = json::parse(
|
||||
gnmi_get("/sonic-ntp:sonic-ntp/NTP_SERVER/NTP_SERVER_LIST"));
|
||||
|
||||
std::unordered_set<std::string> existing_servers;
|
||||
|
||||
if (existing_servers_json.contains("sonic-ntp:NTP_SERVER_LIST"))
|
||||
{
|
||||
for (const auto &server_json :
|
||||
existing_servers_json.at("sonic-ntp:NTP_SERVER_LIST"))
|
||||
{
|
||||
if (!server_json.contains("server_address"))
|
||||
continue;
|
||||
|
||||
existing_servers.insert(
|
||||
server_json.at("server_address")
|
||||
.template get<std::string>());
|
||||
}
|
||||
}
|
||||
|
||||
return existing_servers;
|
||||
}
|
||||
|
||||
static void apply_ntp_config(const plat_ntp_cfg *ntp_cfg)
|
||||
{
|
||||
if (ntp_cfg->servers)
|
||||
{
|
||||
gnmi_operation op;
|
||||
|
||||
std::unordered_set<std::string> existing_servers =
|
||||
get_existing_ntp_servers();
|
||||
|
||||
json ntp_json;
|
||||
json &server_list_json = ntp_json["sonic-ntp:NTP_SERVER_LIST"];
|
||||
server_list_json = json::array();
|
||||
|
||||
const plat_ntp_server *it = nullptr;
|
||||
UCENTRAL_LIST_FOR_EACH_MEMBER(it, &ntp_cfg->servers)
|
||||
{
|
||||
const auto existing_it =
|
||||
existing_servers.find(it->hostname);
|
||||
|
||||
if (existing_it != existing_servers.cend())
|
||||
{
|
||||
existing_servers.erase(existing_it);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::array<unsigned char, sizeof(in6_addr)> addr_buf{};
|
||||
|
||||
if (inet_pton(AF_INET, it->hostname, addr_buf.data())
|
||||
!= 1
|
||||
&& inet_pton(
|
||||
AF_INET6,
|
||||
it->hostname,
|
||||
addr_buf.data())
|
||||
!= 1)
|
||||
{
|
||||
UC_LOG_ERR(
|
||||
"Domains are not supported in NTP server "
|
||||
"list, use IP addresses");
|
||||
continue;
|
||||
}
|
||||
|
||||
json server_json;
|
||||
server_json["association_type"] = "server";
|
||||
server_json["server_address"] = it->hostname;
|
||||
server_json["resolve_as"] = it->hostname;
|
||||
|
||||
server_list_json.push_back(server_json);
|
||||
}
|
||||
|
||||
op.add_update(
|
||||
"/sonic-ntp:sonic-ntp/NTP_SERVER/NTP_SERVER_LIST",
|
||||
ntp_json.dump());
|
||||
|
||||
for (const auto &server : existing_servers)
|
||||
{
|
||||
op.add_delete(
|
||||
"/sonic-ntp:sonic-ntp/NTP_SERVER/"
|
||||
"NTP_SERVER_LIST[server_address="
|
||||
+ server + "]");
|
||||
}
|
||||
|
||||
op.execute();
|
||||
}
|
||||
}
|
||||
|
||||
void apply_services_config(plat_cfg *cfg)
|
||||
{
|
||||
apply_ntp_config(&cfg->ntp_cfg);
|
||||
}
|
||||
|
||||
} // namespace larch
|
||||
12
src/ucentral-client/platform/larch-sonic/services.hpp
Normal file
12
src/ucentral-client/platform/larch-sonic/services.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef LARCH_PLATFORM_SERVICES_HPP_
|
||||
#define LARCH_PLATFORM_SERVICES_HPP_
|
||||
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
namespace larch {
|
||||
|
||||
void apply_services_config(plat_cfg *cfg);
|
||||
|
||||
}
|
||||
|
||||
#endif // !LARCH_PLATFORM_SERVICES_HPP_
|
||||
10
src/ucentral-client/platform/larch-sonic/state.cpp
Normal file
10
src/ucentral-client/platform/larch-sonic/state.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <metrics.hpp>
|
||||
#include <state.hpp>
|
||||
|
||||
#include <sw/redis++/redis++.h>
|
||||
|
||||
namespace larch {
|
||||
|
||||
platform_state::~platform_state() = default;
|
||||
|
||||
} // namespace larch
|
||||
53
src/ucentral-client/platform/larch-sonic/state.hpp
Normal file
53
src/ucentral-client/platform/larch-sonic/state.hpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef LARCH_PLATFORM_STATE_HPP_
|
||||
#define LARCH_PLATFORM_STATE_HPP_
|
||||
|
||||
#include <gnmi.grpc.pb.h>
|
||||
#include <gnmi.pb.h>
|
||||
#include <sonic_gnoi.grpc.pb.h>
|
||||
#include <sonic_gnoi.pb.h>
|
||||
#include <system.grpc.pb.h>
|
||||
#include <system.pb.h>
|
||||
|
||||
#include <grpc++/grpc++.h>
|
||||
|
||||
#include <router-utils.h>
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations
|
||||
namespace sw::redis {
|
||||
class Redis;
|
||||
}
|
||||
|
||||
namespace larch {
|
||||
|
||||
class periodic;
|
||||
|
||||
struct platform_state {
|
||||
~platform_state();
|
||||
|
||||
std::shared_ptr<grpc::ChannelInterface> channel;
|
||||
std::unique_ptr<gnmi::gNMI::Stub> gnmi_stub;
|
||||
|
||||
std::unique_ptr<gnoi::system::System::Stub> system_gnoi_stub;
|
||||
|
||||
std::unique_ptr<gnoi::sonic::SonicService::Stub> stub_gnoi_sonic;
|
||||
|
||||
std::unique_ptr<periodic> telemetry_periodic;
|
||||
std::unique_ptr<periodic> state_periodic;
|
||||
std::unique_ptr<periodic> health_periodic;
|
||||
|
||||
std::unique_ptr<sw::redis::Redis> redis_asic;
|
||||
std::unique_ptr<sw::redis::Redis> redis_counters;
|
||||
|
||||
std::vector<plat_ipv4> interfaces_addrs;
|
||||
ucentral_router router{};
|
||||
};
|
||||
|
||||
inline std::unique_ptr<platform_state> state;
|
||||
|
||||
} // namespace larch
|
||||
|
||||
#endif // !LARCH_PLATFORM_STATE_HPP_
|
||||
107
src/ucentral-client/platform/larch-sonic/stp.cpp
Normal file
107
src/ucentral-client/platform/larch-sonic/stp.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#include <stp.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_PLAT
|
||||
#include <ucentral-log.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace larch {
|
||||
|
||||
void apply_stp_config(struct plat_cfg *cfg)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
gnmi_operation op;
|
||||
|
||||
switch (cfg->stp_mode) {
|
||||
case PLAT_STP_MODE_NONE:
|
||||
{
|
||||
const auto stp_list = gnmi_get("/sonic-spanning-tree:sonic-spanning-tree/STP/STP_LIST");
|
||||
const json stp_list_json = json::parse(stp_list);
|
||||
|
||||
/* There are no STPs */
|
||||
if (!stp_list_json.contains("sonic-spanning-tree:STP_LIST"))
|
||||
return;
|
||||
|
||||
/* This will clear all per port/vlan stp entries */
|
||||
/* Delete global config since you cannot change the stp mode otherwise */
|
||||
op.add_delete("/sonic-spanning-tree:sonic-spanning-tree/STP/STP_LIST[keyleaf=GLOBAL]");
|
||||
|
||||
break;
|
||||
}
|
||||
case PLAT_STP_MODE_PVST:
|
||||
{
|
||||
/* Config mode */
|
||||
json stp_cfg_mode_json;
|
||||
|
||||
stp_cfg_mode_json["priority"] = cfg->stp_instances[0].priority;
|
||||
stp_cfg_mode_json["keyleaf"] = "GLOBAL";
|
||||
stp_cfg_mode_json["bpdu_filter"] = false;
|
||||
stp_cfg_mode_json["mode"] = "pvst";
|
||||
stp_cfg_mode_json["rootguard_timeout"] = 30;
|
||||
|
||||
json add_stp_cfg_mode_json;
|
||||
add_stp_cfg_mode_json["sonic-spanning-tree:STP_LIST"] = {stp_cfg_mode_json};
|
||||
|
||||
op.add_update("/sonic-spanning-tree:sonic-spanning-tree/STP/STP_LIST", add_stp_cfg_mode_json.dump());
|
||||
|
||||
/* Once mode enabled - create entries for all ports */
|
||||
BITMAP_FOR_EACH_BIT_SET(i, cfg->ports_to_cfg, MAX_NUM_OF_PORTS)
|
||||
{
|
||||
json stp_port_json;
|
||||
|
||||
stp_port_json["ifname"] = "Ethernet" + std::to_string(i);
|
||||
stp_port_json["enabled"] = true;
|
||||
|
||||
json add_stp_port_json;
|
||||
add_stp_port_json["sonic-spanning-tree:STP_PORT_LIST"] = {stp_port_json};
|
||||
|
||||
op.add_update("/sonic-spanning-tree:sonic-spanning-tree/STP_PORT/STP_PORT_LIST", add_stp_port_json.dump());
|
||||
}
|
||||
|
||||
/* Config vlans */
|
||||
for (i = FIRST_VLAN; i < MAX_VLANS; i++) {
|
||||
if (!cfg->stp_instances[i].enabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
json stp_vlan_json;
|
||||
stp_vlan_json["vlanid"] = i;
|
||||
stp_vlan_json["name"] = "Vlan" + std::to_string(i);
|
||||
stp_vlan_json["enabled"] = cfg->stp_instances[i].enabled;
|
||||
stp_vlan_json["priority"] = cfg->stp_instances[i].priority;
|
||||
stp_vlan_json["forward_delay"] = cfg->stp_instances[i].forward_delay;
|
||||
stp_vlan_json["hello_time"] = cfg->stp_instances[i].hello_time;
|
||||
stp_vlan_json["max_age"] = cfg->stp_instances[i].max_age;
|
||||
|
||||
json add_stp_vlan_json;
|
||||
add_stp_vlan_json["sonic-spanning-tree:STP_VLAN_LIST"] = {stp_vlan_json};
|
||||
|
||||
UC_LOG_DBG(
|
||||
"set vlan=%d state.enabled=%d state.priority=%d "
|
||||
"state.forward_delay=%d state.hello_time=%d "
|
||||
"state.max_age=%d ",
|
||||
i,
|
||||
cfg->stp_instances[i].enabled,
|
||||
cfg->stp_instances[i].priority,
|
||||
cfg->stp_instances[i].forward_delay,
|
||||
cfg->stp_instances[i].hello_time,
|
||||
cfg->stp_instances[i].max_age);
|
||||
|
||||
op.add_update("/sonic-spanning-tree:sonic-spanning-tree/STP_VLAN/STP_VLAN_LIST", add_stp_vlan_json.dump());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error{"Failed apply stp config"};
|
||||
}
|
||||
|
||||
op.execute();
|
||||
}
|
||||
|
||||
}
|
||||
12
src/ucentral-client/platform/larch-sonic/stp.hpp
Normal file
12
src/ucentral-client/platform/larch-sonic/stp.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef LARCH_PLATFORM_STP_HPP_
|
||||
#define LARCH_PLATFORM_STP_HPP_
|
||||
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
namespace larch {
|
||||
|
||||
void apply_stp_config(plat_cfg *cfg);
|
||||
|
||||
}
|
||||
|
||||
#endif // !LARCH_PLATFORM_STP_HPP_
|
||||
61
src/ucentral-client/platform/larch-sonic/syslog.cpp
Executable file
61
src/ucentral-client/platform/larch-sonic/syslog.cpp
Executable file
@@ -0,0 +1,61 @@
|
||||
#include <syslog.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#define UC_LOG_COMPONENT UC_LOG_COMPONENT_PLAT
|
||||
#include <ucentral-log.h>
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace larch {
|
||||
|
||||
void gnma_syslog_cfg_clear(void)
|
||||
{
|
||||
std::string path = "/sonic-syslog:sonic-syslog/SYSLOG_SERVER/SYSLOG_SERVER_LIST";
|
||||
|
||||
gnmi_operation op;
|
||||
op.add_delete(path);
|
||||
op.execute();
|
||||
}
|
||||
|
||||
void apply_syslog_config(struct plat_syslog_cfg *cfg, int count)
|
||||
{
|
||||
std::string path = "/sonic-syslog:sonic-syslog/SYSLOG_SERVER/SYSLOG_SERVER_LIST";
|
||||
const std::array<std::string, 8> priority2str = {
|
||||
"crit",
|
||||
"crit",
|
||||
"crit",
|
||||
"error",
|
||||
"warn",
|
||||
"notice",
|
||||
"info",
|
||||
"debug"
|
||||
};
|
||||
int i;
|
||||
|
||||
gnmi_operation op;
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
json syslog_cfg_member_json;
|
||||
syslog_cfg_member_json["server_address"] = cfg[i].host;
|
||||
syslog_cfg_member_json["port"] = cfg[i].port;
|
||||
syslog_cfg_member_json["protocol"] = cfg[i].is_tcp ? "tcp" : "udp";
|
||||
syslog_cfg_member_json["severity"] = priority2str.at(cfg[i].priority);
|
||||
syslog_cfg_member_json["vrf"] = "default";
|
||||
|
||||
json add_syslog_cfg_member_json;
|
||||
add_syslog_cfg_member_json["sonic-syslog:SYSLOG_SERVER_LIST"] = {syslog_cfg_member_json};
|
||||
|
||||
op.add_update(path, add_syslog_cfg_member_json.dump());
|
||||
}
|
||||
|
||||
gnma_syslog_cfg_clear();
|
||||
op.execute();
|
||||
}
|
||||
|
||||
}
|
||||
14
src/ucentral-client/platform/larch-sonic/syslog.hpp
Executable file
14
src/ucentral-client/platform/larch-sonic/syslog.hpp
Executable file
@@ -0,0 +1,14 @@
|
||||
#ifndef LARCH_PLATFORM_SYSLOG_HPP_
|
||||
#define LARCH_PLATFORM_SYSLOG_HPP_
|
||||
|
||||
#include <ucentral-platform.h>
|
||||
|
||||
namespace larch {
|
||||
|
||||
void gnma_syslog_cfg_clear(void);
|
||||
|
||||
void apply_syslog_config(struct plat_syslog_cfg *cfg, int count);
|
||||
|
||||
}
|
||||
|
||||
#endif // !LARCH_PLATFORM_SYSLOG_HPP_
|
||||
308
src/ucentral-client/platform/larch-sonic/utils.cpp
Normal file
308
src/ucentral-client/platform/larch-sonic/utils.cpp
Normal file
@@ -0,0 +1,308 @@
|
||||
#include <state.hpp>
|
||||
#include <utils.hpp>
|
||||
|
||||
#include <gnmi.grpc.pb.h>
|
||||
#include <gnmi.pb.h>
|
||||
|
||||
#include <grpcpp/grpcpp.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility> // std::move
|
||||
#include <vector>
|
||||
|
||||
namespace larch {
|
||||
|
||||
std::vector<std::string>
|
||||
split_string(std::string str, const std::string &delimiter)
|
||||
{
|
||||
std::vector<std::string> results;
|
||||
|
||||
std::string::size_type pos{};
|
||||
while ((pos = str.find(delimiter)) != std::string::npos)
|
||||
{
|
||||
results.push_back(str.substr(0, pos));
|
||||
str.erase(0, pos + 1);
|
||||
}
|
||||
|
||||
// Process the last part
|
||||
results.push_back(std::move(str));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> parse_kv(const std::string &kv_str)
|
||||
{
|
||||
enum class parse_state { open_bracket, close_bracket, key, value };
|
||||
|
||||
parse_state state = parse_state::close_bracket;
|
||||
std::map<std::string, std::string> kv;
|
||||
|
||||
std::string key_buf, value_buf;
|
||||
|
||||
for (const char c : kv_str)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '[':
|
||||
if (state != parse_state::close_bracket)
|
||||
throw std::runtime_error{
|
||||
"Unexpected opening bracket"};
|
||||
|
||||
state = parse_state::open_bracket;
|
||||
break;
|
||||
|
||||
case ']':
|
||||
if (state != parse_state::value)
|
||||
throw std::runtime_error{
|
||||
"Unexpected closing bracket"};
|
||||
|
||||
state = parse_state::close_bracket;
|
||||
|
||||
if (key_buf.empty())
|
||||
throw std::runtime_error{"Empty key"};
|
||||
|
||||
if (value_buf.empty())
|
||||
throw std::runtime_error{"Empty value"};
|
||||
|
||||
kv.emplace(
|
||||
std::move(key_buf),
|
||||
std::move(value_buf));
|
||||
key_buf.clear();
|
||||
value_buf.clear();
|
||||
|
||||
break;
|
||||
|
||||
case '=':
|
||||
if (state != parse_state::key)
|
||||
throw std::runtime_error{
|
||||
"Unexpected equals sign"};
|
||||
|
||||
state = parse_state::value;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
if (state == parse_state::open_bracket)
|
||||
state = parse_state::key;
|
||||
|
||||
if (state == parse_state::key)
|
||||
key_buf.push_back(c);
|
||||
else if (state == parse_state::value)
|
||||
value_buf.push_back(c);
|
||||
else
|
||||
throw std::runtime_error{
|
||||
"Unexpected character '"
|
||||
+ std::string{c} + "'"};
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state != parse_state::close_bracket)
|
||||
throw std::runtime_error{"Couldn't find closing bracket"};
|
||||
|
||||
return kv;
|
||||
}
|
||||
|
||||
void convert_yang_path_to_proto(std::string yang_path, gnmi::Path *proto_path)
|
||||
{
|
||||
struct path_element {
|
||||
std::string name;
|
||||
std::map<std::string, std::string> kv;
|
||||
};
|
||||
|
||||
std::vector<path_element> elements;
|
||||
|
||||
auto process_elem_str = [&elements](std::string elem_str) {
|
||||
if (!elem_str.empty())
|
||||
{
|
||||
const auto open_bracket_pos = elem_str.find('[');
|
||||
|
||||
if (open_bracket_pos == std::string::npos)
|
||||
{
|
||||
elements.push_back({std::move(elem_str), {}});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Parse the key-value part of YANG path
|
||||
// (e.g. [Vlan=100][SomeKey=SomeValue]...)
|
||||
try
|
||||
{
|
||||
elements.push_back(
|
||||
{elem_str.substr(
|
||||
0,
|
||||
open_bracket_pos),
|
||||
parse_kv(elem_str.substr(
|
||||
open_bracket_pos))});
|
||||
}
|
||||
catch (const std::runtime_error &ex)
|
||||
{
|
||||
using namespace std::string_literals;
|
||||
throw std::runtime_error{
|
||||
"Failed to parse key-value part of YANG path: "s
|
||||
+ ex.what()};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::string::size_type pos{};
|
||||
while ((pos = yang_path.find('/')) != std::string::npos)
|
||||
{
|
||||
process_elem_str(yang_path.substr(0, pos));
|
||||
|
||||
yang_path.erase(0, pos + 1);
|
||||
}
|
||||
|
||||
// Process the last part of split string
|
||||
process_elem_str(std::move(yang_path));
|
||||
|
||||
std::string &first_element = elements[0].name;
|
||||
const auto colon_pos = first_element.find(':');
|
||||
|
||||
if (colon_pos != std::string::npos)
|
||||
{
|
||||
proto_path->set_origin(first_element.substr(0, colon_pos));
|
||||
first_element.erase(0, colon_pos + 1);
|
||||
}
|
||||
|
||||
for (const auto &elem : elements)
|
||||
{
|
||||
gnmi::PathElem *path_elem = proto_path->add_elem();
|
||||
path_elem->set_name(elem.name);
|
||||
|
||||
if (!elem.kv.empty())
|
||||
{
|
||||
auto path_kv = path_elem->mutable_key();
|
||||
|
||||
for (const auto &[key, value] : elem.kv)
|
||||
(*path_kv)[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string gnmi_get(const std::string &yang_path)
|
||||
{
|
||||
gnmi::GetRequest greq;
|
||||
greq.set_encoding(gnmi::JSON_IETF);
|
||||
|
||||
convert_yang_path_to_proto(yang_path, greq.add_path());
|
||||
|
||||
grpc::ClientContext context;
|
||||
gnmi::GetResponse gres;
|
||||
const grpc::Status status = state->gnmi_stub->Get(&context, greq, &gres);
|
||||
|
||||
if (!status.ok())
|
||||
{
|
||||
throw gnmi_exception{
|
||||
"gNMI get operation wasn't successful: "
|
||||
+ status.error_message() + "; error code "
|
||||
+ std::to_string(status.error_code())};
|
||||
}
|
||||
|
||||
if (gres.notification_size() != 1)
|
||||
{
|
||||
throw gnmi_exception{"Unsupported notification size"};
|
||||
}
|
||||
|
||||
gnmi::Notification notification = gres.notification(0);
|
||||
if (notification.update_size() != 1)
|
||||
{
|
||||
throw gnmi_exception{"Unsupported update size"};
|
||||
}
|
||||
|
||||
gnmi::Update update = notification.update(0);
|
||||
if (!update.has_val())
|
||||
{
|
||||
throw gnmi_exception{"Empty value"};
|
||||
}
|
||||
|
||||
gnmi::TypedValue value = update.val();
|
||||
if (!value.has_json_ietf_val())
|
||||
{
|
||||
throw gnmi_exception{"Empty JSON value"};
|
||||
}
|
||||
|
||||
return value.json_ietf_val();
|
||||
}
|
||||
|
||||
void gnmi_set(const std::string &yang_path, const std::string &json_data)
|
||||
{
|
||||
gnmi_operation op;
|
||||
op.add_update(yang_path, json_data);
|
||||
op.execute();
|
||||
}
|
||||
|
||||
void gnmi_operation::add_update(const std::string &yang_path, const std::string &json_data)
|
||||
{
|
||||
gnmi::Update *update = set_request_.add_update();
|
||||
convert_yang_path_to_proto(yang_path, update->mutable_path());
|
||||
update->mutable_val()->set_json_ietf_val(json_data);
|
||||
}
|
||||
|
||||
void gnmi_operation::add_delete(const std::string &yang_path)
|
||||
{
|
||||
convert_yang_path_to_proto(yang_path, set_request_.add_delete_());
|
||||
}
|
||||
|
||||
void gnmi_operation::execute()
|
||||
{
|
||||
grpc::ClientContext context;
|
||||
gnmi::SetResponse response;
|
||||
|
||||
const grpc::Status status = state->gnmi_stub->Set(&context, set_request_, &response);
|
||||
|
||||
set_request_.Clear();
|
||||
|
||||
if (!status.ok())
|
||||
{
|
||||
throw gnmi_exception{
|
||||
"gNMI set operation wasn't successful: "
|
||||
+ status.error_message() + "; error code "
|
||||
+ std::to_string(status.error_code())};
|
||||
}
|
||||
}
|
||||
|
||||
std::string addr_to_str(const in_addr &address)
|
||||
{
|
||||
std::array<char, INET_ADDRSTRLEN> addr_str_buf{};
|
||||
|
||||
if (!inet_ntop(
|
||||
AF_INET,
|
||||
&address,
|
||||
addr_str_buf.data(),
|
||||
addr_str_buf.size()))
|
||||
{
|
||||
throw std::runtime_error{
|
||||
"Failed to convert binary IP address to string"};
|
||||
}
|
||||
|
||||
return addr_str_buf.data();
|
||||
}
|
||||
|
||||
cidr parse_cidr(const std::string &str)
|
||||
{
|
||||
cidr result{};
|
||||
std::array<char, 16> addr_buf{};
|
||||
|
||||
if (std::sscanf(
|
||||
str.c_str(),
|
||||
"%15[^/]/%hhu",
|
||||
addr_buf.data(),
|
||||
&result.mask)
|
||||
!= 2)
|
||||
throw std::runtime_error{"Failed to parse CIDR notation"};
|
||||
|
||||
result.ip_address = addr_buf.data();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user