Search code examples
openflowopenvswitchryu

Delete Flows matching specific cookie - OpenFlow 1.3.5 Spec support by OpenVSwitch


According to the OpenFlow 1.3.5 spec, page 44 specifies the following:

Modify and delete commands can also be filtered by cookie value, if the cookie_mask field contains a value other than 0. This constraint is that the bits specified by the cookie_mask in both the cookie field of the flow mod and a flow entry’s cookie value must be equal. In other words, (flow entry.cookie&flow mod.cookie mask) == (flow mod.cookie&flow mod.cookie mask).

Now, using the Ryu python-based controller, I tried to delete a flow by specifying the flow's cookie value, but the procedure was not successful.

The following code is a test-example which I used.

from ryu.base.app_manager import RyuApp
from ryu.controller.dpset import EventDP
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.ofproto import ether, inet

class MPLS_Testing(RyuApp):
  OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

  @set_ev_cls(EventDP, MAIN_DISPATCHER)
  def switch_connect_event(self, ev):
    ofp_parser = ev.dp.ofproto_parser
    ofp = ev.dp.ofproto
    datapath_obj = ev.dp
    if ev.enter:
      datapath_obj.send_msg(  # Removes all flows registered in this switch.
        ofp_parser.OFPFlowMod(
          datapath=datapath_obj,
          table_id=ofp.OFPTT_ALL,
          command=ofp.OFPFC_DELETE,
          out_port=ofp.OFPP_ANY,
          out_group=ofp.OFPG_ANY,
        )
      )
      add_label_flow = ofp_parser.OFPFlowMod(
        datapath=datapath_obj,            
        cookie=1,        
        table_id=0,
        command=ofp.OFPFC_ADD,
        match=ofp_parser.OFPMatch(
          in_port=1
        ),
        instructions=[
          ofp_parser.OFPInstructionActions(
            ofp.OFPIT_APPLY_ACTIONS,
            [
              ofp_parser.OFPActionPushMpls(),
              ofp_parser.OFPActionSetField(mpls_label=16),
            ]
          ),
          ofp_parser.OFPInstructionGotoTable(table_id=1),
        ]
      )
      datapath_obj.send_msg(add_label_flow)

      add_label_flow2 = ofp_parser.OFPFlowMod(
        datapath=datapath_obj,            
        cookie=2,
        table_id=1,
        command=ofp.OFPFC_ADD,            
        match=ofp_parser.OFPMatch(
          in_port=1
        ),
        instructions=[
          ofp_parser.OFPInstructionActions(
            ofp.OFPIT_APPLY_ACTIONS,
            [
              ofp_parser.OFPActionPushMpls(),
              ofp_parser.OFPActionSetField(mpls_label=12),
            ]
          ),
          ofp_parser.OFPInstructionGotoTable(table_id=2),
        ]
      )
      datapath_obj.send_msg(add_label_flow2)

      # Deletes flow with cookie equal to 2.
      datapath_obj.send_msg(
        ofp_parser.OFPFlowMod(
          cookie=2,
          cookie_mask=0xFFFFFFFFFFFFFFFF,
          datapath=datapath_obj,
          command=ofp.OFPFC_DELETE,
          out_port=ofp.OFPP_ANY,
          out_group=ofp.OFPG_ANY,
        )
      )

Can anyone tell me if OpenVSwitch 2.9 supports cookie match when deleting a flow from the tables? OpenFlow 1.3.5 spec clearly states that a Delete command could also filter flows using the cookie value, when the cookie_mask is different than zero. Currently, I'm kinda lost here.


Solution

  • I have figured out what was missing.

    @pchaigno Thank you for your support.

    It seems the table_id = OFPTT_ALL was missing from the OFPFlowMod message. Ryu seems to default this value to zero, when initialising the object. Because of this, the OFPFlowMod message when used as a OFPFC_DELETE command, Ryu adds by default a table_id = 0 matching requirement.

    So, when using Ryu, the proper message structure to remove a Flow with a cookie equal to 2 from the Switch, is:

    ofp_parser.OFPFlowMod(
        datapath=datapath_obj,
        cookie=2,
        cookie_mask=0xFFFFFFFFFFFFFFFF,
        table_id=ofp.OFPTT_ALL,
        command=ofp.OFPFC_DELETE,
        out_port=ofp.OFPP_ANY,
        out_group=ofp.OFPG_ANY
    )
    

    According to the standard, out_port needs to be equal to OFPP_ANY and the out_group field needs to be equal to OFPG_ANY, otherwise both fields will be considered as a matching requirement. It seems the table_id field follows almost the same logic, requiring a table_id = OFPTT_ALL to match all tables.

    I now consider this issue resolved.