def check_config(self): super(Port, self).check_config() test_config_condition(not (isinstance(self.number, int) and self.number > 0 and ( not valve_of.ignore_port(self.number))), ('Port number invalid: %s' % self.number)) test_config_condition( self.hairpin and self.hairpin_unicast, 'Cannot have both hairpin and hairpin_unicast enabled') if self.dot1x: test_config_condition(self.number > 65535, ( '802.1x not supported on ports > 65535')) if self.dot1x_acl: test_config_condition(not self.dot1x, ( '802.1x_ACL requires dot1x to be enabled also')) if self.mirror: test_config_condition(self.tagged_vlans or self.native_vlan, ( 'mirror port %s cannot have any VLANs assigned' % self)) if self.stack: self._check_conf_types(self.stack, self.stack_defaults_types) for stack_config in list(self.stack_defaults_types.keys()): test_config_condition(stack_config not in self.stack, ( 'stack %s must be defined' % stack_config)) # LLDP always enabled for stack ports. self.receive_lldp = True if not self.lldp_beacon_enabled(): self.lldp_beacon.update({'enable': True}) if self.lldp_beacon: self._check_conf_types( self.lldp_beacon, self.lldp_beacon_defaults_types) self.lldp_beacon = self._set_unknown_conf( self.lldp_beacon, self.lldp_beacon_defaults_types) if self.lldp_beacon_enabled(): if self.lldp_beacon['port_descr'] is None: self.lldp_beacon['port_descr'] = self.description org_tlvs = [] for org_tlv in self.lldp_beacon['org_tlvs']: self._check_conf_types(org_tlv, self.lldp_org_tlv_defaults_types) test_config_condition(len(org_tlv) != len(self.lldp_org_tlv_defaults_types), ( 'missing org_tlv config')) if not isinstance(org_tlv['info'], bytearray): try: org_tlv['info'] = bytearray.fromhex( org_tlv['info']) # pytype: disable=missing-parameter except ValueError: org_tlv['info'] = org_tlv['info'].encode('utf-8') if not isinstance(org_tlv['oui'], bytearray): org_tlv['oui'] = bytearray.fromhex( '%6.6x' % org_tlv['oui']) # pytype: disable=missing-parameter org_tlvs.append(org_tlv) self.lldp_beacon['org_tlvs'] = org_tlvs if self.acl_in and self.acls_in: raise InvalidConfigError('found both acl_in and acls_in, use only acls_in') if self.acl_in and not isinstance(self.acl_in, list): self.acls_in = [self.acl_in,] self.acl_in = None if self.acls_in: for acl in self.acls_in: test_config_condition(not isinstance(acl, (int, str)), 'ACL names must be int or str')
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 valve = self._get_valve(ryu_dp, 'port_status_handler', msg) if valve is None: return if not valve.dp.running: return port_no = msg.desc.port_no if valve_of.ignore_port(port_no): return ofp = msg.datapath.ofproto reason = msg.reason port_down = msg.desc.state & ofp.OFPPS_LINK_DOWN port_status = not port_down flowmods = valve.port_status_handler(port_no, reason, port_status) self._send_flow_msgs(dp_id, flowmods) # pylint: disable=no-member self.metrics.port_status.labels(dp_id=hex(dp_id), port=port_no).set(port_status)
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 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) 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)
def port_no_valid(self, port_no): """Return True if supplied port number valid on this datapath.""" if valve_of.ignore_port(port_no): return False if port_no not in self.dp.ports: self.logger.info('port %u unknown' % port_no) return False return True
def check_config(self): super(Port, self).check_config() test_config_condition( not (isinstance(self.number, int) and self.number > 0 and (not valve_of.ignore_port(self.number))), ('Port number invalid: %s' % self.number)) if self.mirror: test_config_condition( self.tagged_vlans or self.native_vlan, ('mirror port %s cannot have any VLANs assigned' % self)) if self.stack: self._check_conf_types(self.stack, self.stack_defaults_types) for stack_config in list(self.stack_defaults_types.keys()): test_config_condition( stack_config not in self.stack, ('stack %s must be defined' % stack_config)) if self.lldp_beacon: self._check_conf_types(self.lldp_beacon, self.lldp_beacon_defaults_types) self.lldp_beacon = self._set_unknown_conf( self.lldp_beacon, self.lldp_beacon_defaults_types) if self.lldp_beacon_enabled(): if self.lldp_beacon['port_descr'] is None: self.lldp_beacon['port_descr'] = self.description org_tlvs = [] for org_tlv in self.lldp_beacon['org_tlvs']: self._check_conf_types(org_tlv, self.lldp_org_tlv_defaults_types) test_config_condition( len(org_tlv) != len(self.lldp_org_tlv_defaults_types), ('missing org_tlv config')) if not isinstance(org_tlv['info'], bytearray): try: org_tlv['info'] = bytearray.fromhex( org_tlv['info']) # pytype: disable=missing-parameter except ValueError: org_tlv['info'] = org_tlv['info'].encode('utf-8') if not isinstance(org_tlv['oui'], bytearray): org_tlv['oui'] = bytearray.fromhex( '%6.6x' % org_tlv['oui']) # pytype: disable=missing-parameter org_tlvs.append(org_tlv) self.lldp_beacon['org_tlvs'] = org_tlvs if self.acl_in and self.acls_in: raise InvalidConfigError( 'found both acl_in and acls_in, use only acls_in') if self.acl_in and not isinstance(self.acl_in, list): self.acls_in = [ self.acl_in, ] self.acl_in = None if self.acls_in: for acl in self.acls_in: test_config_condition(not isinstance(acl, (int, str)), 'acl names must be int or')
def _datapath_connect(self, ryu_event): """Handle any/all re/connection of a datapath. Args: ryu_event (ryu.controller.ofp_event.Event) """ now = time.time() valve, ryu_dp, _ = self._get_valve(ryu_event) if valve is None: return discovered_up_ports = [ port.port_no for port in list(ryu_dp.ports.values()) if valve_of.port_status_from_state(port.state) and not valve_of.ignore_port(port.port_no)] self._send_flow_msgs(valve, valve.datapath_connect(now, discovered_up_ports))
def _datapath_connect(self, ryu_event): """Handle any/all re/connection of a datapath. Args: ryu_event (ryu.controller.ofp_event.Event) """ now = time.time() valve, ryu_dp, _ = self._get_valve(ryu_event) if valve is None: return discovered_up_ports = [ port.port_no for port in list(ryu_dp.ports.values()) if (valve_of.port_status_from_state(port.state) and not valve_of.ignore_port(port.port_no))] self._send_flow_msgs(valve, valve.datapath_connect(now, discovered_up_ports))
def _datapath_connect(self, ryu_dp): """Handle any/all re/connection of a datapath. Args: ryu_dp (ryu.controller.controller.Datapath): datapath. """ dp_id = ryu_dp.id valve = self._get_valve(ryu_dp, '_datapath_connect') if valve is None: return discovered_ports = [ port for port in list(ryu_dp.ports.values()) if not valve_of.ignore_port(port.port_no) ] flowmods = valve.datapath_connect(discovered_ports) self._send_flow_msgs(dp_id, flowmods)
def check_config(self): super(Port, self).check_config() assert isinstance(self.number, int) and self.number > 0 and not ignore_port(self.number), ( 'Port number invalid: %s' % self.number) if self.mirror: assert not self.tagged_vlans and not self.native_vlan, ( 'mirror port %s cannot have any VLANs assigned' % self) if self.stack: self._check_conf_types(self.stack, self.stack_defaults_types) for stack_config in list(self.stack_defaults_types.keys()): assert stack_config in self.stack, 'stack %s must be defined' % stack_config if self.lldp_beacon: self._check_conf_types( self.lldp_beacon, self.lldp_beacon_defaults_types) self.lldp_beacon = self._set_unknown_conf( self.lldp_beacon, self.lldp_beacon_defaults_types) if self.lldp_beacon_enabled(): assert self.native_vlan, 'native_vlan must be defined for LLDP beacon' if self.lldp_beacon['port_descr'] is None: self.lldp_beacon['port_descr'] = self.description org_tlvs = [] for org_tlv in self.lldp_beacon['org_tlvs']: self._check_conf_types(org_tlv, self.lldp_org_tlv_defaults_types) assert len(org_tlv) == len(self.lldp_org_tlv_defaults_types), ( 'missing org_tlv config') try: org_tlv['info'] = bytearray.fromhex(org_tlv['info']) except ValueError: org_tlv['info'] = org_tlv['info'].encode('utf-8') org_tlv['oui'] = bytearray.fromhex('%6.6x' % org_tlv['oui']) org_tlvs.append(org_tlv) self.lldp_beacon['org_tlvs'] = org_tlvs if self.acl_in and self.acls_in: assert False, 'found both acl_in and acls_in, use only acls_in' if self.acl_in and not isinstance(self.acl_in, list): self.acls_in = [self.acl_in,] self.acl_in = None if self.acls_in: for acl in self.acls_in: assert isinstance(acl, (int, str)), 'acl names must be int or'
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 in_port = msg.match['in_port'] if valve_of.ignore_port(in_port): return # 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 pkt is None or vlan_vid 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 pkt_meta = valve.parse_rcv_packet(in_port, vlan_vid, eth_type, msg.data, pkt, eth_pkt) other_valves = [ other_valve for other_valve in list(self.valves.values()) if valve != other_valve ] # pylint: disable=no-member self.metrics.of_packet_ins.labels(dp_id=hex(dp_id)).inc() flowmods = valve.rcv_packet(other_valves, pkt_meta) self._send_flow_msgs(dp_id, flowmods) valve.update_metrics(self.metrics)
def check_config(self): super(Port, self).check_config() assert isinstance(self.number, int) and self.number > 0 and not ignore_port(self.number), ( 'Port number invalid: %s' % self.number)
def port_up_valid(port): """Return True if port is up and in valid range.""" return valve_of.port_status_from_state( port.state) and not valve_of.ignore_port(port.port_no)
def port_no_valid(self, port_no): """Return True if supplied port number valid on this datapath.""" return not valve_of.ignore_port(port_no) and port_no in self.ports
def port_up_valid(port): """Return True if port is up and in valid range.""" return port.state == 0 and not valve_of.ignore_port(port.port_no)
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)
def check_config(self): super(Port, self).check_config() test_config_condition(not (isinstance(self.number, int) and self.number > 0 and ( not valve_of.ignore_port(self.number))), ('Port number invalid: %s' % self.number)) non_vlan_options = {'stack', 'mirror', 'coprocessor', 'output_only'} vlan_agnostic_options = {'enabled', 'number', 'name', 'description', 'max_lldp_lost'} vlan_port = self.tagged_vlans or self.native_vlan non_vlan_port_options = {option for option in non_vlan_options if getattr(self, option)} test_config_condition( vlan_port and non_vlan_port_options, 'cannot have VLANs configured on non-VLAN ports: %s' % self) if self.output_only: test_config_condition( not non_vlan_port_options.issubset({'mirror', 'output_only'}), 'output_only can only coexist with mirror option on same port %s' % self) elif self.mirror: test_config_condition( not non_vlan_port_options.issubset({'mirror', 'coprocessor'}), 'coprocessor can only coexist with mirror option on same port %s' % self) else: test_config_condition( len(non_vlan_port_options) > 1, 'cannot have multiple non-VLAN port options %s on same port: %s' % ( non_vlan_port_options, self)) if non_vlan_port_options: for key, default_val in self.defaults.items(): if key in vlan_agnostic_options or key in non_vlan_port_options: continue if key.startswith('acl') and (self.stack or self.coprocessor): continue val = getattr(self, key) test_config_condition( val != default_val and val, 'Cannot have VLAN option %s: %s on non-VLAN port %s' % (key, val, self)) test_config_condition( self.hairpin and self.hairpin_unicast, 'Cannot have both hairpin and hairpin_unicast enabled') dot1x_features = { dot1x_feature for dot1x_feature, dot1x_config in self.defaults.items() if dot1x_feature.startswith('dot1x_') and dot1x_config} test_config_condition( dot1x_features and not self.dot1x, '802.1x features %s require port to have dot1x enabled' % dot1x_features) if self.dot1x: test_config_condition(self.number > 65535, ( '802.1x not supported on ports > 65535')) if self.dot1x_mab: test_config_condition(self.dot1x_dyn_acl, ( '802.1x_MAB cannot be used with 802.1x_DYN_ACL')) if self.dot1x_dyn_acl: test_config_condition(self.dot1x_acl, ( '802.1x_DYN_ACL cannot be used with 802.1x_ACL')) if self.coprocessor: self._check_conf_types(self.coprocessor, self.coprocessor_defaults_types) test_config_condition( self.coprocessor.get('strategy', None) != 'vlan_vid', 'coprocessor only supports vlan_vid strategy') self.coprocessor['vlan_vid_base'] = self.coprocessor.get('vlan_vid_base', 1000) if self.stack: self._check_conf_types(self.stack, self.stack_defaults_types) for stack_config in list(self.stack_defaults_types.keys()): test_config_condition(stack_config not in self.stack, ( 'stack %s must be defined' % stack_config)) # LLDP always enabled for stack ports. self.receive_lldp = True if not self.lldp_beacon_enabled(): self.lldp_beacon.update({'enable': True}) if self.lacp_resp_interval is not None: test_config_condition( self.lacp_resp_interval > 65535 or self.lacp_resp_interval < 0.3, ('interval must be at least 0.3 and less than 65536')) if self.lacp_port_priority is not None: test_config_condition( self.lacp_port_priority > 255 or self.lacp_port_priority < 0, ('lacp port priority must be at least 0 and less than 256')) if self.lldp_peer_mac: test_config_condition(not netaddr.valid_mac(self.lldp_peer_mac), ( 'invalid MAC address %s' % self.lldp_peer_mac)) if self.lldp_beacon: self._check_conf_types( self.lldp_beacon, self.lldp_beacon_defaults_types) self.lldp_beacon = self._set_unknown_conf( self.lldp_beacon, self.lldp_beacon_defaults_types) if self.lldp_beacon_enabled(): if self.lldp_beacon['port_descr'] is None: self.lldp_beacon['port_descr'] = self.description org_tlvs = [] for org_tlv in self.lldp_beacon['org_tlvs']: self._check_conf_types(org_tlv, self.lldp_org_tlv_defaults_types) test_config_condition(len(org_tlv) != len(self.lldp_org_tlv_defaults_types), ( 'missing org_tlv config')) if not isinstance(org_tlv['info'], bytearray): try: org_tlv['info'] = bytearray.fromhex( org_tlv['info']) # pytype: disable=missing-parameter except ValueError: org_tlv['info'] = org_tlv['info'].encode('utf-8') if not isinstance(org_tlv['oui'], bytearray): org_tlv['oui'] = bytearray.fromhex( '%6.6x' % org_tlv['oui']) # pytype: disable=missing-parameter org_tlvs.append(org_tlv) self.lldp_beacon['org_tlvs'] = org_tlvs test_config_condition( self.acl_in and self.acls_in, 'Found both acl_in and acls_in, use only acls_in') if self.acl_in and not isinstance(self.acl_in, list): self.acls_in = [self.acl_in] self.acl_in = None if self.acls_in: for acl in self.acls_in: test_config_condition(not isinstance(acl, (int, str)), 'ACL names must be int or str') lacp_options = [self.lacp_selected, self.lacp_unselected, self.lacp_standby] test_config_condition( lacp_options.count(True) > 1, 'Cannot force multiple LACP port selection states')
def port_up_valid(port): return port.state == 0 and not valve_of.ignore_port(port.port_no)