Open italovalcy opened 1 month ago
Workaround we created:
self.new_actions = {
"set_ipv4_dst": ActionSetIPv4Dst,
OFActionSetField: ActionSetFieldFactory,
}
for name, action in self.new_actions.items():
Action.add_action_class(name, action)
class ActionSetFieldFactory(OFActionSetField):
_subclass_set_field = {
OxmOfbMatchField.OFPXMT_OFB_VLAN_VID: ActionSetVlan,
OxmOfbMatchField.OFPXMT_OFB_IPV4_DST: ActionSetIPv4Dst,
OxmOfbMatchField.OFPXMT_OFB_IPV6_DST: ActionSetIPv6Dst,
OxmOfbMatchField.OFPXMT_OFB_TCP_DST: ActionSetTCPDst,
OxmOfbMatchField.OFPXMT_OFB_UDP_DST: ActionSetUDPDst,
OxmOfbMatchField.OFPXMT_OFB_ETH_DST: ActionSetETHDst,
}
@classmethod
def from_of_action(cls, of_action):
"""Return a high-level ActionSetField to call specific subclass."""
subclass = cls._subclass_set_field.get(of_action.field.oxm_field)
return subclass.from_of_action(of_action) if subclass else None
@classmethod
def add_set_field_subclass(cls, oxm_field, subclass):
"""Add a subclass for ActionSetField based on OXM Field."""
cls._subclass_set_field[oxm_field] = subclass
I believe that we should include this solution into of_core directly (to avoid someone else having to depending on our Napp or ended up overriding our subclasses when using together)
Usage examples after deploying the solution above (https://github.com/hackinsdn/containment):
curl -X POST -H 'Content-type: application/json' http://127.0.0.1:8181/api/kytos/flow_manager/v2/flows/00:00:00:00:00:00:00:01 -d '{"flows":[{"priority": 1000, "match":{"dl_vlan": 101, "dl_type": 2048}, "actions":[{"action_type": "set_ipv4_dst", "ipv4_dst": "10.0.0.1"}]}]}'
curl -X POST -H 'Content-type: application/json' http://127.0.0.1:8181/api/kytos/flow_manager/v2/flows/00:00:00:00:00:00:00:01 -d '{"flows":[{"priority": 1000, "match":{"dl_vlan": 101, "dl_type": 34525}, "actions":[{"action_type": "set_ipv6_dst", "ipv6_dst": "2001:db8:100:1::233"}]}]}'
curl -X POST -H 'Content-type: application/json' http://127.0.0.1:8181/api/kytos/flow_manager/v2/flows/00:00:00:00:00:00:00:01 -d '{"flows":[{"priority": 1000, "match":{"dl_vlan": 101, "dl_type": 2048, "nw_proto": 6}, "actions":[{"action_type": "set_tcp_dst", "port": 33884}]}]}'
curl -X POST -H 'Content-type: application/json' http://127.0.0.1:8181/api/kytos/flow_manager/v2/flows/00:00:00:00:00:00:00:01 -d '{"flows":[{"priority": 1000, "match":{"dl_vlan": 101, "dl_type": 2048, "nw_proto": 17}, "actions":[{"action_type": "set_udp_dst", "port": 33884}]}]}'
curl -X POST -H 'Content-type: application/json' http://127.0.0.1:8181/api/kytos/flow_manager/v2/flows/00:00:00:00:00:00:00:01 -d '{"flows":[{"priority": 1000, "match":{"dl_vlan": 101}, "actions":[{"action_type": "set_eth_dst", "eth_addr": "00:01:02:03:04:05"}]}]}'
Hi,
Currently, the ActionSetField class is only considering the action type on the deserialization process, as defined here:
https://github.com/kytos-ng/of_core/blob/3545b1c23fa8f39937b686d3fb0d056a8fa996e5/v0x04/flow.py#L189
If one were to implement a new ActionSetField (for instance, ActionSetFieldIPv4Dst), we would have to also consider the OXM_FIELD to take the decision of the proper subclass to deserialize the OF Action data.
Use case: in the HackInSDN project we are defining new Action Set Fields to implement Custom Containment actions to mitigate cyberattacks. Some actions we are adding include: ActionSetFieldIPv4Dst, ActionSetFieldIPv6Dst, ActionSetFieldTCPDst, etc.
On our implementation we ended up overriding the OFActionSetField as showed below:
Then after adding a flow with set_ipv4_dst and also set_vlan, we got the following error:
This error happened because our class ended up being responsible for deserializing all OFActionSetField packets.
It seems that using a ActionSetField Factory to proper identify the subclass responsible for each OXM fields would be proper solution.
cc @talitarp since she is also working on this