def build_output_actions(acl_table, output_dict): """Implement actions to alter packet/output.""" output_actions = [] output_port = None ofmsgs = [] # rewrite any VLAN headers first always vlan_actions = rewrite_vlan(acl_table, output_dict) if vlan_actions: output_actions.extend(vlan_actions) if 'set_fields' in output_dict: for set_field in output_dict['set_fields']: output_actions.append(acl_table.set_field(**set_field)) if 'port' in output_dict: output_port = output_dict['port'] output_actions.append(valve_of.output_port(output_port)) if 'ports' in output_dict: for output_port in output_dict['ports']: output_actions.append(valve_of.output_port(output_port)) if 'failover' in output_dict: failover = output_dict['failover'] group_id = failover['group_id'] buckets = [] for port in failover['ports']: buckets.append( valve_of.bucket(watch_port=port, actions=[valve_of.output_port(port)])) ofmsgs.append(valve_of.groupdel(group_id=group_id)) ofmsgs.append(valve_of.groupadd_ff(group_id=group_id, buckets=buckets)) output_actions.append(valve_of.group_act(group_id=group_id)) return (output_port, output_actions, ofmsgs)
def build_output_actions(output_dict): """Implement actions to alter packet/output.""" output_actions = [] output_port = None ofmsgs = [] # if destination rewriting selected, rewrite it. if 'dl_dst' in output_dict: output_actions.append(valve_of.set_eth_dst(output_dict['dl_dst'])) # rewrite any VLAN headers. vlan_actions = rewrite_vlan(output_dict) if vlan_actions: output_actions.extend(vlan_actions) if 'port' in output_dict: output_port = output_dict['port'] output_actions.append(valve_of.output_port(output_port)) if 'failover' in output_dict: failover = output_dict['failover'] group_id = failover['group_id'] buckets = [] for port in failover['ports']: buckets.append( valve_of.bucket(watch_port=port, actions=[valve_of.output_port(port)])) ofmsgs.append(valve_of.groupdel(group_id=group_id)) ofmsgs.append(valve_of.groupadd_ff(group_id=group_id, buckets=buckets)) output_actions.append(valve_of.group_act(group_id=group_id)) return (output_port, output_actions, ofmsgs)
def get_port_acls(self, valve, dot1x_port): """Setup the dot1x forward port acls. Args: dot1x_port: valve: Returns: list of flowmods """ port_acl_table = valve.dp.tables['port_acl'] nfv_sw_port = valve.dp.dot1x['nfv_sw_port'] valve_index = self.dp_id_to_valve_index[valve.dp.dp_id] mac = get_mac_str(valve_index, dot1x_port.number) ofmsgs = [] ofmsgs.append(port_acl_table.flowmod( port_acl_table.match( in_port=dot1x_port.number, eth_type=valve_packet.ETH_EAPOL), priority=valve.dp.highest_priority, inst=[valve_of.apply_actions([ valve_of.set_field(eth_dst=mac), valve_of.output_port(nfv_sw_port)])])) ofmsgs.append(port_acl_table.flowmod( port_acl_table.match( in_port=nfv_sw_port, eth_type=valve_packet.ETH_EAPOL, eth_src=mac), priority=valve.dp.highest_priority, inst=[valve_of.apply_actions([ valve_of.set_field(eth_src=EAPOL_DST), valve_of.output_port(dot1x_port.number)])])) return ofmsgs
def create_dot1x_flow_pair(self, dot1x_port, nfv_sw_port, mac): ofmsgs = [ self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=dot1x_port.number, eth_type=valve_packet.ETH_EAPOL), priority=self.acl_priority, inst=[ valve_of.apply_actions([ self.port_acl_table.set_field(eth_dst=mac), valve_of.output_port(nfv_sw_port.number) ]) ], ), self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=nfv_sw_port.number, eth_type=valve_packet.ETH_EAPOL, eth_src=mac), priority=self.acl_priority, inst=[ valve_of.apply_actions([ self.port_acl_table.set_field( eth_src=valve_packet.EAPOL_ETH_DST), valve_of.output_port(dot1x_port.number) ]) ], ) ] return ofmsgs
def create_flow_pair(self, dot1x_port, nfv_sw_port, valve): """Creates the pair of flows that redirects the eapol packets to/from the supplicant and nfv port Args: dot1x_port (Port): nfv_sw_port (int): valve (Valve): Returns: list """ port_acl_table = valve.dp.tables['port_acl'] valve_index = self.dp_id_to_valve_index[valve.dp.dp_id] mac = get_mac_str(valve_index, dot1x_port.number) if dot1x_port.running(): return [ port_acl_table.flowmod( inst=[valve_of.apply_actions([ valve_of.set_field(eth_dst=mac), valve_of.output_port(nfv_sw_port)])], **FaucetDot1x.get_dot1x_port_match_priority(dot1x_port, port_acl_table, valve)), port_acl_table.flowmod( inst=[valve_of.apply_actions([ valve_of.set_field(eth_src=EAPOL_DST), valve_of.output_port(dot1x_port.number)])], **FaucetDot1x.get_nfv_sw_port_match_priority(mac, nfv_sw_port, port_acl_table, valve) )] return []
def create_dot1x_flow_pair(self, dot1x_port, nfv_sw_port, mac): ofmsgs = [ self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=dot1x_port.number, eth_type=valve_packet.ETH_EAPOL), priority=self.acl_priority, inst=[valve_of.apply_actions([ self.port_acl_table.set_field(eth_dst=mac), valve_of.output_port(nfv_sw_port.number)])], ), self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=nfv_sw_port.number, eth_type=valve_packet.ETH_EAPOL, eth_src=mac), priority=self.acl_priority, inst=[valve_of.apply_actions([ self.port_acl_table.set_field( eth_src=valve_packet.EAPOL_ETH_DST), valve_of.output_port(dot1x_port.number) ])], ) ] return ofmsgs
def build_output_actions(acl_table, output_dict): """Implement actions to alter packet/output.""" output_actions = [] output_port = None ofmsgs = [] # rewrite any VLAN headers first always vlan_actions = rewrite_vlan(acl_table, output_dict) if vlan_actions: output_actions.extend(vlan_actions) if 'set_fields' in output_dict: for set_field in output_dict['set_fields']: output_actions.append(acl_table.set_field(**set_field)) if 'port' in output_dict: output_port = output_dict['port'] output_actions.append(valve_of.output_port(output_port)) if 'ports' in output_dict: for output_port in output_dict['ports']: output_actions.append(valve_of.output_port(output_port)) if 'failover' in output_dict: failover = output_dict['failover'] group_id = failover['group_id'] buckets = [] for port in failover['ports']: buckets.append(valve_of.bucket( watch_port=port, actions=[valve_of.output_port(port)])) ofmsgs.append(valve_of.groupdel(group_id=group_id)) ofmsgs.append(valve_of.groupadd_ff(group_id=group_id, buckets=buckets)) output_actions.append(valve_of.group_act(group_id=group_id)) return (output_port, output_actions, ofmsgs)
def create_dot1x_flow_pair(self, port_num, nfv_sw_port_num, mac): """Create dot1x flow pair""" ofmsgs = [ self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=port_num, eth_type=valve_packet.ETH_EAPOL), priority=self.dot1x_static_rules_priority, inst=[valve_of.apply_actions([ self.port_acl_table.set_field(eth_dst=mac), valve_of.output_port(nfv_sw_port_num)])], ), self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=nfv_sw_port_num, eth_type=valve_packet.ETH_EAPOL, eth_src=mac), priority=self.dot1x_static_rules_priority, inst=[valve_of.apply_actions([ self.port_acl_table.set_field( eth_src=valve_packet.EAPOL_ETH_DST), valve_of.output_port(port_num) ])], ) ] return ofmsgs
def create_dot1x_flow_pair(self, port_num, nfv_sw_port_num, mac): """Create dot1x flow pair""" ofmsgs = [ self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=port_num, eth_type=valve_packet.ETH_EAPOL), priority=self.override_priority, inst=(valve_of.apply_actions([ self.port_acl_table.set_field(eth_dst=mac), valve_of.output_port(nfv_sw_port_num)]),), ), self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=nfv_sw_port_num, eth_type=valve_packet.ETH_EAPOL, eth_src=mac), priority=self.override_priority, inst=(valve_of.apply_actions([ self.port_acl_table.set_field( eth_src=valve_packet.EAPOL_ETH_DST), valve_of.output_port(port_num) ]),), ) ] return ofmsgs
def output_port(self, port, hairpin=False): actions = port.mirror_actions() if self.port_is_untagged(port): actions.append(valve_of.pop_vlan()) if hairpin: actions.append(valve_of.output_port(valve_of.OFP_IN_PORT)) else: actions.append(valve_of.output_port(port.number)) return actions
def _build_group_buckets(self, vlan, unicast_flood): buckets = [] for port in vlan.tagged_flood_ports(unicast_flood): buckets.append(valve_of.bucket( actions=[valve_of.output_port(port.number)])) for port in vlan.untagged_flood_ports(unicast_flood): buckets.append(valve_of.bucket( actions=[ valve_of.pop_vlan(), valve_of.output_port(port.number)])) return buckets
def output_port(self, port, hairpin=False, output_table=None, loop_protect_field=None): actions = port.mirror_actions() if self.port_is_untagged(port): actions.append(valve_of.pop_vlan()) elif loop_protect_field is not None: actions.append(output_table.set_field(**{STACK_LOOP_PROTECT_FIELD: loop_protect_field})) if hairpin: actions.append(valve_of.output_port(valve_of.OFP_IN_PORT)) else: actions.append(valve_of.output_port(port.number)) return actions
def build_acl_entry(rule_conf, acl_allow_inst, port_num=None, vlan_vid=None): acl_inst = [] match_dict = {} for attrib, attrib_value in list(rule_conf.items()): if attrib == 'in_port': continue if attrib == 'actions': allow = False allow_specified = False if 'allow' in attrib_value: allow_specified = True if attrib_value['allow'] == 1: allow = True if 'mirror' in attrib_value: port_no = attrib_value['mirror'] acl_inst.append( valve_of.apply_actions([valve_of.output_port(port_no)])) if not allow_specified: allow = True if 'output' in attrib_value: output_dict = attrib_value['output'] output_actions = [] output_port = None if 'port' in output_dict: output_port = output_dict['port'] # if destination rewriting selected, rewrite it. if 'dl_dst' in output_dict: output_actions.append( valve_of.set_eth_dst(output_dict['dl_dst'])) # rewrite any VLAN headers. vlan_actions = rewrite_vlan(output_dict) if vlan_actions: output_actions.extend(vlan_actions) # output to a port if specified. if output_port is not None: output_actions.append(valve_of.output_port(output_port)) acl_inst.append(valve_of.apply_actions(output_actions)) # if port specified, output packet now and exit pipeline. if output_port is not None: continue if allow: acl_inst.append(acl_allow_inst) else: match_dict[attrib] = attrib_value if port_num is not None: match_dict['in_port'] = port_num if vlan_vid is not None: match_dict['vlan_vid'] = valve_of.vid_present(vlan_vid) acl_match = valve_of.match_from_dict(match_dict) return acl_match, acl_inst
def build_port_out_inst(self, vlan, port): dst_act = [] if not vlan.port_is_tagged(port.number) and port.stack is None: dst_act.append(valve_of.pop_vlan()) dst_act.append(valve_of.output_port(port.number)) if port.mirror is not None: mirror_acts = [valve_of.output_port(port.mirror)] dst_act.extend(mirror_acts) return [valve_of.apply_actions(dst_act)]
def output_port(self, port, hairpin=False): actions = [] # If port should mirror add output to mirror ports if port.mirror is not None: for mirror_port in port.mirror: actions.append(valve_of.output_port(mirror_port)) if self.port_is_untagged(port): actions.append(valve_of.pop_vlan()) if hairpin: actions.append(valve_of.output_port(valve_of.OFP_IN_PORT)) else: actions.append(valve_of.output_port(port.number)) return actions
def build_ordered_output_actions(acl_table, output_list, tunnel_rules=None, source_id=None): """Build actions from ordered ACL output list""" output_actions = [] output_ports = [] output_ofmsgs = [] output_inst = [] for action in output_list: for key, value in action.items(): if key == 'pop_vlans': for _ in range(value): output_actions.append(valve_of.pop_vlan()) if key == 'vlan_vid': output_actions.extend(push_vlan(acl_table, value)) if key == 'swap_vid': output_actions.append(acl_table.set_vlan_vid(value)) if key == 'vlan_vids': for vlan_vid in value: output_actions.extend(push_vlan(acl_table, vlan_vid)) if key == 'set_fields': for set_field in value: output_actions.append(acl_table.set_field(**set_field)) if key == 'port': output_ports.append(value) output_actions.append(valve_of.output_port(value)) if key == 'ports': for output_port in value: output_ports.append(output_port) output_actions.append(valve_of.output_port(output_port)) if key == 'failover': group_id = value['group_id'] buckets = [] for port in value['ports']: buckets.append( valve_of.bucket(watch_port=port, actions=[valve_of.output_port(port)])) output_ofmsgs.extend( valve_of.groupadd_ff(group_id=group_id, buckets=buckets)) output_actions.append(valve_of.group_act(group_id=group_id)) if key == 'tunnel' and tunnel_rules and source_id is not None: source_rule = tunnel_rules[value][source_id] _, tunnel_actions, tunnel_ofmsgs, tunnel_inst = build_output_actions( acl_table, source_rule) output_actions.extend(tunnel_actions) output_ofmsgs.extend(tunnel_ofmsgs) output_inst.extend(tunnel_inst) if key == 'goto': output_inst.append(valve_of.goto_table_id(value)) return (output_ports, output_actions, output_ofmsgs, output_inst)
def build_port_out_inst(self, vlan, port, port_number=None): """Return instructions to output a packet on a given port.""" if port_number is None: port_number = port.number dst_act = [] if not vlan.port_is_tagged(port) and port.stack is None: dst_act.append(valve_of.pop_vlan()) dst_act.append(valve_of.output_port(port_number)) if port.mirror is not None: mirror_acts = [valve_of.output_port(port.mirror)] dst_act.extend(mirror_acts) return [valve_of.apply_actions(dst_act)]
def _build_flood_port_outputs(self, ports, exclude_port): flood_acts = [] for port in ports: if port == exclude_port: continue flood_acts.append(valve_of.output_port(port.number)) return flood_acts
def create_mab_flow(self, port_num, nfv_sw_port_num, mac): """ Create MAB ACL for sending IP Activity to Chewie NFV Returns flowmods to send all IP traffic to Chewie Args: port_num (int): Number of port in nfv_sw_port_num(int): Number of port out mac(str): MAC address of the valve/port combo """ return self.port_acl_table.flowmod( match=self.port_acl_table.match( in_port=port_num, eth_type=valve_of.ether.ETH_TYPE_IP, nw_proto=valve_of.inet.IPPROTO_UDP, udp_src=68, udp_dst=67, ), priority=self.low_priority, inst=(valve_of.apply_actions([ self.port_acl_table.set_field(eth_dst=mac), valve_of.output_port(nfv_sw_port_num) ]), ), )
def _nexthop_group_buckets(self, vlan, port, eth_src): actions = self._nexthop_actions(eth_src, vlan) if not vlan.port_is_tagged(port): actions.append(valve_of.pop_vlan()) actions.append(valve_of.output_port(port.number)) buckets = [valve_of.bucket(actions=actions)] return buckets
def add_port(self, port): """Add flows to allow coprocessor to inject or output packets.""" ofmsgs = [] if port.coprocessor: ofmsgs.append( self.vlan_table.flowmod( self.vlan_table.match(in_port=port.number), priority=self.low_priority, inst=(self.vlan_table.goto(self.copro_table), ))) ofmsgs.append( self.eth_src_table.flowmod( match=self.eth_src_table.match(in_port=port.number), priority=self.high_priority, inst=(self.eth_src_table.goto(self.output_table), ))) # TODO: add additional output port strategies (eg. MPLS) and tagged ports vlan_vid_base = port.coprocessor.get('vlan_vid_base', 0) for port_number in self.ports: inst = (valve_of.apply_actions( (valve_of.pop_vlan(), valve_of.output_port(port_number))), ) vid = vlan_vid_base + port_number vlan = OFVLAN(str(vid), vid) match = self.copro_table.match(vlan=vlan) ofmsgs.append( self.copro_table.flowmod(match=match, priority=self.high_priority, inst=inst)) return ofmsgs
def build_output_actions(acl_table, output_dict, tunnel_rules=None, source_id=None): """Implement actions to alter packet/output.""" if isinstance(output_dict, (list, tuple)): return build_ordered_output_actions(acl_table, output_dict, tunnel_rules, source_id) output_actions = [] output_inst = [] output_port = None ofmsgs = [] # rewrite any VLAN headers first always vlan_actions = rewrite_vlan(acl_table, output_dict) if vlan_actions: output_actions.extend(vlan_actions) if 'set_fields' in output_dict: for set_field in output_dict['set_fields']: output_actions.append(acl_table.set_field(**set_field)) if 'port' in output_dict: output_port = output_dict['port'] output_actions.append(valve_of.output_port(output_port)) if 'ports' in output_dict: for output_port in output_dict['ports']: output_actions.append(valve_of.output_port(output_port)) if 'failover' in output_dict: failover = output_dict['failover'] group_id = failover['group_id'] buckets = [] for port in failover['ports']: buckets.append( valve_of.bucket(watch_port=port, actions=[valve_of.output_port(port)])) ofmsgs.extend(valve_of.groupadd_ff(group_id=group_id, buckets=buckets)) output_actions.append(valve_of.group_act(group_id=group_id)) if 'tunnel' in output_dict and tunnel_rules and source_id is not None: tunnel_id = output_dict['tunnel'] source_rule = tunnel_rules[tunnel_id][source_id] _, tunnel_actions, tunnel_ofmsgs, tunnel_inst = build_output_actions( acl_table, source_rule) output_actions.extend(tunnel_actions) tunnel_ofmsgs.extend(tunnel_ofmsgs) output_inst.extend(tunnel_inst) if 'goto' in output_dict: output_inst.append(valve_of.goto_table_id(output_dict['goto'])) return (output_port, output_actions, ofmsgs, output_inst)
def output_port(self, port, hairpin=False, output_table=None, loop_protect_field=None): actions = port.mirror_actions() if self.port_is_untagged(port): actions.append(valve_of.pop_vlan()) elif loop_protect_field is not None: actions.append( output_table.set_field( **{STACK_LOOP_PROTECT_FIELD: loop_protect_field})) if hairpin: actions.append(valve_of.output_port(valve_of.OFP_IN_PORT)) else: actions.append(valve_of.output_port(port.number)) return actions
def mirror_actions(self): """Return OF actions to mirror this port.""" if self.mirror is not None: return [ valve_of.output_port(mirror_port) for mirror_port in self.mirror ] return []
def learn_host_on_vlan_port_flows(self, port, vlan, eth_src, delete_existing, refresh_rules, src_rule_idle_timeout, src_rule_hard_timeout, dst_rule_idle_timeout): """Return flows that implement learning a host on a port.""" ofmsgs = [] # Delete any existing entries for MAC. if delete_existing: ofmsgs.extend(self.delete_host_from_vlan(eth_src, vlan)) # Associate this MAC with source port. src_match = self.eth_src_table.match(in_port=port.number, vlan=vlan, eth_src=eth_src) src_priority = self.host_priority - 1 inst = self.eth_src_table.goto(self.output_table) if port.override_output_port: inst = valve_of.apply_actions( [valve_of.output_port(port.override_output_port.number)]) ofmsgs.append( self.eth_src_table.flowmod(match=src_match, priority=src_priority, inst=[inst], hard_timeout=src_rule_hard_timeout, idle_timeout=src_rule_idle_timeout)) hairpinning = port.hairpin or port.hairpin_unicast # If we are refreshing only and not in hairpin mode, leave existing eth_dst alone. if refresh_rules and not hairpinning: return ofmsgs # Output packets for this MAC to specified port. ofmsgs.append( self.eth_dst_table.flowmod(self.eth_dst_table.match( vlan=vlan, eth_dst=eth_src), priority=self.host_priority, inst=self.pipeline.output(port, vlan), idle_timeout=dst_rule_idle_timeout)) # If port is in hairpin mode, install a special rule # that outputs packets destined to this MAC back out the same # port they came in (e.g. multiple hosts on same WiFi AP, # and FAUCET is switching between them on the same port). if hairpinning: ofmsgs.append( self.eth_dst_hairpin_table.flowmod( self.eth_dst_hairpin_table.match(in_port=port.number, vlan=vlan, eth_dst=eth_src), priority=self.host_priority, inst=self.pipeline.output(port, vlan, hairpin=True), idle_timeout=dst_rule_idle_timeout)) return ofmsgs
def learn_host_on_vlan_port_flows(self, port, vlan, eth_src, delete_existing, refresh_rules, src_rule_idle_timeout, src_rule_hard_timeout, dst_rule_idle_timeout): """Return flows that implement learning a host on a port.""" ofmsgs = [] # Delete any existing entries for MAC. if delete_existing: ofmsgs.extend(self.delete_host_from_vlan(eth_src, vlan)) # Associate this MAC with source port. src_match = self.eth_src_table.match( in_port=port.number, vlan=vlan, eth_src=eth_src) src_priority = self.host_priority - 1 inst = self.eth_src_table.goto(self.output_table) if port.override_output_port: inst = valve_of.apply_actions([ valve_of.output_port(port.override_output_port.number)]) loop_protect_field = None if port.tagged_vlans and port.loop_protect_external and self.stack: loop_protect_field = 0 ofmsgs.append(self.eth_src_table.flowmod( match=src_match, priority=src_priority, inst=[inst], hard_timeout=src_rule_hard_timeout, idle_timeout=src_rule_idle_timeout)) hairpinning = port.hairpin or port.hairpin_unicast # If we are refreshing only and not in hairpin mode, leave existing eth_dst alone. if refresh_rules and not hairpinning: return ofmsgs # Output packets for this MAC to specified port. ofmsgs.append(self.eth_dst_table.flowmod( self.eth_dst_table.match(vlan=vlan, eth_dst=eth_src), priority=self.host_priority, inst=self.pipeline.output(port, vlan, loop_protect_field=loop_protect_field), idle_timeout=dst_rule_idle_timeout)) # If port is in hairpin mode, install a special rule # that outputs packets destined to this MAC back out the same # port they came in (e.g. multiple hosts on same WiFi AP, # and FAUCET is switching between them on the same port). if hairpinning: ofmsgs.append(self.eth_dst_hairpin_table.flowmod( self.eth_dst_hairpin_table.match(in_port=port.number, vlan=vlan, eth_dst=eth_src), priority=self.host_priority, inst=self.pipeline.output(port, vlan, hairpin=True), idle_timeout=dst_rule_idle_timeout)) return ofmsgs
def output_port(self, port, hairpin=False, output_table=None, external_forwarding_requested=None): actions = [] if self.port_is_untagged(port): actions.append(valve_of.pop_vlan()) # Packet is mirrored, as the receiving host sees it (without a tag). actions.extend(port.mirror_actions()) else: actions.extend(port.mirror_actions()) if external_forwarding_requested is not None: if external_forwarding_requested: actions.append(output_table.set_external_forwarding_requested()) else: actions.append(output_table.set_no_external_forwarding_requested()) if hairpin: actions.append(valve_of.output_port(valve_of.OFP_IN_PORT)) else: actions.append(valve_of.output_port(port.number)) return actions
def learn_host_on_vlan_port_flows(self, port, vlan, eth_src, delete_existing, src_rule_idle_timeout, src_rule_hard_timeout, dst_rule_idle_timeout): """Return flows that implement learning a host on a port.""" ofmsgs = [] if port.permanent_learn: # Antispoofing rule for this MAC. ofmsgs.append(self.eth_src_table.flowdrop( self.eth_src_table.match(vlan=vlan, eth_src=eth_src), priority=(self.host_priority - 2))) else: # Delete any existing entries for MAC. # TODO: for LAGs, don't delete entries in the same LAG. if delete_existing: ofmsgs.extend(self.delete_host_from_vlan(eth_src, vlan)) # Associate this MAC with source port. src_match = self.eth_src_table.match( in_port=port.number, vlan=vlan, eth_src=eth_src) if port.override_output_port: ofmsgs.append(self.eth_src_table.flowmod( match=src_match, priority=(self.host_priority - 1), inst=[valve_of.apply_actions([ valve_of.output_port(port.override_output_port.number)])], hard_timeout=src_rule_hard_timeout, idle_timeout=src_rule_idle_timeout)) else: ofmsgs.append(self.eth_src_table.flowmod( match=src_match, priority=(self.host_priority - 1), inst=[valve_of.goto_table(self.eth_dst_table)], hard_timeout=src_rule_hard_timeout, idle_timeout=src_rule_idle_timeout)) # Output packets for this MAC to specified port. ofmsgs.append(self.eth_dst_table.flowmod( self.eth_dst_table.match(vlan=vlan, eth_dst=eth_src), priority=self.host_priority, inst=[valve_of.apply_actions(vlan.output_port(port))], idle_timeout=dst_rule_idle_timeout)) # If port is in hairpin mode, install a special rule # that outputs packets destined to this MAC back out the same # port they came in (e.g. multiple hosts on same WiFi AP, # and FAUCET is switching between them on the same port). if port.hairpin: ofmsgs.append(self.eth_dst_table.flowmod( self.eth_dst_table.match(in_port=port.number, vlan=vlan, eth_dst=eth_src), priority=(self.host_priority + 1), inst=[valve_of.apply_actions(vlan.output_port(port, hairpin=True))], idle_timeout=dst_rule_idle_timeout)) return ofmsgs
def build_acl_entry(rule_conf, acl_allow_inst, meters, port_num=None, vlan_vid=None): acl_inst = [] acl_match_dict = {} acl_ofmsgs = [] acl_cookie = None for attrib, attrib_value in list(rule_conf.items()): if attrib == 'in_port': continue if attrib == 'cookie': acl_cookie = attrib_value continue if attrib == 'actions': allow = False allow_specified = False if 'allow' in attrib_value: allow_specified = True if attrib_value['allow'] == 1: allow = True if 'meter' in attrib_value: meter_name = attrib_value['meter'] acl_inst.append( valve_of.apply_meter(meters[meter_name].meter_id)) if 'mirror' in attrib_value: port_no = attrib_value['mirror'] acl_inst.append( valve_of.apply_actions([valve_of.output_port(port_no)])) if not allow_specified: allow = True if 'output' in attrib_value: output_port, output_actions, output_ofmsgs = build_output_actions( attrib_value['output']) acl_inst.append(valve_of.apply_actions(output_actions)) acl_ofmsgs.extend(output_ofmsgs) # if port specified, output packet now and exit pipeline. if output_port is not None: continue if allow: acl_inst.append(acl_allow_inst) else: acl_match_dict[attrib] = attrib_value if port_num is not None: acl_match_dict['in_port'] = port_num if vlan_vid is not None: acl_match_dict['vlan_vid'] = valve_of.vid_present(vlan_vid) try: acl_match = valve_of.match_from_dict(acl_match_dict) except TypeError: assert False, 'invalid type in ACL' return (acl_match, acl_inst, acl_cookie, acl_ofmsgs)
def _build_mirrored_flood_rules(self, vlan, eth_dst, eth_dst_mask, exclude_unicast, command, flood_priority): ofmsgs = [] mirrored_ports = vlan.mirrored_ports() for port in mirrored_ports: mirror_acts = [valve_of.output_port(port.mirror)] ofmsgs.extend(self._build_flood_rule_for_port( vlan, eth_dst, eth_dst_mask, exclude_unicast, command, flood_priority, port, mirror_acts)) return ofmsgs
def _add_egress_table_rule(self, port, vlan, pop_vlan=True): metadata, metadata_mask = faucet_md.get_egress_metadata( port.number, vlan.vid) actions = copy.copy(port.mirror_actions()) if pop_vlan: actions.append(valve_of.pop_vlan()) actions.append(valve_of.output_port(port.number)) inst = (valve_of.apply_actions(tuple(actions)), ) return self.egress_table.flowmod(self.egress_table.match( vlan=vlan, metadata=metadata, metadata_mask=metadata_mask), priority=self.dp.high_priority, inst=inst)
def add_port(self, port): """initialise override_output_port if necessary""" ofmsgs = [] if port.override_output_port: ofmsgs.append(self.eth_src_table.flowmod( match=self.eth_src_table.match( in_port=port.number), priority=self.low_priority + 1, inst=[valve_of.apply_actions([ valve_of.output_controller(), valve_of.output_port(port.override_output_port.number)])])) return ofmsgs
def output_port(self, port, hairpin=False, output_table=None, loop_protect_field=None): actions = [] if self.port_is_untagged(port): actions.append(valve_of.pop_vlan()) # Packet is mirrored, as the receiving host sees it (without a tag). actions.extend(port.mirror_actions()) else: actions.extend(port.mirror_actions()) if loop_protect_field is not None: actions.append( output_table.set_field( **{STACK_LOOP_PROTECT_FIELD: loop_protect_field})) if hairpin: actions.append(valve_of.output_port(valve_of.OFP_IN_PORT)) else: actions.append(valve_of.output_port(port.number)) return actions
def _add_egress_table_rule(self, port, vlan, pop_vlan=True): metadata, metadata_mask = faucet_md.get_egress_metadata( port.number, vlan.vid) actions = copy.copy(port.mirror_actions()) if pop_vlan: actions.append(valve_of.pop_vlan()) actions.append(valve_of.output_port(port.number)) inst = [valve_of.apply_actions(actions)] return self.egress_table.flowmod( self.egress_table.match( vlan=vlan, metadata=metadata, metadata_mask=metadata_mask ), priority=self.dp.high_priority, inst=inst )
def test_delete_order(self): """Test delete ordering/deupdlication.""" global_groupdel = valve_of.groupdel(group_id=valve_of.ofp.OFPG_ALL) global_flowdel = valve_of.flowmod(cookie=None, hard_timeout=None, idle_timeout=None, match_fields=None, out_port=None, table_id=valve_of.ofp.OFPTT_ALL, inst=(), priority=0, command=valve_of.ofp.OFPFC_DELETE, out_group=valve_of.ofp.OFPG_ANY) flowdel = valve_of.flowmod(cookie=None, hard_timeout=None, idle_timeout=None, match_fields=None, out_port=None, table_id=9, inst=(), priority=0, command=valve_of.ofp.OFPFC_DELETE, out_group=valve_of.ofp.OFPG_ANY) flow = valve_of.output_port(1) flows = [flowdel, flow, flow, flow, global_flowdel, global_groupdel] reordered = valve_of.valve_flowreorder(flows, use_barriers=True) reordered_str = [str(flow) for flow in reordered] # global deletes come first self.assertTrue(valve_of.is_global_groupdel(reordered[0]), msg=reordered) self.assertTrue(valve_of.is_global_flowdel(reordered[1]), msg=reordered) # with a berrier self.assertEqual(str(valve_of.barrier()), str(reordered[2]), msg=reordered) # without the individual delete self.assertTrue(str(flowdel) not in reordered_str, msg=reordered) # with regular flow last self.assertEqual(str(flow), reordered_str[-1], msg=reordered)
def build_acl_entry( # pylint: disable=too-many-arguments,too-many-branches,too-many-statements acl_table, rule_conf, meters, acl_allow_inst, acl_force_port_vlan_inst, port_num=None, vlan_vid=None, tunnel_rules=None, source_id=None): """Build flow/groupmods for one ACL rule entry.""" acl_inst = [] acl_act = [] acl_match_dict = {} acl_ofmsgs = [] acl_cookie = None allow_inst = acl_allow_inst for attrib, attrib_value in rule_conf.items(): # if attrib == 'in_port': # continue if attrib == 'cookie': acl_cookie = attrib_value continue if attrib == 'description': continue if attrib == 'actions': allow = False allow_specified = False if 'allow' in attrib_value: allow_specified = True if attrib_value['allow'] == 1: allow = True if 'force_port_vlan' in attrib_value: if attrib_value['force_port_vlan'] == 1: allow_inst = acl_force_port_vlan_inst if 'meter' in attrib_value: meter_name = attrib_value['meter'] acl_inst.append(valve_of.apply_meter(meters[meter_name].meter_id)) if 'mirror' in attrib_value: port_no = attrib_value['mirror'] acl_act.append(valve_of.output_port(port_no)) if not allow_specified: allow = True if 'output' in attrib_value: output_port, output_actions, output_ofmsgs, output_inst = build_output_actions( acl_table, attrib_value['output'], tunnel_rules, source_id) acl_act.extend(output_actions) acl_ofmsgs.extend(output_ofmsgs) acl_inst.extend(output_inst) # if port specified, output packet now and exit pipeline. if not allow and output_port is not None: continue if 'ct' in attrib_value: ct_action = build_ct_actions(acl_table, attrib_value['ct']) acl_act.append(ct_action) if allow: acl_inst.extend(allow_inst) else: acl_match_dict[attrib] = attrib_value if port_num is not None: # This overwrites the `in_port` match if it is specified in the ACL config acl_match_dict['in_port'] = port_num if vlan_vid is not None: # This overwrites the `vlan_vid` match if it is specified in the ACL config acl_match_dict['vlan_vid'] = valve_of.vid_present(vlan_vid) try: acl_match = valve_of.match_from_dict(acl_match_dict) except TypeError as type_error: raise InvalidConfigError('invalid match type in ACL') from type_error if acl_act: acl_inst.append(valve_of.apply_actions(acl_act)) return (acl_match, acl_inst, acl_cookie, acl_ofmsgs)
def learn_host_on_vlan_port_flows(self, port, vlan, eth_src, delete_existing, refresh_rules, src_rule_idle_timeout, src_rule_hard_timeout, dst_rule_idle_timeout): """Return flows that implement learning a host on a port.""" ofmsgs = [] if port.permanent_learn: # Antispoofing rule for this MAC. if self.classification_table != self.eth_src_table: ofmsgs.append(self.classification_table.flowmod( self.classification_table.match( in_port=port.number, vlan=vlan, eth_src=eth_src), priority=self.host_priority, inst=[self.classification_table.goto(self.eth_src_table)])) ofmsgs.append(self.classification_table.flowdrop( self.classification_table.match(vlan=vlan, eth_src=eth_src), priority=(self.host_priority - 2))) else: # Delete any existing entries for MAC. if delete_existing: ofmsgs.extend(self.delete_host_from_vlan(eth_src, vlan)) # Associate this MAC with source port. src_match = self.eth_src_table.match( in_port=port.number, vlan=vlan, eth_src=eth_src) src_priority = self.host_priority - 1 inst = self.eth_src_table.goto(self.output_table) if port.override_output_port: inst = valve_of.apply_actions([ valve_of.output_port(port.override_output_port.number)]) ofmsgs.append(self.eth_src_table.flowmod( match=src_match, priority=src_priority, inst=[inst], hard_timeout=src_rule_hard_timeout, idle_timeout=src_rule_idle_timeout)) hairpinning = port.hairpin or port.hairpin_unicast # If we are refreshing only and not in hairpin mode, leave existing eth_dst alone. if refresh_rules and not hairpinning: return ofmsgs # Output packets for this MAC to specified port. if self.egress_table is not None: metadata, metadata_mask = get_egress_metadata(port.number, vlan.vid) ofmsgs.append(self.eth_dst_table.flowmod( self.eth_dst_table.match(vlan=vlan, eth_dst=eth_src), priority=self.host_priority, inst=valve_of.metadata_goto_table( metadata, metadata_mask, self.egress_table), idle_timeout=dst_rule_idle_timeout)) else: ofmsgs.append(self.eth_dst_table.flowmod( self.eth_dst_table.match(vlan=vlan, eth_dst=eth_src), priority=self.host_priority, inst=[valve_of.apply_actions(vlan.output_port(port))], idle_timeout=dst_rule_idle_timeout)) # If port is in hairpin mode, install a special rule # that outputs packets destined to this MAC back out the same # port they came in (e.g. multiple hosts on same WiFi AP, # and FAUCET is switching between them on the same port). if hairpinning: ofmsgs.append(self.eth_dst_hairpin_table.flowmod( self.eth_dst_hairpin_table.match(in_port=port.number, vlan=vlan, eth_dst=eth_src), priority=self.host_priority, inst=[valve_of.apply_actions(vlan.output_port(port, hairpin=True))], idle_timeout=dst_rule_idle_timeout)) return ofmsgs
def build_acl_entry(acl_table, rule_conf, meters, acl_allow_inst, acl_force_port_vlan_inst, port_num=None, vlan_vid=None): """Build flow/groupmods for one ACL rule entry.""" acl_inst = [] acl_act = [] acl_match_dict = {} acl_ofmsgs = [] acl_cookie = None allow_inst = acl_allow_inst for attrib, attrib_value in rule_conf.items(): if attrib == 'in_port': continue if attrib == 'cookie': acl_cookie = attrib_value continue if attrib == 'description': continue if attrib == 'actions': allow = False allow_specified = False if 'allow' in attrib_value: allow_specified = True if attrib_value['allow'] == 1: allow = True if 'force_port_vlan' in attrib_value: if attrib_value['force_port_vlan'] == 1: allow_inst = acl_force_port_vlan_inst if 'meter' in attrib_value: meter_name = attrib_value['meter'] acl_inst.append( valve_of.apply_meter(meters[meter_name].meter_id)) if 'mirror' in attrib_value: port_no = attrib_value['mirror'] acl_act.append(valve_of.output_port(port_no)) if not allow_specified: allow = True if 'output' in attrib_value: output_port, output_actions, output_ofmsgs = build_output_actions( acl_table, attrib_value['output']) acl_act.extend(output_actions) acl_ofmsgs.extend(output_ofmsgs) # if port specified, output packet now and exit pipeline. if not allow and output_port is not None: continue if allow: acl_inst.extend(allow_inst) else: acl_match_dict[attrib] = attrib_value if port_num is not None: acl_match_dict['in_port'] = port_num if vlan_vid is not None: acl_match_dict['vlan_vid'] = valve_of.vid_present(vlan_vid) try: acl_match = valve_of.match_from_dict(acl_match_dict) except TypeError: raise InvalidConfigError('invalid type in ACL') if acl_act: acl_inst.append(valve_of.apply_actions(acl_act)) return (acl_match, acl_inst, acl_cookie, acl_ofmsgs)
def mirror_actions(self): """Return OF actions to mirror this port.""" if self.mirror is not None: return [valve_of.output_port(mirror_port) for mirror_port in self.mirror] return []
def build_acl_entry(acl_table, rule_conf, meters, acl_allow_inst, acl_force_port_vlan_inst, port_num=None, vlan_vid=None): """Build flow/groupmods for one ACL rule entry.""" acl_inst = [] acl_act = [] acl_match_dict = {} acl_ofmsgs = [] acl_cookie = None allow_inst = acl_allow_inst for attrib, attrib_value in rule_conf.items(): if attrib == 'in_port': continue if attrib == 'cookie': acl_cookie = attrib_value continue if attrib == 'description': continue if attrib == 'actions': allow = False allow_specified = False if 'allow' in attrib_value: allow_specified = True if attrib_value['allow'] == 1: allow = True if 'force_port_vlan' in attrib_value: if attrib_value['force_port_vlan'] == 1: allow_inst = acl_force_port_vlan_inst if 'meter' in attrib_value: meter_name = attrib_value['meter'] acl_inst.append(valve_of.apply_meter(meters[meter_name].meter_id)) if 'mirror' in attrib_value: port_no = attrib_value['mirror'] acl_act.append(valve_of.output_port(port_no)) if not allow_specified: allow = True if 'output' in attrib_value: output_port, output_actions, output_ofmsgs = build_output_actions( acl_table, attrib_value['output']) acl_act.extend(output_actions) acl_ofmsgs.extend(output_ofmsgs) # if port specified, output packet now and exit pipeline. if not allow and output_port is not None: continue if allow: acl_inst.extend(allow_inst) else: acl_match_dict[attrib] = attrib_value if port_num is not None: acl_match_dict['in_port'] = port_num if vlan_vid is not None: acl_match_dict['vlan_vid'] = valve_of.vid_present(vlan_vid) try: acl_match = valve_of.match_from_dict(acl_match_dict) except TypeError: raise InvalidConfigError('invalid type in ACL') if acl_act: acl_inst.append(valve_of.apply_actions(acl_act)) return (acl_match, acl_inst, acl_cookie, acl_ofmsgs)