Exemplo n.º 1
0
    def test_unpack_weird_header(self):
        """
    Test the unpacking of a header we don't have a class for
    """

        # Make a weird header...
        class nxm_weird(nx._nxm_maskable, nx._nxm_numeric_entry):
            _nxm_type = nx._make_type(0xdead, 0x42)
            _nxm_length = 4

        original = nx.nx_reg_load(dst=nxm_weird, value=42, nbits=32)

        original_packed = original.pack()

        # Currently, the action unpacking API still sucks...
        unoriginal = nx.nx_reg_load()
        offset = unoriginal.unpack(original_packed, 0)
        self.assertEqual(offset, len(original_packed),
                         "Didn't unpack entire entry")
        unoriginal_packed = unoriginal.pack()

        self.assertEqual(unoriginal.dst.__name__, "NXM_UNKNOWN_dead_42",
                         "Didn't generate new class correctly?")

        self.assertEqual(original_packed, unoriginal_packed,
                         "Pack/Unpack failed")
Exemplo n.º 2
0
        def vlan_load_reg():
            if vlan_removed:
                of_actions.append(nx.nx_reg_load(dst=vlan_reg,
                                                 value=0, nbits=16))
            else:
                """The load/unload operations are complicated to simplify the intermediate
                masked write operations. This is really helpful with multiple
                stages: it's easier to do a single masked write per stage; there
                are more stages which do the former than load/unload.

                Basically what is happening is the following mapping of
                different parts of the VLAN_TCI field into the register
                (typically NXM_NX_REG3) as follows:

                REG3:        CFI PCP2 PCP1 PCP0 ID11 ID10 ... ID1 ID0
                VLAN_TCI:    PCP2 PCP1 PCP0 CFI ID11 ID10 ... ID1 ID0

                This enables masked writes considering the VLAN as one
                *contiguous* 15 bit field, instead of breaking the masked write
                into two writes, one for the ID part and one for the PCP part
                (yuck!)
                """
                of_actions.append(nx.nx_reg_move(dst=vlan_reg,
                                                 src=nx.NXM_OF_VLAN_TCI,
                                                 dst_ofs=0, src_ofs=0,
                                                 nbits=12))
                of_actions.append(nx.nx_reg_move(dst=vlan_reg,
                                                 src=nx.NXM_OF_VLAN_TCI,
                                                 dst_ofs=12, src_ofs=13,
                                                 nbits=3))
                of_actions.append(nx.nx_reg_move(dst=vlan_reg,
                                                 src=nx.NXM_OF_VLAN_TCI,
                                                 dst_ofs=15, src_ofs=12,
                                                 nbits=1))
Exemplo n.º 3
0
def ofp_action_set_in_port (in_port = 0):
  """
  Creates an action that modifies a packet's in_port

  Use like: ofp_action_set_in_port(in_port = 42)
  If in_port is not given, defaults to 0 (a port never used by OpenFlow)
  """
  # Return action that loads the OF_IN_PORT register with the given value
  return nxt.nx_reg_load(dst=nxt.NXM_OF_IN_PORT, value=in_port)
Exemplo n.º 4
0
 def vlan_masked_write():
     if debug:
         print "pox_client: build_nx_actions: in rewrite function:"
         print vlan_removed, vlan_written
     if vlan_removed:
         if debug:
             print "pox_client: build_nx_actions: VLAN was removed"
         of_actions.append(nx.nx_reg_load(dst=vlan_reg,
                                          value=0, nbits=16))
     elif vlan_written:
         vlan_16bit = ((int(vlan_written['pcp']) << 12) |
                       (int(vlan_written['id'])))
         load_value = ((vlan_16bit >> vlan_written['offset']) &
                       ((1 << vlan_written['nbits'])-1))
         of_actions.append(nx.nx_reg_load(dst=vlan_reg,
                                          value=load_value,
                                          offset=vlan_written['offset'],
                                          nbits=vlan_written['nbits']))
         of_actions.append(nx.nx_reg_load(dst=vlan_reg,
                                          value=1,
                                          offset=15,
                                          nbits=1))
Exemplo n.º 5
0
  def test_unpack_weird_header (self):
    """
    Test the unpacking of a header we don't have a class for
    """
    # Make a weird header...
    class nxm_weird (nx._nxm_maskable, nx._nxm_numeric_entry):
      _nxm_type = nx._make_type(0xdead,0x42)
      _nxm_length = 4
    original = nx.nx_reg_load(dst=nxm_weird,value=42,nbits=32)

    original_packed = original.pack()

    # Currently, the action unpacking API still sucks...
    unoriginal = nx.nx_reg_load()
    offset = unoriginal.unpack(original_packed, 0)
    self.assertEqual(offset, len(original_packed),
                     "Didn't unpack entire entry")
    unoriginal_packed = unoriginal.pack()

    self.assertEqual(unoriginal.dst.__name__, "NXM_UNKNOWN_dead_42",
                     "Didn't generate new class correctly?")

    self.assertEqual(original_packed, unoriginal_packed, "Pack/Unpack failed")
Exemplo n.º 6
0
    def _handle_ConnectionUp(self, event):
        # Initialize Nicira
        msg = nx.nx_flow_mod()
        event.connection.send(msg)

        # Signal Table use
        msg = nx.nx_flow_mod_table_id()
        event.connection.send(msg)

        #Table 1 -> TCP Table 2 -> ARP
        for temp_table_id in range(1, 5):
            msg = nx.nx_flow_mod(command=of.OFPFC_DELETE,
                                 table_id=temp_table_id)
            event.connection.send(msg)

        #Table 0 rule: Selection of tables
        #IP Packet Handling / TCP
        msg = nx.nx_flow_mod()
        msg.table_id = 0
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.priority = 65000
        msg.actions.append(nx.nx_multipath(dst=nx.NXM_NX_REG2))
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=1))
        event.connection.send(msg)

        #ARP Packet Handling
        msg = nx.nx_flow_mod()
        msg.table_id = 0
        msg.priority = 65001
        msg.match.eth_type = pkt.ethernet.ARP_TYPE
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=4))
        event.connection.send(msg)
        log.info("Table 0 done")

        #Table 1 Rules
        # TBD: State Machine and Hash value
        # New flow function
        msg = nx.nx_flow_mod()
        msg.table_id = 1
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.priority = 65004
        # Signifying New flow
        msg.actions.append(nx.nx_reg_load(dst=nx.NXM_NX_REG0, value=0x0))
        # currently learning based on eth address
        # no hash
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=2))
        event.connection.send(msg)

        #Table 2 Rules

        #1. Sync (Should be a Sync)
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.NXM_NX_REG0 = 0
        msg.match.tcp_flags = 2
        msg.priority = 65001
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1, priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(
            fms(load=nx.NXM_NX_REG0,
                src=nx.nx_learn_src_immediate.u32(None, 1)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #2. Sync Ack (Should be after sync)
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x12
        msg.priority = 65002
        msg.match.NXM_NX_REG0 = 1
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1, priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(
            fms(load=nx.NXM_NX_REG0,
                src=nx.nx_learn_src_immediate.u32(None, 2)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #3. Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x010
        msg.priority = 65003
        msg.match.NXM_NX_REG0 = 2
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1, priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(
            fms(load=nx.NXM_NX_REG0,
                src=nx.nx_learn_src_immediate.u32(None, 3)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #4. Fin
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x010
        msg.priority = 65003
        msg.match.NXM_NX_REG0 = 3
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1, priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(
            fms(load=nx.NXM_NX_REG0,
                src=nx.nx_learn_src_immediate.u32(None, 4)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #5. Fin-Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x010
        msg.priority = 65003
        msg.match.NXM_NX_REG0 = 4
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1, priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(
            fms(load=nx.NXM_NX_REG0,
                src=nx.nx_learn_src_immediate.u32(None, 5)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #7. Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x010
        msg.priority = 65003
        msg.match.NXM_NX_REG0 = 5
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1, priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(
            fms(load=nx.NXM_NX_REG0,
                src=nx.nx_learn_src_immediate.u32(None, 6)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #8. RST
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x14
        msg.priority = 65003
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #9. PSH-Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x18
        msg.priority = 65003
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #9. Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x10
        msg.priority = 65003
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)

        #send to controller  currently sending to the destination as no old state stored
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.priority = 64999
        msg.actions.append(nx.nx_reg_load(dst=nx.NXM_NX_REG1, value=int(1)))
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=3))
        event.connection.send(msg)
        log.info("Table 2 done")

        #Table 3 Rules: Forward the packet to the Destination
        msg = nx.nx_flow_mod()
        msg.table_id = 3
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_dst = "10.0.0.1"
        msg.priority = 65001
        msg.actions.append(of.ofp_action_output(port=1))
        event.connection.send(msg)

        msg = nx.nx_flow_mod()
        msg.table_id = 3
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_dst = "10.0.0.2"
        msg.priority = 65001
        msg.actions.append(of.ofp_action_output(port=2))
        event.connection.send(msg)

        msg = nx.nx_flow_mod()
        msg.table_id = 3
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_dst = "10.0.0.3"
        msg.priority = 65001
        msg.actions.append(of.ofp_action_output(port=3))
        event.connection.send(msg)

        #send to controller
        msg = nx.nx_flow_mod()
        msg.table_id = 3
        msg.match.NXM_NX_REG1 = 1
        msg.priority = 65005
        msg.actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER))
        event.connection.send(msg)
        log.info("Table 3 done")

        #Table 4 Rules
        msg = nx.nx_flow_mod()
        msg.table_id = 4
        msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD))
        event.connection.send(msg)
        log.info("Table 4 done")
Exemplo n.º 7
0
    def build_nx_actions(self,inport,action_list,table_id,pipeline):
        ### BUILD NX ACTIONS
        of_actions = []
        ctlr_outport = False # there is a controller outport action
        phys_outports = list() # list of physical outports to forward out of
        possibly_resubmit_next_table = False # should packet be passed on to next table?
        atleast_one_action = False

        for actions in action_list:
            atleast_one_action = True
            if 'srcmac' in actions:
                of_actions.append(of.ofp_action_dl_addr.set_src(actions['srcmac']))
            if 'dstmac' in actions:
                of_actions.append(of.ofp_action_dl_addr.set_dst(actions['dstmac']))
            if 'srcip' in actions:
                of_actions.append(of.ofp_action_nw_addr.set_src(actions['srcip']))
            if 'dstip' in actions:
                of_actions.append(of.ofp_action_nw_addr.set_dst(actions['dstip']))
            if 'srcport' in actions:
                of_actions.append(of.ofp_action_tp_port.set_src(actions['srcport']))
            if 'dstport' in actions:
                of_actions.append(of.ofp_action_tp_port.set_dst(actions['dstport']))
            if 'vlan_id' in actions:
                if actions['vlan_id'] is None:
                    of_actions.append(of.ofp_action_strip_vlan())
                else:
                    of_actions.append(of.ofp_action_vlan_vid(vlan_vid=actions['vlan_id']))
            if 'vlan_pcp' in actions:
                if actions['vlan_pcp'] is None:
                    if not actions['vlan_id'] is None:
                        raise RuntimeError("vlan_id and vlan_pcp must be set together!")
                    pass
                else:
                    of_actions.append(of.ofp_action_vlan_pcp(vlan_pcp=actions['vlan_pcp']))

            assert 'port' in actions
            outport = actions['port']

            if outport == of.OFPP_CONTROLLER:
                ctlr_outport = True
            else:
                """ There is either a physical output action (i.e., on a
                non-controller port), or a "send to next table" action."""
                possibly_resubmit_next_table = True
                if outport != CUSTOM_NEXT_TABLE_PORT:
                    phys_outports.append(outport)
                """ Otherwise there are no physical outports; just a possibility
                of resubmitting to the next table. Pass. """

        """In general, actual packet forwarding may have to wait until the final table
        in the pipeline. This means we must determine if there is a "next" table
        that processes the packet from here, or if this is the last one.

        But first, the easy part. There are exactly three cases where a
        forwarding table *will* in fact "immediately forward" a packet according
        to the current rule (and all previous table stages that processed the
        packet), without waiting for any other further processing:

        (1) if the packet is dropped by the current rule,
        (2) if the packet is forwarded to the controller port, or
        (3) if this is the last stage of the pipeline.

        In the case of (1) and (2), packet forwarding may happen immediately and
        only depend on the current rule. But in (3), the forwarding decision
        must take the current rule as well as previous port changes into
        account, as follows:

        (a) if the current rule specifies an output port, forward the packet out
        of that port.

        (b) if the current rule does not specify an outport, then forward the
        packet out of the port using the value stored in the dedicated
        per-packet port register.

        If neither of (1)-(3) above is true, then we take the following
        approach:

        (a) if there is an outport set by this rule, write that value into the
        dedicated per-packet register that contains the current port the
        packet is in.

        (b) if there is no outport set by this rule, and if this is table id 0,
        move the value of the inport into the dedicated per-packet port
        register. This denotes that the packet is currently still on its inport.

        (c) resubmit the packet to the "next" table (according to the pipeline).
        """
        exists_next_table = table_id in pipeline.edges

        # Decide first on "immediate forwarding" conditions:
        immediately_fwd = True
        if not atleast_one_action: # (1) drop
            of_actions = []
        elif ctlr_outport: # (2) controller
            of_actions = []
            of_actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER))
        elif possibly_resubmit_next_table and (not exists_next_table):
            # (3) last stage of pipeline
            if len(phys_outports) > 0: # fwd out of latest assigned ports
                for p in phys_outports:
                    of_actions.append(of.ofp_action_output(port=p))
            else:
                # fwd out of stored port value
                of_actions.append(nx.nx_output_reg(reg=nx.NXM_NX_REG2,
                                                   nbits=16))
        elif (not exists_next_table) and (not possibly_resubmit_next_table):
            raise RuntimeError("Unexpected condition in multi-stage processing")
        else: # must resubmit packet to subsequent tables for processing
            immediately_fwd = False

        if immediately_fwd:
            return of_actions

        # Act on packet with knowledge that subsequent tables must process it
        assert (possibly_resubmit_next_table and exists_next_table and
                (not immediately_fwd))
        next_table = pipeline.edges[table_id]
        if len(phys_outports) > 0:
            # move port register to latest assigned port values
            for p in phys_outports:
                of_actions.append(nx.nx_reg_load(dst=nx.NXM_NX_REG2,
                                                 value=p, nbits=16))
                of_actions.append(nx.nx_action_resubmit.resubmit_table(
                    table=next_table))
        elif table_id == 0:
            # move the inport value to reg2.
            of_actions.append(nx.nx_reg_move(src=nx.NXM_OF_IN_PORT,
                                             dst=nx.NXM_NX_REG2,
                                             nbits=16))
            of_actions.append(nx.nx_action_resubmit.resubmit_table(
                table=next_table))
        else:
            of_actions.append(nx.nx_action_resubmit.resubmit_table(
                table=next_table))
        return of_actions
Exemplo n.º 8
0
    def sync_table(self):
        if not self._conn: return

        self._cur = {RIP_NET_TABLE: {}, RIP_PORT_TABLE: {}}
        cur = self._cur

        for e in self.table.values():
            if e.metric >= INFINITY: continue
            fm = ovs.ofp_flow_mod_table_id()
            fm.xid = 0
            fm.table_id = RIP_NET_TABLE
            fm.priority = e.size + 1  # +1 because 0 reserved for fallback
            fm.match.dl_type = pkt.ethernet.IP_TYPE
            fm.match.nw_dst = (e.ip, e.size)
            if e.dev is not None:
                # This is for a directly attached network.  It'll be looked up in
                # the port table.
                fm.actions.append(
                    ovs.nx_action_resubmit.resubmit_table(RIP_PORT_TABLE))
            else:
                # This is for a remote network.
                # Load the gateway into the dst IP; it will be looked up in the port
                # table to find the right port.  The real dst IP will get reloaded
                # from a register before egress.
                fm.actions.append(of.ofp_action_nw_addr.set_dst(e.next_hop))
                fm.actions.append(
                    ovs.nx_action_resubmit.resubmit_table(RIP_PORT_TABLE))
            cur[RIP_NET_TABLE][(e.ip, e.size)] = fm

        for e in self.table.values():
            if e.metric >= INFINITY: continue
            fm = ovs.ofp_flow_mod_table_id()
            fm.xid = 0
            fm.table_id = RIP_PORT_TABLE
            fm.priority = e.size + 1  # +1 because 0 reserved for fallback
            fm.match.dl_type = pkt.ethernet.IP_TYPE
            fm.match.nw_dst = (e.ip, e.size)
            if e.dev is not None:
                # This is for a directly attached network.  Look up the port.
                # Also, fix the dst IP address.
                port = self._conn.ports.get(e.dev)
                if port is None: continue
                fm.actions.append(
                    ovs.nx_reg_load(dst=OUT_PORT_REGISTER, value=e.dev))
                fm.actions.append(of.ofp_action_dl_addr.set_src(port.hw_addr))
                fm.actions.append(
                    ovs.nx_action_resubmit.resubmit_table(ARP_TABLE))
            else:
                # If we get to this table and we don't have a direct entry that
                # matches, we have no working route!
                # Should we install something so that we generate an ICMP unreachable
                # or something?
                pass
            cur[RIP_PORT_TABLE][(e.ip, e.size)] = fm

        if self._conn:
            data1 = b''.join(x.pack()
                             for x in self._cur[RIP_PORT_TABLE].itervalues())
            data2 = b''.join(x.pack()
                             for x in self._cur[RIP_NET_TABLE].itervalues())
            data = data1 + data2
            if data == self._prev: return  # Nothing changed

            self._clear_table(RIP_NET_TABLE)
            self._clear_table(RIP_PORT_TABLE)
            self._init_rip_net_table()
            self._init_rip_port_table()

            self.log.debug("Syncing %s port and %s net table entries",
                           len(cur[RIP_PORT_TABLE]), len(cur[RIP_NET_TABLE]))
            self._conn.send(data)

            self._prev = data
Exemplo n.º 9
0
    def build_nx_actions(self,inport,action_list,table_id,pipeline,debug=False):
        ### BUILD NX ACTIONS
        of_actions = []
        ctlr_outport = False # there is a controller outport action
        phys_outports = list() # list of physical outports to forward out of
        possibly_resubmit_next_table = False # should packet be passed on to next table?
        atleast_one_action = False

        # vlan handling flags
        vlan_removed = False
        vlan_written = {}

        if debug:
            print "pox_client: build_nx_actions: Received actions:"
            print action_list

        for actions in action_list:
            atleast_one_action = True
            if 'srcmac' in actions:
                of_actions.append(of.ofp_action_dl_addr.set_src(actions['srcmac']))
            if 'dstmac' in actions:
                of_actions.append(of.ofp_action_dl_addr.set_dst(actions['dstmac']))
            if 'srcip' in actions:
                of_actions.append(of.ofp_action_nw_addr.set_src(actions['srcip']))
            if 'dstip' in actions:
                of_actions.append(of.ofp_action_nw_addr.set_dst(actions['dstip']))
            if 'srcport' in actions:
                of_actions.append(of.ofp_action_tp_port.set_src(actions['srcport']))
            if 'dstport' in actions:
                of_actions.append(of.ofp_action_tp_port.set_dst(actions['dstport']))
            if 'vlan_id' in actions:
                if actions['vlan_id'] is None:
                    vlan_removed = True
                else:
                    assert 'vlan_pcp' in actions
                    assert 'vlan_offset' in actions
                    assert 'vlan_nbits' in actions
                    vlan_written = {k: actions['vlan_' + k] for k in
                                      ['pcp', 'offset', 'nbits', 'id']}
            if 'vlan_pcp' in actions:
                assert 'vlan_id' in actions, "vlan_id and vlan_pcp must be set together"
            assert 'port' in actions
            outport = actions['port']

            if outport == of.OFPP_CONTROLLER:
                ctlr_outport = True
            else:
                """ There is either a physical output action (i.e., on a
                non-controller port), or a "send to next table" action."""
                possibly_resubmit_next_table = True
                if outport != CUSTOM_NEXT_TABLE_PORT:
                    phys_outports.append(outport)
                """ Otherwise there are no physical outports; just a possibility
                of resubmitting to the next table. Pass. """

        """Construct routines to move packet VLAN into the register, do a masked write
        into the register, and to write back the register into the packet.
        """
        vlan_reg = nx.NXM_NX_REG3
        def vlan_load_reg():
            if vlan_removed:
                of_actions.append(nx.nx_reg_load(dst=vlan_reg,
                                                 value=0, nbits=16))
            else:
                """The load/unload operations are complicated to simplify the intermediate
                masked write operations. This is really helpful with multiple
                stages: it's easier to do a single masked write per stage; there
                are more stages which do the former than load/unload.

                Basically what is happening is the following mapping of
                different parts of the VLAN_TCI field into the register
                (typically NXM_NX_REG3) as follows:

                REG3:        CFI PCP2 PCP1 PCP0 ID11 ID10 ... ID1 ID0
                VLAN_TCI:    PCP2 PCP1 PCP0 CFI ID11 ID10 ... ID1 ID0

                This enables masked writes considering the VLAN as one
                *contiguous* 15 bit field, instead of breaking the masked write
                into two writes, one for the ID part and one for the PCP part
                (yuck!)
                """
                of_actions.append(nx.nx_reg_move(dst=vlan_reg,
                                                 src=nx.NXM_OF_VLAN_TCI,
                                                 dst_ofs=0, src_ofs=0,
                                                 nbits=12))
                of_actions.append(nx.nx_reg_move(dst=vlan_reg,
                                                 src=nx.NXM_OF_VLAN_TCI,
                                                 dst_ofs=12, src_ofs=13,
                                                 nbits=3))
                of_actions.append(nx.nx_reg_move(dst=vlan_reg,
                                                 src=nx.NXM_OF_VLAN_TCI,
                                                 dst_ofs=15, src_ofs=12,
                                                 nbits=1))

        def vlan_masked_write():
            if debug:
                print "pox_client: build_nx_actions: in rewrite function:"
                print vlan_removed, vlan_written
            if vlan_removed:
                if debug:
                    print "pox_client: build_nx_actions: VLAN was removed"
                of_actions.append(nx.nx_reg_load(dst=vlan_reg,
                                                 value=0, nbits=16))
            elif vlan_written:
                vlan_16bit = ((int(vlan_written['pcp']) << 12) |
                              (int(vlan_written['id'])))
                load_value = ((vlan_16bit >> vlan_written['offset']) &
                              ((1 << vlan_written['nbits'])-1))
                of_actions.append(nx.nx_reg_load(dst=vlan_reg,
                                                 value=load_value,
                                                 offset=vlan_written['offset'],
                                                 nbits=vlan_written['nbits']))
                of_actions.append(nx.nx_reg_load(dst=vlan_reg,
                                                 value=1,
                                                 offset=15,
                                                 nbits=1))

        def vlan_write_back():
            """ The write back operation is slightly complicated for reasons
            described under `vlan_load_reg()`. """
            if debug:
                print "pox_client: build_nx_actions: Writing back VLAN. The actions are:"
                print actions
            if table_id > 0:
                of_actions.append(nx.nx_reg_move(src=vlan_reg,
                                                 dst=nx.NXM_OF_VLAN_TCI,
                                                 src_ofs=0, dst_ofs=0,
                                                 nbits=12))
                of_actions.append(nx.nx_reg_move(src=vlan_reg,
                                                 dst=nx.NXM_OF_VLAN_TCI,
                                                 src_ofs=12, dst_ofs=13,
                                                 nbits=3))
                of_actions.append(nx.nx_reg_move(src=vlan_reg,
                                                 dst=nx.NXM_OF_VLAN_TCI,
                                                 src_ofs=15, dst_ofs=12,
                                                 nbits=1))

        """In general, actual packet forwarding may have to wait until the final table
        in the pipeline. This means we must determine if there is a "next" table
        that processes the packet from here, or if this is the last one.

        But first, the easy part. There are exactly three cases where a
        forwarding table *will* in fact "immediately forward" a packet according
        to the current rule (and all previous table stages that processed the
        packet), without waiting for any other further processing:

        (1) if the packet is dropped by the current rule,
        (2) if the packet is forwarded to the controller port, or
        (3) if this is the last stage of the pipeline.

        In the case of (1) and (2), packet forwarding may happen immediately and
        only depend on the current rule. But in (3), the forwarding decision
        must take the current rule as well as previous port changes into
        account, as follows:

        (a) if the current rule specifies an output port, forward the packet out
        of that port.

        (b) if the current rule does not specify an outport, then forward the
        packet out of the port using the value stored in the dedicated
        per-packet port register.

        If neither of (1)-(3) above is true, then we take the following
        approach:

        (a) if there is an outport set by this rule, write that value into the
        dedicated per-packet register that contains the current port the
        packet is in.

        (b) if there is no outport set by this rule, and if this is table id 0,
        move the value of the inport into the dedicated per-packet port
        register. This denotes that the packet is currently still on its inport.

        (c) resubmit the packet to the "next" table (according to the pipeline).
        """
        exists_next_table = table_id in pipeline.edges

        # Decide first on "immediate forwarding" conditions:
        immediately_fwd = True
        if not atleast_one_action: # (1) drop
            of_actions = []
        elif ctlr_outport: # (2) controller
            of_actions = []
            vlan_write_back()
            of_actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER))
        elif possibly_resubmit_next_table and (not exists_next_table):
            # (3) last stage of pipeline
            vlan_masked_write()
            vlan_write_back()
            if len(phys_outports) > 0: # fwd out of latest assigned ports
                for p in phys_outports:
                    of_actions.append(of.ofp_action_output(port=p))
            else:
                # fwd out of stored port value
                of_actions.append(nx.nx_output_reg(reg=nx.NXM_NX_REG2,
                                                   nbits=16))
        elif (not exists_next_table) and (not possibly_resubmit_next_table):
            raise RuntimeError("Unexpected condition in multi-stage processing")
        else: # must resubmit packet to subsequent tables for processing
            immediately_fwd = False

        if immediately_fwd:
            return of_actions

        if debug:
            print "pox_client: build_nx_actions: Not the last stage."

        # Act on packet with knowledge that subsequent tables must process it
        assert (possibly_resubmit_next_table and exists_next_table and
                (not immediately_fwd))

        # 1. Handle VLAN writing for resubmitted packets
        if table_id == 0:
            vlan_load_reg()
        vlan_masked_write()

        # 2. Handle packet forwarding for resubmitted packets
        next_table = pipeline.edges[table_id]
        if len(phys_outports) > 0:
            # move port register to latest assigned port values
            for p in phys_outports:
                of_actions.append(nx.nx_reg_load(dst=nx.NXM_NX_REG2,
                                                 value=p, nbits=16))
                of_actions.append(nx.nx_action_resubmit.resubmit_table(
                    table=next_table))
        elif table_id == 0:
            # move the inport value to reg2.
            of_actions.append(nx.nx_reg_move(src=nx.NXM_OF_IN_PORT,
                                             dst=nx.NXM_NX_REG2,
                                             nbits=16))
            of_actions.append(nx.nx_action_resubmit.resubmit_table(
                table=next_table))
        else:
            of_actions.append(nx.nx_action_resubmit.resubmit_table(
                table=next_table))
        return of_actions
Exemplo n.º 10
0
    def _handle_ConnectionUp(self, event):
        # Initialize Nicira
        msg = nx.nx_flow_mod()
        event.connection.send(msg)
        
        # Signal Table use 
        msg = nx.nx_flow_mod_table_id()
        event.connection.send(msg)

        #Table 1 -> TCP Table 2 -> ARP
        for temp_table_id in range(1, 5):  
            msg = nx.nx_flow_mod(command=of.OFPFC_DELETE, table_id = temp_table_id)
            event.connection.send(msg)
    
        #Table 0 rule: Selection of tables
        #IP Packet Handling / TCP
        msg = nx.nx_flow_mod()
        msg.table_id = 0
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.priority = 65000
        msg.actions.append(nx.nx_multipath(dst = nx.NXM_NX_REG2))
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 1))
        event.connection.send(msg)
 
        #ARP Packet Handling
        msg = nx.nx_flow_mod()
        msg.table_id = 0
        msg.priority = 65001
        msg.match.eth_type = pkt.ethernet.ARP_TYPE
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 4))
        event.connection.send(msg)
        log.info("Table 0 done")
     
        #Table 1 Rules 
        # TBD: State Machine and Hash value
        # New flow function
        msg = nx.nx_flow_mod()
        msg.table_id = 1
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.priority = 65004
        # Signifying New flow
        msg.actions.append(nx.nx_reg_load(dst=nx.NXM_NX_REG0, value=0x0))
        # currently learning based on eth address
        # no hash
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 2))
        event.connection.send(msg)
 
        #Table 2 Rules

        #1. Sync (Should be a Sync)
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.NXM_NX_REG0 = 0
        msg.match.tcp_flags = 2
        msg.priority = 65001
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1,priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(fms(load=nx.NXM_NX_REG0, src=nx.nx_learn_src_immediate.u32(None, 1)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True ))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)

        #2. Sync Ack (Should be after sync)
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x12
        msg.priority = 65002
        msg.match.NXM_NX_REG0 = 1
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1,priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(fms(load=nx.NXM_NX_REG0, src=nx.nx_learn_src_immediate.u32(None, 2)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True ))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)

        
        #3. Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x010
        msg.priority = 65003
        msg.match.NXM_NX_REG0 = 2
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1,priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(fms(load=nx.NXM_NX_REG0, src=nx.nx_learn_src_immediate.u32(None, 3)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True ))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)

        #4. Fin
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x010
        msg.priority = 65003
        msg.match.NXM_NX_REG0 = 3
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1,priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(fms(load=nx.NXM_NX_REG0, src=nx.nx_learn_src_immediate.u32(None, 4)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True ))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)


        #5. Fin-Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x010
        msg.priority = 65003
        msg.match.NXM_NX_REG0 = 4
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1,priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(fms(load=nx.NXM_NX_REG0, src=nx.nx_learn_src_immediate.u32(None, 5)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True ))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)

        #7. Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x010
        msg.priority = 65003
        msg.match.NXM_NX_REG0 = 5
        # learn function for table 1
        learn = nx.nx_action_learn(table_id=1,priority=65111)
        learn.spec = [
            nx.flow_mod_spec(src=nx.nx_learn_src_field(nx.NXM_NX_REG2),
                             dst=nx.nx_learn_dst_match(nx.NXM_NX_REG2)),
        ]
        fms = nx.flow_mod_spec.new
        learn.spec.append(fms(load=nx.NXM_NX_REG0, src=nx.nx_learn_src_immediate.u32(None, 6)))
        learn.spec.append(fms(field=nx.NXM_NX_REG0, reserved=True ))
        msg.actions.append(learn)
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)

        #8. RST
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x14
        msg.priority = 65003
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)

        #9. PSH-Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x18
        msg.priority = 65003
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)

        #9. Ack
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_proto = ipv4.TCP_PROTOCOL
        msg.match.tcp_flags = 0x10
        msg.priority = 65003
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)

        #send to controller  currently sending to the destination as no old state stored
        msg = nx.nx_flow_mod()
        msg.table_id = 2
        msg.priority = 64999
        msg.actions.append(nx.nx_reg_load(dst=nx.NXM_NX_REG1, value=int(1)))
        msg.actions.append(nx.nx_action_resubmit.resubmit_table(table = 3))
        event.connection.send(msg)
        log.info("Table 2 done")


        #Table 3 Rules: Forward the packet to the Destination
        msg = nx.nx_flow_mod()
        msg.table_id = 3
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_dst = "10.0.0.1"
        msg.priority = 65001
        msg.actions.append(of.ofp_action_output(port = 1))
        event.connection.send(msg)

        msg = nx.nx_flow_mod()
        msg.table_id = 3
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_dst = "10.0.0.2"
        msg.priority = 65001
        msg.actions.append(of.ofp_action_output(port = 2))
        event.connection.send(msg)

        msg = nx.nx_flow_mod()
        msg.table_id = 3
        msg.match.eth_type = pkt.ethernet.IP_TYPE
        msg.match.ip_dst = "10.0.0.3"
        msg.priority = 65001
        msg.actions.append(of.ofp_action_output(port = 3))
        event.connection.send(msg)
       
        #send to controller 
        msg = nx.nx_flow_mod()
        msg.table_id = 3
        msg.match.NXM_NX_REG1 = 1 
        msg.priority = 65005
        msg.actions.append(of.ofp_action_output(port = of.OFPP_CONTROLLER))
        event.connection.send(msg)
        log.info("Table 3 done")
        
        #Table 4 Rules 
        msg = nx.nx_flow_mod()
        msg.table_id = 4
        msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
        event.connection.send(msg)
        log.info("Table 4 done")