private void installDownstreamRules(ForwardingObjective fwd) { List<Pair<Instruction, Instruction>> vlanOps = vlanOps(fwd, L2ModificationInstruction.L2SubType.VLAN_POP); if (vlanOps == null) { return; } Instruction output = fetchOutput(fwd, "downstream"); if (output == null) { return; } Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0); TrafficSelector selector = fwd.selector(); Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID); Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID); Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT); if (outerVlan == null || innerVlan == null || inport == null) { log.error("Forwarding objective is underspecified: {}", fwd); fail(fwd, ObjectiveError.BADPARAMS); return; } Criterion innerVid = Criteria.matchVlanId(((VlanIdCriterion) innerVlan).vlanId()); FlowRule.Builder outer = DefaultFlowRule.builder() .forDevice(deviceId) .fromApp(appId) .makePermanent() .withPriority(fwd.priority()) .withSelector(buildSelector(inport, outerVlan)) .withTreatment( buildTreatment(popAndRewrite.getLeft(), Instructions.transition(QQ_TABLE))); FlowRule.Builder inner = DefaultFlowRule.builder() .forDevice(deviceId) .fromApp(appId) .forTable(QQ_TABLE) .makePermanent() .withPriority(fwd.priority()) .withSelector(buildSelector(inport, innerVid)) .withTreatment(buildTreatment(popAndRewrite.getLeft(), output)); applyRules(fwd, inner, outer); }
private void buildAndApplyRule( FilteringObjective filter, TrafficSelector selector, TrafficTreatment treatment) { FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .forTable(0) .fromApp(filter.appId()) .makePermanent() .withSelector(selector) .withTreatment(treatment) .withPriority(filter.priority()) .build(); FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder(); switch (filter.type()) { case PERMIT: opsBuilder.add(rule); break; case DENY: opsBuilder.remove(rule); break; default: log.warn("Unknown filter type : {}", filter.type()); fail(filter, ObjectiveError.UNSUPPORTED); } applyFlowRules(opsBuilder, filter); }
private void installUpstreamRules(ForwardingObjective fwd) { List<Pair<Instruction, Instruction>> vlanOps = vlanOps(fwd, L2ModificationInstruction.L2SubType.VLAN_PUSH); if (vlanOps == null) { return; } Instruction output = fetchOutput(fwd, "upstream"); if (output == null) { return; } Pair<Instruction, Instruction> innerPair = vlanOps.remove(0); Pair<Instruction, Instruction> outerPair = vlanOps.remove(0); FlowRule.Builder inner = DefaultFlowRule.builder() .forDevice(deviceId) .fromApp(appId) .makePermanent() .withPriority(fwd.priority()) .withSelector(fwd.selector()) .withTreatment(buildTreatment(innerPair.getRight(), Instructions.transition(QQ_TABLE))); PortCriterion inPort = (PortCriterion) fwd.selector().getCriterion(Criterion.Type.IN_PORT); VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) innerPair.getRight()).vlanId(); FlowRule.Builder outer = DefaultFlowRule.builder() .forDevice(deviceId) .fromApp(appId) .forTable(QQ_TABLE) .makePermanent() .withPriority(fwd.priority()) .withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId))) .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(), output)); applyRules(fwd, inner, outer); }
private void prepareInstallation() { Set<ControllerNode> instances = Sets.newHashSet(clusterService.getNodes()); instances.remove(clusterService.getLocalNode()); Set<NodeId> acceptableNodes = Sets.newHashSet(); if (neighbours >= instances.size()) { instances.forEach(instance -> acceptableNodes.add(instance.id())); } else { Iterator<ControllerNode> nodes = instances.iterator(); for (int i = neighbours; i > 0; i--) { acceptableNodes.add(nodes.next().id()); } } acceptableNodes.add(clusterService.getLocalNode().id()); Set<Device> devices = Sets.newHashSet(); for (Device dev : deviceService.getDevices()) { if (acceptableNodes.contains(mastershipService.getMasterFor(dev.id()))) { devices.add(dev); } } TrafficTreatment treatment = DefaultTrafficTreatment.builder() .setOutput(PortNumber.portNumber(RandomUtils.nextInt())) .build(); TrafficSelector.Builder sbuilder; FlowRuleOperations.Builder rules = FlowRuleOperations.builder(); FlowRuleOperations.Builder remove = FlowRuleOperations.builder(); for (Device d : devices) { for (int i = 0; i < this.flowPerDevice; i++) { sbuilder = DefaultTrafficSelector.builder(); sbuilder .matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i)) .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt())); int randomPriority = RandomUtils.nextInt(); FlowRule f = DefaultFlowRule.builder() .forDevice(d.id()) .withSelector(sbuilder.build()) .withTreatment(treatment) .withPriority(randomPriority) .fromApp(appId) .makeTemporary(10) .build(); rules.add(f); remove.remove(f); } } this.adds = rules; this.removes = remove; }
/** * Ensures packet is of required type. Obtain the PortNumber associated with the inPackets * DeviceId. If this port has previously been learned (in initMacTable method) build a flow * using the packet's out port, treatment, destination, and other properties. Send the flow to * the learned out port. Otherwise, flood packet to all ports if out port is not learned. * * @param pc the PacketContext object passed through from activate() method */ public void actLikeSwitch(PacketContext pc) { /* * Ensures the type of packet being processed is only of type IPV4 (not LLDP or BDDP). If it is not, return * and do nothing with the packet. actLikeSwitch can only process IPV4 packets. */ Short type = pc.inPacket().parsed().getEtherType(); if (type != Ethernet.TYPE_IPV4) { return; } /* * Learn the destination, source, and output port of the packet using a ConnectPoint and the * associated macTable. If there is a known port associated with the packet's destination MAC Address, * the output port will not be null. */ ConnectPoint cp = pc.inPacket().receivedFrom(); Map<MacAddress, PortNumber> macTable = macTables.get(cp.deviceId()); MacAddress srcMac = pc.inPacket().parsed().getSourceMAC(); MacAddress dstMac = pc.inPacket().parsed().getDestinationMAC(); macTable.put(srcMac, cp.port()); PortNumber outPort = macTable.get(dstMac); /* * If port is known, set pc's out port to the packet's learned output port and construct a * FlowRule using a source, destination, treatment and other properties. Send the FlowRule * to the designated output port. */ if (outPort != null) { pc.treatmentBuilder().setOutput(outPort); FlowRule fr = DefaultFlowRule.builder() .withSelector(DefaultTrafficSelector.builder().matchEthDst(dstMac).build()) .withTreatment(DefaultTrafficTreatment.builder().setOutput(outPort).build()) .forDevice(cp.deviceId()) .withPriority(PacketPriority.REACTIVE.priorityValue()) .makeTemporary(60) .fromApp(appId) .build(); flowRuleService.applyFlowRules(fr); pc.send(); } else { /* * else, the output port has not been learned yet. Flood the packet to all ports using * the actLikeHub method */ actLikeHub(pc); } }
private void processMulticastRule(ForwardingObjective fwd) { if (fwd.nextId() == null) { log.error("Multicast objective does not have a next id"); fail(fwd, ObjectiveError.BADPARAMS); } OLTPipelineGroup next = getGroupForNextObjective(fwd.nextId()); if (next == null) { log.error("Group for forwarding objective missing: {}", fwd); fail(fwd, ObjectiveError.GROUPMISSING); } Group group = groupService.getGroup(deviceId, next.key()); TrafficTreatment treatment = buildTreatment(Instructions.createGroup(group.id())); FlowRule rule = DefaultFlowRule.builder() .forDevice(deviceId) .forTable(0) .fromApp(fwd.appId()) .makePermanent() .withPriority(fwd.priority()) .withSelector(fwd.selector()) .withTreatment(treatment) .build(); FlowRuleOperations.Builder builder = FlowRuleOperations.builder(); switch (fwd.op()) { case ADD: builder.add(rule); break; case REMOVE: builder.remove(rule); break; case ADD_TO_EXISTING: case REMOVE_FROM_EXISTING: break; default: log.warn("Unknown forwarding operation: {}", fwd.op()); } applyFlowRules(builder, fwd); }
@Override // Dell switches need ETH_DST based match condition in all IP table entries. // So this method overrides the default spring-open behavior and adds // ETH_DST match condition while pushing IP table flow rules protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) { log.debug("Processing specific"); TrafficSelector selector = fwd.selector(); EthTypeCriterion ethType = (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); if ((ethType == null) || ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) && (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) { log.debug("processSpecific: Unsupported " + "forwarding objective criteraia"); fail(fwd, ObjectiveError.UNSUPPORTED); return Collections.emptySet(); } TrafficSelector.Builder filteredSelectorBuilder = DefaultTrafficSelector.builder(); int forTableId = -1; if (((short) ethType.ethType()) == Ethernet.TYPE_IPV4) { if (deviceTMac == null) { log.debug( "processSpecific: ETH_DST filtering " + "objective is not set which is required " + "before sending a IPv4 forwarding objective"); // TODO: Map the error to more appropriate error code. fail(fwd, ObjectiveError.DEVICEMISSING); return Collections.emptySet(); } filteredSelectorBuilder = filteredSelectorBuilder .matchEthType(Ethernet.TYPE_IPV4) .matchEthDst(deviceTMac) .matchIPDst(((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip()); forTableId = ipv4UnicastTableId; log.debug("processing IPv4 specific forwarding objective"); } else { filteredSelectorBuilder = filteredSelectorBuilder .matchEthType(Ethernet.MPLS_UNICAST) .matchMplsLabel( ((MplsCriterion) selector.getCriterion(Criterion.Type.MPLS_LABEL)).label()); // TODO: Add Match for BoS // if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) { // } forTableId = mplsTableId; log.debug("processing MPLS specific forwarding objective"); } TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); if (fwd.treatment() != null) { for (Instruction i : fwd.treatment().allInstructions()) { treatmentBuilder.add(i); } } if (fwd.nextId() != null) { NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); if (next != null) { GroupKey key = appKryo.deserialize(next.data()); Group group = groupService.getGroup(deviceId, key); if (group == null) { log.warn("The group left!"); fail(fwd, ObjectiveError.GROUPMISSING); return Collections.emptySet(); } treatmentBuilder.group(group.id()); log.debug("Adding OUTGROUP action"); } else { log.warn("processSpecific: No associated next objective object"); fail(fwd, ObjectiveError.GROUPMISSING); return Collections.emptySet(); } } TrafficSelector filteredSelector = filteredSelectorBuilder.build(); TrafficTreatment treatment = treatmentBuilder.transition(aclTableId).build(); FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() .fromApp(fwd.appId()) .withPriority(fwd.priority()) .forDevice(deviceId) .withSelector(filteredSelector) .withTreatment(treatment); if (fwd.permanent()) { ruleBuilder.makePermanent(); } else { ruleBuilder.makeTemporary(fwd.timeout()); } ruleBuilder.forTable(forTableId); return Collections.singletonList(ruleBuilder.build()); }