blob: f8625aaec996c9933a6f2d210d0149749ff9755e [file] [log] [blame]
Saurav Das52025962016-01-28 22:30:01 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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;
28import org.onosproject.net.Port;
29import org.onosproject.net.PortNumber;
30import org.onosproject.net.behaviour.NextGroup;
31import org.onosproject.net.flow.DefaultFlowRule;
32import org.onosproject.net.flow.DefaultTrafficSelector;
33import org.onosproject.net.flow.DefaultTrafficTreatment;
34import org.onosproject.net.flow.FlowRule;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.flow.criteria.Criteria;
38import org.onosproject.net.flow.criteria.Criterion;
39import org.onosproject.net.flow.criteria.EthCriterion;
40import org.onosproject.net.flow.criteria.EthTypeCriterion;
41import org.onosproject.net.flow.criteria.PortCriterion;
42import org.onosproject.net.flow.criteria.VlanIdCriterion;
43import org.onosproject.net.flow.instructions.Instruction;
44import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
45import org.onosproject.net.flowobjective.ForwardingObjective;
46import org.onosproject.net.flowobjective.ObjectiveError;
47import org.onosproject.net.group.Group;
48import org.onosproject.net.group.GroupKey;
49import org.slf4j.Logger;
50
51
52/**
53 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
54 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
55 * does not handle vlan tags and mpls labels simultaneously, which requires us
56 * to do some workarounds in the driver. This driver is meant for the use of
57 * the cpqd switch when MPLS is not a requirement from the ofdpa pipeline. As a
58 * result this driver correctly handles both incoming untagged and vlan-tagged
59 * packets.
60 *
61 */
Charles Chan361154b2016-03-24 10:23:39 -070062public class CpqdOfdpa2VlanPipeline extends CpqdOfdpa2Pipeline {
Saurav Das52025962016-01-28 22:30:01 -080063
64 private final Logger log = getLogger(getClass());
65
66 /*
67 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
68 * Since this driver does not deal with MPLS, there is no need for
69 * working around VLAN tags. In particular we do not pop off vlan tags in
70 * the middle of the pipeline.
71 *
72 * (non-Javadoc)
73 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
74 */
75 @Override
76 protected List<FlowRule> processEthDstFilter(PortCriterion portCriterion,
77 EthCriterion ethCriterion,
78 VlanIdCriterion vidCriterion,
79 VlanId assignedVlan,
80 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -080081 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
82 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
83 return processEthDstOnlyFilter(ethCriterion, applicationId);
84 }
85
Saurav Das52025962016-01-28 22:30:01 -080086 //handling untagged packets via assigned VLAN
87 if (vidCriterion.vlanId() == VlanId.NONE) {
88 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
89 }
90 // ofdpa cannot match on ALL portnumber, so we need to use separate
91 // rules for each port.
92 List<PortNumber> portnums = new ArrayList<PortNumber>();
93 if (portCriterion.port() == PortNumber.ALL) {
94 for (Port port : deviceService.getPorts(deviceId)) {
95 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
96 portnums.add(port.number());
97 }
98 }
99 } else {
100 portnums.add(portCriterion.port());
101 }
102
103 List<FlowRule> rules = new ArrayList<FlowRule>();
104 for (PortNumber pnum : portnums) {
105 // for unicast IP packets
106 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
107 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
108 selector.matchInPort(pnum);
109 selector.matchVlanId(vidCriterion.vlanId());
110 selector.matchEthType(Ethernet.TYPE_IPV4);
111 selector.matchEthDst(ethCriterion.mac());
112
113 treatment.transition(UNICAST_ROUTING_TABLE);
114 FlowRule rule = DefaultFlowRule.builder()
115 .forDevice(deviceId)
116 .withSelector(selector.build())
117 .withTreatment(treatment.build())
118 .withPriority(DEFAULT_PRIORITY)
119 .fromApp(applicationId)
120 .makePermanent()
121 .forTable(TMAC_TABLE).build();
122 rules.add(rule);
123 }
124 return rules;
125 }
126
127 /*
128 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
129 * ACL table. Since we do not pop off vlans in the TMAC table we can continue
130 * to match on vlans in the ACL table if necessary.
131 */
132 @Override
133 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
134 log.info("Processing versatile forwarding objective");
135
136 EthTypeCriterion ethType =
137 (EthTypeCriterion) fwd.selector().getCriterion(Criterion.Type.ETH_TYPE);
138 if (ethType == null) {
139 log.error("Versatile forwarding objective must include ethType");
140 fail(fwd, ObjectiveError.BADPARAMS);
141 return Collections.emptySet();
142 }
143 if (fwd.nextId() == null && fwd.treatment() == null) {
144 log.error("Forwarding objective {} from {} must contain "
145 + "nextId or Treatment", fwd.selector(), fwd.appId());
146 return Collections.emptySet();
147 }
148
149 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
150 fwd.selector().criteria().forEach(criterion -> {
151 if (criterion instanceof VlanIdCriterion) {
152 VlanId vlanId = ((VlanIdCriterion) criterion).vlanId();
153 // ensure that match does not include vlan = NONE as OF-DPA does not
154 // match untagged packets this way in the ACL table.
155 if (vlanId.equals(VlanId.NONE)) {
156 return;
157 }
158 }
159 sbuilder.add(criterion);
160 });
161
162 // XXX driver does not currently do type checking as per Tables 65-67 in
163 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
164 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
165 if (fwd.treatment() != null) {
166 for (Instruction ins : fwd.treatment().allInstructions()) {
167 if (ins instanceof OutputInstruction) {
168 OutputInstruction o = (OutputInstruction) ins;
169 if (o.port() == PortNumber.CONTROLLER) {
170 ttBuilder.add(o);
171 } else {
172 log.warn("Only allowed treatments in versatile forwarding "
173 + "objectives are punts to the controller");
174 }
175 } else {
176 log.warn("Cannot process instruction in versatile fwd {}", ins);
177 }
178 }
179 }
180 if (fwd.nextId() != null) {
181 // overide case
182 NextGroup next = getGroupForNextObjective(fwd.nextId());
183 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
184 // we only need the top level group's key to point the flow to it
185 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
186 if (group == null) {
187 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
188 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
189 fail(fwd, ObjectiveError.GROUPMISSING);
190 return Collections.emptySet();
191 }
192 ttBuilder.deferred().group(group.id());
193 }
194
195 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
196 .fromApp(fwd.appId())
197 .withPriority(fwd.priority())
198 .forDevice(deviceId)
199 .withSelector(sbuilder.build())
200 .withTreatment(ttBuilder.build())
201 .makePermanent()
202 .forTable(ACL_TABLE);
203 return Collections.singletonList(ruleBuilder.build());
204 }
205
206
207}