Exemple #1
0
    def datapath_connect(self, dp_id, discovered_up_port_nums):
        """Handle Ryu datapath connection event and provision pipeline.

        Args:
            dp_id (int): datapath ID.
            discovered_up_port_nums (list): datapath ports that are up as ints.
        Returns:
            list: OpenFlow messages to send to datapath.
        """
        if self._ignore_dpid(dp_id):
            return []
        self.logger.info('Configuring %s', util.dpid_log(dp_id))
        ofmsgs = []
        ofmsgs.extend(self._add_default_flows())
        changed_ports = set([])
        for port_no in discovered_up_port_nums:
            if valve_of.ignore_port(port_no):
                continue
            changed_ports.add(port_no)
        changed_vlans = self.dp.vlans.iterkeys()
        changes = ([], changed_ports, [], changed_vlans)
        ofmsgs.extend(self._apply_config_changes(self.dp, changes))
        ofmsgs.extend(self._add_ports_and_vlans(discovered_up_port_nums))
        self.dp.running = True
        return ofmsgs
    def port_status_handler(self, ryu_event):
        """Handle a port status change event.

        Args:
            ryu_event (ryu.controller.ofp_event.EventOFPPortStatus): trigger.
        """
        msg = ryu_event.msg
        ryu_dp = msg.datapath
        dp_id = ryu_dp.id
        ofp = msg.datapath.ofproto
        reason = msg.reason
        port_no = msg.desc.port_no

        if dp_id not in self.valves:
            self.logger.error('port_status_handler: unknown %s',
                              dpid_log(dp_id))
            return

        valve = self.valves[dp_id]
        flowmods = []
        if reason == ofp.OFPPR_ADD:
            flowmods = valve.port_add(dp_id, port_no)
        elif reason == ofp.OFPPR_DELETE:
            flowmods = valve.port_delete(dp_id, port_no)
        elif reason == ofp.OFPPR_MODIFY:
            port_down = msg.desc.state & ofp.OFPPS_LINK_DOWN
            if port_down:
                flowmods = valve.port_delete(dp_id, port_no)
            else:
                flowmods = valve.port_add(dp_id, port_no)
        else:
            self.logger.warning('Unhandled port status %s for port %u', reason,
                                port_no)

        self._send_flow_msgs(ryu_dp, flowmods)
Exemple #3
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

        if not dp_id in self.valves:
            self.logger.error('_packet_in_handler: unknown %s', dpid_log(dp_id))
            return

        valve = self.valves[dp_id]
        valve.ofchannel_log([msg])

        pkt = packet.Packet(msg.data)
        eth_pkt = pkt.get_protocols(ethernet.ethernet)[0]
        eth_type = eth_pkt.ethertype

        # Packet ins, can only come when a VLAN header has already been pushed
        # (ie. when we have progressed past the VLAN table). This gaurantees
        # a VLAN header will always be present, so we know which VLAN the packet
        # belongs to.
        if eth_type == ether.ETH_TYPE_8021Q:
            # tagged packet
            vlan_proto = pkt.get_protocols(ryu_vlan.vlan)[0]
            vlan_vid = vlan_proto.vid
        else:
            return

        in_port = msg.match['in_port']
        flowmods = valve.rcv_packet(dp_id, self.valves, in_port, vlan_vid, pkt)
        self._send_flow_msgs(ryu_dp, flowmods)
Exemple #4
0
    def port_status_handler(self, ryu_event):
        """Handle a port status change event.

        Args:
            ryu_event (ryu.controller.ofp_event.EventOFPPortStatus): trigger.
        """
        msg = ryu_event.msg
        ryu_dp = msg.datapath
        dp_id = ryu_dp.id
        ofp = msg.datapath.ofproto
        reason = msg.reason
        port_no = msg.desc.port_no

        if dp_id not in self.valves:
            self.logger.error(
                'port_status_handler: unknown %s', dpid_log(dp_id))
            return

        valve = self.valves[dp_id]
        flowmods = []
        if reason == ofp.OFPPR_ADD:
            flowmods = valve.port_add(dp_id, port_no)
        elif reason == ofp.OFPPR_DELETE:
            flowmods = valve.port_delete(dp_id, port_no)
        elif reason == ofp.OFPPR_MODIFY:
            port_down = msg.desc.state & ofp.OFPPS_LINK_DOWN
            if port_down:
                flowmods = valve.port_delete(dp_id, port_no)
            else:
                flowmods = valve.port_add(dp_id, port_no)
        else:
            self.logger.warning('Unhandled port status %s for port %u',
                                reason, port_no)

        self._send_flow_msgs(ryu_dp, flowmods)
Exemple #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

        if not dp_id in self.valves:
            self.logger.error('_packet_in_handler: unknown %s', dpid_log(dp_id))
            return

        valve = self.valves[dp_id]
        valve.ofchannel_log([msg])

        pkt = packet.Packet(msg.data)
        eth_pkt = pkt.get_protocols(ethernet.ethernet)[0]
        eth_type = eth_pkt.ethertype

        # Packet ins, can only come when a VLAN header has already been pushed
        # (ie. when we have progressed past the VLAN table). This gaurantees
        # a VLAN header will always be present, so we know which VLAN the packet
        # belongs to.
        if eth_type == ether.ETH_TYPE_8021Q:
            # tagged packet
            vlan_proto = pkt.get_protocols(ryu_vlan.vlan)[0]
            vlan_vid = vlan_proto.vid
        else:
            return

        in_port = msg.match['in_port']
        flowmods = valve.rcv_packet(dp_id, self.valves, in_port, vlan_vid, pkt)
        self._send_flow_msgs(ryu_dp, flowmods)
Exemple #6
0
    def datapath_connect(self, dp_id, discovered_up_port_nums):
        """Handle Ryu datapath connection event and provision pipeline.

        Args:
            dp_id (int): datapath ID.
            discovered_up_port_nums (list): datapath ports that are up as ints.
        Returns:
            list: OpenFlow messages to send to datapath.
        """
        if self._ignore_dpid(dp_id):
            return []
        self.logger.info('Configuring %s', util.dpid_log(dp_id))
        ofmsgs = []
        ofmsgs.extend(self._add_default_flows())
        changed_ports = set([])
        for port_no in discovered_up_port_nums:
            if valve_of.ignore_port(port_no):
                continue
            changed_ports.add(port_no)
        changed_vlans = self.dp.vlans.iterkeys()
        changes = ([], changed_ports, [], changed_vlans)
        ofmsgs.extend(self._apply_config_changes(self.dp, changes))
        ofmsgs.extend(self._add_ports_and_vlans(discovered_up_port_nums))
        self.dp.running = True
        return ofmsgs
    def datapath_connect(self, dp_id, discovered_up_port_nums):
        """Handle Ryu datapath connection event and provision pipeline.

        Args:
            dp_id (int): datapath ID.
            discovered_up_port_nums (list): datapath ports that are up as ints.
        Returns:
            list: OpenFlow messages to send to datapath.
        """
        if self._ignore_dpid(dp_id):
            return []
        self.logger.info('Configuring %s', util.dpid_log(dp_id))
        ofmsgs = []
        # Add the default meter to ofmsgs, assumes that meter and Controller meter are supported (Jayden Hewer)
        #ofmsgs.extend(self._add_default_meters())
        # The line above is commented out as Lagopus does not support this feature.
        ofmsgs.extend(self._add_simple_meter())
        ofmsgs.extend(self._add_default_flows())
        changed_ports = set([])
        for port_no in discovered_up_port_nums:
            if valve_of.ignore_port(port_no):
                continue
            changed_ports.add(port_no)
        changed_vlans = self.dp.vlans.iterkeys()
        changes = ([], changed_ports, [], changed_vlans)
        ofmsgs.extend(self._apply_config_changes(self.dp, changes))
        ofmsgs.extend(self._add_ports_and_vlans(discovered_up_port_nums))
        self.dp.running = True
        return ofmsgs
Exemple #8
0
    def handler_connect_or_disconnect(self, ryu_event):
        ryu_dp = ryu_event.dp
        dp_id = ryu_dp.id
        if dp_id not in self.watchers:
            self.logger.info('no watcher configured for %s', dpid_log(dp_id))
            return

        if ryu_event.enter: # DP is connecting
            self.logger.info('%s up', dpid_log(dp_id))
            for watcher in self.watchers[dp_id].values():
                watcher.start(ryu_dp)
        else: # DP is disconnecting
            if ryu_dp.id in self.watchers:
                for watcher in self.watchers[dp_id].values():
                    watcher.stop()
                del self.watchers[dp_id]
            self.logger.info('%s down', dpid_log(dp_id))
Exemple #9
0
    def handler_connect_or_disconnect(self, ryu_event):
        ryu_dp = ryu_event.dp
        dp_id = ryu_dp.id
        if dp_id not in self.watchers:
            self.logger.info('no watcher configured for %s', dpid_log(dp_id))
            return

        if ryu_event.enter:  # DP is connecting
            self.logger.info('%s up', dpid_log(dp_id))
            for watcher in self.watchers[dp_id].values():
                watcher.start(ryu_dp)
        else:  # DP is disconnecting
            if ryu_dp.id in self.watchers:
                for watcher in self.watchers[dp_id].values():
                    watcher.stop()
                del self.watchers[dp_id]
            self.logger.info('%s down', dpid_log(dp_id))
Exemple #10
0
    def datapath_disconnect(self, dp_id):
        """Handle Ryu datapath disconnection event.

        Args:
            dp_id (int): datapath ID.
        """
        if not self._ignore_dpid(dp_id):
            self.dp.running = False
            self.logger.warning('%s down', util.dpid_log(dp_id))
    def handler_reconnect(self, ryu_event):
        """Handle reconnection of a datapath.

        Args:
            ryu_event (ryu.controller.dpset.EventDPReconnected): trigger.
        """
        ryu_dp = ryu_event.dp
        self.logger.debug('%s reconnected', dpid_log(ryu_dp.id))
        self.handler_datapath(ryu_dp)
Exemple #12
0
    def datapath_disconnect(self, dp_id):
        """Handle Ryu datapath disconnection event.

        Args:
            dp_id (int): datapath ID.
        """
        if not self._ignore_dpid(dp_id):
            self.dp.running = False
            self.logger.warning('%s down', util.dpid_log(dp_id))
Exemple #13
0
    def handler_reconnect(self, ryu_event):
        """Handle reconnection of a datapath.

        Args:
            ryu_event (ryu.controller.dpset.EventDPReconnected): trigger.
        """
        ryu_dp = ryu_event.dp
        self.logger.debug('%s reconnected', dpid_log(ryu_dp.id))
        self.handler_datapath(ryu_dp)
Exemple #14
0
    def handler_connect_or_disconnect(self, ryu_event):
        """Handle connection or disconnection of a datapath.

        Args:
            ryu_event (ryu.controller.dpset.EventDP): trigger.
        """
        ryu_dp = ryu_event.dp
        dp_id = ryu_dp.id

        if not ryu_event.enter:
            if dp_id in self.valves:
                # Datapath down message
                self.logger.debug('%s disconnected', dpid_log(dp_id))
                self.valves[dp_id].datapath_disconnect(dp_id)
            else:
                self.logger.error(
                    'handler_connect_or_disconnect: unknown %s', dpid_log(dp_id))
            return

        self.logger.debug('%s connected', dpid_log(dp_id))
        self.handler_datapath(ryu_dp)
Exemple #15
0
    def rcv_packet(self, dp_id, in_port, vlan_vid, pkt):
        """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:
            dp_id (int): datapath ID.
            in_port (int): port packet was received on.
            vlan_vid (int): VLAN VID of port packet was received on.
            pkt (ryu.lib.packet.packet): packet received.
        Return:
            list: OpenFlow messages, if any.
        """
        if not self._known_up_dpid_and_port(dp_id, in_port):
            return []

        ofmsgs = []
        eth_pkt = valve_packet.parse_pkt(pkt)
        eth_src = eth_pkt.src
        eth_dst = eth_pkt.dst
        vlan = self.dp.vlans[vlan_vid]
        port = self.dp.ports[in_port]

        if valve_packet.mac_addr_is_unicast(eth_src):
            self.logger.debug(
                'Packet_in %s src:%s in_port:%d vid:%s',
                util.dpid_log(dp_id), eth_src, in_port, vlan_vid)

            ofmsgs.extend(self.control_plane_handler(
                in_port, vlan, eth_src, eth_dst, pkt))

        # ban learning new hosts if max_hosts reached on a VLAN.
        if (vlan.max_hosts is not None and
                len(vlan.host_cache) == vlan.max_hosts and
                eth_src not in vlan.host_cache):
            ofmsgs.append(self.host_manager.temp_ban_host_learning_on_vlan(
                vlan))
            self.logger.info(
                'max hosts %u reached on vlan %u, ' +
                'temporarily banning learning on this vlan, ' +
                'and not learning %s',
                vlan.max_hosts, vlan.vid, eth_src)
        else:
            # TODO: it would be good to be able to notify an external
            # system upon re/learning a host.
            ofmsgs.extend(self.host_manager.learn_host_on_vlan_port(
                port, vlan, eth_src))
            self.logger.info(
                'learned %u hosts on vlan %u',
                len(vlan.host_cache), vlan.vid)
        return ofmsgs
    def handler_connect_or_disconnect(self, ryu_event):
        """Handle connection or disconnection of a datapath.

        Args:
            ryu_event (ryu.controller.dpset.EventDP): trigger.
        """
        ryu_dp = ryu_event.dp
        dp_id = ryu_dp.id

        if not ryu_event.enter:
            if dp_id in self.valves:
                # Datapath down message
                self.logger.debug('%s disconnected', dpid_log(dp_id))
                self.valves[dp_id].datapath_disconnect(dp_id)
            else:
                self.logger.error('handler_connect_or_disconnect: unknown %s',
                                  dpid_log(dp_id))
            return

        self.logger.debug('%s connected', dpid_log(dp_id))
        self.handler_datapath(ryu_dp)
Exemple #17
0
    def _ignore_dpid(self, dp_id):
        """Return True if this datapath ID is not ours.

        Args:
            dp_id (int): datapath ID
        Returns:
            bool: True if this datapath ID is not ours.
        """
        if dp_id != self.dp.dp_id:
            self.logger.error('Unknown %s', util.dpid_log(dp_id))
            return True
        return False
Exemple #18
0
    def _ignore_dpid(self, dp_id):
        """Return True if this datapath ID is not ours.

        Args:
            dp_id (int): datapath ID
        Returns:
            bool: True if this datapath ID is not ours.
        """
        if dp_id != self.dp.dp_id:
            self.logger.error('Unknown %s', util.dpid_log(dp_id))
            return True
        return False
Exemple #19
0
    def handler_datapath(self, ryu_dp):
        """Handle any/all re/dis/connection of a datapath.

        Args:
            ryu_dp (ryu.controller.controller.Datapath): datapath.
        """
        dp_id = ryu_dp.id
        if dp_id in self.valves:
            discovered_ports = [
                p.port_no for p in ryu_dp.ports.values() if p.state == 0]
            flowmods = self.valves[dp_id].datapath_connect(dp_id, discovered_ports)
            self._send_flow_msgs(ryu_dp, flowmods)
        else:
            self.logger.error('handler_datapath: unknown %s', dpid_log(dp_id))
Exemple #20
0
    def _error_handler(self, ryu_event):
        """Handle an OFPError from a datapath.

        Args:
            ryu_event (ryu.controller.ofp_event.EventOFPErrorMsg): trigger
        """
        msg = ryu_event.msg
        ryu_dp = msg.datapath
        dp_id = ryu_dp.id
        if dp_id in self.valves:
            self.valves[dp_id].ofchannel_log([msg])
            self.logger.error('Got OFError: %s', msg)
        else:
            self.logger.error('_error_handler: unknown %s', dpid_log(dp_id))
Exemple #21
0
    def handler_features(self, ryu_event):
        """Handle receiving a switch features message from a datapath.

        Args:
            ryu_event (ryu.controller.ofp_event.EventOFPStateChange): trigger.
        """
        msg = ryu_event.msg
        ryu_dp = msg.datapath
        dp_id = ryu_dp.id
        if dp_id in self.valves:
            flowmods = self.valves[dp_id].switch_features(dp_id, msg)
            self._send_flow_msgs(ryu_dp, flowmods)
        else:
            self.logger.error('handler_features: unknown %s', dpid_log(dp_id))
    def _error_handler(self, ryu_event):
        """Handle an OFPError from a datapath.

        Args:
            ryu_event (ryu.controller.ofp_event.EventOFPErrorMsg): trigger
        """
        msg = ryu_event.msg
        ryu_dp = msg.datapath
        dp_id = ryu_dp.id
        if dp_id in self.valves:
            self.valves[dp_id].ofchannel_log([msg])
            self.logger.error('Got OFError: %s', msg)
        else:
            self.logger.error('_error_handler: unknown %s', dpid_log(dp_id))
    def handler_features(self, ryu_event):
        """Handle receiving a switch features message from a datapath.

        Args:
            ryu_event (ryu.controller.ofp_event.EventOFPStateChange): trigger.
        """
        msg = ryu_event.msg
        ryu_dp = msg.datapath
        dp_id = ryu_dp.id
        if dp_id in self.valves:
            flowmods = self.valves[dp_id].switch_features(dp_id, msg)
            self._send_flow_msgs(ryu_dp, flowmods)
        else:
            self.logger.error('handler_features: unknown %s', dpid_log(dp_id))
Exemple #24
0
    def _send_flow_msgs(self, ryu_dp, flow_msgs):
        """Send OpenFlow messages to a connected datapath.

        Args:
            ryu_db (ryu.controller.controller.Datapath): datapath.
            flow_msgs (list): OpenFlow messages to send.
        """
        dp_id = ryu_dp.id
        if dp_id not in self.valves:
            self.logger.error('send_flow_msgs: unknown %s', dpid_log(dp_id))
            return
        self.valves[dp_id].ofchannel_log(flow_msgs)
        for flow_msg in flow_msgs:
            flow_msg.datapath = ryu_dp
            ryu_dp.send_msg(flow_msg)
Exemple #25
0
    def handler_datapath(self, ryu_dp):
        """Handle any/all re/dis/connection of a datapath.

        Args:
            ryu_dp (ryu.controller.controller.Datapath): datapath.
        """
        dp_id = ryu_dp.id
        if dp_id in self.valves:
            discovered_up_port_nums = [
                port.port_no for port in ryu_dp.ports.values() if port.state == 0]
            flowmods = self.valves[dp_id].datapath_connect(
                dp_id, discovered_up_port_nums)
            self._send_flow_msgs(ryu_dp, flowmods)
        else:
            self.logger.error('handler_datapath: unknown %s', dpid_log(dp_id))
Exemple #26
0
    def _send_flow_msgs(self, ryu_dp, flow_msgs):
        """Send OpenFlow messages to a connected datapath.

        Args:
            ryu_db (ryu.controller.controller.Datapath): datapath.
            flow_msgs (list): OpenFlow messages to send.
        """
        dp_id = ryu_dp.id
        if dp_id not in self.valves:
            self.logger.error('send_flow_msgs: unknown %s', dpid_log(dp_id))
            return
        self.valves[dp_id].ofchannel_log(flow_msgs)
        for flow_msg in flow_msgs:
            flow_msg.datapath = ryu_dp
            ryu_dp.send_msg(flow_msg)
Exemple #27
0
    def rcv_packet(self, dp_id, valves, in_port, vlan_vid, pkt):
        """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:
            dp_id (int): datapath ID.
            valves (dict): all datapaths, indexed by datapath ID.
            in_port (int): port packet was received on.
            vlan_vid (int): VLAN VID of port packet was received on.
            pkt (ryu.lib.packet.packet): packet received.
        Return:
            list: OpenFlow messages, if any.
        """
        if not self._known_up_dpid_and_port(dp_id, in_port):
            return []

        pkt_meta = self._parse_rcv_packet(in_port, vlan_vid, pkt)
        ofmsgs = []

        if valve_packet.mac_addr_is_unicast(pkt_meta.eth_src):
            self.logger.debug(
                'Packet_in %s src:%s in_port:%d vid:%s',
                util.dpid_log(dp_id),
                pkt_meta.eth_src,
                pkt_meta.port.number,
                pkt_meta.vlan.vid)

            ofmsgs.extend(self.control_plane_handler(pkt_meta))

        if self._rate_limit_packet_ins():
            return ofmsgs

        ban_vlan_rules = self._vlan_learn_ban_rules(pkt_meta)
        if ban_vlan_rules:
            ofmsgs.extend(ban_vlan_rules)
            return ofmsgs

        ofmsgs.extend(self._learn_host(valves, dp_id, pkt_meta))
        return ofmsgs
Exemple #28
0
    def rcv_packet(self, dp_id, valves, in_port, vlan_vid, pkt):
        """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:
            dp_id (int): datapath ID.
            valves (dict): all datapaths, indexed by datapath ID.
            in_port (int): port packet was received on.
            vlan_vid (int): VLAN VID of port packet was received on.
            pkt (ryu.lib.packet.packet): packet received.
        Return:
            list: OpenFlow messages, if any.
        """
        if not self._known_up_dpid_and_port(dp_id, in_port):
            return []

        pkt_meta = self._parse_rcv_packet(in_port, vlan_vid, pkt)
        ofmsgs = []

        if valve_packet.mac_addr_is_unicast(pkt_meta.eth_src):
            self.logger.debug(
                'Packet_in %s src:%s in_port:%d vid:%s',
                util.dpid_log(dp_id),
                pkt_meta.eth_src,
                pkt_meta.port.number,
                pkt_meta.vlan.vid)

            ofmsgs.extend(self.control_plane_handler(pkt_meta))

        if self._rate_limit_packet_ins():
            return ofmsgs

        ban_vlan_rules = self._vlan_learn_ban_rules(pkt_meta)
        if ban_vlan_rules:
            ofmsgs.extend(ban_vlan_rules)
            return ofmsgs

        ofmsgs.extend(self._learn_host(valves, dp_id, pkt_meta))
        return ofmsgs
Exemple #29
0
 def ofchannel_log(self, ofmsgs):
     """Log OpenFlow messages in text format to debugging log."""
     if (self.dp is not None and self.dp.ofchannel_log is not None):
         if self.ofchannel_logger is None:
             self.ofchannel_logger = util.get_logger(
                 self.dp.ofchannel_log, self.dp.ofchannel_log,
                 logging.DEBUG, 0)
         for i, ofmsg in enumerate(ofmsgs, start=1):
             log_prefix = '%u/%u %s' % (i, len(ofmsgs),
                                        util.dpid_log(self.dp.dp_id))
             self.ofchannel_logger.debug('%s %s', log_prefix, ofmsg)
             # TODO: log group operations as well.
             if valve_of.is_flowmod(ofmsg):
                 match_types = self.debug_match_types(ofmsg)
                 inst_types, action_types = self.debug_instruction_types(
                     ofmsg)
                 self.ofchannel_logger.debug(
                     '%s FlowMod types table: %u match: %s instructions: %s actions: %s',
                     log_prefix, ofmsg.table_id, match_types, inst_types,
                     action_types)
Exemple #30
0
    def datapath_connect(self, dp_id, discovered_port_nums):
        """Handle Ryu datapath connection event and provision pipeline.

        Args:
            dp_id (int): datapath ID.
            discovered_port_nums (list): known datapath ports as ints.
        Returns:
            list: OpenFlow messages to send to datapath.
        """
        if self._ignore_dpid(dp_id):
            return []
        if discovered_port_nums is None:
            discovered_port_nums = []

        self.logger.info('Configuring %s', util.dpid_log(dp_id))
        ofmsgs = []
        ofmsgs.extend(self._add_default_flows())
        ofmsgs.extend(self._add_ports_and_vlans(discovered_port_nums))
        self.dp.running = True
        return ofmsgs
Exemple #31
0
    def rcv_packet(self, dp_id, valves, in_port, vlan_vid, pkt):
        """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:
            dp_id (int): datapath ID.
            valves (dict): all datapaths, indexed by datapath ID.
            in_port (int): port packet was received on.
            vlan_vid (int): VLAN VID of port packet was received on.
            pkt (ryu.lib.packet.packet): packet received.
        Return:
            list: OpenFlow messages, if any.
        """
        if not self._known_up_dpid_and_port(dp_id, in_port):
            return []

        ofmsgs = []
        eth_pkt = valve_packet.parse_pkt(pkt)
        eth_src = eth_pkt.src
        eth_dst = eth_pkt.dst
        vlan = self.dp.vlans[vlan_vid]
        port = self.dp.ports[in_port]

        if valve_packet.mac_addr_is_unicast(eth_src):
            self.logger.debug(
                'Packet_in %s src:%s in_port:%d vid:%s',
                util.dpid_log(dp_id), eth_src, in_port, vlan_vid)

            ofmsgs.extend(self.control_plane_handler(
                in_port, vlan, eth_src, eth_dst, pkt))

        # Apply learning packet in rate limit.
        if self.dp.ignore_learn_ins:
            if int(time.time() * 1e3) % self.dp.ignore_learn_ins == 0:
                return ofmsgs

        # ban learning new hosts if max_hosts reached on a VLAN.
        if (vlan.max_hosts is not None and
                len(vlan.host_cache) == vlan.max_hosts and
                eth_src not in vlan.host_cache):
            ofmsgs.append(self.host_manager.temp_ban_host_learning_on_vlan(
                vlan))
            self.logger.info(
                'max hosts %u reached on vlan %u, ' +
                'temporarily banning learning on this vlan, ' +
                'and not learning %s',
                vlan.max_hosts, vlan.vid, eth_src)
        else:
            if port.stack is None:
                learn_port = port
            else:
                # TODO: simplest possible unicast learning.
                # We find just one port that is the shortest unicast path to
                # the destination. We could use other factors (eg we could
                # load balance over multiple ports based on destination MAC).
                # TODO: each DP learns independently. An edge DP could
                # call other valves so they learn immediately without waiting
                # for packet in.
                # TODO: edge DPs could use a different forwarding algorithm
                # (for example, just default switch to a neighbor).
                host_learned_other_dp = None
                # Find port that forwards closer to destination DP that
                # has already learned this host (if any).
                for other_dpid, other_valve in valves.iteritems():
                    if other_dpid == dp_id:
                        continue
                    other_dp = other_valve.dp
                    other_dp_host_cache = other_dp.vlans[vlan_vid].host_cache
                    if eth_src in other_dp_host_cache:
                        host = other_dp_host_cache[eth_src]
                        if host.edge:
                            host_learned_other_dp = other_dp
                            break
                # No edge DP may have learned this host yet.
                if host_learned_other_dp is None:
                    return ofmsgs

                learn_port = self.dp.shortest_path_port(
                    host_learned_other_dp.name)
                self.logger.info(
                    'host learned via stack port to %s',
                    host_learned_other_dp.name)

            # TODO: it would be good to be able to notify an external
            # system upon re/learning a host.
            ofmsgs.extend(self.host_manager.learn_host_on_vlan_port(
                learn_port, vlan, eth_src))
            self.logger.info(
                'learned %u hosts on vlan %u',
                len(vlan.host_cache), vlan.vid)
        return ofmsgs
Exemple #32
0
 def handler_reconnect(self, ryu_event):
     ryu_dp = ryu_event.dp
     self.logger.info('%s reconnected', dpid_log(ryu_dp.id))
     for watcher in self.watchers[ryu_dp.id].values():
         watcher.start(ryu_dp)
Exemple #33
0
 def handler_reconnect(self, ryu_event):
     ryu_dp = ryu_event.dp
     self.logger.info('%s reconnected', dpid_log(ryu_dp.id))
     for watcher in self.watchers[ryu_dp.id].values():
         watcher.start(ryu_dp)