Committed by
Gerrit Code Review
[CORD-46] Implement L2 switching in Segment Routing
DONE - Update SpringOpenTTP to support bridging table emulation - Populate low priority subnet broadcast entry for bridging table - Move IP entry population to host event handler as well - Update ArpHandler to handle intra-rack ARP forwarding/flooding - Move TTL_OUT action from IP table to corresponding group Since hardware does not support TTL_OUT in the IP table - Populate entries to bridging table (MAC learning) - Emulate src mac table Not in this submission - Emulate src-mac table behavior - Pop vlan in the group instead of the flow Change-Id: Ib69357c1889ccddaa4daa272d9f5843790ee1a3c
Showing
7 changed files
with
678 additions
and
121 deletions
... | @@ -20,10 +20,10 @@ import org.onlab.packet.Ethernet; | ... | @@ -20,10 +20,10 @@ import org.onlab.packet.Ethernet; |
20 | import org.onlab.packet.Ip4Address; | 20 | import org.onlab.packet.Ip4Address; |
21 | import org.onlab.packet.IpAddress; | 21 | import org.onlab.packet.IpAddress; |
22 | import org.onlab.packet.MacAddress; | 22 | import org.onlab.packet.MacAddress; |
23 | +import org.onlab.packet.VlanId; | ||
23 | import org.onosproject.net.ConnectPoint; | 24 | import org.onosproject.net.ConnectPoint; |
24 | import org.onosproject.net.DeviceId; | 25 | import org.onosproject.net.DeviceId; |
25 | import org.onosproject.net.Host; | 26 | import org.onosproject.net.Host; |
26 | -import org.onosproject.net.Port; | ||
27 | import org.onosproject.net.PortNumber; | 27 | import org.onosproject.net.PortNumber; |
28 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 28 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
29 | import org.onosproject.net.flow.TrafficTreatment; | 29 | import org.onosproject.net.flow.TrafficTreatment; |
... | @@ -60,12 +60,21 @@ public class ArpHandler { | ... | @@ -60,12 +60,21 @@ public class ArpHandler { |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * Processes incoming ARP packets. | 62 | * Processes incoming ARP packets. |
63 | + * | ||
63 | * If it is an ARP request to router itself or known hosts, | 64 | * If it is an ARP request to router itself or known hosts, |
64 | * then it sends ARP response. | 65 | * then it sends ARP response. |
65 | * If it is an ARP request to unknown hosts in its own subnet, | 66 | * If it is an ARP request to unknown hosts in its own subnet, |
66 | * then it flood the ARP request to the ports. | 67 | * then it flood the ARP request to the ports. |
67 | * If it is an ARP response, then set a flow rule for the host | 68 | * If it is an ARP response, then set a flow rule for the host |
68 | * and forward any IP packets to the host in the packet buffer to the host. | 69 | * and forward any IP packets to the host in the packet buffer to the host. |
70 | + * <p> | ||
71 | + * Note: We handles all ARP packet in, even for those ARP packets between | ||
72 | + * hosts in the same subnet. | ||
73 | + * For an ARP packet with broadcast destination MAC, | ||
74 | + * some switches pipelines will send it to the controller due to table miss, | ||
75 | + * other swithches will flood the packets directly in the data plane without | ||
76 | + * packet in. | ||
77 | + * We can deal with both cases. | ||
69 | * | 78 | * |
70 | * @param pkt incoming packet | 79 | * @param pkt incoming packet |
71 | */ | 80 | */ |
... | @@ -86,29 +95,56 @@ public class ArpHandler { | ... | @@ -86,29 +95,56 @@ public class ArpHandler { |
86 | if (arp.getOpCode() == ARP.OP_REQUEST) { | 95 | if (arp.getOpCode() == ARP.OP_REQUEST) { |
87 | handleArpRequest(deviceId, connectPoint, ethernet); | 96 | handleArpRequest(deviceId, connectPoint, ethernet); |
88 | } else { | 97 | } else { |
89 | - srManager.ipHandler.forwardPackets(deviceId, hostIpAddress); | 98 | + handleArpReply(deviceId, connectPoint, ethernet); |
90 | } | 99 | } |
91 | } | 100 | } |
92 | 101 | ||
93 | private void handleArpRequest(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) { | 102 | private void handleArpRequest(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) { |
94 | ARP arpRequest = (ARP) payload.getPayload(); | 103 | ARP arpRequest = (ARP) payload.getPayload(); |
104 | + VlanId vlanId = VlanId.vlanId(payload.getVlanID()); | ||
95 | HostId targetHostId = HostId.hostId(MacAddress.valueOf( | 105 | HostId targetHostId = HostId.hostId(MacAddress.valueOf( |
96 | - arpRequest.getTargetHardwareAddress())); | 106 | + arpRequest.getTargetHardwareAddress()), |
107 | + vlanId); | ||
97 | 108 | ||
98 | - // ARP request for router | 109 | + // ARP request for router. Send ARP reply. |
99 | if (isArpReqForRouter(deviceId, arpRequest)) { | 110 | if (isArpReqForRouter(deviceId, arpRequest)) { |
100 | Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress()); | 111 | Ip4Address targetAddress = Ip4Address.valueOf(arpRequest.getTargetProtocolAddress()); |
101 | - | 112 | + sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress), vlanId); |
102 | - sendArpResponse(arpRequest, config.getRouterMacForAGatewayIp(targetAddress)); | ||
103 | } else { | 113 | } else { |
104 | Host targetHost = srManager.hostService.getHost(targetHostId); | 114 | Host targetHost = srManager.hostService.getHost(targetHostId); |
105 | - // ARP request for known hosts | 115 | + // ARP request for known hosts. Send proxy ARP reply on behalf of the target. |
106 | if (targetHost != null) { | 116 | if (targetHost != null) { |
107 | - sendArpResponse(arpRequest, targetHost.mac()); | 117 | + removeVlanAndForward(payload, targetHost.location()); |
118 | + // ARP request for unknown host in the subnet. Flood in the subnet. | ||
119 | + } else { | ||
120 | + removeVlanAndFlood(payload, inPort); | ||
121 | + } | ||
122 | + } | ||
123 | + } | ||
108 | 124 | ||
109 | - // ARP request for unknown host in the subnet | 125 | + private void handleArpReply(DeviceId deviceId, ConnectPoint inPort, Ethernet payload) { |
110 | - } else if (isArpReqForSubnet(deviceId, arpRequest)) { | 126 | + ARP arpReply = (ARP) payload.getPayload(); |
111 | - flood(payload, inPort); | 127 | + VlanId vlanId = VlanId.vlanId(payload.getVlanID()); |
128 | + HostId targetHostId = HostId.hostId(MacAddress.valueOf( | ||
129 | + arpReply.getTargetHardwareAddress()), | ||
130 | + vlanId); | ||
131 | + | ||
132 | + // ARP reply for router. Process all pending IP packets. | ||
133 | + if (isArpReqForRouter(deviceId, arpReply)) { | ||
134 | + Ip4Address hostIpAddress = Ip4Address.valueOf(arpReply.getSenderProtocolAddress()); | ||
135 | + srManager.ipHandler.forwardPackets(deviceId, hostIpAddress); | ||
136 | + } else { | ||
137 | + Host targetHost = srManager.hostService.getHost(targetHostId); | ||
138 | + // ARP reply for known hosts. Forward to the host. | ||
139 | + if (targetHost != null) { | ||
140 | + removeVlanAndForward(payload, targetHost.location()); | ||
141 | + // ARP reply for unknown host, Flood in the subnet. | ||
142 | + } else { | ||
143 | + // Don't flood to non-edge ports | ||
144 | + if (vlanId.equals(VlanId.vlanId(srManager.ASSIGNED_VLAN_NO_SUBNET))) { | ||
145 | + return; | ||
146 | + } | ||
147 | + removeVlanAndFlood(payload, inPort); | ||
112 | } | 148 | } |
113 | } | 149 | } |
114 | } | 150 | } |
... | @@ -126,14 +162,6 @@ public class ArpHandler { | ... | @@ -126,14 +162,6 @@ public class ArpHandler { |
126 | return false; | 162 | return false; |
127 | } | 163 | } |
128 | 164 | ||
129 | - private boolean isArpReqForSubnet(DeviceId deviceId, ARP arpRequest) { | ||
130 | - return config.getSubnets(deviceId).stream() | ||
131 | - .anyMatch((prefix)-> | ||
132 | - prefix.contains(Ip4Address. | ||
133 | - valueOf(arpRequest. | ||
134 | - getTargetProtocolAddress()))); | ||
135 | - } | ||
136 | - | ||
137 | /** | 165 | /** |
138 | * Sends an APR request for the target IP address to all ports except in-port. | 166 | * Sends an APR request for the target IP address to all ports except in-port. |
139 | * | 167 | * |
... | @@ -170,11 +198,10 @@ public class ArpHandler { | ... | @@ -170,11 +198,10 @@ public class ArpHandler { |
170 | .setSourceMACAddress(senderMacAddress) | 198 | .setSourceMACAddress(senderMacAddress) |
171 | .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest); | 199 | .setEtherType(Ethernet.TYPE_ARP).setPayload(arpRequest); |
172 | 200 | ||
173 | - flood(eth, inPort); | 201 | + removeVlanAndFlood(eth, inPort); |
174 | } | 202 | } |
175 | 203 | ||
176 | - private void sendArpResponse(ARP arpRequest, MacAddress targetMac) { | 204 | + private void sendArpResponse(ARP arpRequest, MacAddress targetMac, VlanId vlanId) { |
177 | - | ||
178 | ARP arpReply = new ARP(); | 205 | ARP arpReply = new ARP(); |
179 | arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET) | 206 | arpReply.setHardwareType(ARP.HW_TYPE_ETHERNET) |
180 | .setProtocolType(ARP.PROTO_TYPE_IP) | 207 | .setProtocolType(ARP.PROTO_TYPE_IP) |
... | @@ -193,8 +220,9 @@ public class ArpHandler { | ... | @@ -193,8 +220,9 @@ public class ArpHandler { |
193 | .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply); | 220 | .setEtherType(Ethernet.TYPE_ARP).setPayload(arpReply); |
194 | 221 | ||
195 | 222 | ||
196 | - HostId dstId = HostId.hostId(MacAddress.valueOf( | 223 | + HostId dstId = HostId.hostId( |
197 | - arpReply.getTargetHardwareAddress())); | 224 | + MacAddress.valueOf(arpReply.getTargetHardwareAddress()), |
225 | + vlanId); | ||
198 | Host dst = srManager.hostService.getHost(dstId); | 226 | Host dst = srManager.hostService.getHost(dstId); |
199 | if (dst == null) { | 227 | if (dst == null) { |
200 | log.warn("Cannot send ARP response to unknown device"); | 228 | log.warn("Cannot send ARP response to unknown device"); |
... | @@ -209,19 +237,51 @@ public class ArpHandler { | ... | @@ -209,19 +237,51 @@ public class ArpHandler { |
209 | srManager.packetService.emit(packet); | 237 | srManager.packetService.emit(packet); |
210 | } | 238 | } |
211 | 239 | ||
212 | - private void flood(Ethernet request, ConnectPoint inPort) { | 240 | + /** |
213 | - TrafficTreatment.Builder builder; | 241 | + * Remove VLAN tag and flood to all ports in the same subnet. |
214 | - ByteBuffer buf = ByteBuffer.wrap(request.serialize()); | 242 | + * |
215 | - | 243 | + * @param packet packet to be flooded |
216 | - for (Port port: srManager.deviceService.getPorts(inPort.deviceId())) { | 244 | + * @param inPort where the packet comes from |
217 | - if (!port.number().equals(inPort.port()) && | 245 | + */ |
218 | - port.number().toLong() > 0) { | 246 | + private void removeVlanAndFlood(Ethernet packet, ConnectPoint inPort) { |
219 | - builder = DefaultTrafficTreatment.builder(); | 247 | + Ip4Address targetProtocolAddress = Ip4Address.valueOf( |
220 | - builder.setOutput(port.number()); | 248 | + ((ARP) packet.getPayload()).getTargetProtocolAddress() |
221 | - srManager.packetService.emit(new DefaultOutboundPacket(inPort.deviceId(), | 249 | + ); |
222 | - builder.build(), buf)); | 250 | + |
251 | + srManager.deviceConfiguration.getSubnetPortsMap(inPort.deviceId()).forEach((subnet, ports) -> { | ||
252 | + if (subnet.contains(targetProtocolAddress)) { | ||
253 | + ports.stream() | ||
254 | + .filter(port -> port != inPort.port()) | ||
255 | + .forEach(port -> { | ||
256 | + removeVlanAndForward(packet, new ConnectPoint(inPort.deviceId(), port)); | ||
257 | + }); | ||
223 | } | 258 | } |
224 | - } | 259 | + }); |
225 | } | 260 | } |
226 | 261 | ||
262 | + /** | ||
263 | + * Remove VLAN tag and packet out to given port. | ||
264 | + * | ||
265 | + * Note: In current implementation, we expect all communication with | ||
266 | + * end hosts within a subnet to be untagged. | ||
267 | + * <p> | ||
268 | + * For those pipelines that internally assigns a VLAN, the VLAN tag will be | ||
269 | + * removed before egress. | ||
270 | + * <p> | ||
271 | + * For those pipelines that do not assign internal VLAN, the packet remains | ||
272 | + * untagged. | ||
273 | + * | ||
274 | + * @param packet packet to be forwarded | ||
275 | + * @param outPort where the packet should be forwarded | ||
276 | + */ | ||
277 | + private void removeVlanAndForward(Ethernet packet, ConnectPoint outPort) { | ||
278 | + packet.setEtherType(Ethernet.TYPE_ARP); | ||
279 | + packet.setVlanID(Ethernet.VLAN_UNTAGGED); | ||
280 | + ByteBuffer buf = ByteBuffer.wrap(packet.serialize()); | ||
281 | + | ||
282 | + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); | ||
283 | + tbuilder.setOutput(outPort.port()); | ||
284 | + srManager.packetService.emit(new DefaultOutboundPacket(outPort.deviceId(), | ||
285 | + tbuilder.build(), buf)); | ||
286 | + } | ||
227 | } | 287 | } | ... | ... |
... | @@ -105,8 +105,17 @@ public class IcmpHandler { | ... | @@ -105,8 +105,17 @@ public class IcmpHandler { |
105 | } | 105 | } |
106 | } | 106 | } |
107 | 107 | ||
108 | + /** | ||
109 | + * Sends an ICMP reply message. | ||
110 | + * | ||
111 | + * Note: we assume that packets sending from the edge switches to the hosts | ||
112 | + * have untagged VLAN. | ||
113 | + * @param icmpRequest the original ICMP request | ||
114 | + * @param outport the output port where the ICMP reply should be sent to | ||
115 | + */ | ||
108 | private void sendICMPResponse(Ethernet icmpRequest, ConnectPoint outport) { | 116 | private void sendICMPResponse(Ethernet icmpRequest, ConnectPoint outport) { |
109 | - | 117 | + // Note: We assume that packets arrive at the edge switches have |
118 | + // untagged VLAN. | ||
110 | Ethernet icmpReplyEth = new Ethernet(); | 119 | Ethernet icmpReplyEth = new Ethernet(); |
111 | 120 | ||
112 | IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload(); | 121 | IPv4 icmpRequestIpv4 = (IPv4) icmpRequest.getPayload(); |
... | @@ -129,7 +138,6 @@ public class IcmpHandler { | ... | @@ -129,7 +138,6 @@ public class IcmpHandler { |
129 | icmpReplyEth.setEtherType(Ethernet.TYPE_IPV4); | 138 | icmpReplyEth.setEtherType(Ethernet.TYPE_IPV4); |
130 | icmpReplyEth.setDestinationMACAddress(icmpRequest.getSourceMACAddress()); | 139 | icmpReplyEth.setDestinationMACAddress(icmpRequest.getSourceMACAddress()); |
131 | icmpReplyEth.setSourceMACAddress(icmpRequest.getDestinationMACAddress()); | 140 | icmpReplyEth.setSourceMACAddress(icmpRequest.getDestinationMACAddress()); |
132 | - icmpReplyEth.setVlanID(icmpRequest.getVlanID()); | ||
133 | 141 | ||
134 | Ip4Address destIpAddress = Ip4Address.valueOf(icmpReplyIpv4.getDestinationAddress()); | 142 | Ip4Address destIpAddress = Ip4Address.valueOf(icmpReplyIpv4.getDestinationAddress()); |
135 | Ip4Address destRouterAddress = config.getRouterIpAddressForASubnetHost(destIpAddress); | 143 | Ip4Address destRouterAddress = config.getRouterIpAddressForASubnetHost(destIpAddress); | ... | ... |
... | @@ -55,7 +55,6 @@ import java.util.concurrent.atomic.AtomicLong; | ... | @@ -55,7 +55,6 @@ import java.util.concurrent.atomic.AtomicLong; |
55 | import static com.google.common.base.Preconditions.checkNotNull; | 55 | import static com.google.common.base.Preconditions.checkNotNull; |
56 | 56 | ||
57 | public class RoutingRulePopulator { | 57 | public class RoutingRulePopulator { |
58 | - | ||
59 | private static final Logger log = LoggerFactory | 58 | private static final Logger log = LoggerFactory |
60 | .getLogger(RoutingRulePopulator.class); | 59 | .getLogger(RoutingRulePopulator.class); |
61 | 60 | ||
... | @@ -105,13 +104,45 @@ public class RoutingRulePopulator { | ... | @@ -105,13 +104,45 @@ public class RoutingRulePopulator { |
105 | */ | 104 | */ |
106 | public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp, | 105 | public void populateIpRuleForHost(DeviceId deviceId, Ip4Address hostIp, |
107 | MacAddress hostMac, PortNumber outPort) { | 106 | MacAddress hostMac, PortNumber outPort) { |
108 | - MacAddress deviceMac; | 107 | + log.debug("Populate IP table entry for host {} at {}:{}", |
108 | + hostIp, deviceId, outPort); | ||
109 | + ForwardingObjective.Builder fwdBuilder; | ||
109 | try { | 110 | try { |
110 | - deviceMac = config.getDeviceMac(deviceId); | 111 | + fwdBuilder = getForwardingObjectiveBuilder( |
112 | + deviceId, hostIp, hostMac, outPort); | ||
111 | } catch (DeviceConfigNotFoundException e) { | 113 | } catch (DeviceConfigNotFoundException e) { |
112 | log.warn(e.getMessage() + " Aborting populateIpRuleForHost."); | 114 | log.warn(e.getMessage() + " Aborting populateIpRuleForHost."); |
113 | return; | 115 | return; |
114 | } | 116 | } |
117 | + srManager.flowObjectiveService. | ||
118 | + forward(deviceId, fwdBuilder.add(new SRObjectiveContext(deviceId, | ||
119 | + SRObjectiveContext.ObjectiveType.FORWARDING))); | ||
120 | + rulePopulationCounter.incrementAndGet(); | ||
121 | + } | ||
122 | + | ||
123 | + public void revokeIpRuleForHost(DeviceId deviceId, Ip4Address hostIp, | ||
124 | + MacAddress hostMac, PortNumber outPort) { | ||
125 | + log.debug("Revoke IP table entry for host {} at {}:{}", | ||
126 | + hostIp, deviceId, outPort); | ||
127 | + ForwardingObjective.Builder fwdBuilder; | ||
128 | + try { | ||
129 | + fwdBuilder = getForwardingObjectiveBuilder( | ||
130 | + deviceId, hostIp, hostMac, outPort); | ||
131 | + } catch (DeviceConfigNotFoundException e) { | ||
132 | + log.warn(e.getMessage() + " Aborting revokeIpRuleForHost."); | ||
133 | + return; | ||
134 | + } | ||
135 | + srManager.flowObjectiveService. | ||
136 | + forward(deviceId, fwdBuilder.remove(new SRObjectiveContext(deviceId, | ||
137 | + SRObjectiveContext.ObjectiveType.FORWARDING))); | ||
138 | + } | ||
139 | + | ||
140 | + private ForwardingObjective.Builder getForwardingObjectiveBuilder( | ||
141 | + DeviceId deviceId, Ip4Address hostIp, | ||
142 | + MacAddress hostMac, PortNumber outPort) | ||
143 | + throws DeviceConfigNotFoundException { | ||
144 | + MacAddress deviceMac; | ||
145 | + deviceMac = config.getDeviceMac(deviceId); | ||
115 | 146 | ||
116 | TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); | 147 | TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); |
117 | TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); | 148 | TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); |
... | @@ -127,19 +158,10 @@ public class RoutingRulePopulator { | ... | @@ -127,19 +158,10 @@ public class RoutingRulePopulator { |
127 | TrafficTreatment treatment = tbuilder.build(); | 158 | TrafficTreatment treatment = tbuilder.build(); |
128 | TrafficSelector selector = sbuilder.build(); | 159 | TrafficSelector selector = sbuilder.build(); |
129 | 160 | ||
130 | - ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective | 161 | + return DefaultForwardingObjective.builder() |
131 | - .builder().fromApp(srManager.appId).makePermanent() | 162 | + .fromApp(srManager.appId).makePermanent() |
132 | .withSelector(selector).withTreatment(treatment) | 163 | .withSelector(selector).withTreatment(treatment) |
133 | .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC); | 164 | .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC); |
134 | - | ||
135 | - log.debug("Installing IPv4 forwarding objective " | ||
136 | - + "for host {} in switch {}", hostIp, deviceId); | ||
137 | - srManager.flowObjectiveService. | ||
138 | - forward(deviceId, | ||
139 | - fwdBuilder. | ||
140 | - add(new SRObjectiveContext(deviceId, | ||
141 | - SRObjectiveContext.ObjectiveType.FORWARDING))); | ||
142 | - rulePopulationCounter.incrementAndGet(); | ||
143 | } | 165 | } |
144 | 166 | ||
145 | /** | 167 | /** |
... | @@ -186,26 +208,25 @@ public class RoutingRulePopulator { | ... | @@ -186,26 +208,25 @@ public class RoutingRulePopulator { |
186 | } | 208 | } |
187 | 209 | ||
188 | TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); | 210 | TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); |
189 | - TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); | ||
190 | - | ||
191 | sbuilder.matchIPDst(ipPrefix); | 211 | sbuilder.matchIPDst(ipPrefix); |
192 | sbuilder.matchEthType(Ethernet.TYPE_IPV4); | 212 | sbuilder.matchEthType(Ethernet.TYPE_IPV4); |
213 | + TrafficSelector selector = sbuilder.build(); | ||
193 | 214 | ||
194 | - NeighborSet ns = null; | 215 | + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); |
216 | + NeighborSet ns; | ||
217 | + TrafficTreatment treatment; | ||
195 | 218 | ||
196 | // If the next hop is the same as the final destination, then MPLS label | 219 | // If the next hop is the same as the final destination, then MPLS label |
197 | // is not set. | 220 | // is not set. |
198 | if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) { | 221 | if (nextHops.size() == 1 && nextHops.toArray()[0].equals(destSw)) { |
199 | - tbuilder.deferred().decNwTtl(); | 222 | + tbuilder.immediate().decNwTtl(); |
200 | ns = new NeighborSet(nextHops); | 223 | ns = new NeighborSet(nextHops); |
224 | + treatment = tbuilder.build(); | ||
201 | } else { | 225 | } else { |
202 | - tbuilder.deferred().copyTtlOut(); | ||
203 | ns = new NeighborSet(nextHops, segmentId); | 226 | ns = new NeighborSet(nextHops, segmentId); |
227 | + treatment = null; | ||
204 | } | 228 | } |
205 | 229 | ||
206 | - TrafficTreatment treatment = tbuilder.build(); | ||
207 | - TrafficSelector selector = sbuilder.build(); | ||
208 | - | ||
209 | if (srManager.getNextObjectiveId(deviceId, ns) <= 0) { | 230 | if (srManager.getNextObjectiveId(deviceId, ns) <= 0) { |
210 | log.warn("No next objective in {} for ns: {}", deviceId, ns); | 231 | log.warn("No next objective in {} for ns: {}", deviceId, ns); |
211 | return false; | 232 | return false; |
... | @@ -216,10 +237,12 @@ public class RoutingRulePopulator { | ... | @@ -216,10 +237,12 @@ public class RoutingRulePopulator { |
216 | .fromApp(srManager.appId) | 237 | .fromApp(srManager.appId) |
217 | .makePermanent() | 238 | .makePermanent() |
218 | .nextStep(srManager.getNextObjectiveId(deviceId, ns)) | 239 | .nextStep(srManager.getNextObjectiveId(deviceId, ns)) |
219 | - .withTreatment(treatment) | ||
220 | .withSelector(selector) | 240 | .withSelector(selector) |
221 | .withPriority(100) | 241 | .withPriority(100) |
222 | .withFlag(ForwardingObjective.Flag.SPECIFIC); | 242 | .withFlag(ForwardingObjective.Flag.SPECIFIC); |
243 | + if (treatment != null) { | ||
244 | + fwdBuilder.withTreatment(treatment); | ||
245 | + } | ||
223 | log.debug("Installing IPv4 forwarding objective " | 246 | log.debug("Installing IPv4 forwarding objective " |
224 | + "for router IP/subnet {} in switch {}", | 247 | + "for router IP/subnet {} in switch {}", |
225 | ipPrefix, | 248 | ipPrefix, |
... | @@ -423,8 +446,6 @@ public class RoutingRulePopulator { | ... | @@ -423,8 +446,6 @@ public class RoutingRulePopulator { |
423 | ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) | 446 | ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) |
424 | : srManager.getSubnetAssignedVlanId(deviceId, portSubnet); | 447 | : srManager.getSubnetAssignedVlanId(deviceId, portSubnet); |
425 | 448 | ||
426 | - | ||
427 | - | ||
428 | FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); | 449 | FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); |
429 | fob.withKey(Criteria.matchInPort(port.number())) | 450 | fob.withKey(Criteria.matchInPort(port.number())) |
430 | .addCondition(Criteria.matchEthDst(deviceMac)) | 451 | .addCondition(Criteria.matchEthDst(deviceMac)) |
... | @@ -469,14 +490,14 @@ public class RoutingRulePopulator { | ... | @@ -469,14 +490,14 @@ public class RoutingRulePopulator { |
469 | Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId)); | 490 | Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId)); |
470 | allIps.add(routerIp); | 491 | allIps.add(routerIp); |
471 | for (Ip4Address ipaddr : allIps) { | 492 | for (Ip4Address ipaddr : allIps) { |
472 | - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | 493 | + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); |
473 | - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); | 494 | + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); |
474 | - selector.matchEthType(Ethernet.TYPE_IPV4); | 495 | + sbuilder.matchEthType(Ethernet.TYPE_IPV4); |
475 | - selector.matchIPDst(IpPrefix.valueOf(ipaddr, | 496 | + sbuilder.matchIPDst(IpPrefix.valueOf(ipaddr, |
476 | IpPrefix.MAX_INET_MASK_LENGTH)); | 497 | IpPrefix.MAX_INET_MASK_LENGTH)); |
477 | - treatment.setOutput(PortNumber.CONTROLLER); | 498 | + tbuilder.setOutput(PortNumber.CONTROLLER); |
478 | - puntIp.withSelector(selector.build()); | 499 | + puntIp.withSelector(sbuilder.build()); |
479 | - puntIp.withTreatment(treatment.build()); | 500 | + puntIp.withTreatment(tbuilder.build()); |
480 | puntIp.withFlag(Flag.VERSATILE) | 501 | puntIp.withFlag(Flag.VERSATILE) |
481 | .withPriority(HIGHEST_PRIORITY) | 502 | .withPriority(HIGHEST_PRIORITY) |
482 | .makePermanent() | 503 | .makePermanent() |
... | @@ -489,6 +510,48 @@ public class RoutingRulePopulator { | ... | @@ -489,6 +510,48 @@ public class RoutingRulePopulator { |
489 | } | 510 | } |
490 | } | 511 | } |
491 | 512 | ||
513 | + /** | ||
514 | + * Populates a forwarding objective to send packets that miss other high | ||
515 | + * priority Bridging Table entries to a group that contains all ports of | ||
516 | + * its subnet. | ||
517 | + * | ||
518 | + * Note: We assume that packets sending from the edge switches to the hosts | ||
519 | + * have untagged VLAN. | ||
520 | + * The VLAN tag will be popped later in the flooding group. | ||
521 | + * | ||
522 | + * @param deviceId switch ID to set the rules | ||
523 | + */ | ||
524 | + public void populateSubnetBroadcastRule(DeviceId deviceId) { | ||
525 | + config.getSubnets(deviceId).forEach(subnet -> { | ||
526 | + int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet); | ||
527 | + VlanId vlanId = srManager.getSubnetAssignedVlanId(deviceId, subnet); | ||
528 | + | ||
529 | + /* Driver should treat objective with MacAddress.NONE as the | ||
530 | + * subnet broadcast rule | ||
531 | + */ | ||
532 | + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); | ||
533 | + sbuilder.matchVlanId(vlanId); | ||
534 | + sbuilder.matchEthDst(MacAddress.NONE); | ||
535 | + | ||
536 | + ForwardingObjective.Builder fob = DefaultForwardingObjective.builder(); | ||
537 | + fob.withFlag(Flag.SPECIFIC) | ||
538 | + .withSelector(sbuilder.build()) | ||
539 | + .nextStep(nextId) | ||
540 | + .withPriority(5) | ||
541 | + .fromApp(srManager.appId) | ||
542 | + .makePermanent(); | ||
543 | + | ||
544 | + srManager.flowObjectiveService.forward( | ||
545 | + deviceId, | ||
546 | + fob.add(new SRObjectiveContext( | ||
547 | + deviceId, | ||
548 | + SRObjectiveContext.ObjectiveType.FORWARDING) | ||
549 | + ) | ||
550 | + ); | ||
551 | + }); | ||
552 | + } | ||
553 | + | ||
554 | + | ||
492 | private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) { | 555 | private PortNumber selectOnePort(DeviceId srcId, Set<DeviceId> destIds) { |
493 | 556 | ||
494 | Set<Link> links = srManager.linkService.getDeviceLinks(srcId); | 557 | Set<Link> links = srManager.linkService.getDeviceLinks(srcId); | ... | ... |
... | @@ -22,6 +22,7 @@ import org.apache.felix.scr.annotations.Reference; | ... | @@ -22,6 +22,7 @@ import org.apache.felix.scr.annotations.Reference; |
22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 22 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
23 | import org.apache.felix.scr.annotations.Service; | 23 | import org.apache.felix.scr.annotations.Service; |
24 | import org.onlab.packet.Ethernet; | 24 | import org.onlab.packet.Ethernet; |
25 | +import org.onlab.packet.MacAddress; | ||
25 | import org.onlab.packet.VlanId; | 26 | import org.onlab.packet.VlanId; |
26 | import org.onlab.packet.IPv4; | 27 | import org.onlab.packet.IPv4; |
27 | import org.onlab.packet.Ip4Address; | 28 | import org.onlab.packet.Ip4Address; |
... | @@ -33,11 +34,23 @@ import org.onosproject.core.ApplicationId; | ... | @@ -33,11 +34,23 @@ import org.onosproject.core.ApplicationId; |
33 | import org.onosproject.core.CoreService; | 34 | import org.onosproject.core.CoreService; |
34 | import org.onosproject.event.Event; | 35 | import org.onosproject.event.Event; |
35 | import org.onosproject.net.ConnectPoint; | 36 | import org.onosproject.net.ConnectPoint; |
37 | +import org.onosproject.net.PortNumber; | ||
36 | import org.onosproject.net.config.ConfigFactory; | 38 | import org.onosproject.net.config.ConfigFactory; |
37 | import org.onosproject.net.config.NetworkConfigEvent; | 39 | import org.onosproject.net.config.NetworkConfigEvent; |
38 | import org.onosproject.net.config.NetworkConfigRegistry; | 40 | import org.onosproject.net.config.NetworkConfigRegistry; |
39 | import org.onosproject.net.config.NetworkConfigListener; | 41 | import org.onosproject.net.config.NetworkConfigListener; |
40 | import org.onosproject.net.config.basics.SubjectFactories; | 42 | import org.onosproject.net.config.basics.SubjectFactories; |
43 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
44 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
45 | +import org.onosproject.net.flow.TrafficSelector; | ||
46 | +import org.onosproject.net.flow.TrafficTreatment; | ||
47 | +import org.onosproject.net.flowobjective.DefaultForwardingObjective; | ||
48 | +import org.onosproject.net.flowobjective.ForwardingObjective; | ||
49 | +import org.onosproject.net.flowobjective.Objective; | ||
50 | +import org.onosproject.net.flowobjective.ObjectiveContext; | ||
51 | +import org.onosproject.net.flowobjective.ObjectiveError; | ||
52 | +import org.onosproject.net.host.HostEvent; | ||
53 | +import org.onosproject.net.host.HostListener; | ||
41 | import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException; | 54 | import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException; |
42 | import org.onosproject.segmentrouting.config.DeviceConfiguration; | 55 | import org.onosproject.segmentrouting.config.DeviceConfiguration; |
43 | import org.onosproject.segmentrouting.config.SegmentRoutingConfig; | 56 | import org.onosproject.segmentrouting.config.SegmentRoutingConfig; |
... | @@ -139,11 +152,13 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -139,11 +152,13 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
139 | 152 | ||
140 | private static ScheduledFuture<?> eventHandlerFuture = null; | 153 | private static ScheduledFuture<?> eventHandlerFuture = null; |
141 | private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>(); | 154 | private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>(); |
142 | - private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>(); | 155 | + private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = |
156 | + new ConcurrentHashMap<DeviceId, DefaultGroupHandler>(); | ||
143 | // Per device next objective ID store with (device id + neighbor set) as key | 157 | // Per device next objective ID store with (device id + neighbor set) as key |
144 | - private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, | 158 | + private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer> |
145 | - Integer> nsNextObjStore = null; | 159 | + nsNextObjStore = null; |
146 | - private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null; | 160 | + private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> |
161 | + subnetNextObjStore = null; | ||
147 | private EventuallyConsistentMap<String, Tunnel> tunnelStore = null; | 162 | private EventuallyConsistentMap<String, Tunnel> tunnelStore = null; |
148 | private EventuallyConsistentMap<String, Policy> policyStore = null; | 163 | private EventuallyConsistentMap<String, Policy> policyStore = null; |
149 | // Per device, per-subnet assigned-vlans store, with (device id + subnet | 164 | // Per device, per-subnet assigned-vlans store, with (device id + subnet |
... | @@ -170,6 +185,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -170,6 +185,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
170 | } | 185 | } |
171 | }; | 186 | }; |
172 | 187 | ||
188 | + private final HostListener hostListener = new InternalHostListener(); | ||
189 | + | ||
173 | private Object threadSchedulerLock = new Object(); | 190 | private Object threadSchedulerLock = new Object(); |
174 | private static int numOfEventsQueued = 0; | 191 | private static int numOfEventsQueued = 0; |
175 | private static int numOfEventsExecuted = 0; | 192 | private static int numOfEventsExecuted = 0; |
... | @@ -259,6 +276,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -259,6 +276,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
259 | cfgService.addListener(cfgListener); | 276 | cfgService.addListener(cfgListener); |
260 | cfgService.registerConfigFactory(cfgFactory); | 277 | cfgService.registerConfigFactory(cfgFactory); |
261 | 278 | ||
279 | + hostService.addListener(hostListener); | ||
280 | + | ||
262 | processor = new InternalPacketProcessor(); | 281 | processor = new InternalPacketProcessor(); |
263 | linkListener = new InternalLinkListener(); | 282 | linkListener = new InternalLinkListener(); |
264 | deviceListener = new InternalDeviceListener(); | 283 | deviceListener = new InternalDeviceListener(); |
... | @@ -637,6 +656,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -637,6 +656,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
637 | if (mastershipService.isLocalMaster(device.id())) { | 656 | if (mastershipService.isLocalMaster(device.id())) { |
638 | DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id()); | 657 | DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id()); |
639 | groupHandler.createGroupsFromSubnetConfig(); | 658 | groupHandler.createGroupsFromSubnetConfig(); |
659 | + routingRulePopulator.populateSubnetBroadcastRule(device.id()); | ||
640 | } | 660 | } |
641 | } | 661 | } |
642 | 662 | ||
... | @@ -703,6 +723,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -703,6 +723,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
703 | if (mastershipService.isLocalMaster(device.id())) { | 723 | if (mastershipService.isLocalMaster(device.id())) { |
704 | DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id()); | 724 | DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id()); |
705 | groupHandler.createGroupsFromSubnetConfig(); | 725 | groupHandler.createGroupsFromSubnetConfig(); |
726 | + routingRulePopulator.populateSubnetBroadcastRule(device.id()); | ||
706 | } | 727 | } |
707 | } | 728 | } |
708 | 729 | ||
... | @@ -723,4 +744,205 @@ public class SegmentRoutingManager implements SegmentRoutingService { | ... | @@ -723,4 +744,205 @@ public class SegmentRoutingManager implements SegmentRoutingService { |
723 | } | 744 | } |
724 | } | 745 | } |
725 | } | 746 | } |
747 | + | ||
748 | + private class InternalHostListener implements HostListener { | ||
749 | + private ForwardingObjective.Builder getForwardingObjectiveBuilder( | ||
750 | + MacAddress mac, VlanId vlanId, PortNumber port) { | ||
751 | + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); | ||
752 | + sbuilder.matchEthDst(mac); | ||
753 | + sbuilder.matchVlanId(vlanId); | ||
754 | + | ||
755 | + TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); | ||
756 | + // TODO Move popVlan from flow action to group action | ||
757 | + tbuilder.immediate().popVlan(); | ||
758 | + tbuilder.immediate().setOutput(port); | ||
759 | + | ||
760 | + return DefaultForwardingObjective.builder() | ||
761 | + .withFlag(ForwardingObjective.Flag.SPECIFIC) | ||
762 | + .withSelector(sbuilder.build()) | ||
763 | + .withTreatment(tbuilder.build()) | ||
764 | + .withPriority(100) | ||
765 | + .fromApp(appId) | ||
766 | + .makePermanent(); | ||
767 | + } | ||
768 | + | ||
769 | + private void processHostAddedEvent(HostEvent event) { | ||
770 | + MacAddress mac = event.subject().mac(); | ||
771 | + VlanId vlanId = event.subject().vlan(); | ||
772 | + DeviceId deviceId = event.subject().location().deviceId(); | ||
773 | + PortNumber port = event.subject().location().port(); | ||
774 | + Set<IpAddress> ips = event.subject().ipAddresses(); | ||
775 | + log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port); | ||
776 | + | ||
777 | + // TODO Move bridging table population to a separate class | ||
778 | + // Populate bridging table entry | ||
779 | + ForwardingObjective.Builder fob = | ||
780 | + getForwardingObjectiveBuilder(mac, vlanId, port); | ||
781 | + flowObjectiveService.forward(deviceId, fob.add( | ||
782 | + new BridgingTableObjectiveContext(mac, vlanId) | ||
783 | + )); | ||
784 | + | ||
785 | + // Populate IP table entry | ||
786 | + ips.forEach(ip -> { | ||
787 | + if (ip.isIp4()) { | ||
788 | + routingRulePopulator.populateIpRuleForHost( | ||
789 | + deviceId, ip.getIp4Address(), mac, port); | ||
790 | + } | ||
791 | + }); | ||
792 | + } | ||
793 | + | ||
794 | + private void processHostRemoveEvent(HostEvent event) { | ||
795 | + MacAddress mac = event.subject().mac(); | ||
796 | + VlanId vlanId = event.subject().vlan(); | ||
797 | + DeviceId deviceId = event.subject().location().deviceId(); | ||
798 | + PortNumber port = event.subject().location().port(); | ||
799 | + Set<IpAddress> ips = event.subject().ipAddresses(); | ||
800 | + log.debug("Host {}/{} is removed from {}:{}", mac, vlanId, deviceId, port); | ||
801 | + | ||
802 | + // Revoke bridging table entry | ||
803 | + ForwardingObjective.Builder fob = | ||
804 | + getForwardingObjectiveBuilder(mac, vlanId, port); | ||
805 | + flowObjectiveService.forward(deviceId, fob.remove( | ||
806 | + new BridgingTableObjectiveContext(mac, vlanId) | ||
807 | + )); | ||
808 | + | ||
809 | + // Revoke IP table entry | ||
810 | + ips.forEach(ip -> { | ||
811 | + if (ip.isIp4()) { | ||
812 | + routingRulePopulator.revokeIpRuleForHost( | ||
813 | + deviceId, ip.getIp4Address(), mac, port); | ||
814 | + } | ||
815 | + }); | ||
816 | + } | ||
817 | + | ||
818 | + private void processHostMovedEvent(HostEvent event) { | ||
819 | + MacAddress mac = event.subject().mac(); | ||
820 | + VlanId vlanId = event.subject().vlan(); | ||
821 | + DeviceId prevDeviceId = event.prevSubject().location().deviceId(); | ||
822 | + PortNumber prevPort = event.prevSubject().location().port(); | ||
823 | + Set<IpAddress> prevIps = event.prevSubject().ipAddresses(); | ||
824 | + DeviceId newDeviceId = event.subject().location().deviceId(); | ||
825 | + PortNumber newPort = event.subject().location().port(); | ||
826 | + Set<IpAddress> newIps = event.subject().ipAddresses(); | ||
827 | + log.debug("Host {}/{} is moved from {}:{} to {}:{}", | ||
828 | + mac, vlanId, prevDeviceId, prevPort, newDeviceId, newPort); | ||
829 | + | ||
830 | + // Revoke previous bridging table entry | ||
831 | + ForwardingObjective.Builder prevFob = | ||
832 | + getForwardingObjectiveBuilder(mac, vlanId, prevPort); | ||
833 | + flowObjectiveService.forward(prevDeviceId, prevFob.remove( | ||
834 | + new BridgingTableObjectiveContext(mac, vlanId) | ||
835 | + )); | ||
836 | + | ||
837 | + // Revoke previous IP table entry | ||
838 | + prevIps.forEach(ip -> { | ||
839 | + if (ip.isIp4()) { | ||
840 | + routingRulePopulator.revokeIpRuleForHost( | ||
841 | + prevDeviceId, ip.getIp4Address(), mac, prevPort); | ||
842 | + } | ||
843 | + }); | ||
844 | + | ||
845 | + // Populate new bridging table entry | ||
846 | + ForwardingObjective.Builder newFob = | ||
847 | + getForwardingObjectiveBuilder(mac, vlanId, prevPort); | ||
848 | + flowObjectiveService.forward(newDeviceId, newFob.add( | ||
849 | + new BridgingTableObjectiveContext(mac, vlanId) | ||
850 | + )); | ||
851 | + | ||
852 | + // Populate new IP table entry | ||
853 | + newIps.forEach(ip -> { | ||
854 | + if (ip.isIp4()) { | ||
855 | + routingRulePopulator.populateIpRuleForHost( | ||
856 | + newDeviceId, ip.getIp4Address(), mac, newPort); | ||
857 | + } | ||
858 | + }); | ||
859 | + } | ||
860 | + | ||
861 | + private void processHostUpdatedEvent(HostEvent event) { | ||
862 | + MacAddress mac = event.subject().mac(); | ||
863 | + VlanId vlanId = event.subject().vlan(); | ||
864 | + DeviceId prevDeviceId = event.prevSubject().location().deviceId(); | ||
865 | + PortNumber prevPort = event.prevSubject().location().port(); | ||
866 | + Set<IpAddress> prevIps = event.prevSubject().ipAddresses(); | ||
867 | + DeviceId newDeviceId = event.subject().location().deviceId(); | ||
868 | + PortNumber newPort = event.subject().location().port(); | ||
869 | + Set<IpAddress> newIps = event.subject().ipAddresses(); | ||
870 | + log.debug("Host {}/{} is updated", mac, vlanId); | ||
871 | + | ||
872 | + // Revoke previous IP table entry | ||
873 | + prevIps.forEach(ip -> { | ||
874 | + if (ip.isIp4()) { | ||
875 | + routingRulePopulator.revokeIpRuleForHost( | ||
876 | + prevDeviceId, ip.getIp4Address(), mac, prevPort); | ||
877 | + } | ||
878 | + }); | ||
879 | + | ||
880 | + // Populate new IP table entry | ||
881 | + newIps.forEach(ip -> { | ||
882 | + if (ip.isIp4()) { | ||
883 | + routingRulePopulator.populateIpRuleForHost( | ||
884 | + newDeviceId, ip.getIp4Address(), mac, newPort); | ||
885 | + } | ||
886 | + }); | ||
887 | + } | ||
888 | + | ||
889 | + @Override | ||
890 | + public void event(HostEvent event) { | ||
891 | + // Do not proceed without mastership | ||
892 | + DeviceId deviceId = event.subject().location().deviceId(); | ||
893 | + if (!mastershipService.isLocalMaster(deviceId)) { | ||
894 | + return; | ||
895 | + } | ||
896 | + | ||
897 | + switch (event.type()) { | ||
898 | + case HOST_ADDED: | ||
899 | + processHostAddedEvent(event); | ||
900 | + break; | ||
901 | + case HOST_MOVED: | ||
902 | + processHostMovedEvent(event); | ||
903 | + break; | ||
904 | + case HOST_REMOVED: | ||
905 | + processHostRemoveEvent(event); | ||
906 | + break; | ||
907 | + case HOST_UPDATED: | ||
908 | + processHostUpdatedEvent(event); | ||
909 | + break; | ||
910 | + default: | ||
911 | + log.warn("Unsupported host event type: {}", event.type()); | ||
912 | + break; | ||
913 | + } | ||
914 | + } | ||
915 | + } | ||
916 | + | ||
917 | + private static class BridgingTableObjectiveContext implements ObjectiveContext { | ||
918 | + final MacAddress mac; | ||
919 | + final VlanId vlanId; | ||
920 | + | ||
921 | + BridgingTableObjectiveContext(MacAddress mac, VlanId vlanId) { | ||
922 | + this.mac = mac; | ||
923 | + this.vlanId = vlanId; | ||
924 | + } | ||
925 | + | ||
926 | + @Override | ||
927 | + public void onSuccess(Objective objective) { | ||
928 | + if (objective.op() == Objective.Operation.ADD) { | ||
929 | + log.debug("Successfully populate bridging table entry for {}/{}", | ||
930 | + mac, vlanId); | ||
931 | + } else { | ||
932 | + log.debug("Successfully revoke bridging table entry for {}/{}", | ||
933 | + mac, vlanId); | ||
934 | + } | ||
935 | + } | ||
936 | + | ||
937 | + @Override | ||
938 | + public void onError(Objective objective, ObjectiveError error) { | ||
939 | + if (objective.op() == Objective.Operation.ADD) { | ||
940 | + log.debug("Fail to populate bridging table entry for {}/{}. {}", | ||
941 | + mac, vlanId, error); | ||
942 | + } else { | ||
943 | + log.debug("Fail to revoke bridging table entry for {}/{}. {}", | ||
944 | + mac, vlanId, error); | ||
945 | + } | ||
946 | + } | ||
947 | + } | ||
726 | } | 948 | } | ... | ... |
... | @@ -224,8 +224,8 @@ public class DefaultGroupHandler { | ... | @@ -224,8 +224,8 @@ public class DefaultGroupHandler { |
224 | .setEthSrc(nodeMacAddr); | 224 | .setEthSrc(nodeMacAddr); |
225 | if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) { | 225 | if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) { |
226 | tBuilder.pushMpls() | 226 | tBuilder.pushMpls() |
227 | - .setMpls(MplsLabel. | 227 | + .copyTtlOut() |
228 | - mplsLabel(ns.getEdgeLabel())); | 228 | + .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); |
229 | } | 229 | } |
230 | 230 | ||
231 | Integer nextId = nsNextObjStore. | 231 | Integer nextId = nsNextObjStore. |
... | @@ -292,8 +292,9 @@ public class DefaultGroupHandler { | ... | @@ -292,8 +292,9 @@ public class DefaultGroupHandler { |
292 | .setEthDst(dstMac) | 292 | .setEthDst(dstMac) |
293 | .setEthSrc(nodeMacAddr); | 293 | .setEthSrc(nodeMacAddr); |
294 | if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) { | 294 | if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) { |
295 | - tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(ns | 295 | + tBuilder.pushMpls() |
296 | - .getEdgeLabel())); | 296 | + .copyTtlOut() |
297 | + .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); | ||
297 | } | 298 | } |
298 | 299 | ||
299 | Integer nextId = nsNextObjStore. | 300 | Integer nextId = nsNextObjStore. |
... | @@ -536,8 +537,9 @@ public class DefaultGroupHandler { | ... | @@ -536,8 +537,9 @@ public class DefaultGroupHandler { |
536 | .setEthDst(deviceMac) | 537 | .setEthDst(deviceMac) |
537 | .setEthSrc(nodeMacAddr); | 538 | .setEthSrc(nodeMacAddr); |
538 | if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) { | 539 | if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) { |
539 | - tBuilder.pushMpls().setMpls(MplsLabel.mplsLabel(ns | 540 | + tBuilder.pushMpls() |
540 | - .getEdgeLabel())); | 541 | + .copyTtlOut() |
542 | + .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); | ||
541 | } | 543 | } |
542 | nextObjBuilder.addTreatment(tBuilder.build()); | 544 | nextObjBuilder.addTreatment(tBuilder.build()); |
543 | } | 545 | } | ... | ... |
... | @@ -25,6 +25,7 @@ import com.google.common.cache.RemovalNotification; | ... | @@ -25,6 +25,7 @@ import com.google.common.cache.RemovalNotification; |
25 | 25 | ||
26 | import org.onlab.osgi.ServiceDirectory; | 26 | import org.onlab.osgi.ServiceDirectory; |
27 | import org.onlab.packet.Ethernet; | 27 | import org.onlab.packet.Ethernet; |
28 | +import org.onlab.packet.MacAddress; | ||
28 | import org.onlab.packet.VlanId; | 29 | import org.onlab.packet.VlanId; |
29 | import org.onlab.util.KryoNamespace; | 30 | import org.onlab.util.KryoNamespace; |
30 | import org.onosproject.core.ApplicationId; | 31 | import org.onosproject.core.ApplicationId; |
... | @@ -54,6 +55,7 @@ import org.onosproject.net.flow.criteria.PortCriterion; | ... | @@ -54,6 +55,7 @@ import org.onosproject.net.flow.criteria.PortCriterion; |
54 | import org.onosproject.net.flow.criteria.VlanIdCriterion; | 55 | import org.onosproject.net.flow.criteria.VlanIdCriterion; |
55 | import org.onosproject.net.flow.instructions.Instruction; | 56 | import org.onosproject.net.flow.instructions.Instruction; |
56 | import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; | 57 | import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; |
58 | +import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction; | ||
57 | import org.onosproject.net.flowobjective.FilteringObjective; | 59 | import org.onosproject.net.flowobjective.FilteringObjective; |
58 | import org.onosproject.net.flowobjective.FlowObjectiveStore; | 60 | import org.onosproject.net.flowobjective.FlowObjectiveStore; |
59 | import org.onosproject.net.flowobjective.ForwardingObjective; | 61 | import org.onosproject.net.flowobjective.ForwardingObjective; |
... | @@ -94,7 +96,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour | ... | @@ -94,7 +96,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour |
94 | private static final int TABLE_TMAC = 1; | 96 | private static final int TABLE_TMAC = 1; |
95 | private static final int TABLE_IPV4_UNICAST = 2; | 97 | private static final int TABLE_IPV4_UNICAST = 2; |
96 | private static final int TABLE_MPLS = 3; | 98 | private static final int TABLE_MPLS = 3; |
99 | + private static final int TABLE_DMAC = 4; | ||
97 | private static final int TABLE_ACL = 5; | 100 | private static final int TABLE_ACL = 5; |
101 | + private static final int TABLE_SMAC = 6; | ||
98 | 102 | ||
99 | /** | 103 | /** |
100 | * Set the default values. These variables will get overwritten based on the | 104 | * Set the default values. These variables will get overwritten based on the |
... | @@ -104,7 +108,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour | ... | @@ -104,7 +108,9 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour |
104 | protected int tmacTableId = TABLE_TMAC; | 108 | protected int tmacTableId = TABLE_TMAC; |
105 | protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST; | 109 | protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST; |
106 | protected int mplsTableId = TABLE_MPLS; | 110 | protected int mplsTableId = TABLE_MPLS; |
111 | + protected int dstMacTableId = TABLE_DMAC; | ||
107 | protected int aclTableId = TABLE_ACL; | 112 | protected int aclTableId = TABLE_ACL; |
113 | + protected int srcMacTableId = TABLE_SMAC; | ||
108 | 114 | ||
109 | protected final Logger log = getLogger(getClass()); | 115 | protected final Logger log = getLogger(getClass()); |
110 | 116 | ||
... | @@ -448,12 +454,14 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour | ... | @@ -448,12 +454,14 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour |
448 | fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { | 454 | fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { |
449 | OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); | 455 | OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); |
450 | if (o.port() == PortNumber.CONTROLLER) { | 456 | if (o.port() == PortNumber.CONTROLLER) { |
451 | - log.warn("Punts to the controller are handled by misses in" | 457 | + treatmentBuilder.punt(); |
452 | - + " the TMAC, IP and MPLS tables."); | 458 | + treatment = treatmentBuilder.build(); |
453 | - return Collections.emptySet(); | 459 | + } else { |
460 | + treatment = fwd.treatment(); | ||
454 | } | 461 | } |
462 | + } else { | ||
463 | + treatment = fwd.treatment(); | ||
455 | } | 464 | } |
456 | - treatment = fwd.treatment(); | ||
457 | } else { | 465 | } else { |
458 | log.warn("VERSATILE forwarding objective needs next objective ID " | 466 | log.warn("VERSATILE forwarding objective needs next objective ID " |
459 | + "or treatment."); | 467 | + "or treatment."); |
... | @@ -475,19 +483,52 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour | ... | @@ -475,19 +483,52 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour |
475 | return Collections.singletonList(ruleBuilder.build()); | 483 | return Collections.singletonList(ruleBuilder.build()); |
476 | } | 484 | } |
477 | 485 | ||
478 | - protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) { | 486 | + private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) { |
479 | - log.debug("Processing specific"); | ||
480 | TrafficSelector selector = fwd.selector(); | 487 | TrafficSelector selector = fwd.selector(); |
481 | EthTypeCriterion ethType = (EthTypeCriterion) selector | 488 | EthTypeCriterion ethType = (EthTypeCriterion) selector |
482 | .getCriterion(Criterion.Type.ETH_TYPE); | 489 | .getCriterion(Criterion.Type.ETH_TYPE); |
483 | if ((ethType == null) || | 490 | if ((ethType == null) || |
484 | - (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && | 491 | + ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) && |
485 | - (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) { | 492 | + (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) { |
493 | + return false; | ||
494 | + } | ||
495 | + return true; | ||
496 | + } | ||
497 | + | ||
498 | + private boolean isSupportedEthDstObjective(ForwardingObjective fwd) { | ||
499 | + TrafficSelector selector = fwd.selector(); | ||
500 | + EthCriterion ethDst = (EthCriterion) selector | ||
501 | + .getCriterion(Criterion.Type.ETH_DST); | ||
502 | + VlanIdCriterion vlanId = (VlanIdCriterion) selector | ||
503 | + .getCriterion(Criterion.Type.VLAN_VID); | ||
504 | + if (ethDst == null && vlanId == null) { | ||
505 | + return false; | ||
506 | + } | ||
507 | + return true; | ||
508 | + } | ||
509 | + | ||
510 | + protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) { | ||
511 | + log.debug("Processing specific"); | ||
512 | + boolean isEthTypeObj = isSupportedEthTypeObjective(fwd); | ||
513 | + boolean isEthDstObj = isSupportedEthDstObjective(fwd); | ||
514 | + | ||
515 | + if (isEthTypeObj) { | ||
516 | + return processEthTypeSpecificObjective(fwd); | ||
517 | + } else if (isEthDstObj) { | ||
518 | + return processEthDstSpecificObjective(fwd); | ||
519 | + } else { | ||
486 | log.warn("processSpecific: Unsupported " | 520 | log.warn("processSpecific: Unsupported " |
487 | + "forwarding objective criteraia"); | 521 | + "forwarding objective criteraia"); |
488 | fail(fwd, ObjectiveError.UNSUPPORTED); | 522 | fail(fwd, ObjectiveError.UNSUPPORTED); |
489 | return Collections.emptySet(); | 523 | return Collections.emptySet(); |
490 | } | 524 | } |
525 | + } | ||
526 | + | ||
527 | + protected Collection<FlowRule> | ||
528 | + processEthTypeSpecificObjective(ForwardingObjective fwd) { | ||
529 | + TrafficSelector selector = fwd.selector(); | ||
530 | + EthTypeCriterion ethType = (EthTypeCriterion) selector | ||
531 | + .getCriterion(Criterion.Type.ETH_TYPE); | ||
491 | 532 | ||
492 | TrafficSelector.Builder filteredSelectorBuilder = | 533 | TrafficSelector.Builder filteredSelectorBuilder = |
493 | DefaultTrafficSelector.builder(); | 534 | DefaultTrafficSelector.builder(); |
... | @@ -565,59 +606,167 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour | ... | @@ -565,59 +606,167 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour |
565 | 606 | ||
566 | } | 607 | } |
567 | 608 | ||
568 | - protected List<FlowRule> processEthDstFilter(Criterion c, | 609 | + protected Collection<FlowRule> |
610 | + processEthDstSpecificObjective(ForwardingObjective fwd) { | ||
611 | + List<FlowRule> rules = new ArrayList<>(); | ||
612 | + | ||
613 | + // Build filtered selector | ||
614 | + TrafficSelector selector = fwd.selector(); | ||
615 | + EthCriterion ethCriterion = (EthCriterion) selector | ||
616 | + .getCriterion(Criterion.Type.ETH_DST); | ||
617 | + VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector | ||
618 | + .getCriterion(Criterion.Type.VLAN_VID); | ||
619 | + TrafficSelector.Builder filteredSelectorBuilder = | ||
620 | + DefaultTrafficSelector.builder(); | ||
621 | + // Do not match MacAddress for subnet broadcast entry | ||
622 | + if (!ethCriterion.mac().equals(MacAddress.NONE)) { | ||
623 | + filteredSelectorBuilder.matchEthDst(ethCriterion.mac()); | ||
624 | + } | ||
625 | + filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId()); | ||
626 | + TrafficSelector filteredSelector = filteredSelectorBuilder.build(); | ||
627 | + | ||
628 | + // Build filtered treatment | ||
629 | + TrafficTreatment.Builder treatmentBuilder = | ||
630 | + DefaultTrafficTreatment.builder(); | ||
631 | + if (fwd.treatment() != null) { | ||
632 | + treatmentBuilder.deferred(); | ||
633 | + fwd.treatment().allInstructions().forEach(treatmentBuilder::add); | ||
634 | + } | ||
635 | + if (fwd.nextId() != null) { | ||
636 | + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId()); | ||
637 | + if (next != null) { | ||
638 | + GroupKey key = appKryo.deserialize(next.data()); | ||
639 | + Group group = groupService.getGroup(deviceId, key); | ||
640 | + if (group != null) { | ||
641 | + treatmentBuilder.deferred().group(group.id()); | ||
642 | + } else { | ||
643 | + log.warn("Group Missing"); | ||
644 | + fail(fwd, ObjectiveError.GROUPMISSING); | ||
645 | + return Collections.emptySet(); | ||
646 | + } | ||
647 | + } | ||
648 | + } | ||
649 | + treatmentBuilder.immediate().transition(aclTableId); | ||
650 | + TrafficTreatment filteredTreatment = treatmentBuilder.build(); | ||
651 | + | ||
652 | + // Build bridging table entries | ||
653 | + FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder(); | ||
654 | + flowRuleBuilder.fromApp(fwd.appId()) | ||
655 | + .withPriority(fwd.priority()) | ||
656 | + .forDevice(deviceId) | ||
657 | + .withSelector(filteredSelector) | ||
658 | + .withTreatment(filteredTreatment) | ||
659 | + .forTable(dstMacTableId); | ||
660 | + if (fwd.permanent()) { | ||
661 | + flowRuleBuilder.makePermanent(); | ||
662 | + } else { | ||
663 | + flowRuleBuilder.makeTemporary(fwd.timeout()); | ||
664 | + } | ||
665 | + rules.add(flowRuleBuilder.build()); | ||
666 | + | ||
667 | + /* | ||
668 | + // TODO Emulate source MAC table behavior | ||
669 | + // Do not install source MAC table entry for subnet broadcast | ||
670 | + if (!ethCriterion.mac().equals(MacAddress.NONE)) { | ||
671 | + // Build filtered selector | ||
672 | + selector = fwd.selector(); | ||
673 | + ethCriterion = (EthCriterion) selector.getCriterion(Criterion.Type.ETH_DST); | ||
674 | + filteredSelectorBuilder = DefaultTrafficSelector.builder(); | ||
675 | + filteredSelectorBuilder.matchEthSrc(ethCriterion.mac()); | ||
676 | + filteredSelector = filteredSelectorBuilder.build(); | ||
677 | + | ||
678 | + // Build empty treatment. Apply existing instruction if match. | ||
679 | + treatmentBuilder = DefaultTrafficTreatment.builder(); | ||
680 | + filteredTreatment = treatmentBuilder.build(); | ||
681 | + | ||
682 | + // Build bridging table entries | ||
683 | + flowRuleBuilder = DefaultFlowRule.builder(); | ||
684 | + flowRuleBuilder.fromApp(fwd.appId()) | ||
685 | + .withPriority(fwd.priority()) | ||
686 | + .forDevice(deviceId) | ||
687 | + .withSelector(filteredSelector) | ||
688 | + .withTreatment(filteredTreatment) | ||
689 | + .forTable(srcMacTableId) | ||
690 | + .makePermanent(); | ||
691 | + rules.add(flowRuleBuilder.build()); | ||
692 | + } | ||
693 | + */ | ||
694 | + | ||
695 | + return rules; | ||
696 | + } | ||
697 | + | ||
698 | + protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion, | ||
699 | + VlanIdCriterion vlanIdCriterion, | ||
569 | FilteringObjective filt, | 700 | FilteringObjective filt, |
701 | + VlanId assignedVlan, | ||
570 | ApplicationId applicationId) { | 702 | ApplicationId applicationId) { |
703 | + //handling untagged packets via assigned VLAN | ||
704 | + if (vlanIdCriterion.vlanId() == VlanId.NONE) { | ||
705 | + vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); | ||
706 | + } | ||
707 | + | ||
708 | + /* | ||
709 | + * Note: CpqD switches do not handle MPLS-related operation properly | ||
710 | + * for a packet with VLAN tag. We pop VLAN here as a workaround. | ||
711 | + * Side effect: HostService learns redundant hosts with same MAC but | ||
712 | + * different VLAN. No known side effect on the network reachability. | ||
713 | + */ | ||
571 | List<FlowRule> rules = new ArrayList<>(); | 714 | List<FlowRule> rules = new ArrayList<>(); |
572 | - EthCriterion e = (EthCriterion) c; | ||
573 | TrafficSelector.Builder selectorIp = DefaultTrafficSelector | 715 | TrafficSelector.Builder selectorIp = DefaultTrafficSelector |
574 | .builder(); | 716 | .builder(); |
575 | TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment | 717 | TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment |
576 | .builder(); | 718 | .builder(); |
577 | - selectorIp.matchEthDst(e.mac()); | 719 | + selectorIp.matchEthDst(ethCriterion.mac()); |
578 | selectorIp.matchEthType(Ethernet.TYPE_IPV4); | 720 | selectorIp.matchEthType(Ethernet.TYPE_IPV4); |
721 | + selectorIp.matchVlanId(vlanIdCriterion.vlanId()); | ||
722 | + treatmentIp.popVlan(); | ||
579 | treatmentIp.transition(ipv4UnicastTableId); | 723 | treatmentIp.transition(ipv4UnicastTableId); |
580 | FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId) | 724 | FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId) |
581 | .withSelector(selectorIp.build()) | 725 | .withSelector(selectorIp.build()) |
582 | .withTreatment(treatmentIp.build()) | 726 | .withTreatment(treatmentIp.build()) |
583 | .withPriority(filt.priority()).fromApp(applicationId) | 727 | .withPriority(filt.priority()).fromApp(applicationId) |
584 | .makePermanent().forTable(tmacTableId).build(); | 728 | .makePermanent().forTable(tmacTableId).build(); |
585 | - log.debug("adding IP ETH rule for MAC: {}", e.mac()); | 729 | + log.debug("adding IP ETH rule for MAC: {}", ethCriterion.mac()); |
586 | rules.add(ruleIp); | 730 | rules.add(ruleIp); |
587 | 731 | ||
588 | TrafficSelector.Builder selectorMpls = DefaultTrafficSelector | 732 | TrafficSelector.Builder selectorMpls = DefaultTrafficSelector |
589 | .builder(); | 733 | .builder(); |
590 | TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment | 734 | TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment |
591 | .builder(); | 735 | .builder(); |
592 | - selectorMpls.matchEthDst(e.mac()); | 736 | + selectorMpls.matchEthDst(ethCriterion.mac()); |
593 | selectorMpls.matchEthType(Ethernet.MPLS_UNICAST); | 737 | selectorMpls.matchEthType(Ethernet.MPLS_UNICAST); |
738 | + selectorMpls.matchVlanId(vlanIdCriterion.vlanId()); | ||
739 | + treatmentMpls.popVlan(); | ||
594 | treatmentMpls.transition(mplsTableId); | 740 | treatmentMpls.transition(mplsTableId); |
595 | FlowRule ruleMpls = DefaultFlowRule.builder() | 741 | FlowRule ruleMpls = DefaultFlowRule.builder() |
596 | .forDevice(deviceId).withSelector(selectorMpls.build()) | 742 | .forDevice(deviceId).withSelector(selectorMpls.build()) |
597 | .withTreatment(treatmentMpls.build()) | 743 | .withTreatment(treatmentMpls.build()) |
598 | .withPriority(filt.priority()).fromApp(applicationId) | 744 | .withPriority(filt.priority()).fromApp(applicationId) |
599 | .makePermanent().forTable(tmacTableId).build(); | 745 | .makePermanent().forTable(tmacTableId).build(); |
600 | - log.debug("adding MPLS ETH rule for MAC: {}", e.mac()); | 746 | + log.debug("adding MPLS ETH rule for MAC: {}", ethCriterion.mac()); |
601 | rules.add(ruleMpls); | 747 | rules.add(ruleMpls); |
602 | 748 | ||
603 | return rules; | 749 | return rules; |
604 | } | 750 | } |
605 | 751 | ||
606 | - protected List<FlowRule> processVlanIdFilter(Criterion c, | 752 | + protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion, |
607 | FilteringObjective filt, | 753 | FilteringObjective filt, |
754 | + VlanId assignedVlan, | ||
608 | ApplicationId applicationId) { | 755 | ApplicationId applicationId) { |
609 | List<FlowRule> rules = new ArrayList<>(); | 756 | List<FlowRule> rules = new ArrayList<>(); |
610 | - VlanIdCriterion v = (VlanIdCriterion) c; | 757 | + log.debug("adding rule for VLAN: {}", vlanIdCriterion.vlanId()); |
611 | - log.debug("adding rule for VLAN: {}", v.vlanId()); | ||
612 | TrafficSelector.Builder selector = DefaultTrafficSelector | 758 | TrafficSelector.Builder selector = DefaultTrafficSelector |
613 | .builder(); | 759 | .builder(); |
614 | TrafficTreatment.Builder treatment = DefaultTrafficTreatment | 760 | TrafficTreatment.Builder treatment = DefaultTrafficTreatment |
615 | .builder(); | 761 | .builder(); |
616 | PortCriterion p = (PortCriterion) filt.key(); | 762 | PortCriterion p = (PortCriterion) filt.key(); |
617 | - if (v.vlanId() != VlanId.NONE) { | 763 | + if (vlanIdCriterion.vlanId() != VlanId.NONE) { |
618 | - selector.matchVlanId(v.vlanId()); | 764 | + selector.matchVlanId(vlanIdCriterion.vlanId()); |
619 | selector.matchInPort(p.port()); | 765 | selector.matchInPort(p.port()); |
620 | treatment.deferred().popVlan(); | 766 | treatment.deferred().popVlan(); |
767 | + } else { | ||
768 | + selector.matchInPort(p.port()); | ||
769 | + treatment.immediate().pushVlan().setVlanId(assignedVlan); | ||
621 | } | 770 | } |
622 | treatment.transition(tmacTableId); | 771 | treatment.transition(tmacTableId); |
623 | FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId) | 772 | FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId) |
... | @@ -641,30 +790,79 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour | ... | @@ -641,30 +790,79 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour |
641 | fail(filt, ObjectiveError.UNKNOWN); | 790 | fail(filt, ObjectiveError.UNKNOWN); |
642 | return; | 791 | return; |
643 | } | 792 | } |
793 | + | ||
794 | + EthCriterion ethCriterion = null; | ||
795 | + VlanIdCriterion vlanIdCriterion = null; | ||
796 | + | ||
644 | // convert filtering conditions for switch-intfs into flowrules | 797 | // convert filtering conditions for switch-intfs into flowrules |
645 | FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); | 798 | FlowRuleOperations.Builder ops = FlowRuleOperations.builder(); |
646 | - for (Criterion c : filt.conditions()) { | 799 | + |
647 | - if (c.type() == Criterion.Type.ETH_DST) { | 800 | + for (Criterion criterion : filt.conditions()) { |
648 | - for (FlowRule rule : processEthDstFilter(c, | 801 | + if (criterion.type() == Criterion.Type.ETH_DST) { |
649 | - filt, | 802 | + ethCriterion = (EthCriterion) criterion; |
650 | - applicationId)) { | 803 | + } else if (criterion.type() == Criterion.Type.VLAN_VID) { |
651 | - ops = install ? ops.add(rule) : ops.remove(rule); | 804 | + vlanIdCriterion = (VlanIdCriterion) criterion; |
652 | - } | 805 | + } else if (criterion.type() == Criterion.Type.IPV4_DST) { |
653 | - } else if (c.type() == Criterion.Type.VLAN_VID) { | ||
654 | - for (FlowRule rule : processVlanIdFilter(c, | ||
655 | - filt, | ||
656 | - applicationId)) { | ||
657 | - ops = install ? ops.add(rule) : ops.remove(rule); | ||
658 | - } | ||
659 | - } else if (c.type() == Criterion.Type.IPV4_DST) { | ||
660 | log.debug("driver does not process IP filtering rules as it " + | 806 | log.debug("driver does not process IP filtering rules as it " + |
661 | "sends all misses in the IP table to the controller"); | 807 | "sends all misses in the IP table to the controller"); |
662 | } else { | 808 | } else { |
663 | log.warn("Driver does not currently process filtering condition" | 809 | log.warn("Driver does not currently process filtering condition" |
664 | - + " of type: {}", c.type()); | 810 | + + " of type: {}", criterion.type()); |
665 | fail(filt, ObjectiveError.UNSUPPORTED); | 811 | fail(filt, ObjectiveError.UNSUPPORTED); |
666 | } | 812 | } |
667 | } | 813 | } |
814 | + | ||
815 | + VlanId assignedVlan = null; | ||
816 | + if (vlanIdCriterion != null && vlanIdCriterion.vlanId() == VlanId.NONE) { | ||
817 | + // Assign a VLAN ID to untagged packets | ||
818 | + if (filt.meta() == null) { | ||
819 | + log.error("Missing metadata in filtering objective required " | ||
820 | + + "for vlan assignment in dev {}", deviceId); | ||
821 | + fail(filt, ObjectiveError.BADPARAMS); | ||
822 | + return; | ||
823 | + } | ||
824 | + for (Instruction i : filt.meta().allInstructions()) { | ||
825 | + if (i instanceof ModVlanIdInstruction) { | ||
826 | + assignedVlan = ((ModVlanIdInstruction) i).vlanId(); | ||
827 | + } | ||
828 | + } | ||
829 | + if (assignedVlan == null) { | ||
830 | + log.error("Driver requires an assigned vlan-id to tag incoming " | ||
831 | + + "untagged packets. Not processing vlan filters on " | ||
832 | + + "device {}", deviceId); | ||
833 | + fail(filt, ObjectiveError.BADPARAMS); | ||
834 | + return; | ||
835 | + } | ||
836 | + } | ||
837 | + | ||
838 | + if (ethCriterion == null) { | ||
839 | + log.debug("filtering objective missing dstMac, cannot program TMAC table"); | ||
840 | + } else { | ||
841 | + for (FlowRule tmacRule : processEthDstFilter(ethCriterion, | ||
842 | + vlanIdCriterion, | ||
843 | + filt, | ||
844 | + assignedVlan, | ||
845 | + applicationId)) { | ||
846 | + log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}", | ||
847 | + tmacRule, deviceId); | ||
848 | + ops = install ? ops.add(tmacRule) : ops.remove(tmacRule); | ||
849 | + } | ||
850 | + } | ||
851 | + | ||
852 | + if (ethCriterion == null || vlanIdCriterion == null) { | ||
853 | + log.debug("filtering objective missing dstMac or vlan, cannot program" | ||
854 | + + "Vlan Table"); | ||
855 | + } else { | ||
856 | + for (FlowRule vlanRule : processVlanIdFilter(vlanIdCriterion, | ||
857 | + filt, | ||
858 | + assignedVlan, | ||
859 | + applicationId)) { | ||
860 | + log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}", | ||
861 | + vlanRule, deviceId); | ||
862 | + ops = install ? ops.add(vlanRule) : ops.remove(vlanRule); | ||
863 | + } | ||
864 | + } | ||
865 | + | ||
668 | // apply filtering flow rules | 866 | // apply filtering flow rules |
669 | flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { | 867 | flowRuleService.apply(ops.build(new FlowRuleOperationsContext() { |
670 | @Override | 868 | @Override |
... | @@ -686,10 +884,10 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour | ... | @@ -686,10 +884,10 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour |
686 | protected void setTableMissEntries() { | 884 | protected void setTableMissEntries() { |
687 | // set all table-miss-entries | 885 | // set all table-miss-entries |
688 | populateTableMissEntry(vlanTableId, true, false, false, -1); | 886 | populateTableMissEntry(vlanTableId, true, false, false, -1); |
689 | - populateTableMissEntry(tmacTableId, true, false, false, -1); | 887 | + populateTableMissEntry(tmacTableId, false, false, true, dstMacTableId); |
690 | - populateTableMissEntry(ipv4UnicastTableId, false, true, true, | 888 | + populateTableMissEntry(ipv4UnicastTableId, false, true, true, aclTableId); |
691 | - aclTableId); | ||
692 | populateTableMissEntry(mplsTableId, false, true, true, aclTableId); | 889 | populateTableMissEntry(mplsTableId, false, true, true, aclTableId); |
890 | + populateTableMissEntry(dstMacTableId, false, false, true, aclTableId); | ||
693 | populateTableMissEntry(aclTableId, false, false, false, -1); | 891 | populateTableMissEntry(aclTableId, false, false, false, -1); |
694 | } | 892 | } |
695 | 893 | ... | ... |
... | @@ -21,6 +21,7 @@ import java.util.List; | ... | @@ -21,6 +21,7 @@ import java.util.List; |
21 | 21 | ||
22 | import org.onlab.packet.Ethernet; | 22 | import org.onlab.packet.Ethernet; |
23 | import org.onlab.packet.MacAddress; | 23 | import org.onlab.packet.MacAddress; |
24 | +import org.onlab.packet.VlanId; | ||
24 | import org.onosproject.core.ApplicationId; | 25 | import org.onosproject.core.ApplicationId; |
25 | import org.onosproject.net.behaviour.NextGroup; | 26 | import org.onosproject.net.behaviour.NextGroup; |
26 | import org.onosproject.net.flow.DefaultFlowRule; | 27 | import org.onosproject.net.flow.DefaultFlowRule; |
... | @@ -34,6 +35,7 @@ import org.onosproject.net.flow.criteria.EthCriterion; | ... | @@ -34,6 +35,7 @@ import org.onosproject.net.flow.criteria.EthCriterion; |
34 | import org.onosproject.net.flow.criteria.EthTypeCriterion; | 35 | import org.onosproject.net.flow.criteria.EthTypeCriterion; |
35 | import org.onosproject.net.flow.criteria.IPCriterion; | 36 | import org.onosproject.net.flow.criteria.IPCriterion; |
36 | import org.onosproject.net.flow.criteria.MplsCriterion; | 37 | import org.onosproject.net.flow.criteria.MplsCriterion; |
38 | +import org.onosproject.net.flow.criteria.VlanIdCriterion; | ||
37 | import org.onosproject.net.flow.instructions.Instruction; | 39 | import org.onosproject.net.flow.instructions.Instruction; |
38 | import org.onosproject.net.flowobjective.FilteringObjective; | 40 | import org.onosproject.net.flowobjective.FilteringObjective; |
39 | import org.onosproject.net.flowobjective.ForwardingObjective; | 41 | import org.onosproject.net.flowobjective.ForwardingObjective; |
... | @@ -175,12 +177,13 @@ public class SpringOpenTTPDell extends SpringOpenTTP { | ... | @@ -175,12 +177,13 @@ public class SpringOpenTTPDell extends SpringOpenTTP { |
175 | //Dell switches need ETH_DST based match condition in all IP table entries. | 177 | //Dell switches need ETH_DST based match condition in all IP table entries. |
176 | //So while processing the ETH_DST based filtering objective, store | 178 | //So while processing the ETH_DST based filtering objective, store |
177 | //the device MAC to be used locally to use it while pushing the IP rules. | 179 | //the device MAC to be used locally to use it while pushing the IP rules. |
178 | - protected List<FlowRule> processEthDstFilter(Criterion c, | 180 | + protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion, |
181 | + VlanIdCriterion vlanIdCriterion, | ||
179 | FilteringObjective filt, | 182 | FilteringObjective filt, |
183 | + VlanId assignedVlan, | ||
180 | ApplicationId applicationId) { | 184 | ApplicationId applicationId) { |
181 | // Store device termination Mac to be used in IP flow entries | 185 | // Store device termination Mac to be used in IP flow entries |
182 | - EthCriterion e = (EthCriterion) c; | 186 | + deviceTMac = ethCriterion.mac(); |
183 | - deviceTMac = e.mac(); | ||
184 | 187 | ||
185 | log.debug("For now not adding any TMAC rules " | 188 | log.debug("For now not adding any TMAC rules " |
186 | + "into Dell switches as it is ignoring"); | 189 | + "into Dell switches as it is ignoring"); |
... | @@ -189,8 +192,9 @@ public class SpringOpenTTPDell extends SpringOpenTTP { | ... | @@ -189,8 +192,9 @@ public class SpringOpenTTPDell extends SpringOpenTTP { |
189 | } | 192 | } |
190 | 193 | ||
191 | @Override | 194 | @Override |
192 | - protected List<FlowRule> processVlanIdFilter(Criterion c, | 195 | + protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion, |
193 | FilteringObjective filt, | 196 | FilteringObjective filt, |
197 | + VlanId assignedVlan, | ||
194 | ApplicationId applicationId) { | 198 | ApplicationId applicationId) { |
195 | log.debug("For now not adding any VLAN rules " | 199 | log.debug("For now not adding any VLAN rules " |
196 | + "into Dell switches as it is ignoring"); | 200 | + "into Dell switches as it is ignoring"); | ... | ... |
-
Please register or login to post a comment