def lacp_handler(self, now, pkt_meta, valve, other_valves, lacp_update): """ Handle receiving an LACP packet Args: now (float): current epoch time pkt_meta (PacketMeta): packet for control plane valve (Valve): valve instance other_valves (list): all other valves lacp_update: callable to signal LACP state changes Returns dict: OpenFlow messages, if any by Valve """ ofmsgs_by_valve = defaultdict(list) if (pkt_meta.eth_dst == valve_packet.SLOW_PROTOCOL_MULTICAST and pkt_meta.eth_type == valve_of.ether.ETH_TYPE_SLOW and pkt_meta.port.lacp): # LACP packet so reparse pkt_meta.data = pkt_meta.data[:valve_packet.LACP_SIZE] pkt_meta.reparse_all() lacp_pkt = valve_packet.parse_lacp_pkt(pkt_meta.pkt) if lacp_pkt: self.logger.debug('receive LACP %s on %s' % (lacp_pkt, pkt_meta.port)) # Respond to new LACP packet or if we haven't sent anything in a while age = None if pkt_meta.port.dyn_lacp_last_resp_time: age = now - pkt_meta.port.dyn_lacp_last_resp_time lacp_pkt_change = ( pkt_meta.port.dyn_last_lacp_pkt is None or str(lacp_pkt) != str(pkt_meta.port.dyn_last_lacp_pkt)) lacp_resp_interval = pkt_meta.port.lacp_resp_interval if lacp_pkt_change or (age is not None and age > lacp_resp_interval): ofmsgs_by_valve[valve].extend( self.lacp_req_reply(lacp_pkt, pkt_meta.port)) pkt_meta.port.dyn_lacp_last_resp_time = now # Update the LACP information actor_up = lacp_pkt.actor_state_synchronization ofmsgs_by_valve[valve].extend( lacp_update(pkt_meta.port, actor_up, now=now, lacp_pkt=lacp_pkt, other_valves=other_valves)) # Determine if LACP ports with the same ID have met different actor systems other_lag_ports = [ port for port in self.ports.values() if port.lacp == pkt_meta.port.lacp and port.dyn_last_lacp_pkt ] actor_system = lacp_pkt.actor_system for other_lag_port in other_lag_ports: other_actor_system = other_lag_port.dyn_last_lacp_pkt.actor_system if actor_system != other_actor_system: self.logger.error( 'LACP actor system mismatch %s: %s, %s %s' % (pkt_meta.port, actor_system, other_lag_port, other_actor_system)) return ofmsgs_by_valve
def lacp_handler(self, pkt_meta): """Handle a LACP packet. We are a currently a passive, non-aggregateable LACP partner. Args: pkt_meta (PacketMeta): packet for control plane. Returns: list: OpenFlow messages, if any. """ # TODO: ensure config consistent between LAG ports. ofmsgs = [] if (pkt_meta.eth_dst == valve_packet.SLOW_PROTOCOL_MULTICAST and pkt_meta.eth_type == valve_of.ether.ETH_TYPE_SLOW and pkt_meta.port.lacp): pkt_meta.reparse_all() lacp_pkt = valve_packet.parse_lacp_pkt(pkt_meta.pkt) if lacp_pkt: last_lacp_up = pkt_meta.port.dyn_lacp_up pkt_meta.port.dyn_last_lacp_pkt = lacp_pkt pkt_meta.port.dyn_lacp_up = lacp_pkt.actor_state_synchronization pkt_meta.port.dyn_lacp_updated_time = time.time() if last_lacp_up != pkt_meta.port.dyn_lacp_up: self.logger.info( 'LACP state change from %s to %s on %s to %s LAG %u' % (last_lacp_up, pkt_meta.port.dyn_lacp_up, pkt_meta.port, lacp_pkt.actor_system, pkt_meta.port.lacp)) if pkt_meta.port.dyn_lacp_up: ofmsgs.extend(self.lacp_up(pkt_meta.port)) pkt = valve_packet.lacp_reqreply( pkt_meta.vlan.faucet_mac, pkt_meta.vlan.faucet_mac, pkt_meta.port.lacp, pkt_meta.port.number, lacp_pkt.actor_system, lacp_pkt.actor_key, lacp_pkt.actor_port, lacp_pkt.actor_system_priority, lacp_pkt.actor_port_priority, lacp_pkt.actor_state_defaulted, lacp_pkt.actor_state_expired, lacp_pkt.actor_state_timeout, lacp_pkt.actor_state_collecting, lacp_pkt.actor_state_distributing, lacp_pkt.actor_state_aggregation, lacp_pkt.actor_state_synchronization, lacp_pkt.actor_state_activity) ofmsgs.append( valve_of.packetout(pkt_meta.port.number, pkt.data)) return ofmsgs