/** * Step through each FlowEntry in order and match on it. If we get EQUALS or SUBSET, then stop. * * <p>IF we get SUPERSET or INTERSECT, then keep going and merge the results. */ @Override public List<FlowIntersect> intersects(long dpid, OFMatch match) { List<FlowIntersect> results = new ArrayList<FlowIntersect>(); FlowIntersect intersect; MatchType matchType; boolean needMerge = false; for (Iterator<FlowEntry> it = rules.iterator(); it.hasNext(); ) { FlowEntry rule = it.next(); intersect = rule.matches(dpid, match); matchType = intersect.getMatchType(); if (matchType == MatchType.NONE) continue; results.add(intersect); if ((matchType == MatchType.EQUAL) || (matchType == MatchType.SUBSET)) break; if ((matchType == MatchType.INTERSECT) || (matchType == MatchType.SUPERSET)) needMerge = true; else // else, wtf? throw new RuntimeException("Unknown MatchType = " + intersect.getMatchType()); } if (needMerge && (results.size() > 1)) // BROKEN: needs to virtualize priorities // return priorityMerge(results); // expensive, avoid if possible return results; else return results; }
/** Strip down the flow intersections to just the matching rules */ @Override public List<FlowEntry> matches(long dpid, OFMatch match) { List<FlowEntry> results = new LinkedList<FlowEntry>(); for (FlowEntry rule : this.rules) { if (rule.matches(dpid, match).getMatchType() != MatchType.NONE) results.add(rule); } return results; }
/** * Lame: linear search to delete something in a sorted set ... but it's sorted by priority, not ID */ @Override public void removeRule(int id) throws FlowEntryNotFound { for (FlowEntry flowEntry : this.getRules()) if (flowEntry.getId() == id) { this.rules.remove(flowEntry); return; } throw new FlowEntryNotFound(id); }
/** * Get a bitset corresponding to a rule. * * @param rule - the rule. * @return the bitset corresponding to this rule. */ private BitSet getFlowRuleSet(FlowEntry rule) { BitSet flowRuleSet = new BitSet(); flowRuleSet.set(rule.getId()); return flowRuleSet; }
/** * match is called when a switch sends a packet in to the controller. The goal is to find all flow * space rules which match the fields of the packet in. * * @param dpid - the datapath id of the switch which sent the packet in. * @param match - the packet in information * @return a list, sorted by priority, of flow space rules which match. */ public List<FlowEntry> match(long dpid, FVMatch match) { BitSet set = new BitSet(); LinkedList<FlowEntry> flowrules = new LinkedList<FlowEntry>(); int wildcards = match.getWildcards(); FVLog.log(LogLevel.DEBUG, null, "dpid: ", dpid, "match: ", match.toString()); set.or(allRules); FVLog.log(LogLevel.DEBUG, null, "allRules: ", set.toString()); try { testEmpty(set, dpids, dpid, FlowEntry.ALL_DPIDS, wildcards, 0); /* * Test every field and intersect the resulting bitset. If the bit * set is empty an exception is thrown to stop the search. */ testEmpty(set, port, match.getInputPort(), ANY_IN_PORT, wildcards, FVMatch.OFPFW_IN_PORT); if (match.getDataLayerVirtualLan() != ANY_VLAN_ID) { testEmpty( set, vlan, (int) match.getDataLayerVirtualLan(), (int) ANY_VLAN_ID, wildcards, FVMatch.OFPFW_DL_VLAN); testEmpty( set, vlan, match.getDataLayerVirtualLanPriorityCodePoint() << 16, ANY_VLAN_PCP << 16, wildcards, FVMatch.OFPFW_DL_VLAN_PCP); } else { set.andNot(vlan_ignore); } testEmpty( set, dl_type, match.getDataLayerType(), ANY_ETHER, wildcards, FVMatch.OFPFW_DL_TYPE); testEmpty( set, nw, (short) match.getNetworkProtocol(), (short) ANY_NW_PROTO_TOS, wildcards, FVMatch.OFPFW_NW_PROTO); testEmpty( set, nw, (short) (match.getNetworkTypeOfService() << 8), (short) (ANY_NW_PROTO_TOS << 8), wildcards, FVMatch.OFPFW_NW_TOS); testEmpty( set, tp, (int) match.getTransportSource(), (int) ANY_TP, wildcards, FVMatch.OFPFW_TP_SRC); testEmpty( set, tp, match.getTransportDestination() << 16, ANY_TP << 16, wildcards, FVMatch.OFPFW_TP_DST); testEmpty( set, dl_src, FVMatch.toLong(match.getDataLayerSource()), ANY_MAC, wildcards, FVMatch.OFPFW_DL_SRC); testEmpty( set, dl_dst, FVMatch.toLong(match.getDataLayerDestination()), ANY_MAC, wildcards, FVMatch.OFPFW_DL_DST); for (int i = set.nextSetBit(0); i >= 0; i = set.nextSetBit(i + 1)) { FlowEntry fe = rules.get(i); FVMatch ruleMatch = fe.getRuleMatch(); FlowIntersect inter; inter = new FlowIntersect(fe.clone()); FVMatch interMatch = inter.getMatch(); interMatch.setNetworkDestination( testIP( inter, FVMatch.OFPFW_NW_DST_SHIFT, match.getNetworkDestinationMaskLen(), ruleMatch.getNetworkDestinationMaskLen(), match.getNetworkDestination(), ruleMatch.getNetworkDestination())); if (inter.getMatchType() == MatchType.NONE) { set.clear(i); continue; } // test ip_src interMatch.setNetworkSource( testIP( inter, FVMatch.OFPFW_NW_SRC_SHIFT, match.getNetworkSourceMaskLen(), ruleMatch.getNetworkSourceMaskLen(), match.getNetworkSource(), ruleMatch.getNetworkSource())); if (inter.getMatchType() == MatchType.NONE) { set.clear(i); continue; } } } catch (NoMatch e) { FVLog.log(LogLevel.INFO, null, "No match for: ", match); return flowrules; } /* * If we got here we have a match. Now return a prioritized list of * matches. * * Higher numbers have higher priorities. */ TreeSet<FlowEntry> entries = new TreeSet<FlowEntry>(); for (int i = set.nextSetBit(0); i >= 0; i = set.nextSetBit(i + 1)) { entries.add(rules.get(i)); } flowrules.addAll(entries); return flowrules; }
private FlowIntersect getIntersect(FlowEntry fe, HashMap<Integer, FlowIntersect> inters) { FlowIntersect inter = inters.get(fe.getId()); if (inter == null) inter = new FlowIntersect(fe); return inter; }
/** * This is called when a controller issues a FlowMod. The goal here is to rewrite flowmods so that * they guarantee traffic isolation between slices. A flowmod is rewritten following these rules: * * <p>1. Its field is wildcarded, then for every potentially matching rule we rewrite the field * with the value in the rule. * * <p>2. Its field is specified, then leave it untouched, but use it for matching purposes. * * <p>3. We have a potential partial match: 3.1. The field and the flowrule field do not overlap, * return no match. 3.2. The fields overlap, return the smallest possible intersection of the two. * * <p>Currently rule 3 only applies to IP addresses, but this could change in the future. * * @param dpid - The dpid this flowmod is directed to, could be wildcarded. * @param match - The set of field modifications issued by this flowmod. * @return a list of intersections (ie. flowmod rewrites) created by the flowmod issued from the * controller. */ public List<FlowIntersect> intersect(long dpid, FVMatch match) { FVLog.log(LogLevel.DEBUG, null, "dpid: ", dpid, " match: ", match.toString()); BitSet set = new BitSet(); normalize(match); int wildcards = match.getWildcards(); TreeSet<FlowIntersect> ret = new TreeSet<FlowIntersect>(); HashMap<Integer, FlowIntersect> intersections = new HashMap<Integer, FlowIntersect>(); HashMap<Integer, Pair<Boolean, BitSet>> rewrites = new HashMap<Integer, Pair<Boolean, BitSet>>(); set.or(allRules); try { testEmpty(set, dpids, dpid, FlowEntry.ALL_DPIDS, wildcards, 0); rewrites.put( FVMatch.OFPFW_IN_PORT, new Pair<Boolean, BitSet>( testEmpty( set, port, match.getInputPort(), ANY_IN_PORT, wildcards, FVMatch.OFPFW_IN_PORT), set)); rewrites.put( FVMatch.OFPFW_DL_SRC, new Pair<Boolean, BitSet>( testEmpty( set, dl_src, FVMatch.toLong(match.getDataLayerSource()), ANY_MAC, wildcards, FVMatch.OFPFW_DL_SRC), set)); rewrites.put( FVMatch.OFPFW_DL_DST, new Pair<Boolean, BitSet>( testEmpty( set, dl_dst, FVMatch.toLong(match.getDataLayerDestination()), ANY_MAC, wildcards, FVMatch.OFPFW_DL_DST), set)); rewrites.put( FVMatch.OFPFW_DL_VLAN, new Pair<Boolean, BitSet>( testEmpty( set, vlan, (int) match.getDataLayerVirtualLan(), (int) ANY_VLAN_ID, wildcards, FVMatch.OFPFW_DL_VLAN), set)); rewrites.put( FVMatch.OFPFW_DL_VLAN_PCP, new Pair<Boolean, BitSet>( testEmpty( set, vlan, match.getDataLayerVirtualLanPriorityCodePoint() << 16, ANY_VLAN_PCP << 16, wildcards, FVMatch.OFPFW_DL_VLAN_PCP), set)); rewrites.put( FVMatch.OFPFW_DL_TYPE, new Pair<Boolean, BitSet>( testEmpty( set, dl_type, match.getDataLayerType(), ANY_ETHER, wildcards, FVMatch.OFPFW_DL_TYPE), set)); rewrites.put( FVMatch.OFPFW_NW_PROTO, new Pair<Boolean, BitSet>( testEmpty( set, nw, (short) match.getNetworkProtocol(), (short) ANY_NW_PROTO_TOS, wildcards, FVMatch.OFPFW_NW_PROTO), set)); rewrites.put( FVMatch.OFPFW_NW_TOS, new Pair<Boolean, BitSet>( testEmpty( set, nw, (short) (match.getNetworkTypeOfService() << 8), (short) (ANY_NW_PROTO_TOS << 8), wildcards, FVMatch.OFPFW_NW_TOS), set)); rewrites.put( FVMatch.OFPFW_TP_SRC, new Pair<Boolean, BitSet>( testEmpty( set, tp, (int) match.getTransportSource(), (int) ANY_TP, wildcards, FVMatch.OFPFW_TP_SRC), set)); rewrites.put( FVMatch.OFPFW_TP_DST, new Pair<Boolean, BitSet>( testEmpty( set, tp, match.getTransportDestination() << 16, ANY_TP << 16, wildcards, FVMatch.OFPFW_TP_DST), set)); int field = 0; boolean rewrite = false; BitSet inters = null; FlowIntersect flow = null; FlowEntry rule = null; for (Entry<Integer, Pair<Boolean, BitSet>> entry : rewrites.entrySet()) { field = entry.getKey(); rewrite = entry.getValue().getFirst(); inters = entry.getValue().getSecond(); FVLog.log(LogLevel.DEBUG, null, "Rule ids which intersect: ", inters.toString()); for (int i = inters.nextSetBit(0); i >= 0; i = inters.nextSetBit(i + 1)) { rule = rules.get(i).clone(); flow = getIntersect(rule, intersections); if (!rewrite) { rule.setRuleMatch(match); setField(flow, rule.getRuleMatch(), field); } FVMatch ruleMatch = rules.get(i).getRuleMatch(); FlowIntersect inter = flow; FVMatch interMatch = inter.getMatch(); interMatch.setNetworkDestination( testIP( inter, FVMatch.OFPFW_NW_DST_SHIFT, match.getNetworkDestinationMaskLen(), ruleMatch.getNetworkDestinationMaskLen(), match.getNetworkDestination(), ruleMatch.getNetworkDestination())); if (inter.getMatchType() == MatchType.NONE) continue; interMatch.setNetworkSource( testIP( inter, FVMatch.OFPFW_NW_SRC_SHIFT, match.getNetworkSourceMaskLen(), ruleMatch.getNetworkSourceMaskLen(), match.getNetworkSource(), ruleMatch.getNetworkSource())); if (inter.getMatchType() == MatchType.NONE) continue; intersections.put(flow.getFlowEntry().getId(), flow); } } /* * Need to resolve intersection by priority. * * In the worst case this will be O(n) where n is the number of * rules. But in average we will only have a small subset of the * rules. Right?? */ ret.addAll(intersections.values()); FVLog.log(LogLevel.DEBUG, null, "Intersections: ", intersections); } catch (NoMatch e) { FVLog.log(LogLevel.FATAL, null, "Failed to intersect flow mod " + match); return new ArrayList<FlowIntersect>(ret); } catch (UnknownMatchField umf) { FVLog.log(LogLevel.FATAL, null, umf.getMessage()); } return new ArrayList<FlowIntersect>(ret); }
/** * Converse of addRule. Since we know all the rules ever stored in this flowmap we simply retrieve * the rule using the id provided and remove each of its fields from the underlying structures. * * @param id - the id of the rule to remove * @throws FlowEntryNotFound - if this id is unknown. Could indicate that rule has already been * removed. * @return */ public void removeRule(int id) throws FlowEntryNotFound { ruleCount--; if (!rules.containsKey(id)) throw new FlowEntryNotFound(id); FlowEntry rule = rules.get(id); BitSet flowRuleSet = getFlowRuleSet(rule); remove(port, rule.getRuleMatch().getInputPort(), flowRuleSet); remove(dpids, rule.dpid, flowRuleSet); remove(vlan, (int) rule.getRuleMatch().getDataLayerVirtualLan(), flowRuleSet); remove(vlan, rule.getRuleMatch().getDataLayerVirtualLanPriorityCodePoint() << 16, flowRuleSet); remove(dl_type, rule.getRuleMatch().getDataLayerType(), flowRuleSet); remove(nw, (short) rule.getRuleMatch().getNetworkProtocol(), flowRuleSet); remove(nw, (short) (rule.getRuleMatch().getNetworkTypeOfService() << 8), flowRuleSet); remove(tp, (int) rule.getRuleMatch().getTransportSource(), flowRuleSet); remove(tp, rule.getRuleMatch().getTransportDestination() << 16, flowRuleSet); remove(dl_src, FVMatch.toLong(rule.getRuleMatch().getDataLayerSource()), flowRuleSet); remove(dl_dst, FVMatch.toLong(rule.getRuleMatch().getDataLayerDestination()), flowRuleSet); remove(prioSet, rule.getPriority(), flowRuleSet); vlan_ignore.clear(rule.getId()); rules.remove(rule.getId()); allRules.andNot(flowRuleSet); }
/** * Adds a rule to the flowmap. It does so by exploding the rule into its fields and storing each * field into its independent structure. * * @param rule - the rule which will be added to the flowmap * @return */ public void addRule(FlowEntry rule) { ruleCount++; allRules.set(rule.getId()); BitSet flowRuleSet = getFlowRuleSet(rule); add(dpids, rule.dpid, flowRuleSet); add( port, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_IN_PORT) != 0 ? ANY_IN_PORT : rule.getRuleMatch().getInputPort(), flowRuleSet); short vid = rule.getRuleMatch().getDataLayerVirtualLan(); int vpcp = rule.getRuleMatch().getDataLayerVirtualLanPriorityCodePoint(); /* * Openflowj sets unspecified fields to zero. */ if (vid != 0 || vpcp != 0) { vlan_ignore.set(rule.getId()); } add( vlan, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_DL_VLAN) != 0 ? (int) ANY_VLAN_ID : (int) rule.getRuleMatch().getDataLayerVirtualLan(), flowRuleSet); add( vlan, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_DL_VLAN_PCP) != 0 ? ANY_VLAN_PCP << 16 : rule.getRuleMatch().getDataLayerVirtualLanPriorityCodePoint() << 16, flowRuleSet); add( dl_type, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_DL_TYPE) != 0 ? ANY_ETHER : rule.getRuleMatch().getDataLayerType(), flowRuleSet); add( nw, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_NW_PROTO) != 0 ? ANY_NW_PROTO_TOS : (short) rule.getRuleMatch().getNetworkProtocol(), flowRuleSet); add( nw, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_NW_TOS) != 0 ? (short) (ANY_NW_PROTO_TOS << 8) : (short) (rule.getRuleMatch().getNetworkTypeOfService() << 8), flowRuleSet); add( tp, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_TP_SRC) != 0 ? ANY_TP : (int) rule.getRuleMatch().getTransportSource(), flowRuleSet); add( tp, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_TP_DST) != 0 ? ANY_TP << 16 : rule.getRuleMatch().getTransportDestination() << 16, flowRuleSet); add( dl_src, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_DL_SRC) != 0 ? ANY_MAC : FVMatch.toLong(rule.getRuleMatch().getDataLayerSource()), flowRuleSet); add( dl_dst, (rule.getRuleMatch().getWildcards() & FVMatch.OFPFW_DL_DST) != 0 ? ANY_MAC : FVMatch.toLong(rule.getRuleMatch().getDataLayerDestination()), flowRuleSet); add(prioSet, rule.getPriority(), flowRuleSet); FVLog.log(LogLevel.DEBUG, null, "prioSet:", prioSet); rules.put(rule.getId(), rule); getPrioSetRange(); }
/* * (non-Javadoc) * * @see java.lang.Object#clone() */ @Override public FlowMap clone() { LinearFlowMap flowMap = new LinearFlowMap(); for (FlowEntry flowEntry : this.rules) flowMap.addRule(flowEntry.clone()); return flowMap; }