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 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.startswith('_') and attrib.endswith('_'): continue 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) 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_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 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 _build_flood_rule_actions(self, vlan, exclude_unicast, exclude_ports=[]): flood_acts = [] tagged_ports = vlan.tagged_flood_ports(exclude_unicast) untagged_ports = vlan.untagged_flood_ports(exclude_unicast) for port in tagged_ports: if port not in exclude_ports: flood_acts.append(valve_of.output_port(port.number)) if untagged_ports: flood_acts.append(valve_of.pop_vlan()) for port in untagged_ports: if port not in exclude_ports: flood_acts.append(valve_of.output_port(port.number)) return flood_acts
def _nexthop_group_buckets(self, vlan, in_port, eth_src): actions = self._nexthop_actions(eth_src) if not vlan.port_is_tagged(in_port): actions.append(valve_of.pop_vlan()) actions.append(valve_of.output_port(in_port)) buckets = [valve_of.bucket(actions=actions)] return buckets
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 build_flood_rules(self, vlan, modify=False): """Add flows to flood packets to unknown destinations on a VLAN.""" # TODO: not all vendors implement groups well. # That means we need flood rules for each input port, outputting # to all ports except the input port. When all vendors implement # groups correctly we can use them. command = ofp.OFPFC_ADD if modify: command = ofp.OFPFC_MODIFY_STRICT flood_priority = self.flood_priority flood_eth_dst_matches = [] if vlan.unicast_flood: flood_eth_dst_matches.extend([(None, None)]) flood_eth_dst_matches.extend([ ('01:80:C2:00:00:00', 'ff:ff:ff:00:00:00'), # 802.x ('01:00:5E:00:00:00', 'ff:ff:ff:00:00:00'), # IPv4 multicast ('33:33:00:00:00:00', 'ff:ff:00:00:00:00'), # IPv6 multicast (mac.BROADCAST_STR, None), # flood on ethernet broadcasts ]) ofmsgs = [] vlan_all_ports = vlan.flood_ports(vlan.get_ports(), False) mirrored_ports = vlan.mirrored_ports() for eth_dst, eth_dst_mask in flood_eth_dst_matches: for port in vlan_all_ports: if eth_dst is None: flood_acts = self._build_flood_rule_actions( vlan, False, exclude_ports=[port]) else: flood_acts = self._build_flood_rule_actions( vlan, True, exclude_ports=[port]) ofmsgs.append(self.valve_flowmod( self.flood_table, match=self.valve_in_match( self.flood_table, in_port=port.number, vlan=vlan, eth_dst=eth_dst, eth_dst_mask=eth_dst_mask), command=command, inst=[valve_of.apply_actions(flood_acts)], priority=flood_priority)) flood_priority += 1 for port in mirrored_ports: if eth_dst is None: flood_acts = self._build_flood_rule_actions(vlan, False) else: flood_acts = self._build_flood_rule_actions(vlan, True) mirror_acts = [ valve_of.output_port(port.mirror)] + flood_acts ofmsgs.append(self.valve_flowmod( self.flood_table, match=self.valve_in_match( self.flood_table, vlan=vlan, in_port=port.number, eth_dst=eth_dst, eth_dst_mask=eth_dst_mask), command=command, inst=[valve_of.apply_actions(mirror_acts)], priority=flood_priority)) flood_priority += 1 return ofmsgs
def build_acl_entry(rule_conf, acl_allow_inst, port_num=None, vlan_vid=None): acl_inst = [] match_dict = {} for attrib, attrib_value in 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 selected, output packet now and exit pipeline. if 'output' in attrib_value: output_dict = attrib_value['output'] output_actions = [] # if destination rewriting selected, rewrite it. if 'dl_dst' in output_dict: output_actions.append( valve_of.set_eth_dst(output_dict['dl_dst'])) # if vlan tag is specified, push it. if 'vlan_vid' in output_dict: output_actions.extend( valve_of.push_vlan_act(output_dict['vlan_vid'])) # output to port port_no = output_dict['port'] output_actions.append(valve_of.output_port(port_no)) acl_inst.append(valve_of.apply_actions(output_actions)) 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_acl_entry(rule_conf, acl_allow_inst, port_num=None, vlan_vid=None): acl_inst = [] match_dict = {} for attrib, attrib_value in rule_conf.iteritems(): 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 selected, output packet now and exit pipeline. if 'output' in attrib_value: output_dict = attrib_value['output'] output_actions = [] # if destination rewriting selected, rewrite it. if 'dl_dst' in output_dict: output_actions.append( valve_of.set_eth_dst(output_dict['dl_dst'])) # if vlan tag is specified, push it. if 'vlan_vid' in output_dict: output_actions.extend( valve_of.push_vlan_act(output_dict['vlan_vid'])) # output to port port_no = output_dict['port'] output_actions.append(valve_of.output_port(port_no)) acl_inst.append(valve_of.apply_actions(output_actions)) 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_flood_port_outputs(self, ports, in_port): flood_acts = [] for port in ports: if port == in_port: if port.hairpin: flood_acts.append(valve_of.output_in_port()) else: flood_acts.append(valve_of.output_port(port.number)) return flood_acts
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 port_add(self, dp_id, port_num): """Handle the addition of a port. Args: dp_id (int): datapath ID. port_num (int): port number. Returns: list: OpenFlow messages, if any. """ if self._ignore_dpid(dp_id) or valve_of.ignore_port(port_num): return [] if port_num not in self.dp.ports: self.logger.info( 'Ignoring port:%u not present in configuration file', port_num) return [] port = self.dp.ports[port_num] self.logger.info('Port %s added', port) port.phys_up = True if not port.running(): return [] ofmsgs = [] self.logger.info('Sending config for port %s', port) # Delete all flows previously matching this port ofmsgs.extend(self._delete_all_port_match_flows(port)) # Port is a mirror destination; drop all input packets if port.mirror_destination: ofmsgs.append(self.valve_flowdrop( self.dp.vlan_table, match=self.valve_in_match(self.dp.vlan_table, in_port=port_num), priority=self.dp.highest_priority)) return ofmsgs # Add ACL if any acl_ofmsgs, forwarding_table = self._port_add_acl(port_num) ofmsgs.extend(acl_ofmsgs) # Add mirroring if any mirror_act = [] if port.mirror: mirror_act = [valve_of.output_port(port.mirror)] # Add port/to VLAN rules. ofmsgs.extend(self._port_add_vlans(port, forwarding_table, mirror_act)) return ofmsgs
def build_acl_entry(rule_conf, acl_allow_inst, meters, port_num=None, vlan_vid=None): acl_inst = [] match_dict = {} ofmsgs = [] 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 '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)) 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: 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, ofmsgs)
def _update_nexthop(self, vlan, in_port, eth_src, resolved_ip_gw): ofmsgs = [] is_updated = None routes = self._vlan_routes(vlan) group_mod_method = None group_id = None nexthop_cache_entry = self._vlan_nexthop_cache_entry( vlan, resolved_ip_gw) if (nexthop_cache_entry is not None and nexthop_cache_entry.eth_src is not None): cached_eth_dst = nexthop_cache_entry.eth_src if cached_eth_dst != eth_src: is_updated = True if self.use_group_table: group_mod_method = valve_of.groupmod group_id = self.ip_gw_to_group_id[resolved_ip_gw] else: is_updated = False if self.use_group_table: group_mod_method = valve_of.groupadd group_id = self._group_id_from_ip_gw(resolved_ip_gw) self.ip_gw_to_group_id[resolved_ip_gw] = group_id if is_updated is not None: if self.use_group_table: actions = [] actions.extend([ valve_of.set_eth_src(self.faucet_mac), valve_of.set_eth_dst(eth_src), valve_of.dec_ip_ttl()]) if not vlan.port_is_tagged(in_port): actions.append(valve_of.pop_vlan()) actions.append(valve_of.output_port(in_port)) ofmsgs.append(group_mod_method( group_id=group_id, buckets=[valve_of.bucket(actions=actions)])) for ip_dst, ip_gw in routes.iteritems(): if ip_gw == resolved_ip_gw: ofmsgs.extend(self._add_resolved_route( vlan, ip_gw, ip_dst, eth_src, is_updated)) self._update_nexthop_cache(vlan, eth_src, resolved_ip_gw) return ofmsgs
def port_add(self, dp_id, port_num, modify=False): """Handle the addition of a port. Args: dp_id (int): datapath ID. port_num (int): port number. Returns: list: OpenFlow messages, if any. """ if self._ignore_dpid(dp_id) or valve_of.ignore_port(port_num): return [] if port_num not in self.dp.ports: self.logger.info( 'Ignoring port:%u not present in configuration file', port_num) return [] port = self.dp.ports[port_num] port.phys_up = True ofmsgs = [] if modify: # delete all rules related to this port tables = [self.dp.vlan_table, self.dp.acl_table, self.dp.eth_src_table, self.dp.flood_table] for table_id in tables: ofmsgs.extend(self.valve_flowdel( table_id, self.valve_in_match(table_id, in_port=port_num))) if not port.permanent_learn: # delete eth_dst rules ofmsgs.extend(self.valve_flowdel( self.dp.eth_dst_table, out_port=port_num)) self.logger.info('Port %s modified', port) else: self.logger.info('Port %s added', port) if not port.running(): return ofmsgs self.logger.info('Sending config for port %s', port) # Delete all flows previously matching this port ofmsgs.extend(self._delete_all_port_match_flows(port)) # Port is a mirror destination; drop all input packets if port.mirror_destination: ofmsgs.append(self.valve_flowdrop( self.dp.vlan_table, match=self.valve_in_match(self.dp.vlan_table, in_port=port_num), priority=self.dp.highest_priority)) return ofmsgs # Add ACL if any. acl_ofmsgs, forwarding_table = self._port_add_acl(port_num) ofmsgs.extend(acl_ofmsgs) # If this is a stacking port, accept all VLANs (came from another FAUCET) if port.stack is not None: ofmsgs.append(self.valve_flowmod( self.dp.vlan_table, match=self.valve_in_match(self.dp.vlan_table, in_port=port_num), priority=self.dp.low_priority, inst=[valve_of.goto_table(forwarding_table)])) return ofmsgs # Add mirroring if any mirror_act = [] if port.mirror: mirror_act = [valve_of.output_port(port.mirror)] # Add port/to VLAN rules. ofmsgs.extend(self._port_add_vlans(port, forwarding_table, mirror_act)) return ofmsgs
def port_add(self, dp_id, port_num, modify=False): """Handle the addition of a port. Args: dp_id (int): datapath ID. port_num (int): port number. Returns: list: OpenFlow messages, if any. """ if self._ignore_dpid(dp_id) or valve_of.ignore_port(port_num): return [] if port_num not in self.dp.ports: self.logger.info( 'Ignoring port:%u not present in configuration file', port_num) return [] port = self.dp.ports[port_num] port.phys_up = True ofmsgs = [] if modify: if not port.permanent_learn: # delete eth_dst rules ofmsgs.extend(self.valve_flowdel( self.dp.eth_dst_table, out_port=port_num)) self.logger.info('Port %s modified', port) else: self.logger.info('Port %s added', port) if not port.running(): return ofmsgs self.logger.info('Sending config for port %s', port) # Delete all flows previously matching this port ofmsgs.extend(self._delete_all_port_match_flows(port)) # Port is a mirror destination; drop all input packets if port.mirror_destination: ofmsgs.append(self.valve_flowdrop( self.dp.vlan_table, match=self.valve_in_match(self.dp.vlan_table, in_port=port_num), priority=self.dp.highest_priority)) return ofmsgs # Add ACL if any. acl_ofmsgs = self._port_add_acl(port_num) ofmsgs.extend(acl_ofmsgs) # If this is a stacking port, accept all VLANs (came from another FAUCET) if port.stack is not None: ofmsgs.append(self.valve_flowmod( self.dp.vlan_table, match=self.valve_in_match(self.dp.vlan_table, in_port=port_num), priority=self.dp.low_priority, inst=[valve_of.goto_table(self.dp.eth_src_table)])) for vlan in self.dp.vlans.values(): ofmsgs.extend(self.flood_manager.build_flood_rules(vlan)) else: mirror_act = [] # Add mirroring if any if port.mirror: mirror_act = [valve_of.output_port(port.mirror)] # Add port/to VLAN rules. ofmsgs.extend(self._port_add_vlans(port, mirror_act)) return ofmsgs