Example #1
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))
Example #2
0
 def _handle_ConnectionUp (self, event):
   if _install_flow:
     fm = of.ofp_flow_mod()
     fm.priority = 0x7000 # Pretty high
     fm.match.dl_type = ethernet.ARP_TYPE
     fm.actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER))
     event.connection.send(fm)
Example #3
0
 def clear_table(self, xid=None):
     fm = of.ofp_flow_mod()
     fm.xid = xid
     fm.command = of.OFPFC_DELETE
     self._con.send(fm)
     bar = of.ofp_barrier_request()
     bar.xid = xid
     self._con.send(bar)
Example #4
0
 def _install(self, switch, in_port, out_port, match, buf=None):
     msg = of.ofp_flow_mod()
     msg.match = match
     msg.match.in_port = in_port
     msg.idle_timeout = FLOW_IDLE_TIMEOUT
     msg.hard_timeout = FLOW_HARD_TIMEOUT
     msg.actions.append(of.ofp_action_output(port=out_port))
     msg.buffer_id = buf
     switch.connection.send(msg)
Example #5
0
 def _handle_ConnectionUp (self, event):
   if self._install_flow:
     msg = of.ofp_flow_mod()
     msg.match = of.ofp_match()
     msg.match.dl_type = pkt.ethernet.IP_TYPE
     msg.match.nw_proto = pkt.ipv4.UDP_PROTOCOL
     msg.match.tp_src = 53
     msg.actions.append(of.ofp_action_output(port = of.OFPP_CONTROLLER))
     event.connection.send(msg)
Example #6
0
    def _handle_LinkEvent(self, event):
        def flip(link):
            return Discovery.Link(link[2], link[3], link[0], link[1])

        l = event.link
        sw1 = switches[l.dpid1]
        sw2 = switches[l.dpid2]

        # Invalidate all flows and path info.
        # For link adds, this makes sure that if a new link leads to an
        # improved path, we use it.
        # For link removals, this makes sure that we don't use a
        # path that may have been broken.
        #NOTE: This could be radically improved! (e.g., not *ALL* paths break)
        clear = of.ofp_flow_mod(command=of.OFPFC_DELETE)
        for sw in switches.itervalues():
            if sw.connection is None: continue
            sw.connection.send(clear)
        path_map.clear()

        if event.removed:
            # This link no longer okay
            if sw2 in adjacency[sw1]: del adjacency[sw1][sw2]
            if sw1 in adjacency[sw2]: del adjacency[sw2][sw1]

            # But maybe there's another way to connect these...
            for ll in core.openflow_discovery.adjacency:
                if ll.dpid1 == l.dpid1 and ll.dpid2 == l.dpid2:
                    if flip(ll) in core.openflow_discovery.adjacency:
                        # Yup, link goes both ways
                        adjacency[sw1][sw2] = ll.port1
                        adjacency[sw2][sw1] = ll.port2
                        # Fixed -- new link chosen to connect these
                        break
        else:
            # If we already consider these nodes connected, we can
            # ignore this link up.
            # Otherwise, we might be interested...
            if adjacency[sw1][sw2] is None:
                # These previously weren't connected.  If the link
                # exists in both directions, we consider them connected now.
                if flip(l) in core.openflow_discovery.adjacency:
                    # Yup, link goes both ways -- connected!
                    adjacency[sw1][sw2] = l.port1
                    adjacency[sw2][sw1] = l.port2

            # If we have learned a MAC on this port which we now know to
            # be connected to a switch, unlearn it.
            bad_macs = set()
            for mac, (sw, port) in mac_map.iteritems():
                if sw is sw1 and port == l.port1: bad_macs.add(mac)
                if sw is sw2 and port == l.port2: bad_macs.add(mac)
            for mac in bad_macs:
                log.debug("Unlearned %s", mac)
                del mac_map[mac]
Example #7
0
    def _send_rewrite_rule(self, ip, mac):
        p = ipinfo(ip)[1]

        msg = of.ofp_flow_mod()
        msg.match = of.ofp_match()
        msg.match.dl_type = pkt.ethernet.IP_TYPE
        msg.match.nw_dst = ip
        msg.actions.append(of.ofp_action_dl_addr.set_src(self.mac))
        msg.actions.append(of.ofp_action_dl_addr.set_dst(mac))
        msg.actions.append(of.ofp_action_output(port=p))
        self.connection.send(msg)
Example #8
0
 def _handle_ConnectionUp (self, event):
   if self._install_flow:
     msg = of.ofp_flow_mod()
     msg.match = of.ofp_match()
     msg.match.dl_type = pkt.ethernet.IP_TYPE
     msg.match.nw_proto = pkt.ipv4.UDP_PROTOCOL
     #msg.match.nw_dst = IP_BROADCAST
     msg.match.tp_src = pkt.dhcp.CLIENT_PORT
     msg.match.tp_dst = pkt.dhcp.SERVER_PORT
     msg.actions.append(of.ofp_action_output(port = of.OFPP_CONTROLLER))
     #msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
     event.connection.send(msg)
Example #9
0
    def _handle_openflow_ConnectionUp(self, event):
        if not self.install_flow: return

        log.debug("Installing flow for ARP ping responses")

        m = of.ofp_flow_mod()
        m.priority += 1  # Higher than normal
        m.match.dl_type = ethernet.ARP_TYPE
        m.match.dl_dst = self.ping_src_mac

        m.actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER))
        event.connection.send(m)
Example #10
0
    def _start(self, connection):
        self._connection = connection

        self._outside_portno = connection.ports[self.outside_port].port_no

        fm = of.ofp_flow_mod()
        fm.match.in_port = self._outside_portno
        fm.priority = 1
        connection.send(fm)

        fm = of.ofp_flow_mod()
        fm.match.in_port = self._outside_portno
        fm.match.dl_type = 0x800  # IP
        fm.match.nw_dst = self.outside_ip
        fm.actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER))
        fm.priority = 2
        connection.send(fm)

        connection.addListeners(self)

        # Need to find gateway MAC -- send an ARP
        self._arp_for_gateway()
Example #11
0
 def get_flow(broadcast=False):
     fm = of.ofp_flow_mod()
     if broadcast:
         fm.match.dl_dst = pkt.ETHER_BROADCAST
     else:
         fm.match.dl_dst = self.port_eth
     fm.match.in_port = self.portno
     fm.match.dl_type = pkt.ethernet.IP_TYPE
     fm.match.nw_proto = pkt.ipv4.UDP_PROTOCOL
     fm.match.tp_src = pkt.dhcp.SERVER_PORT
     fm.match.tp_dst = pkt.dhcp.CLIENT_PORT
     fm.priority += 1
     return fm
Example #12
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)
Example #13
0
  def install_flow (self, con_or_dpid, priority = None):
    if priority is None:
      priority = self._flow_priority
    if isinstance(con_or_dpid, (int,long)):
      con = core.openflow.connections.get(con_or_dpid)
      if con is None:
        log.warn("Can't install flow for %s", dpid_to_str(con_or_dpid))
        return False
    else:
      con = con_or_dpid

    match = of.ofp_match(dl_type = pkt.ethernet.LLDP_TYPE,
                          dl_dst = pkt.ETHERNET.NDP_MULTICAST)
    msg = of.ofp_flow_mod()
    msg.priority = priority
    msg.match = match
    msg.actions.append(of.ofp_action_output(port = of.OFPP_CONTROLLER))
    con.send(msg)
    return True
Example #14
0
def dict_to_flow_mod(flow):
    match = flow.get('match')
    if match is None:
        match = of.ofp_match()
    else:
        match = dict_to_match(match)

    actions = flow.get('actions', [])
    if not isinstance(actions, list): actions = [actions]
    actions = [dict_to_action(a) for a in actions]
    if 'output' in flow:
        a = of.ofp_action_output(port=_fix_of_int(flow['output']))
        po.actions.append(a)

    fm = of.ofp_flow_mod(match=match)
    fm.actions = actions

    for k in ['cookie', 'idle_timeout', 'hard_timeout', 'priority']:
        if k in flow:
            setattr(fm, k, flow[k])

    return fm
Example #15
0
    def _exec_cmd_set_table(self, event):
        try:
            msg = event.msg
            dpid = strToDPID(msg['dpid'])
            con = core.openflow.getConnection(dpid)
            if con is None:
                raise RuntimeError("No such switch")

            xid = of.generate_xid()

            fm = of.ofp_flow_mod()
            fm.xid = xid
            fm.command = of.OFPFC_DELETE
            con.send(fm)
            bar = of.ofp_barrier_request()
            bar.xid = xid
            con.send(bar)

            for flow in msg.get('flows', []):
                fm = dict_to_flow_mod(flow)
                fm.xid = xid

                con.send(fm)
                #con.send(of.ofp_barrier_request(xid=xid))
            con.send(of.ofp_barrier_request(xid=xid))

            self.reply(event, **{'type': 'set_table', 'xid': xid})

        except:
            #log.exception("Exception in set_table")
            log.debug("Exception in set_table - %s:%s",
                      sys.exc_info()[0].__name__,
                      sys.exc_info()[1])
            self.reply(event,
                       exception="%s: %s" %
                       (sys.exc_info()[0], sys.exc_info()[1]),
                       traceback=traceback.format_exc())
Example #16
0
def _handle_ConnectionUp(event):
    msg = of.ofp_flow_mod()
    msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD))
    event.connection.send(msg)
    log.info("Hubifying %s", dpidToStr(event.dpid))
Example #17
0
def handle_FEATURES_REPLY(con, msg):
    connecting = con.connect_time == None
    con.features = msg
    con.original_ports._ports = set(msg.ports)
    con.ports._reset()
    con.dpid = msg.datapath_id

    if not connecting:
        con.ofnexus._connect(con)
        e = con.ofnexus.raiseEventNoErrors(FeaturesReceived, con, msg)
        if e is None or e.halt != True:
            con.raiseEventNoErrors(FeaturesReceived, con, msg)
        return

    nexus = core.OpenFlowConnectionArbiter.getNexus(con)
    if nexus is None:
        # Cancel connection
        con.info("No OpenFlow nexus for " +
                 pox.lib.util.dpidToStr(msg.datapath_id))
        con.disconnect()
        return
    con.ofnexus = nexus
    con.ofnexus._connect(con)
    #connections[con.dpid] = con

    barrier = of.ofp_barrier_request()

    listeners = []

    def finish_connecting(event):
        if event.xid != barrier.xid:
            con.dpid = None
            con.err("failed connect")
            con.disconnect()
        else:
            con.info("connected : TEST TEST TEST")
            con.connect_time = time.time()
            e = con.ofnexus.raiseEventNoErrors(ConnectionUp, con, msg)
            if e is None or e.halt != True:
                con.raiseEventNoErrors(ConnectionUp, con, msg)
            e = con.ofnexus.raiseEventNoErrors(FeaturesReceived, con, msg)
            if e is None or e.halt != True:
                con.raiseEventNoErrors(FeaturesReceived, con, msg)
        con.removeListeners(listeners)

    listeners.append(con.addListener(BarrierIn, finish_connecting))

    def also_finish_connecting(event):
        if event.xid != barrier.xid: return
        if event.ofp.type != of.OFPET_BAD_REQUEST: return
        if event.ofp.code != of.OFPBRC_BAD_TYPE: return
        # Okay, so this is probably an HP switch that doesn't support barriers
        # (ugh).  We'll just assume that things are okay.
        finish_connecting(event)

    listeners.append(con.addListener(ErrorIn, also_finish_connecting))

    #TODO: Add a timeout for finish_connecting

    if con.ofnexus.miss_send_len is not None:
        con.send(of.ofp_set_config(miss_send_len=con.ofnexus.miss_send_len))
    if con.ofnexus.clear_flows_on_connect:
        con.send(of.ofp_flow_mod(match=of.ofp_match(),
                                 command=of.OFPFC_DELETE))

    con.send(barrier)
    """
Example #18
0
 def _handle_PacketIn(self, event):
     msg = of.ofp_flow_mod()
     self.connection.send(msg)
Example #19
0
    def _handle_PacketIn(self, event):
        inport = event.port
        packet = event.parsed

        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

        tcpp = packet.find('tcp')
        if not tcpp:
            arpp = packet.find('arp')
            if arpp:
                # Handle replies to our server-liveness probes
                if arpp.opcode == arpp.REPLY:
                    if arpp.protosrc in self.outstanding_probes:
                        # A server is (still?) up; cool.
                        del self.outstanding_probes[arpp.protosrc]
                        if (self.live_servers.get(arpp.protosrc,
                                                  (None, None)) == (arpp.hwsrc,
                                                                    inport)):
                            # Ah, nothing new here.
                            pass
                        else:
                            # Ooh, new server.
                            self.live_servers[
                                arpp.protosrc] = arpp.hwsrc, inport
                            self.log.info("Server %s up", arpp.protosrc)
                return

            # Not TCP and not ARP.  Don't know what to do with this.  Drop it.
            return drop()

        # It's TCP.

        ipp = packet.find('ipv4')

        if ipp.srcip in self.servers:
            # It's FROM one of our balanced servers.
            # Rewrite it BACK to the client

            key = ipp.srcip, ipp.dstip, tcpp.srcport, tcpp.dstport
            entry = self.memory.get(key)

            if entry is None:
                # We either didn't install it, or we forgot about it.
                self.log.debug("No client for %s", key)
                return drop()

            # Refresh time timeout and reinstall.
            entry.refresh()

            #self.log.debug("Install reverse flow for %s", key)

            # Install reverse table entry
            mac, port = self.live_servers[entry.server]

            actions = []
            actions.append(of.ofp_action_dl_addr.set_src(self.mac))
            actions.append(of.ofp_action_nw_addr.set_src(self.service_ip))
            actions.append(of.ofp_action_output(port=entry.client_port))
            match = of.ofp_match.from_packet(packet, inport)

            msg = of.ofp_flow_mod(command=of.OFPFC_ADD,
                                  idle_timeout=FLOW_IDLE_TIMEOUT,
                                  hard_timeout=of.OFP_FLOW_PERMANENT,
                                  data=event.ofp,
                                  actions=actions,
                                  match=match)
            self.con.send(msg)

        elif ipp.dstip == self.service_ip:
            # Ah, it's for our service IP and needs to be load balanced

            # Do we already know this flow?
            key = ipp.srcip, ipp.dstip, tcpp.srcport, tcpp.dstport
            entry = self.memory.get(key)
            if entry is None or entry.server not in self.live_servers:
                # Don't know it (hopefully it's new!)
                if len(self.live_servers) == 0:
                    self.log.warn("No servers!")
                    return drop()

                # Pick a server for this flow
                server = self._pick_server(key, inport)
                self.log.debug("Directing traffic to %s", server)
                entry = MemoryEntry(server, packet, inport)
                self.memory[entry.key1] = entry
                self.memory[entry.key2] = entry

            # Update timestamp
            entry.refresh()

            # Set up table entry towards selected server
            mac, port = self.live_servers[entry.server]

            actions = []
            actions.append(of.ofp_action_dl_addr.set_dst(mac))
            actions.append(of.ofp_action_nw_addr.set_dst(entry.server))
            actions.append(of.ofp_action_output(port=port))
            match = of.ofp_match.from_packet(packet, inport)

            msg = of.ofp_flow_mod(command=of.OFPFC_ADD,
                                  idle_timeout=FLOW_IDLE_TIMEOUT,
                                  hard_timeout=of.OFP_FLOW_PERMANENT,
                                  data=event.ofp,
                                  actions=actions,
                                  match=match)
            self.con.send(msg)
Example #20
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))
Example #21
0
    def send_table(self):
        if self.connection is None:
            self.log.debug("Can't send table: disconnected")
            return

        clear = of.ofp_flow_mod(command=of.OFPFC_DELETE)
        self.connection.send(clear)
        self.connection.send(of.ofp_barrier_request())

        # From DHCPD
        msg = of.ofp_flow_mod()
        msg.match = of.ofp_match()
        msg.match.dl_type = pkt.ethernet.IP_TYPE
        msg.match.nw_proto = pkt.ipv4.UDP_PROTOCOL
        #msg.match.nw_dst = IP_BROADCAST
        msg.match.tp_src = pkt.dhcp.CLIENT_PORT
        msg.match.tp_dst = pkt.dhcp.SERVER_PORT
        msg.actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER))
        #msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
        self.connection.send(msg)

        core.openflow_discovery.install_flow(self.connection)

        src = self
        for dst in switches_by_dpid.itervalues():
            if dst is src: continue
            p = _get_path(src, dst)
            if p is None: continue

            msg = of.ofp_flow_mod()
            msg.match = of.ofp_match()
            msg.match.dl_type = pkt.ethernet.IP_TYPE
            #msg.match.nw_dst = "%s/%s" % (dst.network, dst.subnet)
            msg.match.nw_dst = "%s/%s" % (dst.network, "255.255.0.0")

            msg.actions.append(of.ofp_action_output(port=p[0][1]))
            self.connection.send(msg)
        """
    # Can just do this instead of MAC learning if you run arp_responder...
    for port in self.ports:
      p = port.port_no
      if p < 0 or p >= of.OFPP_MAX: continue
      msg = of.ofp_flow_mod()
      msg.match = of.ofp_match()
      msg.match.dl_type = pkt.ethernet.IP_TYPE
      msg.match.nw_dst = "10.%s.%s.0/255.255.255.0" % (self._id,p)
      msg.actions.append(of.ofp_action_output(port=p))
      self.connection.send(msg)
    """

        for ip, mac in self.ip_to_mac.iteritems():
            self._send_rewrite_rule(ip, mac)

        flood_ports = []
        for port in self.ports:
            p = port.port_no
            if p < 0 or p >= of.OFPP_MAX: continue

            if core.openflow_discovery.is_edge_port(self.dpid, p):
                flood_ports.append(p)

            msg = of.ofp_flow_mod()
            msg.priority -= 1
            msg.match = of.ofp_match()
            msg.match.dl_type = pkt.ethernet.IP_TYPE
            msg.match.nw_dst = "10.%s.%s.0/255.255.255.0" % (self._id, p)
            msg.actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER))
            self.connection.send(msg)

        msg = of.ofp_flow_mod()
        msg.priority -= 1
        msg.match = of.ofp_match()
        msg.match.dl_type = pkt.ethernet.IP_TYPE
        msg.match.nw_dst = "255.255.255.255"
        for p in flood_ports:
            msg.actions.append(of.ofp_action_output(port=p))
        self.connection.send(msg)
Example #22
0
    def _handle_PacketIn(self, event):
        if self._outside_eth is None: return

        #print
        #print "PACKET",event.connection.ports[event.port].name,event.port,
        #print self.outside_port, self.make_match(event.ofp)

        incoming = event.port == self._outside_portno

        if self._gateway_eth is None:
            # Need to find gateway MAC -- send an ARP
            self._arp_for_gateway()
            return

        packet = event.parsed
        dns_hack = False

        # We only handle TCP and UDP
        tcpp = packet.find('tcp')
        if not tcpp:
            tcpp = packet.find('udp')
            if not tcpp: return
            if tcpp.dstport == 53 and tcpp.prev.dstip == self.inside_ip:
                if self.dns_ip and not incoming:
                    # Special hack for DNS since we've lied and claimed to be the server
                    dns_hack = True
        ipp = tcpp.prev

        if not incoming:
            # Assume we only NAT public addresses
            if self._is_local(ipp.dstip) and not dns_hack: return
        else:
            # Assume we only care about ourselves
            if ipp.dstip != self.outside_ip: return

        match = self.make_match(event.ofp)

        if incoming:
            match2 = match.clone()
            match2.dl_dst = None  # See note below
            record = self._record_by_incoming.get(match2)
            if record is None:
                # Ignore for a while
                fm = of.ofp_flow_mod()
                fm.idle_timeout = 1
                fm.hard_timeout = 10
                fm.match = of.ofp_match.from_packet(event.ofp)
                event.connection.send(fm)
                return
            log.debug("%s reinstalled", record)
            record.incoming_fm.data = event.ofp  # Hacky!
        else:
            record = self._record_by_outgoing.get(match)
            if record is None:
                record = Record()

                record.real_srcport = tcpp.srcport
                record.fake_srcport = self._pick_port(match)

                # Outside heading in
                fm = of.ofp_flow_mod()
                fm.flags |= of.OFPFF_SEND_FLOW_REM
                fm.hard_timeout = FLOW_TIMEOUT

                fm.match = match.flip()
                fm.match.in_port = self._outside_portno
                fm.match.nw_dst = self.outside_ip
                fm.match.tp_dst = record.fake_srcport
                fm.match.dl_src = self._gateway_eth

                # We should set dl_dst, but it can get in the way.  Why?  Because
                # in some situations, the ARP may ARP for and get the local host's
                # MAC, but in others it may not.
                #fm.match.dl_dst = self._outside_eth
                fm.match.dl_dst = None

                fm.actions.append(of.ofp_action_dl_addr.set_src(packet.dst))
                fm.actions.append(of.ofp_action_dl_addr.set_dst(packet.src))
                fm.actions.append(of.ofp_action_nw_addr.set_dst(ipp.srcip))

                if dns_hack:
                    fm.match.nw_src = self.dns_ip
                    fm.actions.append(
                        of.ofp_action_nw_addr.set_src(self.inside_ip))
                if record.fake_srcport != record.real_srcport:
                    fm.actions.append(
                        of.ofp_action_tp_port.set_dst(record.real_srcport))

                fm.actions.append(of.ofp_action_output(port=event.port))

                record.incoming_match = self.strip_match(fm.match)
                record.incoming_fm = fm

                # Inside heading out
                fm = of.ofp_flow_mod()
                fm.data = event.ofp
                fm.flags |= of.OFPFF_SEND_FLOW_REM
                fm.hard_timeout = FLOW_TIMEOUT
                fm.match = match.clone()
                fm.match.in_port = event.port
                fm.actions.append(
                    of.ofp_action_dl_addr.set_src(self._outside_eth))
                fm.actions.append(
                    of.ofp_action_nw_addr.set_src(self.outside_ip))
                if dns_hack:
                    fm.actions.append(
                        of.ofp_action_nw_addr.set_dst(self.dns_ip))
                if record.fake_srcport != record.real_srcport:
                    fm.actions.append(
                        of.ofp_action_tp_port.set_src(record.fake_srcport))
                fm.actions.append(
                    of.ofp_action_dl_addr.set_dst(self._gateway_eth))
                fm.actions.append(
                    of.ofp_action_output(port=self._outside_portno))

                record.outgoing_match = self.strip_match(fm.match)
                record.outgoing_fm = fm

                self._record_by_incoming[record.incoming_match] = record
                self._record_by_outgoing[record.outgoing_match] = record

                log.debug("%s installed", record)
            else:
                log.debug("%s reinstalled", record)
                record.outgoing_fm.data = event.ofp  # Hacky!

        record.touch()

        # Send/resend the flow mods
        if incoming:
            data = record.outgoing_fm.pack() + record.incoming_fm.pack()
        else:
            data = record.incoming_fm.pack() + record.outgoing_fm.pack()
        self._connection.send(data)

        # We may have set one of the data fields, but they should be reset since
        # they won't be valid in the future.  Kind of hacky.
        record.outgoing_fm.data = None
        record.incoming_fm.data = None
Example #23
0
def clear_flows():
    """ Clear flows on all switches """
    for c in core.openflow.connections:
        d = of.ofp_flow_mod(command=of.OFPFC_DELETE)
        c.send(d)
Example #24
0
    def _handle_PacketIn(self, event):
        """
    Handle packet in messages from the switch to implement above algorithm.
    """

        packet = event.parsed

        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)

        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)

        self.macToPort[packet.src] = event.port  # 1

        if not self.transparent:  # 2
            if packet.type == packet.LLDP_TYPE or packet.dst.isBridgeFiltered(
            ):
                drop()  # 2a
                return

        if packet.dst.is_multicast:
            flood()  # 3a
        else:
            if packet.dst not in self.macToPort:  # 4
                flood("Port for %s unknown -- flooding" % (packet.dst, ))  # 4a
            else:
                port = self.macToPort[packet.dst]
                if port == event.port:  # 5
                    # 5a
                    log.warning(
                        "Same port for packet from %s -> %s on %s.%s.  Drop." %
                        (packet.src, packet.dst, dpid_to_str(
                            event.dpid), port))
                    drop(10)
                    return
                # 6
                log.debug("installing flow for %s.%i -> %s.%i" %
                          (packet.src, event.port, packet.dst, port))
                msg = of.ofp_flow_mod()
                msg.match = of.ofp_match.from_packet(packet, event.port)
                msg.idle_timeout = 10
                msg.hard_timeout = 30
                msg.actions.append(of.ofp_action_output(port=port))
                msg.data = event.ofp  # 6a
                self.connection.send(msg)
Example #25
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)