Skip to content

Comments

Fix/issue 108#110

Merged
italovalcy merged 6 commits intomasterfrom
fix/issue_108
Dec 10, 2025
Merged

Fix/issue 108#110
italovalcy merged 6 commits intomasterfrom
fix/issue_108

Conversation

@italovalcy
Copy link

@italovalcy italovalcy commented Nov 26, 2025

Closes #108

Summary

See updated changelog file and/or add any other summarized helpful information for reviewers

Local Tests

Using the proposed changes we can now pack and unpack ActionsProperty, InstructionProperty and OxmProperty (expected byte strings here were copied from a Wireshark packet capture on a passive OVS connection to a Noviflow switch -- see screenshot below):

>>>
>>> from pyof.v0x04.common.flow_instructions import InstructionType, Instruction
... from pyof.v0x04.controller2switch.common import InstructionsProperty, TableFeaturePropType, InstructionId
... insts = [
...     InstructionType.OFPIT_GOTO_TABLE,
...     InstructionType.OFPIT_WRITE_METADATA,
...     InstructionType.OFPIT_WRITE_ACTIONS,
...     InstructionType.OFPIT_APPLY_ACTIONS,
...     InstructionType.OFPIT_CLEAR_ACTIONS,
...     InstructionType.OFPIT_METER,
... ]
... inst_ids = []
... for inst in insts:
...     inst_ids.append(InstructionId(instruction_type=inst))
...
... inst_prop = InstructionsProperty(property_type=TableFeaturePropType.OFPTFPT_INSTRUCTIONS, instruction_ids=inst_ids)
... inst_prop.pack()
...
b'\x00\x00\x00\x1c\x00\x01\x00\x04\x00\x02\x00\x04\x00\x03\x00\x04\x00\x04\x00\x04\x00\x05\x00\x04\x00\x06\x00\x04\x00\x00\x00\x00'
>>> expected = b"\x00\x00\x00\x1c\x00\x01\x00\x04\x00\x02\x00\x04\x00\x03\x00\x04\x00\x04\x00\x04\x00\x05\x00\x04\x00\x06\x00\
\x04\x00\x00\x00\x00"
...
... inst_prop.pack() == expected
...
True
>>> unpacked = InstructionsProperty()
... unpacked.unpack(inst_prop.pack())
...
>>> unpacked == inst_prop
...
True
>>>
>>>
>>> from pyof.v0x04.controller2switch.common import ActionId, ActionsProperty, TableFeaturePropType
...
... from pyof.v0x04.common.action import ActionType
...
... actions = [
...             ActionType.OFPAT_OUTPUT,
...             ActionType.OFPAT_COPY_TTL_OUT,
...             ActionType.OFPAT_COPY_TTL_IN,
...             ActionType.OFPAT_SET_MPLS_TTL,
...             ActionType.OFPAT_DEC_MPLS_TTL,
...             ActionType.OFPAT_PUSH_VLAN,
...             ActionType.OFPAT_POP_VLAN,
...             ActionType.OFPAT_PUSH_MPLS,
...             ActionType.OFPAT_POP_MPLS,
...             ActionType.OFPAT_SET_QUEUE,
...             ActionType.OFPAT_GROUP,
...             ActionType.OFPAT_SET_NW_TTL,
...             ActionType.OFPAT_DEC_NW_TTL,
...             ActionType.OFPAT_SET_FIELD,
...             ActionType.OFPAT_PUSH_PBB,
...             ActionType.OFPAT_POP_PBB,
...         ]
... action_ids = []
... for action in actions:
...     action_ids.append(ActionId(action_type=action))
...
... action_ids.append(ActionId(action_type=ActionType.OFPAT_EXPERIMENTER, length=8, exp_data=0xFF000002))
...
... action_prop = ActionsProperty(property_type=TableFeaturePropType.OFPTFPT_WRITE_ACTIONS, action_ids=action_ids)
...
... action_prop.pack()
...
b'\x00\x04\x00L\x00\x00\x00\x04\x00\x0b\x00\x04\x00\x0c\x00\x04\x00\x0f\x00\x04\x00\x10\x00\x04\x00\x11\x00\x04\x00\x12\x00\x04\x00\x13\x00\x04\x00\x14\x00\x04\x00\x15\x00\x04\x00\x16\x00\x04\x00\x17\x00\x04\x00\x18\x00\x04\x00\x19\x00\x04\x00\x1a\x00\x04\x00\x1b\x00\x04\xff\xff\x00\x08\xff\x00\x00\x02\x00\x00\x00\x00'
>>> expected_action = b"\x00\x04\x00\x4c\x00\x00\x00\x04\x00\x0b\x00\x04\x00\x0c\x00\x04\x00\x0f\x00\x04\x00\x10\x00\x04\x00\\
x11\x00\x04\x00\x12\x00\x04\x00\x13\x00\x04\x00\x14\x00\x04\x00\x15\x00\x04\x00\x16\x00\x04\x00\x17\x00\x04\x00\x18\x00\x04\x\
00\x19\x00\x04\x00\x1a\x00\x04\x00\x1b\x00\x04\xff\xff\x00\x08\xff\x00\x00\x02\x00\x00\x00\x00"
...
>>> action_prop.pack() == expected_action
...
True
>>> unpacked_action = ActionsProperty()
... unpacked_action.unpack(action_prop.pack())
...
>>>
>>> unpacked_action == action_prop
...
True
>>> from pyof.v0x04.common.flow_match import OxmOfbMatchField
... from pyof.v0x04.controller2switch.common import OxmId, OxmProperty, TableFeaturePropType
...
... oxms = [
...             OxmOfbMatchField.OFPXMT_OFB_IN_PORT,
...             OxmOfbMatchField.OFPXMT_OFB_ETH_DST,
...             OxmOfbMatchField.OFPXMT_OFB_ETH_SRC,
...             OxmOfbMatchField.OFPXMT_OFB_ETH_TYPE,
...             OxmOfbMatchField.OFPXMT_OFB_VLAN_VID,
...             OxmOfbMatchField.OFPXMT_OFB_VLAN_PCP,
...             OxmOfbMatchField.OFPXMT_OFB_IP_PROTO,
...             OxmOfbMatchField.OFPXMT_OFB_IPV4_SRC,
...             OxmOfbMatchField.OFPXMT_OFB_IPV4_DST,
...             OxmOfbMatchField.OFPXMT_OFB_TCP_SRC,
...             OxmOfbMatchField.OFPXMT_OFB_TCP_DST,
...             OxmOfbMatchField.OFPXMT_OFB_UDP_SRC,
...             OxmOfbMatchField.OFPXMT_OFB_UDP_DST,
...             OxmOfbMatchField.OFPXMT_OFB_SCTP_SRC,
...             OxmOfbMatchField.OFPXMT_OFB_SCTP_DST,
...         ]
...
... match_fields_size_mask = {
...             OxmOfbMatchField.OFPXMT_OFB_IN_PORT.value: (4, False),
...             OxmOfbMatchField.OFPXMT_OFB_ETH_TYPE.value: (2, False),
...             OxmOfbMatchField.OFPXMT_OFB_IP_PROTO.value: (1, False),
...             OxmOfbMatchField.OFPXMT_OFB_VLAN_VID.value: (2, True),
...             OxmOfbMatchField.OFPXMT_OFB_VLAN_PCP.value: (1, True),
...             OxmOfbMatchField.OFPXMT_OFB_ETH_SRC.value: (6, True),
...             OxmOfbMatchField.OFPXMT_OFB_ETH_DST.value: (6, True),
...             OxmOfbMatchField.OFPXMT_OFB_IPV4_SRC.value: (4, True),
...             OxmOfbMatchField.OFPXMT_OFB_IPV4_DST.value: (4, True),
...             OxmOfbMatchField.OFPXMT_OFB_IP_DSCP.value: (1, True),
...             OxmOfbMatchField.OFPXMT_OFB_TCP_SRC.value: (2, True),
...             OxmOfbMatchField.OFPXMT_OFB_TCP_DST.value: (2, True),
...             OxmOfbMatchField.OFPXMT_OFB_UDP_SRC.value: (2, True),
...             OxmOfbMatchField.OFPXMT_OFB_UDP_DST.value: (2, True),
...             OxmOfbMatchField.OFPXMT_OFB_ICMPV4_TYPE.value: (1, True),
...             OxmOfbMatchField.OFPXMT_OFB_IPV6_SRC.value: (16, True),
...             OxmOfbMatchField.OFPXMT_OFB_IPV6_DST.value: (16, True),
...             OxmOfbMatchField.OFPXMT_OFB_ICMPV6_TYPE.value: (1, True),
...             OxmOfbMatchField.OFPXMT_OFB_SCTP_SRC.value: (2, True),
...             OxmOfbMatchField.OFPXMT_OFB_SCTP_DST.value: (2, True),
...         }
... oxm_ids = []
... for oxm in oxms:
...     s, m = match_fields_size_mask[oxm.value]
...     oxm_ids.append(OxmId(oxm_field=oxm, oxm_hasmask=m, oxm_length=s))
...
... oxm_prop = OxmProperty(property_type=TableFeaturePropType.OFPTFPT_MATCH, oxm_ids=oxm_ids)
...
>>> expected_oxm = b"\x00\x08\x00\x40\x80\x00\x00\x04\x80\x00\x07\x06\x80\x00\x09\x06\x80\x00\x0a\x02\x80\x00\x0d\x02\x80\x00\
\x0f\x01\x80\x00\x14\x01\x80\x00\x17\x04\x80\x00\x19\x04\x80\x00\x1b\x02\x80\x00\x1d\x02\x80\x00\x1f\x02\x80\x00\x21\x02\x80\\
x00\x23\x02\x80\x00\x25\x02"
...
...
... oxm_prop.pack() == expected_oxm
...
True
>>> unpacked = OxmProperty()
... unpacked.unpack(oxm_prop.pack())
...
>>> unpacked == oxm_prop
True
>>>
Screenshot 2025-11-26 at 18 08 08

End-to-End Tests

Tests were executed with this branch covering all the changes for recent PRs (#105, #106, #107, #109, #110):

> kubectl --kubeconfig $KUBECONFIG exec -it deployment/kytos-regression-tests --container kytos -- python3 -m pip install https://github.com/kytos-ng/python-openflow/archive/fix/issue_108.zip
Collecting https://github.com/kytos-ng/python-openflow/archive/fix/issue_108.zip
  Downloading https://github.com/kytos-ng/python-openflow/archive/fix/issue_108.zip
     | 250.4 kB 2.2 MB/s 0:00:00
  Preparing metadata (setup.py) ... done
Building wheels for collected packages: python-openflow
  Building wheel for python-openflow (setup.py) ... done
  Created wheel for python-openflow: filename=python_openflow-2025.2.0rc1-py3-none-any.whl size=200958 sha256=97d618d9b7e1dd00413fca0b277ef1d36670b3199eb996ed67be3bf10fe843f8
  Stored in directory: /tmp/pip-ephem-wheel-cache-ks8k0_be/wheels/4e/fe/eb/5c5cce0ad06271e2694cfd2d0e5d0de10284eaa96f5c3984c8
Successfully built python-openflow
Installing collected packages: python-openflow
  Attempting uninstall: python-openflow
    Found existing installation: python-openflow 2025.1.0
    Uninstalling python-openflow-2025.1.0:
      Successfully uninstalled python-openflow-2025.1.0
Successfully installed python-openflow-2025.2.0rc1
[notice] A new release of pip is available: 24.0 -> 25.3
[notice] To update, run: python3 -m pip install --upgrade pip
> kubectl --kubeconfig $KUBECONFIG exec -it deployment/kytos-regression-tests --container kytos -- python3 -m pip show python-openflow
Name: python-openflow
Version: 2025.2.0rc1
Summary: Library to parse and generate OpenFlow messages
Home-page: http://github.com/kytos/python-openflow
Author: Kytos Team
Author-email: devel@lists.kytos.io
License: MIT
Location: /usr/local/lib/python3.11/dist-packages
Requires:
Required-by: kytos

...

============================= test session starts ==============================
platform linux -- Python 3.11.2, pytest-8.4.2, pluggy-1.6.0
rootdir: /kytos-end-to-end-tests
configfile: pytest.ini
plugins: timeout-2.2.0, asyncio-1.1.0, rerunfailures-13.0, anyio-4.3.0
asyncio: mode=Mode.AUTO, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 300 items

tests/test_e2e_01_kytos_startup.py ..                                    [  0%]
tests/test_e2e_05_topology.py ...................                        [  7%]
tests/test_e2e_06_topology.py ....                                       [  8%]
tests/test_e2e_10_mef_eline.py ..........ss.....x....................... [ 22%]
.                                                                        [ 22%]
tests/test_e2e_11_mef_eline.py ........                                  [ 25%]
tests/test_e2e_12_mef_eline.py .....Xx.                                  [ 27%]
tests/test_e2e_13_mef_eline.py ....Xs.s.....Xs.s.XXxX.xxxx..X........... [ 41%]
.                                                                        [ 41%]
tests/test_e2e_14_mef_eline.py ......                                    [ 43%]
tests/test_e2e_15_mef_eline.py ......                                    [ 45%]
tests/test_e2e_16_mef_eline.py ..                                        [ 46%]
tests/test_e2e_17_mef_eline.py .....                                     [ 48%]
tests/test_e2e_18_mef_eline.py .....                                     [ 49%]
tests/test_e2e_20_flow_manager.py ............................           [ 59%]
tests/test_e2e_21_flow_manager.py ...                                    [ 60%]
tests/test_e2e_22_flow_manager.py ...............                        [ 65%]
tests/test_e2e_23_flow_manager.py ..............                         [ 69%]
tests/test_e2e_30_of_lldp.py ....                                        [ 71%]
tests/test_e2e_31_of_lldp.py ....                                        [ 72%]
tests/test_e2e_32_of_lldp.py ...                                         [ 73%]
tests/test_e2e_40_sdntrace.py ................                           [ 78%]
tests/test_e2e_41_kytos_auth.py ........                                 [ 81%]
tests/test_e2e_42_sdntrace.py ..                                         [ 82%]
tests/test_e2e_50_maintenance.py ...............................         [ 92%]
tests/test_e2e_60_of_multi_table.py .....                                [ 94%]
tests/test_e2e_70_kytos_stats.py .........                               [ 97%]
tests/test_e2e_80_pathfinder.py ss......                                 [ 99%]
tests/test_e2e_90_kafka_events.py .                                      [100%]
------------------------------- start/stop times -------------------------------
= 278 passed, 8 skipped, 7 xfailed, 7 xpassed, 1359 warnings in 13961.35s (3:52:41) =

…le properties instead of reusing the OxmTLV, ActionHeader and Instruction that were giving problems when packing/unpacking
@italovalcy italovalcy requested a review from a team as a code owner November 26, 2025 21:11
Copy link
Member

@viniarck viniarck left a comment

Choose a reason for hiding this comment

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

Nicely done @italovalcy. LGTM.

Copy link
Member

@viniarck viniarck left a comment

Choose a reason for hiding this comment

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

The latest pushed commits look good to me too

Base automatically changed from fix/issue_102 to master December 10, 2025 16:14
@italovalcy italovalcy merged commit f80aef3 into master Dec 10, 2025
1 check passed
@italovalcy italovalcy deleted the fix/issue_108 branch December 10, 2025 16:48
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.

UnpackException while unpacking Table Feature Properties objects

2 participants