Пример #1
0
    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 []
Пример #2
0
    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
Пример #3
0
    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
Пример #4
0
    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
Пример #5
0
    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)