def learn_and_forward(self, dpid, inport, packet, buf, bufid): # learn mac on incoming port from src src_mac = mac_to_str(packet.src) dst_mac = mac_to_str(packet.dst) if self.mac_to_port.has_key(src_mac): # print update msg old_outport = self.mac_to_port[src_mac] if old_outport != inport: logger.info('MAC ' + src_mac + ' has moved from %d to %d', old_outport, inport) else: logger.info('MAC ' + src_mac + ' remained on %d', old_outport) else: logger.info('learned MAC ' + src_mac + ' on %d port %d', dpid, inport) self.mac_to_port[src_mac] = inport # try find a outport for dst if self.mac_to_port.has_key(dst_mac): outport = self.mac_to_port[dst_mac] if outport == inport: self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport) logger.error('*** warning *** learned port == inport, flood packet') else: logger.info('install flow for ' + str(packet)) flow = extract_flow(packet) flow[core.IN_PORT] = inport actions = [[openflow.OFPAT_OUTPUT, [0, outport]]] self.install_datapath_flow(dpid, flow, CACHE_TIMEOUT, openflow.OFP_FLOW_PERMANENT, actions, bufid, openflow.OFP_DEFAULT_PRIORITY, inport, buf) else: logger.info('*** warning *** no learned, flood packet') self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)
def learn_and_forward(self, dpid, inport, packet, buf, bufid): """Learn MAC src port mapping, then flood or send unicast.""" print inport print mac_to_str(packet.src) print mac_to_str(packet.dst) # Initial hub behavior: flood packet out everything but input port. # Comment out the line below when starting the exercise. # self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport) # Starter psuedocode for learning switch exercise below: you'll need to # replace each pseudocode line with more specific Python code. # Learn the port for the source MAC #self.mac_to_port = <fill in> src_mac = mac_to_int(packet.src) self.mac_to_port[src_mac] = inport dst_mac = mac_to_int(packet.dst) if ( dst_mac in self.mac_to_port ): print 'find a match' # Send unicast packet to known output port outport = self.mac_to_port[dst_mac] actions = [[openflow.OFPAT_OUTPUT, [0, outport]]] self.send_openflow(dpid, bufid, buf, actions, inport) else: print 'no match, flood to all ports' #flood packet out everything but the input port self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)
def delete_flow(flow, replicaNum): switchNum = findReplicasSwitch(replicaNum) deleteMultipaths = getMultipaths(switchNum) for currNode in deleteMultipaths: currSwitchNum = currNode['no'] currMac = currNode['mac'] flowList = getMultiFlow(flow, len(currNode['nexthops'])) for i, miniFlow in enumerate(flowList): Globals.COMPONENT.delete_strict_datapath_flow(currMac, miniFlow) if not flow.has_key(NW_SRC_N_WILD): Globals.RULESLOG.write( mac_to_str(currMac) + " Delete Multipath @ " + str(currSwitchNum) + " to dest " + str(switchNum) + ' ' + ip_to_str(flow[NW_SRC]) + '\n') else: Globals.RULESLOG.write( mac_to_str(currMac) + " Delete Multipath @ " + str(currSwitchNum) + " to dest " + str(switchNum) + ' ' + ip_to_str(flow[NW_SRC]) + '/' + str(flow[NW_SRC_N_WILD]) + '\n') # orderDelete = getAllPaths(switchNum) # for switch in orderDelete: # currMac = getMac(switch) # Globals.log.info('Delete Flow: ' + str(flow) + ' at ' + str(switch)) # Globals.COMPONENT.delete_strict_datapath_flow(currMac, flow) Globals.RULESLOG.write('Delete: ' + ip_to_str(flow[NW_SRC]) + '/' + str(flow[NW_SRC_N_WILD]) + '\n')
def packet_in_callback(self, dpid, inport, reason, len, bufid, packet): if packet.type == Globals.ARP_TYPE: # ARP Response from replicas for our ARP Requests if packet.dst == octstr_to_array(Globals.VMAC): self.foundMac(dpid, mac_to_str(packet.src), ip_to_str(packet.next.protosrc), inport) # Request for VIP, respond with ARP Response elif packet.next.protodst == ipstr_to_int(Globals.VIP): Globals.STATSLOG.write(mac_to_str(dpid) + ' received ' + ip_to_str(packet.next.protosrc) + '\n') srcIP = ip_to_str(packet.next.protosrc) # Install Rewrite Rules (flow, defaultActions, rewriteActions) = IPs.get_forwarding_srcrule(srcIP, mac_to_str(packet.src), Globals.VMAC, Globals.VIP, inport) Multipath.install_microflow_flow(flow, openflow.OFP_FLOW_PERMANENT, openflow.OFP_FLOW_PERMANENT, defaultActions, None, openflow.OFP_DEFAULT_PRIORITY + 20, 0, None, dpid, inport, rewriteActions) # Response arpResponse = Arps.create_virtual_arp_response(packet, octstr_to_array(Globals.VMAC), ipstr_to_int(Globals.VIP)) Multipath.send(dpid, None, arpResponse, [[openflow.OFPAT_OUTPUT, [0, inport]]], openflow.OFPP_CONTROLLER) ip = ip_to_str(packet.next.protosrc) for i, switchJ in enumerate(Globals.SWITCHES): if switchJ['mac'] == dpid: found = False for i, client in enumerate(switchJ['clients']): if client['ip'] == ip: found = True if not found: Globals.STATSLOG.write(mac_to_str(dpid) + ' found ' + ip + '\n') switchJ['clients'].append({'port': inport, 'ip': ip, 'oldCount': 0L, 'newCount': 0L, 'avg': 0L}) elif packet.src != octstr_to_array(Globals.VMAC): Globals.STATSLOG.write(mac_to_str(dpid) + ' received REQ ' + ip_to_str(packet.next.protosrc) + '\n') arpResponse = Arps.create_arp_response(packet) Multipath.send(dpid, None, arpResponse, [[openflow.OFPAT_OUTPUT, [0, inport]]], openflow.OFPP_CONTROLLER) elif packet.type == Globals.IP_TYPE: if reason == openflow.OFPR_ACTION: IPTransition.handleControllerAction(packet)
def install_replica_flow(flow, idle_timeout, hard_timeout, actions, bufid, priority, inport, packet, replicaNum, rewriteActions): switchNum = findReplicasSwitch(replicaNum) orderMultipaths = getMultipaths(switchNum) Globals.log.info("Order Multipaths") Globals.log.info(str(orderMultipaths)) for currNode in orderMultipaths: currSwitchNum = currNode['no'] currMac = currNode['mac'] if flow.has_key(NW_SRC_N_WILD): flowList = getMultiFlow(flow, len(currNode['nexthops'])) for i, miniFlow in enumerate(flowList): if switchNum == currSwitchNum: nextHop = 0 actions = setReplicaOutPort(rewriteActions, switchNum, currSwitchNum, nextHop, replicaNum) else: nextHop = currNode['nexthops'][i % len(currNode['nexthops'])] actions = setReplicaOutPort(actions, switchNum, currSwitchNum, nextHop, replicaNum) Globals.COMPONENT.install_datapath_flow(currMac, miniFlow, idle_timeout, hard_timeout, actions, bufid, priority, inport, packet) Globals.RULESLOG.write(mac_to_str(currMac) + " Install Multipath @ " + str(currSwitchNum) + " to dest " + str(switchNum) + ' ' + ip_to_str(miniFlow[NW_SRC]) + '/' + str(miniFlow[NW_SRC_N_WILD]) + '\n') else: if switchNum == currSwitchNum: nextHop = 0 actions = setReplicaOutPort(rewriteActions, switchNum, currSwitchNum, nextHop, replicaNum) else: nextHopIndex = random.randint(0, len(currNode['nexthops']) - 1) nextHop = currNode['nexthops'][nextHopIndex] # nextHop = Globals.FORWARDINGTABLE[switchNum][currSwitchNum]['prevhop'] actions = setReplicaOutPort(actions, switchNum, currSwitchNum, nextHop, replicaNum) Globals.COMPONENT.install_datapath_flow(currMac, flow, idle_timeout, hard_timeout, actions, bufid, priority, inport, packet) Globals.RULESLOG.write(mac_to_str(currMac) + " Install Multipath @ " + str(currSwitchNum) + " to dest " + str(switchNum) + ' ' + ip_to_str(flow[NW_SRC]) + '\n') Globals.RULESLOG.write('Install Wildcard: ' + ip_to_str(flow[NW_SRC]) + '\n')
def l2_forwarding (self, dpid, inport, packet, bufid) : [forward_type, outports] = self.fdb.search (dpid, mac_to_str (packet.src), mac_to_str (packet.dst), inport) if forward_type == 'FLOOD' : actions = [] for port in outports : actions.append ([openflow.OFPAT_OUTPUT, [0, port]]) print 'flooding dipd=%x dstmac=%s' % (dpid, mac_to_str (packet.dst)) print outports self.send_openflow (dpid, bufid, packet.arr, actions, inport) elif forward_type == 'UNICAST' : flow = extract_flow (packet) flow[core.IN_PORT] = inport actions = [[openflow.OFPAT_OUTPUT, [0, outports.pop ()]]] self.install_datapath_flow (dpid, flow, FLOW_LIFETIME, openflow.OFP_FLOW_PERMANENT, actions, bufid, openflow.OFP_DEFAULT_PRIORITY, inport, packet.arr) return
def updateInstalledCounters(switchNum, ports): switch = getSwitch(Globals.SWITCHES, switchNum) Globals.log.info(mac_to_str(switchNum) + ' has ' + str(len(ports)) + ' ports') for i, port in enumerate(ports): for j, client in enumerate(switch['clients']): client['oldCount'] = client['newCount'] if port['port_no'] == client['port']: client['newCount'] = port['rx_packets'] # client['newCount'] = Globals.EMA_CONSTANT * port['rx_packets'] + (1 - Globals.EMA_CONSTANT) * client['oldCount'] # client['newCount'] = port['rx_packets'] client['avg'] = Globals.EMA_CONSTANT * (client['newCount'] - client['oldCount']) + (1 - Globals.EMA_CONSTANT) * client['oldCount'] Globals.STATSLOG.write(mac_to_str(switchNum) + ' ' + str(client['ip']) + ' -> ' + str(port['rx_packets']) + '\n')
def install_replica_flow(flow, idle_timeout, hard_timeout, actions, bufid, priority, inport, packet, replicaNum, rewriteActions): switchNum = findReplicasSwitch(replicaNum) orderMultipaths = getMultipaths(switchNum) Globals.log.info("Order Multipaths") Globals.log.info(str(orderMultipaths)) for currNode in orderMultipaths: currSwitchNum = currNode['no'] currMac = currNode['mac'] if flow.has_key(NW_SRC_N_WILD): flowList = getMultiFlow(flow, len(currNode['nexthops'])) for i, miniFlow in enumerate(flowList): if switchNum == currSwitchNum: nextHop = 0 actions = setReplicaOutPort(rewriteActions, switchNum, currSwitchNum, nextHop, replicaNum) else: nextHop = currNode['nexthops'][i % len(currNode['nexthops'])] actions = setReplicaOutPort(actions, switchNum, currSwitchNum, nextHop, replicaNum) Globals.COMPONENT.install_datapath_flow( currMac, miniFlow, idle_timeout, hard_timeout, actions, bufid, priority, inport, packet) Globals.RULESLOG.write( mac_to_str(currMac) + " Install Multipath @ " + str(currSwitchNum) + " to dest " + str(switchNum) + ' ' + ip_to_str(miniFlow[NW_SRC]) + '/' + str(miniFlow[NW_SRC_N_WILD]) + '\n') else: if switchNum == currSwitchNum: nextHop = 0 actions = setReplicaOutPort(rewriteActions, switchNum, currSwitchNum, nextHop, replicaNum) else: nextHopIndex = random.randint(0, len(currNode['nexthops']) - 1) nextHop = currNode['nexthops'][nextHopIndex] # nextHop = Globals.FORWARDINGTABLE[switchNum][currSwitchNum]['prevhop'] actions = setReplicaOutPort(actions, switchNum, currSwitchNum, nextHop, replicaNum) Globals.COMPONENT.install_datapath_flow(currMac, flow, idle_timeout, hard_timeout, actions, bufid, priority, inport, packet) Globals.RULESLOG.write( mac_to_str(currMac) + " Install Multipath @ " + str(currSwitchNum) + " to dest " + str(switchNum) + ' ' + ip_to_str(flow[NW_SRC]) + '\n') Globals.RULESLOG.write('Install Wildcard: ' + ip_to_str(flow[NW_SRC]) + '\n')
def host_bind_handler(self, data): """ Handler for host_bind_event """ assert(data is not None) try: bind_data = data.__dict__ dladdr = pkt_utils.mac_to_str(bind_data['dladdr']) host_ipaddr = nxw_utils.convert_ipv4_to_str(bind_data['nwaddr']) # Check reason value reason = int(bind_data['reason']) if not reason in self.__reasons: LOG.error("Got host_leave event with unsupported reason value") return CONTINUE reason_str = self.__reasons[reason] LOG.info("Received host_bind_ev with reason '%s'" % reason_str) # XXX FIXME: Insert mapping for values <--> reason if reason > 7: if dladdr not in self.hosts: LOG.debug("Ignoring Received host_leave_ev for an host" + \ " not present in DB") return CONTINUE else: ret = self.__host_leave(dladdr) if not ret: return CONTINUE elif (reason < 3 or reason == 5) and (bind_data['nwaddr'] == 0): LOG.debug("Ignoring host_bind_ev without IPaddr info") return CONTINUE elif (reason > 2) and (reason != 5): LOG.error("Unsupported reason for host_bind_ev: '%s'" % \ reason_str) return CONTINUE LOG.info("Received host_bind_ev with the following data: %s" % \ str(bind_data)) # Check for presence of the host in stored (internal) hosts if dladdr in self.hosts: if self.hosts[dladdr].ip_addr is None: LOG.debug("Got host_bind_ev for an host not posted yet") # Post host payload = {"ip_addr" : host_ipaddr, "mac" : dladdr, "peer_dpid" : self.hosts[dladdr].rem_dpid, "peer_portno": self.hosts[dladdr].rem_port} req = requests.post(url=self.url + "pckt_host", headers=self.hs, data=json.dumps(payload)) LOG.debug("URL=%s, response(code=%d, content=%s)", req.url, req.status_code, str(req.content)) else: LOG.debug("Got host_bind_ev for an host already posted") else: LOG.debug("Got host_bind_ev for an host not authenticated yet") except Exception, err: LOG.error("Got error in host_bind_handler (%s)" % str(err))
def dp_join(self, dp, stats): if self.known_switches.has_key(dp): lg.err("Received datapath join for a known switch: %s" % hex(dp)) del self.known_switches[dp] import pprint lg.debug("Received datapath join %s: %s" % (hex(dp), pprint.pformat(stats))) stats['dpid'] = dp ip = self.ctxt.get_switch_ip(dp) stats["ip"] = str(create_ipaddr(c_htonl(ip))) self.known_switches[dp] = stats ports_by_id = {} ports_by_name = {} for port in stats["ports"]: new_mac = mac_to_str(port['hw_addr']) port['hw_addr'] = new_mac ports_by_name[port['name']] = port ports_by_id[port['port_no']] = port stats["ports_by_id"] = ports_by_id stats["ports_by_name"] = ports_by_name return CONTINUE
def dp_join(self, dp, stats): dpid_obj = datapathid.from_host(dp) stats['dpid'] = dp self.dp_stats[dp] = stats # convert all port hw_addrs to ASCII # and register all port names with bindings storage port_list = self.dp_stats[dp]['ports'] for i in range(0,len(port_list)): new_mac = mac_to_str(port_list[i]['hw_addr']).replace(':','-') port_list[i]['hw_addr'] = new_mac # polling intervals for switch statistics self.dp_poll_period[dp] = {} self.dp_poll_period[dp]['table'] = DEFAULT_POLL_TABLE_PERIOD self.dp_poll_period[dp]['port'] = DEFAULT_POLL_PORT_PERIOD self.dp_poll_period[dp]['aggr'] = DEFAULT_POLL_AGGREGATE_PERIOD # Switch descriptions do not change while connected, so just send once self.ctxt.send_desc_stats_request(dp) # stagger timers by one second self.post_callback(self.dp_poll_period[dp]['table'], lambda : self.table_timer(dp)) self.post_callback(self.dp_poll_period[dp]['port'] + 1, lambda : self.port_timer(dp)) return CONTINUE
def do_l2_learning(dpid, inport, packet, buf, bufid): global inst # learn MAC on incoming port srcaddr = packet.src.tostring() if ord(srcaddr[0]) & 1: return if inst.st[dpid].has_key(srcaddr): dst = inst.st[dpid][srcaddr] if dst[0] != inport: log.msg('MAC has moved from ' + str(dst) + 'to' + str(inport), system='pyswitch') else: return else: log.msg('learned MAC ' + mac_to_str(packet.src) + ' on %d %d' % (dpid, inport), system="pyswitch") # learn or update timestamp of entry inst.st[dpid][srcaddr] = (inport, time(), packet) # and set-up wildcard flow to this mac address flow = {} flow[core.DL_DST] = packet.src actions = [[openflow.OFPAT_OUTPUT, [0, inport]]] inst.install_datapath_flow(dpid, flow, CACHE_TIMEOUT, openflow.OFP_FLOW_PERMANENT, actions, None, openflow.OFP_DEFAULT_PRIORITY, inport, None)
def __build_fentry_db(self, ingress): flow = {"dl_type" : None, "dl_src" : None, "dl_dst" : None, "dl_vlan" : None, "dl_vlan_pcp" : None, "nw_src" : None, "nw_dst" : None, "nw_proto" : None, "in_port" : None, "nw_src_n_wild" : None, "nw_dst_n_wild" : None, "tp_src" : None, "tp_dst" : None, } # update flow with not null received values for key in ingress: # conversions for mac_addr and nw_addr if (key == "dl_src") or (key == "dl_dst"): flow[key] = pkt_utils.mac_to_str(ingress[key]) elif (key == "nw_src") or (key == "nw_dst"): flow[key] = pkt_utils.ip_to_str(ingress[key]) else: flow[key] = ingress[key] return flow
def host_auth_handler(self, data): """ Handler for host_auth_event """ assert(data is not None) try: auth_data = data.__dict__ LOG.info("Received host_auth_ev with the following data: %s" % str(auth_data)) dladdr = pkt_utils.mac_to_str(auth_data['dladdr']) host_ipaddr = nxw_utils.convert_ipv4_to_str(auth_data['nwaddr']) try: # connect and open transaction self.db_conn.open_transaction() if auth_data['nwaddr'] == 0: LOG.debug("Received auth_event without IP address...") mac_addresses = self.db_conn.port_get_macs() if dladdr in mac_addresses: LOG.debug("Ignoring received auth_ev for OF switch...") return CONTINUE else: # Since Datapath_join event for an OF switch with # dladdr could be caught later, we need to store info self.hosts[dladdr] = nxw_utils.Host(dladdr) self.hosts[dladdr].rem_dpid = auth_data['datapath_id'] self.hosts[dladdr].rem_port = auth_data['port'] return CONTINUE if dladdr in self.auth_hosts: LOG.debug("Ignoring auth_event (more notifications for" + \ " multiple inter-switch links)") return CONTINUE self.auth_hosts.append(dladdr) host_idx = None try: host_idx = self.db_conn.host_get_index(dladdr) except Exception, err: LOG.debug("Any host with mac='%s' in DB" % str(dladdr)) if host_idx is None: LOG.debug("Adding new host with MAC addr '%s'" % \ str(dladdr)) try: # Insert Host info into DB self.__host_insert_db(dladdr, auth_data['datapath_id'], auth_data['port'], host_ipaddr) LOG.info("Added host '%s' into DB" % str(dladdr)) if dladdr in self.auth_hosts: self.auth_hosts.remove(dladdr) log.debug("Removed '%s' from (local) auth hosts" % str(dladdr)) except nxw_utils.DBException as err: LOG.error(str(err)) self.db_conn.rollback() except Exception, err: LOG.error("Cannot insert host info into DB ('%s')") else:
def port_status_handler(self, dpid, reason, port): intdp = int(dpid) if intdp not in self.dp_stats: log.err("port status from unknown datapath", system="switchstats") return # copy over existing port status for i in range(0, len(self.dp_stats[intdp]["ports"])): oldport = self.dp_stats[intdp]["ports"][i] if oldport["name"] == port["name"]: port["hw_addr"] = mac_to_str(port["hw_addr"]).replace(":", "-") self.dp_stats[intdp]["ports"][i] = port
def port_status_handler(self, dpid, reason, port): intdp = int(dpid) if intdp not in self.dp_stats: log.err('port status from unknown datapath', system='switchstats') return # copy over existing port status for i in range(0, len(self.dp_stats[intdp]['ports'])): oldport = self.dp_stats[intdp]['ports'][i] if oldport['name'] == port['name']: port['hw_addr'] = mac_to_str(port['hw_addr']).replace(':','-') self.dp_stats[intdp]['ports'][i] = port
def delete_flow(flow, replicaNum): switchNum = findReplicasSwitch(replicaNum) deleteMultipaths = getMultipaths(switchNum) for currNode in deleteMultipaths: currSwitchNum = currNode['no'] currMac = currNode['mac'] flowList = getMultiFlow(flow, len(currNode['nexthops'])) for i, miniFlow in enumerate(flowList): Globals.COMPONENT.delete_strict_datapath_flow(currMac, miniFlow) if not flow.has_key(NW_SRC_N_WILD): Globals.RULESLOG.write(mac_to_str(currMac) + " Delete Multipath @ " + str(currSwitchNum) + " to dest " + str(switchNum) + ' ' + ip_to_str(flow[NW_SRC]) + '\n') else: Globals.RULESLOG.write(mac_to_str(currMac) + " Delete Multipath @ " + str(currSwitchNum) + " to dest " + str(switchNum) + ' ' + ip_to_str(flow[NW_SRC]) + '/' + str(flow[NW_SRC_N_WILD]) + '\n') # orderDelete = getAllPaths(switchNum) # for switch in orderDelete: # currMac = getMac(switch) # Globals.log.info('Delete Flow: ' + str(flow) + ' at ' + str(switch)) # Globals.COMPONENT.delete_strict_datapath_flow(currMac, flow) Globals.RULESLOG.write('Delete: ' + ip_to_str(flow[NW_SRC]) + '/' + str(flow[NW_SRC_N_WILD]) + '\n')
def timer_callback(): global inst curtime = time() for dpid in inst.st.keys(): for entry in inst.st[dpid].keys(): if (curtime - inst.st[dpid][entry][1]) > CACHE_TIMEOUT: log.msg('timing out entry'+mac_to_str(entry)+str(inst.st[dpid][entry])+' on switch %x' % dpid, system='pyswitch') inst.st[dpid].pop(entry) inst.post_callback(1, timer_callback) return True
def do_l2_learning(dpid, inport, packet): global inst # learn MAC on incoming port srcaddr = packet.src.tostring() if ord(srcaddr[0]) & 1: return if inst.st[dpid].has_key(srcaddr): dst = inst.st[dpid][srcaddr] if dst[0] != inport: log.msg('MAC has moved from '+str(dst)+'to'+str(inport), system='pyswitch') else: return else: log.msg('learned MAC '+mac_to_str(packet.src)+' on %d %d'% (dpid,inport), system="pyswitch") logger.info('learned MAC '+mac_to_str(packet.src)+' on %x %d'% (dpid,inport)) # learn or update timestamp of entry inst.st[dpid][srcaddr] = (inport, time(), packet) # Replace any old entry for (switch,mac). mac = mac_to_int(packet.src)
def timer_callback(): global inst curtime = time() for dpid in inst.st.keys(): for entry in inst.st[dpid].keys(): if (curtime - inst.st[dpid][entry][1]) > CACHE_TIMEOUT: log.msg('timing out entry' + mac_to_str(entry) + str(inst.st[dpid][entry]) + ' on switch %x' % dpid, system='pyswitch') inst.st[dpid].pop(entry) inst.post_callback(1, timer_callback) return True
def learn_and_forward(self, dpid, inport, packet, buf, bufid): logger.info("Learning & Forwarding Packet" + str(packet)) # Starter psuedocode for learning switch exercise if not self.mac_to_port.has_key(dpid): self.mac_to_port[dpid] = {} #learn the port for the source MAC srcaddr = packet.src.tostring() if (self.mac_to_port[dpid].has_key(srcaddr)): # If address has already been learned, check if it has moved dst = self.mac_to_port[dpid][srcaddr] if dst[0] != inport: logger.info('MAC has moved from ' + str(dst) + 'to' + str(inport)) else: logger.info('Learned MAC ' + mac_to_str(packet.src) + 'on %d %d' % (dpid, inport)) self.mac_to_port[dpid][srcaddr] = (inport, packet) #if (destination MAC of the packet is known) dstaddr = packet.dst.tostring() if (self.mac_to_port[dpid].has_key(dstaddr)): logger.info('Learned Destionation MAC') prt = self.mac_to_port[dpid][dstaddr] #send unicast packet to known output port self.send_openflow(dpid, bufid, buf, prt[0], inport) # push down flow entry # flow = extract_flow(packet) # flow[core.IN_PORT] = inport # actions = [[openflow.OFPAT_OUTPUT, [0, prt[0]]]] # CACHE_TIMEOUT = 5 # self.install_datapath_flow(dpid, flow, CACHE_TIMEOUT, # openflow.OFP_FLOW_PERMANENT, actions, # bufid, openflow.OFP_DEFAULT_PRIORITY, # inport, buf) # else: #flood packet out everything but the input port self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport)
def dp_join(self, dp, stats): lg.warn('############### dp_join ###############\n') #lg.warn('dp_list_size = ', len(dp_list)) global dp_num if dp in dp_list: dp_list.remove(dp) lg.warn(dp) lg.warn('#######################################\n') dp_list.append(dp) dp_list.sort() dpid_obj = datapathid.from_host(dp) stats['dpid'] = dp self.dp_stats[dp] = stats # convert all port hw_addrs to ASCII # and register all port names with bindings storage port_list = self.dp_stats[dp]['ports'] for i in range(0,len(port_list)): new_mac = mac_to_str(port_list[i]['hw_addr']).replace(':','-') port_list[i]['hw_addr'] = new_mac # polling intervals for switch statistics self.dp_poll_period[dp] = {} self.dp_poll_period[dp]['table'] = DEFAULT_POLL_TABLE_PERIOD self.dp_poll_period[dp]['port'] = DEFAULT_POLL_PORT_PERIOD self.dp_poll_period[dp]['aggr'] = DEFAULT_POLL_AGGREGATE_PERIOD self.dp_poll_period[dp]['flow'] = DEFAULT_POLL_FLOW_PERIOD # Switch descriptions do not change while connected, so just send once #self.ctxt.send_desc_stats_request(dp) # stagger timers by one second self.post_callback(self.dp_poll_period[dp]['table'], lambda : self.table_timer(dp)) self.post_callback(self.dp_poll_period[dp]['port'] + 0.5, lambda : self.port_timer(dp)) self.post_callback(self.dp_poll_period[dp]['aggr'] + 1, lambda : self.aggr_timer(dp)) self.post_callback(self.dp_poll_period[dp]['flow'] + 1.5, lambda : self.flow_timer(dp)) self.post_callback(DEFAULT_POLL_FILE_PERIOD, lambda : self.file_timer()) return CONTINUE
def packet_in_callback(self, dpid, inport, reason, len, bufid, packet): """Packet-in handler""" if not packet.parsed: log.debug('Ignoring incomplete packet') else: print 'Packet-in no router', dpid, '--Fonte:', mac_to_str(packet.src), '--Destino:', mac_to_str(packet.dst) print 'In-Port:', inport if self.im == None: self.im = InstallationManager() self.im.nox = self #self.im.samples_number = 10 self.im.collect_begin_installs() self.install_routes() self.im.collect_end_installs() self.im.start() return CONTINUE
def host_auth_handler(self, data): """ Handler for host_auth_event """ assert(data is not None) try: auth_data = data.__dict__ LOG.info("Received host_auth_ev with the following data: %s" % str(auth_data)) dladdr = pkt_utils.mac_to_str(auth_data['dladdr']) host_ipaddr = nxw_utils.convert_ipv4_to_str(auth_data['nwaddr']) if dladdr in self.hosts: LOG.debug("Ignoring auth_event (more notifications for" + \ " multiple inter-switch links)") return CONTINUE r_ = dpid_from_host(auth_data['datapath_id']) if not r_: return CONTINUE self.hosts[dladdr] = nxw_utils.Host(dladdr) self.hosts[dladdr].rem_dpid = r_ self.hosts[dladdr].rem_port = auth_data['port'] if auth_data['nwaddr'] == 0: LOG.debug("Received auth_event without IP address...") else: LOG.debug("Received auth_event with IP address info...") self.hosts[dladdr].ip_addr = host_ipaddr # post host payload = {"ip_addr" : host_ipaddr, "mac" : dladdr, "peer_dpid" : r_, "peer_portno" : auth_data['port']} req = requests.post(url=self.url + "pckt_host", headers=self.hs, data=json.dumps(payload)) LOG.debug("URL=%s, response(code=%d, content=%s)", req.url, req.status_code, str(req.content)) except Exception, err: LOG.error("Got errors in host_auth_ev handler ('%s')" % str(err))
def __do_l2_learning(self, dpid, inport, packet): """ Layer 2 addresses learning """ assert(dpid is not None) assert(inport is not None) assert(packet is not None) # learn MAC on incoming port srcaddr = packet.src.tostring() if ord(srcaddr[0]) & 1: return if srcaddr in self.switches[dpid]: dst = self.switches[dpid][srcaddr] if dst[0] != inport: LOG.debug("MAC has moved from '%s' to '%s' " % (str(dst), str(inport))) else: return else: LOG.debug("Learned MAC '%s' on %d %d " % \ (pkt_utils.mac_to_str(packet.src), dpid, inport)) # learn or update timestamp of entry self.switches[dpid][srcaddr] = (inport, time(), packet)
def datapath_join_handler(self, dpid, stats): """ Handler for datapath_join event """ assert (dpid is not None) assert (stats is not None) dpid_ = dpid_from_host(dpid) if not dpid_: return CONTINUE try: ports = [] for p_info in stats['ports']: port = {} port['port_no'] = p_info['port_no'] port['hw_addr'] = pkt_utils.mac_to_str(p_info['hw_addr']) port['name'] = p_info['name'] port['config'] = p_info['config'] port['state'] = p_info['state'] port['curr'] = p_info['curr'] port['advertised'] = p_info['advertised'] port['supported'] = p_info['supported'] port['peer'] = p_info['peer'] ports.append(port) payload = {"dpid": dpid_, "region": "packet_" + self.region, "ofp_capabilities": stats['caps'], "ofp_actions": stats['actions'], "buffers": stats['n_bufs'], "tables": stats['n_tables'], "ports": ports} req = requests.post(url=self.url + "pckt_dpid", headers=self.hs, data=json.dumps(payload)) LOG.debug("URL=%s, response(code=%d, content=%s)", req.url, req.status_code, str(req.content)) except Exception, err: LOG.error("Got error in datapath_join handler (%s)" % str(err))
def do_l2_learning(dpid, inport, packet): global inst # learn MAC on incoming port srcaddr = packet.src.tostring() if ord(srcaddr[0]) & 1: return if inst.st[dpid].has_key(srcaddr): dst = inst.st[dpid][srcaddr] if dst[0] != inport: log.msg('MAC has moved from ' + str(dst) + 'to' + str(inport), system='pyswitch') else: return else: log.msg('learned MAC ' + mac_to_str(packet.src) + ' on %d %d' % (dpid, inport), system="pyswitch") # learn or update timestamp of entry inst.st[dpid][srcaddr] = (inport, time(), packet) # Replace any old entry for (switch,mac). mac = mac_to_int(packet.src)
def do_l2_learning(dpid, inport, packet, buf, bufid): global inst # learn MAC on incoming port srcaddr = packet.src.tostring() if ord(srcaddr[0]) & 1: return if inst.st[dpid].has_key(srcaddr): dst = inst.st[dpid][srcaddr] if dst[0] != inport: log.msg('MAC has moved from '+str(dst)+'to'+str(inport), system='pyswitch') else: return else: log.msg('learned MAC '+mac_to_str(packet.src)+' on %d %d'% (dpid,inport), system="pyswitch") # learn or update timestamp of entry inst.st[dpid][srcaddr] = (inport, time(), packet) # and set-up wildcard flow to this mac address flow = {} flow[core.DL_DST] = packet.src actions = [[openflow.OFPAT_OUTPUT, [0, inport]]] inst.install_datapath_flow(dpid, flow, CACHE_TIMEOUT, openflow.OFP_FLOW_PERMANENT, actions, None, openflow.OFP_DEFAULT_PRIORITY, inport, None)
def packet_in_callback(self, dpid, inport, reason, len, bufid, packet): # Install initial setup forwarding rules if self.Init == True: self.post_callback(Globals.PORT_STATS_PERIOD, lambda : self.port_timer()) self.Init = False # Controller Attention if reason == openflow.OFPR_ACTION: self.myIPTransition.controllerAction(packet) # Incoming ARPs elif packet.type == Globals.ARP_TYPE: # Response to our ARP requests # 1. Record MAC # 2. Install appropriate IP Forwarding Rule: Change dest VIP to dest Replica i if packet.dst == octstr_to_array(Globals.VMAC): foundMacs = True for i in range(0, Globals.NUMREPLICAS): if ((packet.next.protosrc == ipstr_to_int(Globals.REPLICAS[i]['ip'])) and (Globals.REPLICAS[i]['mac'] != mac_to_str(packet.src))): Globals.REPLICAS[i]['mac'] = mac_to_str(packet.src) Globals.REPLICAS[i]['port'] = inport for j, switchJ in enumerate(Globals.SWITCHES): if switchJ['mac'] == dpid: switchJ['replicas'].append(Globals.REPLICAS[i]['no']) if (Globals.REPLICAS[i]['mac'] == ''): foundMacs = False if foundMacs == True and self.AllMacsFound == False: Globals.log.info('REPLICAS ' + str(Globals.REPLICAS)) Globals.log.info('SWITCHES ' + str(Globals.SWITCHES)) Globals.log.info('\n') Globals.log.info('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>') rulePairList = self.myEvalRules.updateAlphas() self.myIPTransition.installRules(rulePairList) Globals.log.info('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<') Globals.log.info('\n') self.AllMacsFound = True # Requests for VIP respond with ARP Response elif packet.next.protodst == ipstr_to_int(Globals.VIP): srcIP = ip_to_str(packet.next.protosrc) # IP Rules (flow, defaultActions, rewriteActions) = IPs.get_forwarding_srcrule(srcIP, mac_to_str(packet.src), Globals.VMAC, Globals.VIP, inport) self.Multipath.install_microflow_flow(flow, openflow.OFP_FLOW_PERMANENT, openflow.OFP_FLOW_PERMANENT, defaultActions, None, openflow.OFP_DEFAULT_PRIORITY, 0, None, dpid, inport, rewriteActions) arpResponse = Arps.create_virtual_arp_response(packet, octstr_to_array(Globals.VMAC), ipstr_to_int(Globals.VIP)) self.Multipath.send(dpid, None, arpResponse, [[openflow.OFPAT_OUTPUT, [0, inport]]], openflow.OFPP_CONTROLLER) else: arpResponse = Arps.create_arp_response(packet) self.Multipath.send(dpid, None, arpResponse, [[openflow.OFPAT_OUTPUT, [0, inport]]], openflow.OFPP_CONTROLLER) elif packet.type == Globals.IP_TYPE: Globals.log.info("Warning! S1 SHOULD NOT BE RECEIVING IP Traffic!!!") # self.myIPTransition.controllerAction(packet) return CONTINUE
def lldp_input_handler(self, dp_id, inport, ofp_reason, total_frame_len, buffer_id, packet): assert (packet.type == ethernet.LLDP_TYPE) if not packet.next: lg.error("lldp_input_handler lldp packet could not be parsed") return assert (isinstance(packet.next, lldp)) lldph = packet.next if (len(lldph.tlvs) < 4) or \ (lldph.tlvs[0].type != lldp.CHASSIS_ID_TLV) or\ (lldph.tlvs[1].type != lldp.PORT_ID_TLV) or\ (lldph.tlvs[2].type != lldp.TTL_TLV): lg.error("lldp_input_handler invalid lldp packet") return # parse out chassis id if lldph.tlvs[0].subtype != chassis_id.SUB_MAC: lg.error("lldp chassis ID subtype is not MAC, ignoring") return assert(len(lldph.tlvs[0].id) == 6) cid = lldph.tlvs[0].id # convert 48bit cid (in nbo) to longlong chassid = cid[5] | cid[4] << 8 | \ cid[3] << 16 | cid[2] << 24 | \ cid[1] << 32 | cid[0] << 40 # if chassid is from a switch we're not connected to, ignore dst_dpid_ = None for k_ in self.dps.keys(): if chassid == (k_ & 0x00ffffff): dst_dpid_ = k_ break else: for info in self.dps[k_]['ports']: chassid_mac = array_to_octstr(array.array('B',struct.pack('!Q',chassid))[2:]) if chassid_mac == mac_to_str(info['hw_addr']): dst_dpid_ = k_ break if dst_dpid_: break if not dst_dpid_: lg.debug('Received LLDP packet from unconnected switch') return chassid = dst_dpid_ # grab 16bit port ID from port tlv if lldph.tlvs[1].subtype != port_id.SUB_PORT: return # not one of ours if len(lldph.tlvs[1].id) != 2: lg.error("invalid lldph port_id format") return (portid,) = struct.unpack("!H", lldph.tlvs[1].id) if (dp_id, inport) == (chassid, portid): lg.error('Loop detected, received our own LLDP event') return # print 'LLDP packet in from',longlong_to_octstr(chassid),' port',str(portid) #linktuple = (longlong_to_octstr(dp_id), inport, longlong_to_octstr(chassid), portid) linktuple = (dp_id, inport, chassid, portid) if linktuple not in self.adjacency_list: self.add_link(linktuple) lg.warn('new link detected ('+longlong_to_octstr(linktuple[0])+' p:'\ +str(linktuple[1]) +' -> '+\ longlong_to_octstr(linktuple[2])+\ ' p:'+str(linktuple[3])+')') # add to adjaceny list or update timestamp self.adjacency_list[(dp_id, inport, chassid, portid)] = time.time()
def host_bind_handler(self, data): """ Handler for host_binf_event """ assert(data is not None) try: bind_data = data.__dict__ dladdr = pkt_utils.mac_to_str(bind_data['dladdr']) host_ipaddr = nxw_utils.convert_ipv4_to_str(bind_data['nwaddr']) # Check reason value reason = int(bind_data['reason']) if not reason in self.__reasons: LOG.error("Got host_leave event with unsupported reason value") return CONTINUE reason_str = self.__reasons[reason] LOG.info("Received host_bind_ev with reason '%s'" % reason_str) # XXX FIXME: Insert mapping for values <--> reason if reason > 7: ret = self.__host_leave(dladdr) if not ret: return CONTINUE elif (reason < 3 or reason == 5) and (bind_data['nwaddr'] == 0): LOG.debug("Ignoring host_bind_ev without IPaddr info") return CONTINUE elif (reason > 2) and (reason != 5): LOG.error("Unsupported reason for host_bind_ev: '%s'" % \ reason_str) return CONTINUE LOG.info("Received host_bind_ev with the following data: %s" % \ str(bind_data)) try: try: self.db_conn.open_transaction() host_idx = None host_idx = self.db_conn.host_get_index(dladdr) LOG.debug("Host with mac_addr '%s' has index '%s'" % \ (str(dladdr), str(host_idx))) except Exception, err: LOG.debug("Any host with mac='%s' in DB" % str(dladdr)) if dladdr in self.hosts: LOG.debug("Got host_bind_ev for an host not present " + \ "in DB yet") # Insert Host info into DB self.__host_insert_db(dladdr, self.hosts[dladdr].rem_dpid, self.hosts[dladdr].rem_port, host_ipaddr) LOG.info("Added host '%s' into DB" % str(dladdr)) self.hosts.pop(dladdr) # XXX FIXME Remove auth_hosts (maintain only self.hosts) if dladdr in self.auth_hosts: self.auth_hosts.remove(dladdr) else: LOG.debug("Got host_bind_ev for an host already " + \ "present in DB") LOG.debug("Updating host info in DB...") self.db_conn.host_update(dladdr, host_ipaddr) self.db_conn.commit() LOG.info("Host info updated successfully") except nxw_utils.DBException as err: LOG.error(str(err)) self.db_conn.rollback() finally: self.db_conn.close() # check ior-dispatcher on pce node if not self.ior_topo and not self.pce_topology_enable(): LOG.error("Unable to contact ior-dispatcher on PCE node!") return CONTINUE nodes = [host_ipaddr] # Update flow-pce topology (hosts) LOG.debug("Hosts=%s", nodes) self.fpce.add_node_from_string(host_ipaddr) # update flow-pce topology (links between DPID and host) try: # connect and open transaction self.db_conn.open_transaction() # Host_insert dpid = self.db_conn.host_get_dpid(dladdr) in_port = self.db_conn.host_get_inport(dladdr) except nxw_utils.DBException as err: LOG.error(str(err)) self.db_conn.rollback() finally: self.db_conn.close() try: node = self.node_get_frompidport(dpid, in_port) nodes.append(node) except nxw_utils.DBException as err: LOG.error(str(err)) except Exception, err: LOG.error(str(err))
def datapath_join_handler(self, dpid, stats): """ Handler for datapath_join event """ assert (dpid is not None) assert (stats is not None) # insert values into topology-db try: # connect and open transaction self.db_conn.open_transaction() # datapath_insert self.db_conn.datapath_insert(d_id=dpid, d_name="ofswitch-" + str(dpid), caps=stats['caps'], actions=stats['actions'], buffers=stats['n_bufs'], tables=stats['n_tables']) # port_insert for p_info in stats['ports']: mac = pkt_utils.mac_to_str(p_info['hw_addr']) self.db_conn.port_insert(d_id=dpid, port_no=p_info['port_no'], hw_addr=mac, name=p_info['name'], config=p_info['config'], state=p_info['state'], curr=p_info['curr'], advertised=p_info['advertised'], supported=p_info['supported'], peer=p_info['peer']) # commit transaction self.db_conn.commit() LOG.debug("Successfull committed information!") except nxw_utils.DBException as err: LOG.error(str(err)) # rollback transaction self.db_conn.rollback() finally: self.db_conn.close() self.post_callback(5, lambda : self.table_timer(dpid)) self.post_callback(5, lambda : self.port_timer(dpid)) # check ior-dispatcher on pce node if not self.ior_topo and not self.pce_topology_enable(): LOG.error("Unable to contact ior-dispatcher on PCE node!") return CONTINUE # get datapath and ports index from topology-db nodes = [] try: for p_info in stats['ports']: node = self.node_get_frompidport(dpid, p_info['port_no']) nodes.append(node) except nxw_utils.DBException as err: LOG.error(str(err)) except Exception, err: LOG.error(str(err))
def learn_and_forward(self, dpid, inport, packet, buf, bufid): # Flood # Find MAC + IP from header srcMACaddr = packet.src.tostring() ippkt = self.get_ippacket(packet) srcIPaddr = '0.0.0.0' if (ippkt != None): srcIPaddr = ip_to_str(ippkt.srcip) # Does the source MAC + IP need to be learned? if (self.mac_to_port.has_key(srcMACaddr)): dstMACaddr = self.mac_to_port[srcMACaddr] if dstMACaddr[0] != inport: logger.info('MAC moved from ' + str(dst) + ' to ' + str(inport)) elif (dstMACaddr[1] == '0.0.0.0') and (srcIPaddr != None): logger.info('IP update') self.mac_to_port[srcMACaddr] = (inport, srcIPaddr) # If not, update table entry else: logger.info('MAC learned ' + mac_to_str(packet.src) + ' on %d %d' % (dpid, inport)) self.mac_to_port[srcMACaddr] = (inport, srcIPaddr) # Have we already learned destination MAC + IP? dstMACaddr = packet.dst.tostring() dstIPaddr = None if (ippkt != None): dstIPaddr = ip_to_str(ippkt.dstip) logger.info('Sending to destination') # Is this server address? if ((dstIPaddr != None) and (dstIPaddr == "10.0.0.0")): logger.info('SPECIAL FORWARDING IP\n') for item in self.mac_to_port.items(): logger.info(str(item) + "\n") if (item[1] == "10.0.0.2"): logger.info('Found 10.0.0.2 and sending packet\n'); self.send_openflow(dpid, bufid, buf, item[0], inport) #prt = self.mac_to_port[dstMACaddr] # CHANGE #self.send_openflow(dpid, bufid, buf, prt[0] ,inport) # HARDCODED if (isinstance(packet.next, arp.arp) and (ip_to_str(packet.next.protodst) == "10.0.0.0")): logger.info('SPECIAL FORWARDING ARP\n') for item in self.mac_to_port.items(): logger.info(str(item) + ": " + str(item[1][1]) + "\n") if (str(item[1][1]) == '10.0.0.2'): logger.info('Found 10.0.0.2 and sending packet\n'); #self.send_openflow(dpid, bufid, buf, item[1][0], inport) # Install Flow Rule #flow = extract_flow(packet) #flow[core.IN_PORT] = inport #flow = {} #flow[DL_TYPE] = 0x0800 #flow[NW_PROTO] = 17 #flow[NW_DST] = ippkt.srcip #flow[NW_DST_N_WILD] = 31 #actions = [[openflow.OFPAT_OUTPUT, [0, item[1][0]]]] #CACHE_TIMEOUT = 100 #self.install_datapath_flow(dpid, flow, CACHE_TIMEOUT, # openflow.OFP_FLOW_PERMANENT, actions, # bufid, openflow.OFP_DEFAULT_PRIORITY, # inport, buf) # Otherwise forward appropriately elif (self.mac_to_port.has_key(dstMACaddr)): prt = self.mac_to_port[dstMACaddr] #self.send_openflow(dpid, bufid, buf, prt[0] ,inport) # If we have not then flood else: self.send_openflow(dpid, bufid, buf, openflow.OFPP_FLOOD, inport) # Install Flow Rule #flow = extract_flow(packet) #flow[core.IN_PORT] = inport flow = {} #flow[DL_TYPE] = 0x0800 #flow[NW_PROTO] = 17 #flow[NW_DST] = flow[NW_DST_N_WILD] = 32 actions = [[openflow.OFPAT_OUTPUT, [0, 1]]] CACHE_TIMEOUT = 100 self.install_datapath_flow(dpid, flow, CACHE_TIMEOUT, openflow.OFP_FLOW_PERMANENT, actions, bufid, openflow.OFP_DEFAULT_PRIORITY, inport, buf)
def l2_learning (self, dpid, inport, packet) : self.fdb.update (dpid, mac_to_str (packet.src), inport) return