Skip to content

MACsec/ MKA config and metric support in OTG model #408

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 144 commits into
base: master
Choose a base branch
from
Open

Conversation

sasubrata
Copy link
Contributor

@sasubrata sasubrata commented Feb 14, 2025

Issue #407

Redocly View:

config:
https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/open-traffic-generator/models/macsec/artifacts/openapi.yaml&nocors#tag/Configuration/operation/set_config

metric:
https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/open-traffic-generator/models/macsec/artifacts/openapi.yaml&nocors#tag/Monitor/operation/get_metrics

Objectives:

Add MACsec and MKA model in OTG.

New fields for config:
devices: macsec
devices: mka

New fields for metric:
get_metrics: macsec
get_metrics: mka

Sample Code Snippet (MACsec with MKA):

import pytest
import time

def test_stateless_encryption_with_mka(api, b2b_raw_config, utils):
"""
Test for the macsec configuration
"""
config = b2b_raw_config
api.set_config(api.config())
config.flows.clear()
#ixnetwork = api._ixnetwork

p1, p2 = config.ports
d1, d2 = config.devices.device(name="enc_only_macsec1").device(name="enc_only_macsec2")

eth1, eth2 = d1.ethernets.add(), d2.ethernets.add()
eth1.connection.port_name, eth2.connection.port_name = p1.name, p2.name
eth1.mac, eth2.mac = "00:00:00:00:00:11", "00:00:00:00:00:22"
ip1, ip2 = eth1.ipv4_addresses.add(), eth2.ipv4_addresses.add()
eth1.name, eth2.name = "eth1", "eth2"
ip1.name, ip2.name = "ip1", "ip2"

####################
# MKA
####################
mka1, mka2 = d1.mka, d2.mka
mka1_int, mka2_int = mka1.ethernet_interfaces.add(), mka2.ethernet_interfaces.add()
mka1_int.eth_name, mka2_int.eth_name = eth1.name, eth2.name
kay1, kay2 = mka1_int.kay, mka2_int.kay
kay1.name, kay2.name = "mka1", "mka2"

# Basic properties
kay1.basic.key_derivation_function = kay2.basic.key_derivation_function = "aes_cmac_128"

# Key source: PSK
kay1_key_src, kay2_key_src = kay1.basic.key_source, kay2.basic.key_source
kay1_key_src.choice = kay2_key_src.choice = "psk"
kay1_psk_chain, kay2_psk_chain = kay1_key_src.psks, kay2_key_src.psks

# PSK 1
kay1_psk1, kay2_psk1 = kay1_psk_chain.add(), kay2_psk_chain.add()
kay1_psk1.cak_name = kay2_psk1.cak_name = "0xF123456789ABCDEF0123456789ABCDEFF123456789ABCDEF0123456789ABCD01"
kay1_psk1.cak_value = kay2_psk1.cak_value = "0xF123456789ABCDEF0123456789ABCD01"
kay1_psk1.start_time = kay2_psk1.start_time = "00:00"
kay1_psk1.end_time = kay2_psk1.end_time = "00:00"

# PSK 2
kay1_psk2, kay2_psk2 = kay1_psk_chain.add(), kay2_psk_chain.add()
kay1_psk2.cak_name = kay2_psk2.cak_name = "0xF123456789ABCDEF0123456789ABCDEFF123456789ABCDEF0123456789ABCD02"
kay1_psk2.cak_value = kay2_psk2.cak_value = "0xF123456789ABCDEF0123456789ABCD02"
kay1_psk2.start_time = kay2_psk2.start_time = "00:00"
kay1_psk2.end_time = kay2_psk2.end_time = "00:00"

# Rekey mode
kay1_rekey_mode, kay2_rekey_mode = kay1.basic.rekey_mode, kay2.basic.rekey_mode
kay1_rekey_mode.choice = kay2_rekey_mode.choice = "dont_rekey"
#kay1_rekey_mode.choice = kay2_rekey_mode.choice = "timer_based"
kay1_rekey_timer_based, kay2_rekey_timer_based = kay1_rekey_mode.timer_based, kay2_rekey_mode.timer_based
kay1_rekey_timer_based.choice = kay2_rekey_timer_based.choice = "fixed_count"
kay1_rekey_timer_based.fixed_count = kay2_rekey_timer_based.fixed_count = 20
kay1_rekey_timer_based.interval = kay2_rekey_timer_based.interval = 200

# Remaining basic properties autofilled

# Tx SC
kay1_txsc1, kay2_txsc1 = kay1.txscs.add(), kay2.txscs.add() 
kay1_txsc1.name, kay2_txsc1.name = "txsc1", "txsc2"
kay1_txsc1.system_id, kay2_txsc1.system_id = eth1.mac, eth2.mac 
# Remaining Tx SC settings autofilled

####################
# MACsec
####################
macsec1, macsec2 = d1.macsec, d2.macsec
macsec1_int, macsec2_int = macsec1.ethernet_interfaces.add(), macsec2.ethernet_interfaces.add()
macsec1_int.eth_name, macsec2_int.eth_name = eth1.name, eth2.name
secy1, secy2 = macsec1_int.secy, macsec2_int.secy
secy1.name, secy2.name = "macsec1", "macsec2"

# Crypto engine
secy1.crypto_engine.choice = secy2.crypto_engine.choice = "stateless_encryption_only" 
secy1.crypto_engine.stateless_encryption_only.tx_pn.choice = "incrementing_pn"

####################
# Traffic
####################
# Gratuitous ARP is sent so that DUT can learn our IP. Grat ARP source/destination are local address
# DUT MAC needs to be configured manually stateless encyption only engine cannot decrypt any packet including DUT ARP
ip1.address = "10.1.1.1"
ip2.address = "10.1.1.2"

ip1.prefix = 24
ip2.prefix = 24

ip1.gateway = ip2.address
ip2.gateway = ip1.address

ip1.gateway_mac.choice = "value"
ip1.gateway_mac.value = eth2.mac

ip2.gateway_mac.choice = "value"
ip2.gateway_mac.value = eth1.mac

#traffic
f1 = config.flows.flow(name="f1")[-1]
f1.tx_rx.device.tx_names = [secy1.name]
f1.tx_rx.device.rx_names = [secy2.name]
f1.packet.ethernet()
f1.rate.pps = 10

utils.start_traffic(api, config)

####################
# MACsec stats
####################
print("Sleeping for 30 secoonds: start")
time.sleep(30)
print("Sleeping for 30 secoonds: end")
utils.wait_for(
    lambda: results_macsec_ok(api), "stats to be as expected", timeout_seconds=10
)

enums = [
    "out_pkts_protected",
    "out_pkts_encrypted",
    "in_pkts_ok",
    "in_pkts_bad",
    "in_pkts_bad_tag",
    "in_pkts_late",
    "in_pkts_no_sci",
    "in_pkts_not_using_sa",
    "in_pkts_not_valid",
    "in_pkts_unknown_sci",
    "in_pkts_unused_sa",
    "in_pkts_invalid",
    "in_pkts_untagged",
    "out_octets_protected",
    "out_octets_encrypted",
    "in_octets_validated",
    "in_octets_decrypted",
]
expected_results = {
    "enc_only_macsec1": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    "enc_only_macsec2": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
}
req = api.metrics_request()
req.macsec.secy_names = ["enc_only_macsec1"]
results = api.get_metrics(req)
assert len(results.macsec_metrics) == 1
assert results.macsec_metrics[0].name == "enc_only_macsec1"
print(f"MACsec Result : enc_only_macsec1")
for macsec_res in results.macsec_metrics:
    for i, enum in enumerate(enums):
        val = expected_results[macsec_res.name][i]
        if "session_state" in enum:
            assert getattr(macsec_res, enum) == val
        else:
            assert getattr(macsec_res, enum) >= val
        print(f"{enum} : {getattr(macsec_res, enum)}")

req = api.metrics_request()
req.macsec.secy_names = ["enc_only_macsec2"]
results = api.get_metrics(req)

assert len(results.macsec_metrics) == 1
assert results.macsec_metrics[0].name == "enc_only_macsec2"
print(f"MACsec Result : enc_only_macsec2")
for macsec_res in results.macsec_metrics:
    for i, enum in enumerate(enums):
        val = expected_results[macsec_res.name][i]
        if "session_state" in enum:
            assert getattr(macsec_res, enum) == val
        else:
            assert getattr(macsec_res, enum) >= val
        print(f"{enum} : {getattr(macsec_res, enum)}")

####################
# MKA stats
####################
utils.wait_for(
    lambda: results_mka_ok(api), "stats to be as expected", timeout_seconds=10
)
enums = [
    "mkpdu_tx",
    "mkpdu_rx",
    "live_peer_count",
    "potential_peer_count",
    "latest_key_tx_peer_count",
    "latest_key_rx_peer_count",
    "malformed_mkpdu",
    "icv_mismatch",
]
expected_results = {
    "enc_only_macsec1": [0, 0, 0, 0, 0, 0, 0, 0],
    "enc_only_macsec2": [0, 0, 0, 0, 0, 0, 0, 0],
}
req = api.metrics_request()
req.mka.kay_names = ["enc_only_macsec1"]
results = api.get_metrics(req)
assert len(results.mka_metrics) == 1
assert results.mka_metrics[0].name == "enc_only_macsec1"
print(f"MKA Result : enc_only_macsec1")
for mka_res in results.mka_metrics:
    for i, enum in enumerate(enums):
        val = expected_results[mka_res.name][i]
        if "session_state" in enum:
            assert getattr(mka_res, enum) == val
        else:
            assert getattr(mka_res, enum) >= val
        print(f"{enum} : {getattr(mka_res, enum)}")

req = api.metrics_request()
req.mka.kay_names = ["enc_only_macsec2"]
results = api.get_metrics(req)
assert len(results.mka_metrics) == 1
assert results.mka_metrics[0].name == "enc_only_macsec2"
print(f"MKA Result : enc_only_macsec2")
for mka_res in results.mka_metrics:
    for i, enum in enumerate(enums):
        val = expected_results[mka_res.name][i]
        if "session_state" in enum:
            assert getattr(mka_res, enum) == val
        else:
            assert getattr(mka_res, enum) >= val
        print(f"{enum} : {getattr(mka_res, enum)}")

utils.stop_traffic(api, config)

def results_macsec_ok(api):
#req = api.metrics_request()
#req.macsec.column_names = ["session_state"]
#results = api.get_metrics(req)
ok = []
#for r in results.macsec_metrics:
# ok.append(r.session_state == "up")
return all(ok)

def results_mka_ok(api):
req = api.metrics_request()
req.mka.column_names = ["session_state"]
results = api.get_metrics(req)
ok = []
for r in results.mka_metrics:
ok.append(r.session_state == "up")
return all(ok)

if name == "main":
pytest.main(["-vv", "-s", file])

Sample Code Snippet (MACsec with static key):

def test_stateless_encryption(api, b2b_raw_config, utils):
"""
Test for the macsec configuration
"""
config = b2b_raw_config
api.set_config(api.config())
config.flows.clear()
#ixnetwork = api._ixnetwork

p1, p2 = config.ports
d1, d2 = config.devices.device(name="enc_only_macsec1").device(name="enc_only_macsec2")

eth1, eth2 = d1.ethernets.add(), d2.ethernets.add()
eth1.connection.port_name, eth2.connection.port_name = p1.name, p2.name
eth1.mac, eth2.mac = "00:00:00:00:00:11", "00:00:00:00:00:22"
ip1, ip2 = eth1.ipv4_addresses.add(), eth2.ipv4_addresses.add()
eth1.name, eth2.name = "eth1", "eth2"
ip1.name, ip2.name = "ip1", "ip2"

macsec1, macsec2 = d1.macsec, d2.macsec
macsec1_int, macsec2_int = macsec1.ethernet_interfaces.add(), macsec2.ethernet_interfaces.add()
macsec1_int.eth_name, macsec2_int.eth_name = eth1.name, eth2.name
secy1, secy2 = macsec1_int.secy, macsec2_int.secy
secy1.name, secy2.name = "macsec1", "macsec2"

# crypto_engine
secy1.crypto_engine.choice = secy2.crypto_engine.choice = "stateless_encryption_only" 
secy1.crypto_engine.stateless_encryption_only.tx_pn.choice = "incrementing_pn"

# Static key
secy1_sk, secy2_sk = secy1.static_key, secy2.static_key
secy1_sk.cipher_suite = secy2_sk.cipher_suite = "gcm_aes_128"

# Tx
secy1_tx, secy2_tx = secy1.tx, secy2.tx
secy1_txsc1, secy2_txsc1 = secy1_tx.scs.add(), secy2_tx.scs.add()

# Tx SC end station
secy1_txsc1.end_station = secy2_txsc1.end_station = True

# Tx key
secy1_txsc1.static_key.sak_pool.name, secy2_txsc1.static_key.sak_pool.name = "macsec1_tx_sakpool", "macsec2_tx_sakpool"
secy1_tx_sak1, secy2_tx_sak1 = secy1_txsc1.static_key.sak_pool.saks.add(), secy2_txsc1.static_key.sak_pool.saks.add()
#secy1_tx_sak1.sak = secy2_tx_sak1.sak = "0xF123456789ABCDEF0123456789ABCDEF"
secy1_tx_sak1.sak = secy2_tx_sak1.sak = "f123456789abcdef0123456789abcdef"

# Remaining Tx SC settings autofilled

# Rx
secy1_rx, secy2_rx = secy1.rx, secy2.rx
secy1_rxsc1, secy2_rxsc1 = secy1.rx.static_key.scs.add(), secy2.rx.static_key.scs.add()

# Rx SC
secy1_rxsc1.dut_system_id =  eth2.mac
secy2_rxsc1.dut_system_id =  eth1.mac

# Rx key
secy1_rxsc1.sak_pool.name, secy2_rxsc1.sak_pool.name = "macsec1_rx_sakpool", "macsec2_rx_sakpool"
secy1_rx_sak1, secy2_rx_sak1 = secy1_rxsc1.sak_pool.saks.add(), secy2_rxsc1.sak_pool.saks.add()
#secy1_rx_sak1.sak = secy2_rx_sak1.sak = "0xF123456789ABCDEF0123456789ABCDEF"
secy1_rx_sak1.sak = secy2_rx_sak1.sak = "f123456789abcdef0123456789abcdef"

# Remaining Rx SC settings autofilled

# Gratuitous ARP is sent so that DUT can learn our IP. Grat ARP source/destination are local address
# DUT MAC needs to be configured manually stateless encyption only engine cannot decrypt any packet including DUT ARP
ip1.address = "10.1.1.1"
ip2.address = "10.1.1.2"

ip1.prefix = 24
ip2.prefix = 24

ip1.gateway = ip2.address
ip2.gateway = ip1.address

ip1.gateway_mac.choice = "value"
ip1.gateway_mac.value = eth2.mac

ip2.gateway_mac.choice = "value"
ip2.gateway_mac.value = eth1.mac

#traffic
f1 = config.flows.flow(name="f1")[-1]
f1.tx_rx.device.tx_names = [secy1.name]
f1.tx_rx.device.rx_names = [secy2.name]
f1.packet.ethernet()

utils.start_traffic(api, config)
print("Sleeping for 20 secoonds: start")
time.sleep(20)
print("Sleeping for 20 secoonds: end")
utils.wait_for(
    lambda: results_ok(api), "stats to be as expected", timeout_seconds=10
)
enums = [
    "out_pkts_protected",
    "out_pkts_encrypted",
    "in_pkts_ok",
    "in_pkts_bad",
    "in_pkts_bad_tag",
    "in_pkts_late",
    "in_pkts_no_sci",
    "in_pkts_not_using_sa",
    "in_pkts_not_valid",
    "in_pkts_unknown_sci",
    "in_pkts_unused_sa",
    "in_pkts_invalid",
    "in_pkts_untagged",
    "out_octets_protected",
    "out_octets_encrypted",
    "in_octets_validated",
    "in_octets_decrypted",
]
expected_results = {
    "enc_only_macsec1": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    "enc_only_macsec2": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
}
req = api.metrics_request()
req.macsec.secy_names = ["enc_only_macsec1"]
results = api.get_metrics(req)
assert len(results.macsec_metrics) == 1
assert results.macsec_metrics[0].name == "enc_only_macsec1"
print(f"MACsec Result : enc_only_macsec1")
for macsec_res in results.macsec_metrics:
    for i, enum in enumerate(enums):
        val = expected_results[macsec_res.name][i]
        if "session_state" in enum:
            assert getattr(macsec_res, enum) == val
        else:
            assert getattr(macsec_res, enum) >= val
        print(f"{enum} : {getattr(macsec_res, enum)}")

req = api.metrics_request()
req.macsec.secy_names = ["enc_only_macsec2"]
results = api.get_metrics(req)

assert len(results.macsec_metrics) == 1
assert results.macsec_metrics[0].name == "enc_only_macsec2"
print(f"MACsec Result : enc_only_macsec2")
for macsec_res in results.macsec_metrics:
    for i, enum in enumerate(enums):
        val = expected_results[macsec_res.name][i]
        if "session_state" in enum:
            assert getattr(macsec_res, enum) == val
        else:
            assert getattr(macsec_res, enum) >= val
        print(f"{enum} : {getattr(macsec_res, enum)}")

utils.stop_traffic(api, config)

def results_ok(api):
#req = api.metrics_request()
#req.macsec.column_names = ["session_state"]
#results = api.get_metrics(req)
ok = []
#for r in results.macsec_metrics:
# ok.append(r.session_state == "up")
return all(ok)

if name == "main":
pytest.main(["-vv", "-s", file])

sasubrata and others added 30 commits December 21, 2024 01:11
Copy link
Contributor

@apratimmukherjee apratimmukherjee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial review.

Fixed Tx XPN. 8 bytes PN with which all packets will be sent out.
type: integer
minimum: 1
default: 0x0000000000000006
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this just be 6 . Is pn and xpn both always needed and set ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, numerically 6 is default - but it should be input in HEX format for XPN because it is easy to think 64 bytes in hex.

Let me try with:

      type: string
      format: hex
      minLength: 1
      maxLength: 8
      minimum: 1
      default: "0x0000000000000006"

More details:

Either PN or XPN is used at a time depending on the cipher dynamically selected by MKA protocol. So DUT is a factor here. However for static key, test port knows it.

In almost all cases, MKA will be used. Chip vendors use static key to test their hardware - there MKA may not be available and static key is used.

Some more details:

PN - 4 bytes packet number used to determine initialization vector (IV) for basic ciphers (A).
XPN - 8 bytes packet numbed used for the same for extended packet number (XPN) based ciphers (B).

Now for both the cipher types (either set from from static key or MKA protocol), 4 bytes go in MACsec header in packet. For XPN ciphers, the most significant 4 bytes are tracked encryption and decryption end points.

first_xpn:
description: >-
The first XPN.
type: integer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you wish this to be uint64

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uint64 is a format of type integer. But that won't let XPN be input as HEX string - this is the requirement.

x-field-uid: 2
Macsec.CryptoEngine.StatefulEncryptionDecryption.HardwareAcceleration.InlineCrypto:
description: >-
Inline cryto engine settings.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

crypto ( or cryptographic ? )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost all documentations online write as "crypto engine" E.g. DPDK also uses the same name here: https://core.dpdk.org/supported/cryptos/

description: |-
Key start time in HH:MM.
type: string
default: "00:00"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think much better to have a class with hours (0-23 ? ) and minutes ( 0-59) as specific fields . Dont want user to have to create correctly formatted strings in input.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User can input any value e.g. 27:80 (I verified this from IxNetwork). This time is relative to test start time i.e. port assignment time as per clock time known from chassis.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this requires user to form the string. This is not type checked as well by model. So not preferable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of now MKA in snappi-ixnetwork can be modified to validate "HH:MM" of this MKA field. However I do not know how to add a new format e.g. "time_hh_mm" in model.

format: ipv4 - is an example but I could not find where it is defined.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not asking to add a ne format .. I am asking to allow user to provide as:
start_time.hour = 0 to 23
start_time.minute = 0 to 59
instead of having to create a type unchecked string like 01:59

Copy link
Contributor

@SuryyaKrJana SuryyaKrJana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started to review, however found inadequate information of the fields. Requested to look at any recent protocol say OSPFv2.

Copy link
Contributor Author

@sasubrata sasubrata left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have responded to review comments. Also pushed commits wherever rework was necessary.

Please take a look and resolve remaining open conversations/ comment.

Copy link
Contributor

@apratimmukherjee apratimmukherjee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some breaking changes must be fixed. Some need a discussion with hopefully few people present who can take a call on Macsec/MKA modelling to get a conclusion.

description: |-
Key start time in HH:MM.
type: string
default: "00:00"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this requires user to form the string. This is not type checked as well by model. So not preferable.

@@ -123,8 +133,12 @@ components:
x-field-uid: 13
ospfv2_metrics:
x-field-uid: 14
convergence_metrics:
macsec_metrics:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking change. Need to fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to keep convergence ( older field) as is and add your new stuff at the end with higher ids . Else the break is still there .

12 bytes salt used in case of XPN cipher suites.
type: string
format: hex
minLength: 12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will make it 6 bytes and 12 characters. Not what you want from description.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E.g. salt "000000000000000000000001" comprises of 12 bytes - each byte is a two digit hex number "0x00".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is a preferred description?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not about description . Since maxLength is 12, user can enter max 6 bytes = 6x2 = 12 characters . not 12 bytes = 12x2 = needed 24 as max.
And probably min if you want to enforce user needs to always enter the whole thing, though min probably can be 0 or 1 also if just '6' is okay as input , not sure why you want user to enter as 0000000000000...6 instead of just 6

x-constraint:
- '/components/schemas/Device.Ethernet/properties/name'
x-field-uid: 1
secy:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would like to discuss this with some you and some other MacSec stakeholders if possible. Need to also discuss if external ( to Keysight ) is planned for this model or has been done. Ideally prefer validations to be built in into model where possible not allowing users to make mistakes at compile time itself. Not sure on this. Need to also see what are the number of common parameters you describe.

12 bytes salt used in case of XPN cipher suites.
type: string
format: hex
minLength: 12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not about description . Since maxLength is 12, user can enter max 6 bytes = 6x2 = 12 characters . not 12 bytes = 12x2 = needed 24 as max.
And probably min if you want to enforce user needs to always enter the whole thing, though min probably can be 0 or 1 also if just '6' is okay as input , not sure why you want user to enter as 0000000000000...6 instead of just 6

description: |-
Key start time in HH:MM.
type: string
default: "00:00"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not asking to add a ne format .. I am asking to allow user to provide as:
start_time.hour = 0 to 23
start_time.minute = 0 to 59
instead of having to create a type unchecked string like 01:59

@@ -123,8 +133,12 @@ components:
x-field-uid: 13
ospfv2_metrics:
x-field-uid: 14
convergence_metrics:
macsec_metrics:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to keep convergence ( older field) as is and add your new stuff at the end with higher ids . Else the break is still there .

apratimmukherjee pushed a commit that referenced this pull request Mar 7, 2025
…ments from PR #408 (on macsec branch) (#412)

* MACsec OTG model reworked based on review of model from macsec branch

* Update auto generated content

* More rework based on review comments

* Add missing file

* Update auto generated content

* Fix secure channels

* Update auto generated content

* Fix secure channels

* Update auto generated content

* Fix secure channels

* Update auto generated content

* Fix secure channels

* Update auto generated content

* Correct min and max length of hex fields

* Update auto generated content

* Update key time descriptions

* Update auto generated content

* Add MACsec and MKA metrics

* Update auto generated content

* More rework based on review

* Update auto generated content

* Split time offset and key chain start time into subfields

* Update auto generated content

* Fix time fields

* Update auto generated content

* Fix time fields

* Update auto generated content

* Add integer format to time subfields

* Change class name from Macsec to SecureEntity to match field name secure_entity

* Update auto generated content

* Change description of psk_chain_start_time

* Update auto generated content

* Try to set psk chain start time description from the field description itself

* Update auto generated content

* Move re-shared key(PSK) chain start time description

* Update auto generated content

* Add lifetime validity information

* Update auto generated content

* add required fields

* Update auto generated content

* Minutes field max limit set to 59

* Remove encrypt_decrypt engine type from the model as of now as it is not implemented/ tested yet.

* Update auto generated content

* Some change in description to reflect previus change in redocly view

* Update auto generated content

---------

Co-authored-by: Github Actions Bot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants