blob: 58ba6d6b92f55cc0ebd46289e90fa934a7bf4c8b [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Thomas Vachuska58de4162015-09-10 16:15:33 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Saurav Das558afec2015-05-31 17:12:48 -070016package org.onosproject.driver.pipeline;
17
Charles Chan5270ed02016-01-30 23:22:37 -080018import com.google.common.collect.ImmutableList;
Charles Chan5b9df8d2016-03-28 22:21:40 -070019import com.google.common.collect.ImmutableSet;
Saurav Das8a0732e2015-11-20 15:27:53 -080020import org.onlab.packet.Ethernet;
Flavio Castroe10fa242016-01-15 12:43:51 -080021import org.onlab.packet.IpPrefix;
Saurav Das2857f382015-11-03 14:39:27 -080022import org.onlab.packet.VlanId;
23import org.onosproject.core.ApplicationId;
Charles Chan0f43e472017-02-14 14:00:16 -080024import org.onosproject.core.DefaultGroupId;
Saurav Das2857f382015-11-03 14:39:27 -080025import org.onosproject.net.Port;
26import org.onosproject.net.PortNumber;
Saurav Das8a0732e2015-11-20 15:27:53 -080027import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070028import org.onosproject.net.behaviour.PipelinerContext;
Saurav Das558afec2015-05-31 17:12:48 -070029import org.onosproject.net.flow.DefaultFlowRule;
30import org.onosproject.net.flow.DefaultTrafficSelector;
31import org.onosproject.net.flow.DefaultTrafficTreatment;
32import org.onosproject.net.flow.FlowRule;
33import org.onosproject.net.flow.FlowRuleOperations;
34import org.onosproject.net.flow.FlowRuleOperationsContext;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
Saurav Das4ce45962015-11-24 23:21:05 -080037import org.onosproject.net.flow.criteria.Criteria;
Saurav Das8a0732e2015-11-20 15:27:53 -080038import org.onosproject.net.flow.criteria.Criterion;
Saurav Das4ce45962015-11-24 23:21:05 -080039import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080040import org.onosproject.net.flow.criteria.EthTypeCriterion;
41import org.onosproject.net.flow.criteria.IPCriterion;
Pier Ventree0ae7a32016-11-23 09:57:42 -080042import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
43import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080044import org.onosproject.net.flow.criteria.MplsBosCriterion;
45import org.onosproject.net.flow.criteria.MplsCriterion;
Saurav Das2857f382015-11-03 14:39:27 -080046import org.onosproject.net.flow.criteria.PortCriterion;
47import org.onosproject.net.flow.criteria.VlanIdCriterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080048import org.onosproject.net.flow.instructions.Instruction;
Saurav Das52025962016-01-28 22:30:01 -080049import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Charles Chan40132b32017-01-22 00:19:37 -080050import org.onosproject.net.flow.instructions.L3ModificationInstruction;
Saurav Das52025962016-01-28 22:30:01 -080051import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
52import org.onosproject.net.flowobjective.FilteringObjective;
Saurav Das8a0732e2015-11-20 15:27:53 -080053import org.onosproject.net.flowobjective.ForwardingObjective;
54import org.onosproject.net.flowobjective.ObjectiveError;
Charles Chan0f43e472017-02-14 14:00:16 -080055import org.onosproject.net.group.DefaultGroupBucket;
56import org.onosproject.net.group.DefaultGroupDescription;
57import org.onosproject.net.group.DefaultGroupKey;
Saurav Das8a0732e2015-11-20 15:27:53 -080058import org.onosproject.net.group.Group;
Charles Chan0f43e472017-02-14 14:00:16 -080059import org.onosproject.net.group.GroupBucket;
60import org.onosproject.net.group.GroupBuckets;
61import org.onosproject.net.group.GroupDescription;
Saurav Das8a0732e2015-11-20 15:27:53 -080062import org.onosproject.net.group.GroupKey;
Charles Chanf57a8252016-06-29 19:12:37 -070063import org.onosproject.net.packet.PacketPriority;
Saurav Das558afec2015-05-31 17:12:48 -070064import org.slf4j.Logger;
65
Jonathan Hart855179c2016-04-26 07:40:04 -070066import java.util.ArrayList;
67import java.util.Collection;
68import java.util.Collections;
69import java.util.Deque;
70import java.util.List;
Charles Chan0f43e472017-02-14 14:00:16 -080071import java.util.Objects;
Jonathan Hart855179c2016-04-26 07:40:04 -070072
Pier Ventree0ae7a32016-11-23 09:57:42 -080073import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
Charles Chand05f54b2017-02-13 11:56:54 -080074import static org.onlab.packet.MacAddress.BROADCAST;
75import static org.onlab.packet.MacAddress.NONE;
Charles Chan0f43e472017-02-14 14:00:16 -080076import static org.onosproject.driver.pipeline.Ofdpa2GroupHandler.FOUR_BIT_MASK;
Jonathan Hart855179c2016-04-26 07:40:04 -070077import static org.slf4j.LoggerFactory.getLogger;
78
Saurav Das558afec2015-05-31 17:12:48 -070079
80/**
Charles Chan40132b32017-01-22 00:19:37 -080081 * Driver for software switch emulation of the OFDPA pipeline.
Saurav Das52025962016-01-28 22:30:01 -080082 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
83 * does not handle vlan tags and mpls labels simultaneously, which requires us
84 * to do some workarounds in the driver. This driver is meant for the use of
85 * the cpqd switch when MPLS is required. As a result this driver works only
86 * on incoming untagged packets.
Saurav Das558afec2015-05-31 17:12:48 -070087 */
Charles Chan361154b2016-03-24 10:23:39 -070088public class CpqdOfdpa2Pipeline extends Ofdpa2Pipeline {
Saurav Das558afec2015-05-31 17:12:48 -070089
90 private final Logger log = getLogger(getClass());
91
Charles Chan40132b32017-01-22 00:19:37 -080092 /**
Charles Chan0f43e472017-02-14 14:00:16 -080093 * Table that determines whether VLAN is popped before punting to controller.
94 * <p>
95 * This is a non-OFDPA table to emulate OFDPA packet in behavior.
96 * VLAN will be popped before punting if the VLAN is internally assigned.
97 * <p>
98 * Also note that 63 is the max table number in CpqD.
99 */
100 private static final int PUNT_TABLE = 63;
101
102 /**
103 * A static indirect group that pop vlan and punt to controller.
104 * <p>
105 * The purpose of using a group instead of immediate action is that this
106 * won't affect another copy on the data plane when write action exists.
107 */
108 private static final int POP_VLAN_PUNT_GROUP_ID = 0xc0000000;
109
110 /**
Charles Chan40132b32017-01-22 00:19:37 -0800111 * Determines whether this pipeline support copy ttl instructions or not.
112 *
113 * @return true if copy ttl instructions are supported
114 */
115 protected boolean supportCopyTtl() {
116 return true;
117 }
118
Charles Chan0f43e472017-02-14 14:00:16 -0800119 /**
120 * Determines whether this pipeline support push mpls to vlan-tagged packets or not.
121 * <p>
122 * If not support, pop vlan before push entering unicast and mpls table.
123 * Side effect: HostService learns redundant hosts with same MAC but
124 * different VLAN. No known side effect on the network reachability.
125 *
126 * @return true if push mpls to vlan-tagged packets is supported
127 */
128 protected boolean supportTaggedMpls() {
129 return false;
130 }
131
132 /**
133 * Determines whether this pipeline support punt action in group bucket.
134 *
135 * @return true if punt action in group bucket is supported
136 */
137 protected boolean supportPuntGroup() {
138 return false;
139 }
140
Charles Chan425854b2016-04-11 15:32:12 -0700141 @Override
Charles Chan40132b32017-01-22 00:19:37 -0800142 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -0700143 driverId = coreService.registerApplication(
144 "org.onosproject.driver.CpqdOfdpa2Pipeline");
Charles Chan40132b32017-01-22 00:19:37 -0800145 }
Charles Chan425854b2016-04-11 15:32:12 -0700146
Charles Chan40132b32017-01-22 00:19:37 -0800147 @Override
148 protected void initGroupHander(PipelinerContext context) {
149 groupHandler = new CpqdOfdpa2GroupHandler();
150 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -0700151 }
152
Saurav Das4ce45962015-11-24 23:21:05 -0800153 /*
Saurav Das52025962016-01-28 22:30:01 -0800154 * CPQD emulation does not require special untagged packet handling, unlike
155 * the real ofdpa.
156 */
157 @Override
158 protected void processFilter(FilteringObjective filt,
159 boolean install, ApplicationId applicationId) {
160 // This driver only processes filtering criteria defined with switch
161 // ports as the key
162 PortCriterion portCriterion = null;
163 EthCriterion ethCriterion = null;
164 VlanIdCriterion vidCriterion = null;
165 Collection<IPCriterion> ips = new ArrayList<IPCriterion>();
166 if (!filt.key().equals(Criteria.dummy()) &&
167 filt.key().type() == Criterion.Type.IN_PORT) {
168 portCriterion = (PortCriterion) filt.key();
169 } else {
170 log.warn("No key defined in filtering objective from app: {}. Not"
171 + "processing filtering objective", applicationId);
172 fail(filt, ObjectiveError.UNKNOWN);
173 return;
174 }
175 // convert filtering conditions for switch-intfs into flowrules
176 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
177 for (Criterion criterion : filt.conditions()) {
Charles Chan5b9df8d2016-03-28 22:21:40 -0700178 if (criterion.type() == Criterion.Type.ETH_DST ||
179 criterion.type() == Criterion.Type.ETH_DST_MASKED) {
Saurav Das52025962016-01-28 22:30:01 -0800180 ethCriterion = (EthCriterion) criterion;
181 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
182 vidCriterion = (VlanIdCriterion) criterion;
183 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
184 ips.add((IPCriterion) criterion);
185 } else {
186 log.error("Unsupported filter {}", criterion);
187 fail(filt, ObjectiveError.UNSUPPORTED);
188 return;
189 }
190 }
191
192 VlanId assignedVlan = null;
193 // For VLAN cross-connect packets, use the configured VLAN
194 if (vidCriterion != null) {
195 if (vidCriterion.vlanId() != VlanId.NONE) {
196 assignedVlan = vidCriterion.vlanId();
197
198 // For untagged packets, assign a VLAN ID
199 } else {
200 if (filt.meta() == null) {
201 log.error("Missing metadata in filtering objective required " +
202 "for vlan assignment in dev {}", deviceId);
203 fail(filt, ObjectiveError.BADPARAMS);
204 return;
205 }
206 for (Instruction i : filt.meta().allInstructions()) {
207 if (i instanceof ModVlanIdInstruction) {
208 assignedVlan = ((ModVlanIdInstruction) i).vlanId();
209 }
210 }
211 if (assignedVlan == null) {
212 log.error("Driver requires an assigned vlan-id to tag incoming "
213 + "untagged packets. Not processing vlan filters on "
214 + "device {}", deviceId);
215 fail(filt, ObjectiveError.BADPARAMS);
216 return;
217 }
218 }
219 }
220
Charles Chand05f54b2017-02-13 11:56:54 -0800221 if (ethCriterion == null || ethCriterion.mac().equals(NONE)) {
Saurav Das52025962016-01-28 22:30:01 -0800222 log.debug("filtering objective missing dstMac, cannot program TMAC table");
223 } else {
224 for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
225 vidCriterion, assignedVlan,
226 applicationId)) {
227 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
228 tmacRule, deviceId);
229 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
230 }
231 }
232
233 if (ethCriterion == null || vidCriterion == null) {
234 log.debug("filtering objective missing dstMac or VLAN, "
235 + "cannot program VLAN Table");
236 } else {
237 List<FlowRule> allRules = processVlanIdFilter(
238 portCriterion, vidCriterion, assignedVlan, applicationId);
239 for (FlowRule rule : allRules) {
240 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
241 rule, deviceId);
242 ops = install ? ops.add(rule) : ops.remove(rule);
243 }
244 }
245
246 for (IPCriterion ipaddr : ips) {
247 // since we ignore port information for IP rules, and the same (gateway) IP
248 // can be configured on multiple ports, we make sure that we send
249 // only a single rule to the switch.
250 if (!sentIpFilters.contains(ipaddr)) {
251 sentIpFilters.add(ipaddr);
252 log.debug("adding IP filtering rules in ACL table {} for dev: {}",
253 ipaddr, deviceId);
254 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
255 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
256 selector.matchEthType(Ethernet.TYPE_IPV4);
257 selector.matchIPDst(ipaddr.ip());
258 treatment.setOutput(PortNumber.CONTROLLER);
259 FlowRule rule = DefaultFlowRule.builder()
260 .forDevice(deviceId)
261 .withSelector(selector.build())
262 .withTreatment(treatment.build())
263 .withPriority(HIGHEST_PRIORITY)
264 .fromApp(applicationId)
265 .makePermanent()
266 .forTable(ACL_TABLE).build();
267 ops = install ? ops.add(rule) : ops.remove(rule);
268 }
269 }
270
271 // apply filtering flow rules
272 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
273 @Override
274 public void onSuccess(FlowRuleOperations ops) {
275 log.info("Applied {} filtering rules in device {}",
276 ops.stages().get(0).size(), deviceId);
277 pass(filt);
278 }
279
280 @Override
281 public void onError(FlowRuleOperations ops) {
282 log.info("Failed to apply all filtering rules in dev {}", deviceId);
283 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
284 }
285 }));
286
287 }
288
289 /*
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700290 * Cpqd emulation does not require the non OF-standard rules for
291 * matching untagged packets that ofdpa uses.
Saurav Das4ce45962015-11-24 23:21:05 -0800292 *
293 * (non-Javadoc)
294 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processVlanIdFilter
295 */
Saurav Das558afec2015-05-31 17:12:48 -0700296 @Override
Saurav Das2857f382015-11-03 14:39:27 -0800297 protected List<FlowRule> processVlanIdFilter(PortCriterion portCriterion,
298 VlanIdCriterion vidCriterion,
299 VlanId assignedVlan,
300 ApplicationId applicationId) {
Charles Chan79769232016-07-05 16:34:39 -0700301 List<FlowRule> rules = new ArrayList<>();
Saurav Das2857f382015-11-03 14:39:27 -0800302 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
303 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
304 selector.matchVlanId(vidCriterion.vlanId());
Saurav Das4f980082015-11-05 13:39:15 -0800305 treatment.transition(TMAC_TABLE);
306
Saurav Das2857f382015-11-03 14:39:27 -0800307 if (vidCriterion.vlanId() == VlanId.NONE) {
308 // untagged packets are assigned vlans
309 treatment.pushVlan().setVlanId(assignedVlan);
310 }
Saurav Das2857f382015-11-03 14:39:27 -0800311
312 // ofdpa cannot match on ALL portnumber, so we need to use separate
313 // rules for each port.
314 List<PortNumber> portnums = new ArrayList<PortNumber>();
315 if (portCriterion.port() == PortNumber.ALL) {
316 for (Port port : deviceService.getPorts(deviceId)) {
317 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
318 portnums.add(port.number());
319 }
320 }
321 } else {
322 portnums.add(portCriterion.port());
323 }
Saurav Das4f980082015-11-05 13:39:15 -0800324
Saurav Das2857f382015-11-03 14:39:27 -0800325 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800326 // NOTE: Emulating OFDPA behavior by popping off internal assigned
327 // VLAN before sending to controller
328 if (supportPuntGroup() && vidCriterion.vlanId() == VlanId.NONE) {
329 GroupKey groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(
330 POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK)));
331 Group group = groupService.getGroup(deviceId, groupKey);
332 if (group != null) {
333 rules.add(buildPuntTableRule(pnum, assignedVlan));
334 } else {
335 log.info("popVlanPuntGroup not found in dev:{}", deviceId);
336 return Collections.emptyList();
337 }
338 }
339
Saurav Das4f980082015-11-05 13:39:15 -0800340 // create rest of flowrule
Saurav Das2857f382015-11-03 14:39:27 -0800341 selector.matchInPort(pnum);
342 FlowRule rule = DefaultFlowRule.builder()
343 .forDevice(deviceId)
344 .withSelector(selector.build())
345 .withTreatment(treatment.build())
346 .withPriority(DEFAULT_PRIORITY)
347 .fromApp(applicationId)
348 .makePermanent()
349 .forTable(VLAN_TABLE).build();
350 rules.add(rule);
351 }
Charles Chanf57a8252016-06-29 19:12:37 -0700352
Saurav Das2857f382015-11-03 14:39:27 -0800353 return rules;
354 }
355
Pier Ventree0ae7a32016-11-23 09:57:42 -0800356 /**
Charles Chan0f43e472017-02-14 14:00:16 -0800357 * Creates punt table entry that matches IN_PORT and VLAN_VID and points to
358 * a group that pop vlan and punt.
359 *
360 * @param portNumber port number
361 * @param assignedVlan internally assigned vlan id
362 * @return punt table flow rule
363 */
364 private FlowRule buildPuntTableRule(PortNumber portNumber, VlanId assignedVlan) {
365 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
366 .matchInPort(portNumber)
367 .matchVlanId(assignedVlan);
368 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
369 .group(new DefaultGroupId(POP_VLAN_PUNT_GROUP_ID));
370
371 return DefaultFlowRule.builder()
372 .forDevice(deviceId)
373 .withSelector(sbuilder.build())
374 .withTreatment(tbuilder.build())
375 .withPriority(PacketPriority.CONTROL.priorityValue())
376 .fromApp(driverId)
377 .makePermanent()
378 .forTable(PUNT_TABLE).build();
379 }
380
381 /**
Pier Ventree0ae7a32016-11-23 09:57:42 -0800382 * Builds a punt to the controller rule for the arp protocol.
Charles Chan0f43e472017-02-14 14:00:16 -0800383 * <p>
384 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
385 * pop VLAN before sending to controller disregarding whether
386 * it's an internally assigned VLAN or a natural VLAN.
387 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800388 *
389 * @param assignedVlan the internal assigned vlan id
390 * @param applicationId the application id
391 * @return the punt flow rule for the arp
392 */
393 private FlowRule buildArpPunt(VlanId assignedVlan, ApplicationId applicationId) {
394 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
395 .matchEthType(Ethernet.TYPE_ARP)
396 .matchVlanId(assignedVlan);
397 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
398 .popVlan()
399 .punt();
400
401 return DefaultFlowRule.builder()
402 .forDevice(deviceId)
403 .withSelector(sbuilder.build())
404 .withTreatment(tbuilder.build())
405 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
406 .fromApp(applicationId)
407 .makePermanent()
408 .forTable(ACL_TABLE).build();
409 }
410
411 /**
412 * Builds a punt to the controller rule for the icmp v6 messages.
Charles Chan0f43e472017-02-14 14:00:16 -0800413 * <p>
414 * NOTE: CpqD cannot punt correctly in group bucket. The current impl will
415 * pop VLAN before sending to controller disregarding whether
416 * it's an internally assigned VLAN or a natural VLAN.
417 * Therefore, trunk port is not supported in CpqD.
Pier Ventree0ae7a32016-11-23 09:57:42 -0800418 *
419 * @param assignedVlan the internal assigned vlan id
420 * @param applicationId the application id
421 * @return the punt flow rule for the icmp v6 messages
422 */
423 private FlowRule buildIcmpV6Punt(VlanId assignedVlan, ApplicationId applicationId) {
424 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder()
425 .matchVlanId(assignedVlan)
426 .matchEthType(Ethernet.TYPE_IPV6)
427 .matchIPProtocol(PROTOCOL_ICMP6);
428 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder()
429 .popVlan()
430 .punt();
431
432 return DefaultFlowRule.builder()
433 .forDevice(deviceId)
434 .withSelector(sbuilder.build())
435 .withTreatment(tbuilder.build())
436 .withPriority(PacketPriority.CONTROL.priorityValue() + 1)
437 .fromApp(applicationId)
438 .makePermanent()
439 .forTable(ACL_TABLE).build();
440 }
441
Saurav Das4ce45962015-11-24 23:21:05 -0800442 /*
443 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
444 * Workaround requires popping off the VLAN tags in the TMAC table.
445 *
446 * (non-Javadoc)
447 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
448 */
Saurav Das8a0732e2015-11-20 15:27:53 -0800449 @Override
Saurav Das4ce45962015-11-24 23:21:05 -0800450 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
451 EthCriterion ethCriterion,
452 VlanIdCriterion vidCriterion,
453 VlanId assignedVlan,
454 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800455 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
456 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
457 return processEthDstOnlyFilter(ethCriterion, applicationId);
458 }
459
Charles Chan5b9df8d2016-03-28 22:21:40 -0700460 // Multicast MAC
461 if (ethCriterion.mask() != null) {
462 return processMcastEthDstFilter(ethCriterion, applicationId);
463 }
464
Saurav Das4ce45962015-11-24 23:21:05 -0800465 //handling untagged packets via assigned VLAN
466 if (vidCriterion.vlanId() == VlanId.NONE) {
467 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
468 }
469 // ofdpa cannot match on ALL portnumber, so we need to use separate
470 // rules for each port.
471 List<PortNumber> portnums = new ArrayList<PortNumber>();
472 if (portCriterion.port() == PortNumber.ALL) {
473 for (Port port : deviceService.getPorts(deviceId)) {
474 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
475 portnums.add(port.number());
476 }
477 }
478 } else {
479 portnums.add(portCriterion.port());
480 }
481
482 List<FlowRule> rules = new ArrayList<FlowRule>();
483 for (PortNumber pnum : portnums) {
Charles Chan0f43e472017-02-14 14:00:16 -0800484 // TMAC rules for unicast IP packets
Saurav Das4ce45962015-11-24 23:21:05 -0800485 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
486 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
487 selector.matchInPort(pnum);
488 selector.matchVlanId(vidCriterion.vlanId());
489 selector.matchEthType(Ethernet.TYPE_IPV4);
490 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800491 if (!supportTaggedMpls()) {
492 treatment.popVlan();
493 }
Saurav Das4ce45962015-11-24 23:21:05 -0800494 treatment.transition(UNICAST_ROUTING_TABLE);
495 FlowRule rule = DefaultFlowRule.builder()
496 .forDevice(deviceId)
497 .withSelector(selector.build())
498 .withTreatment(treatment.build())
499 .withPriority(DEFAULT_PRIORITY)
500 .fromApp(applicationId)
501 .makePermanent()
502 .forTable(TMAC_TABLE).build();
503 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800504
505 // TMAC rules for MPLS packets
Saurav Das4ce45962015-11-24 23:21:05 -0800506 selector = DefaultTrafficSelector.builder();
507 treatment = DefaultTrafficTreatment.builder();
508 selector.matchInPort(pnum);
509 selector.matchVlanId(vidCriterion.vlanId());
510 selector.matchEthType(Ethernet.MPLS_UNICAST);
511 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800512 if (!supportTaggedMpls()) {
513 treatment.popVlan();
514 }
Saurav Das4ce45962015-11-24 23:21:05 -0800515 treatment.transition(MPLS_TABLE_0);
516 rule = DefaultFlowRule.builder()
517 .forDevice(deviceId)
518 .withSelector(selector.build())
519 .withTreatment(treatment.build())
520 .withPriority(DEFAULT_PRIORITY)
521 .fromApp(applicationId)
522 .makePermanent()
523 .forTable(TMAC_TABLE).build();
524 rules.add(rule);
Charles Chan0f43e472017-02-14 14:00:16 -0800525
526 // TMAC rules for IPv6 packets
Pier Ventree0ae7a32016-11-23 09:57:42 -0800527 selector = DefaultTrafficSelector.builder();
528 treatment = DefaultTrafficTreatment.builder();
529 selector.matchInPort(pnum);
530 selector.matchVlanId(vidCriterion.vlanId());
531 selector.matchEthType(Ethernet.TYPE_IPV6);
532 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800533 if (!supportTaggedMpls()) {
534 treatment.popVlan();
535 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800536 treatment.transition(UNICAST_ROUTING_TABLE);
537 rule = DefaultFlowRule.builder()
538 .forDevice(deviceId)
539 .withSelector(selector.build())
540 .withTreatment(treatment.build())
541 .withPriority(DEFAULT_PRIORITY)
542 .fromApp(applicationId)
543 .makePermanent()
544 .forTable(TMAC_TABLE).build();
545 rules.add(rule);
Saurav Das4ce45962015-11-24 23:21:05 -0800546 }
547 return rules;
548 }
549
Charles Chan5270ed02016-01-30 23:22:37 -0800550 @Override
551 protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
552 ApplicationId applicationId) {
553 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
554 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
555 selector.matchEthType(Ethernet.TYPE_IPV4);
556 selector.matchEthDst(ethCriterion.mac());
Charles Chan0f43e472017-02-14 14:00:16 -0800557 if (!supportTaggedMpls()) {
558 treatment.popVlan();
559 }
Charles Chan5270ed02016-01-30 23:22:37 -0800560 treatment.transition(UNICAST_ROUTING_TABLE);
561 FlowRule rule = DefaultFlowRule.builder()
562 .forDevice(deviceId)
563 .withSelector(selector.build())
564 .withTreatment(treatment.build())
565 .withPriority(DEFAULT_PRIORITY)
566 .fromApp(applicationId)
567 .makePermanent()
568 .forTable(TMAC_TABLE).build();
569 return ImmutableList.<FlowRule>builder().add(rule).build();
570 }
571
Saurav Das4ce45962015-11-24 23:21:05 -0800572 /*
573 * Cpqd emulation allows MPLS ecmp.
574 *
575 * (non-Javadoc)
576 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthTypeSpecific
577 */
578 @Override
579 protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800580 TrafficSelector selector = fwd.selector();
581 EthTypeCriterion ethType =
582 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
583 if ((ethType == null) ||
584 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
Pier Ventree0ae7a32016-11-23 09:57:42 -0800585 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST) &&
586 (ethType.ethType().toShort() != Ethernet.TYPE_IPV6)) {
Saurav Das4ce45962015-11-24 23:21:05 -0800587 log.warn("processSpecific: Unsupported forwarding objective criteria"
588 + "ethType:{} in dev:{}", ethType, deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800589 fail(fwd, ObjectiveError.UNSUPPORTED);
590 return Collections.emptySet();
591 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800592 boolean defaultRule = false;
Saurav Das8a0732e2015-11-20 15:27:53 -0800593 int forTableId = -1;
594 TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
Flavio Castroe10fa242016-01-15 12:43:51 -0800595 TrafficSelector.Builder complementarySelector = DefaultTrafficSelector.builder();
596
Saurav Das8a0732e2015-11-20 15:27:53 -0800597 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Flavio Castroe10fa242016-01-15 12:43:51 -0800598 IpPrefix ipv4Dst = ((IPCriterion) selector.getCriterion(Criterion.Type.IPV4_DST)).ip();
Charles Chan5b9df8d2016-03-28 22:21:40 -0700599 if (ipv4Dst.isMulticast()) {
600 if (ipv4Dst.prefixLength() != 32) {
601 log.warn("Multicast specific forwarding objective can only be /32");
602 fail(fwd, ObjectiveError.BADPARAMS);
603 return ImmutableSet.of();
604 }
605 VlanId assignedVlan = readVlanFromSelector(fwd.meta());
606 if (assignedVlan == null) {
607 log.warn("VLAN ID required by multicast specific fwd obj is missing. Abort.");
608 fail(fwd, ObjectiveError.BADPARAMS);
609 return ImmutableSet.of();
610 }
611 filteredSelector.matchVlanId(assignedVlan);
612 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
613 forTableId = MULTICAST_ROUTING_TABLE;
614 log.debug("processing IPv4 multicast specific forwarding objective {} -> next:{}"
615 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800616 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700617 if (ipv4Dst.prefixLength() == 0) {
618 // The entire IPV4_DST field is wildcarded intentionally
619 filteredSelector.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700620 } else {
Charles Chanf9e98652016-09-07 16:54:23 -0700621 filteredSelector.matchEthType(Ethernet.TYPE_IPV4).matchIPDst(ipv4Dst);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700622 }
623 forTableId = UNICAST_ROUTING_TABLE;
624 log.debug("processing IPv4 unicast specific forwarding objective {} -> next:{}"
625 + " in dev:{}", fwd.id(), fwd.nextId(), deviceId);
Flavio Castroe10fa242016-01-15 12:43:51 -0800626 }
Pier Ventree0ae7a32016-11-23 09:57:42 -0800627 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV6) {
628 if (buildIpv6Selector(filteredSelector, fwd) < 0) {
629 return Collections.emptyList();
630 }
631 forTableId = UNICAST_ROUTING_TABLE;
Saurav Das8a0732e2015-11-20 15:27:53 -0800632 } else {
633 filteredSelector
634 .matchEthType(Ethernet.MPLS_UNICAST)
635 .matchMplsLabel(((MplsCriterion)
636 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
637 MplsBosCriterion bos = (MplsBosCriterion) selector
638 .getCriterion(Criterion.Type.MPLS_BOS);
639 if (bos != null) {
640 filteredSelector.matchMplsBos(bos.mplsBos());
641 }
642 forTableId = MPLS_TABLE_1;
Saurav Das4ce45962015-11-24 23:21:05 -0800643 log.debug("processing MPLS specific forwarding objective {} -> next:{}"
644 + " in dev {}", fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800645 }
646
647 TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder();
648 if (fwd.treatment() != null) {
649 for (Instruction i : fwd.treatment().allInstructions()) {
Charles Chan40132b32017-01-22 00:19:37 -0800650 if (!supportCopyTtl() && i instanceof L3ModificationInstruction) {
651 L3ModificationInstruction l3instr = (L3ModificationInstruction) i;
652 if (l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_IN) ||
653 l3instr.subtype().equals(L3ModificationInstruction.L3SubType.TTL_OUT)) {
654 continue;
655 }
656 }
Charles Chan7d10b162015-12-07 18:54:45 -0800657 /*
658 * NOTE: OF-DPA does not support immediate instruction in
659 * L3 unicast and MPLS table.
660 */
661 tb.deferred().add(i);
Saurav Das8a0732e2015-11-20 15:27:53 -0800662 }
663 }
664
665 if (fwd.nextId() != null) {
Saurav Das423fe2b2015-12-04 10:52:59 -0800666 NextGroup next = getGroupForNextObjective(fwd.nextId());
667 if (next != null) {
668 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
669 // we only need the top level group's key to point the flow to it
670 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
671 if (group == null) {
Saurav Das1ce0a7b2016-10-21 14:06:29 -0700672 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
673 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
Saurav Das423fe2b2015-12-04 10:52:59 -0800674 fail(fwd, ObjectiveError.GROUPMISSING);
675 return Collections.emptySet();
676 }
677 tb.deferred().group(group.id());
Saurav Das8a0732e2015-11-20 15:27:53 -0800678 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800679 }
680 tb.transition(ACL_TABLE);
681 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
682 .fromApp(fwd.appId())
683 .withPriority(fwd.priority())
684 .forDevice(deviceId)
685 .withSelector(filteredSelector.build())
686 .withTreatment(tb.build())
687 .forTable(forTableId);
688
689 if (fwd.permanent()) {
690 ruleBuilder.makePermanent();
691 } else {
692 ruleBuilder.makeTemporary(fwd.timeout());
693 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800694 Collection<FlowRule> flowRuleCollection = new ArrayList<>();
695 flowRuleCollection.add(ruleBuilder.build());
696 if (defaultRule) {
Pier Ventree0ae7a32016-11-23 09:57:42 -0800697 flowRuleCollection.add(
698 defaultRoute(fwd, complementarySelector, forTableId, tb)
699 );
Flavio Castroe10fa242016-01-15 12:43:51 -0800700 log.debug("Default rule 0.0.0.0/0 is being installed two rules");
701 }
Flavio Castroe10fa242016-01-15 12:43:51 -0800702 return flowRuleCollection;
Saurav Das8a0732e2015-11-20 15:27:53 -0800703 }
704
Charles Chan1e492d32016-01-30 23:22:37 -0800705 @Override
706 protected Collection<FlowRule> processEthDstSpecific(ForwardingObjective fwd) {
707 List<FlowRule> rules = new ArrayList<>();
708
709 // Build filtered selector
710 TrafficSelector selector = fwd.selector();
711 EthCriterion ethCriterion = (EthCriterion) selector
712 .getCriterion(Criterion.Type.ETH_DST);
713 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
714 .getCriterion(Criterion.Type.VLAN_VID);
715
716 if (vlanIdCriterion == null) {
717 log.warn("Forwarding objective for bridging requires vlan. Not "
718 + "installing fwd:{} in dev:{}", fwd.id(), deviceId);
719 fail(fwd, ObjectiveError.BADPARAMS);
720 return Collections.emptySet();
721 }
722
723 TrafficSelector.Builder filteredSelectorBuilder =
724 DefaultTrafficSelector.builder();
725 // Do not match MacAddress for subnet broadcast entry
Charles Chand05f54b2017-02-13 11:56:54 -0800726 if (!ethCriterion.mac().equals(NONE) && !ethCriterion.mac().equals(BROADCAST)) {
Charles Chan1e492d32016-01-30 23:22:37 -0800727 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
728 log.debug("processing L2 forwarding objective:{} -> next:{} in dev:{}",
729 fwd.id(), fwd.nextId(), deviceId);
730 } else {
731 log.debug("processing L2 Broadcast forwarding objective:{} -> next:{} "
732 + "in dev:{} for vlan:{}",
733 fwd.id(), fwd.nextId(), deviceId, vlanIdCriterion.vlanId());
734 }
735 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
736 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
737
738 if (fwd.treatment() != null) {
739 log.warn("Ignoring traffic treatment in fwd rule {} meant for L2 table"
740 + "for dev:{}. Expecting only nextId", fwd.id(), deviceId);
741 }
742
743 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
744 if (fwd.nextId() != null) {
745 NextGroup next = getGroupForNextObjective(fwd.nextId());
746 if (next != null) {
747 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
748 // we only need the top level group's key to point the flow to it
749 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
750 if (group != null) {
751 treatmentBuilder.deferred().group(group.id());
752 } else {
753 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
754 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
755 fail(fwd, ObjectiveError.GROUPMISSING);
756 return Collections.emptySet();
757 }
758 }
759 }
760 treatmentBuilder.immediate().transition(ACL_TABLE);
761 TrafficTreatment filteredTreatment = treatmentBuilder.build();
762
763 // Build bridging table entries
764 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
765 flowRuleBuilder.fromApp(fwd.appId())
766 .withPriority(fwd.priority())
767 .forDevice(deviceId)
768 .withSelector(filteredSelector)
769 .withTreatment(filteredTreatment)
770 .forTable(BRIDGING_TABLE);
771 if (fwd.permanent()) {
772 flowRuleBuilder.makePermanent();
773 } else {
774 flowRuleBuilder.makeTemporary(fwd.timeout());
775 }
776 rules.add(flowRuleBuilder.build());
777 return rules;
778 }
779
Saurav Das52025962016-01-28 22:30:01 -0800780 /*
781 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
782 * ACL table. Because we pop off vlan tags in TMAC table,
783 * we need to avoid matching on vlans in the ACL table.
784 */
785 @Override
786 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
787 log.info("Processing versatile forwarding objective");
788
789 EthTypeCriterion ethType =
790 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
791 if (ethType == null) {
792 log.error("Versatile forwarding objective must include ethType");
793 fail(fwd, ObjectiveError.BADPARAMS);
794 return Collections.emptySet();
795 }
796 if (fwd.nextId() == null && fwd.treatment() == null) {
797 log.error("Forwarding objective {} from {} must contain "
798 + "nextId or Treatment", fwd.selector(), fwd.appId());
799 return Collections.emptySet();
800 }
801
802 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
803 fwd.selector().criteria().forEach(criterion -> {
804 if (criterion instanceof VlanIdCriterion) {
805 // avoid matching on vlans
806 return;
Pier Ventree0ae7a32016-11-23 09:57:42 -0800807 } else if (criterion instanceof Icmpv6TypeCriterion ||
808 criterion instanceof Icmpv6CodeCriterion) {
809 /*
810 * We silenty discard these criterions, our current
811 * OFDPA platform does not support these matches on
812 * the ACL table.
813 */
814 log.warn("ICMPv6 Type and ICMPv6 Code are not supported");
Saurav Das52025962016-01-28 22:30:01 -0800815 } else {
816 sbuilder.add(criterion);
817 }
818 });
819
820 // XXX driver does not currently do type checking as per Tables 65-67 in
821 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
822 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
823 if (fwd.treatment() != null) {
824 for (Instruction ins : fwd.treatment().allInstructions()) {
825 if (ins instanceof OutputInstruction) {
826 OutputInstruction o = (OutputInstruction) ins;
827 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan0f43e472017-02-14 14:00:16 -0800828 ttBuilder.transition(PUNT_TABLE);
Saurav Das52025962016-01-28 22:30:01 -0800829 } else {
830 log.warn("Only allowed treatments in versatile forwarding "
831 + "objectives are punts to the controller");
832 }
833 } else {
834 log.warn("Cannot process instruction in versatile fwd {}", ins);
835 }
836 }
Charles Chan2df0e8a2017-01-09 11:45:08 -0800837 if (fwd.treatment().clearedDeferred()) {
838 ttBuilder.wipeDeferred();
839 }
Saurav Das52025962016-01-28 22:30:01 -0800840 }
841 if (fwd.nextId() != null) {
842 // overide case
843 NextGroup next = getGroupForNextObjective(fwd.nextId());
844 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
845 // we only need the top level group's key to point the flow to it
846 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
847 if (group == null) {
848 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
849 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
850 fail(fwd, ObjectiveError.GROUPMISSING);
851 return Collections.emptySet();
852 }
853 ttBuilder.deferred().group(group.id());
854 }
855
856 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
857 .fromApp(fwd.appId())
858 .withPriority(fwd.priority())
859 .forDevice(deviceId)
860 .withSelector(sbuilder.build())
861 .withTreatment(ttBuilder.build())
862 .makePermanent()
863 .forTable(ACL_TABLE);
864 return Collections.singletonList(ruleBuilder.build());
865 }
866
867 /*
868 * Cpqd emulation requires table-miss-entries in forwarding tables.
869 * Real OFDPA does not require these rules as they are put in by default.
870 *
871 * (non-Javadoc)
872 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#initializePipeline()
873 */
Saurav Das2857f382015-11-03 14:39:27 -0800874 @Override
Saurav Das558afec2015-05-31 17:12:48 -0700875 protected void initializePipeline() {
Charles Chanf6ec1532017-02-08 16:10:40 -0800876 initTableMiss(PORT_TABLE, VLAN_TABLE, null);
877 initTableMiss(VLAN_TABLE, ACL_TABLE, null);
878 initTableMiss(TMAC_TABLE, BRIDGING_TABLE, null);
879 initTableMiss(UNICAST_ROUTING_TABLE, ACL_TABLE, null);
880 initTableMiss(MULTICAST_ROUTING_TABLE, ACL_TABLE, null);
881 initTableMiss(MPLS_TABLE_0, MPLS_TABLE_1, null);
882 initTableMiss(MPLS_TABLE_1, ACL_TABLE, null);
883 initTableMiss(BRIDGING_TABLE, ACL_TABLE, null);
884 initTableMiss(ACL_TABLE, -1, null);
Charles Chan0f43e472017-02-14 14:00:16 -0800885
886 if (supportPuntGroup()) {
887 initTableMiss(PUNT_TABLE, -1,
888 DefaultTrafficTreatment.builder().punt().build());
889 initPopVlanPuntGroup();
890 } else {
891 initTableMiss(PUNT_TABLE, -1,
892 DefaultTrafficTreatment.builder().popVlan().punt().build());
893 }
Saurav Das558afec2015-05-31 17:12:48 -0700894 }
895
Charles Chanf6ec1532017-02-08 16:10:40 -0800896 /**
897 * Install table-miss flow entry.
898 *
899 * If treatment exists, use it directly.
900 * Else if treatment does not exist but nextTable > 0, transit to next table.
901 * Else apply empty treatment.
902 *
903 * @param thisTable this table ID
904 * @param nextTable next table ID
905 * @param treatment traffic treatment to apply.
906 */
907 private void initTableMiss(int thisTable, int nextTable, TrafficTreatment treatment) {
Saurav Das558afec2015-05-31 17:12:48 -0700908 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chanf6ec1532017-02-08 16:10:40 -0800909 TrafficSelector selector = DefaultTrafficSelector.builder().build();
Saurav Das558afec2015-05-31 17:12:48 -0700910
Charles Chanf6ec1532017-02-08 16:10:40 -0800911 if (treatment == null) {
912 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
913 if (nextTable > 0) {
914 tBuilder.transition(nextTable);
Saurav Das558afec2015-05-31 17:12:48 -0700915 }
Charles Chanf6ec1532017-02-08 16:10:40 -0800916 treatment = tBuilder.build();
917 }
Saurav Das558afec2015-05-31 17:12:48 -0700918
Charles Chanb7504392017-02-10 12:51:04 -0800919 FlowRule rule = DefaultFlowRule.builder()
920 .forDevice(deviceId)
Charles Chanf6ec1532017-02-08 16:10:40 -0800921 .withSelector(selector)
922 .withTreatment(treatment)
Charles Chanb7504392017-02-10 12:51:04 -0800923 .withPriority(LOWEST_PRIORITY)
924 .fromApp(driverId)
925 .makePermanent()
Charles Chanf6ec1532017-02-08 16:10:40 -0800926 .forTable(thisTable).build();
Charles Chanb7504392017-02-10 12:51:04 -0800927 ops = ops.add(rule);
Saurav Das2857f382015-11-03 14:39:27 -0800928
929 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
930 @Override
931 public void onSuccess(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800932 log.info("Initialized table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800933 }
Saurav Das2857f382015-11-03 14:39:27 -0800934 @Override
935 public void onError(FlowRuleOperations ops) {
Charles Chanf6ec1532017-02-08 16:10:40 -0800936 log.warn("Failed to initialize table {} on {}", thisTable, deviceId);
Saurav Das2857f382015-11-03 14:39:27 -0800937 }
938 }));
939 }
Charles Chan0f43e472017-02-14 14:00:16 -0800940
941 /**
942 * Builds a indirect group contains pop_vlan and punt actions.
943 * <p>
944 * Using group instead of immediate action to ensure that
945 * the copy of packet on the data plane is not affected by the pop vlan action.
946 */
947 private void initPopVlanPuntGroup() {
948 GroupKey groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(
949 POP_VLAN_PUNT_GROUP_ID | (Objects.hash(deviceId) & FOUR_BIT_MASK)));
950 TrafficTreatment bucketTreatment = DefaultTrafficTreatment.builder()
951 .popVlan().punt().build();
952 GroupBucket bucket =
953 DefaultGroupBucket.createIndirectGroupBucket(bucketTreatment);
954 GroupDescription groupDesc =
955 new DefaultGroupDescription(
956 deviceId,
957 GroupDescription.Type.INDIRECT,
958 new GroupBuckets(Collections.singletonList(bucket)),
959 groupKey,
960 POP_VLAN_PUNT_GROUP_ID,
961 driverId);
962 groupService.addGroup(groupDesc);
963
964 log.info("Initialized pop vlan punt group on {}", deviceId);
965 }
Saurav Das558afec2015-05-31 17:12:48 -0700966}