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
Showing
5 changed files
with
240 additions
and
93 deletions
| ... | @@ -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,33 +226,85 @@ public class ControlPlaneRedirectManager { | ... | @@ -219,33 +226,85 @@ 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 | + } |
| 247 | - .withPriority(PRIORITY) | 302 | + if (nextId != -1) { |
| 248 | - .withFlag(ForwardingObjective.Flag.VERSATILE); | 303 | + fobBuilder.nextStep(nextId); |
| 304 | + } | ||
| 305 | + fobBuilder.fromApp(appId) | ||
| 306 | + .withPriority(PRIORITY) | ||
| 307 | + .withFlag(ForwardingObjective.Flag.VERSATILE); | ||
| 249 | 308 | ||
| 250 | return add ? fobBuilder.add() : fobBuilder.remove(); | 309 | return add ? fobBuilder.add() : fobBuilder.remove(); |
| 251 | } | 310 | } | ... | ... |
| ... | @@ -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,33 +339,48 @@ public class SingleSwitchFibInstaller { | ... | @@ -329,33 +339,48 @@ 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 | + } | ||
| 337 | 352 | ||
| 338 | - fob.permit().fromApp(appId); | 353 | + fob.permit().fromApp(routerAppId); |
| 339 | - flowObjectiveService.filter( | 354 | + sendFilteringObjective(install, fob, intf); |
| 340 | - deviceId, | 355 | + if (controlPlaneConnectPoint != null) { |
| 341 | - fob.add(new ObjectiveContext() { | 356 | + // then add the same mac/vlan filters for control-plane connect point |
| 342 | - @Override | 357 | + fob.withKey(Criteria.matchInPort(controlPlaneConnectPoint.port())); |
| 343 | - public void onSuccess(Objective objective) { | 358 | + sendFilteringObjective(install, fob, intf); |
| 344 | - log.info("Successfully installed interface based " | 359 | + } |
| 345 | - + "filtering objectives for intf {}", intf); | ||
| 346 | - } | ||
| 347 | - | ||
| 348 | - @Override | ||
| 349 | - public void onError(Objective objective, | ||
| 350 | - ObjectiveError error) { | ||
| 351 | - log.error("Failed to install interface filters for intf {}: {}", | ||
| 352 | - intf, error); | ||
| 353 | - // TODO something more than just logging | ||
| 354 | - } | ||
| 355 | - })); | ||
| 356 | } | 360 | } |
| 357 | } | 361 | } |
| 358 | 362 | ||
| 363 | + private void sendFilteringObjective(boolean install, FilteringObjective.Builder fob, | ||
| 364 | + Interface intf) { | ||
| 365 | + flowObjectiveService.filter( | ||
| 366 | + deviceId, | ||
| 367 | + fob.add(new ObjectiveContext() { | ||
| 368 | + @Override | ||
| 369 | + public void onSuccess(Objective objective) { | ||
| 370 | + log.info("Successfully installed interface based " | ||
| 371 | + + "filtering objectives for intf {}", intf); | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + @Override | ||
| 375 | + public void onError(Objective objective, | ||
| 376 | + ObjectiveError error) { | ||
| 377 | + log.error("Failed to install interface filters for intf {}: {}", | ||
| 378 | + intf, error); | ||
| 379 | + // TODO something more than just logging | ||
| 380 | + } | ||
| 381 | + })); | ||
| 382 | + } | ||
| 383 | + | ||
| 359 | private class InternalFibListener implements FibListener { | 384 | private class InternalFibListener implements FibListener { |
| 360 | 385 | ||
| 361 | @Override | 386 | @Override | ... | ... |
| ... | @@ -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,34 +584,59 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline | ... | @@ -584,34 +584,59 @@ 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) { |
| 593 | - if (o.port() == PortNumber.CONTROLLER) { | 594 | + OutputInstruction o = (OutputInstruction) ins; |
| 594 | - FlowRule.Builder ruleBuilder = DefaultFlowRule.builder() | 595 | + if (o.port() == PortNumber.CONTROLLER) { |
| 595 | - .fromApp(fwd.appId()) | 596 | + ttBuilder.add(o); |
| 596 | - .withPriority(fwd.priority()) | 597 | + } else { |
| 597 | - .forDevice(deviceId) | 598 | + log.warn("Only allowed treatments in versatile forwarding " |
| 598 | - .withSelector(fwd.selector()) | 599 | + + "objectives are punts to the controller"); |
| 599 | - .withTreatment(fwd.treatment()) | 600 | + } |
| 600 | - .makePermanent() | 601 | + } else { |
| 601 | - .forTable(ACL_TABLE); | 602 | + log.warn("Cannot process instruction in versatile fwd {}", ins); |
| 602 | - return Collections.singletonList(ruleBuilder.build()); | 603 | + } |
| 603 | - } else { | ||
| 604 | - log.warn("Only allowed treatments in versatile forwarding " | ||
| 605 | - + "objectives are punts to the controller"); | ||
| 606 | - return Collections.emptySet(); | ||
| 607 | } | 604 | } |
| 608 | } | 605 | } |
| 609 | - | ||
| 610 | if (fwd.nextId() != null) { | 606 | if (fwd.nextId() != null) { |
| 611 | - // XXX overide case | 607 | + // overide case |
| 612 | - log.warn("versatile objective --> next Id not yet implemeted"); | 608 | + NextGroup next = getGroupForNextObjective(fwd.nextId()); |
| 613 | - } | 609 | + List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data()); |
| 614 | - return Collections.emptySet(); | 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); | ||
| 616 | + return Collections.emptySet(); | ||
| 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()); | ||
| 615 | } | 640 | } |
| 616 | 641 | ||
| 617 | /** | 642 | /** | ... | ... |
| ... | @@ -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)); | ... | ... |
-
Please register or login to post a comment