private void sendPacketOut(ConnectPoint outport, Ethernet payload, int sid) { IPv4 ipPacket = (IPv4) payload.getPayload(); Ip4Address destIpAddress = Ip4Address.valueOf(ipPacket.getDestinationAddress()); if (sid == -1 || config.getSegmentId(payload.getDestinationMAC()) == sid || config.inSameSubnet(outport.deviceId(), destIpAddress)) { TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(outport.port()).build(); OutboundPacket packet = new DefaultOutboundPacket( outport.deviceId(), treatment, ByteBuffer.wrap(payload.serialize())); srManager.packetService.emit(packet); } else { log.info("Send a MPLS packet as a ICMP response"); TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(outport.port()).build(); payload.setEtherType(Ethernet.MPLS_UNICAST); MPLS mplsPkt = new MPLS(); mplsPkt.setLabel(sid); mplsPkt.setTtl(((IPv4) payload.getPayload()).getTtl()); mplsPkt.setPayload(payload.getPayload()); payload.setPayload(mplsPkt); OutboundPacket packet = new DefaultOutboundPacket( outport.deviceId(), treatment, ByteBuffer.wrap(payload.serialize())); srManager.packetService.emit(packet); } }
private void sendArpResponse(ARP arpRequest, MacAddress targetMac, VlanId vlanId) { ARP arpReply = new ARP(); arpReply .setHardwareType(ARP.HW_TYPE_ETHERNET) .setProtocolType(ARP.PROTO_TYPE_IP) .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH) .setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH) .setOpCode(ARP.OP_REPLY) .setSenderHardwareAddress(targetMac.toBytes()) .setSenderProtocolAddress(arpRequest.getTargetProtocolAddress()) .setTargetHardwareAddress(arpRequest.getSenderHardwareAddress()) .setTargetProtocolAddress(arpRequest.getSenderProtocolAddress()); Ethernet eth = new Ethernet(); eth.setDestinationMACAddress(arpRequest.getSenderHardwareAddress()) .setSourceMACAddress(targetMac.toBytes()) .setEtherType(Ethernet.TYPE_ARP) .setPayload(arpReply); MacAddress hostMac = MacAddress.valueOf(arpReply.getTargetHardwareAddress()); HostId dstId = HostId.hostId(hostMac, vlanId); Host dst = srManager.hostService.getHost(dstId); if (dst == null) { log.warn("Cannot send ARP response to host {}", dstId); return; } TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(dst.location().port()).build(); OutboundPacket packet = new DefaultOutboundPacket( dst.location().deviceId(), treatment, ByteBuffer.wrap(eth.serialize())); srManager.packetService.emit(packet); }
private static TrafficTreatment treatment(Instruction... insts) { TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); for (Instruction i : insts) { builder.add(i); } return builder.build(); }
private void sendArpNdpProbe( ConnectPoint connectPoint, IpAddress targetIp, IpAddress sourceIp, MacAddress sourceMac, VlanId vlan) { Ethernet probePacket = null; if (targetIp.isIp4()) { // IPv4: Use ARP probePacket = buildArpRequest(targetIp, sourceIp, sourceMac, vlan); } else { // IPv6: Use Neighbor Discovery probePacket = buildNdpRequest(targetIp, sourceIp, sourceMac, vlan); } List<Instruction> instructions = new ArrayList<>(); instructions.add(Instructions.createOutput(connectPoint.port())); TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build(); OutboundPacket outboundPacket = new DefaultOutboundPacket( connectPoint.deviceId(), treatment, ByteBuffer.wrap(probePacket.serialize())); packetService.emit(outboundPacket); }
private void populateRoutingRulestoDifferentNode( Ip4Address vmIp, long vni, DeviceId deviceId, Ip4Address hostIp, String cidr) { TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); sBuilder .matchEthType(Ethernet.TYPE_IPV4) .matchTunnelId(vni) .matchIPSrc(IpPrefix.valueOf(cidr)) .matchIPDst(vmIp.toIpPrefix()); tBuilder .extension(buildExtension(deviceService, deviceId, hostIp), deviceId) .setOutput(nodeService.tunnelPort(deviceId).get()); ForwardingObjective fo = DefaultForwardingObjective.builder() .withSelector(sBuilder.build()) .withTreatment(tBuilder.build()) .withPriority(EW_ROUTING_RULE_PRIORITY) .withFlag(ForwardingObjective.Flag.SPECIFIC) .fromApp(appId) .add(); flowObjectiveService.forward(deviceId, fo); }
private void populateRoutingRulestoSameNode( Ip4Address vmIp, MacAddress vmMac, PortNumber port, DeviceId deviceId, long vni, String cidr) { TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); // FIXME: we need to check the VNI of the dest IP also just in case... sBuilder .matchEthType(Ethernet.TYPE_IPV4) .matchIPDst(vmIp.toIpPrefix()) .matchIPSrc(IpPrefix.valueOf(cidr)) .matchTunnelId(vni); tBuilder.setEthDst(vmMac).setOutput(port); ForwardingObjective fo = DefaultForwardingObjective.builder() .withSelector(sBuilder.build()) .withTreatment(tBuilder.build()) .withPriority(EW_ROUTING_RULE_PRIORITY) .withFlag(ForwardingObjective.Flag.SPECIFIC) .fromApp(appId) .add(); flowObjectiveService.forward(deviceId, fo); }
// Test Group creation before AUDIT process private void testGroupCreationBeforeAudit(DeviceId deviceId) { PortNumber[] ports1 = {PortNumber.portNumber(31), PortNumber.portNumber(32)}; PortNumber[] ports2 = {PortNumber.portNumber(41), PortNumber.portNumber(42)}; GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes()); List<GroupBucket> buckets = new ArrayList<>(); List<PortNumber> outPorts = new ArrayList<>(); outPorts.addAll(Arrays.asList(ports1)); outPorts.addAll(Arrays.asList(ports2)); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupBuckets = new GroupBuckets(buckets); GroupDescription newGroupDesc = new DefaultGroupDescription(deviceId, Group.Type.SELECT, groupBuckets, key, null, appId); groupService.addGroup(newGroupDesc); assertEquals(null, groupService.getGroup(deviceId, key)); assertEquals(0, Iterables.size(groupService.getGroups(deviceId, appId))); }
private void send(Ethernet eth, ConnectPoint cp) { OutboundPacket packet = new DefaultOutboundPacket( cp.deviceId(), DefaultTrafficTreatment.builder().setOutput(cp.port()).build(), ByteBuffer.wrap(eth.serialize())); packetService.emit(packet); }
/** * Remove VLAN tag and packet out to given port. * * <p>Note: In current implementation, we expect all communication with end hosts within a subnet * to be untagged. * * <p>For those pipelines that internally assigns a VLAN, the VLAN tag will be removed before * egress. * * <p>For those pipelines that do not assign internal VLAN, the packet remains untagged. * * @param packet packet to be forwarded * @param outPort where the packet should be forwarded */ private void removeVlanAndForward(Ethernet packet, ConnectPoint outPort) { packet.setEtherType(Ethernet.TYPE_ARP); packet.setVlanID(Ethernet.VLAN_UNTAGGED); ByteBuffer buf = ByteBuffer.wrap(packet.serialize()); TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); tbuilder.setOutput(outPort.port()); srManager.packetService.emit( new DefaultOutboundPacket(outPort.deviceId(), tbuilder.build(), buf)); }
private TrafficTreatment buildTreatment(Instruction... instructions) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); for (Instruction i : instructions) { tBuilder.add(i); } return tBuilder.build(); }
/** * Constructs a BGP intent and put it into the intentList. * * <p>The purpose of this method is too simplify the setUpBgpIntents() method, and to make the * setUpBgpIntents() easy to read. * * @param srcVlanId ingress VlanId * @param dstVlanId egress VlanId * @param srcPrefix source IP prefix to match * @param dstPrefix destination IP prefix to match * @param srcTcpPort source TCP port to match * @param dstTcpPort destination TCP port to match * @param srcConnectPoint source connect point for PointToPointIntent * @param dstConnectPoint destination connect point for PointToPointIntent */ private void bgpPathintentConstructor( VlanId srcVlanId, VlanId dstVlanId, String srcPrefix, String dstPrefix, Short srcTcpPort, Short dstTcpPort, ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) { TrafficSelector.Builder builder = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_IPV4) .matchIPProtocol(IPv4.PROTOCOL_TCP) .matchIPSrc(IpPrefix.valueOf(srcPrefix)) .matchIPDst(IpPrefix.valueOf(dstPrefix)); if (!srcVlanId.equals(VlanId.NONE)) { builder.matchVlanId(srcVlanId); } TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); if (!dstVlanId.equals(VlanId.NONE)) { treatment.setVlanId(dstVlanId); } if (srcTcpPort != null) { builder.matchTcpSrc(TpPort.tpPort(srcTcpPort)); } if (dstTcpPort != null) { builder.matchTcpDst(TpPort.tpPort(dstTcpPort)); } Key key = Key.of( srcPrefix.split("/")[0] + "-" + dstPrefix.split("/")[0] + "-" + ((srcTcpPort == null) ? "dst" : "src"), APPID); PointToPointIntent intent = PointToPointIntent.builder() .appId(APPID) .key(key) .selector(builder.build()) .treatment(treatment.build()) .ingressPoint(srcConnectPoint) .egressPoint(dstConnectPoint) .build(); intentList.add(intent); }
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; }
/** Tests the encoding of an intent with treatment, selector and constraints specified. */ @Test public void intentWithTreatmentSelectorAndConstraints() { ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); ConnectPoint egress = NetTestTools.connectPoint("egress", 2); DeviceId did1 = did("device1"); DeviceId did2 = did("device2"); DeviceId did3 = did("device3"); Lambda ochSignal = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8); final TrafficSelector selector = DefaultTrafficSelector.builder() .matchIPProtocol((byte) 3) .matchMplsLabel(MplsLabel.mplsLabel(4)) .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID)) .add(Criteria.matchLambda(ochSignal)) .matchEthDst(MacAddress.BROADCAST) .matchIPDst(IpPrefix.valueOf("1.2.3.4/24")) .build(); final TrafficTreatment treatment = DefaultTrafficTreatment.builder() .add(Instructions.modL0Lambda(new IndexedLambda(33))) .setMpls(MplsLabel.mplsLabel(44)) .setOutput(PortNumber.CONTROLLER) .setEthDst(MacAddress.BROADCAST) .build(); final List<Constraint> constraints = ImmutableList.of( new BandwidthConstraint(Bandwidth.bps(1.0)), new LambdaConstraint(new IndexedLambda(3)), new AnnotationConstraint("key", 33.0), new AsymmetricPathConstraint(), new LatencyConstraint(Duration.ofSeconds(2)), new ObstacleConstraint(did1, did2), new WaypointConstraint(did3)); final PointToPointIntent intent = PointToPointIntent.builder() .appId(appId) .selector(selector) .treatment(treatment) .ingressPoint(ingress) .egressPoint(egress) .constraints(constraints) .build(); final JsonCodec<PointToPointIntent> intentCodec = context.codec(PointToPointIntent.class); assertThat(intentCodec, notNullValue()); final ObjectNode intentJson = intentCodec.encode(intent, context); assertThat(intentJson, matchesIntent(intent)); }
/** * 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); } }
/** Simple class representing a pair of hosts and precomputes the associated h2h intent. */ private class HostPair { private final Host src; private final Host dst; private final TrafficSelector selector = DefaultTrafficSelector.emptySelector(); private final TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); private final List<Constraint> constraint = Lists.newArrayList(); private final HostToHostIntent intent; public HostPair(Host src, Host dst) { this.src = src; this.dst = dst; this.intent = HostToHostIntent.builder() .appId(appId) .one(src.id()) .two(dst.id()) .selector(selector) .treatment(treatment) .constraints(constraint) .build(); } public HostToHostIntent h2hIntent() { return intent; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } HostPair hostPair = (HostPair) o; return Objects.equals(src, hostPair.src) && Objects.equals(dst, hostPair.dst); } @Override public int hashCode() { return Objects.hash(src, dst); } }
// Test group add bucket operations private void testAddBuckets(DeviceId deviceId) { GroupKey addKey = new DefaultGroupKey("group1AddBuckets".getBytes()); GroupKey prevKey = new DefaultGroupKey("group1BeforeAudit".getBytes()); Group createdGroup = groupService.getGroup(deviceId, prevKey); List<GroupBucket> buckets = new ArrayList<>(); buckets.addAll(createdGroup.buckets().buckets()); PortNumber[] addPorts = {PortNumber.portNumber(51), PortNumber.portNumber(52)}; List<PortNumber> outPorts; outPorts = new ArrayList<>(); outPorts.addAll(Arrays.asList(addPorts)); List<GroupBucket> addBuckets; addBuckets = new ArrayList<>(); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets); groupService.addBucketsToGroup(deviceId, prevKey, groupAddBuckets, addKey, appId); GroupBuckets updatedBuckets = new GroupBuckets(buckets); List<GroupOperation> expectedGroupOps = Collections.singletonList( GroupOperation.createModifyGroupOperation( createdGroup.id(), Group.Type.SELECT, updatedBuckets)); if (deviceId.equals(DID)) { internalProvider.validate(deviceId, expectedGroupOps); } else { this.validate(deviceId, expectedGroupOps); } Group existingGroup = groupService.getGroup(deviceId, addKey); List<Group> groupEntries = Collections.singletonList(existingGroup); providerService.pushGroupMetrics(deviceId, groupEntries); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATED)); }
private Group createSouthboundGroupEntry( GroupId gId, List<PortNumber> ports, long referenceCount, DeviceId deviceId) { List<PortNumber> outPorts = new ArrayList<>(); outPorts.addAll(ports); List<GroupBucket> buckets = new ArrayList<>(); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupBuckets = new GroupBuckets(buckets); StoredGroupEntry group = new DefaultGroup(gId, deviceId, Group.Type.SELECT, groupBuckets); group.setReferenceCount(referenceCount); return group; }
private void populateRuleToGateway(DeviceId deviceId, GroupId groupId, long vni, String cidr) { TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); sBuilder .matchEthType(Ethernet.TYPE_IPV4) .matchTunnelId(vni) .matchIPSrc(IpPrefix.valueOf(cidr)) .matchEthDst(Constants.DEFAULT_GATEWAY_MAC); tBuilder.group(groupId); ForwardingObjective fo = DefaultForwardingObjective.builder() .withSelector(sBuilder.build()) .withTreatment(tBuilder.build()) .withFlag(ForwardingObjective.Flag.SPECIFIC) .withPriority(ROUTING_RULE_PRIORITY) .fromApp(appId) .add(); flowObjectiveService.forward(deviceId, fo); }
private void populateGatewayIcmpRule(Ip4Address gatewayIp, DeviceId deviceId) { TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); sBuilder .matchEthType(Ethernet.TYPE_IPV4) .matchIPProtocol(IPv4.PROTOCOL_ICMP) .matchIPDst(gatewayIp.toIpPrefix()); tBuilder.setOutput(PortNumber.CONTROLLER); ForwardingObjective fo = DefaultForwardingObjective.builder() .withSelector(sBuilder.build()) .withTreatment(tBuilder.build()) .withPriority(GATEWAY_ICMP_PRIORITY) .withFlag(ForwardingObjective.Flag.VERSATILE) .fromApp(appId) .add(); flowObjectiveService.forward(deviceId, fo); }
@Override public void run() { TrafficSelector selector = DefaultTrafficSelector.emptySelector(); TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); List<Constraint> constraint = Lists.newArrayList(); List<Host> hosts = Lists.newArrayList(hostService.getHosts()); while (!hosts.isEmpty()) { Host src = hosts.remove(0); for (Host dst : hosts) { HostToHostIntent intent = HostToHostIntent.builder() .appId(appId) .one(src.id()) .two(dst.id()) .selector(selector) .treatment(treatment) .constraints(constraint) .build(); existingIntents.add(intent); intentService.submit(intent); } } }
/** * Builds a Multi Point to Single Point intent. * * @param key The intent key * @param srcs The source Connect Points * @param dst The destination Connect Point * @return Multi Point to Single Point intent generated. */ private MultiPointToSinglePointIntent buildUniIntent( Key key, Set<ConnectPoint> srcs, ConnectPoint dst, VlanId vlanId, MacAddress mac) { MultiPointToSinglePointIntent intent; TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); TrafficSelector.Builder builder = DefaultTrafficSelector.builder().matchEthDst(mac).matchVlanId(vlanId); TrafficSelector selector = builder.build(); intent = MultiPointToSinglePointIntent.builder() .appId(APPID) .key(key) .selector(selector) .treatment(treatment) .ingressPoints(srcs) .egressPoint(dst) .priority(PRIORITY_OFFSET) .build(); return intent; }
private void populateGatewayToController(long vni, String subNetCidr) { TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder(); TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); sBuilder .matchEthType(Ethernet.TYPE_IPV4) .matchTunnelId(vni) .matchIPSrc(IpPrefix.valueOf(subNetCidr)) .matchEthDst(Constants.DEFAULT_GATEWAY_MAC); tBuilder.setOutput(PortNumber.CONTROLLER); ForwardingObjective fo = DefaultForwardingObjective.builder() .withSelector(sBuilder.build()) .withTreatment(tBuilder.build()) .withFlag(ForwardingObjective.Flag.VERSATILE) .withPriority(ROUTING_RULE_PRIORITY) .fromApp(appId) .add(); gatewayService .getGatewayDeviceIds() .forEach(deviceId -> flowObjectiveService.forward(deviceId, fo)); }
/** * Builds a Single Point to Multi Point intent. * * @param key The intent key * @param src The source Connect Point * @param dsts The destination Connect Points * @return Single Point to Multi Point intent generated. */ private SinglePointToMultiPointIntent buildBrcIntent( Key key, ConnectPoint src, Set<ConnectPoint> dsts, VlanId vlanId) { SinglePointToMultiPointIntent intent; TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); TrafficSelector selector = DefaultTrafficSelector.builder() .matchEthDst(MacAddress.BROADCAST) .matchVlanId(vlanId) .build(); intent = SinglePointToMultiPointIntent.builder() .appId(APPID) .key(key) .selector(selector) .treatment(treatment) .ingressPoint(src) .egressPoints(dsts) .priority(PRIORITY_OFFSET) .build(); return intent; }
@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()); }
private void groupOperationFaliure(DeviceId deviceId) { PortNumber[] ports1 = {PortNumber.portNumber(31), PortNumber.portNumber(32)}; PortNumber[] ports2 = {PortNumber.portNumber(41), PortNumber.portNumber(42)}; // Test Group creation before AUDIT process GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes()); List<GroupBucket> buckets = new ArrayList<>(); List<PortNumber> outPorts = new ArrayList<>(); outPorts.addAll(Arrays.asList(ports1)); outPorts.addAll(Arrays.asList(ports2)); for (PortNumber portNumber : outPorts) { TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); tBuilder .setOutput(portNumber) .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) .pushMpls() .setMpls(MplsLabel.mplsLabel(106)); buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); } GroupBuckets groupBuckets = new GroupBuckets(buckets); GroupDescription newGroupDesc = new DefaultGroupDescription(deviceId, Group.Type.SELECT, groupBuckets, key, null, appId); groupService.addGroup(newGroupDesc); // Test initial group audit process GroupId gId1 = new DefaultGroupId(1); Group group1 = createSouthboundGroupEntry(gId1, Arrays.asList(ports1), 0, deviceId); GroupId gId2 = new DefaultGroupId(2); // Non zero reference count will make the group manager to queue // the extraneous groups until reference count is zero. Group group2 = createSouthboundGroupEntry(gId2, Arrays.asList(ports2), 2, deviceId); List<Group> groupEntries = Arrays.asList(group1, group2); providerService.pushGroupMetrics(deviceId, groupEntries); Group createdGroup = groupService.getGroup(deviceId, key); // Group Add failure test GroupOperation groupAddOp = GroupOperation.createAddGroupOperation( createdGroup.id(), createdGroup.type(), createdGroup.buckets()); providerService.groupOperationFailed(deviceId, groupAddOp); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_ADD_FAILED)); // Group Mod failure test groupService.addGroup(newGroupDesc); createdGroup = groupService.getGroup(deviceId, key); assertNotNull(createdGroup); GroupOperation groupModOp = GroupOperation.createModifyGroupOperation( createdGroup.id(), createdGroup.type(), createdGroup.buckets()); providerService.groupOperationFailed(deviceId, groupModOp); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_UPDATE_FAILED)); // Group Delete failure test groupService.addGroup(newGroupDesc); createdGroup = groupService.getGroup(deviceId, key); assertNotNull(createdGroup); GroupOperation groupDelOp = GroupOperation.createDeleteGroupOperation(createdGroup.id(), createdGroup.type()); providerService.groupOperationFailed(deviceId, groupDelOp); internalListener.validateEvent(Collections.singletonList(GroupEvent.Type.GROUP_REMOVE_FAILED)); }
/** * Generates a route intent for a prefix, the next hop IP address, and the next hop MAC address. * * <p>This method will find the egress interface for the intent. Intent will match dst IP prefix * and rewrite dst MAC address at all other border switches, then forward packets according to dst * MAC address. * * @param prefix IP prefix of the route to add * @param nextHopIpAddress IP address of the next hop * @param nextHopMacAddress MAC address of the next hop * @return the generated intent, or null if no intent should be submitted */ private MultiPointToSinglePointIntent generateRouteIntent( IpPrefix prefix, IpAddress nextHopIpAddress, MacAddress nextHopMacAddress) { // Find the attachment point (egress interface) of the next hop Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress); if (egressInterface == null) { log.warn("No outgoing interface found for {}", nextHopIpAddress); return null; } // Generate the intent itself Set<ConnectPoint> ingressPorts = new HashSet<>(); ConnectPoint egressPort = egressInterface.connectPoint(); log.debug("Generating intent for prefix {}, next hop mac {}", prefix, nextHopMacAddress); for (Interface intf : interfaceService.getInterfaces()) { // TODO this should be only peering interfaces if (!intf.connectPoint().equals(egressInterface.connectPoint())) { ConnectPoint srcPort = intf.connectPoint(); ingressPorts.add(srcPort); } } // Match the destination IP prefix at the first hop TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); if (prefix.isIp4()) { selector.matchEthType(Ethernet.TYPE_IPV4); // if it is default route, then we do not need match destination // IP address if (prefix.prefixLength() != 0) { selector.matchIPDst(prefix); } } else { selector.matchEthType(Ethernet.TYPE_IPV6); // if it is default route, then we do not need match destination // IP address if (prefix.prefixLength() != 0) { selector.matchIPv6Dst(prefix); } } // Rewrite the destination MAC address TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder().setEthDst(nextHopMacAddress); if (!egressInterface.vlan().equals(VlanId.NONE)) { treatment.setVlanId(egressInterface.vlan()); // If we set VLAN ID, we have to make sure a VLAN tag exists. // TODO support no VLAN -> VLAN routing selector.matchVlanId(VlanId.ANY); } int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET; Key key = Key.of(prefix.toString(), appId); return MultiPointToSinglePointIntent.builder() .appId(appId) .key(key) .selector(selector.build()) .treatment(treatment.build()) .ingressPoints(ingressPorts) .egressPoint(egressPort) .priority(priority) .constraints(CONSTRAINTS) .build(); }
// Install a rule forwarding the packet to the specified port. private void installRule(PacketContext context, PortNumber portNumber) { // // We don't support (yet) buffer IDs in the Flow Service so // packet out first. // Ethernet inPkt = context.inPacket().parsed(); TrafficSelector.Builder selectorBuilder = DefaultTrafficSelector.builder(); // If PacketOutOnly or ARP packet than forward directly to output port if (packetOutOnly || inPkt.getEtherType() == Ethernet.TYPE_ARP) { packetOut(context, portNumber); return; } // // If matchDstMacOnly // Create flows matching dstMac only // Else // Create flows with default matching and include configured fields // if (matchDstMacOnly) { selectorBuilder.matchEthDst(inPkt.getDestinationMAC()); } else { selectorBuilder .matchInPort(context.inPacket().receivedFrom().port()) .matchEthSrc(inPkt.getSourceMAC()) .matchEthDst(inPkt.getDestinationMAC()); // If configured Match Vlan ID if (matchVlanId && inPkt.getVlanID() != Ethernet.VLAN_UNTAGGED) { selectorBuilder.matchVlanId(VlanId.vlanId(inPkt.getVlanID())); } // // If configured and EtherType is IPv4 - Match IPv4 and // TCP/UDP/ICMP fields // if (matchIpv4Address && inPkt.getEtherType() == Ethernet.TYPE_IPV4) { IPv4 ipv4Packet = (IPv4) inPkt.getPayload(); byte ipv4Protocol = ipv4Packet.getProtocol(); Ip4Prefix matchIp4SrcPrefix = Ip4Prefix.valueOf(ipv4Packet.getSourceAddress(), Ip4Prefix.MAX_MASK_LENGTH); Ip4Prefix matchIp4DstPrefix = Ip4Prefix.valueOf(ipv4Packet.getDestinationAddress(), Ip4Prefix.MAX_MASK_LENGTH); selectorBuilder .matchEthType(Ethernet.TYPE_IPV4) .matchIPSrc(matchIp4SrcPrefix) .matchIPDst(matchIp4DstPrefix); if (matchIpv4Dscp) { byte dscp = ipv4Packet.getDscp(); byte ecn = ipv4Packet.getEcn(); selectorBuilder.matchIPDscp(dscp).matchIPEcn(ecn); } if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_TCP) { TCP tcpPacket = (TCP) ipv4Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv4Protocol) .matchTcpSrc(tcpPacket.getSourcePort()) .matchTcpDst(tcpPacket.getDestinationPort()); } if (matchTcpUdpPorts && ipv4Protocol == IPv4.PROTOCOL_UDP) { UDP udpPacket = (UDP) ipv4Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv4Protocol) .matchUdpSrc(udpPacket.getSourcePort()) .matchUdpDst(udpPacket.getDestinationPort()); } if (matchIcmpFields && ipv4Protocol == IPv4.PROTOCOL_ICMP) { ICMP icmpPacket = (ICMP) ipv4Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv4Protocol) .matchIcmpType(icmpPacket.getIcmpType()) .matchIcmpCode(icmpPacket.getIcmpCode()); } } // // If configured and EtherType is IPv6 - Match IPv6 and // TCP/UDP/ICMP fields // if (matchIpv6Address && inPkt.getEtherType() == Ethernet.TYPE_IPV6) { IPv6 ipv6Packet = (IPv6) inPkt.getPayload(); byte ipv6NextHeader = ipv6Packet.getNextHeader(); Ip6Prefix matchIp6SrcPrefix = Ip6Prefix.valueOf(ipv6Packet.getSourceAddress(), Ip6Prefix.MAX_MASK_LENGTH); Ip6Prefix matchIp6DstPrefix = Ip6Prefix.valueOf(ipv6Packet.getDestinationAddress(), Ip6Prefix.MAX_MASK_LENGTH); selectorBuilder .matchEthType(Ethernet.TYPE_IPV6) .matchIPv6Src(matchIp6SrcPrefix) .matchIPv6Dst(matchIp6DstPrefix); if (matchIpv6FlowLabel) { selectorBuilder.matchIPv6FlowLabel(ipv6Packet.getFlowLabel()); } if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_TCP) { TCP tcpPacket = (TCP) ipv6Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv6NextHeader) .matchTcpSrc(tcpPacket.getSourcePort()) .matchTcpDst(tcpPacket.getDestinationPort()); } if (matchTcpUdpPorts && ipv6NextHeader == IPv6.PROTOCOL_UDP) { UDP udpPacket = (UDP) ipv6Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv6NextHeader) .matchUdpSrc(udpPacket.getSourcePort()) .matchUdpDst(udpPacket.getDestinationPort()); } if (matchIcmpFields && ipv6NextHeader == IPv6.PROTOCOL_ICMP6) { ICMP6 icmp6Packet = (ICMP6) ipv6Packet.getPayload(); selectorBuilder .matchIPProtocol(ipv6NextHeader) .matchIcmpv6Type(icmp6Packet.getIcmpType()) .matchIcmpv6Code(icmp6Packet.getIcmpCode()); } } } TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(portNumber).build(); ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder() .withSelector(selectorBuilder.build()) .withTreatment(treatment) .withPriority(flowPriority) .withFlag(ForwardingObjective.Flag.VERSATILE) .fromApp(appId) .makeTemporary(flowTimeout) .add(); flowObjectiveService.forward(context.inPacket().receivedFrom().deviceId(), forwardingObjective); // // If packetOutOfppTable // Send packet back to the OpenFlow pipeline to match installed flow // Else // Send packet direction on the appropriate port // if (packetOutOfppTable) { packetOut(context, PortNumber.TABLE); } else { packetOut(context, portNumber); } }
/** Unit tests for the host to host intent class codec. */ public class IntentCodecTest extends AbstractIntentTest { private final HostId id1 = hid("12:34:56:78:91:ab/1"); private final HostId id2 = hid("12:34:56:78:92:ab/1"); private final ApplicationId appId = new DefaultApplicationId(3, "test"); final TrafficSelector emptySelector = DefaultTrafficSelector.emptySelector(); final TrafficTreatment emptyTreatment = DefaultTrafficTreatment.emptyTreatment(); private final MockCodecContext context = new MockCodecContext(); final CoreService mockCoreService = createMock(CoreService.class); @Before public void setUpIntentService() { final IntentService mockIntentService = new IntentServiceAdapter(); context.registerService(IntentService.class, mockIntentService); context.registerService(CoreService.class, mockCoreService); expect(mockCoreService.getAppId(appId.name())).andReturn(appId); replay(mockCoreService); } /** Tests the encoding of a host to host intent. */ @Test public void hostToHostIntent() { final HostToHostIntent intent = HostToHostIntent.builder().appId(appId).one(id1).two(id2).build(); final JsonCodec<HostToHostIntent> intentCodec = context.codec(HostToHostIntent.class); assertThat(intentCodec, notNullValue()); final ObjectNode intentJson = intentCodec.encode(intent, context); assertThat(intentJson, matchesIntent(intent)); } /** Tests the encoding of a point to point intent. */ @Test public void pointToPointIntent() { ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); ConnectPoint egress = NetTestTools.connectPoint("egress", 2); final PointToPointIntent intent = PointToPointIntent.builder() .appId(appId) .selector(emptySelector) .treatment(emptyTreatment) .ingressPoint(ingress) .egressPoint(egress) .build(); final JsonCodec<PointToPointIntent> intentCodec = context.codec(PointToPointIntent.class); assertThat(intentCodec, notNullValue()); final ObjectNode intentJson = intentCodec.encode(intent, context); assertThat(intentJson, matchesIntent(intent)); } /** Tests the encoding of an intent with treatment, selector and constraints specified. */ @Test public void intentWithTreatmentSelectorAndConstraints() { ConnectPoint ingress = NetTestTools.connectPoint("ingress", 1); ConnectPoint egress = NetTestTools.connectPoint("egress", 2); DeviceId did1 = did("device1"); DeviceId did2 = did("device2"); DeviceId did3 = did("device3"); Lambda ochSignal = Lambda.ochSignal(GridType.DWDM, ChannelSpacing.CHL_100GHZ, 4, 8); final TrafficSelector selector = DefaultTrafficSelector.builder() .matchIPProtocol((byte) 3) .matchMplsLabel(MplsLabel.mplsLabel(4)) .add(Criteria.matchOchSignalType(OchSignalType.FIXED_GRID)) .add(Criteria.matchLambda(ochSignal)) .matchEthDst(MacAddress.BROADCAST) .matchIPDst(IpPrefix.valueOf("1.2.3.4/24")) .build(); final TrafficTreatment treatment = DefaultTrafficTreatment.builder() .add(Instructions.modL0Lambda(new IndexedLambda(33))) .setMpls(MplsLabel.mplsLabel(44)) .setOutput(PortNumber.CONTROLLER) .setEthDst(MacAddress.BROADCAST) .build(); final List<Constraint> constraints = ImmutableList.of( new BandwidthConstraint(Bandwidth.bps(1.0)), new LambdaConstraint(new IndexedLambda(3)), new AnnotationConstraint("key", 33.0), new AsymmetricPathConstraint(), new LatencyConstraint(Duration.ofSeconds(2)), new ObstacleConstraint(did1, did2), new WaypointConstraint(did3)); final PointToPointIntent intent = PointToPointIntent.builder() .appId(appId) .selector(selector) .treatment(treatment) .ingressPoint(ingress) .egressPoint(egress) .constraints(constraints) .build(); final JsonCodec<PointToPointIntent> intentCodec = context.codec(PointToPointIntent.class); assertThat(intentCodec, notNullValue()); final ObjectNode intentJson = intentCodec.encode(intent, context); assertThat(intentJson, matchesIntent(intent)); } /** * Reads in a rule from the given resource and decodes it. * * @param resourceName resource to use to read the JSON for the rule * @return decoded flow rule * @throws IOException if processing the resource fails */ private Intent getIntent(String resourceName, JsonCodec intentCodec) throws IOException { InputStream jsonStream = IntentCodecTest.class.getResourceAsStream(resourceName); JsonNode json = context.mapper().readTree(jsonStream); assertThat(json, notNullValue()); Intent intent = (Intent) intentCodec.decode((ObjectNode) json, context); assertThat(intent, notNullValue()); return intent; } /** * Tests the point to point intent JSON codec. * * @throws IOException if JSON processing fails */ @Test public void decodePointToPointIntent() throws IOException { JsonCodec<Intent> intentCodec = context.codec(Intent.class); assertThat(intentCodec, notNullValue()); Intent intent = getIntent("PointToPointIntent.json", intentCodec); assertThat(intent, notNullValue()); assertThat(intent, instanceOf(PointToPointIntent.class)); PointToPointIntent pointIntent = (PointToPointIntent) intent; assertThat(pointIntent.priority(), is(55)); assertThat(pointIntent.ingressPoint().deviceId(), is(did("0000000000000001"))); assertThat(pointIntent.ingressPoint().port(), is(PortNumber.portNumber(1))); assertThat(pointIntent.egressPoint().deviceId(), is(did("0000000000000007"))); assertThat(pointIntent.egressPoint().port(), is(PortNumber.portNumber(2))); assertThat(pointIntent.constraints(), hasSize(1)); assertThat(pointIntent.selector(), notNullValue()); assertThat(pointIntent.selector().criteria(), hasSize(1)); Criterion criterion1 = pointIntent.selector().criteria().iterator().next(); assertThat(criterion1, instanceOf(EthCriterion.class)); EthCriterion ethCriterion = (EthCriterion) criterion1; assertThat(ethCriterion.mac().toString(), is("11:22:33:44:55:66")); assertThat(ethCriterion.type().name(), is("ETH_DST")); assertThat(pointIntent.treatment(), notNullValue()); assertThat(pointIntent.treatment().allInstructions(), hasSize(1)); Instruction instruction1 = pointIntent.treatment().allInstructions().iterator().next(); assertThat(instruction1, instanceOf(ModEtherInstruction.class)); ModEtherInstruction ethInstruction = (ModEtherInstruction) instruction1; assertThat(ethInstruction.mac().toString(), is("22:33:44:55:66:77")); assertThat(ethInstruction.type().toString(), is("L2MODIFICATION")); assertThat(ethInstruction.subtype().toString(), is("ETH_SRC")); } /** * Tests the host to host intent JSON codec. * * @throws IOException */ @Test public void decodeHostToHostIntent() throws IOException { JsonCodec<Intent> intentCodec = context.codec(Intent.class); assertThat(intentCodec, notNullValue()); Intent intent = getIntent("HostToHostIntent.json", intentCodec); assertThat(intent, notNullValue()); assertThat(intent, instanceOf(HostToHostIntent.class)); HostToHostIntent hostIntent = (HostToHostIntent) intent; assertThat(hostIntent.priority(), is(7)); assertThat(hostIntent.constraints(), hasSize(1)); } }