def _control_plane_handler(self, pkt_meta, route_manager): """Handle a packet probably destined to FAUCET's route managers. For example, next hop resolution or ICMP echo requests. Args: pkt_meta (PacketMeta): packet for control plane. route_manager (ValveRouteManager): route manager for this eth_type. Returns: list: OpenFlow messages, if any. """ if (pkt_meta.eth_dst == pkt_meta.vlan.faucet_mac or not valve_packet.mac_addr_is_unicast(pkt_meta.eth_dst)): return route_manager.control_plane_handler(pkt_meta) return []
def control_plane_handler(self, pkt_meta): """Handle a packet probably destined to FAUCET's route managers. For example, next hop resolution or ICMP echo requests. Args: pkt_meta (PacketMeta): packet for control plane. Returns: list: OpenFlow messages, if any. """ ofmsgs = [] if (pkt_meta.eth_dst == pkt_meta.vlan.faucet_mac or not valve_packet.mac_addr_is_unicast(pkt_meta.eth_dst)): for route_manager in list(self.route_manager_by_ipv.values()): if pkt_meta.eth_type in route_manager.CONTROL_ETH_TYPES: ofmsgs = route_manager.control_plane_handler(pkt_meta) break return ofmsgs
def parse_pkt_meta(self, msg): if not self.dp.running: return None if self.dp.cookie != msg.cookie: return None # Drop any packet we didn't specifically ask for if msg.reason != valve_of.ofp.OFPR_ACTION: return None in_port = msg.match['in_port'] if not self.port_no_valid(in_port): return None # Truncate packet in data (OVS > 2.5 does not honor max_len) msg.data = msg.data[:valve_of.MAX_PACKET_IN_BYTES] # eth/VLAN header only pkt, eth_pkt, vlan_vid, eth_type = valve_packet.parse_packet_in_pkt( msg.data, max_len=valve_packet.ETH_VLAN_HEADER_SIZE) if vlan_vid is None: self.logger.info('packet without VLAN header port %u' % in_port) return None if pkt is None: self.logger.info('unparseable packet from port %u' % in_port) return None if vlan_vid not in self.dp.vlans: self.logger.info('packet for unknown VLAN %u' % vlan_vid) return None pkt_meta = self.parse_rcv_packet(in_port, vlan_vid, eth_type, msg.data, msg.total_len, pkt, eth_pkt) if not valve_packet.mac_addr_is_unicast(pkt_meta.eth_src): self.logger.info('packet with non-unicast eth_src %s port %u' % (pkt_meta.eth_src, in_port)) return None if self.dp.stack is not None: if (not pkt_meta.port.stack and pkt_meta.vlan not in pkt_meta.port.tagged_vlans and pkt_meta.vlan != pkt_meta.port.native_vlan): self.logger.warning(( 'packet from non-stack port number %u is not member of VLAN %u' % (pkt_meta.port.number, pkt_meta.vlan.vid))) return None return pkt_meta
def rcv_packet(self, other_valves, pkt_meta): """Handle a packet from the dataplane (eg to re/learn a host). The packet may be sent to us also in response to FAUCET initiating IPv6 neighbor discovery, or ARP, to resolve a nexthop. Args: other_valves (list): all Valves other than this one. pkt_meta (PacketMeta): packet for control plane. Return: list: OpenFlow messages, if any. """ ofmsgs = [] control_plane_handled = False learn_from_pkt = True if valve_packet.mac_addr_is_unicast(pkt_meta.eth_src): self.logger.debug( 'Packet_in src:%s in_port:%d vid:%s' % (pkt_meta.eth_src, pkt_meta.port.number, pkt_meta.vlan.vid)) if pkt_meta.port.lacp: lacp_ofmsgs = self.lacp_handler(pkt_meta) if lacp_ofmsgs: learn_from_pkt = False ofmsgs.extend(lacp_ofmsgs) if not pkt_meta.port.dyn_lacp_up: return ofmsgs for eth_types in list(valve_route.ETH_TYPES.values()): if pkt_meta.eth_type in eth_types: pkt_meta.reparse_ip(pkt_meta.eth_type) if pkt_meta.l3_pkt: if self.L3: control_plane_ofmsgs = self.control_plane_handler( pkt_meta) if control_plane_ofmsgs: control_plane_handled = True ofmsgs.extend(control_plane_ofmsgs) break if self._rate_limit_packet_ins(): return ofmsgs ban_rules = self.host_manager.ban_rules(pkt_meta) if ban_rules: ofmsgs.extend(ban_rules) return ofmsgs if learn_from_pkt: ofmsgs.extend(self._learn_host(other_valves, pkt_meta)) # Add FIB entries, if routing is active and not already handled # by control plane. if self.L3 and pkt_meta.l3_pkt and not control_plane_handled: for route_manager in list(self.route_manager_by_ipv.values()): ofmsgs.extend( route_manager.add_host_fib_route_from_pkt(pkt_meta)) return ofmsgs
def packet_in_handler(self, ryu_event): """Handle a packet in event from the dataplane. Args: ryu_event (ryu.controller.event.EventReplyBase): packet in message. """ msg = ryu_event.msg ryu_dp = msg.datapath dp_id = ryu_dp.id valve = self._get_valve(ryu_dp, 'packet_in_handler', msg) if valve is None: return if not valve.dp.running: return if valve.dp.cookie != msg.cookie: return # Drop any packet we didn't specifically ask for if msg.reason != valve_of.ofp.OFPR_ACTION: return in_port = msg.match['in_port'] if valve_of.ignore_port(in_port): return # Truncate packet in data (OVS > 2.5 does not honor max_len) msg.data = msg.data[:valve_of.MAX_PACKET_IN_BYTES] # eth/VLAN header only pkt, eth_pkt, vlan_vid, eth_type = valve_packet.parse_packet_in_pkt( msg.data, max_len=valve_packet.ETH_VLAN_HEADER_SIZE) if vlan_vid is None: self.logger.info('packet without VLAN header from %s port %s', dpid_log(dp_id), in_port) return if pkt is None: self.logger.info('unparseable packet from %s port %s', dpid_log(dp_id), in_port) return if vlan_vid not in valve.dp.vlans: self.logger.info('packet for unknown VLAN %u from %s', vlan_vid, dpid_log(dp_id)) return if in_port not in valve.dp.ports: self.logger.info('packet for unknown port %u from %s', in_port, dpid_log(dp_id)) return pkt_meta = valve.parse_rcv_packet(in_port, vlan_vid, eth_type, msg.data, msg.total_len, pkt, eth_pkt) if not valve_packet.mac_addr_is_unicast(pkt_meta.eth_src): self.logger.info( 'packet with non-unicast eth_src %s port %u from %s', pkt_meta.eth_src, in_port, dpid_log(dp_id)) return if valve.dp.stack is not None: if (not pkt_meta.port.stack and pkt_meta.vlan not in pkt_meta.port.tagged_vlans and pkt_meta.vlan != pkt_meta.port.native_vlan): self.logger.warning(( 'packet from non-stack port number %u is not member of VLAN %u' % (pkt_meta.port.number, pkt_meta.vlan.vid))) return other_valves = [ other_valve for other_valve in list(self.valves.values()) if valve != other_valve ] self.metrics.of_packet_ins.labels( # pylint: disable=no-member **valve.base_prom_labels).inc() packet_in_start = time.time() flowmods = valve.rcv_packet(other_valves, pkt_meta) packet_in_stop = time.time() self.metrics.faucet_packet_in_secs.labels( # pylint: disable=no-member **valve.base_prom_labels).observe(packet_in_stop - packet_in_start) self._send_flow_msgs(dp_id, flowmods) valve.update_metrics(self.metrics)