Saurav Das
Committed by Gerrit Code Review

Changes to vRouter to accomodate ofdpa and softrouter pipelines.

Adding arp-spa to flow from vRouter to distinguish between multiple untagged
interfaces with the same macAddress.

Change-Id: Ifd6e00f70c538c780c0f5728d9ba960a4c70b1db
...@@ -22,6 +22,7 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -22,6 +22,7 @@ import org.apache.felix.scr.annotations.Deactivate;
22 import org.apache.felix.scr.annotations.Reference; 22 import org.apache.felix.scr.annotations.Reference;
23 import org.apache.felix.scr.annotations.ReferenceCardinality; 23 import org.apache.felix.scr.annotations.ReferenceCardinality;
24 import org.onlab.packet.EthType; 24 import org.onlab.packet.EthType;
25 +import org.onlab.packet.VlanId;
25 import org.onosproject.core.ApplicationId; 26 import org.onosproject.core.ApplicationId;
26 import org.onosproject.core.CoreService; 27 import org.onosproject.core.CoreService;
27 import org.onosproject.incubator.net.intf.Interface; 28 import org.onosproject.incubator.net.intf.Interface;
...@@ -40,8 +41,10 @@ import org.onosproject.net.flow.DefaultTrafficTreatment; ...@@ -40,8 +41,10 @@ import org.onosproject.net.flow.DefaultTrafficTreatment;
40 import org.onosproject.net.flow.TrafficSelector; 41 import org.onosproject.net.flow.TrafficSelector;
41 import org.onosproject.net.flow.TrafficTreatment; 42 import org.onosproject.net.flow.TrafficTreatment;
42 import org.onosproject.net.flowobjective.DefaultForwardingObjective; 43 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
44 +import org.onosproject.net.flowobjective.DefaultNextObjective;
43 import org.onosproject.net.flowobjective.FlowObjectiveService; 45 import org.onosproject.net.flowobjective.FlowObjectiveService;
44 import org.onosproject.net.flowobjective.ForwardingObjective; 46 import org.onosproject.net.flowobjective.ForwardingObjective;
47 +import org.onosproject.net.flowobjective.NextObjective;
45 import org.onosproject.net.host.InterfaceIpAddress; 48 import org.onosproject.net.host.InterfaceIpAddress;
46 import org.onosproject.routing.RoutingService; 49 import org.onosproject.routing.RoutingService;
47 import org.onosproject.routing.config.RouterConfig; 50 import org.onosproject.routing.config.RouterConfig;
...@@ -110,7 +113,7 @@ public class ControlPlaneRedirectManager { ...@@ -110,7 +113,7 @@ public class ControlPlaneRedirectManager {
110 routingAppId, RoutingService.ROUTER_CONFIG_CLASS); 113 routingAppId, RoutingService.ROUTER_CONFIG_CLASS);
111 114
112 if (config == null) { 115 if (config == null) {
113 - log.info("Router config not available"); 116 + log.warn("Router config not available");
114 return; 117 return;
115 } 118 }
116 119
...@@ -145,6 +148,23 @@ public class ControlPlaneRedirectManager { ...@@ -145,6 +148,23 @@ public class ControlPlaneRedirectManager {
145 PortNumber controlPlanePort = controlPlaneConnectPoint.port(); 148 PortNumber controlPlanePort = controlPlaneConnectPoint.port();
146 149
147 for (InterfaceIpAddress ip : intf.ipAddresses()) { 150 for (InterfaceIpAddress ip : intf.ipAddresses()) {
151 + // create nextObjectives for forwarding to this interface and the
152 + // controlPlaneConnectPoint
153 + int cpNextId, intfNextId;
154 + if (intf.vlan() == VlanId.NONE) {
155 + cpNextId = createNextObjective(deviceId, controlPlanePort,
156 + VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
157 + true);
158 + intfNextId = createNextObjective(deviceId, intf.connectPoint().port(),
159 + VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
160 + true);
161 + } else {
162 + cpNextId = createNextObjective(deviceId, controlPlanePort,
163 + intf.vlan(), false);
164 + intfNextId = createNextObjective(deviceId, intf.connectPoint().port(),
165 + intf.vlan(), false);
166 + }
167 +
148 // IPv4 to router 168 // IPv4 to router
149 TrafficSelector toSelector = DefaultTrafficSelector.builder() 169 TrafficSelector toSelector = DefaultTrafficSelector.builder()
150 .matchInPort(intf.connectPoint().port()) 170 .matchInPort(intf.connectPoint().port())
...@@ -154,12 +174,8 @@ public class ControlPlaneRedirectManager { ...@@ -154,12 +174,8 @@ public class ControlPlaneRedirectManager {
154 .matchIPDst(ip.ipAddress().toIpPrefix()) 174 .matchIPDst(ip.ipAddress().toIpPrefix())
155 .build(); 175 .build();
156 176
157 - TrafficTreatment toTreatment = DefaultTrafficTreatment.builder()
158 - .setOutput(controlPlanePort)
159 - .build();
160 -
161 flowObjectiveService.forward(deviceId, 177 flowObjectiveService.forward(deviceId,
162 - buildForwardingObjective(toSelector, toTreatment, true)); 178 + buildForwardingObjective(toSelector, null, cpNextId, true));
163 179
164 // IPv4 from router 180 // IPv4 from router
165 TrafficSelector fromSelector = DefaultTrafficSelector.builder() 181 TrafficSelector fromSelector = DefaultTrafficSelector.builder()
...@@ -170,12 +186,8 @@ public class ControlPlaneRedirectManager { ...@@ -170,12 +186,8 @@ public class ControlPlaneRedirectManager {
170 .matchIPSrc(ip.ipAddress().toIpPrefix()) 186 .matchIPSrc(ip.ipAddress().toIpPrefix())
171 .build(); 187 .build();
172 188
173 - TrafficTreatment intfTreatment = DefaultTrafficTreatment.builder()
174 - .setOutput(intf.connectPoint().port())
175 - .build();
176 -
177 flowObjectiveService.forward(deviceId, 189 flowObjectiveService.forward(deviceId,
178 - buildForwardingObjective(fromSelector, intfTreatment, true)); 190 + buildForwardingObjective(fromSelector, null, intfNextId, true));
179 191
180 // ARP to router 192 // ARP to router
181 toSelector = DefaultTrafficSelector.builder() 193 toSelector = DefaultTrafficSelector.builder()
...@@ -184,13 +196,12 @@ public class ControlPlaneRedirectManager { ...@@ -184,13 +196,12 @@ public class ControlPlaneRedirectManager {
184 .matchVlanId(intf.vlan()) 196 .matchVlanId(intf.vlan())
185 .build(); 197 .build();
186 198
187 - toTreatment = DefaultTrafficTreatment.builder() 199 + TrafficTreatment puntTreatment = DefaultTrafficTreatment.builder()
188 - .setOutput(controlPlanePort)
189 .punt() 200 .punt()
190 .build(); 201 .build();
191 202
192 flowObjectiveService.forward(deviceId, 203 flowObjectiveService.forward(deviceId,
193 - buildForwardingObjective(toSelector, toTreatment, true)); 204 + buildForwardingObjective(toSelector, puntTreatment, cpNextId, true));
194 205
195 // ARP from router 206 // ARP from router
196 fromSelector = DefaultTrafficSelector.builder() 207 fromSelector = DefaultTrafficSelector.builder()
...@@ -198,15 +209,11 @@ public class ControlPlaneRedirectManager { ...@@ -198,15 +209,11 @@ public class ControlPlaneRedirectManager {
198 .matchEthSrc(intf.mac()) 209 .matchEthSrc(intf.mac())
199 .matchVlanId(intf.vlan()) 210 .matchVlanId(intf.vlan())
200 .matchEthType(EthType.EtherType.ARP.ethType().toShort()) 211 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
201 - .build(); 212 + .matchArpSpa(ip.ipAddress().getIp4Address())
202 -
203 - intfTreatment = DefaultTrafficTreatment.builder()
204 - .setOutput(intf.connectPoint().port())
205 - .punt()
206 .build(); 213 .build();
207 214
208 flowObjectiveService.forward(deviceId, 215 flowObjectiveService.forward(deviceId,
209 - buildForwardingObjective(fromSelector, intfTreatment, true)); 216 + buildForwardingObjective(fromSelector, puntTreatment, intfNextId, true));
210 } 217 }
211 } 218 }
212 219
...@@ -219,31 +226,83 @@ public class ControlPlaneRedirectManager { ...@@ -219,31 +226,83 @@ public class ControlPlaneRedirectManager {
219 .matchIPProtocol((byte) OSPF_IP_PROTO) 226 .matchIPProtocol((byte) OSPF_IP_PROTO)
220 .build(); 227 .build();
221 228
222 - TrafficTreatment toTreatment = DefaultTrafficTreatment.builder() 229 + // create nextObjectives for forwarding to the controlPlaneConnectPoint
223 - .setOutput(controlPlaneConnectPoint.port()) 230 + DeviceId deviceId = controlPlaneConnectPoint.deviceId();
224 - .build(); 231 + PortNumber controlPlanePort = controlPlaneConnectPoint.port();
225 - 232 + int cpNextId;
233 + if (intf.vlan() == VlanId.NONE) {
234 + cpNextId = createNextObjective(deviceId, controlPlanePort,
235 + VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN),
236 + true);
237 + } else {
238 + cpNextId = createNextObjective(deviceId, controlPlanePort,
239 + intf.vlan(), false);
240 + }
241 + log.debug("ospf flows intf:{} nextid:{}", intf, cpNextId);
226 flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(), 242 flowObjectiveService.forward(controlPlaneConnectPoint.deviceId(),
227 - buildForwardingObjective(toSelector, toTreatment, ospfEnabled)); 243 + buildForwardingObjective(toSelector, null, cpNextId, ospfEnabled));
228 } 244 }
229 245
230 /** 246 /**
231 - * Builds a forwarding objective from the given selector and treatment. 247 + * Creates a next objective for forwarding to a port. Handles metadata for
248 + * some pipelines that require vlan information for egress port.
249 + *
250 + * @param deviceId the device on which the next objective is being created
251 + * @param portNumber the egress port
252 + * @param vlanId vlan information for egress port
253 + * @param popVlan if vlan tag should be popped or not
254 + * @return nextId of the next objective created
255 + */
256 + private int createNextObjective(DeviceId deviceId, PortNumber portNumber,
257 + VlanId vlanId, boolean popVlan) {
258 + int nextId = flowObjectiveService.allocateNextId();
259 + NextObjective.Builder nextObjBuilder = DefaultNextObjective
260 + .builder().withId(nextId)
261 + .withType(NextObjective.Type.SIMPLE)
262 + .fromApp(appId);
263 +
264 + TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
265 + if (popVlan) {
266 + ttBuilder.popVlan();
267 + }
268 + ttBuilder.setOutput(portNumber);
269 +
270 + // setup metadata to pass to nextObjective - indicate the vlan on egress
271 + // if needed by the switch pipeline.
272 + TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
273 + metabuilder.matchVlanId(vlanId);
274 +
275 + nextObjBuilder.withMeta(metabuilder.build());
276 + nextObjBuilder.addTreatment(ttBuilder.build());
277 + log.debug("Submited next objective {} in device {} for port/vlan {}/{}",
278 + nextId, deviceId, portNumber, vlanId);
279 + flowObjectiveService.next(deviceId, nextObjBuilder.add());
280 + return nextId;
281 + }
282 +
283 + /**
284 + * Builds a forwarding objective from the given selector, treatment and nextId.
232 * 285 *
233 * @param selector selector 286 * @param selector selector
234 - * @param treatment treatment 287 + * @param treatment treatment to apply to packet, can be null
288 + * @param nextId next objective to point to for forwarding packet
235 * @param add true to create an add objective, false to create a remove 289 * @param add true to create an add objective, false to create a remove
236 * objective 290 * objective
237 * @return forwarding objective 291 * @return forwarding objective
238 */ 292 */
239 private ForwardingObjective buildForwardingObjective(TrafficSelector selector, 293 private ForwardingObjective buildForwardingObjective(TrafficSelector selector,
240 TrafficTreatment treatment, 294 TrafficTreatment treatment,
295 + int nextId,
241 boolean add) { 296 boolean add) {
242 - 297 + DefaultForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder();
243 - ForwardingObjective.Builder fobBuilder = DefaultForwardingObjective.builder() 298 + fobBuilder.withSelector(selector);
244 - .withSelector(selector) 299 + if (treatment != null) {
245 - .withTreatment(treatment) 300 + fobBuilder.withTreatment(treatment);
246 - .fromApp(appId) 301 + }
302 + if (nextId != -1) {
303 + fobBuilder.nextStep(nextId);
304 + }
305 + fobBuilder.fromApp(appId)
247 .withPriority(PRIORITY) 306 .withPriority(PRIORITY)
248 .withFlag(ForwardingObjective.Flag.VERSATILE); 307 .withFlag(ForwardingObjective.Flag.VERSATILE);
249 308
......
...@@ -34,6 +34,7 @@ import org.onosproject.core.ApplicationId; ...@@ -34,6 +34,7 @@ import org.onosproject.core.ApplicationId;
34 import org.onosproject.core.CoreService; 34 import org.onosproject.core.CoreService;
35 import org.onosproject.incubator.net.intf.Interface; 35 import org.onosproject.incubator.net.intf.Interface;
36 import org.onosproject.incubator.net.intf.InterfaceService; 36 import org.onosproject.incubator.net.intf.InterfaceService;
37 +import org.onosproject.net.ConnectPoint;
37 import org.onosproject.net.DeviceId; 38 import org.onosproject.net.DeviceId;
38 import org.onosproject.net.config.NetworkConfigEvent; 39 import org.onosproject.net.config.NetworkConfigEvent;
39 import org.onosproject.net.config.NetworkConfigListener; 40 import org.onosproject.net.config.NetworkConfigListener;
...@@ -80,6 +81,8 @@ public class SingleSwitchFibInstaller { ...@@ -80,6 +81,8 @@ public class SingleSwitchFibInstaller {
80 private static final int PRIORITY_OFFSET = 100; 81 private static final int PRIORITY_OFFSET = 100;
81 private static final int PRIORITY_MULTIPLIER = 5; 82 private static final int PRIORITY_MULTIPLIER = 5;
82 83
84 + public static final short ASSIGNED_VLAN = 4094;
85 +
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected CoreService coreService; 87 protected CoreService coreService;
85 88
...@@ -103,7 +106,8 @@ public class SingleSwitchFibInstaller { ...@@ -103,7 +106,8 @@ public class SingleSwitchFibInstaller {
103 // Device id of data-plane switch - should be learned from config 106 // Device id of data-plane switch - should be learned from config
104 private DeviceId deviceId; 107 private DeviceId deviceId;
105 108
106 - private ApplicationId appId; 109 + private ConnectPoint controlPlaneConnectPoint;
110 +
107 private ApplicationId routerAppId; 111 private ApplicationId routerAppId;
108 112
109 // Reference count for how many times a next hop is used by a route 113 // Reference count for how many times a next hop is used by a route
...@@ -121,11 +125,8 @@ public class SingleSwitchFibInstaller { ...@@ -121,11 +125,8 @@ public class SingleSwitchFibInstaller {
121 125
122 @Activate 126 @Activate
123 protected void activate() { 127 protected void activate() {
124 - // TODO why are there two of the same app ID?
125 routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID); 128 routerAppId = coreService.registerApplication(RoutingService.ROUTER_APP_ID);
126 129
127 - appId = coreService.getAppId(RoutingService.ROUTER_APP_ID);
128 -
129 deviceListener = new InternalDeviceListener(); 130 deviceListener = new InternalDeviceListener();
130 deviceService.addListener(deviceListener); 131 deviceService.addListener(deviceListener);
131 132
...@@ -156,6 +157,8 @@ public class SingleSwitchFibInstaller { ...@@ -156,6 +157,8 @@ public class SingleSwitchFibInstaller {
156 log.info("Router config not available"); 157 log.info("Router config not available");
157 return; 158 return;
158 } 159 }
160 + controlPlaneConnectPoint = routerConfig.getControlPlaneConnectPoint();
161 + log.info("Control Plane Connect Point: {}", controlPlaneConnectPoint);
159 162
160 deviceId = routerConfig.getControlPlaneConnectPoint().deviceId(); 163 deviceId = routerConfig.getControlPlaneConnectPoint().deviceId();
161 164
...@@ -231,7 +234,7 @@ public class SingleSwitchFibInstaller { ...@@ -231,7 +234,7 @@ public class SingleSwitchFibInstaller {
231 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET; 234 int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
232 235
233 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder() 236 ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder()
234 - .fromApp(appId) 237 + .fromApp(routerAppId)
235 .makePermanent() 238 .makePermanent()
236 .withSelector(selector) 239 .withSelector(selector)
237 .withPriority(priority) 240 .withPriority(priority)
...@@ -266,23 +269,30 @@ public class SingleSwitchFibInstaller { ...@@ -266,23 +269,30 @@ public class SingleSwitchFibInstaller {
266 .setEthSrc(egressIntf.mac()) 269 .setEthSrc(egressIntf.mac())
267 .setEthDst(nextHop.mac()); 270 .setEthDst(nextHop.mac());
268 271
272 + TrafficSelector.Builder metabuilder = null;
269 if (!egressIntf.vlan().equals(VlanId.NONE)) { 273 if (!egressIntf.vlan().equals(VlanId.NONE)) {
270 treatment.pushVlan() 274 treatment.pushVlan()
271 .setVlanId(egressIntf.vlan()) 275 .setVlanId(egressIntf.vlan())
272 .setVlanPcp((byte) 0); 276 .setVlanPcp((byte) 0);
277 + } else {
278 + // untagged outgoing port may require internal vlan in some pipelines
279 + metabuilder = DefaultTrafficSelector.builder();
280 + metabuilder.matchVlanId(VlanId.vlanId(ASSIGNED_VLAN));
273 } 281 }
274 282
275 treatment.setOutput(egressIntf.connectPoint().port()); 283 treatment.setOutput(egressIntf.connectPoint().port());
276 284
277 int nextId = flowObjectiveService.allocateNextId(); 285 int nextId = flowObjectiveService.allocateNextId();
278 - 286 + NextObjective.Builder nextBuilder = DefaultNextObjective.builder()
279 - NextObjective nextObjective = DefaultNextObjective.builder()
280 .withId(nextId) 287 .withId(nextId)
281 .addTreatment(treatment.build()) 288 .addTreatment(treatment.build())
282 .withType(NextObjective.Type.SIMPLE) 289 .withType(NextObjective.Type.SIMPLE)
283 - .fromApp(appId) 290 + .fromApp(routerAppId);
284 - .add(); // TODO add callbacks 291 + if (metabuilder != null) {
292 + nextBuilder.withMeta(metabuilder.build());
293 + }
285 294
295 + NextObjective nextObjective = nextBuilder.add(); // TODO add callbacks
286 flowObjectiveService.next(deviceId, nextObjective); 296 flowObjectiveService.next(deviceId, nextObjective);
287 297
288 nextHops.put(nextHop.ip(), nextId); 298 nextHops.put(nextHop.ip(), nextId);
...@@ -329,13 +339,29 @@ public class SingleSwitchFibInstaller { ...@@ -329,13 +339,29 @@ public class SingleSwitchFibInstaller {
329 } 339 }
330 340
331 FilteringObjective.Builder fob = DefaultFilteringObjective.builder(); 341 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
342 + // first add filter for the interface
332 fob.withKey(Criteria.matchInPort(intf.connectPoint().port())) 343 fob.withKey(Criteria.matchInPort(intf.connectPoint().port()))
333 .addCondition(Criteria.matchEthDst(intf.mac())) 344 .addCondition(Criteria.matchEthDst(intf.mac()))
334 .addCondition(Criteria.matchVlanId(intf.vlan())); 345 .addCondition(Criteria.matchVlanId(intf.vlan()));
335 -
336 fob.withPriority(PRIORITY_OFFSET); 346 fob.withPriority(PRIORITY_OFFSET);
347 + if (intf.vlan() == VlanId.NONE) {
348 + TrafficTreatment tt = DefaultTrafficTreatment.builder()
349 + .pushVlan().setVlanId(VlanId.vlanId(ASSIGNED_VLAN)).build();
350 + fob.withMeta(tt);
351 + }
352 +
353 + fob.permit().fromApp(routerAppId);
354 + sendFilteringObjective(install, fob, intf);
355 + if (controlPlaneConnectPoint != null) {
356 + // then add the same mac/vlan filters for control-plane connect point
357 + fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port()));
358 + sendFilteringObjective(install, fob, intf);
359 + }
360 + }
361 + }
337 362
338 - fob.permit().fromApp(appId); 363 + private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob,
364 + Interface intf) {
339 flowObjectiveService.filter( 365 flowObjectiveService.filter(
340 deviceId, 366 deviceId,
341 fob.add(new ObjectiveContext() { 367 fob.add(new ObjectiveContext() {
...@@ -354,7 +380,6 @@ public class SingleSwitchFibInstaller { ...@@ -354,7 +380,6 @@ public class SingleSwitchFibInstaller {
354 } 380 }
355 })); 381 }));
356 } 382 }
357 - }
358 383
359 private class InternalFibListener implements FibListener { 384 private class InternalFibListener implements FibListener {
360 385
......
...@@ -387,11 +387,12 @@ public class FlowObjectiveManager implements FlowObjectiveService { ...@@ -387,11 +387,12 @@ public class FlowObjectiveManager implements FlowObjectiveService {
387 Set<PendingNext> pending = pendingForwards.remove(event.subject()); 387 Set<PendingNext> pending = pendingForwards.remove(event.subject());
388 388
389 if (pending == null) { 389 if (pending == null) {
390 - log.debug("Nothing pending for this obj event"); 390 + log.warn("Nothing pending for this obj event {}", event);
391 return; 391 return;
392 } 392 }
393 393
394 - log.debug("Processing pending forwarding objectives {}", pending.size()); 394 + log.debug("Processing {} pending forwarding objectives for nextId {}",
395 + pending.size(), event.subject());
395 pending.forEach(p -> getDevicePipeliner(p.deviceId()) 396 pending.forEach(p -> getDevicePipeliner(p.deviceId())
396 .forward(p.forwardingObjective())); 397 .forward(p.forwardingObjective()));
397 } 398 }
......
...@@ -584,35 +584,60 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -584,35 +584,60 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
584 + "nextId or Treatment", fwd.selector(), fwd.appId()); 584 + "nextId or Treatment", fwd.selector(), fwd.appId());
585 return Collections.emptySet(); 585 return Collections.emptySet();
586 } 586 }
587 +
587 // XXX driver does not currently do type checking as per Tables 65-67 in 588 // XXX driver does not currently do type checking as per Tables 65-67 in
588 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller. 589 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
589 - if (fwd.treatment() != null && 590 + TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
590 - fwd.treatment().allInstructions().size() == 1 && 591 + if (fwd.treatment() != null) {
591 - fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { 592 + for (Instruction ins : fwd.treatment().allInstructions()) {
592 - OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); 593 + if (ins instanceof OutputInstruction) {
594 + OutputInstruction o = (OutputInstruction) ins;
593 if (o.port() == PortNumber.CONTROLLER) { 595 if (o.port() == PortNumber.CONTROLLER) {
594 - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() 596 + ttBuilder.add(o);
595 - .fromApp(fwd.appId())
596 - .withPriority(fwd.priority())
597 - .forDevice(deviceId)
598 - .withSelector(fwd.selector())
599 - .withTreatment(fwd.treatment())
600 - .makePermanent()
601 - .forTable(ACL_TABLE);
602 - return Collections.singletonList(ruleBuilder.build());
603 } else { 597 } else {
604 log.warn("Only allowed treatments in versatile forwarding " 598 log.warn("Only allowed treatments in versatile forwarding "
605 + "objectives are punts to the controller"); 599 + "objectives are punts to the controller");
606 - return Collections.emptySet(); 600 + }
601 + } else {
602 + log.warn("Cannot process instruction in versatile fwd {}", ins);
607 } 603 }
608 } 604 }
609 -
610 - if (fwd.nextId() != null) {
611 - // XXX overide case
612 - log.warn("versatile objective --> next Id not yet implemeted");
613 } 605 }
606 + if (fwd.nextId() != null) {
607 + // overide case
608 + NextGroup next = getGroupForNextObjective(fwd.nextId());
609 + List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
610 + // we only need the top level group's key to point the flow to it
611 + Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
612 + if (group == null) {
613 + log.warn("Group with key:{} for next-id:{} not found in dev:{}",
614 + gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
615 + fail(fwd, ObjectiveError.GROUPMISSING);
614 return Collections.emptySet(); 616 return Collections.emptySet();
615 } 617 }
618 + ttBuilder.deferred().group(group.id());
619 + }
620 + // ensure that match does not include vlan = NONE as OF-DPA does not
621 + // match untagged packets this way in the ACL table.
622 + TrafficSelector.Builder selBuilder = DefaultTrafficSelector.builder();
623 + for (Criterion criterion : fwd.selector().criteria()) {
624 + if (criterion instanceof VlanIdCriterion &&
625 + ((VlanIdCriterion) criterion).vlanId() == VlanId.NONE) {
626 + continue;
627 + }
628 + selBuilder.add(criterion);
629 + }
630 +
631 + FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
632 + .fromApp(fwd.appId())
633 + .withPriority(fwd.priority())
634 + .forDevice(deviceId)
635 + .withSelector(selBuilder.build())
636 + .withTreatment(ttBuilder.build())
637 + .makePermanent()
638 + .forTable(ACL_TABLE);
639 + return Collections.singletonList(ruleBuilder.build());
640 + }
616 641
617 /** 642 /**
618 * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table 643 * In the OF-DPA 2.0 pipeline, specific forwarding refers to the IP table
......
...@@ -42,6 +42,8 @@ import org.onosproject.net.flow.criteria.EthTypeCriterion; ...@@ -42,6 +42,8 @@ import org.onosproject.net.flow.criteria.EthTypeCriterion;
42 import org.onosproject.net.flow.criteria.IPCriterion; 42 import org.onosproject.net.flow.criteria.IPCriterion;
43 import org.onosproject.net.flow.criteria.PortCriterion; 43 import org.onosproject.net.flow.criteria.PortCriterion;
44 import org.onosproject.net.flow.criteria.VlanIdCriterion; 44 import org.onosproject.net.flow.criteria.VlanIdCriterion;
45 +import org.onosproject.net.flow.instructions.Instruction;
46 +import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
45 import org.onosproject.net.flowobjective.FilteringObjective; 47 import org.onosproject.net.flowobjective.FilteringObjective;
46 import org.onosproject.net.flowobjective.FlowObjectiveStore; 48 import org.onosproject.net.flowobjective.FlowObjectiveStore;
47 import org.onosproject.net.flowobjective.ForwardingObjective; 49 import org.onosproject.net.flowobjective.ForwardingObjective;
...@@ -50,6 +52,7 @@ import org.onosproject.net.flowobjective.Objective; ...@@ -50,6 +52,7 @@ import org.onosproject.net.flowobjective.Objective;
50 import org.onosproject.net.flowobjective.ObjectiveError; 52 import org.onosproject.net.flowobjective.ObjectiveError;
51 import org.onosproject.store.serializers.KryoNamespaces; 53 import org.onosproject.store.serializers.KryoNamespaces;
52 import org.slf4j.Logger; 54 import org.slf4j.Logger;
55 +import static org.onlab.util.Tools.delay;
53 56
54 import java.util.ArrayList; 57 import java.util.ArrayList;
55 import java.util.Collection; 58 import java.util.Collection;
...@@ -314,19 +317,50 @@ public class SoftRouterPipeline extends AbstractHandlerBehaviour implements Pipe ...@@ -314,19 +317,50 @@ public class SoftRouterPipeline extends AbstractHandlerBehaviour implements Pipe
314 } 317 }
315 318
316 /** 319 /**
317 - * SoftRouter has a single versatile table - the filter table. All versatile 320 + * SoftRouter has a single versatile table - the filter table.
318 - * flow rules must include the filtering rules. 321 + * This table can be used to filter entries that reach the next table (FIB table).
322 + * It can also be used to punt packets to the controller and/or bypass
323 + * the FIB table to forward out of a port.
319 * 324 *
320 * @param fwd The forwarding objective of type versatile 325 * @param fwd The forwarding objective of type versatile
321 * @return A collection of flow rules meant to be delivered to the flowrule 326 * @return A collection of flow rules meant to be delivered to the flowrule
322 * subsystem. May return empty collection in case of failures. 327 * subsystem. May return empty collection in case of failures.
323 */ 328 */
324 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) { 329 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
330 + log.debug("Received versatile fwd: to next:{}", fwd.nextId());
325 Collection<FlowRule> flowrules = new ArrayList<>(); 331 Collection<FlowRule> flowrules = new ArrayList<>();
332 + if (fwd.nextId() == null && fwd.treatment() == null) {
333 + log.error("Forwarding objective {} from {} must contain "
334 + + "nextId or Treatment", fwd.selector(), fwd.appId());
335 + return Collections.emptySet();
336 + }
337 + TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
338 + if (fwd.treatment() != null) {
339 + fwd.treatment().immediate().forEach(ins -> ttBuilder.add(ins));
340 + }
341 + //convert nextId to flow actions
342 + if (fwd.nextId() != null) {
343 + // only acceptable value is output to port
344 + NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
345 + if (next == null) {
346 + log.error("next-id {} does not exist in store", fwd.nextId());
347 + return Collections.emptySet();
348 + }
349 + TrafficTreatment nt = appKryo.deserialize(next.data());
350 + if (nt == null) {
351 + log.error("Error in deserializing next-id {}", fwd.nextId());
352 + return Collections.emptySet();
353 + }
354 + for (Instruction ins : nt.allInstructions()) {
355 + if (ins instanceof OutputInstruction) {
356 + ttBuilder.add(ins);
357 + }
358 + }
359 + }
326 360
327 FlowRule rule = DefaultFlowRule.builder() 361 FlowRule rule = DefaultFlowRule.builder()
328 .withSelector(fwd.selector()) 362 .withSelector(fwd.selector())
329 - .withTreatment(fwd.treatment()) 363 + .withTreatment(ttBuilder.build())
330 .makePermanent() 364 .makePermanent()
331 .forDevice(deviceId) 365 .forDevice(deviceId)
332 .fromApp(fwd.appId()) 366 .fromApp(fwd.appId())
...@@ -350,7 +384,7 @@ public class SoftRouterPipeline extends AbstractHandlerBehaviour implements Pipe ...@@ -350,7 +384,7 @@ public class SoftRouterPipeline extends AbstractHandlerBehaviour implements Pipe
350 * 384 *
351 */ 385 */
352 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) { 386 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
353 - log.debug("Processing specific forwarding objective"); 387 + log.debug("Processing specific forwarding objective to next:{}", fwd.nextId());
354 TrafficSelector selector = fwd.selector(); 388 TrafficSelector selector = fwd.selector();
355 EthTypeCriterion ethType = 389 EthTypeCriterion ethType =
356 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE); 390 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
...@@ -411,6 +445,9 @@ public class SoftRouterPipeline extends AbstractHandlerBehaviour implements Pipe ...@@ -411,6 +445,9 @@ public class SoftRouterPipeline extends AbstractHandlerBehaviour implements Pipe
411 */ 445 */
412 private void processSimpleNextObjective(NextObjective nextObj) { 446 private void processSimpleNextObjective(NextObjective nextObj) {
413 // Simple next objective has a single treatment (not a collection) 447 // Simple next objective has a single treatment (not a collection)
448 + log.debug("Received nextObj {}", nextObj.id());
449 + // delay processing to emulate group creation
450 + delay(50);
414 TrafficTreatment treatment = nextObj.next().iterator().next(); 451 TrafficTreatment treatment = nextObj.next().iterator().next();
415 flowObjectiveStore.putNextGroup(nextObj.id(), 452 flowObjectiveStore.putNextGroup(nextObj.id(),
416 new DummyGroup(treatment)); 453 new DummyGroup(treatment));
......