def _handle_ARPRequest(self, event): """ First check if the host is newly attached to another switch""" # Nov.2015 self.numOfARP_REQUEST = self.numOfARP_REQUEST + 1 #logging.info("ARP " + str(self.numOfARP_REQUEST) + " " + str(time.time()) + " R") #log.info("Event.DPID {}".format(event.dpid)) #log.info("Event.SRC {}".format(event.ip)) #log.info("Event.MAC {}".format(self.topo.findHostByIp(event.ip).mac)) #log.info("Event.DST {}".format(event.dst)) #log.info("Event.PORT {}".format(event.port)) compareHost = self.topo.findHostByIp(event.ip) if compareHost is not None: compareSwitch = self.topo.findSwitchByDpid(event.dpid) if compareSwitch.vid.sw != compareHost.vid.sw: # Delete Original oldSwitch = self.topo.findSwitchByVid(VidAddr(compareHost.vid.sw, 0x00)) self.topo.deleteHost(compareHost) oldSwitch.deleteHost(compareHost) # Add new newVID = VidAddr(compareSwitch.vid.sw, compareSwitch.nextHostId()) newHost = self.topo.addHost(Host(compareHost.mac, event.ip, newVID, event.port, compareSwitch)) compareSwitch.addHost(newHost) # Notify local controller self.numOfVIRO_LOCAL_HOST = self.numOfVIRO_LOCAL_HOST+ 1 #logging.info("LOCAL_HOST " + str(self.numOfVIRO_LOCAL_HOST) + " " + str(time.time()) + " S") self.send_local_host(compareHost.mac, event.ip, newVID, event.port, compareSwitch) if event.dst == IPAddr("192.168.0.254"): event.reply = EthAddr("11-22-33-44-55-66") return """ Update the reply field in the ARP request """ host = self.topo.findHostByIp(event.dst) # matching on the destination IP Address # check if src and dst hosts are attached to the same switch. If so return the "true" MAC address for the dst if host: if host.vid.sw == compareHost.vid.sw: log.debug("Hosts attached to the same switch src-mac=%s dst-mac=%s", host.mac, compareHost.mac) event.reply = EthAddr(host.mac.raw) else: event.reply = EthAddr(host.vid.raw) else: log.debug("Host not found in _handle_ARPRequest")
def _handle_ConnectionUp (event): # 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_dl_addr.set_dst(EthAddr("11-22-33-44-55-66"))) # 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) # src_vid = VidAddr(0x04, 0x01) # dst_vid = VidAddr(0x07, 0x01) msg = vnx.nx_flow_mod() msg.match.in_port = 1 msg.actions.append(vof.viro_action_push_fd(fd = VidAddr(0x08, 0x0a))) msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = vnx.nx_flow_mod() msg.match.in_port = 2 msg.actions.append(vof.viro_action_pop_fd()) msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg)
def _unpack_body(self, raw, offset, avail): offset, (self.subtype, host, sw) = of._unpack('!HHI', raw, offset) offset = of._skip(raw, offset, 8) self.fd = VidAddr(sw, host) return offset
def routeViroPacket(self, pkt, inport=None): """ Route the viro packet closer to destination """ dst_pkt = VidAddr(pkt.dst.sw, 0x00) if (dst_pkt == self.sw.vid): # consume the packet since its sent to me self.processViroPacket(pkt, inport) return if pkt.effective_ethertype == viroctrl.VIRO_CTRL_TYPE: op = pkt.payload.op nexthop, port = self.routing.getNextHop(dst_pkt, op) else: nexthop, port = self.routing.getNextHop(dst_pkt) if nexthop != None: msg = msgFactory.packetOut(pkt, port) self.sw.connection.send(msg) else: log.debug("routeViroPacket nexthop not found") # use for handling data packets if inport: return port
def _handle_ViroSwitchUp(self, event): """ Register a viro switch to the remote controller """ log.debug("Connection %s %s" % (event.connection, dpidToStr(event.dpid))) # register the viro switch vid = VidAddr(event.dpid, 0x00) sw = self.topo.addSwitch(Switch(event.dpid, vid, event.connection)) # set the remote controller id at the switch sw.connection.send(msgFactory.ofpControllerId(RemoteViro.CONTROLLER_ID)) # enable the flowMod tableId extension (nicira extensions) sw.connection.send(msgFactory.ofpFlowModTableId())
def parse(self, raw): assert isinstance(raw, bytes) self.raw = raw dlen = len(raw) if dlen < rdv_publish.MIN_LEN: self.msg( '(rdv_publish parse) warning rdv_publish packet data too short to parse header: data len %u' % (dlen, )) return hdr = struct.unpack("!I", raw[:rdv_publish.MIN_LEN]) self.vid = VidAddr(hdr[0], 0) self.parsed = True
def parse(self, raw): assert isinstance(raw, bytes) self.raw = raw dlen = len(raw) if dlen < gw_withdraw.MIN_LEN: self.msg( '(gw_withdraw parse) warning gw_withdraw packet data too short to parse header: data len %u' % (dlen, )) return hdr = struct.unpack("!I", raw[:gw_withdraw.MIN_LEN]) self.failed_gw = VidAddr(hdr[0], 0) self.parsed = True
def parse(self, raw): assert isinstance(raw, bytes) self.raw = raw dlen = len(raw) if dlen < rdv_reply.MIN_LEN: self.msg( '(rdv_reply parse) warning rdv_reply packet data too short to parse header: data len %u' % (dlen, )) return hdr = struct.unpack("!II", raw[:rdv_reply.MIN_LEN]) self.bucket_dist = hdr[0] self.gw = VidAddr(hdr[1], 0) self.parsed = True
def parse(self, raw): assert isinstance(raw, bytes) self.raw = raw dlen = len(raw) if dlen < controller_echo.MIN_LEN: self.msg( '(controller_echo parse) warning controller_echo packet data too short to parse header: data len %u' % (dlen, )) return hdr = struct.unpack("!BBIH", raw[:controller_echo.MIN_LEN]) self.from_controller_id = hdr[0] self.to_controller_id = hdr[1] self.vid = VidAddr(hdr[2], hdr[3]) self.parsed = True
def pushRoutingTableETH(dst_vid, dst_vid_mask, Outport): fake_dst_mac = VidAddr(dst_vid, 0x00) fake_dst_mac_mask = VidAddr(dst_vid_mask, 0x00) msg = vnx.nx_flow_mod() msg.table_id = 1 msg.priority = 15 msg.match.eth_type = ethernet.IP_TYPE msg.match.eth_dst = fake_dst_mac.to_raw() msg.match.eth_dst_mask = fake_dst_mac_mask.to_raw() msg.actions.append(of.ofp_action_output(port=Outport)) return msg
def parse(self, raw): assert isinstance(raw, bytes) self.raw = raw dlen = len(raw) if dlen < local_host.MIN_LEN: self.msg( '(local_host) warning local_host packet data too short to parse header: data len %u' % (dlen, )) return hdr = struct.unpack("!IIHI", raw[6:local_host.MIN_LEN]) mac = raw[:6] self.mac = EthAddr(mac) self.ip = IPAddr(hdr[0]) self.vid = VidAddr(hdr[1], hdr[2]) self.port = hdr[3] self.host = Host(self.mac, self.ip, self.vid, self.port, None) self.parsed = True
def encapsulate(src_mac, src_vid, dst_mac, dst_vid): msg = vnx.nx_flow_mod() msg.table_id = 0 msg.priority = 15 msg.match.eth_type = ethernet.IP_TYPE msg.match.eth_src = src_mac msg.match.eth_dst = dst_mac msg.actions.append(vof.viro_action_push_fd(fd=VidAddr(0x08, 0x0a))) msg.actions.append(vof.viro_action_vid_sw.set_src(src_vid.sw)) msg.actions.append(vof.viro_action_vid_host.set_src(src_vid.host)) msg.actions.append(vof.viro_action_vid_sw.set_dst(dst_vid.sw)) msg.actions.append(vof.viro_action_vid_host.set_dst(dst_vid.host)) msg.actions.append(vnx.nx_action_resubmit.resubmit_table(1)) # msg.actions.append(of.ofp_action_output(port = Outport)) return msg
def _handle_DHCPLease(self, event): """ Register a host """ # Nov.2015 self.numOfDHCP_REQUEST = self.numOfDHCP_REQUEST + 1 #logging.info("DHCP " + str(self.numOfDHCP_REQUEST) + " " + str(time.time()) + " R") log.debug("handling dhcp lease event dpid=%s mac=%s ip=%s", dpidToStr(event.dpid), event.host_mac, event.ip) sw = self.topo.findSwitchByDpid(event.dpid) hostMac = event.host_mac hostIp = event.ip hostPort = event.port hostVid = VidAddr(sw.vid.sw, sw.nextHostId()) host = self.topo.addHost(Host(hostMac, hostIp, hostVid, hostPort, sw)) sw.addHost(host) self.numOfVIRO_LOCAL_HOST = self.numOfVIRO_LOCAL_HOST+ 1 #logging.info("LOCAL_HOST " + str(self.numOfVIRO_LOCAL_HOST) + " " + str(time.time()) + " S") # sending host information to the local controller self.send_local_host(hostMac, hostIp, hostVid, hostPort, sw)
def _handle_ViroPacketInVIROCtrl(self, event): """ VIRO control Vid Request pkts """ viropkt = event.packet inport = event.port log.debug(str(viropkt)) ctrlpkt = viropkt.payload if ctrlpkt.op == viroctrl.VID_REQUEST: # local control vid request message # assigns the VidAddress the the local host attached to sw self.numOfVIRO_VID_REQUEST = self.numOfVIRO_VID_REQUEST + 1 #logging.info("VIRO_VID_REQUEST " + str(self.numOfVIRO_VID_REQUEST) + " " + str(time.time()) + " R") log.debug('Receiving VidRequest pkt from local controller') payload = ctrlpkt.payload mac = payload.mac ip = payload.ip port = payload.port sw = self.topo.findSwitchByDpid(event.dpid) vid = VidAddr(sw.vid.sw, sw.nextHostId()) host = self.topo.addHost(Host(mac, ip, vid, port, sw)) sw.addHost(host) # sending host information to the local controller self.send_local_host(mac, ip, vid, port, sw) elif ctrlpkt.op == viroctrl.HOST_WITHDRAW: self.numOfVIRO_HOST_WITHDRAW = self.numOfVIRO_HOST_WITHDRAW + 1 #logging.info("VIRO_HOST_WITHDRAW " + str(self.numOfVIRO_HOST_WITHDRAW) + " " + str(time.time()) + " R") log.debug('Receiving a failed host packet') host_ip = ctrlpkt.payload.failed_host log.debug('Updating its global topology table') self.topo.deleteHostByIP(host_ip) # remove host
from pox.core import core import struct from viro.packet.viro import viro from viro.packet.viro_ctrl import viroctrl from viro.packet.vid import VidAddr from viro.packet.ctrl import * from pox.lib.packet import * log = core.getLogger() vidNull = VidAddr(0, 0) def controlPacket(srcVid, dstVid, fdVid, op, payload): """ Create a viro control packet """ ctrl = viroctrl(op=op) ctrl.payload = payload packet = viro(src=srcVid, dst=dstVid, fd=fdVid) packet.next_eth_type = viroctrl.VIRO_CTRL_TYPE packet.payload = ctrl return packet def controllerEcho(fromCtrlId, toCtrlId, vid): """ Create a controller-to-controller echo packet """ payload = controller_echo(from_controller_id=fromCtrlId, to_controller_id=toCtrlId, vid=vid) return controlPacket(vidNull, vidNull, vidNull, viroctrl.CONTROLLER_ECHO, payload)
def _handle_ViroPacketInIP(self, event): IPv4_frame = event.packet inport = event.port IPv4pkt = IPv4_frame.payload # Ip packet payload log.debug( "IPv4 packet in_port=%d, srcvid=%s, dstvid=%s, type=%#04x", inport, IPv4_frame.src, IPv4_frame.dst, IPv4_frame.type, ) # Is it to us? (eg. not a DHCP packet) if isinstance(IPv4pkt, pkt.dhcp): log.debug("%s: packet is a DHCP: it is not for us", str(event.connection)) return # obtain the frame header info. srcMac = IPv4_frame.src dstMac = IPv4_frame.dst ethtype = IPv4_frame.type ipv4 = IPv4pkt.srcip log.debug("This is the ipv4 packet: {}".format(ipv4)) n = dstMac.toRaw() dst_sw, dst_host = self.sw.vid.getSWHost(n) dst_vid = VidAddr(dst_sw, dst_host) # find src and dst host objects #dist_host = self.local_topo.findHostByVid(dst_vid) dist_host = self.local_topo.findHostByMac(dstMac) local_host = self.local_topo.findHostByMac(srcMac) # if local host does not exist in our topology # send a vid request to the remote controller # Drop the IPv4 pkts if local_host == None: packet = pktFactory.vidRequest(srcMac, ipv4, inport) msg = msgFactory.controllerEcho(LocalViro.RemoteViro_CONTROLLER_ID, packet) self.sw.connection.send(msg) log.debug("Sending a Vid Request pkt to the remote controller") return # obtain the src VidAddress src_vid = local_host.vid if dist_host != None: ###### Handling packets to src and dst in the same switch ###### log.debug("src and dst attached to the same switch!") lport = dist_host.port #dst_mac = dist_host.mac #etherpkt = event.packet # set the destination macAddress and the source vid #etherpkt.src = src_vid.to_raw() #etherpkt.dst = dst_mac log.debug("forwarding the packet to the next host") msg = msgFactory.packetOut(IPv4_frame, lport) self.sw.connection.send(msg) #--------------------------------------------- # Add a rule to the switch for future packets #--------------------------------------------- log.debug("pushing the rules to the switch") #msg = msgFactory.rewriteMac(src_vid, dstMac, dst_mac, lport) # Pushing the rule in both directons # a) src --> dst msg = msgFactory.rewriteMac(srcMac, dstMac, lport) self.sw.connection.send(msg) # b) dst --> src msg = msgFactory.rewriteMac(dstMac, srcMac, inport) self.sw.connection.send(msg) return else: ###### Handling packets to src and dst in different switch ###### log.debug("Converting IPv4pkts to Viropkts") # Generates a Viropkt frame and route it log.debug('VidAddress parameters - Src: {} , Dst: {}'.format( src_vid, dst_vid)) viropkt = pktFactory.ViroPacket(src_vid, dst_vid, None, ethtype, IPv4pkt) self.routeViroPacket(viropkt, True) log.debug("routing Viro packets") #--------------------------------------------- # Add a rule to the switch for future packets #--------------------------------------------- # log.debug("Port is {}".format(outport)) msg = msgFactory.encapsulate(srcMac, src_vid, dstMac, dst_vid) self.sw.connection.send(msg) return
def processDataPacket(self, viropkt, inport): """ Process a VIRO data packet """ # 1.proces the packet # 2. Add a rule to the switch to match future requests # 3. Need to check if I am the destination of the packet # If so remove the forwarding directive, replace the # Vid with the mac address with the client mac address and forward # the packet to the host: I need to save to which port the client is # connected to dst = viropkt.dst src = viropkt.src dst_pkt = VidAddr(dst.sw, 0x00) if dst_pkt == self.sw.vid: # I am the destination for the packet: # converting a Viropkt frame to ethernet frame log.debug("Destination VID: {} myVid: {}".format( dst, self.sw.vid)) datapkt = viropkt.payload local_host = self.local_topo.findHostByVid(dst) if local_host == None: log.debug( "Unknown destination Vid to hosts attached to this switch!" ) return srcMac = src.to_raw() dstMac = local_host.mac lport = local_host.port type = viropkt.effective_ethertype # Generates a internet frame and route it etherpkt = pktFactory.ethernetPkt(type, srcMac, dstMac, datapkt) msg = msgFactory.packetOut(etherpkt, lport) self.sw.connection.send(msg) log.debug("Sending data packets to local hosts") #--------------------------------------------- # Add a rule to the switch for future packets #--------------------------------------------- msg = msgFactory.decapsulate(dstMac, dst, lport) self.sw.connection.send(msg) return else: # Viropkt is not for us then route it! port = self.routeViroPacket(viropkt) #--------------------------------------------- # Add a rule to the switch for future packets #--------------------------------------------- level = self.sw.vid.delta(dst_pkt) prefix = self.sw.vid.bucketPrefix(level) dst_vid = int(prefix.replace("*", "0"), 2) dst_vid_mask = int(prefix.replace("0", "1").replace("*", "0"), 2) msg = msgFactory.pushRoutingTable(dst_vid, dst_vid_mask, port) self.sw.connection.send(msg) msg = msgFactory.pushRoutingTableETH(dst_vid, dst_vid_mask, port) self.sw.connection.send(msg) return