def _do_dns_packet(self, packet, event): dnsp = packet.find('dns') if len(dnsp.questions) > 1: self._drop(packet, event.ofp.buffer_id, event.port) return question = dnsp.questions[0] response = None log.debug("Question: %s" % (question.name)) if question.qtype == dns.rr.A_TYPE and question.name == self.service_name: # Some one is asking about our service so let's # choose one of data centers and answer him dc_ip = self._choose_server() response = dns.rr(question.name, question.qtype, question.qclass, 0, 4, dc_ip) elif question.qtype == dns.rr.PTR_TYPE: # for now we assume that only our dns is resolvable response = dns.rr(question.name, question.qtype, question.qclass, 0, len(self.service_name), self.service_name) else: self._drop(packet, event.ofp.buffer_id, event.port) return self._send_dns_response_packet(packet, dnsp, question, response, event.port)
def _answer_A (self, q): if not q.name.endswith('.local'): log.info('ignoring question: %s' % q) return None, None name = q.name[:-len('.local')] for node in core.Outband.t.nodes: if (node.name.lower() == name.lower()): # TODO multiple addresses in the response? port = node.ports[max(node.ports)] log.info('answering: %s %s' % (q.name, port.ip)) ttl = 120 # 2 minutes addr = IPAddr(port.ip).toRaw() # byte-order ??? r = pkt_dns.rr(q.name, q.qtype, q.qclass, ttl, 4, addr) return port, r return None, None
def _answer_PTR (self, q): if not q.name.endswith('.in-addr.arpa'): log.info('ignoring question: %s' % q) return None, None name = q.name[:-len('.in-addr.arpa')] ip = name.split('.') ip.reverse() ip = '.'.join(ip) node, port = core.Outband.t.ip_and_port(ip) if not node: return None, None log.info('answering: %s %s' % (q.name, node.name)) ttl = 120 # 2 minutes domain = putName('', node.name + '.local') domain = domain.encode('ascii', 'ignore') r = pkt_dns.rr(q.name, q.qtype, q.qclass, ttl, len(domain), domain) return port, r
def _handle_PacketIn(self, event): dpid = event.connection.dpid inport = event.port packet = copy.deepcopy(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)) # store the mac, ip info of the DNS SERVER into arpTable self.arpTable[dpid][IPAddr(IP_OF_DNS_SERVER)] = Entry( 6633, EthAddr(MAC_OF_DNS_SERVER)) if packet.type == ethernet.LLDP_TYPE: # Ignore LLDP packets return p = packet.find('dns') if p is not None and p.parsed: # Get dstName of the DNS Query dstname = '' for question in p.questions: dstname = question.name log.debug("DNS Query msg from %s: asking ip address for %s", packet.next.srcip, dstname) # 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) # generate random virtual ip for internal node n = random.randint(128, 254) vip = "10.0.0." + str(n) #add the srcip and virtual destination ip pair into srcip_dstip_map self.srcip_dstvip_map[str(packet.next.srcip)] = vip # forming answer answer = dns.rr(dstname, 1, 1, 5, len(vip), IPAddr(vip)) # write dns reply msg d = dns() d.questions = p.questions d.answers.append(answer) d.authorities = [] d.additional = [] d.id = p.id d.qr = True # dns reply d.opcode = 0 # standard d.aa = False d.tc = False d.rd = False d.ra = False d.z = False d.ad = False d.cd = False d.rcode = 0 e = ethernet(type=ethernet.IP_TYPE, src=MAC_OF_DNS_SERVER, dst=str(packet.src)) ip = ipv4(srcip=IPAddr(IP_OF_DNS_SERVER)) ip.dstip = packet.next.srcip ip.protocol = ip.UDP_PROTOCOL u = udp() u.srcport = dns.SERVER_PORT # get srcport from the packet and set it to the udp's dstport m = packet.find("udp") m.parsed u.dstport = m.srcport u.payload = d ip.payload = u e.payload = ip msg = of.ofp_packet_out() msg.data = e.pack() msg.actions.append(of.ofp_action_nw_addr.set_dst( packet.next.srcip)) msg.actions.append(of.ofp_action_dl_addr.set_dst(packet.src)) msg.actions.append(of.ofp_action_output(port=of.OFPP_IN_PORT)) msg.in_port = inport event.connection.send(msg) log.debug( " DNS reply msg has been sent to %s: %s's ip address is %s" % (str(packet.next.srcip), dstname, vip)) elif isinstance(packet.next, ipv4): log.debug("IPv4 msg: %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) print "Have sent lost buffers" # 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) srcaddr = packet.next.srcip dstaddr = packet.next.dstip if (dstaddr in self.vipList): self.srcip_dstvip_map[srcaddr] = dstaddr dstaddr = IPAddr(REAL_IP_OF_INTERNAL_HOST) 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 # Try to forward icmpmsg = packet.find("icmp") icmpmsg.parsed # icmp echo reply from internal host if icmpmsg.type == 0 and srcaddr == IPAddr( REAL_IP_OF_INTERNAL_HOST): log.info("ICMP echo reply msg from %s to %s", srcaddr, packet.next.dstip) 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)) # add flow entry msg = of.ofp_flow_mod(command=of.OFPFC_ADD) msg.match.dl_type = 0x0800 #ipv4 msg.match.nw_src = REAL_IP_OF_INTERNAL_HOST msg.match.nw_dst = dstaddr # change the srcip to virtual ip msg.actions.append( of.ofp_action_nw_addr.set_src( IPAddr(self.srcip_dstvip_map[dstaddr]))) msg.actions.append(of.ofp_action_dl_addr.set_dst(mac)) msg.actions.append(of.ofp_action_output(port=prt)) event.connection.send(msg) log.info( "ICMP echo reply flow entry for internal node to %s has been installed", packet.next.dstip) # icmp echo reply for internal host elif icmpmsg.type == 8 and dstaddr == IPAddr( REAL_IP_OF_INTERNAL_HOST): log.info("ICMP echo request msg from %s to %s", packet.next.srcip, packet.next.dstip) 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)) msg = of.ofp_flow_mod(command=of.OFPFC_ADD) msg.match.dl_type = 0x0800 #ipv4 msg msg.match.in_port = inport msg.match.nw_dst = "10.0.0.128/255.255.255.128" msg.actions.append(of.ofp_action_nw_addr.set_dst(dstaddr)) msg.actions.append(of.ofp_action_output(port=prt)) msg.actions.append(of.ofp_action_dl_addr.set_dst(mac)) event.connection.send(msg) log.info( "ICMP echo request flow entry for %s to internal host has been instaled", packet.next.srcip) else: log.warning("Uninvolved icmp msg type") return 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 if dstaddr in self.vipList: r.protodst = IPAddr(REAL_IP_OF_INTERNAL_HOST) else: 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 for Ipv4" % (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 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) if a.protodst in self.vipList: self.srcip_dstvip_map[a.protosrc] = str(a.protodst) a.protodst = REAL_IP_OF_INTERNAL_HOST log.info("%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.REPLY: r = arp() r.hwtype = a.hwtype r.prototype = a.prototype r.hwlen = a.hwlen r.protolen = a.protolen r.opcode = arp.REPLY r.hwsrc = a.hwsrc if a.protosrc == IPAddr(REAL_IP_OF_INTERNAL_HOST): if a.protodst in self.srcip_dstvip_map: r.protosrc = IPAddr( self.srcip_dstvip_map[a.protodst]) else: r.protosrc = a.protosrc r.protodst = a.protodst r.hwdst = self.arpTable[dpid][a.protodst].mac e = ethernet(type=packet.type, src=dpid_to_mac(dpid), dst=a.hwdst) e.set_payload(r) log.debug("%i %i answering ARP for %s to %s" % (dpid, inport, str( r.protosrc), str(r.protodst))) msg = of.ofp_packet_out() msg.data = e.pack() msg.actions.append( of.ofp_action_output( port=self.arpTable[dpid][a.protodst].port)) msg.in_port = inport event.connection.send(msg) return if a.opcode == arp.REQUEST: # Maybe we can answer if a.protodst in self.vipList: self.srcip_dstvip_map[a.protosrc] = str( a.protodst) a.protodst = IPAddr(REAL_IP_OF_INTERNAL_HOST) 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.hwsrc = self.arpTable[dpid][ a.protodst].mac r.protodst = a.protosrc if a.protodst == IPAddr( REAL_IP_OF_INTERNAL_HOST): r.protosrc = IPAddr( self.srcip_dstvip_map[a.protosrc]) else: r.protosrc = a.protodst 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))) r1 = arp() r1.hwtype = a.HW_TYPE_ETHERNET r1.prototype = a.PROTO_TYPE_IP r1.hwlen = 6 r1.protolen = a.protolen r1.opcode = arp.REQUEST r1.hwdst = ETHER_BROADCAST r1.protodst = IPAddr(a.protodst) r1.hwsrc = a.hwsrc r1.protosrc = a.protosrc e1 = ethernet(type=ethernet.ARP_TYPE, src=a.hwsrc, dst=ETHER_BROADCAST) e1.set_payload(r1) log.debug("%i %i ARPing for %s on behalf of %s" % (dpid, inport, str( r1.protodst), str(r1.protosrc))) msg1 = of.ofp_packet_out() msg1.data = e1.pack() msg1.actions.append( of.ofp_action_output(port=of.OFPP_FLOOD)) msg1.in_port = inport event.connection.send(msg1)
def _handle_PacketIn (self, event): dpid = event.connection.dpid inport = event.port packet = copy.deepcopy(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)) # store the mac, ip info of the DNS SERVER into arpTable self.arpTable[dpid][IPAddr(IP_OF_DNS_SERVER)]=Entry(6633, EthAddr(MAC_OF_DNS_SERVER)) if packet.type == ethernet.LLDP_TYPE: # Ignore LLDP packets return p = packet.find('dns') if p is not None and p.parsed: # Get dstName of the DNS Query dstname = ''; for question in p.questions: dstname = question.name log.debug("DNS Query msg from %s: asking ip address for %s", packet.next.srcip, dstname) # 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) # generate random virtual ip for internal node n = random.randint(128, 254) vip = "10.0.0." + str(n) #add the srcip and virtual destination ip pair into srcip_dstip_map self.srcip_dstvip_map[str(packet.next.srcip)] = vip # forming answer answer = dns.rr(dstname, 1, 1, 5, len(vip), IPAddr(vip)) # write dns reply msg d = dns() d.questions = p.questions d.answers.append(answer) d.authorities = [] d.additional =[] d.id = p.id d.qr = True # dns reply d.opcode = 0 # standard d.aa = False d.tc = False d.rd = False d.ra = False d.z = False d.ad = False d.cd = False d.rcode = 0 e = ethernet(type=ethernet.IP_TYPE, src=MAC_OF_DNS_SERVER, dst=str(packet.src)) ip = ipv4(srcip = IPAddr(IP_OF_DNS_SERVER)) ip.dstip = packet.next.srcip ip.protocol = ip.UDP_PROTOCOL u = udp() u.srcport = dns.SERVER_PORT # get srcport from the packet and set it to the udp's dstport m = packet.find("udp") m.parsed u.dstport = m.srcport u.payload = d ip.payload = u e.payload = ip msg = of.ofp_packet_out() msg.data = e.pack() msg.actions.append(of.ofp_action_nw_addr.set_dst(packet.next.srcip)) msg.actions.append(of.ofp_action_dl_addr.set_dst(packet.src)) msg.actions.append(of.ofp_action_output(port = of.OFPP_IN_PORT)) msg.in_port = inport event.connection.send(msg) log.debug(" DNS reply msg has been sent to %s: %s's ip address is %s" % (str(packet.next.srcip), dstname, vip)) elif isinstance(packet.next, ipv4): log.debug("IPv4 msg: %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) print "Have sent lost buffers" # 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) srcaddr = packet.next.srcip dstaddr = packet.next.dstip if(dstaddr in self.vipList): self.srcip_dstvip_map[srcaddr] = dstaddr dstaddr = IPAddr(REAL_IP_OF_INTERNAL_HOST) 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 # Try to forward icmpmsg = packet.find("icmp") icmpmsg.parsed # icmp echo reply from internal host if icmpmsg.type == 0 and srcaddr == IPAddr(REAL_IP_OF_INTERNAL_HOST): log.info("ICMP echo reply msg from %s to %s", srcaddr, packet.next.dstip) 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)) # add flow entry msg = of.ofp_flow_mod(command = of.OFPFC_ADD) msg.match.dl_type = 0x0800 #ipv4 msg.match.nw_src = REAL_IP_OF_INTERNAL_HOST msg.match.nw_dst = dstaddr # change the srcip to virtual ip msg.actions.append(of.ofp_action_nw_addr.set_src(IPAddr(self.srcip_dstvip_map[dstaddr]))) msg.actions.append(of.ofp_action_dl_addr.set_dst(mac)) msg.actions.append(of.ofp_action_output(port = prt)) event.connection.send(msg) log.info("ICMP echo reply flow entry for internal node to %s has been installed", packet.next.dstip) # icmp echo reply for internal host elif icmpmsg.type == 8 and dstaddr == IPAddr(REAL_IP_OF_INTERNAL_HOST): log.info("ICMP echo request msg from %s to %s", packet.next.srcip, packet.next.dstip) 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)) msg = of.ofp_flow_mod(command = of.OFPFC_ADD) msg.match.dl_type = 0x0800 #ipv4 msg msg.match.in_port = inport msg.match.nw_dst = "10.0.0.128/255.255.255.128" msg.actions.append(of.ofp_action_nw_addr.set_dst(dstaddr)) msg.actions.append(of.ofp_action_output(port = prt)) msg.actions.append(of.ofp_action_dl_addr.set_dst(mac)) event.connection.send(msg) log.info("ICMP echo request flow entry for %s to internal host has been instaled", packet.next.srcip) else: log.warning("Uninvolved icmp msg type") return 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 if dstaddr in self.vipList: r.protodst = IPAddr(REAL_IP_OF_INTERNAL_HOST) else: 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 for Ipv4" % (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 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) if a.protodst in self.vipList: self.srcip_dstvip_map[a.protosrc] = str(a.protodst) a.protodst = REAL_IP_OF_INTERNAL_HOST log.info("%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.REPLY: r = arp() r.hwtype = a.hwtype r.prototype = a.prototype r.hwlen = a.hwlen r.protolen = a.protolen r.opcode = arp.REPLY r.hwsrc = a.hwsrc if a.protosrc == IPAddr(REAL_IP_OF_INTERNAL_HOST): if a.protodst in self.srcip_dstvip_map: r.protosrc = IPAddr(self.srcip_dstvip_map[a.protodst]) else: r.protosrc = a.protosrc r.protodst = a.protodst r.hwdst = self.arpTable[dpid][a.protodst].mac e = ethernet(type=packet.type, src=dpid_to_mac(dpid), dst=a.hwdst) e.set_payload(r) log.debug("%i %i answering ARP for %s to %s" % (dpid, inport, str(r.protosrc), str(r.protodst))) msg = of.ofp_packet_out() msg.data = e.pack() msg.actions.append(of.ofp_action_output(port = self.arpTable[dpid][a.protodst].port)) msg.in_port = inport event.connection.send(msg) return if a.opcode == arp.REQUEST: # Maybe we can answer if a.protodst in self.vipList: self.srcip_dstvip_map[a.protosrc] = str(a.protodst) a.protodst = IPAddr(REAL_IP_OF_INTERNAL_HOST) 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.hwsrc = self.arpTable[dpid][a.protodst].mac r.protodst = a.protosrc if a.protodst == IPAddr(REAL_IP_OF_INTERNAL_HOST): r.protosrc = IPAddr(self.srcip_dstvip_map[a.protosrc]) else: r.protosrc = a.protodst 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))) r1 = arp() r1.hwtype = a.HW_TYPE_ETHERNET r1.prototype = a.PROTO_TYPE_IP r1.hwlen = 6 r1.protolen = a.protolen r1.opcode = arp.REQUEST r1.hwdst = ETHER_BROADCAST r1.protodst = IPAddr(a.protodst) r1.hwsrc = a.hwsrc r1.protosrc = a.protosrc e1 = ethernet(type=ethernet.ARP_TYPE, src=a.hwsrc, dst=ETHER_BROADCAST) e1.set_payload(r1) log.debug("%i %i ARPing for %s on behalf of %s" % (dpid, inport, str(r1.protodst), str(r1.protosrc))) msg1 = of.ofp_packet_out() msg1.data = e1.pack() msg1.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD)) msg1.in_port = inport event.connection.send(msg1)