/** * Step through all of the partially computed results, compute the intersections and remove the * intersections by priority. * * <p>Could be O(n^2) in worst case, but we expect that intersections are rare (?) * * <p>Uses the fact that the order of the list is also the priority order * * <p>FIXME :: come back and make this faster * * @param mergeList List of all FlowEntry's from matches(), including overlaps. * @return A pruned list of just the non-completely-overlapping matches */ List<FlowIntersect> priorityMerge(List<FlowIntersect> mergeList) { List<FlowIntersect> results = new ArrayList<FlowIntersect>(); boolean eclipsed; MatchType matchType; results.add(mergeList.get(0)); mergeList.remove(0); for (FlowIntersect merge : mergeList) { eclipsed = false; for (FlowIntersect result : results) { /* * is this new match eclipsed by previous entries? * * with each successive matches() call, the part that over laps * result is removed, so that if a merge rule is not fully * eclipsed by any one result, but is fully eclipsed by a sum of * results, we will catch that to */ FlowIntersect tmpIntersect = merge.getFlowEntry().matches(result.getDpid(), result.getMatch()); matchType = tmpIntersect.getMatchType(); if ((matchType == MatchType.EQUAL) || (matchType == MatchType.SUPERSET)) { eclipsed = true; break; } else if (matchType == MatchType.SUBSET) { merge = tmpIntersect; // then update with the intersection } // note: if matchtype == NONE, then tmpIntersect.getMatch() is // undefined } if (!eclipsed) // add this match to the list iff it's results.add(merge); // not complete eclipsed by something before // it } return results; }
/** * 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); }