diff --git a/pyof/v0x01/controller2switch/packet_out.py b/pyof/v0x01/controller2switch/packet_out.py
index 78cb669..e7c9965 100644
--- a/pyof/v0x01/controller2switch/packet_out.py
+++ b/pyof/v0x01/controller2switch/packet_out.py
@@ -7,12 +7,16 @@ uses the OFPT_PACKET_OUT message"""
 
 # Local source tree imports
 from pyof.v0x01.common import header as of_header
+from pyof.v0x01.common.phy_port import Port
 from pyof.v0x01.controller2switch import common
 from pyof.v0x01.foundation import base
 from pyof.v0x01.foundation import basic_types
+from pyof.v0x01.foundation.exceptions import ValidationError
 
 # Classes
 
+#: in_port valid virtual port values, for validation
+_VIRT_IN_PORTS = (Port.OFPP_LOCAL, Port.OFPP_CONTROLLER, Port.OFPP_NONE)
 
 class PacketOut(base.GenericMessage):
     """
@@ -47,3 +51,25 @@ class PacketOut(base.GenericMessage):
         self.actions_len = actions_len
         self.actions = [] if actions is None else actions
         self.data = data
+
+    def validate(self):
+        if not super().is_valid():
+            raise ValidationError()
+        self._validate_in_port()
+
+    def is_valid(self):
+        try:
+            self.validate()
+            return True
+        except ValidationError:
+            return False
+
+    def _validate_in_port(self):
+        port = self.in_port
+        valid = True
+        if isinstance(port, int) and (port < 1 or port >= Port.OFPP_MAX.value):
+            valid = False
+        elif isinstance(port, Port) and port not in _VIRT_IN_PORTS:
+            valid = False
+        if not valid:
+            raise ValidationError('{} is not a valid input port.'.format(port))
diff --git a/pyof/v0x01/foundation/exceptions.py b/pyof/v0x01/foundation/exceptions.py
index 0dab2cd..13e9296 100644
--- a/pyof/v0x01/foundation/exceptions.py
+++ b/pyof/v0x01/foundation/exceptions.py
@@ -1,6 +1,11 @@
 """Exceptions defined on this Library"""
 
 
+class ValidationError(Exception):
+    """Can be used directly or inherited by specific validation errors."""
+    pass
+
+
 class MethodNotImplemented(Exception):
     """Exception to be raised when a method is not implemented"""
     def __init__(self, message=None):
@@ -33,44 +38,11 @@ class WrongListItemType(Exception):
         return message
 
 
-class PADHasNoValue(Exception):
-    """Exception raised when user tries to set a value on a PAD attribute"""
-    def __str__(self):
-        return "You can't set a value on a PAD attribute"
-
-
-class AttributeTypeError(Exception):
-    """Error raise when the attribute is not of the expected type
-    defined on the class definition"""
-
-    def __init__(self, item, item_class, expected_class):
-        super().__init__()
-        self.item = item
-        self.item_class = item_class
-        self.expected_class = expected_class
-
-    def __str__(self):
-        msg = "Unexpected value '{}' ".format(str(self.item))
-        msg += "with class '{}' ".format(str(self.item_class))
-        msg += "and expected class '{}'".format(str(self.expected_class))
-        return msg
-
-
 class NotBinaryData(Exception):
     """Error raised when the content of a BinaryData attribute is not binary"""
     def __str__(self):
         return "The content of this variable needs to be binary data"
 
 
-class ValidationError(Exception):
-    """Error on validate message or struct"""
-    def __init__(self, msg="Error on validate message"):
-        super().__init__()
-        self.msg = msg
-
-    def __str__(self):
-        return self.msg
-
-
 class UnpackException(Exception):
     pass

Check  1.0.1 and 1.0.2 compliance
diff --git a/tests/v0x01/test_controller2switch/test_packet_out.py b/tests/v0x01/test_controller2switch/test_packet_out.py
index 38dfd5a..4130c77 100644
--- a/tests/v0x01/test_controller2switch/test_packet_out.py
+++ b/tests/v0x01/test_controller2switch/test_packet_out.py
@@ -1,11 +1,12 @@
 import unittest
 
 from pyof.v0x01.common import phy_port
+from pyof.v0x01.common.phy_port import Port
 from pyof.v0x01.controller2switch import packet_out
+from pyof.v0x01.foundation.exceptions import ValidationError
 
 
 class TestPacketOut(unittest.TestCase):
-
     def setUp(self):
         self.message = packet_out.PacketOut()
         self.message.header.xid = 80
@@ -28,3 +29,35 @@ class TestPacketOut(unittest.TestCase):
         """[Controller2Switch/PacketOut] - unpacking"""
         # TODO
         pass
+
+    def test_valid_virtual_in_ports(self):
+        """Valid virtual ports as defined in 1.0.1 spec."""
+        valid = (Port.OFPP_LOCAL, Port.OFPP_CONTROLLER, Port.OFPP_NONE)
+        msg = packet_out.PacketOut()
+        for in_port in valid:
+            msg.in_port = in_port
+            self.assertTrue(msg.is_valid())
+
+    def test_invalid_virtual_in_ports(self):
+        """Invalid virtual ports as defined in 1.0.1 spec."""
+        invalid = (Port.OFPP_IN_PORT, Port.OFPP_TABLE, Port.OFPP_NORMAL,
+                   Port.OFPP_FLOOD, Port.OFPP_ALL)
+        for in_port in invalid:
+            self.message.in_port = in_port
+            self.assertFalse(self.message.is_valid())
+            self.assertRaises(ValidationError, self.message.validate)
+
+    def test_valid_physical_in_ports(self):
+        """Physical port limits from 1.0.0 spec."""
+        max_valid = int(Port.OFPP_MAX.value) - 1
+        for in_port in (1, max_valid):
+            self.message.in_port = in_port
+            self.assertTrue(self.message.is_valid())
+
+    def test_invalid_physical_in_port(self):
+        """Physical port limits from 1.0.0 spec."""
+        max_valid = int(Port.OFPP_MAX.value) - 1
+        for in_port in (-1, 0, max_valid + 1, max_valid + 2):
+            self.message.in_port = in_port
+            self.assertFalse(self.message.is_valid())
+            self.assertRaises(ValidationError, self.message.validate)

pip install -e .
parse_log_pytest
requirements.txt
pytest pytest-cov coverage
3.9
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
coverage==7.8.0
exceptiongroup==1.2.2
iniconfig==2.1.0
-e git+https://github.com/kytos/python-openflow.git@1b4d191de2e51695ab94395d4f0ba93a7f0e98f8#egg=Kytos_OpenFlow_Parser_library
packaging==24.2
pluggy==1.5.0
pytest==8.3.5
pytest-cov==6.0.0
tomli==2.2.1

name: python-openflow
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - pip=25.0=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - coverage==7.8.0
      - exceptiongroup==1.2.2
      - iniconfig==2.1.0
      - packaging==24.2
      - pluggy==1.5.0
      - pytest==8.3.5
      - pytest-cov==6.0.0
      - tomli==2.2.1
prefix: /opt/conda/envs/python-openflow

tests/v0x01/test_controller2switch/test_packet_out.py::TestPacketOut::test_invalid_physical_in_port tests/v0x01/test_controller2switch/test_packet_out.py::TestPacketOut::test_invalid_virtual_in_ports
tests/v0x01/test_controller2switch/test_packet_out.py::TestPacketOut::test_get_size tests/v0x01/test_controller2switch/test_packet_out.py::TestPacketOut::test_valid_physical_in_ports tests/v0x01/test_controller2switch/test_packet_out.py::TestPacketOut::test_valid_virtual_in_ports
pyof/v0x01/foundation/exceptions.py pyof/v0x01/controller2switch/packet_out.py
pyof/v0x01/foundation/exceptions.py pyof/v0x01/controller2switch/packet_out.py