Пример #1
0
def _handle_PacketIn(event):
    packet = event.parsed

    if packet.find("arp"):
        # Reply to ARP
        a = packet.find("arp")
        if a.opcode == a.REQUEST:
            r = pkt.arp()
            r.hwtype = a.hwtype
            r.prototype = a.prototype
            r.hwlen = a.hwlen
            r.protolen = a.protolen
            r.opcode = r.REPLY
            r.hwdst = a.hwsrc
            r.protodst = a.protosrc
            r.protosrc = a.protodst
            r.hwsrc = EthAddr("02:00:DE:AD:BE:EF")
            e = pkt.ethernet(type=packet.type, src=r.hwsrc, dst=a.hwsrc)
            e.payload = r

            msg = of.ofp_packet_out()
            msg.data = e.pack()
            msg.actions.append(of.ofp_action_output(port=of.OFPP_IN_PORT))
            msg.in_port = event.port
            event.connection.send(msg)

            log.info("%s ARPed for %s", r.protodst, r.protosrc)

    elif packet.find("icmp"):
        # Reply to pings

        # Make the ping reply
        icmp = pkt.icmp()
        icmp.type = pkt.TYPE_ECHO_REPLY
        icmp.payload = packet.find("icmp").payload

        # Make the IP packet around it
        ipp = pkt.ipv4()
        ipp.protocol = ipp.ICMP_PROTOCOL
        ipp.srcip = packet.find("ipv4").dstip
        ipp.dstip = packet.find("ipv4").srcip

        # Ethernet around that...
        e = pkt.ethernet()
        e.src = packet.dst
        e.dst = packet.src
        e.type = e.IP_TYPE

        # Hook them up...
        ipp.payload = icmp
        e.payload = ipp

        # Send it back to the input port
        msg = of.ofp_packet_out()
        msg.actions.append(of.ofp_action_output(port=of.OFPP_IN_PORT))
        msg.data = e.pack()
        msg.in_port = event.port
        event.connection.send(msg)

        log.debug("%s pinged %s", ipp.dstip, ipp.srcip)
Пример #2
0
 def drop():
     # Kill buffer on switch
     if event.ofp.buffer_id is not None:
         msg = of.ofp_packet_out()
         msg.buffer_id = event.ofp.buffer_id
         msg.in_port = event.port
         event.connection.send(msg)
Пример #3
0
def _handle_PacketIn(event):
    packet = event.parsed

    # Learn the source
    table[(event.connection, packet.src)] = event.port

    dst_port = table.get((event.connection, packet.dst))

    if dst_port is None:
        # We don't know where the destination is yet.  So, we'll just
        # send the packet out all ports (except the one it came in on!)
        # and hope the destination is out there somewhere. :)
        msg = of.ofp_packet_out(data=event.ofp)
        msg.actions.append(of.ofp_action_output(port=all_ports))
        event.connection.send(msg)
    else:
        # Since we know the switch ports for both the source and dest
        # MACs, we can install rules for both directions.
        msg = of.ofp_flow_mod()
        msg.match.dl_dst = packet.src
        msg.match.dl_src = packet.dst
        msg.actions.append(of.ofp_action_output(port=event.port))
        event.connection.send(msg)

        # This is the packet that just came in -- we want to
        # install the rule and also resend the packet.
        msg = of.ofp_flow_mod()
        msg.data = event.ofp  # Forward the incoming packet
        msg.match.dl_src = packet.src
        msg.match.dl_dst = packet.dst
        msg.actions.append(of.ofp_action_output(port=dst_port))
        event.connection.send(msg)

        log.debug("Installing %s <-> %s" % (packet.src, packet.dst))
Пример #4
0
  def reply (self, event, msg):
    orig = event.parsed.find('dhcp')
    broadcast = (orig.flags & orig.BROADCAST_FLAG) != 0
    msg.op = msg.BOOTREPLY
    msg.chaddr = event.parsed.src
    msg.htype = 1
    msg.hlen = 6
    msg.xid = orig.xid
    msg.add_option(pkt.DHCP.DHCPServerIdentifierOption(self.ip_addr))

    ethp = pkt.ethernet(src=ip_for_event(event),dst=event.parsed.src)
    ethp.type = pkt.ethernet.IP_TYPE
    ipp = pkt.ipv4(srcip = self.ip_addr)
    ipp.dstip = event.parsed.find('ipv4').srcip
    if broadcast:
      ipp.dstip = IP_BROADCAST
      ethp.dst = pkt.ETHERNET.ETHER_BROADCAST
    ipp.protocol = ipp.UDP_PROTOCOL
    udpp = pkt.udp()
    udpp.srcport = pkt.dhcp.SERVER_PORT
    udpp.dstport = pkt.dhcp.CLIENT_PORT
    udpp.payload = msg
    ipp.payload = udpp
    ethp.payload = ipp
    po = of.ofp_packet_out(data=ethp.pack())
    po.actions.append(of.ofp_action_output(port=event.port))
    event.connection.send(po)
Пример #5
0
    def _do_probe(self):
        """
    Send an ARP to a server to see if it's still up
    """
        self._do_expire()

        server = self.servers.pop(0)
        self.servers.append(server)

        r = arp()
        r.hwtype = r.HW_TYPE_ETHERNET
        r.prototype = r.PROTO_TYPE_IP
        r.opcode = r.REQUEST
        r.hwdst = ETHER_BROADCAST
        r.protodst = server
        r.hwsrc = self.mac
        r.protosrc = self.service_ip
        e = ethernet(type=ethernet.ARP_TYPE, src=self.mac, dst=ETHER_BROADCAST)
        e.set_payload(r)
        #self.log.debug("ARPing for %s", server)
        msg = of.ofp_packet_out()
        msg.data = e.pack()
        msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD))
        msg.in_port = of.OFPP_NONE
        self.con.send(msg)

        self.outstanding_probes[server] = time.time() + self.arp_timeout

        core.callDelayed(self._probe_wait_time, self._do_probe)
Пример #6
0
def send_arp_reply(reply_to, mac, src_mac=None, src_ip=None):
    """
  Send an ARP reply.

  src_mac can be None to use the "DPID MAC" or True to use the port Mac.
    (or it can be an EthAddr)
  """
    # reply_to should be a PacketIn event
    arpp = reply_to.parsed.find('arp')
    mac = EthAddr(mac)
    if src_mac is None:
        #src_mac = mac # Used to be this ???
        src_mac = reply_to.connection.eth_addr
    elif src_mac is True:
        src_mac = reply_to.connection.ports[reply_to.port].hw_addr
    else:
        src_mac = EthAddr(src_mac)
    r = arp()
    r.opcode = r.REPLY
    r.hwdst = arpp.hwsrc
    r.protodst = arpp.protosrc
    r.hwsrc = EthAddr(src_mac)
    r.protosrc = IPAddr("0.0.0.0") if src_ip is None else IPAddr(src_ip)
    e = ethernet(type=ethernet.ARP_TYPE, src=src_mac, dst=r.hwdst)
    e.payload = r
    msg = of.ofp_packet_out()
    msg.data = e.pack()
    msg.actions.append(of.ofp_action_output(port=reply_to.port))
    msg.in_port = of.OFPP_NONE
    reply_to.connection.send(msg)
Пример #7
0
 def sendPing(self, macEntry, ipAddr):
     """
 Builds an ETH/IP any-to-any ARP packet (an "ARP ping")
 """
     r = arp()
     r.opcode = arp.REQUEST
     r.hwdst = macEntry.macaddr
     r.hwsrc = self.ping_src_mac
     r.protodst = ipAddr
     # src is IP_ANY
     e = ethernet(type=ethernet.ARP_TYPE, src=r.hwsrc, dst=r.hwdst)
     e.payload = r
     log.debug("%i %i sending ARP REQ to %s %s", macEntry.dpid,
               macEntry.port, str(r.hwdst), str(r.protodst))
     msg = of.ofp_packet_out(
         data=e.pack(), action=of.ofp_action_output(port=macEntry.port))
     if core.openflow.sendToDPID(macEntry.dpid, msg.pack()):
         ipEntry = macEntry.ipAddrs[ipAddr]
         ipEntry.pings.sent()
     else:
         # macEntry is stale, remove it.
         log.debug("%i %i ERROR sending ARP REQ to %s %s", macEntry.dpid,
                   macEntry.port, str(r.hwdst), str(r.protodst))
         del macEntry.ipAddrs[ipAddr]
     return
Пример #8
0
  def create_discovery_packet (self, dpid, port_num, port_addr):
    """
    Build discovery packet
    """

    chassis_id = pkt.chassis_id(subtype=pkt.chassis_id.SUB_LOCAL)
    chassis_id.id = bytes('dpid:' + hex(long(dpid))[2:-1])
    # Maybe this should be a MAC.  But a MAC of what?  Local port, maybe?

    port_id = pkt.port_id(subtype=pkt.port_id.SUB_PORT, id=str(port_num))

    ttl = pkt.ttl(ttl = self._ttl)

    sysdesc = pkt.system_description()
    sysdesc.payload = bytes('dpid:' + hex(long(dpid))[2:-1])

    discovery_packet = pkt.lldp()
    discovery_packet.tlvs.append(chassis_id)
    discovery_packet.tlvs.append(port_id)
    discovery_packet.tlvs.append(ttl)
    discovery_packet.tlvs.append(sysdesc)
    discovery_packet.tlvs.append(pkt.end_tlv())

    eth = pkt.ethernet(type=pkt.ethernet.LLDP_TYPE)
    eth.src = port_addr
    eth.dst = pkt.ETHERNET.NDP_MULTICAST
    eth.payload = discovery_packet

    po = of.ofp_packet_out(action = of.ofp_action_output(port=port_num))
    po.data = eth.pack()
    return po.pack()
Пример #9
0
 def drop():
     # Kill the buffer
     if event.ofp.buffer_id is not None:
         msg = of.ofp_packet_out()
         msg.buffer_id = event.ofp.buffer_id
         event.ofp.buffer_id = None  # Mark is dead
         msg.in_port = event.port
         self.connection.send(msg)
Пример #10
0
    def _handle_PacketIn(self, event):
        dpid = event.connection.dpid
        inport = event.port
        packet = event.parsed

        a = packet.find('arp')
        if not a: return

        if a.prototype != arp.PROTO_TYPE_IP:
            return

        if a.hwtype != arp.HW_TYPE_ETHERNET:
            return

        if a.opcode == arp.REQUEST:
            log.debug("%s ARP request %s => %s", dpid_to_str(dpid), a.protosrc,
                      a.protodst)

            if self.use_port_mac:
                src_mac = event.connection.ports[inport].hw_addr
            else:
                src_mac = event.connection.eth_addr
            ev = ARPRequest(event.connection, a, src_mac, self.eat_packets,
                            inport)
            self.raiseEvent(ev)
            if ev.reply is not None:
                r = arp()
                r.hwtype = a.hwtype
                r.prototype = a.prototype
                r.hwlen = a.hwlen
                r.protolen = a.protolen
                r.opcode = arp.REPLY
                r.hwdst = a.hwsrc
                r.protodst = a.protosrc
                r.protosrc = a.protodst
                r.hwsrc = EthAddr(ev.reply)
                e = ethernet(type=packet.type, src=ev.reply_from, dst=a.hwsrc)
                e.payload = r
                log.debug("%s answering ARP for %s" %
                          (dpid_to_str(dpid), str(r.protosrc)))
                msg = of.ofp_packet_out()
                msg.data = e.pack()
                msg.actions.append(of.ofp_action_output(port=of.OFPP_IN_PORT))
                msg.in_port = inport
                event.connection.send(msg)
                return EventHalt if ev.eat_packet else None

        elif a.opcode == arp.REPLY:
            log.debug("%s ARP reply %s => %s", dpid_to_str(dpid), a.protosrc,
                      a.hwsrc)

            ev = ARPReply(event.connection, a, self.eat_packets, inport)
            self.raiseEvent(ev)
            return EventHalt if ev.eat_packet else None

        return EventHalt if self.eat_packets else None
Пример #11
0
 def flood():
     """ Floods the packet """
     if self.is_holding_down:
         log.warning("Not flooding -- holddown active")
     msg = of.ofp_packet_out()
     # OFPP_FLOOD is optional; some switches may need OFPP_ALL
     msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD))
     msg.buffer_id = event.ofp.buffer_id
     msg.in_port = event.port
     self.connection.send(msg)
Пример #12
0
    def install_path(self, dst_sw, last_port, match, event):
        """
    Attempts to install a path between this switch and some destination
    """
        p = _get_path(self, dst_sw, event.port, last_port)
        if p is None:
            log.warning("Can't get from %s to %s", match.dl_src, match.dl_dst)

            import pox.lib.packet as pkt

            if (match.dl_type == pkt.ethernet.IP_TYPE
                    and event.parsed.find('ipv4')):
                # It's IP -- let's send a destination unreachable
                log.debug("Dest unreachable (%s -> %s)", match.dl_src,
                          match.dl_dst)

                from pox.lib.addresses import EthAddr
                e = pkt.ethernet()
                e.src = EthAddr(dpid_to_str(self.dpid))  #FIXME: Hmm...
                e.dst = match.dl_src
                e.type = e.IP_TYPE
                ipp = pkt.ipv4()
                ipp.protocol = ipp.ICMP_PROTOCOL
                ipp.srcip = match.nw_dst  #FIXME: Ridiculous
                ipp.dstip = match.nw_src
                icmp = pkt.icmp()
                icmp.type = pkt.ICMP.TYPE_DEST_UNREACH
                icmp.code = pkt.ICMP.CODE_UNREACH_HOST
                orig_ip = event.parsed.find('ipv4')

                d = orig_ip.pack()
                d = d[:orig_ip.hl * 4 + 8]
                import struct
                d = struct.pack("!HH", 0, 0) + d  #FIXME: MTU
                icmp.payload = d
                ipp.payload = icmp
                e.payload = ipp
                msg = of.ofp_packet_out()
                msg.actions.append(of.ofp_action_output(port=event.port))
                msg.data = e.pack()
                self.connection.send(msg)

            return

        log.debug("Installing path for %s -> %s %04x (%i hops)", match.dl_src,
                  match.dl_dst, match.dl_type, len(p))

        # We have a path -- install it
        self._install_path(p, match, event.ofp)

        # Now reverse it and install it backwards
        # (we'll just assume that will work)
        p = [(sw, out_port, in_port) for sw, in_port, out_port in p]
        self._install_path(p, match.flip())
Пример #13
0
    def notify(self, event):
        """
    Called when a barrier has been received
    """
        self.xids.discard((event.dpid, event.xid))
        if len(self.xids) == 0:
            # Done!
            if self.packet:
                log.debug("Sending delayed packet out %s" %
                          (dpid_to_str(self.first_switch), ))
                msg = of.ofp_packet_out(
                    data=self.packet,
                    action=of.ofp_action_output(port=of.OFPP_TABLE))
                core.openflow.sendToDPID(self.first_switch, msg)

            core.l2_multi.raiseEvent(PathInstalled(self.path))
Пример #14
0
 def _send_lost_buffers (self, dpid, ipaddr, macaddr, port):
   """
   We may have "lost" buffers -- packets we got but didn't know
   where to send at the time.  We may know now.  Try and see.
   """
   if (dpid,ipaddr) in self.lost_buffers:
     # Yup!
     bucket = self.lost_buffers[(dpid,ipaddr)]
     del self.lost_buffers[(dpid,ipaddr)]
     log.debug("Sending %i buffered packets to %s from %s"
               % (len(bucket),ipaddr,dpid_to_str(dpid)))
     for _,buffer_id,in_port in bucket:
       po = of.ofp_packet_out(buffer_id=buffer_id,in_port=in_port)
       po.actions.append(of.ofp_action_dl_addr.set_dst(macaddr))
       po.actions.append(of.ofp_action_output(port = port))
       core.openflow.sendToDPID(dpid, po)
Пример #15
0
 def _send_dhcp(self, msg):
     ethp = pkt.ethernet(src=self.port_eth, dst=pkt.ETHER_BROADCAST)
     ethp.type = pkt.ethernet.IP_TYPE
     ipp = pkt.ipv4()
     ipp.srcip = pkt.IP_ANY  #NOTE: If rebinding, use existing local IP?
     ipp.dstip = pkt.IP_BROADCAST
     ipp.protocol = ipp.UDP_PROTOCOL
     udpp = pkt.udp()
     udpp.srcport = pkt.dhcp.CLIENT_PORT
     udpp.dstport = pkt.dhcp.SERVER_PORT
     udpp.payload = msg
     ipp.payload = udpp
     ethp.payload = ipp
     po = of.ofp_packet_out(data=ethp.pack())
     po.actions.append(of.ofp_action_output(port=self.portno))
     self._con.send(po)
Пример #16
0
  def _handle_expiration (self):
    # Called by a timer so that we can remove old items.
    empty = []
    for k,v in self.lost_buffers.iteritems():
      dpid,ip = k

      for item in list(v):
        expires_at,buffer_id,in_port = item
        if expires_at < time.time():
          # This packet is old.  Tell this switch to drop it.
          v.remove(item)
          po = of.ofp_packet_out(buffer_id = buffer_id, in_port = in_port)
          core.openflow.sendToDPID(dpid, po)
      if len(v) == 0: empty.append(k)

    # Remove empty buffer bins
    for k in empty:
      del self.lost_buffers[k]
Пример #17
0
def send_arp_request(connection,
                     ip,
                     port=of.OFPP_FLOOD,
                     src_mac=None,
                     src_ip=None):
    """
  Send an ARP request

  src_mac can be None to use the "DPID MAC" or True to use the port Mac.
    (or it can be an EthAddr)
  """
    if src_mac is None:
        src_mac = connection.eth_addr
    elif src_mac is True:
        if port in (of.OFPP_FLOOD, of.OFPP_ALL):
            for p in connection.ports.values():
                if p.config & OFPPC_NO_FLOOD:
                    if port == of.ofPP_FLOOD:
                        continue
                if p.port_no < 0: continue
                if p.port_no > of.OFPP_MAX: continue  # Off by one?
                send_arp_request(connection,
                                 ip,
                                 p.port_no,
                                 src_mac=p.hw_addr,
                                 src_ip=src_ip)
            return
        src_mac = connection.ports[port].hw_addr
    else:
        src_mac = EthAddr(src_mac)
    r = arp()
    r.opcode = r.REQUEST
    r.hwdst = ETHER_BROADCAST
    r.protodst = IPAddr(ip)
    r.hwsrc = src_mac
    r.protosrc = IPAddr("0.0.0.0") if src_ip is None else IPAddr(src_ip)
    e = ethernet(type=ethernet.ARP_TYPE, src=src_mac, dst=r.hwdst)
    e.payload = r
    msg = of.ofp_packet_out()
    msg.data = e.pack()
    msg.actions.append(of.ofp_action_output(port=port))
    msg.in_port = of.OFPP_NONE
    connection.send(msg)
Пример #18
0
    def resend_packet(self, packet_in, out_port):
        """
    Instructs the switch to resend a packet that it had sent to us.
    "packet_in" is the ofp_packet_in object the switch had sent to the
    controller due to a table-miss.
    """
        msg = of.ofp_packet_out()
        msg.data = packet_in

        # Add an action to send to the specified port
        action = of.ofp_action_output(port=out_port)
        msg.actions.append(action)

        log.debug(" OF_TUTORIAL : Message being sent on the connection : %s " %
                  msg)
        # Send message to switch
        self.connection.send(msg)
        log.debug(" OF_TUTORIAL : Message sent to the switch")
        log.debug(" OF_TUTORIAL : --------------------------")
Пример #19
0
   def drop(duration=None):
       """
 Drops this packet and optionally installs a flow to continue
 dropping similar ones for a while
 """
       if duration is not None:
           if not isinstance(duration, tuple):
               duration = (duration, duration)
           msg = of.ofp_flow_mod()
           msg.match = of.ofp_match.from_packet(packet)
           msg.idle_timeout = duration[0]
           msg.hard_timeout = duration[1]
           msg.buffer_id = event.ofp.buffer_id
           self.connection.send(msg)
       elif event.ofp.buffer_id is not None:
           msg = of.ofp_packet_out()
           msg.buffer_id = event.ofp.buffer_id
           msg.in_port = event.port
           self.connection.send(msg)
Пример #20
0
    def resend_packet_face(self, packet_in, face):
        """
    Instructs the switch to resend a packet that it had sent to us.
    "packet_in" is the ofp_packet_in object the switch had sent to the
    controller due to a table-miss.
    """
        print(
            "\n Sending PACKET_OUT message to switch to send the packet in a face\n"
        )
        msg = of.ofp_packet_out()
        msg.data = packet_in

        # Add an action to send to the specified port
        action = of.ofp_action_outputface(face=face)
        msg.actions.append(action)

        log.debug(" OF_TUTORIAL : Message being sent on the connection : %s " %
                  msg)
        # Send message to switch
        self.connection.send(msg)
        log.debug(" OF_TUTORIAL : Message sent to the switch")
        log.debug(" OF_TUTORIAL : --------------------------")
Пример #21
0
def dict_to_packet_out(d):
    """
  Converts dict to packet_out
  Also, special key "output" is an output port.
  """
    po = of.ofp_packet_out()
    po.buffer_id = d.get('buffer_id', -1)
    po.in_port = _fix_of_int(d.get('in_port', of.OFPP_NONE))
    actions = d.get('actions', [])
    actions = [dict_to_action(a) for a in actions]
    po.actions = actions
    if 'output' in d:
        a = of.ofp_action_output(port=_fix_of_int(d['output']))
        po.actions.append(a)

    if 'data' in d:
        data = dict_to_packet(d['data'])
        if hasattr(data, 'pack'):
            data = data.pack()
        po.data = data

    return po
Пример #22
0
        def flood(message=None):
            """ Floods the packet """
            msg = of.ofp_packet_out()
            if time.time() - self.connection.connect_time >= _flood_delay:
                # Only flood if we've been connected for a little while...

                if self.hold_down_expired is False:
                    # Oh yes it is!
                    self.hold_down_expired = True
                    log.info("%s: Flood hold-down expired -- flooding",
                             dpid_to_str(event.dpid))

                if message is not None: log.debug(message)
                #log.debug("%i: flood %s -> %s", event.dpid,packet.src,packet.dst)
                # OFPP_FLOOD is optional; on some switches you may need to change
                # this to OFPP_ALL.
                msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD))
            else:
                pass
                #log.info("Holding down flood for %s", dpid_to_str(event.dpid))
            msg.data = event.ofp
            msg.in_port = event.port
            self.connection.send(msg)
Пример #23
0
def _handle_PacketIn(event):
    """
  Handle messages the switch has sent us because it has no
  matching rule.
  """
    def drop():
        # Kill buffer on switch
        if event.ofp.buffer_id is not None:
            msg = of.ofp_packet_out()
            msg.buffer_id = event.ofp.buffer_id
            msg.in_port = event.port
            event.connection.send(msg)

    packet = event.parsed

    if packet.type == packet.LLDP_TYPE or packet.dst.isBridgeFiltered():
        return drop()

    # Learn the source
    table[(event.connection, packet.src)] = event.port

    if not packet.dst.is_multicast:
        dst_port = table.get((event.connection, packet.dst))
    else:
        # Ideally, we'd install a flow entries that output multicasts
        # to all ports on the spanning tree.
        dst_port = None

    if dst_port is None:
        # We don't know where the destination is yet.  So, we'll just
        # send the packet out all ports in the spanning tree
        # and hope the destination is out there somewhere. :)
        msg = of.ofp_packet_out(data=event.ofp)

        tree_ports = [p[1] for p in tree.get(event.dpid, [])]

        for p in event.connection.ports:
            if p >= of.OFPP_MAX:
                # Not a normal port
                continue

            if not core.openflow_discovery.is_edge_port(event.dpid, p):
                # If the port isn't a switch-to-switch port, it's fine to flood
                # through it.  But if it IS a switch-to-switch port, we only
                # want to use it if it's on the spanning tree.
                if p not in tree_ports:
                    continue

            msg.actions.append(of.ofp_action_output(port=p))

        event.connection.send(msg)

    else:
        # Since we know the switch ports for both the source and dest
        # MACs, we can install rules for both directions.
        msg = of.ofp_flow_mod()
        msg.match.dl_dst = packet.src
        msg.match.dl_src = packet.dst
        msg.actions.append(of.ofp_action_output(port=event.port))
        event.connection.send(msg)

        # This is the packet that just came in -- we want to
        # install the rule and also resend the packet.
        msg = of.ofp_flow_mod()
        msg.data = event.ofp  # Forward the incoming packet
        msg.match.dl_src = packet.src
        msg.match.dl_dst = packet.dst
        msg.actions.append(of.ofp_action_output(port=dst_port))
        event.connection.send(msg)

        log.debug("Installing %s <-> %s" % (packet.src, packet.dst))
Пример #24
0
 def drop():
     if event.ofp.buffer_id is not None:
         # Kill the buffer
         msg = of.ofp_packet_out(data=event.ofp)
         self.con.send(msg)
     return None
Пример #25
0
  def _handle_openflow_PacketIn (self, event):
    """
    Receive and process LLDP packets
    """

    packet = event.parsed

    if (packet.effective_ethertype != pkt.ethernet.LLDP_TYPE
        or packet.dst != pkt.ETHERNET.NDP_MULTICAST):
      if not self._eat_early_packets: return
      if not event.connection.connect_time: return
      enable_time = time.time() - self.send_cycle_time - 1
      if event.connection.connect_time > enable_time:
        return EventHalt
      return

    if self._explicit_drop:
      if event.ofp.buffer_id is not None:
        log.debug("Dropping LLDP packet %i", event.ofp.buffer_id)
        msg = of.ofp_packet_out()
        msg.buffer_id = event.ofp.buffer_id
        msg.in_port = event.port
        event.connection.send(msg)

    lldph = packet.find(pkt.lldp)
    if lldph is None or not lldph.parsed:
      log.error("LLDP packet could not be parsed")
      return EventHalt
    if len(lldph.tlvs) < 3:
      log.error("LLDP packet without required three TLVs")
      return EventHalt
    if lldph.tlvs[0].tlv_type != pkt.lldp.CHASSIS_ID_TLV:
      log.error("LLDP packet TLV 1 not CHASSIS_ID")
      return EventHalt
    if lldph.tlvs[1].tlv_type != pkt.lldp.PORT_ID_TLV:
      log.error("LLDP packet TLV 2 not PORT_ID")
      return EventHalt
    if lldph.tlvs[2].tlv_type != pkt.lldp.TTL_TLV:
      log.error("LLDP packet TLV 3 not TTL")
      return EventHalt

    def lookInSysDesc ():
      r = None
      for t in lldph.tlvs[3:]:
        if t.tlv_type == pkt.lldp.SYSTEM_DESC_TLV:
          # This is our favored way...
          for line in t.payload.split('\n'):
            if line.startswith('dpid:'):
              try:
                return int(line[5:], 16)
              except:
                pass
          if len(t.payload) == 8:
            # Maybe it's a FlowVisor LLDP...
            # Do these still exist?
            try:
              return struct.unpack("!Q", t.payload)[0]
            except:
              pass
          return None

    originatorDPID = lookInSysDesc()

    if originatorDPID == None:
      # We'll look in the CHASSIS ID
      if lldph.tlvs[0].subtype == pkt.chassis_id.SUB_LOCAL:
        if lldph.tlvs[0].id.startswith('dpid:'):
          # This is how NOX does it at the time of writing
          try:
            originatorDPID = int(lldph.tlvs[0].id[5:], 16)
          except:
            pass
      if originatorDPID == None:
        if lldph.tlvs[0].subtype == pkt.chassis_id.SUB_MAC:
          # Last ditch effort -- we'll hope the DPID was small enough
          # to fit into an ethernet address
          if len(lldph.tlvs[0].id) == 6:
            try:
              s = lldph.tlvs[0].id
              originatorDPID = struct.unpack("!Q",'\x00\x00' + s)[0]
            except:
              pass

    if originatorDPID == None:
      log.warning("Couldn't find a DPID in the LLDP packet")
      return EventHalt

    if originatorDPID not in core.openflow.connections:
      log.info('Received LLDP packet from unknown switch')
      return EventHalt

    # Get port number from port TLV
    if lldph.tlvs[1].subtype != pkt.port_id.SUB_PORT:
      log.warning("Thought we found a DPID, but packet didn't have a port")
      return EventHalt
    originatorPort = None
    if lldph.tlvs[1].id.isdigit():
      # We expect it to be a decimal value
      originatorPort = int(lldph.tlvs[1].id)
    elif len(lldph.tlvs[1].id) == 2:
      # Maybe it's a 16 bit port number...
      try:
        originatorPort  =  struct.unpack("!H", lldph.tlvs[1].id)[0]
      except:
        pass
    if originatorPort is None:
      log.warning("Thought we found a DPID, but port number didn't " +
                  "make sense")
      return EventHalt

    if (event.dpid, event.port) == (originatorDPID, originatorPort):
      log.warning("Port received its own LLDP packet; ignoring")
      return EventHalt

    link = Discovery.Link(originatorDPID, originatorPort, event.dpid,
                          event.port)

    if link not in self.adjacency:
      self.adjacency[link] = time.time()
      log.info('link detected: %s', link)
      self.raiseEventNoErrors(LinkEvent, True, link)
    else:
      # Just update timestamp
      self.adjacency[link] = time.time()

    return EventHalt # Probably nobody else needs this event
Пример #26
0
  def _handle_PacketIn (self, event):
    # Note: arp.hwsrc is not necessarily equal to ethernet.src
    # (one such example are arp replies generated by this module itself
    # as ethernet mac is set to switch dpid) so we should be careful
    # to use only arp addresses in the learning code!
    squelch = False

    dpid = event.connection.dpid
    inport = event.port
    packet = event.parsed
    if not packet.parsed:
      log.warning("%s: ignoring unparsed packet", dpid_to_str(dpid))
      return

    a = packet.find('arp')
    if not a: return

    log.debug("%s ARP %s %s => %s", dpid_to_str(dpid),
      {arp.REQUEST:"request",arp.REPLY:"reply"}.get(a.opcode,
      'op:%i' % (a.opcode,)), str(a.protosrc), str(a.protodst))

    if a.prototype == arp.PROTO_TYPE_IP:
      if a.hwtype == arp.HW_TYPE_ETHERNET:
        if a.protosrc != 0:

          if _learn:
            # Learn or update port/MAC info
            if a.protosrc in _arp_table:
              if _arp_table[a.protosrc] != a.hwsrc:
                log.warn("%s RE-learned %s: %s->%s", dpid_to_str(dpid),
                    a.protosrc, _arp_table[a.protosrc].mac, a.hwsrc)
            else:
              log.info("%s learned %s", dpid_to_str(dpid), a.protosrc)
            _arp_table[a.protosrc] = Entry(a.hwsrc)

          if a.opcode == arp.REQUEST:
            # Maybe we can answer

            if a.protodst in _arp_table:
              # We have an answer...

              r = arp()
              r.hwtype = a.hwtype
              r.prototype = a.prototype
              r.hwlen = a.hwlen
              r.protolen = a.protolen
              r.opcode = arp.REPLY
              r.hwdst = a.hwsrc
              r.protodst = a.protosrc
              r.protosrc = a.protodst
              mac = _arp_table[a.protodst].mac
              if mac is True:
                # Special case -- use ourself
                mac = _dpid_to_mac(dpid)
              r.hwsrc = mac
              e = ethernet(type=packet.type, src=_dpid_to_mac(dpid),
                            dst=a.hwsrc)
              e.payload = r
              if packet.type == ethernet.VLAN_TYPE:
                v_rcv = packet.find('vlan')
                e.payload = vlan(eth_type = e.type,
                                 payload = e.payload,
                                 id = v_rcv.id,
                                 pcp = v_rcv.pcp)
                e.type = ethernet.VLAN_TYPE
              log.info("%s answering ARP for %s" % (dpid_to_str(dpid),
                str(r.protosrc)))
              msg = of.ofp_packet_out()
              msg.data = e.pack()
              msg.actions.append(of.ofp_action_output(port =
                                                      of.OFPP_IN_PORT))
              msg.in_port = inport
              event.connection.send(msg)
              return EventHalt if _eat_packets else None
            else:
              # Keep track of failed queries
              squelch = a.protodst in _failed_queries
              _failed_queries[a.protodst] = time.time()

    if self._check_for_flood(dpid, a):
      # Didn't know how to handle this ARP, so just flood it
      msg = "%s flooding ARP %s %s => %s" % (dpid_to_str(dpid),
          {arp.REQUEST:"request",arp.REPLY:"reply"}.get(a.opcode,
          'op:%i' % (a.opcode,)), a.protosrc, a.protodst)

      if squelch:
        log.debug(msg)
      else:
        log.info(msg)

      msg = of.ofp_packet_out()
      msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
      msg.data = event.ofp
      event.connection.send(msg.pack())

    return EventHalt if _eat_packets else None
Пример #27
0
  def _handle_PacketIn (self, event):
    dpid = event.connection.dpid
    inport = event.port
    packet = event.parsed
    if not packet.parsed:
      log.warning("%i %i ignoring unparsed packet", dpid, inport)
      return

    if dpid not in self.arpTable:
      # New switch -- create an empty table
      self.arpTable[dpid] = {}
      for fake in self.fakeways:
        self.arpTable[dpid][IPAddr(fake)] = Entry(of.OFPP_NONE,
         dpid_to_mac(dpid))

    if packet.type == ethernet.LLDP_TYPE:
      # Ignore LLDP packets
      return

    if isinstance(packet.next, ipv4):
      log.debug("%i %i IP %s => %s", dpid,inport,
                packet.next.srcip,packet.next.dstip)

      # Send any waiting packets...
      self._send_lost_buffers(dpid, packet.next.srcip, packet.src, inport)

      # Learn or update port/MAC info
      if packet.next.srcip in self.arpTable[dpid]:
        if self.arpTable[dpid][packet.next.srcip] != (inport, packet.src):
          log.info("%i %i RE-learned %s", dpid,inport,packet.next.srcip)
      else:
        log.debug("%i %i learned %s", dpid,inport,str(packet.next.srcip))
      self.arpTable[dpid][packet.next.srcip] = Entry(inport, packet.src)

      # Try to forward
      dstaddr = packet.next.dstip
      if dstaddr in self.arpTable[dpid]:
        # We have info about what port to send it out on...

        prt = self.arpTable[dpid][dstaddr].port
        mac = self.arpTable[dpid][dstaddr].mac
        if prt == inport:
          log.warning("%i %i not sending packet for %s back out of the " +
                      "input port" % (dpid, inport, str(dstaddr)))
        else:
          log.debug("%i %i installing flow for %s => %s out port %i"
                    % (dpid, inport, packet.next.srcip, dstaddr, prt))

          actions = []
          actions.append(of.ofp_action_dl_addr.set_dst(mac))
          actions.append(of.ofp_action_output(port = prt))
          match = of.ofp_match.from_packet(packet, inport)
          match.dl_src = None # Wildcard source MAC

          msg = of.ofp_flow_mod(command=of.OFPFC_ADD,
                                idle_timeout=FLOW_IDLE_TIMEOUT,
                                hard_timeout=of.OFP_FLOW_PERMANENT,
                                buffer_id=event.ofp.buffer_id,
                                actions=actions,
                                match=of.ofp_match.from_packet(packet,
                                                               inport))
          event.connection.send(msg.pack())
      elif self.arp_for_unknowns:
        # We don't know this destination.
        # First, we track this buffer so that we can try to resend it later
        # if we learn the destination, second we ARP for the destination,
        # which should ultimately result in it responding and us learning
        # where it is

        # Add to tracked buffers
        if (dpid,dstaddr) not in self.lost_buffers:
          self.lost_buffers[(dpid,dstaddr)] = []
        bucket = self.lost_buffers[(dpid,dstaddr)]
        entry = (time.time() + MAX_BUFFER_TIME,event.ofp.buffer_id,inport)
        bucket.append(entry)
        while len(bucket) > MAX_BUFFERED_PER_IP: del bucket[0]

        # Expire things from our outstanding ARP list...
        self.outstanding_arps = {k:v for k,v in
         self.outstanding_arps.iteritems() if v > time.time()}

        # Check if we've already ARPed recently
        if (dpid,dstaddr) in self.outstanding_arps:
          # Oop, we've already done this one recently.
          return

        # And ARP...
        self.outstanding_arps[(dpid,dstaddr)] = time.time() + 4

        r = arp()
        r.hwtype = r.HW_TYPE_ETHERNET
        r.prototype = r.PROTO_TYPE_IP
        r.hwlen = 6
        r.protolen = r.protolen
        r.opcode = r.REQUEST
        r.hwdst = ETHER_BROADCAST
        r.protodst = dstaddr
        r.hwsrc = packet.src
        r.protosrc = packet.next.srcip
        e = ethernet(type=ethernet.ARP_TYPE, src=packet.src,
                     dst=ETHER_BROADCAST)
        e.set_payload(r)
        log.debug("%i %i ARPing for %s on behalf of %s" % (dpid, inport,
         str(r.protodst), str(r.protosrc)))
        msg = of.ofp_packet_out()
        msg.data = e.pack()
        msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
        msg.in_port = inport
        event.connection.send(msg)

    elif isinstance(packet.next, arp):
      a = packet.next
      log.debug("%i %i ARP %s %s => %s", dpid, inport,
       {arp.REQUEST:"request",arp.REPLY:"reply"}.get(a.opcode,
       'op:%i' % (a.opcode,)), str(a.protosrc), str(a.protodst))

      if a.prototype == arp.PROTO_TYPE_IP:
        if a.hwtype == arp.HW_TYPE_ETHERNET:
          if a.protosrc != 0:

            # Learn or update port/MAC info
            if a.protosrc in self.arpTable[dpid]:
              if self.arpTable[dpid][a.protosrc] != (inport, packet.src):
                log.info("%i %i RE-learned %s", dpid,inport,str(a.protosrc))
            else:
              log.debug("%i %i learned %s", dpid,inport,str(a.protosrc))
            self.arpTable[dpid][a.protosrc] = Entry(inport, packet.src)

            # Send any waiting packets...
            self._send_lost_buffers(dpid, a.protosrc, packet.src, inport)

            if a.opcode == arp.REQUEST:
              # Maybe we can answer

              if a.protodst in self.arpTable[dpid]:
                # We have an answer...

                if not self.arpTable[dpid][a.protodst].isExpired():
                  # .. and it's relatively current, so we'll reply ourselves

                  r = arp()
                  r.hwtype = a.hwtype
                  r.prototype = a.prototype
                  r.hwlen = a.hwlen
                  r.protolen = a.protolen
                  r.opcode = arp.REPLY
                  r.hwdst = a.hwsrc
                  r.protodst = a.protosrc
                  r.protosrc = a.protodst
                  r.hwsrc = self.arpTable[dpid][a.protodst].mac
                  e = ethernet(type=packet.type, src=dpid_to_mac(dpid),
                               dst=a.hwsrc)
                  e.set_payload(r)
                  log.debug("%i %i answering ARP for %s" % (dpid, inport,
                   str(r.protosrc)))
                  msg = of.ofp_packet_out()
                  msg.data = e.pack()
                  msg.actions.append(of.ofp_action_output(port =
                                                          of.OFPP_IN_PORT))
                  msg.in_port = inport
                  event.connection.send(msg)
                  return

      # Didn't know how to answer or otherwise handle this ARP, so just flood it
      log.debug("%i %i flooding ARP %s %s => %s" % (dpid, inport,
       {arp.REQUEST:"request",arp.REPLY:"reply"}.get(a.opcode,
       'op:%i' % (a.opcode,)), str(a.protosrc), str(a.protodst)))

      msg = of.ofp_packet_out(in_port = inport, data = event.ofp,
          action = of.ofp_action_output(port = of.OFPP_FLOOD))
      event.connection.send(msg)