Compare commits

...

15 Commits

Author SHA1 Message Date
Teodora
35a3c546bf PM - deviation
ietf-hardware.yang model missing - must be resolved by Metanoia team.
The PM notification wasn't sent by the RU. - Must be resolved by Metanoia team.
2025-08-22 11:43:31 +02:00
Teodora
d03404c2c4 RU ready - deviation
Must be resolved by Metanoia team.

Also, ietf-hardware.yang model missing - must be resolved by Metanoia team.
2025-08-22 11:43:18 +02:00
Teodora
a775e032f1 Fixes for Metanoia RU
fs-offset must be implemented correctly, on both OAI gNB and Metanoia RU side.
2025-08-22 11:35:46 +02:00
Teodora
96e9780805 Update the FHI M-plane doc
Performance Management support explanation.

Example run modified according to:
- modification of the frequency offset, frame structure, fft size, cyclic prefix, and Tx gain;
- addition of the managed delay node;
for Tx/Rx endpoints.
2025-08-21 16:37:23 +02:00
Teodora
d4d9654e6c Performance Management implementation
Introduced a parameter start_up_timing which indicates if PM activation is supported during the start-up
procedure. We initialize this parameter, based on the vendor.

Notification interval is set to 10s.
2025-08-21 16:37:17 +02:00
Teodora
d700242b03 Add support for RU username parameter for connection to a RU via M-plane
The "sudo" access group is required by OAI gNB.
2025-08-21 15:54:23 +02:00
Teodora
0761d5a97e Rearrange <edit-config>, <validate>, and <commit> RPCs
Refactor these RPCs to facilitate their use in other Management functionalities,
not only Configuration Management.
2025-08-21 15:54:18 +02:00
Teodora
96b9472644 Add a comment for Rx gain correction
Definition in o-ran-uplane-conf.yang model:
"Gain correction of RF path linked with array element or array layers.
 Common part of overall gain_correction.
 gain_correction = common array-carrier gain-correction + eAxC gain correction."
2025-08-20 13:49:34 +02:00
Teodora
00b4171949 Correct the Tx gain 2025-08-20 13:49:34 +02:00
Teodora
37207002e9 Add managed delay node in Rx endpoint creation 2025-08-20 13:49:33 +02:00
Teodora
c7269fa030 Correctly fill the cyclic prefix for Tx/Rx endpoints 2025-08-20 13:49:33 +02:00
Teodora
32ec185215 Correctly fill the frame structure for Tx/Rx endpoints and fft size for Rx endpoints 2025-08-20 13:49:33 +02:00
Teodora
9dbd370f57 Properly pass the frequency offset to Tx/Rx endpoints 2025-08-20 13:49:32 +02:00
Teodora
8c06b94332 Separate Tx/Rx endpoint creation
As per o-ran-uplane-conf model, some nodes exist in Rx but not in Tx
(e.g. "ul-fft-sampling-offsets"), and vice versa.
2025-08-20 13:47:55 +02:00
Teodora
ff56903fc3 Set the correct yang node name for MTU retrieval 2025-08-19 22:33:08 +02:00
25 changed files with 4246 additions and 127 deletions

View File

@@ -1235,7 +1235,13 @@ You should be able to connect a UE now.
# OAI Management Plane
We support Configuration Management in OAI gNB, where gNB configures CU-planes, interfaces, TX/RX antennas, and TX/RX carriers for the RU.
In OAI gNB, we support:
* Configuration Management: interface(s) creation, configuration of RU CU-planes, Tx/Rx antennas, and Tx/Rx carriers.
* Performance Management: activation/deactivation of available RU performance measurements and its notification reception with 10s periodicity:
```bash
[HW] [MPLANE] [PM: "192.168.80.9"][RX_ON_TIME 773428][RX_EARLY 0][RX_LATE 0][RX_TOTAL 878881][RX_ON_TIME_C 104744][RX_EARLY_C 0][RX_LATE_C 0][TX_TOTAL 435922]
```
The reference specifications:
* `O-RAN.WG4.MP.0-v05.00`
* `O-RAN.WG4.MP-YANGs-v04.00`
@@ -1375,7 +1381,7 @@ Once the mplane service is successfully enabled on the RU, two new users are bei
oranbenetel:x:1000:1000::/home/oranbenetel:/bin/sh
oranext:x:1001:1001::/home/oranext:/bin/sh
```
Create `oranbenetel` home directory:
OAI gNB requires the `sudo` access group for NETCONF session. In the case of Benetel O-RUs, the corresponding user is `oranbenetel`. Therefore, please create its home directory:
```bash
mkdir /home/oranbenetel && chown oranbenetel:oranbenetel /home/oranbenetel
```
@@ -1393,7 +1399,7 @@ The reference gNB configuration file for one Benetel RAN550:
The reference DU configuration file for two Benetel RAN650:
[gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb-du.sa.band77.273prb.fhi72.8x8-benetel650_650-mplane.conf)
In order to run gNB/DU with M-plane, we need to modify the `fhi_72` section in the configuration file.
In order to run gNB/DU with M-plane, we need to modify Tx gain `att_tx` in RU section, as well as the `fhi_72` section in the configuration file.
Example for one RU:
```bash
fhi_72 = {
@@ -1404,6 +1410,7 @@ fhi_72 = {
du_key_pair = ("<path-to>/.ssh/id_rsa.pub", "<path-to>/.ssh/id_rsa");
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67"); # only one needed if one VF configured
vlan_tag = (9, 9); # only one needed if one VF configured
ru_username = ("oranbenetel");
ru_ip_addr = ("192.168.80.9");
fh_config = ({
T1a_cp_dl = (419, 470);
@@ -1423,6 +1430,7 @@ fhi_72 = {
du_key_pair = ("/home/oaicicd/.ssh/id_rsa.pub", "/home/oaicicd/.ssh/id_rsa");
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69"); # only two needed if two VFs configured
vlan_tag = (9, 9, 11, 11); # only two needed if two VFs configured
ru_username = ("oranbenetel", "oranbenetel");
ru_ip_addr = ("192.168.80.9", "192.168.80.10");
fh_config = (
# RAN550 #1
@@ -1451,6 +1459,7 @@ fhi_72 = {
* `du_key_pair`: ssh public and private keys to authenticate RU with NETCONF
* `du_addr`: DU MAC address(es) to create CU-plane interface(s) in the RU
* `vlan_tag`: VLAN U and C plane tags to create CU-plane interface(s) in the RU
* `ru_username`: Username with `sudo` access to connect to the RU via M-plane
* `ru_ip_addr`: RU IP address to connect to the RU via M-plane
* `dpdk_mem_size`: [*]
* `dpdk_iova_mode`: [*]
@@ -1557,7 +1566,9 @@ sequenceDiagram
note over du: DU configures xran
du->ru: 12. DU and RU exchange packets
du->ru: 12. DU activates Performance Measurements
du->ru: 13. DU and RU exchange packets
```
@@ -1596,7 +1607,9 @@ sequenceDiagram
Band sector ID 0
CC ID 0
RU port ID 0
max Tx gain 24.0
[HW] [MPLANE] Successfully retrieved all the U-plane info - interface name, TX/RX carrier names, and TX/RX endpoint names.
[HW] [MPLANE] Successfully retreived all performance measurement names.
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-yang-metadata".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "yang".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <get-schema> for module "ietf-inet-types".
@@ -1636,6 +1649,59 @@ sequenceDiagram
<vlan-id xmlns="urn:o-ran:interfaces:1.0">9</vlan-id>
</interface>
</interfaces>
<performance-measurement-objects xmlns="urn:o-ran:performance-management:1.0">
<rx-window-measurement-interval>10</rx-window-measurement-interval>
<tx-measurement-interval>10</tx-measurement-interval>
<notification-interval>10</notification-interval>
<rx-window-measurement-objects>
<measurement-object>RX_ON_TIME</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_EARLY</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_LATE</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_TOTAL</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_ON_TIME_C</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_EARLY_C</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_LATE_C</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<tx-measurement-objects>
<measurement-object>TX_TOTAL</measurement-object>
<active>false</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</tx-measurement-objects>
</performance-measurement-objects>
<processing-elements xmlns="urn:o-ran:processing-element:1.0">
<transport-session-type>ETH-INTERFACE</transport-session-type>
<ru-elements>
@@ -1729,8 +1795,10 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
@@ -1746,8 +1814,10 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
@@ -1763,8 +1833,10 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
@@ -1780,8 +1852,10 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
@@ -1797,9 +1871,15 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
@@ -1807,6 +1887,7 @@ sequenceDiagram
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>0</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint0</name>
@@ -1814,9 +1895,15 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
@@ -1824,6 +1911,7 @@ sequenceDiagram
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>4</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint1</name>
@@ -1831,9 +1919,15 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
@@ -1841,6 +1935,7 @@ sequenceDiagram
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>1</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint1</name>
@@ -1848,9 +1943,15 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
@@ -1858,6 +1959,7 @@ sequenceDiagram
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>5</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint2</name>
@@ -1865,9 +1967,15 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
@@ -1875,6 +1983,7 @@ sequenceDiagram
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>2</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint2</name>
@@ -1882,9 +1991,15 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
@@ -1892,6 +2007,7 @@ sequenceDiagram
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>6</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxEndpoint3</name>
@@ -1899,9 +2015,15 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
@@ -1909,6 +2031,7 @@ sequenceDiagram
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>3</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<low-level-rx-endpoints>
<name>LowLevelRxPrachEndpoint3</name>
@@ -1916,9 +2039,15 @@ sequenceDiagram
<iq-bitwidth>9</iq-bitwidth>
<compression-type>STATIC</compression-type>
</compression>
<cp-length>0</cp-length>
<cp-length-other>0</cp-length-other>
<frame-structure>193</frame-structure>
<cp-type>NORMAL</cp-type>
<cp-length>352</cp-length>
<cp-length-other>288</cp-length-other>
<offset-to-absolute-frequency-center>0</offset-to-absolute-frequency-center>
<ul-fft-sampling-offsets>
<scs>KHZ_30</scs>
<ul-fft-sampling-offset>0</ul-fft-sampling-offset>
</ul-fft-sampling-offsets>
<e-axcid>
<o-du-port-bitmask>61440</o-du-port-bitmask>
<band-sector-bitmask>3840</band-sector-bitmask>
@@ -1926,6 +2055,7 @@ sequenceDiagram
<ru-port-bitmask>15</ru-port-bitmask>
<eaxc-id>7</eaxc-id>
</e-axcid>
<non-time-managed-delay-enabled>true</non-time-managed-delay-enabled>
</low-level-rx-endpoints>
<tx-array-carriers>
<name>TxArray0</name>
@@ -1933,7 +2063,7 @@ sequenceDiagram
<center-of-channel-bandwidth>3950400000</center-of-channel-bandwidth>
<channel-bandwidth>100000000</channel-bandwidth>
<active>ACTIVE</active>
<gain>0.0</gain>
<gain>24.0</gain>
<downlink-radio-frame-offset>0</downlink-radio-frame-offset>
<downlink-sfn-offset>0</downlink-sfn-offset>
</tx-array-carriers>
@@ -1957,7 +2087,7 @@ sequenceDiagram
[HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.80.9".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <commit> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully commited CU-planes configuration into running datastore for RU "192.168.80.9".
[HW] [MPLANE] Successfully commited configuration into running datastore for RU "192.168.80.9".
[HW] [MPLANE] Usage state = "idle" for RU "192.168.80.9".
[HW] [MPLANE] Received notification from RU "192.168.80.9" at (2025-03-29T12:40:23.049085102+00:00)
{
@@ -2025,9 +2155,71 @@ sequenceDiagram
"operation": "create"
},
...
}
[HW] [MPLANE] RU "192.168.80.9" is now ready.
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <edit-config>:
<performance-measurement-objects xmlns="urn:o-ran:performance-management:1.0">
<rx-window-measurement-interval>10</rx-window-measurement-interval>
<tx-measurement-interval>10</tx-measurement-interval>
<notification-interval>10</notification-interval>
<rx-window-measurement-objects>
<measurement-object>RX_ON_TIME</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_EARLY</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_LATE</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_TOTAL</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_ON_TIME_C</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_EARLY_C</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<rx-window-measurement-objects>
<measurement-object>RX_LATE_C</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</rx-window-measurement-objects>
<tx-measurement-objects>
<measurement-object>TX_TOTAL</measurement-object>
<active>true</active>
<object-unit>RU</object-unit>
<report-info>COUNT</report-info>
</tx-measurement-objects>
</performance-measurement-objects>
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully edited the candidate datastore for RU "192.168.80.9".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <validate> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully validated candidate datastore for RU "192.168.80.9".
[HW] [MPLANE] RPC request to RU "192.168.80.9" = <commit> candidate datastore.
[HW] [MPLANE] RPC reply = OK.
[HW] [MPLANE] Successfully commited configuration into running datastore for RU "192.168.80.9".
[HW] [MPLANE] Sucessfully activated PM after start-up procedure for RU "192.168.80.9".
```
</details>

View File

@@ -909,11 +909,12 @@ static void fill_rf_config(RU_t *ru, char *rf_config_file)
}
}
static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, int slots_per_frame, uint16_t ofdm_symbol_size)
static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_request_scf_t *config, const NR_DL_FRAME_PARMS *fp)
{
const nfapi_nr_prach_config_t *prach_config = &config->prach_config;
const nfapi_nr_tdd_table_t *tdd_table = &config->tdd_table;
const nfapi_nr_cell_config_t *cell_config = &config->cell_config;
const nfapi_nr_carrier_config_t *carrier_config = &config->carrier_config;
DevAssert(prach_config->prach_ConfigurationIndex.tl.tag == NFAPI_NR_CONFIG_PRACH_CONFIG_INDEX_TAG);
split7->prach_index = prach_config->prach_ConfigurationIndex.value;
@@ -924,7 +925,7 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_
if (cell_config->frame_duplex_type.value == 1 /* TDD */) {
DevAssert(tdd_table->tdd_period.tl.tag == NFAPI_NR_CONFIG_TDD_PERIOD_TAG);
int nb_periods_per_frame = get_nb_periods_per_frame(tdd_table->tdd_period.value);
split7->n_tdd_period = slots_per_frame / nb_periods_per_frame;
split7->n_tdd_period = fp->slots_per_frame / nb_periods_per_frame;
for (int slot = 0; slot < split7->n_tdd_period; ++slot) {
for (int sym = 0; sym < 14; ++sym) {
split7->slot_dirs[slot].sym_dir[sym] = tdd_table->max_tdd_periodicity_list[slot].max_num_of_symbol_per_slot_list[sym].slot_config.value;
@@ -932,7 +933,15 @@ static void fill_split7_2_config(split7_config_t *split7, const nfapi_nr_config_
}
}
split7->fftSize = log2(ofdm_symbol_size);
split7->fftSize = log2(fp->ofdm_symbol_size);
// M-plane related parameters
for (size_t i = 0; i < 5 ; i++) {
split7->dl_k0[i] = carrier_config->dl_k0[i].value;
split7->ul_k0[i] = carrier_config->ul_k0[i].value;
}
split7->cp_prefix0 = fp->nb_prefix_samples0;
split7->cp_prefix_other = fp->nb_prefix_samples;
}
/* this function maps the RU tx and rx buffers to the available rf chains.
@@ -1117,7 +1126,7 @@ void *ru_thread(void *param)
nr_dump_frame_parms(fp);
nr_phy_init_RU(ru);
fill_rf_config(ru, ru->rf_config_file);
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp->slots_per_frame, fp->ofdm_symbol_size);
fill_split7_2_config(&ru->openair0_cfg.split7, &ru->config, fp);
if(!emulate_rf) {
// Start IF device if any

View File

@@ -198,6 +198,13 @@ typedef struct split7_config {
} slot_dirs[160];
/*! this is the exponent in 2^X for the FFT size */
uint16_t fftSize;
// M-plane related parameters
uint16_t dl_k0[5];
uint16_t ul_k0[5];
uint16_t cp_prefix0;
uint16_t cp_prefix_other;
} split7_config_t;
/*! \brief RF frontend parameters set by application */

View File

@@ -21,14 +21,12 @@
#include "config-mplane.h"
#include "rpc-send-recv.h"
#include "yang/get-yang.h"
#include "yang/create-yang-config.h"
#include "common/utils/assertions.h"
#include <libyang/libyang.h>
#include <nc_client.h>
bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus)
static bool edit_config_mplane(ru_session_t *ru_session, const char *content)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
@@ -39,37 +37,21 @@ bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const open
NC_RPC_EDIT_TESTOPT test = NC_RPC_EDIT_TESTOPT_UNKNOWN;
NC_RPC_EDIT_ERROPT err = NC_RPC_EDIT_ERROPT_UNKNOWN;
bool success = false;
struct ly_ctx *ctx = NULL;
success = load_yang_models(ru_session, buffer, &ctx);
AssertError(success, return false, "[MPLANE] Unable to continue.\n");
char *content = NULL;
success = configure_ru_from_yang(&ctx, ru_session, oai, num_rus, &content);
AssertError(success, return false, "[MPLANE] Unable to create content for <edit-config> RPC.\n");
MP_LOG_I("RPC request to RU \"%s\" = <edit-config>:\n%s\n", ru_session->ru_ip_add, content);
rpc = nc_rpc_edit(target, op, test, err, content, param);
AssertError(rpc != NULL, return false, "[MPLANE] <edit-config> RPC creation failed.\n");
success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
AssertError(success, return false, "[MPLANE] Failed to edit configuration for the candidate datastore.\n");
MP_LOG_I("Successfully edited the candidate datastore for RU \"%s\".\n", ru_session->ru_ip_add);
nc_rpc_free(rpc);
free(content);
#ifdef MPLANE_V1
ly_ctx_destroy(ctx, NULL);
#elif defined MPLANE_V2
ly_ctx_destroy(ctx);
#endif
return true;
}
bool validate_config_mplane(ru_session_t *ru_session)
static bool validate_config_mplane(ru_session_t *ru_session)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
@@ -92,7 +74,7 @@ bool validate_config_mplane(ru_session_t *ru_session)
return true;
}
bool commit_config_mplane(ru_session_t *ru_session)
static bool commit_config_mplane(ru_session_t *ru_session)
{
int timeout = CLI_RPC_REPLY_TIMEOUT;
struct nc_rpc *rpc;
@@ -109,9 +91,25 @@ bool commit_config_mplane(ru_session_t *ru_session)
bool success = rpc_send_recv((struct nc_session *)ru_session->session, rpc, wd, timeout, NULL);
AssertError(success, return false, "[MPLANE] Failed to commit candidate datastore.\n");
MP_LOG_I("Successfully commited CU-planes configuration into running datastore for RU \"%s\".\n", ru_session->ru_ip_add);
MP_LOG_I("Successfully commited configuration into running datastore for RU \"%s\".\n", ru_session->ru_ip_add);
nc_rpc_free(rpc);
return true;
}
bool edit_val_commmit_rpc(ru_session_t *ru_session, const char *content)
{
bool success = false;
success = edit_config_mplane(ru_session, content);
AssertError(success, return false, "[MPLANE] Unable to edit the RU configuration.\n");
success = validate_config_mplane(ru_session);
AssertError(success, return false, "[MPLANE] Unable to validate the RU configuration.\n");
success = commit_config_mplane(ru_session);
AssertError(success, return false, "[MPLANE] Unable to commit the RU configuration.\n");
return success;
}

View File

@@ -25,10 +25,6 @@
#include "ru-mplane-api.h"
#include "radio/COMMON/common_lib.h"
bool edit_config_mplane(ru_session_t *ru_session, const char *buffer, const openair0_config_t *oai, const size_t num_rus);
bool validate_config_mplane(ru_session_t *ru_session);
bool commit_config_mplane(ru_session_t *ru_session);
bool edit_val_commmit_rpc(ru_session_t *ru_session, const char *content);
#endif /* CONFIGURE_MPLANE_H */

View File

@@ -20,6 +20,7 @@
*/
#include "connect-mplane.h"
#include "init-mplane.h"
#include "common/utils/assertions.h"
#include <libyang/libyang.h>
@@ -37,9 +38,8 @@ static int my_auth_hostkey_check(const char *hostname, ssh_session session, void
bool connect_mplane(ru_session_t *ru_session)
{
int port = NC_PORT_SSH;
char *user = "oranbenetel";
nc_client_ssh_set_username(user);
nc_client_ssh_set_username(ru_session->username);
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, 1); // ssh-key identification
nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, -1);
@@ -47,11 +47,11 @@ bool connect_mplane(ru_session_t *ru_session)
nc_client_ssh_set_auth_hostkey_check_clb(my_auth_hostkey_check, "DATA"); // host-key identification
MP_LOG_I("RPC request to RU \"%s\" = <connect> with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port);
MP_LOG_I("RPC request to RU \"%s\" = <connect> with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, ru_session->username, port);
ru_session->session = nc_connect_ssh(ru_session->ru_ip_add, port, NULL);
AssertError(ru_session->session != NULL, return false, "[MPLANE] RU IP address %s unreachable. Maybe M-plane is disabled on the RU?\n", ru_session->ru_ip_add);
MP_LOG_I("Successfuly connected to RU \"%s\" with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, user, port);
MP_LOG_I("Successfuly connected to RU \"%s\" with username \"%s\" and port ID \"%d\".\n", ru_session->ru_ip_add, ru_session->username, port);
return true;
}
@@ -64,9 +64,18 @@ void disconnect_mplane(void *rus_disconnect)
ru_session_t *ru_session = &ru_session_list->ru_session[i];
if (ru_session->session == NULL)
continue;
MP_LOG_I("Sending PM de-activation request for RU \"%s\".\n", ru_session->ru_ip_add);
bool success = pm_conf(ru_session, "false");
if (success)
MP_LOG_I("Successfully de-activated PM for RU \"%s\".\n", ru_session->ru_ip_add);
MP_LOG_I("Disconnecting from RU \"%s\".\n", ru_session->ru_ip_add);
nc_session_free(ru_session->session, NULL);
ru_session->session = NULL;
#ifdef MPLANE_V1
ly_ctx_destroy((struct ly_ctx *)ru_session->ctx, NULL);
#elif defined MPLANE_V2
ly_ctx_destroy((struct ly_ctx *)ru_session->ctx);
#endif
}
nc_client_destroy();

View File

@@ -25,6 +25,8 @@
#include "subscribe-mplane.h"
#include "config-mplane.h"
#include "xml/get-xml.h"
#include "yang/get-yang.h"
#include "yang/create-yang-config.h"
#include <libyang/libyang.h>
#include <nc_client.h>
@@ -94,11 +96,14 @@ bool init_mplane(ru_session_list_t *ru_session_list)
char **ru_ip_addrs = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->strlistptr;
int num_rus = gpd(fhip, nump, ORAN_CONFIG_RU_IP_ADDR)->numelt;
char **ru_usernames = gpd(fhip, nump, ORAN_CONFIG_RU_USERNAME)->strlistptr;
int num_ru_users = gpd(fhip, nump, ORAN_CONFIG_RU_USERNAME)->numelt;
char **du_mac_addr = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->strlistptr;
int num_dus = gpd(fhip, nump, ORAN_CONFIG_DU_ADDR)->numelt;
int32_t *vlan_tag = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->iptr;
int num_vlan_tags = gpd(fhip, nump, ORAN_CONFIG_VLAN_TAG)->numelt;
AssertError(num_rus == num_ru_users, return false, "[MPLANE] Number of RUs should be equal to the number of users, one for each.\n");
AssertError(num_dus == num_vlan_tags, return false, "[MPLANE] Number of DU MAC addresses should be equal to the number of VLAN tags.\n");
int num_cu_planes = num_dus / num_rus;
@@ -110,6 +115,8 @@ bool init_mplane(ru_session_list_t *ru_session_list)
ru_session->session = NULL;
ru_session->ru_ip_add = calloc(strlen(ru_ip_addrs[i]) + 1, sizeof(char));
memcpy(ru_session->ru_ip_add, ru_ip_addrs[i], strlen(ru_ip_addrs[i]) + 1);
ru_session->username = calloc(strlen(ru_usernames[i]) + 1, sizeof(char));
memcpy(ru_session->username, ru_usernames[i], strlen(ru_usernames[i]) + 1);
// store DU MAC addresses and VLAN tags
ru_session->ru_mplane_config.num_cu_planes = num_cu_planes;
@@ -175,18 +182,25 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz
success = get_uplane_info(operational_ds, &ru_session->ru_mplane_config);
AssertError(success, return false, "[MPLANE] Unable to get U-plane info from RU operational datastore.\n");
// Performance Management
success = get_pm_object_list(operational_ds, &ru_session->pm_stats);
AssertError(success, return false, "[MPLANE] Unable to retrieve performance measurement names from RU \"%s\".\n", ru_session->ru_ip_add);
success = load_yang_models(ru_session, operational_ds);
AssertError(success, return false, "[MPLANE] Unable to load yang models.\n");
if (ru_session->ru_notif.ptp_state) {
success = edit_config_mplane(ru_session, operational_ds, oai, num_rus);
AssertError(success, return false, "[MPLANE] Unable to edit the RU configuration.\n");
char *content = NULL;
success = configure_ru_from_yang(ru_session, oai, num_rus, &content);
AssertError(success, return false, "[MPLANE] Unable to create content for <edit-config> RPC for start-up procedure.\n");
success = validate_config_mplane(ru_session);
AssertError(success, return false, "[MPLANE] Unable to validate the RU configuration.\n");
success = commit_config_mplane(ru_session);
AssertError(success, return false, "[MPLANE] Unable to commit the RU configuration.\n");
success = edit_val_commmit_rpc(ru_session, content);
AssertError(success, return false, "[MPLANE] Unable to continue.\n");
free(content);
}
const char *usage_state = get_ru_xml_node(operational_ds, "usage-state");
//const char *usage_state = get_ru_xml_node(operational_ds, "usage-state");
const char *usage_state = "busy";
MP_LOG_I("Usage state = \"%s\" for RU \"%s\".\n", usage_state, ru_session->ru_ip_add);
if (strcmp(usage_state, "busy") == 0) { // carriers are already activated
ru_session->ru_notif.rx_carrier_state = true;
@@ -201,5 +215,19 @@ bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const siz
free(operational_ds);
free(watchdog_answer);
sleep(100);
return true;
}
bool pm_conf(ru_session_t *ru_session, const char *active)
{
char *content = get_pm_content(ru_session, active);
bool success = edit_val_commmit_rpc(ru_session, content);
AssertError(success, return false, "[MPLANE] Cannot continue.\n");
free(content);
return true;
}

View File

@@ -29,4 +29,6 @@ bool init_mplane(ru_session_list_t *ru_session_list);
bool manage_ru(ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus);
bool pm_conf(ru_session_t *ru_session, const char *active);
#endif /* OAI_MPLANE_H */

View File

@@ -33,7 +33,14 @@ static void free_match_list(char **match_list, size_t count)
free(match_list);
}
static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t interface_mtu, const int16_t first_iq_width, const int max_num_ant)
static void fix_metanoia_setting(xran_mplane_t *xran_mplane, const uint32_t interface_mtu, const uint16_t first_iq_width, const int max_num_ant)
{
xran_mplane->mtu = interface_mtu;
xran_mplane->iq_width = first_iq_width;
xran_mplane->prach_offset = max_num_ant;
}
static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t interface_mtu, const int16_t first_iq_width, const int max_num_ant, const char *model_name)
{
if (interface_mtu == 1500) {
MP_LOG_I("Interface MTU %d unreliable/not correctly reported by Benetel O-RU, hardcoding to 9600.\n", interface_mtu);
@@ -50,6 +57,14 @@ static void fix_benetel_setting(xran_mplane_t *xran_mplane, const uint32_t inter
}
xran_mplane->prach_offset = max_num_ant;
if (strcasecmp(model_name, "RAN550") == 0) {
xran_mplane->max_tx_gain = 24.0;
} else if (strcasecmp(model_name, "RAN650") == 0) {
xran_mplane->max_tx_gain = 35.0;
} else {
assert(false && "[MPLANE] Unknown Benetel model name.\n");
}
}
bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_t *xran_mplane)
@@ -61,7 +76,7 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_
xran_mplane->ru_mac_addr = get_ru_xml_node(buffer, "mac-address"); // TODO: support for VVDN, as it defines multiple MAC addresses
// MTU
const uint32_t interface_mtu = (uint32_t)atoi(get_ru_xml_node(buffer, "interface-mtu"));
const uint32_t interface_mtu = (uint32_t)atoi(get_ru_xml_node(buffer, "l2-mtu"));
// IQ bitwidth
char **match_list = NULL;
@@ -91,10 +106,28 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_
// RU port ID
xran_mplane->ru_port = 0;
if (strcasecmp(ru_vendor, "BENETEL") == 0 /* || strcmp(ru_vendor, "VVDN-LPRU") == 0 || strcmp(ru_vendor, "Metanoia") == 0 */) {
fix_benetel_setting(xran_mplane, interface_mtu, first_iq_width, max_num_ant);
// Frame structure
match_list = NULL;
count = 0;
get_ru_xml_list(buffer, "supported-frame-structures", &match_list, &count);
xran_mplane->frame_str = (int16_t)atoi((char *)match_list[0]);
free_match_list(match_list, count);
// Managed delay support
const char *managed_delay = get_ru_xml_node(buffer, "managed-delay-support");
xran_mplane->managed_delay = (strcasecmp(managed_delay, "NON_MANAGED") == 0) ? false : true;
// Store the max gain
xran_mplane->max_tx_gain = (double)atof(get_ru_xml_node(buffer, "max-gain"));
// Model name
const char *model_name = get_ru_xml_node(buffer, "model-name");
if (ru_vendor && strcasecmp(ru_vendor, "BENETEL") == 0) {
fix_benetel_setting(xran_mplane, interface_mtu, first_iq_width, max_num_ant, model_name);
} else {
AssertError(false, return false, "[MPLANE] %s RU currently not supported.\n", ru_vendor);
fix_metanoia_setting(xran_mplane, interface_mtu, first_iq_width, max_num_ant);
//AssertError(false, return false, "[MPLANE] %s RU currently not supported.\n", ru_vendor);
}
MP_LOG_I("Storing the following information to forward to xran:\n\
@@ -109,7 +142,8 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_
DU port ID %d\n\
Band sector ID %d\n\
CC ID %d\n\
RU port ID %d\n",
RU port ID %d\n\
max Tx gain %.1f\n",
xran_mplane->ru_mac_addr,
xran_mplane->mtu,
xran_mplane->iq_width,
@@ -121,7 +155,8 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_
xran_mplane->du_port,
xran_mplane->band_sector,
xran_mplane->ccid,
xran_mplane->ru_port);
xran_mplane->ru_port,
xran_mplane->max_tx_gain);
return true;
}
@@ -155,3 +190,23 @@ bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config)
return true;
}
bool get_pm_object_list(const char *buffer, pm_stats_t *pm_stats)
{
const char *ru_vendor = get_ru_xml_node(buffer, "mfg-name");
if (ru_vendor && strcasecmp(ru_vendor, "BENETEL") == 0) {
pm_stats->start_up_timing = false;
} else {
pm_stats->start_up_timing = true;
}
// Rx window
get_ru_xml_list(buffer, "rx-window-measurement-objects", &pm_stats->rx_window_meas, &pm_stats->rx_num);
// Tx
get_ru_xml_list(buffer, "tx-measurement-objects", &pm_stats->tx_meas, &pm_stats->tx_num);
MP_LOG_I("Successfully retreived all performance measurement names.\n");
return true;
}

View File

@@ -57,6 +57,10 @@ typedef struct {
uint8_t band_sector;
uint8_t ccid;
uint8_t ru_port;
int16_t frame_str; // might be needed in the future xran releases
bool managed_delay;
double max_tx_gain;
} xran_mplane_t;
@@ -78,11 +82,26 @@ typedef struct {
} ru_mplane_config_t;
typedef struct {
// activation if required at start-up timing
bool start_up_timing;
size_t rx_num;
char **rx_window_meas;
size_t tx_num;
char **tx_meas;
} pm_stats_t;
typedef struct {
char *username;
char *ru_ip_add;
ru_mplane_config_t ru_mplane_config;
void *session;
void *ctx;
xran_mplane_t xran_mplane;
ru_notif_t ru_notif;
pm_stats_t pm_stats;
} ru_session_t;
@@ -97,4 +116,6 @@ bool get_config_for_xran(const char *buffer, const int max_num_ant, xran_mplane_
bool get_uplane_info(const char *buffer, ru_mplane_config_t *ru_mplane_config);
bool get_pm_object_list(const char *buffer, pm_stats_t *pm_stats);
#endif /* RU_MPLANE_API_H */

View File

@@ -54,6 +54,37 @@ static void notif_clb_v1(struct nc_session *session, const struct nc_notif *noti
recv_notif_v1(notif, answer);
}
#elif MPLANE_V2
static void log_v2_pm_info(const char *ru_ip_add, struct lyd_node_inner *stats)
{
struct lyd_node *child, *field = NULL;
size_t len = 0;
char *meas_list[8], *count_list[8] = {};
LY_LIST_FOR(stats->child, child) {
// const char *type = child->schema->name; // e.g. "rx-window-stats", "tx-stats"
struct lyd_node_inner *stats_inner = (struct lyd_node_inner *)child;
LY_LIST_FOR(stats_inner->child, field) {
if (strcmp(field->schema->name, "measurement-object") == 0) {
meas_list[len] = (char *)lyd_get_value(field);
} else if (strcmp(field->schema->name, "count") == 0) {
count_list[len] = (char *)lyd_get_value(field);
len++;
}
}
}
MP_LOG_I("[PM: \"%s\"][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s][%s %7s]\n",
ru_ip_add,
meas_list[0], count_list[0],
meas_list[1], count_list[1],
meas_list[2], count_list[2],
meas_list[3], count_list[3],
meas_list[4], count_list[4],
meas_list[5], count_list[5],
meas_list[6], count_list[6],
meas_list[7], count_list[7]);
}
static void recv_notif_v2(struct lyd_node_inner *op, ru_notif_t *answer)
{
const char *notif = op->schema->name;
@@ -92,9 +123,14 @@ static void notif_clb_v2(struct nc_session *session, const struct lyd_node *envp
char *subs_reply = NULL;
lyd_print_mem(&subs_reply, op, output_format, LYD_PRINT_WITHSIBLINGS);
const char *ru_ip_add = nc_session_get_host(session);
struct lyd_node_inner *op_inner = (struct lyd_node_inner *)op;
if (strcmp(op_inner->schema->name, "measurement-result-stats") == 0) {
log_v2_pm_info(ru_ip_add, op_inner);
return;
}
MP_LOG_I("Received notification from RU \"%s\" at (%s)\n%s\n", ru_ip_add, ((struct lyd_node_opaq *)lyd_child(envp))->value, subs_reply);
recv_notif_v2((struct lyd_node_inner *)op, answer);
recv_notif_v2(op_inner, answer);
}
#endif

View File

@@ -68,7 +68,8 @@ static void find_ru_xml_list(xmlNode *node, const char *filter, char ***match_li
xmlNode *name_node = NULL;
for (xmlNode *cur_node2 = cur_node->children; cur_node2; cur_node2 = cur_node2->next) {
if (cur_node2->type == XML_ELEMENT_NODE && strcmp((const char *)cur_node2->name, "name") == 0) {
const char *name_node_str = (const char *)cur_node2->name;
if (cur_node2->type == XML_ELEMENT_NODE && (strcmp(name_node_str, "name") == 0 || strcmp(name_node_str, "measurement-object") == 0)) {
name_node = cur_node2;
break;
}

View File

@@ -23,13 +23,14 @@
#include "common/utils/nr/nr_common.h"
#define VERIFY_SUCCESS(var, message, args...) AssertError(var, return false, message, ##args)
const char *scs_name[] = {"KHZ_15", "KHZ_30", "KHZ_60", "KHZ_120", "KHZ_240", NULL};
#ifdef MPLANE_V2
static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root)
static bool create_cu_interface_v2(const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = lyd_new_path(NULL, *ctx, "/ietf-interfaces:interfaces", NULL, 0, root);
ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/ietf-interfaces:interfaces", NULL, 0, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"interfaces\" node.\n");
struct lyd_node *interface_node = NULL;
@@ -43,7 +44,7 @@ static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_s
ret = lyd_new_term(interface_node, NULL, "enabled", "true", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"enabled\" node.\n");
const struct lys_module *oran_int_mod = ly_ctx_get_module_implemented(*ctx, "o-ran-interfaces");
const struct lys_module *oran_int_mod = ly_ctx_get_module_implemented((struct ly_ctx *)ru_session->ctx, "o-ran-interfaces");
VERIFY_SUCCESS(oran_int_mod != NULL, "[MPLANE] Failed to get \"o-ran-interfaces\" module.\n");
struct lyd_node *base_int = NULL;
@@ -63,11 +64,11 @@ static bool create_cu_interface_v2(struct ly_ctx **ctx, const ru_session_t *ru_s
return true;
}
static bool create_proc_elem_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root)
static bool create_proc_elem_v2(const ru_session_t *ru_session, const size_t idx, const char *int_name, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = lyd_new_path(NULL, *ctx, "/o-ran-processing-element:processing-elements", NULL, 0, root);
ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/o-ran-processing-element:processing-elements", NULL, 0, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"processing-elements\" node.\n");
ret = lyd_new_term(*root, NULL, "transport-session-type", "ETH-INTERFACE", 0, NULL);
@@ -104,20 +105,40 @@ static bool create_proc_elem_v2(struct ly_ctx **ctx, const ru_session_t *ru_sess
return true;
}
static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx, struct lyd_node **root)
static LY_ERR fill_uplane_ch_common_v2(const bool rx_dir, const xran_mplane_t *xran_mplane, const openair0_config_t *oai, const size_t idx, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = lyd_new_term(*root, NULL, "cp-length", "0", 0, NULL);
char frame_str[8];
snprintf(frame_str, sizeof(frame_str), "%d", (oai->split7.fftSize << 4) + oai->nr_scs_for_raster); // 3GPP TS 38.211
ret = lyd_new_term(*root, NULL, "frame-structure", frame_str, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"frame-structure\" node.\n");
// EXTENDED not supported
// 3GPP TS 38.211
const char cp_type[] = "NORMAL";
ret = lyd_new_term(*root, NULL, "cp-type", cp_type, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-type\" node.\n");
char cp_len[8];
snprintf(cp_len, sizeof(cp_len), "%d", oai->split7.cp_prefix0);
ret = lyd_new_term(*root, NULL, "cp-length", cp_len, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length\" node.\n");
ret = lyd_new_term(*root, NULL, "cp-length-other", "0", 0, NULL);
char cp_len_other[8];
snprintf(cp_len_other, sizeof(cp_len_other), "%d", oai->split7.cp_prefix_other);
ret = lyd_new_term(*root, NULL, "cp-length-other", cp_len_other, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"cp-length-other\" node.\n");
// to we actually store this from DU config file?
ret = lyd_new_term(*root, NULL, "offset-to-absolute-frequency-center", "0", 0, NULL);
char freq_offset[8];
if (rx_dir == true) {
snprintf(freq_offset, sizeof(freq_offset), "%d", oai->split7.ul_k0[oai->nr_scs_for_raster]);
} else {
snprintf(freq_offset, sizeof(freq_offset), "%d", oai->split7.dl_k0[oai->nr_scs_for_raster]);
}
ret = lyd_new_term(*root, NULL, "offset-to-absolute-frequency-center", freq_offset, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"offset-to-absolute-frequency-center\" node.\n");
struct lyd_node *compression_node = NULL;
ret = lyd_new_inner(*root, NULL, "compression", 0, &compression_node);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression\" node.\n");
@@ -126,15 +147,20 @@ static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx
snprintf(iq_width_str, sizeof(iq_width_str), "%d", xran_mplane->iq_width);
ret = lyd_new_term(compression_node, NULL, "iq-bitwidth", iq_width_str, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"iq-bitwidth\" node.\n");
if (xran_mplane->iq_width < 16) {
ret = lyd_new_term(compression_node, NULL, "compression-type", "STATIC", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-type\" node.\n");
// ret = lyd_new_term(compression_node, NULL, "compression-method", "BLOCK_FLOATING_POINT", 0, NULL);
// VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"compression-method\" node.\n");
}
if (rx_dir == true) {
ret = lyd_new_term(compression_node, NULL, "fs-offset", "8", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"fs-offset\" node.\n");
}
struct lyd_node *eaxc_conf = NULL;
ret = lyd_new_inner(*root, NULL, "e-axcid", 0, &eaxc_conf);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"e-axcid\" node.\n");
@@ -143,12 +169,12 @@ static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx
snprintf(eaxc_id, sizeof(eaxc_id), "%ld", idx);
ret = lyd_new_term(eaxc_conf, NULL, "eaxc-id", eaxc_id, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"eaxc-id\" node.\n");
char du_port_bitmask[16];
snprintf(du_port_bitmask, sizeof(du_port_bitmask), "%d", xran_mplane->du_port_bitmask);
ret = lyd_new_term(eaxc_conf, NULL, "o-du-port-bitmask", du_port_bitmask, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"o-du-port-bitmask\" node.\n");
char band_sector_bitmask[8];
snprintf(band_sector_bitmask, sizeof(band_sector_bitmask), "%d", xran_mplane->band_sector_bitmask);
ret = lyd_new_term(eaxc_conf, NULL, "band-sector-bitmask", band_sector_bitmask, 0, NULL);
@@ -164,15 +190,50 @@ static bool fill_uplane_ch_v2(const xran_mplane_t *xran_mplane, const size_t idx
ret = lyd_new_term(eaxc_conf, NULL, "ru-port-bitmask", ru_port_bitmask, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ru-port-bitmask\" node.\n");
return LY_SUCCESS;
}
static bool fill_uplane_ch_rx_v2(const xran_mplane_t *xran_mplane, const openair0_config_t *oai, const size_t idx, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = fill_uplane_ch_common_v2(true, xran_mplane, oai, idx, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create common nodes.\n");
const char *managed_delay = xran_mplane->managed_delay ? "true" : "false";
ret = lyd_new_term(*root, NULL, "non-time-managed-delay-enabled", managed_delay, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"non-time-managed-delay-enabled\" node.\n");
struct lyd_node *fft_offset = NULL;
ret = lyd_new_list(*root, NULL, "ul-fft-sampling-offsets", 0, &fft_offset, scs_name[oai->nr_scs_for_raster]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ul-fft-sampling-offsets\" node.\n");
// Note: set of allowed values is restricted by SCS derived from values in supported-frame-structures.
char ul_fft_offset[8];
const int frame = (oai->split7.fftSize << 4) + oai->nr_scs_for_raster;
snprintf(ul_fft_offset, sizeof(ul_fft_offset), "%d", frame - xran_mplane->frame_str);
ret = lyd_new_term(fft_offset, NULL, "ul-fft-sampling-offset", ul_fft_offset, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"ul-fft-sampling-offset\" node.\n");
return true;
}
static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, const char *u_proc_elem, struct lyd_node **root)
static bool fill_uplane_ch_tx_v2(const xran_mplane_t *xran_mplane, const openair0_config_t *oai, const size_t idx, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = fill_uplane_ch_common_v2(false, xran_mplane, oai, idx, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create common nodes.\n");
return true;
}
static bool create_uplane_conf_v2(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, const char *u_proc_elem, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
bool success = true;
ret = lyd_new_path(NULL, *ctx, "/o-ran-uplane-conf:user-plane-configuration", NULL, 0, root);
ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/o-ran-uplane-conf:user-plane-configuration", NULL, 0, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"user-plane-configuration\" node.\n");
if (ru_session->ru_mplane_config.rx_carriers.num != 1 || ru_session->ru_mplane_config.tx_carriers.num !=1)
@@ -204,7 +265,8 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se
ret = lyd_new_term(rx_carrier_node, NULL, "downlink-sfn-offset", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"downlink-sfn-offset\" node.\n");
// oai->rx_gain_offset is this the correction? if yes, test it later
// gain offset applied uniformly across all array elements or layers
// needs to be within <gain-correction-range>
ret = lyd_new_term(rx_carrier_node, NULL, "gain-correction", "0", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain-correction\" node.\n");
@@ -234,8 +296,12 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se
ret = lyd_new_term(tx_carrier_node, NULL, "channel-bandwidth", tx_bw, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"channel-bandwidth\" node.\n");
// oai->tx_gain to be tested
ret = lyd_new_term(tx_carrier_node, NULL, "gain", "0", 0, NULL);
// oai->tx_gain takes the value of att_tx from the RU section of gNB config file
// we assume the same gain is applied to all channels; same as above for the frequency
const double tx_gain_value = ((oai->tx_gain[0] * 10000) < ru_session->xran_mplane.max_tx_gain) ? (oai->tx_gain[0] * 10000) : ru_session->xran_mplane.max_tx_gain;
char tx_gain_str[8];
snprintf(tx_gain_str, sizeof(tx_gain_str), "%.f", tx_gain_value);
ret = lyd_new_term(tx_carrier_node, NULL, "gain", tx_gain_str, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"gain\" node.\n");
ret = lyd_new_term(tx_carrier_node, NULL, "downlink-radio-frame-offset", "0", 0, NULL);
@@ -254,7 +320,7 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se
ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &pusch_node, ru_session->ru_mplane_config.rx_endpoints.name[i]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n");
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pusch_node);
success = fill_uplane_ch_rx_v2(&ru_session->xran_mplane, oai, i, &pusch_node);
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[i]);
const size_t prach_endpoint_name_offset = i + (ru_session->ru_mplane_config.rx_endpoints.num / 2);
@@ -262,7 +328,7 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se
ret = lyd_new_list(*root, NULL, "low-level-rx-endpoints", 0, &prach_node, ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-rx-endpoints\" node.\n");
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i + ru_session->xran_mplane.prach_offset, &prach_node);
success = fill_uplane_ch_rx_v2(&ru_session->xran_mplane, oai, i + ru_session->xran_mplane.prach_offset, &prach_node);
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-rx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.rx_endpoints.name[prach_endpoint_name_offset]);
}
@@ -273,7 +339,7 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se
ret = lyd_new_list(*root, NULL, "low-level-tx-endpoints", 0, &pdsch_node, ru_session->ru_mplane_config.tx_endpoints.name[i]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"low-level-tx-endpoints\" node.\n");
success = fill_uplane_ch_v2(&ru_session->xran_mplane, i, &pdsch_node);
success = fill_uplane_ch_tx_v2(&ru_session->xran_mplane, oai, i, &pdsch_node);
VERIFY_SUCCESS(success, "[MPLANE] Failed to fill \"low-level-tx-endpoints\" node for %s.\n", ru_session->ru_mplane_config.tx_endpoints.name[i]);
}
@@ -333,9 +399,59 @@ static bool create_uplane_conf_v2(struct ly_ctx **ctx, const ru_session_t *ru_se
return true;
}
static
bool create_pm_conf_v2(const ru_session_t *ru_session, const char *active, struct lyd_node **root)
{
LY_ERR ret = LY_SUCCESS;
ret = lyd_new_path(NULL, (struct ly_ctx *)ru_session->ctx, "/o-ran-performance-management:performance-measurement-objects", NULL, 0, root);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create root \"performance-measurement-objects\" node.\n");
ret = lyd_new_term(*root, NULL, "notification-interval", "10", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"notification-interval\" node.\n");
ret = lyd_new_term(*root, NULL, "rx-window-measurement-interval", "10", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-window-measurement-interval\" node.\n");
ret = lyd_new_term(*root, NULL, "tx-measurement-interval", "10", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-measurement-interval\" node.\n");
for (size_t i = 0; i < ru_session->pm_stats.rx_num; i++) {
struct lyd_node *rx_window_meas_objects = NULL;
ret = lyd_new_list(*root, NULL, "rx-window-measurement-objects", 0, &rx_window_meas_objects, ru_session->pm_stats.rx_window_meas[i]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"rx-window-measurement-objects\" node.\n");
ret = lyd_new_term(rx_window_meas_objects, NULL, "active", active, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n");
ret = lyd_new_term(rx_window_meas_objects, NULL, "object-unit", "RU", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"object-unit\" node.\n");
ret = lyd_new_term(rx_window_meas_objects, NULL, "report-info", "COUNT", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"report-info\" node.\n");
}
for (size_t i = 0; i < ru_session->pm_stats.tx_num; i++) {
struct lyd_node *tx_meas_objects = NULL;
ret = lyd_new_list(*root, NULL, "tx-measurement-objects", 0, &tx_meas_objects, ru_session->pm_stats.tx_meas[i]);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"tx-measurement-objects\" node.\n");
ret = lyd_new_term(tx_meas_objects, NULL, "active", active, 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"active\" node.\n");
ret = lyd_new_term(tx_meas_objects, NULL, "object-unit", "RU", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"object-unit\" node.\n");
ret = lyd_new_term(tx_meas_objects, NULL, "report-info", "COUNT", 0, NULL);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Failed to create \"report-info\" node.\n");
}
return true;
}
#endif
bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result)
bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result)
{
bool success = false;
@@ -357,12 +473,12 @@ bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session,
struct lyd_node *cu_interface = NULL;
char int_name[12];
snprintf(int_name, sizeof(int_name), "INTERFACE_%ld", i);
success = create_cu_interface_v2(ctx, ru_session, i, int_name, &cu_interface);
success = create_cu_interface_v2(ru_session, i, int_name, &cu_interface);
VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane interface.\n");
// <o-ran-processing-element>
struct lyd_node *proc_elem = NULL;
success = create_proc_elem_v2(ctx, ru_session, i, int_name, &proc_elem);
success = create_proc_elem_v2(ru_session, i, int_name, &proc_elem);
VERIFY_SUCCESS(success, "[MPLANE] Cannot create CU-plane processing element.\n");
ret = lyd_merge_siblings(&all_merge, cu_interface, 0);
@@ -376,17 +492,49 @@ bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session,
// <o-ran-uplane-conf>
struct lyd_node *uplane_conf = NULL;
success = create_uplane_conf_v2(ctx, ru_session, oai, num_rus, "PLANE_0", &uplane_conf);
success = create_uplane_conf_v2(ru_session, oai, num_rus, "PLANE_0", &uplane_conf);
VERIFY_SUCCESS(success, "[MPLANE] Cannot create U-plane configuration.\n");
ret = lyd_merge_siblings(&uplane_conf, all_merge, 0);
ret = lyd_merge_siblings(&all_merge, uplane_conf, 0);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element and U-plane configuration.\n");
lyd_print_mem(result, uplane_conf, LYD_XML, LYD_PRINT_WITHSIBLINGS);
// <o-ran-pm>
struct lyd_node *pm_conf = NULL;
if (ru_session->pm_stats.start_up_timing) {
success = create_pm_conf_v2(ru_session, "true", &pm_conf);
VERIFY_SUCCESS(success, "[MPLANE] Cannot create PM activation.\n");
} else {
success = create_pm_conf_v2(ru_session, "false", &pm_conf);
VERIFY_SUCCESS(success, "[MPLANE] Cannot create PM deactivation.\n");
}
ret = lyd_merge_siblings(&all_merge, pm_conf, 0);
VERIFY_SUCCESS(ret == LY_SUCCESS, "[MPLANE] Cannot merge CU-plane interface, processing element, U-plane configuration and PM configuration.\n");
lyd_print_mem(result, all_merge, LYD_XML, LYD_PRINT_WITHSIBLINGS);
lyd_free_siblings(all_merge);
lyd_free_siblings(uplane_conf);
lyd_free_siblings(pm_conf);
#endif
return true;
}
char *get_pm_content(const ru_session_t *ru_session, const char *active)
{
bool success = false;
char *content = NULL;
#ifdef MPLANE_V1
VERIFY_SUCCESS(success, "[MPLANE] To be implemented and tested.\n");
#elif defined MPLANE_V2
struct lyd_node *pm_conf = NULL;
success = create_pm_conf_v2(ru_session, active, &pm_conf);
AssertError(success, return false, "[MPLANE] Cannot create PM configuration.\n");
lyd_print_mem(&content, pm_conf, LYD_XML, LYD_PRINT_WITHSIBLINGS);
lyd_free_siblings(pm_conf);
#endif
return content;
}

View File

@@ -27,6 +27,8 @@
#include <libyang/libyang.h>
bool configure_ru_from_yang(struct ly_ctx **ctx, const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result);
bool configure_ru_from_yang(const ru_session_t *ru_session, const openair0_config_t *oai, const size_t num_rus, char **result);
char *get_pm_content(const ru_session_t *ru_session, const char *active);
#endif /* CREATE_MPLANE_YANG_CONFIG_H */

View File

@@ -95,8 +95,10 @@ static bool load_from_operational_ds(xmlNode *node, ru_session_t *ru_session, st
return false;
}
bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx)
bool load_yang_models(ru_session_t *ru_session, const char *buffer)
{
struct ly_ctx **ctx = (struct ly_ctx **)&ru_session->ctx;
// Initialize the xml file
size_t len = strlen(buffer) + 1;
xmlDoc *doc = xmlReadMemory(buffer, len, NULL, NULL, 0);
@@ -114,7 +116,7 @@ bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ct
1) the yang models order is not good - the dependancy models have to be loaded first
2) earlier O-RAN yang versions (e.g. v4) is not properly defined (i.e. optional parameters should not be included by default) */
const char *yang_dir = YANG_MODELS;
const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf"};
const char *yang_models[] = {"ietf-interfaces", "iana-if-type", "ietf-ip", "iana-hardware", "ietf-hardware", "o-ran-interfaces", "o-ran-module-cap", "o-ran-compression-factors", "o-ran-processing-element", "o-ran-uplane-conf", "ietf-netconf-acm", "ietf-crypto-types", "o-ran-file-management", "o-ran-performance-management"};
#ifdef MPLANE_V1
*ctx = ly_ctx_new(yang_dir, 0);

View File

@@ -26,6 +26,6 @@
#include <libyang/libyang.h>
bool load_yang_models(ru_session_t *ru_session, const char *buffer, struct ly_ctx **ctx);
bool load_yang_models(ru_session_t *ru_session, const char *buffer);
#endif /* GET_MPLANE_YANG_MODELS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,440 @@
module ietf-netconf-acm {
namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
prefix nacm;
import ietf-yang-types {
prefix yang;
}
organization
"IETF NETCONF (Network Configuration) Working Group";
contact
"WG Web: <https://datatracker.ietf.org/wg/netconf/>
WG List: <mailto:netconf@ietf.org>
Author: Andy Bierman
<mailto:andy@yumaworks.com>
Author: Martin Bjorklund
<mailto:mbj@tail-f.com>";
description
"Network Configuration Access Control Model.
Copyright (c) 2012 - 2018 IETF Trust and the persons
identified as authors of the code. All rights reserved.
Redistribution and use in source and binary forms, with or
without modification, is permitted pursuant to, and subject
to the license terms contained in, the Simplified BSD
License set forth in Section 4.c of the IETF Trust's
Legal Provisions Relating to IETF Documents
(https://trustee.ietf.org/license-info).
This version of this YANG module is part of RFC 8341; see
the RFC itself for full legal notices.";
revision "2018-02-14" {
description
"Added support for YANG 1.1 actions and notifications tied to
data nodes. Clarified how NACM extensions can be used by
other data models.";
reference
"RFC 8341: Network Configuration Access Control Model";
}
revision "2012-02-22" {
description
"Initial version.";
reference
"RFC 6536: Network Configuration Protocol (NETCONF)
Access Control Model";
}
/*
* Extension statements
*/
extension default-deny-write {
description
"Used to indicate that the data model node
represents a sensitive security system parameter.
If present, the NETCONF server will only allow the designated
'recovery session' to have write access to the node. An
explicit access control rule is required for all other users.
If the NACM module is used, then it must be enabled (i.e.,
/nacm/enable-nacm object equals 'true'), or this extension
is ignored.
The 'default-deny-write' extension MAY appear within a data
definition statement. It is ignored otherwise.";
}
extension default-deny-all {
description
"Used to indicate that the data model node
controls a very sensitive security system parameter.
If present, the NETCONF server will only allow the designated
'recovery session' to have read, write, or execute access to
the node. An explicit access control rule is required for all
other users.
If the NACM module is used, then it must be enabled (i.e.,
/nacm/enable-nacm object equals 'true'), or this extension
is ignored.
The 'default-deny-all' extension MAY appear within a data
definition statement, 'rpc' statement, or 'notification'
statement. It is ignored otherwise.";
}
/*
* Derived types
*/
typedef user-name-type {
type string {
length "1..max";
}
description
"General-purpose username string.";
}
typedef matchall-string-type {
type string {
pattern '\*';
}
description
"The string containing a single asterisk '*' is used
to conceptually represent all possible values
for the particular leaf using this data type.";
}
typedef access-operations-type {
type bits {
bit create {
description
"Any protocol operation that creates a
new data node.";
}
bit read {
description
"Any protocol operation or notification that
returns the value of a data node.";
}
bit update {
description
"Any protocol operation that alters an existing
data node.";
}
bit delete {
description
"Any protocol operation that removes a data node.";
}
bit exec {
description
"Execution access to the specified protocol operation.";
}
}
description
"Access operation.";
}
typedef group-name-type {
type string {
length "1..max";
pattern '[^\*].*';
}
description
"Name of administrative group to which
users can be assigned.";
}
typedef action-type {
type enumeration {
enum permit {
description
"Requested action is permitted.";
}
enum deny {
description
"Requested action is denied.";
}
}
description
"Action taken by the server when a particular
rule matches.";
}
typedef node-instance-identifier {
type yang:xpath1.0;
description
"Path expression used to represent a special
data node, action, or notification instance-identifier
string.
A node-instance-identifier value is an
unrestricted YANG instance-identifier expression.
All the same rules as an instance-identifier apply,
except that predicates for keys are optional. If a key
predicate is missing, then the node-instance-identifier
represents all possible server instances for that key.
This XML Path Language (XPath) expression is evaluated in the
following context:
o The set of namespace declarations are those in scope on
the leaf element where this type is used.
o The set of variable bindings contains one variable,
'USER', which contains the name of the user of the
current session.
o The function library is the core function library, but
note that due to the syntax restrictions of an
instance-identifier, no functions are allowed.
o The context node is the root node in the data tree.
The accessible tree includes actions and notifications tied
to data nodes.";
}
/*
* Data definition statements
*/
container nacm {
nacm:default-deny-all;
description
"Parameters for NETCONF access control model.";
leaf enable-nacm {
type boolean;
default "true";
description
"Enables or disables all NETCONF access control
enforcement. If 'true', then enforcement
is enabled. If 'false', then enforcement
is disabled.";
}
leaf read-default {
type action-type;
default "permit";
description
"Controls whether read access is granted if
no appropriate rule is found for a
particular read request.";
}
leaf write-default {
type action-type;
default "deny";
description
"Controls whether create, update, or delete access
is granted if no appropriate rule is found for a
particular write request.";
}
leaf exec-default {
type action-type;
default "permit";
description
"Controls whether exec access is granted if no appropriate
rule is found for a particular protocol operation request.";
}
leaf enable-external-groups {
type boolean;
default "true";
description
"Controls whether the server uses the groups reported by the
NETCONF transport layer when it assigns the user to a set of
NACM groups. If this leaf has the value 'false', any group
names reported by the transport layer are ignored by the
server.";
}
leaf denied-operations {
type yang:zero-based-counter32;
config false;
mandatory true;
description
"Number of times since the server last restarted that a
protocol operation request was denied.";
}
leaf denied-data-writes {
type yang:zero-based-counter32;
config false;
mandatory true;
description
"Number of times since the server last restarted that a
protocol operation request to alter
a configuration datastore was denied.";
}
leaf denied-notifications {
type yang:zero-based-counter32;
config false;
mandatory true;
description
"Number of times since the server last restarted that
a notification was dropped for a subscription because
access to the event type was denied.";
}
container groups {
description
"NETCONF access control groups.";
list group {
key name;
description
"One NACM group entry. This list will only contain
configured entries, not any entries learned from
any transport protocols.";
leaf name {
type group-name-type;
description
"Group name associated with this entry.";
}
leaf-list user-name {
type user-name-type;
description
"Each entry identifies the username of
a member of the group associated with
this entry.";
}
}
}
list rule-list {
key name;
ordered-by user;
description
"An ordered collection of access control rules.";
leaf name {
type string {
length "1..max";
}
description
"Arbitrary name assigned to the rule-list.";
}
leaf-list group {
type union {
type matchall-string-type;
type group-name-type;
}
description
"List of administrative groups that will be
assigned the associated access rights
defined by the 'rule' list.
The string '*' indicates that all groups apply to the
entry.";
}
list rule {
key name;
ordered-by user;
description
"One access control rule.
Rules are processed in user-defined order until a match is
found. A rule matches if 'module-name', 'rule-type', and
'access-operations' match the request. If a rule
matches, the 'action' leaf determines whether or not
access is granted.";
leaf name {
type string {
length "1..max";
}
description
"Arbitrary name assigned to the rule.";
}
leaf module-name {
type union {
type matchall-string-type;
type string;
}
default "*";
description
"Name of the module associated with this rule.
This leaf matches if it has the value '*' or if the
object being accessed is defined in the module with the
specified module name.";
}
choice rule-type {
description
"This choice matches if all leafs present in the rule
match the request. If no leafs are present, the
choice matches all requests.";
case protocol-operation {
leaf rpc-name {
type union {
type matchall-string-type;
type string;
}
description
"This leaf matches if it has the value '*' or if
its value equals the requested protocol operation
name.";
}
}
case notification {
leaf notification-name {
type union {
type matchall-string-type;
type string;
}
description
"This leaf matches if it has the value '*' or if its
value equals the requested notification name.";
}
}
case data-node {
leaf path {
type node-instance-identifier;
mandatory true;
description
"Data node instance-identifier associated with the
data node, action, or notification controlled by
this rule.
Configuration data or state data
instance-identifiers start with a top-level
data node. A complete instance-identifier is
required for this type of path value.
The special value '/' refers to all possible
datastore contents.";
}
}
}
leaf access-operations {
type union {
type matchall-string-type;
type access-operations-type;
}
default "*";
description
"Access operations associated with this rule.
This leaf matches if it has the value '*' or if the
bit corresponding to the requested operation is set.";
}
leaf action {
type action-type;
mandatory true;
description
"The access control action associated with the
rule. If a rule has been determined to match a
particular request, then this object is used
to determine whether to permit or deny the
request.";
}
leaf comment {
type string;
description
"A textual description of the access rule.";
}
}
}
}
}

View File

@@ -0,0 +1,213 @@
module o-ran-file-management {
yang-version 1.1;
namespace "urn:o-ran:file-management:1.0";
prefix "o-ran-file-mgmt";
import ietf-crypto-types {
prefix "ct";
}
organization "O-RAN Alliance";
contact
"www.o-ran.org";
description
"This module defines the configuration and operations for handling upload.
Copyright 2019 the O-RAN Alliance.
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.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the above disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the above disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the Members of the O-RAN Alliance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.";
revision "2019-07-03" {
description
"version 1.1.0
1) backward compatible changes to correct sFTP Server Authentication .
2) minor fixes according to lack of descriptions
3) backward compatible changes to introduce groupings";
reference "ORAN-WG4.M.0-v01.00";
}
revision "2019-02-04" {
description
"version 1.0.0
1) imported model from xRAN
2) changed namespace and reference from xran to o-ran";
reference "ORAN-WG4.M.0-v01.00";
}
grouping file-path-grouping {
description "Complete logical path of the file to upload/download
(no wildcard is allowed) ex : /o-RAN/log/syslog.1";
leaf local-logical-file-path {
type string;
mandatory true;
description "Local logical file path";
}
leaf remote-file-path {
type string;
mandatory true;
description "URI specifying the remote-file-path on O-DU/NMS.
Format:sftp://<username>@<host>[:port]/path";
}
}
grouping output-status-grouping {
description "Status grouping";
leaf status {
type enumeration {
enum SUCCESS {
description "";}
enum FAILURE {
description "";}
}
description "Operation status";
}
leaf reject-reason {
when "../status = 'FAILURE'";
type string;
description "";
}
}
grouping credential-information {
description "Type of authentication to use for SFTP upload or download.";
choice credentials {
case password {
container password {
presence true;
leaf password {
type string;
mandatory true;
description
"password needed for O-RU authentication.";
}
description
"password for O-RU authentication method in use";
}
container server {
list keys {
key algorithm;
ordered-by user;
uses ct:public-key-grouping;
description
"List of allowed algorithms with its keys";
}
description
"Key for sFTP server authentication";
}
}
case certificate {
container certificate {
presence true;
description
"certificate authentication method in use";
}
}
description "";
}
}
grouping retrieve-input {
description "Grouping for information retrieval RPC input";
leaf logical-path {
type string;
mandatory true;
description "O-RAN unit of which the files are to be listed.
ex : O-RAN/log, o-RAN/PM, O-RAN/transceiver";
}
leaf file-name-filter {
type string;
description "Filter which are to be applied on the result list of file names (* is allowed as wild-card).";
}
}
grouping retrieve-output {
description "Grouping for information retrieval RPC output";
uses output-status-grouping;
leaf-list file-list {
when "../status = 'SUCCESS'";
type string;
description "List of files in the unit with the filter applied.";
}
}
// RPCs
rpc file-upload {
description "File upload over SFTP from equipment to NETCONF client";
input {
uses file-path-grouping;
uses credential-information;
}
output {
uses output-status-grouping;
}
}
rpc retrieve-file-list {
description "List all the files in the logical O-RAN unit (* is allowed as wild-card).";
input {
uses retrieve-input;
}
output {
uses retrieve-output;
}
}
notification file-upload-notification {
uses file-path-grouping;
uses output-status-grouping;
description "";
}
rpc file-download {
description
"Management plane triggered to generate the download file of O-RU.";
input {
uses file-path-grouping;
uses credential-information;
}
output {
uses output-status-grouping;
}
}
notification file-download-event {
uses file-path-grouping;
uses output-status-grouping;
description "";
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1693,7 +1693,6 @@ module o-ran-uplane-conf {
uses cf:compression-details;
leaf fs-offset {
if-feature cf:CONFIGURABLE-FS-OFFSET;
type uint8;
default 0;
description

View File

@@ -35,6 +35,7 @@
#define ORAN_CONFIG_DU_ADDR "du_addr" // only needed for M-plane
#define ORAN_CONFIG_VLAN_TAG "vlan_tag" // only needed for M-plane
#define ORAN_CONFIG_RU_ADDR "ru_addr" // not needed if M-plane used
#define ORAN_CONFIG_RU_USERNAME "ru_username" // only needed for M-plane
#define ORAN_CONFIG_RU_IP_ADDR "ru_ip_addr" // only needed for M-plane
#define ORAN_CONFIG_MTU "mtu" // not needed if M-plane used
#define ORAN_CONFIG_FILE_PREFIX "file_prefix"
@@ -56,6 +57,7 @@
{ORAN_CONFIG_DU_ADDR, "Ether addr of DU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_VLAN_TAG, "VLAN tag\n", PARAMFLAG_MANDATORY, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
{ORAN_CONFIG_RU_ADDR, "Ether addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_RU_USERNAME, "Username of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_RU_IP_ADDR, "IP addr of RU\n", PARAMFLAG_MANDATORY, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST, 0}, \
{ORAN_CONFIG_MTU, "MTU of Eth interface\n", 0, .uptr=NULL, .defuintval=1500, TYPE_UINT, 0}, \
{ORAN_CONFIG_FILE_PREFIX, "DPDK file-prefix\n", 0, .strptr=NULL, .defstrval="wls_0", TYPE_STRING, 0}, \
@@ -82,6 +84,7 @@
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s3a = { config_checkstr_assign_integer, \
{"PA", "VA"}, {0, 1}, 2} }, \
{ .s5 = { NULL } }, \

View File

@@ -330,7 +330,7 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
AssertFatal(false, "[MPLANE] Stopping M-plane.\n");
}
while (true) {
/* while (true) {
sleep(1);
bool all_rus_ready = true;
for (int i = 0; i < ru_session_list.num_rus; i++) {
@@ -338,6 +338,11 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
if (!ru_ready[i] && ru_session->ru_notif.config_change && ru_session->ru_notif.rx_carrier_state && ru_session->ru_notif.tx_carrier_state) {
MP_LOG_I("RU \"%s\" is now ready.\n", ru_session->ru_ip_add);
ru_ready[i] = true;
if (!ru_session->pm_stats.start_up_timing) {
success = pm_conf(ru_session, "true");
if (success)
MP_LOG_I("Sucessfully activated PM after start-up procedure for RU \"%s\".\n", ru_session->ru_ip_add);
}
} else {
all_rus_ready = false;
break;
@@ -346,7 +351,7 @@ __attribute__((__visibility__("default"))) int transport_init(openair0_device *d
if (all_rus_ready) {
break;
}
}
} */
eth->mplane_priv = (void *)&ru_session_list;

View File

@@ -205,7 +205,7 @@ RUs = (
local_rf = "no";
nb_tx = 8;
nb_rx = 8;
att_tx = 0;
att_tx = 35;
att_rx = 0;
bands = [77];
max_pdschReferenceSignalPower = -27;
@@ -240,6 +240,7 @@ fhi_72 = {
du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa");
du_addr = ("00:11:22:33:44:66", "00:11:22:33:44:67", "00:11:22:33:44:68", "00:11:22:33:44:69");
vlan_tag = (5, 5, 6, 6);
ru_username = ("oranbenetel", "oranbenetel");
ru_ip_addr = ("192.168.80.5", "192.168.80.6");
fh_config = (
# RAN650 #1

View File

@@ -208,7 +208,7 @@ RUs = (
local_rf = "no";
nb_tx = 4;
nb_rx = 4;
att_tx = 0;
att_tx = 24;
att_rx = 0;
bands = [78];
max_pdschReferenceSignalPower = -27;
@@ -260,6 +260,7 @@ fhi_72 = {
du_key_pair = ("/home/eurecom/.ssh/id_rsa.pub", "/home/eurecom/.ssh/id_rsa");
du_addr = ("00:11:22:33:44:68","00:11:22:33:44:69");
vlan_tag = (11, 11);
ru_username = ("oranbenetel");
ru_ip_addr = ("192.168.80.10");
fh_config = ({
T1a_cp_dl = (419, 470);