blob: 09fae886a6d2f7aa5781d250c1f33037296e8785 [file] [log] [blame]
Saurav Das52025962016-01-28 22:30:01 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Saurav Das52025962016-01-28 22:30:01 -08003 *
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 */
16package org.onosproject.driver.pipeline;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.ArrayList;
21import java.util.Collection;
22import java.util.Collections;
23import java.util.Deque;
24import java.util.List;
25import org.onlab.packet.Ethernet;
26import org.onlab.packet.VlanId;
27import org.onosproject.core.ApplicationId;
Charles Chan425854b2016-04-11 15:32:12 -070028import org.onosproject.core.CoreService;
29import org.onosproject.net.DeviceId;
Saurav Das52025962016-01-28 22:30:01 -080030import org.onosproject.net.Port;
31import org.onosproject.net.PortNumber;
32import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070033import org.onosproject.net.behaviour.PipelinerContext;
34import org.onosproject.net.device.DeviceService;
Saurav Das52025962016-01-28 22:30:01 -080035import org.onosproject.net.flow.DefaultFlowRule;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.FlowRule;
Charles Chan425854b2016-04-11 15:32:12 -070039import org.onosproject.net.flow.FlowRuleService;
Saurav Das52025962016-01-28 22:30:01 -080040import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
42import org.onosproject.net.flow.criteria.Criteria;
43import org.onosproject.net.flow.criteria.Criterion;
44import org.onosproject.net.flow.criteria.EthCriterion;
45import org.onosproject.net.flow.criteria.EthTypeCriterion;
46import org.onosproject.net.flow.criteria.PortCriterion;
47import org.onosproject.net.flow.criteria.VlanIdCriterion;
48import org.onosproject.net.flow.instructions.Instruction;
49import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
50import org.onosproject.net.flowobjective.ForwardingObjective;
51import org.onosproject.net.flowobjective.ObjectiveError;
52import org.onosproject.net.group.Group;
53import org.onosproject.net.group.GroupKey;
Charles Chan425854b2016-04-11 15:32:12 -070054import org.onosproject.net.group.GroupService;
Saurav Das52025962016-01-28 22:30:01 -080055import org.slf4j.Logger;
56
57
58/**
59 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
60 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
61 * does not handle vlan tags and mpls labels simultaneously, which requires us
62 * to do some workarounds in the driver. This driver is meant for the use of
63 * the cpqd switch when MPLS is not a requirement from the ofdpa pipeline. As a
64 * result this driver correctly handles both incoming untagged and vlan-tagged
65 * packets.
66 *
67 */
Charles Chan361154b2016-03-24 10:23:39 -070068public class CpqdOfdpa2VlanPipeline extends CpqdOfdpa2Pipeline {
Saurav Das52025962016-01-28 22:30:01 -080069
70 private final Logger log = getLogger(getClass());
71
Charles Chan425854b2016-04-11 15:32:12 -070072 @Override
73 public void init(DeviceId deviceId, PipelinerContext context) {
74 this.deviceId = deviceId;
75
76 // Initialize OFDPA group handler
77 groupHandler = new CpqdOfdpa2GroupHandler();
78 groupHandler.init(deviceId, context);
79
80 serviceDirectory = context.directory();
81 coreService = serviceDirectory.get(CoreService.class);
82 flowRuleService = serviceDirectory.get(FlowRuleService.class);
83 groupService = serviceDirectory.get(GroupService.class);
84 flowObjectiveStore = context.store();
85 deviceService = serviceDirectory.get(DeviceService.class);
86
87 driverId = coreService.registerApplication(
88 "org.onosproject.driver.CpqdOfdpa2VlanPipeline");
89
90 initializePipeline();
91 }
92
Saurav Das52025962016-01-28 22:30:01 -080093 /*
94 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
95 * Since this driver does not deal with MPLS, there is no need for
96 * working around VLAN tags. In particular we do not pop off vlan tags in
97 * the middle of the pipeline.
98 *
99 * (non-Javadoc)
100 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
101 */
102 @Override
103 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
104 EthCriterion ethCriterion,
105 VlanIdCriterion vidCriterion,
106 VlanId assignedVlan,
107 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -0800108 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
109 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
110 return processEthDstOnlyFilter(ethCriterion, applicationId);
111 }
112
Charles Chan5b9df8d2016-03-28 22:21:40 -0700113 // Multicast MAC
114 if (ethCriterion.mask() != null) {
115 return processMcastEthDstFilter(ethCriterion, applicationId);
116 }
117
Saurav Das52025962016-01-28 22:30:01 -0800118 //handling untagged packets via assigned VLAN
119 if (vidCriterion.vlanId() == VlanId.NONE) {
120 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
121 }
122 // ofdpa cannot match on ALL portnumber, so we need to use separate
123 // rules for each port.
124 List<PortNumber> portnums = new ArrayList<PortNumber>();
125 if (portCriterion.port() == PortNumber.ALL) {
126 for (Port port : deviceService.getPorts(deviceId)) {
127 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
128 portnums.add(port.number());
129 }
130 }
131 } else {
132 portnums.add(portCriterion.port());
133 }
134
135 List<FlowRule> rules = new ArrayList<FlowRule>();
136 for (PortNumber pnum : portnums) {
137 // for unicast IP packets
138 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
139 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
140 selector.matchInPort(pnum);
141 selector.matchVlanId(vidCriterion.vlanId());
142 selector.matchEthType(Ethernet.TYPE_IPV4);
143 selector.matchEthDst(ethCriterion.mac());
144
145 treatment.transition(UNICAST_ROUTING_TABLE);
146 FlowRule rule = DefaultFlowRule.builder()
147 .forDevice(deviceId)
148 .withSelector(selector.build())
149 .withTreatment(treatment.build())
150 .withPriority(DEFAULT_PRIORITY)
151 .fromApp(applicationId)
152 .makePermanent()
153 .forTable(TMAC_TABLE).build();
154 rules.add(rule);
155 }
156 return rules;
157 }
158
159 /*
160 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
161 * ACL table. Since we do not pop off vlans in the TMAC table we can continue
162 * to match on vlans in the ACL table if necessary.
163 */
164 @Override
165 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
166 log.info("Processing versatile forwarding objective");
167
168 EthTypeCriterion ethType =
169 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
170 if (ethType == null) {
171 log.error("Versatile forwarding objective must include ethType");
172 fail(fwd, ObjectiveError.BADPARAMS);
173 return Collections.emptySet();
174 }
175 if (fwd.nextId() == null && fwd.treatment() == null) {
176 log.error("Forwarding objective {} from {} must contain "
177 + "nextId or Treatment", fwd.selector(), fwd.appId());
178 return Collections.emptySet();
179 }
180
181 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
182 fwd.selector().criteria().forEach(criterion -> {
183 if (criterion instanceof VlanIdCriterion) {
184 VlanId vlanId = ((VlanIdCriterion) criterion).vlanId();
185 // ensure that match does not include vlan = NONE as OF-DPA does not
186 // match untagged packets this way in the ACL table.
187 if (vlanId.equals(VlanId.NONE)) {
188 return;
189 }
190 }
191 sbuilder.add(criterion);
192 });
193
194 // XXX driver does not currently do type checking as per Tables 65-67 in
195 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
196 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
197 if (fwd.treatment() != null) {
198 for (Instruction ins : fwd.treatment().allInstructions()) {
199 if (ins instanceof OutputInstruction) {
200 OutputInstruction o = (OutputInstruction) ins;
201 if (o.port() == PortNumber.CONTROLLER) {
202 ttBuilder.add(o);
203 } else {
204 log.warn("Only allowed treatments in versatile forwarding "
205 + "objectives are punts to the controller");
206 }
207 } else {
208 log.warn("Cannot process instruction in versatile fwd {}", ins);
209 }
210 }
211 }
212 if (fwd.nextId() != null) {
213 // overide case
214 NextGroup next = getGroupForNextObjective(fwd.nextId());
215 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
216 // we only need the top level group's key to point the flow to it
217 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
218 if (group == null) {
219 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
220 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
221 fail(fwd, ObjectiveError.GROUPMISSING);
222 return Collections.emptySet();
223 }
224 ttBuilder.deferred().group(group.id());
225 }
226
227 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
228 .fromApp(fwd.appId())
229 .withPriority(fwd.priority())
230 .forDevice(deviceId)
231 .withSelector(sbuilder.build())
232 .withTreatment(ttBuilder.build())
233 .makePermanent()
234 .forTable(ACL_TABLE);
235 return Collections.singletonList(ruleBuilder.build());
236 }
237
238
239}