def test_max_field_value(self): """Use all bits of oxm_field.""" self.tlv.oxm_class = OxmClass.OFPXMC_EXPERIMENTER self.tlv.oxm_field = 127 unpacked = OxmTLV() unpacked.unpack(self.tlv.pack()) self.assertEqual(self.tlv, unpacked)
def test_unpack_invalid_field(self): """Raise UnpackException if field is invalid for a class. Example: field 42 is invalid for oxm_class OFPXMC_OPENFLOW_BASIC. """ field42 = b'\x80\x00T\x00' tlv = OxmTLV() with self.assertRaises(UnpackException): tlv.unpack(field42)
def __init__(self, field=None): """Create a ActionSetField with the optional parameters below. Args: length (int): length padded to 64 bits, followed by exactly oxm_len bytes containing a single OXM TLV, then exactly ((oxm_len + 4) + 7)/8*8 - (oxm_len + 4) (between 0 and 7) bytes of all-zero bytes field (:class:`OxmTLV`): OXM field and value. """ super().__init__(action_type=ActionType.OFPAT_SET_FIELD) self.field = OxmTLV() if field is None else field
class ActionSetField(ActionHeader): """Action structure for OFPAT_SET_FIELD.""" field = OxmTLV() _allowed_types = ActionType.OFPAT_SET_FIELD, def __init__(self, field=None): """Create a ActionSetField with the optional parameters below. Args: length (int): length padded to 64 bits, followed by exactly oxm_len bytes containing a single OXM TLV, then exactly ((oxm_len + 4) + 7)/8*8 - (oxm_len + 4) (between 0 and 7) bytes of all-zero bytes field (:class:`OxmTLV`): OXM field and value. """ super().__init__(action_type=ActionType.OFPAT_SET_FIELD) self.field = OxmTLV() if field is None else field def pack(self, value=None): """Pack this structure updating the length and padding it.""" self._update_length() packet = super().pack() return self._complete_last_byte(packet) def _update_length(self): """Update the length field of the struct.""" action_length = 4 + len(self.field.pack()) overflow = action_length % 8 self.length = action_length if overflow: self.length = action_length + 8 - overflow def _complete_last_byte(self, packet): """Pad until the packet length is a multiple of 8 (bytes).""" padded_size = self.length padding_bytes = padded_size - len(packet) if padding_bytes > 0: packet += Pad(padding_bytes).pack() return packet
def _create_from_pack(self): """Return a new instance by unpacking self.tlv.pack().""" unpacked = OxmTLV() unpacked.unpack(self.tlv.pack()) return unpacked
def setUp(self): """Instantiate an OXM TLV struct.""" self.tlv = OxmTLV(oxm_class=OxmClass.OFPXMC_OPENFLOW_BASIC, oxm_field=OxmOfbMatchField.OFPXMT_OFB_IN_PHY_PORT, oxm_hasmask=False, oxm_value=b'')
class TestOxmTLV(TestCase): """Test OXM TLV pack and unpack.""" def setUp(self): """Instantiate an OXM TLV struct.""" self.tlv = OxmTLV(oxm_class=OxmClass.OFPXMC_OPENFLOW_BASIC, oxm_field=OxmOfbMatchField.OFPXMT_OFB_IN_PHY_PORT, oxm_hasmask=False, oxm_value=b'') def test_different_class_types(self): """Pack, unpack the result and assert the values are equal.""" for oxm_class in (OxmClass.OFPXMC_OPENFLOW_BASIC, OxmClass.OFPXMC_EXPERIMENTER): self.tlv.oxm_class = oxm_class unpacked = self._create_from_pack() self.assertEqual(oxm_class, unpacked.oxm_class) def test_different_fields(self): """Pack, unpack the result and assert the values are equal.""" for oxm_field in (OxmOfbMatchField.OFPXMT_OFB_IN_PORT, OxmOfbMatchField.OFPXMT_OFB_IPV6_EXTHDR): self.tlv.oxm_field = oxm_field unpacked = self._create_from_pack() self.assertEqual(oxm_field, unpacked.oxm_field) def test_hasmask_bit(self): """Pack, unpack the result and assert the values are equal.""" for oxm_hasmask in True, False: self.tlv.oxm_hasmask = oxm_hasmask unpacked = self._create_from_pack() self.assertEqual(oxm_hasmask, unpacked.oxm_hasmask) def test_different_values(self): """Pack, unpack the result and assert the values are equal.""" for oxm_value in b'', b'abc': self.tlv.oxm_value = oxm_value unpacked = self._create_from_pack() self.assertEqual(oxm_value, unpacked.oxm_value) def _create_from_pack(self): """Return a new instance by unpacking self.tlv.pack().""" unpacked = OxmTLV() unpacked.unpack(self.tlv.pack()) return unpacked def test_pack_overflowed_field(self): """Raise PackException if field is bigger than 7 bit.""" self.tlv.oxm_class = OxmClass.OFPXMC_EXPERIMENTER self.tlv.oxm_field = 2**7 with self.assertRaises(PackException): self.tlv.pack() def test_pack_invalid_field(self): """Raise PackException if field is invalid for a class. Example: field 42 is invalid for oxm_class OFPXMC_OPENFLOW_BASIC. """ self.tlv.oxm_class = OxmClass.OFPXMC_OPENFLOW_BASIC self.tlv.oxm_field = 42 with self.assertRaises(PackException): self.tlv.pack() def test_unpack_invalid_field(self): """Raise UnpackException if field is invalid for a class. Example: field 42 is invalid for oxm_class OFPXMC_OPENFLOW_BASIC. """ field42 = b'\x80\x00T\x00' tlv = OxmTLV() with self.assertRaises(UnpackException): tlv.unpack(field42) def test_max_field_value(self): """Use all bits of oxm_field.""" self.tlv.oxm_class = OxmClass.OFPXMC_EXPERIMENTER self.tlv.oxm_field = 127 unpacked = OxmTLV() unpacked.unpack(self.tlv.pack()) self.assertEqual(self.tlv, unpacked)
def as_of_tlv(self): """Return a pyof OXM TLV instance.""" value_bytes = HWAddress(self.value).pack() return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
def as_of_tlv(self): """Return a pyof OXM TLV instance.""" value_bytes = self.value.to_bytes(1, 'big') return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
def _create_vlan_tlv(vlan_id): tlv = OxmTLV() tlv.oxm_field = OxmOfbMatchField.OFPXMT_OFB_VLAN_VID oxm_value = vlan_id | VlanId.OFPVID_PRESENT tlv.oxm_value = oxm_value.to_bytes(2, 'big') return tlv
def as_of_tlv(self): """Return a pyof OXM TLV instance.""" value = self.value | VlanId.OFPVID_PRESENT value_bytes = value.to_bytes(2, 'big') return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
def _create_flow_mod(version, packet, port): """Create a FlowMod message with the appropriate version and data.""" if version == '0x01': flow_mod = FlowMod10() flow_mod.match.dl_src = packet.source.value flow_mod.match.dl_dst = packet.destination.value flow_mod.match.dl_type = packet.ether_type flow_mod.actions.append(Output10(port=port)) else: flow_mod = FlowMod13() match_dl_type = OxmTLV() match_dl_type.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_TYPE match_dl_type.oxm_value = packet.ether_type.value.to_bytes( 2, 'big') flow_mod.match.oxm_match_fields.append(match_dl_type) match_dl_src = OxmTLV() match_dl_src.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_SRC match_dl_src.oxm_value = packet.source.pack() flow_mod.match.oxm_match_fields.append(match_dl_src) match_dl_dst = OxmTLV() match_dl_dst.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_DST match_dl_dst.oxm_value = packet.destination.pack() flow_mod.match.oxm_match_fields.append(match_dl_dst) action = Output13(port=port) instruction = InstructionApplyAction() instruction.actions.append(action) flow_mod.instructions.append(instruction) flow_mod.command = FlowModCommand.OFPFC_ADD flow_mod.priority = settings.flow_priority return flow_mod
def handle_packet_in(self, event): """Handle PacketIn Event. Install flows allowing communication between switch ports. Args: event (KytosPacketIn): Received Event """ log.debug("PacketIn Received") packet_in = event.content['message'] ethernet = Ethernet() ethernet.unpack(packet_in.data.value) # Ignore LLDP packets or packets not generated by table-miss flows if (ethernet.destination in settings.lldp_macs or packet_in.reason != PacketInReason.OFPR_NO_MATCH): return # Learn the port where the sender is connected in_port = packet_in.in_port switch = event.source.switch switch.update_mac_table(ethernet.source, in_port) ports = switch.where_is_mac(ethernet.destination) # Add a flow to the switch if the destination is known if ports: flow_mod = FlowMod() flow_mod.command = FlowModCommand.OFPFC_ADD flow_mod.priority = settings.flow_priority match_dl_type = OxmTLV() match_dl_type.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_TYPE match_dl_type.oxm_value = ethernet.ether_type.value.to_bytes( 2, 'big') flow_mod.match.oxm_match_fields.append(match_dl_type) match_dl_src = OxmTLV() match_dl_src.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_SRC match_dl_src.oxm_value = ethernet.source.pack() flow_mod.match.oxm_match_fields.append(match_dl_src) match_dl_dst = OxmTLV() match_dl_dst.oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_DST match_dl_dst.oxm_value = ethernet.destination.pack() flow_mod.match.oxm_match_fields.append(match_dl_dst) action = ActionOutput(port=ports[0]) instruction = InstructionApplyAction() instruction.actions.append(action) flow_mod.instructions.append(instruction) event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_flow_mod'), content={ 'destination': event.source, 'message': flow_mod }) self.controller.buffers.msg_out.put(event_out) # Send the packet to correct destination or flood it packet_out = PacketOut() packet_out.buffer_id = packet_in.buffer_id packet_out.in_port = in_port packet_out.data = packet_in.data port = ports[0] if ports else PortNo.OFPP_FLOOD out_action = ActionOutput(port=port) packet_out.actions.append(out_action) event_out = KytosEvent(name=('kytos/of_l2ls.messages.out.' 'ofpt_packet_out'), content={ 'destination': event.source, 'message': packet_out }) self.controller.buffers.msg_out.put(event_out)