def createproxyarp(self, connection, arpentries): ''' Create ARP respond flow for specified ARP entries, each is a tuple (ip_address, mac_address, logical_network_id, local). When local is True, only respond to ARP request from logical port; when local is False, only respond to ARP request from physical port; respond to both else. ''' arp_list = self._extra_arps.setdefault(connection, []) arp_list.extend(arpentries) if connection in self._flowupdaters: self._flowupdaters[connection].updateobjects([ReferenceObject(LogicalNetwork.default_key(nid)) for _, _, nid, _ in arpentries])
def removeproxyarp(self, connection, arpentries): ''' Remove specified ARP entries. ''' arp_list = self._extra_arps[connection] for entry in arpentries: try: arp_list.remove(entry) except KeyError: pass if connection in self._flowupdaters: self._flowupdaters[connection].updateobjects([ReferenceObject(LogicalNetwork.default_key(nid)) for _, _, nid, _ in arpentries])
def updateflow(self, connection, addvalues, removevalues, updatedvalues): try: allobjs = set(o for o in self._savedresult if o is not None and not o.isdeleted()) lastlogportinfo = self._lastlogportinfo lastlognetinfo = self._lastlognetinfo lastphyportinfo = self._lastphyportinfo currentlognetinfo = dict((n, (id, n.physicalnetwork)) for n, id in self._lastlognets if n in allobjs) netdict = dict((n.getkey(), n) for n in currentlognetinfo) currentlogportinfo = dict((p, (id, p.network)) for p, id in self._lastlogports if p in allobjs) currentphyportinfo = dict((p, (id, p.physicalnetwork)) for p, id in self._lastphyports if p in allobjs) last_arps = self._last_arps current_arps = {} if connection in self._parent._extra_arps: _arps_list = self._parent._extra_arps[connection] for ip, mac, lognetid, islocal in _arps_list: lognet = netdict.get(LogicalNetwork.default_key(lognetid)) if lognet is not None: if islocal is None: arp_set = current_arps.setdefault(lognet, set()) arp_set.add((ip, mac, True, None, False)) arp_set.add((ip, mac, False, None, False)) else: arp_set = current_arps.setdefault(lognet, set()) arp_set.add((ip, mac, islocal, None, False)) broadcast_only = self._parent.broadcastonly if self._parent.prepush: for obj in self._savedresult: if obj is not None and not obj.isdeleted( ) and obj.isinstance(LogicalPort) and hasattr( obj, 'ip_address') and hasattr(obj, 'mac_address'): if obj.network in currentlognetinfo: arp_set = current_arps.setdefault( obj.network, set()) arp_set.add((obj.ip_address, obj.mac_address, True, obj, broadcast_only)) self._lastlogportinfo = currentlogportinfo self._lastlognetinfo = currentlognetinfo self._lastphyportinfo = currentphyportinfo self._last_arps = current_arps cmds = [] ofdef = connection.openflowdef vhost = connection.protocol.vhost arp = self._parent._gettableindex('arp', vhost) l2out_next = self._parent._getnexttable('', 'l2output', vhost=vhost) #=================================================================== # if connection.protocol.disablenxext: # def match_network(nid): # return ofdef.create_oxm(ofdef.OXM_OF_METADATA_W, (nid & 0xFFFF) << 48, 0xFFFF000000000000) # def create_instructions(actions, pid): # return [ofdef.ofp_instruction_actions(actions = actions), # ofdef.ofp_instruction_write_metadata(metadata = 0x0000000080000000 | (pid & 0xffff), # metadata_mask = 0x000000008000ffff), # ofdef.ofp_instruction_goto_table(table_id = l2out_next)] #=================================================================== #else: def match_network(nid): return ofdef.create_oxm(ofdef.NXM_NX_REG4, nid) def create_instructions(actions): return [ofdef.ofp_instruction_actions(actions = actions + \ [ofdef.nx_action_reg_load( ofs_nbits = ofdef.create_ofs_nbits(15,1), dst = ofdef.NXM_NX_REG7, value = 1 ), ofdef.nx_action_reg_move( n_bits = 32, src = ofdef.OXM_OF_IN_PORT, dst = ofdef.NXM_NX_REG6 )]), ofdef.ofp_instruction_goto_table(table_id = l2out_next)] for p in lastlogportinfo: if p not in currentlogportinfo or currentlogportinfo[ p] != lastlogportinfo[p]: pid, _ = lastlogportinfo[p] cmds.append( ofdef.ofp_flow_mod( table_id=arp, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm(oxm_fields=[ ofdef.create_oxm(ofdef.OXM_OF_IN_PORT, pid) ]))) for p in lastphyportinfo: if p not in currentphyportinfo or currentphyportinfo[ p] != lastphyportinfo[p]: pid, _ = lastphyportinfo[p] cmds.append( ofdef.ofp_flow_mod( table_id=arp, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm(oxm_fields=[ ofdef.create_oxm(ofdef.OXM_OF_IN_PORT, pid) ]))) for n in last_arps: if n not in current_arps: if n in lastlognetinfo: nid, _ = lastlognetinfo[n] for ip, _, islocal, _, _ in last_arps[n]: cmds.append( ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0x3, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm(oxm_fields=[ match_network(nid), ofdef.create_oxm( ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm( ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ]))) else: if n in lastlognetinfo and n in currentlognetinfo and currentlognetinfo[ n] != lastlognetinfo[n]: nid, _ = lastlognetinfo[n] for ip, _, islocal, _, _ in last_arps[n]: cmds.append( ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0x3, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm(oxm_fields=[ match_network(nid), ofdef.create_oxm( ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm( ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ]))) else: if n in currentlognetinfo: nid, _ = currentlognetinfo[n] for ip, _, islocal, _, _ in last_arps[ n].difference(current_arps[n]): cmds.append( ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0x3, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm(oxm_fields=[ match_network(nid), ofdef.create_oxm( ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm( ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ]))) for m in self.execute_commands(connection, cmds): yield m del cmds[:] # Create flows def _create_flow(ip, mac, nid, islocal, broadcast): return ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0xffffffffffffffff, command=ofdef.OFPFC_ADD, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, priority=ofdef.OFP_DEFAULT_PRIORITY, match=ofdef.ofp_match_oxm(oxm_fields=[ ofdef.create_oxm(ofdef.NXM_NX_REG7_W, 0x4000 if islocal else 0, 0x4000), match_network(nid), ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm(ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm(ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ] + ([ ofdef.create_oxm(ofdef.OXM_OF_ETH_DST_W, b'\x01\x00\x00\x00\x00\x00', b'\x01\x00\x00\x00\x00\x00') ] if broadcast else [])), instructions=create_instructions([ ofdef.nx_action_reg_move(n_bits=32, src=ofdef.OXM_OF_ARP_SPA, dst=ofdef.OXM_OF_ARP_TPA), ofdef.nx_action_reg_move(n_bits=48, src=ofdef.OXM_OF_ARP_SHA, dst=ofdef.OXM_OF_ARP_THA), ofdef.nx_action_reg_move(n_bits=48, src=ofdef.OXM_OF_ETH_SRC, dst=ofdef.OXM_OF_ETH_DST), ofdef.ofp_action_set_field(field=ofdef.create_oxm( ofdef.OXM_OF_ARP_SPA, ofdef.ip4_addr(ip))), ofdef.ofp_action_set_field(field=ofdef.create_oxm( ofdef.OXM_OF_ARP_SHA, ofdef.mac_addr(mac), )), ofdef.ofp_action_set_field(field=ofdef.create_oxm( ofdef.OXM_OF_ETH_SRC, ofdef.mac_addr(mac), )), ofdef.ofp_action_set_field(field=ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REPLY)) ])) def _create_flow2(ip, mac, nid, pid, islocal, broadcast): return ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0xffffffffffffffff, command=ofdef.OFPFC_ADD, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, priority=ofdef.OFP_DEFAULT_PRIORITY + 10, match=ofdef.ofp_match_oxm(oxm_fields=[ ofdef.create_oxm(ofdef.OXM_OF_IN_PORT, pid), match_network(nid), ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm(ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm(ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ] + ([ ofdef.create_oxm(ofdef.OXM_OF_ETH_DST_W, b'\x01\x00\x00\x00\x00\x00', b'\x01\x00\x00\x00\x00\x00') ] if broadcast else [])), instructions=[ ofdef.ofp_instruction_actions( type=ofdef.OFPIT_CLEAR_ACTIONS) ]) logport_arps = dict((ent[3], ent) for n, v in current_arps.items() for ent in v if ent[3] is not None) for p in currentlogportinfo: if p not in lastlogportinfo or lastlogportinfo[ p] != currentlogportinfo[p]: if p in logport_arps: ip, mac, islocal, port, broadcast = logport_arps[p] pid, lognet = currentlogportinfo[p] if lognet in current_arps and lognet in currentlognetinfo: nid, _ = currentlognetinfo[lognet] if islocal and port == p: cmds.append( _create_flow2(ip, mac, nid, pid, islocal, broadcast)) # phynetdict = {} # for n in current_arps: # phynet = n.physicalnetwork # phynetdict.setdefault(phynet, []).append(n) #=================================================================== # for p in currentphyportinfo: # if p not in lastphyportinfo or lastphyportinfo[p] != currentphyportinfo[p]: # pid, phynet = currentphyportinfo[p] # if phynet in phynetdict: # for n in phynetdict[phynet]: # if n in current_arps: # nid, _ = currentlognetinfo[n] # for ip, mac, islocal, port, broadcast in current_arps[n]: # if not islocal and port != p: # cmds.append(_create_flow(ip, mac, nid, islocal, broadcast)) #=================================================================== phyportdict = {} for p in currentphyportinfo: phynet = p.physicalnetwork phyportdict.setdefault(phynet, []).append(p) for n, arps in current_arps.items(): if n in currentlognetinfo: nid, _ = currentlognetinfo[n] if n not in last_arps or n not in lastlognetinfo or lastlognetinfo[ n] != currentlognetinfo[n]: send_arps = arps else: send_arps = arps.difference(last_arps[n]) for ip, mac, islocal, port, broadcast in send_arps: cmds.append( _create_flow(ip, mac, nid, islocal, broadcast)) if islocal: if port in currentlognetinfo: cmds.append( _create_flow2(ip, mac, nid, pid, islocal, broadcast)) for m in self.execute_commands(connection, cmds): yield m except Exception: self._logger.warning( "Unexpected exception in ARPUpdater. Will ignore and continue.", exc_info=True)
async def updateflow(self, connection, addvalues, removevalues, updatedvalues): try: allobjs = set(o for o in self._savedresult if o is not None and not o.isdeleted()) lastlogportinfo = self._lastlogportinfo lastlognetinfo = self._lastlognetinfo lastphyportinfo = self._lastphyportinfo lastfreearps = self._last_freearps currentlognetinfo = dict((n, (id, n.physicalnetwork)) for n, id in self._lastlognets if n in allobjs) netdict = dict((n.getkey(), n) for n in currentlognetinfo) currentlogportinfo = dict((p, (id, p.network)) for p, id in self._lastlogports if p in allobjs) currentphyportinfo = dict((p, (id, p.physicalnetwork)) for p, id in self._lastphyports if p in allobjs) last_arps = self._last_arps current_arps = {} if connection in self._parent._extra_arps: _arps_list = self._parent._extra_arps[connection] for ip, mac, lognetid, islocal in _arps_list: lognet = netdict.get(LogicalNetwork.default_key(lognetid)) if lognet is not None: if islocal is None: arp_set = current_arps.setdefault(lognet, {}) arp_set[(ip, True)] = (mac, False) arp_set[(ip, False)] = (mac, False) else: arp_set = current_arps.setdefault(lognet, {}) arp_set[(ip, islocal)] = (mac, False) broadcast_only = self._parent.broadcastonly currentfreearps = {} if self._parent.prepush: for obj in self._savedresult: if obj is not None and not obj.isdeleted( ) and obj.isinstance(LogicalPort) and hasattr( obj, 'ip_address') and hasattr(obj, 'mac_address'): if obj.network in currentlognetinfo: arp_set = current_arps.setdefault(obj.network, {}) arp_set[(obj.ip_address, True)] = (obj.mac_address, broadcast_only) if obj in currentlogportinfo: # This port is in local switch, add a free ARP flow pid, network = currentlogportinfo[obj] currentfreearps[(network, obj.ip_address, obj)] = (obj.mac_address, broadcast_only, network.physicalnetwork.type in self._parent.enable_freearp_networktypes and \ self._parent.enable_freearp) # Flow mapping: # arp_set => create_flow # currentfreearps => create_flow2 self._lastlogportinfo = currentlogportinfo self._lastlognetinfo = currentlognetinfo self._lastphyportinfo = currentphyportinfo self._last_arps = current_arps self._last_freearps = currentfreearps cmds = [] ofdef = connection.openflowdef vhost = connection.protocol.vhost arp = self._parent._gettableindex('arp', vhost) l2out_next = self._parent._getnexttable('', 'l2output', vhost=vhost) arp_next = self._parent._getnexttable('', 'arp', vhost=vhost) #=================================================================== # if connection.protocol.disablenxext: # def match_network(nid): # return ofdef.create_oxm(ofdef.OXM_OF_METADATA_W, (nid & 0xFFFF) << 48, 0xFFFF000000000000) # def create_instructions(actions, pid): # return [ofdef.ofp_instruction_actions(actions = actions), # ofdef.ofp_instruction_write_metadata(metadata = 0x0000000080000000 | (pid & 0xffff), # metadata_mask = 0x000000008000ffff), # ofdef.ofp_instruction_goto_table(table_id = l2out_next)] #=================================================================== #else: def match_network(nid): return ofdef.create_oxm(ofdef.NXM_NX_REG4, nid) def create_instructions(actions): return [ofdef.ofp_instruction_actions(actions = actions + \ [ofdef.nx_action_reg_load( ofs_nbits = ofdef.create_ofs_nbits(15,1), dst = ofdef.NXM_NX_REG7, value = 1 ), ofdef.nx_action_reg_move( n_bits = 32, src = ofdef.OXM_OF_IN_PORT, dst = ofdef.NXM_NX_REG6 )]), ofdef.ofp_instruction_goto_table(table_id = l2out_next)] for n in last_arps: if n not in current_arps: if n in lastlognetinfo: nid, _ = lastlognetinfo[n] for ip, islocal in last_arps[n]: cmds.append( ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0x7, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm(oxm_fields=[ match_network(nid), ofdef.create_oxm( ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm( ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ]))) else: if n in lastlognetinfo and n in currentlognetinfo and currentlognetinfo[ n] != lastlognetinfo[n]: # Delete all because network changes nid, _ = lastlognetinfo[n] for ip, islocal in last_arps[n]: cmds.append( ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0x7, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm(oxm_fields=[ match_network(nid), ofdef.create_oxm( ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm( ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ]))) else: if n in currentlognetinfo: nid, _ = currentlognetinfo[n] for (ip, islocal), value in last_arps[n].items(): if (ip, islocal) not in current_arps[ n] or value != current_arps[n]: cmds.append( ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0x7, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm( oxm_fields=[ match_network(nid), ofdef.create_oxm( ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm( ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ]))) for (network, ip, port), value in lastfreearps.items(): if (network, ip, port) not in currentfreearps or currentfreearps[(network, ip, port)] != value \ or lastlogportinfo.get(port) != currentlogportinfo.get(port) \ or lastlognetinfo.get(network) != currentlognetinfo.get(network): if port in lastlogportinfo and network in lastlognetinfo: pid, _ = lastlogportinfo[port] nid, _ = lastlognetinfo[network] cmds.append( ofdef.ofp_flow_mod( table_id=arp, cookie=0x5 | (0x2 if islocal else 0), cookie_mask=0x7, command=ofdef.OFPFC_DELETE, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, match=ofdef.ofp_match_oxm(oxm_fields=[ ofdef.create_oxm(ofdef.OXM_OF_IN_PORT, pid), match_network(nid), ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm(ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm(ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ]))) await self.execute_commands(connection, cmds) del cmds[:] # Create flows def _create_flow(ip, mac, nid, islocal, broadcast): return ofdef.ofp_flow_mod( table_id=arp, cookie=0x1 | (0x2 if islocal else 0), cookie_mask=0xffffffffffffffff, command=ofdef.OFPFC_ADD, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, priority=ofdef.OFP_DEFAULT_PRIORITY, match=ofdef.ofp_match_oxm(oxm_fields=[ ofdef.create_oxm(ofdef.NXM_NX_REG7_W, 0x4000 if islocal else 0, 0x4000), match_network(nid), ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm(ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm(ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ] + ([ ofdef.create_oxm(ofdef.OXM_OF_ETH_DST_W, b'\x01\x00\x00\x00\x00\x00', b'\x01\x00\x00\x00\x00\x00') ] if broadcast else [])), instructions=create_instructions([ ofdef.nx_action_reg_move(n_bits=32, src=ofdef.OXM_OF_ARP_SPA, dst=ofdef.OXM_OF_ARP_TPA), ofdef.nx_action_reg_move(n_bits=48, src=ofdef.OXM_OF_ARP_SHA, dst=ofdef.OXM_OF_ARP_THA), ofdef.nx_action_reg_move(n_bits=48, src=ofdef.OXM_OF_ETH_SRC, dst=ofdef.OXM_OF_ETH_DST), ofdef.ofp_action_set_field(field=ofdef.create_oxm( ofdef.OXM_OF_ARP_SPA, ofdef.ip4_addr(ip))), ofdef.ofp_action_set_field(field=ofdef.create_oxm( ofdef.OXM_OF_ARP_SHA, ofdef.mac_addr(mac), )), ofdef.ofp_action_set_field(field=ofdef.create_oxm( ofdef.OXM_OF_ETH_SRC, ofdef.mac_addr(mac), )), ofdef.ofp_action_set_field(field=ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REPLY)) ])) def _create_flow2(ip, mac, nid, pid, islocal, broadcast, ifpass): if ifpass: ins = [ofdef.ofp_instruction_goto_table(table_id=arp_next)] else: ins = [ ofdef.ofp_instruction_actions( type=ofdef.OFPIT_CLEAR_ACTIONS) ] return ofdef.ofp_flow_mod( table_id=arp, cookie=0x5 | (0x2 if islocal else 0), cookie_mask=0xffffffffffffffff, command=ofdef.OFPFC_ADD, buffer_id=ofdef.OFP_NO_BUFFER, out_port=ofdef.OFPP_ANY, out_group=ofdef.OFPG_ANY, priority=ofdef.OFP_DEFAULT_PRIORITY + 10, match=ofdef.ofp_match_oxm(oxm_fields=[ ofdef.create_oxm(ofdef.OXM_OF_IN_PORT, pid), match_network(nid), ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm(ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm(ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ] + ([ ofdef.create_oxm(ofdef.OXM_OF_ETH_DST_W, b'\x01\x00\x00\x00\x00\x00', b'\x01\x00\x00\x00\x00\x00') ] if broadcast else [])), instructions=ins) for (network, ip, port), value in currentfreearps.items(): if (network, ip, port) not in lastfreearps or lastfreearps[(network, ip, port)] != value \ or lastlogportinfo.get(port) != currentlogportinfo.get(port) \ or lastlognetinfo.get(network) != currentlognetinfo.get(network): if port in currentlogportinfo and network in currentlognetinfo: pid, _ = currentlogportinfo[port] nid, _ = currentlognetinfo[network] mac, broadcast, ifpass = value cmds.append( _create_flow2(ip, mac, nid, pid, True, broadcast, ifpass)) # phynetdict = {} # for n in current_arps: # phynet = n.physicalnetwork # phynetdict.setdefault(phynet, []).append(n) #=================================================================== # for p in currentphyportinfo: # if p not in lastphyportinfo or lastphyportinfo[p] != currentphyportinfo[p]: # pid, phynet = currentphyportinfo[p] # if phynet in phynetdict: # for n in phynetdict[phynet]: # if n in current_arps: # nid, _ = currentlognetinfo[n] # for ip, mac, islocal, port, broadcast in current_arps[n]: # if not islocal and port != p: # cmds.append(_create_flow(ip, mac, nid, islocal, broadcast)) #=================================================================== for n, arps in current_arps.items(): if n in currentlognetinfo: nid, _ = currentlognetinfo[n] if n not in last_arps or n not in lastlognetinfo or lastlognetinfo[ n] != currentlognetinfo[n]: send_arps = arps else: send_arps = { k: v for k, v in arps.items() if k not in last_arps[n] or last_arps[n] != v } for (ip, islocal), (mac, broadcast) in send_arps.items(): cmds.append( _create_flow(ip, mac, nid, islocal, broadcast)) await self.execute_commands(connection, cmds) except Exception: self._logger.warning( "Unexpected exception in ARPUpdater. Will ignore and continue.", exc_info=True)
def updateflow(self, connection, addvalues, removevalues, updatedvalues): try: allobjs = set(o for o in self._savedresult if o is not None and not o.isdeleted()) lastlogportinfo = self._lastlogportinfo lastlognetinfo = self._lastlognetinfo lastphyportinfo = self._lastphyportinfo currentlognetinfo = dict((n,(id, n.physicalnetwork)) for n,id in self._lastlognets if n in allobjs) netdict = dict((n.getkey(), n) for n in currentlognetinfo) currentlogportinfo = dict((p, (id, p.network)) for p,id in self._lastlogports if p in allobjs) currentphyportinfo = dict((p, (id, p.physicalnetwork)) for p,id in self._lastphyports if p in allobjs) last_arps = self._last_arps current_arps = {} if connection in self._parent._extra_arps: _arps_list = self._parent._extra_arps[connection] for ip, mac, lognetid, islocal in _arps_list: lognet = netdict.get(LogicalNetwork.default_key(lognetid)) if lognet is not None: if islocal is None: arp_set = current_arps.setdefault(lognet, set()) arp_set.add((ip, mac, True, None, False)) arp_set.add((ip, mac, False, None, False)) else: arp_set = current_arps.setdefault(lognet, set()) arp_set.add((ip, mac, islocal, None, False)) broadcast_only = self._parent.broadcastonly if self._parent.prepush: for obj in self._savedresult: if obj is not None and not obj.isdeleted() and obj.isinstance(LogicalPort) and hasattr(obj, 'ip_address') and hasattr(obj, 'mac_address'): if obj.network in currentlognetinfo: arp_set = current_arps.setdefault(obj.network, set()) arp_set.add((obj.ip_address, obj.mac_address, True, obj, broadcast_only)) self._lastlogportinfo = currentlogportinfo self._lastlognetinfo = currentlognetinfo self._lastphyportinfo = currentphyportinfo self._last_arps = current_arps cmds = [] ofdef = connection.openflowdef vhost = connection.protocol.vhost arp = self._parent._gettableindex('arp', vhost) l2out_next = self._parent._getnexttable('', 'l2output', vhost = vhost) #=================================================================== # if connection.protocol.disablenxext: # def match_network(nid): # return ofdef.create_oxm(ofdef.OXM_OF_METADATA_W, (nid & 0xFFFF) << 48, 0xFFFF000000000000) # def create_instructions(actions, pid): # return [ofdef.ofp_instruction_actions(actions = actions), # ofdef.ofp_instruction_write_metadata(metadata = 0x0000000080000000 | (pid & 0xffff), # metadata_mask = 0x000000008000ffff), # ofdef.ofp_instruction_goto_table(table_id = l2out_next)] #=================================================================== #else: def match_network(nid): return ofdef.create_oxm(ofdef.NXM_NX_REG4, nid) def create_instructions(actions): return [ofdef.ofp_instruction_actions(actions = actions + \ [ofdef.nx_action_reg_load( ofs_nbits = ofdef.create_ofs_nbits(15,1), dst = ofdef.NXM_NX_REG7, value = 1 ), ofdef.nx_action_reg_move( n_bits = 32, src = ofdef.OXM_OF_IN_PORT, dst = ofdef.NXM_NX_REG6 )]), ofdef.ofp_instruction_goto_table(table_id = l2out_next)] for p in lastlogportinfo: if p not in currentlogportinfo or currentlogportinfo[p] != lastlogportinfo[p]: pid, _ = lastlogportinfo[p] cmds.append(ofdef.ofp_flow_mod(table_id = arp, command = ofdef.OFPFC_DELETE, buffer_id = ofdef.OFP_NO_BUFFER, out_port = ofdef.OFPP_ANY, out_group = ofdef.OFPG_ANY, match = ofdef.ofp_match_oxm( oxm_fields = [ofdef.create_oxm(ofdef.OXM_OF_IN_PORT, pid)] ) )) for p in lastphyportinfo: if p not in currentphyportinfo or currentphyportinfo[p] != lastphyportinfo[p]: pid, _ = lastphyportinfo[p] cmds.append(ofdef.ofp_flow_mod(table_id = arp, command = ofdef.OFPFC_DELETE, buffer_id = ofdef.OFP_NO_BUFFER, out_port = ofdef.OFPP_ANY, out_group = ofdef.OFPG_ANY, match = ofdef.ofp_match_oxm( oxm_fields = [ofdef.create_oxm(ofdef.OXM_OF_IN_PORT, pid)] ) )) for n in last_arps: if n not in current_arps: if n in lastlognetinfo: nid, _ = lastlognetinfo[n] for ip,_,islocal,_,_ in last_arps[n]: cmds.append(ofdef.ofp_flow_mod(table_id = arp, cookie = 0x1 | (0x2 if islocal else 0), cookie_mask = 0x3, command = ofdef.OFPFC_DELETE, buffer_id = ofdef.OFP_NO_BUFFER, out_port = ofdef.OFPP_ANY, out_group = ofdef.OFPG_ANY, match = ofdef.ofp_match_oxm( oxm_fields = [match_network(nid), ofdef.create_oxm( ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm( ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ] ) )) else: if n in lastlognetinfo and n in currentlognetinfo and currentlognetinfo[n] != lastlognetinfo[n]: nid, _ = lastlognetinfo[n] for ip,_,islocal,_,_ in last_arps[n]: cmds.append(ofdef.ofp_flow_mod(table_id = arp, cookie = 0x1 | (0x2 if islocal else 0), cookie_mask = 0x3, command = ofdef.OFPFC_DELETE, buffer_id = ofdef.OFP_NO_BUFFER, out_port = ofdef.OFPP_ANY, out_group = ofdef.OFPG_ANY, match = ofdef.ofp_match_oxm( oxm_fields = [match_network(nid), ofdef.create_oxm( ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm( ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ] ) )) else: if n in currentlognetinfo: nid, _ = currentlognetinfo[n] for ip, _, islocal, _, _ in last_arps[n].difference(current_arps[n]): cmds.append(ofdef.ofp_flow_mod(table_id = arp, cookie = 0x1 | (0x2 if islocal else 0), cookie_mask = 0x3, command = ofdef.OFPFC_DELETE, buffer_id = ofdef.OFP_NO_BUFFER, out_port = ofdef.OFPP_ANY, out_group = ofdef.OFPG_ANY, match = ofdef.ofp_match_oxm( oxm_fields = [match_network(nid), ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm(ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm(ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST) ] ) )) for m in self.execute_commands(connection, cmds): yield m del cmds[:] # Create flows def _create_flow(ip, mac, nid, islocal, broadcast): return ofdef.ofp_flow_mod( table_id = arp, cookie = 0x1 | (0x2 if islocal else 0), cookie_mask = 0xffffffffffffffff, command = ofdef.OFPFC_ADD, buffer_id = ofdef.OFP_NO_BUFFER, out_port = ofdef.OFPP_ANY, out_group = ofdef.OFPG_ANY, priority = ofdef.OFP_DEFAULT_PRIORITY, match = ofdef.ofp_match_oxm( oxm_fields = [ ofdef.create_oxm(ofdef.NXM_NX_REG7_W, 0x4000 if islocal else 0, 0x4000), match_network(nid), ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm(ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm(ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST)] + ([ofdef.create_oxm(ofdef.OXM_OF_ETH_DST_W, b'\x01\x00\x00\x00\x00\x00', b'\x01\x00\x00\x00\x00\x00')] if broadcast else []) ), instructions = create_instructions([ofdef.nx_action_reg_move( n_bits = 32, src = ofdef.OXM_OF_ARP_SPA, dst = ofdef.OXM_OF_ARP_TPA), ofdef.nx_action_reg_move( n_bits = 48, src = ofdef.OXM_OF_ARP_SHA, dst = ofdef.OXM_OF_ARP_THA), ofdef.nx_action_reg_move( n_bits = 48, src = ofdef.OXM_OF_ETH_SRC, dst = ofdef.OXM_OF_ETH_DST), ofdef.ofp_action_set_field( field = ofdef.create_oxm( ofdef.OXM_OF_ARP_SPA, ofdef.ip4_addr(ip) )), ofdef.ofp_action_set_field( field = ofdef.create_oxm( ofdef.OXM_OF_ARP_SHA, ofdef.mac_addr(mac), )), ofdef.ofp_action_set_field( field = ofdef.create_oxm( ofdef.OXM_OF_ETH_SRC, ofdef.mac_addr(mac), )), ofdef.ofp_action_set_field( field = ofdef.create_oxm( ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REPLY ) ) ]) ) def _create_flow2(ip, mac, nid, pid, islocal, broadcast): return ofdef.ofp_flow_mod( table_id = arp, cookie = 0x1 | (0x2 if islocal else 0), cookie_mask = 0xffffffffffffffff, command = ofdef.OFPFC_ADD, buffer_id = ofdef.OFP_NO_BUFFER, out_port = ofdef.OFPP_ANY, out_group = ofdef.OFPG_ANY, priority = ofdef.OFP_DEFAULT_PRIORITY + 10, match = ofdef.ofp_match_oxm( oxm_fields = [ ofdef.create_oxm(ofdef.OXM_OF_IN_PORT, pid), match_network(nid), ofdef.create_oxm(ofdef.OXM_OF_ETH_TYPE, ofdef.ETHERTYPE_ARP), ofdef.create_oxm(ofdef.OXM_OF_ARP_TPA, ofdef.ip4_addr(ip)), ofdef.create_oxm(ofdef.OXM_OF_ARP_OP, ofdef.ARPOP_REQUEST)] + ([ofdef.create_oxm(ofdef.OXM_OF_ETH_DST_W, b'\x01\x00\x00\x00\x00\x00', b'\x01\x00\x00\x00\x00\x00')] if broadcast else []) ), instructions = [ofdef.ofp_instruction_actions(type = ofdef.OFPIT_CLEAR_ACTIONS)] ) logport_arps = dict((ent[3],ent) for n,v in current_arps.items() for ent in v if ent[3] is not None) for p in currentlogportinfo: if p not in lastlogportinfo or lastlogportinfo[p] != currentlogportinfo[p]: if p in logport_arps: ip, mac, islocal, port, broadcast = logport_arps[p] pid, lognet = currentlogportinfo[p] if lognet in current_arps and lognet in currentlognetinfo: nid, _ = currentlognetinfo[lognet] if islocal and port == p: cmds.append(_create_flow2(ip, mac, nid, pid, islocal, broadcast)) # phynetdict = {} # for n in current_arps: # phynet = n.physicalnetwork # phynetdict.setdefault(phynet, []).append(n) #=================================================================== # for p in currentphyportinfo: # if p not in lastphyportinfo or lastphyportinfo[p] != currentphyportinfo[p]: # pid, phynet = currentphyportinfo[p] # if phynet in phynetdict: # for n in phynetdict[phynet]: # if n in current_arps: # nid, _ = currentlognetinfo[n] # for ip, mac, islocal, port, broadcast in current_arps[n]: # if not islocal and port != p: # cmds.append(_create_flow(ip, mac, nid, islocal, broadcast)) #=================================================================== phyportdict = {} for p in currentphyportinfo: phynet = p.physicalnetwork phyportdict.setdefault(phynet, []).append(p) for n, arps in current_arps.items(): if n in currentlognetinfo: nid, _ = currentlognetinfo[n] if n not in last_arps or n not in lastlognetinfo or lastlognetinfo[n] != currentlognetinfo[n]: send_arps = arps else: send_arps = arps.difference(last_arps[n]) for ip, mac, islocal, port, broadcast in send_arps: cmds.append(_create_flow(ip, mac, nid, islocal, broadcast)) if islocal: if port in currentlognetinfo: cmds.append(_create_flow2(ip, mac, nid, pid, islocal, broadcast)) for m in self.execute_commands(connection, cmds): yield m except Exception: self._logger.warning("Unexpected exception in ARPUpdater. Will ignore and continue.", exc_info = True)