blob: 53d8fe1b495d54b5d5eed95e126aca22faca7e63 [file] [log] [blame]
Saurav Das52025962016-01-28 22:30:01 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
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 */
Yi Tsengef19de12017-04-24 11:33:05 -070016package org.onosproject.driver.pipeline.ofdpa;
Saurav Das52025962016-01-28 22:30:01 -080017
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;
Charles Chan206506b2018-03-02 16:43:28 -080025
26import com.google.common.collect.ImmutableList;
Saurav Das52025962016-01-28 22:30:01 -080027import org.onlab.packet.Ethernet;
Charles Chand57552d2018-03-02 15:41:41 -080028import org.onlab.packet.MacAddress;
Saurav Das52025962016-01-28 22:30:01 -080029import org.onlab.packet.VlanId;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.net.Port;
32import org.onosproject.net.PortNumber;
33import org.onosproject.net.behaviour.NextGroup;
Charles Chan425854b2016-04-11 15:32:12 -070034import org.onosproject.net.behaviour.PipelinerContext;
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;
39import org.onosproject.net.flow.TrafficSelector;
40import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.flow.criteria.Criteria;
Saurav Das52025962016-01-28 22:30:01 -080042import org.onosproject.net.flow.criteria.EthCriterion;
Saurav Das52025962016-01-28 22:30:01 -080043import org.onosproject.net.flow.criteria.PortCriterion;
44import org.onosproject.net.flow.criteria.VlanIdCriterion;
45import org.onosproject.net.flow.instructions.Instruction;
46import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Charles Chan3fe71712018-06-15 18:54:18 -070047import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction;
Saurav Das52025962016-01-28 22:30:01 -080048import org.onosproject.net.flowobjective.ForwardingObjective;
49import org.onosproject.net.flowobjective.ObjectiveError;
50import org.onosproject.net.group.Group;
51import org.onosproject.net.group.GroupKey;
52import org.slf4j.Logger;
53
pier5c817582019-04-17 17:05:08 +020054import static org.onosproject.driver.pipeline.ofdpa.OfdpaPipelineUtility.*;
Saurav Das52025962016-01-28 22:30:01 -080055
56/**
57 * Driver for software switch emulation of the OFDPA 2.0 pipeline.
58 * The software switch is the CPqD OF 1.3 switch. Unfortunately the CPqD switch
59 * does not handle vlan tags and mpls labels simultaneously, which requires us
60 * to do some workarounds in the driver. This driver is meant for the use of
61 * the cpqd switch when MPLS is not a requirement from the ofdpa pipeline. As a
62 * result this driver correctly handles both incoming untagged and vlan-tagged
63 * packets.
64 *
65 */
Charles Chan361154b2016-03-24 10:23:39 -070066public class CpqdOfdpa2VlanPipeline extends CpqdOfdpa2Pipeline {
Saurav Das52025962016-01-28 22:30:01 -080067
68 private final Logger log = getLogger(getClass());
69
Charles Chan425854b2016-04-11 15:32:12 -070070 @Override
Charles Chan40132b32017-01-22 00:19:37 -080071 protected void initDriverId() {
Charles Chan425854b2016-04-11 15:32:12 -070072 driverId = coreService.registerApplication(
73 "org.onosproject.driver.CpqdOfdpa2VlanPipeline");
Charles Chan40132b32017-01-22 00:19:37 -080074 }
Charles Chan425854b2016-04-11 15:32:12 -070075
Charles Chan40132b32017-01-22 00:19:37 -080076 @Override
77 protected void initGroupHander(PipelinerContext context) {
78 groupHandler = new CpqdOfdpa2GroupHandler();
79 groupHandler.init(deviceId, context);
Charles Chan425854b2016-04-11 15:32:12 -070080 }
81
Saurav Das52025962016-01-28 22:30:01 -080082 /*
83 * Cpqd emulation does not handle vlan tags and mpls labels correctly.
84 * Since this driver does not deal with MPLS, there is no need for
85 * working around VLAN tags. In particular we do not pop off vlan tags in
86 * the middle of the pipeline.
87 *
88 * (non-Javadoc)
89 * @see org.onosproject.driver.pipeline.OFDPA2Pipeline#processEthDstFilter
90 */
91 @Override
Charles Chan206506b2018-03-02 16:43:28 -080092 protected List<List<FlowRule>> processEthDstFilter(PortCriterion portCriterion,
Saurav Das52025962016-01-28 22:30:01 -080093 EthCriterion ethCriterion,
94 VlanIdCriterion vidCriterion,
95 VlanId assignedVlan,
Charles Chand57552d2018-03-02 15:41:41 -080096 MacAddress unicastMac,
Saurav Das52025962016-01-28 22:30:01 -080097 ApplicationId applicationId) {
Charles Chan5270ed02016-01-30 23:22:37 -080098 // Consider PortNumber.ANY as wildcard. Match ETH_DST only
99 if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
100 return processEthDstOnlyFilter(ethCriterion, applicationId);
101 }
102
Charles Chan5b9df8d2016-03-28 22:21:40 -0700103 // Multicast MAC
104 if (ethCriterion.mask() != null) {
Charles Chand57552d2018-03-02 15:41:41 -0800105 return processMcastEthDstFilter(ethCriterion, assignedVlan, unicastMac, applicationId);
Charles Chan5b9df8d2016-03-28 22:21:40 -0700106 }
107
Saurav Das52025962016-01-28 22:30:01 -0800108 //handling untagged packets via assigned VLAN
109 if (vidCriterion.vlanId() == VlanId.NONE) {
110 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
111 }
112 // ofdpa cannot match on ALL portnumber, so we need to use separate
113 // rules for each port.
Charles Chan93090352018-03-02 13:26:22 -0800114 List<PortNumber> portnums = new ArrayList<>();
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800115 if (portCriterion != null) {
116 if (portCriterion.port() == PortNumber.ALL) {
117 for (Port port : deviceService.getPorts(deviceId)) {
118 if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) {
119 portnums.add(port.number());
120 }
Saurav Das52025962016-01-28 22:30:01 -0800121 }
Ray Milkeyae4e5ed2018-01-17 15:24:52 -0800122 } else {
123 portnums.add(portCriterion.port());
Saurav Das52025962016-01-28 22:30:01 -0800124 }
Saurav Das52025962016-01-28 22:30:01 -0800125 }
126
Charles Chan93090352018-03-02 13:26:22 -0800127 List<FlowRule> rules = new ArrayList<>();
Saurav Das52025962016-01-28 22:30:01 -0800128 for (PortNumber pnum : portnums) {
129 // for unicast IP packets
130 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
131 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
132 selector.matchInPort(pnum);
133 selector.matchVlanId(vidCriterion.vlanId());
134 selector.matchEthType(Ethernet.TYPE_IPV4);
135 selector.matchEthDst(ethCriterion.mac());
136
137 treatment.transition(UNICAST_ROUTING_TABLE);
138 FlowRule rule = DefaultFlowRule.builder()
139 .forDevice(deviceId)
140 .withSelector(selector.build())
141 .withTreatment(treatment.build())
142 .withPriority(DEFAULT_PRIORITY)
143 .fromApp(applicationId)
144 .makePermanent()
145 .forTable(TMAC_TABLE).build();
146 rules.add(rule);
147 }
Charles Chan206506b2018-03-02 16:43:28 -0800148 return ImmutableList.of(rules);
Saurav Das52025962016-01-28 22:30:01 -0800149 }
150
151 /*
152 * In the OF-DPA 2.0 pipeline, versatile forwarding objectives go to the
153 * ACL table. Since we do not pop off vlans in the TMAC table we can continue
154 * to match on vlans in the ACL table if necessary.
155 */
156 @Override
157 protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
158 log.info("Processing versatile forwarding objective");
159
Saurav Das52025962016-01-28 22:30:01 -0800160 if (fwd.nextId() == null && fwd.treatment() == null) {
161 log.error("Forwarding objective {} from {} must contain "
162 + "nextId or Treatment", fwd.selector(), fwd.appId());
163 return Collections.emptySet();
164 }
165
166 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
167 fwd.selector().criteria().forEach(criterion -> {
168 if (criterion instanceof VlanIdCriterion) {
169 VlanId vlanId = ((VlanIdCriterion) criterion).vlanId();
170 // ensure that match does not include vlan = NONE as OF-DPA does not
171 // match untagged packets this way in the ACL table.
172 if (vlanId.equals(VlanId.NONE)) {
173 return;
174 }
175 }
176 sbuilder.add(criterion);
177 });
178
179 // XXX driver does not currently do type checking as per Tables 65-67 in
180 // OFDPA 2.0 spec. The only allowed treatment is a punt to the controller.
181 TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
182 if (fwd.treatment() != null) {
183 for (Instruction ins : fwd.treatment().allInstructions()) {
184 if (ins instanceof OutputInstruction) {
185 OutputInstruction o = (OutputInstruction) ins;
186 if (o.port() == PortNumber.CONTROLLER) {
187 ttBuilder.add(o);
188 } else {
189 log.warn("Only allowed treatments in versatile forwarding "
190 + "objectives are punts to the controller");
191 }
Charles Chan3fe71712018-06-15 18:54:18 -0700192 } else if (ins instanceof NoActionInstruction) {
193 // No action is allowed and nothing needs to be done
Saurav Das52025962016-01-28 22:30:01 -0800194 } else {
195 log.warn("Cannot process instruction in versatile fwd {}", ins);
196 }
197 }
198 }
199 if (fwd.nextId() != null) {
200 // overide case
201 NextGroup next = getGroupForNextObjective(fwd.nextId());
202 List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
203 // we only need the top level group's key to point the flow to it
204 Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
205 if (group == null) {
206 log.warn("Group with key:{} for next-id:{} not found in dev:{}",
207 gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
208 fail(fwd, ObjectiveError.GROUPMISSING);
209 return Collections.emptySet();
210 }
211 ttBuilder.deferred().group(group.id());
212 }
213
214 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
215 .fromApp(fwd.appId())
216 .withPriority(fwd.priority())
217 .forDevice(deviceId)
218 .withSelector(sbuilder.build())
219 .withTreatment(ttBuilder.build())
220 .makePermanent()
221 .forTable(ACL_TABLE);
222 return Collections.singletonList(ruleBuilder.build());
223 }
224
225
226}