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)
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))
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)
def _handle_ConnectionUp(event): # Set up this switch. # Turn on ability to specify table in flow_mods msg = nx.nx_flow_mod_table_id() event.connection.send(msg) # Clear second table msg = nx.nx_flow_mod(command=of.OFPFC_DELETE, table_id=1) event.connection.send(msg) # Learning rule in table 0 msg = nx.nx_flow_mod() msg.table_id = 0 learn = nx.nx_action_learn(table_id=1, hard_timeout=10) learn.spec.chain(field=nx.NXM_OF_VLAN_TCI, n_bits=12).chain(field=nx.NXM_OF_ETH_SRC, match=nx.NXM_OF_ETH_DST).chain( field=nx.NXM_OF_IN_PORT, output=True) msg.actions.append(learn) msg.actions.append(nx.nx_action_resubmit.resubmit_table(1)) event.connection.send(msg) # Fallthrough rule for table 1: flood msg = nx.nx_flow_mod() msg.table_id = 1 msg.priority = 1 # Low priority msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD)) event.connection.send(msg)
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)
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()
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)
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
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)
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)
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)
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
def _handle_ConnectionUp(event): # Set up this switch. # After setting up, we send a barrier and wait for the response # before starting to listen to packet_ins for this switch -- before # the switch is set up, the packet_ins may not be what we expect, # and our responses may not work! # Turn on Nicira packet_ins msg = nx.nx_packet_in_format() event.connection.send(msg) # Turn on ability to specify table in flow_mods msg = nx.nx_flow_mod_table_id() event.connection.send(msg) # Clear second table msg = nx.nx_flow_mod(command=of.OFPFC_DELETE, table_id=1) event.connection.send(msg) # Fallthrough rule for table 0: flood and send to controller msg = nx.nx_flow_mod() msg.priority = 1 # Low priority msg.actions.append(of.ofp_action_output(port=of.OFPP_CONTROLLER)) msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=1)) event.connection.send(msg) # Fallthrough rule for table 1: flood msg = nx.nx_flow_mod() msg.table_id = 1 msg.priority = 1 # Low priority msg.actions.append(of.ofp_action_output(port=of.OFPP_FLOOD)) event.connection.send(msg) def ready(event): if event.ofp.xid != 0x80000000: # Not the right barrier return log.info("%s ready", event.connection) event.connection.addListenerByName("PacketIn", _handle_PacketIn) return EventRemove event.connection.send(of.ofp_barrier_request(xid=0x80000000)) event.connection.addListenerByName("BarrierIn", ready)
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)
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())
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)
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)
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)
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))
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)
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)
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 : --------------------------")
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)
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
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()
def _handle_PacketIn(event): packet = event.parsed if event.port > of.OFPP_MAX: log.debug("Ignoring special port %s", event.port) return # Add to source table msg = nx.nx_flow_mod() msg.match.of_eth_src = packet.src msg.actions.append(nx.nx_action_resubmit.resubmit_table(table=1)) event.connection.send(msg) # Add to destination table msg = nx.nx_flow_mod() msg.table_id = 1 msg.match.of_eth_dst = packet.src msg.actions.append(of.ofp_action_output(port=event.port)) event.connection.send(msg) log.info("Learning %s on port %s of %s" % (packet.src, event.port, event.connection))
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
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
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 _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