blob: 233e537d95792a2711d3281ab43da693d1eac9a0 [file] [log] [blame]
Sean Condonfae8e662016-12-15 10:25:13 +00001/*
2 * Copyright 2016-present 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.drivers.microsemi;
17
18import static com.google.common.base.Preconditions.checkNotNull;
19import static org.slf4j.LoggerFactory.getLogger;
20
21import java.math.BigInteger;
22import java.net.URI;
23import java.util.ArrayList;
24import java.util.Collection;
25import java.util.HashMap;
26import java.util.HashSet;
27import java.util.List;
28import java.util.Map;
29import java.util.concurrent.Semaphore;
Sean Condon06613e92017-06-09 15:14:01 +010030import java.util.concurrent.TimeoutException;
Sean Condonfae8e662016-12-15 10:25:13 +000031import java.util.stream.Collectors;
32
33import org.onlab.packet.EthType;
34import org.onlab.packet.EthType.EtherType;
35import org.onlab.packet.IpPrefix;
36import org.onlab.packet.VlanId;
37import org.onosproject.core.ApplicationId;
38import org.onosproject.core.CoreService;
39import org.onosproject.drivers.microsemi.yang.MseaSaFilteringNetconfService;
40import org.onosproject.drivers.microsemi.yang.MseaUniEvcServiceNetconfService;
41import org.onosproject.drivers.microsemi.yang.UniSide;
Sean Condon06613e92017-06-09 15:14:01 +010042import org.onosproject.drivers.microsemi.yang.custom.CustomEvcPerUnic;
43import org.onosproject.drivers.microsemi.yang.custom.CustomEvcPerUnin;
Sean Condonfae8e662016-12-15 10:25:13 +000044import org.onosproject.drivers.microsemi.yang.utils.CeVlanMapUtils;
45import org.onosproject.net.PortNumber;
46import org.onosproject.net.driver.AbstractHandlerBehaviour;
47import org.onosproject.net.flow.DefaultFlowEntry;
48import org.onosproject.net.flow.DefaultFlowRule;
49import org.onosproject.net.flow.DefaultTrafficSelector;
50import org.onosproject.net.flow.DefaultTrafficTreatment;
51import org.onosproject.net.flow.FlowEntry;
52import org.onosproject.net.flow.FlowEntry.FlowEntryState;
53import org.onosproject.net.flow.FlowRule;
54import org.onosproject.net.flow.FlowRuleProgrammable;
55import org.onosproject.net.flow.TrafficSelector;
56import org.onosproject.net.flow.TrafficTreatment;
57import org.onosproject.net.flow.criteria.Criteria;
58import org.onosproject.net.flow.criteria.Criterion;
59import org.onosproject.net.flow.criteria.Criterion.Type;
60import org.onosproject.net.flow.criteria.PortCriterion;
61import org.onosproject.net.flow.criteria.VlanIdCriterion;
62import org.onosproject.net.flow.instructions.Instruction;
63import org.onosproject.net.flow.instructions.L2ModificationInstruction;
64import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanHeaderInstruction;
65import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
66import org.onosproject.net.meter.MeterId;
Sean Condon06613e92017-06-09 15:14:01 +010067import org.onosproject.netconf.DatastoreId;
Sean Condonfae8e662016-12-15 10:25:13 +000068import org.onosproject.netconf.NetconfController;
Sean Condon06613e92017-06-09 15:14:01 +010069import org.onosproject.netconf.NetconfDevice;
Sean Condonfae8e662016-12-15 10:25:13 +000070import org.onosproject.netconf.NetconfException;
71import org.onosproject.netconf.NetconfSession;
Sean Condon06613e92017-06-09 15:14:01 +010072import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFiltering;
73import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.MseaSaFilteringOpParam;
74import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.DefaultSourceIpaddressFiltering;
75import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.SourceIpaddressFiltering;
76import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.DefaultInterfaceEth0;
77import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.InterfaceEth0;
78import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.DefaultSourceAddressRange;
79import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.FilterAdminStateEnum;
80import org.onosproject.yang.gen.v1.mseasafiltering.rev20160412.mseasafiltering.sourceipaddressfiltering.interfaceeth0.SourceAddressRange;
81import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.Identifier45;
82import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.ServiceListType;
83import org.onosproject.yang.gen.v1.mseatypes.rev20160229.mseatypes.VlanIdType;
84import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcService;
85import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.MseaUniEvcServiceOpParam;
86import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.DefaultMefServices;
87import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.MefServices;
88import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.DefaultFlowMapping;
89import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.FlowMapping;
90import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.TagManipulation;
91import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagOverwrite;
92import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagPop;
93import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.DefaultTagPush;
94import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagOverwrite;
95import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagPop;
96import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.TagPush;
97import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.evcperuniextensionattributes.tagmanipulation.tagpush.tagpush.PushTagTypeEnum;
98import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.DefaultProfiles;
99import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.DefaultUni;
100import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.Profiles;
101import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.Uni;
102import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.BwpGroup;
103import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.profiles.DefaultBwpGroup;
104import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.DefaultEvc;
105import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.Evc;
106import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.UniSideInterfaceAssignmentEnum;
107import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.DefaultEvcPerUni;
108import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.EvcPerUni;
109import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.EvcPerUnic;
110import org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice.mefservices.uni.evc.evcperuni.EvcPerUnin;
Sean Condonfae8e662016-12-15 10:25:13 +0000111import org.slf4j.Logger;
112
113/**
114 * An implementation of the FlowRuleProgrammable behaviour for the EA10000 device.
115 *
116 * This device is not a native Open Flow device. It has only a NETCONF interface for configuration
117 * status retrieval and notifications. It supports only a small subset of OpenFlow rules.<br>
118 *
119 * The device supports only:<br>
120 * 1) Open flow rules that blocks certain IP address ranges, but only those incoming on Port 0
121 * and has a limit of 10 such rules<br>
122 * 2) Open flow rules that PUSH, POP and OVERWRITE VLAN tags on both ports. This can push and overwrite
123 * both C-TAGs (0x8100) and S-TAGs (0x88a8).
124 */
125public class EA1000FlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
126
127 protected final Logger log = getLogger(getClass());
128 public static final String MICROSEMI_DRIVERS = "com.microsemi.drivers";
129 public static final int PRIORITY_DEFAULT = 50000;
130 //To protect the NETCONF session from concurrent access across flow addition and removal
131 static Semaphore sessionMutex = new Semaphore(1);
132
133 /**
134 * Get the flow entries that are present on the EA1000.
135 * Since the EA1000 does not have any 'real' flow entries these are retrieved from 2 configuration
136 * areas on the EA1000 NETCONF model - from SA filtering YANG model and from EVC UNI YANG model.<br>
137 * The flow entries must match exactly the FlowRule entries in the ONOS store. If they are not an
138 * exact match the device will be requested to remove those flows and the FlowRule will stay in a
139 * PENDING_ADD state.
140 * @return A collection of Flow Entries
141 */
142 @Override
143 public Collection<FlowEntry> getFlowEntries() {
144 Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
145
146 UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
147 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
Sean Condon06613e92017-06-09 15:14:01 +0100148 NetconfDevice ncDevice = controller.getDevicesMap().get(handler().data().deviceId());
149 if (ncDevice == null) {
150 log.error("Internal ONOS Error. Device has been marked as reachable, " +
151 "but deviceID {} is not in Devices Map. Continuing with empty description",
152 handler().data().deviceId());
153 return flowEntryCollection;
154 }
155 NetconfSession session = ncDevice.getSession();
Sean Condonfae8e662016-12-15 10:25:13 +0000156 CoreService coreService = checkNotNull(handler().get(CoreService.class));
157 ApplicationId appId = coreService.getAppId(MICROSEMI_DRIVERS);
158 MseaSaFilteringNetconfService mseaSaFilteringService =
159 (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
160 MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
161 (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
162 log.debug("getFlowEntries() called on EA1000FlowRuleProgrammable");
163
164 //First get the MseaSaFiltering rules
Sean Condon06613e92017-06-09 15:14:01 +0100165 SourceIpaddressFiltering sip =
166 new DefaultSourceIpaddressFiltering();
Sean Condonfae8e662016-12-15 10:25:13 +0000167
Sean Condon06613e92017-06-09 15:14:01 +0100168 MseaSaFilteringOpParam op =
169 new MseaSaFilteringOpParam();
170 op.sourceIpaddressFiltering(sip);
171
Sean Condonfae8e662016-12-15 10:25:13 +0000172 try {
173 MseaSaFiltering saFilteringCurrent =
Sean Condon06613e92017-06-09 15:14:01 +0100174 mseaSaFilteringService.getMseaSaFiltering(op, session);
175 if (saFilteringCurrent != null &&
176 saFilteringCurrent.sourceIpaddressFiltering() != null) {
Sean Condonfae8e662016-12-15 10:25:13 +0000177 flowEntryCollection.addAll(
178 convertSaFilteringToFlowRules(saFilteringCurrent, appId));
179 }
180 } catch (NetconfException e) {
Sean Condon06613e92017-06-09 15:14:01 +0100181 if (e.getCause() instanceof TimeoutException) {
182 log.warn("Timeout exception getting SA Filt Flow Entries from {}",
183 handler().data().deviceId());
184 return flowEntryCollection;
185 } else {
186 log.error("Unexpected error on SA Filt getFlowEntries on {}",
187 handler().data().deviceId(), e);
Sean Condon7347de92017-07-21 12:17:25 +0100188 return flowEntryCollection;
Sean Condon06613e92017-06-09 15:14:01 +0100189 }
Sean Condonfae8e662016-12-15 10:25:13 +0000190 }
191
192
193 //Then get the EVCs - there will be a flow entry per EVC
Sean Condon06613e92017-06-09 15:14:01 +0100194 MefServices mefServices = new DefaultMefServices();
195 mefServices.uni(new DefaultUni());
Sean Condonfae8e662016-12-15 10:25:13 +0000196
Sean Condon06613e92017-06-09 15:14:01 +0100197 MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
198 mseaUniEvcServiceFilter.mefServices(mefServices);
Sean Condonfae8e662016-12-15 10:25:13 +0000199 try {
200 MseaUniEvcService uniEvcCurrent =
201 mseaUniEvcServiceSvc.getConfigMseaUniEvcService(mseaUniEvcServiceFilter,
Sean Condon06613e92017-06-09 15:14:01 +0100202 session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000203
204 flowEntryCollection.addAll(
205 convertEvcUniToFlowRules(uniEvcCurrent, portAssignment));
206
207 } catch (NetconfException e) {
Sean Condon06613e92017-06-09 15:14:01 +0100208 if (e.getCause() instanceof TimeoutException) {
209 log.warn("Timeout exception getting EVC Flow Entries from {}",
210 handler().data().deviceId());
211 return flowEntryCollection;
212 } else {
213 log.error("Unexpected error on EVC getFlowEntries on {}",
214 handler().data().deviceId(), e);
215 }
Sean Condonfae8e662016-12-15 10:25:13 +0000216 }
217
Sean Condonfae8e662016-12-15 10:25:13 +0000218 return flowEntryCollection;
219 }
220
221 /**
222 * Apply the flow entries to the EA1000.
223 * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
224 * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.<br>
225 * Only a subset of the possible OpenFlow rules are supported. Any rule that's not handled
226 * will not be in the returned set.
227 *
228 * @param rules A collection of Flow Rules to be applied to the EA1000
229 * @return A collection of the Flow Rules that have been added.
230 */
231 @Override
232 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
233 Collection<FlowRule> frAdded = new HashSet<FlowRule>();
234 if (rules == null || rules.size() == 0) {
235 return rules;
236 }
237 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
238 NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
239 MseaSaFilteringNetconfService mseaSaFilteringService =
240 (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
241 MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
242 (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
243 log.debug("applyFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rules.size());
244 // FIXME: Change this so it's dynamically driven
245 UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
246
247 List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
248 Map<Integer, Evc> evcMap = new HashMap<>();
249
250 //Retrieve the list of actual EVCs and the CeVlanMaps from device
251 List<Evc> activeEvcs = new ArrayList<>();
252 try {
253 sessionMutex.acquire();
254 MseaUniEvcService evcResponse =
Sean Condon06613e92017-06-09 15:14:01 +0100255 mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000256 //There could be zero or more EVCs
257 if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
258 activeEvcs.addAll(evcResponse.mefServices().uni().evc());
259 }
260 } catch (NetconfException | InterruptedException e1) {
261 log.warn("Unexpected error on applyFlowRules", e1);
262 }
263
264 for (FlowRule fr : rules) {
265
266 // IP SA Filtering can only apply to Port 0 optics
267 if (fr.selector().getCriterion(Type.IPV4_SRC) != null &&
268 fr.selector().getCriterion(Type.IN_PORT) != null &&
269 ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
270 parseFrForSaRange(frAdded, saRangeList, fr);
271
272 // EVCs will be defined by Flow Rules relating to VIDs
273 } else if (fr.selector().getCriterion(Type.VLAN_VID) != null &&
274 fr.selector().getCriterion(Type.IN_PORT) != null) {
275 //There could be many Flow Rules for one EVC depending on the ceVlanMap
276 //Cannot build up the EVC until we know the details - the key is the tableID and port
277 parseFrForEvcs(frAdded, evcMap, activeEvcs, portAssignment, fr);
278 } else {
279 log.info("Unexpected Flow Rule type applied: " + fr);
280 }
281 }
282
283 //If there are IPv4 Flow Rules created commit them now through the
284 //MseaSaFiltering service
285 if (saRangeList.size() > 0) {
286 try {
287 mseaSaFilteringService.setMseaSaFiltering(
Sean Condon06613e92017-06-09 15:14:01 +0100288 buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000289 } catch (NetconfException e) {
290 log.error("Error applying Flow Rules to SA Filtering - will try again: " + e.getMessage());
291 sessionMutex.release();
292 return frAdded;
293 }
294 }
295 //If there are EVC flow rules then populate the MseaUniEvc part of EA1000
296 if (evcMap.size() > 0) {
297 List<Evc> evcList = evcMap.entrySet().stream()
298 .map(x -> x.getValue())
299 .collect(Collectors.toList());
Sean Condon06613e92017-06-09 15:14:01 +0100300 Uni uni = new DefaultUni();
Sean Condonfae8e662016-12-15 10:25:13 +0000301 URI deviceName = handler().data().deviceId().uri();
Sean Condon06613e92017-06-09 15:14:01 +0100302 uni.name(new Identifier45("Uni-on-"
303 + deviceName.getSchemeSpecificPart()));
304 uni.evc(evcList);
Sean Condonfae8e662016-12-15 10:25:13 +0000305
306 List<BwpGroup> bwpGroupList = new ArrayList<BwpGroup>();
Sean Condon06613e92017-06-09 15:14:01 +0100307 BwpGroup bwpGrp = new DefaultBwpGroup();
308 bwpGrp.groupIndex((short) 0);
309 bwpGroupList.add(bwpGrp);
310 Profiles profiles = new DefaultProfiles();
311 profiles.bwpGroup(bwpGroupList);
Sean Condonfae8e662016-12-15 10:25:13 +0000312
Sean Condon06613e92017-06-09 15:14:01 +0100313 MefServices mefServices = new DefaultMefServices();
314 mefServices.uni(uni);
315 mefServices.profiles(profiles);
Sean Condonfae8e662016-12-15 10:25:13 +0000316
Sean Condon06613e92017-06-09 15:14:01 +0100317 MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
318 mseaUniEvcServiceFilter.mefServices(mefServices);
Sean Condonfae8e662016-12-15 10:25:13 +0000319 try {
Sean Condon06613e92017-06-09 15:14:01 +0100320 mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter, session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000321 } catch (NetconfException e) {
322 log.error("Error applying Flow Rules to EVC - will try again: " + e.getMessage());
323 sessionMutex.release();
324 return frAdded;
325 }
326 }
327 sessionMutex.release();
328 return frAdded;
329 }
330
331 /**
332 * Remove flow rules from the EA1000.
333 * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
334 * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.
335 *
336 * @param rulesToRemove A collection of Flow Rules to be removed to the EA1000
337 * @return A collection of the Flow Rules that have been removed.
338 */
339 @Override
340 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rulesToRemove) {
341 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
342 NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
343 MseaSaFilteringNetconfService mseaSaFilteringService =
344 (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
345 MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
346 (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
347 UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
348 log.debug("removeFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rulesToRemove.size());
349
350 if (rulesToRemove.size() == 0) {
351 return rulesToRemove;
352 }
353
354 //Retrieve the list of actual EVCs and the CeVlanMaps from device
355 List<Evc> activeEvcs = new ArrayList<>();
Sean Condon06613e92017-06-09 15:14:01 +0100356 List<Short> acvtiveFiltRanges = new ArrayList<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000357 try {
358 sessionMutex.acquire();
359 MseaUniEvcService evcResponse =
Sean Condon06613e92017-06-09 15:14:01 +0100360 mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000361 //There could be zero or more EVCs
362 if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
363 activeEvcs.addAll(evcResponse.mefServices().uni().evc());
364 }
Sean Condon06613e92017-06-09 15:14:01 +0100365 mseaSaFilteringService.getConfigMseaSaFilterIds(session).forEach(
366 r -> acvtiveFiltRanges.add(r.rangeId()));
367
Sean Condonfae8e662016-12-15 10:25:13 +0000368 } catch (NetconfException | InterruptedException e1) {
369 log.warn("Error on removeFlowRules.", e1);
370 }
371
372 List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
373 Map<Integer, String> ceVlanMapMap = new HashMap<>();
374 Map<Integer, List<Short>> flowIdMap = new HashMap<>();
375
376 Collection<FlowRule> rulesRemoved = new HashSet<FlowRule>();
377 for (FlowRule ruleToRemove : rulesToRemove) {
378 // IP SA Filtering can only apply to Port 0 optics
379 if (ruleToRemove.selector().getCriterion(Type.IPV4_SRC) != null &&
380 ruleToRemove.selector().getCriterion(Type.IN_PORT) != null &&
381 ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
Sean Condon06613e92017-06-09 15:14:01 +0100382 SourceAddressRange sar = new DefaultSourceAddressRange();
383 sar.rangeId((short) ruleToRemove.tableId());
384 acvtiveFiltRanges.remove(Short.valueOf((short) ruleToRemove.tableId()));
Sean Condonfae8e662016-12-15 10:25:13 +0000385 rulesRemoved.add(ruleToRemove);
386 saRangeList.add(sar);
387
388 } else if (ruleToRemove.selector().getCriterion(Type.VLAN_VID) != null &&
389 ruleToRemove.selector().getCriterion(Type.IN_PORT) != null) {
390 PortNumber portNumber = ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port();
391 VlanId vlanId = ((VlanIdCriterion) ruleToRemove.selector().getCriterion(Type.VLAN_VID)).vlanId();
392 int evcId = ruleToRemove.tableId();
393 int evcKey = (evcId << 2) + (int) portNumber.toLong();
394 String activeCeVlanMap = "";
395 //If this is one of many VLANs belonging to an EVC then we should only remove this VLAN
396 // from the ceVlanMap and not the whole EVC
397 if (!ceVlanMapMap.containsKey(evcKey)) {
398 for (Evc activeEvc:activeEvcs) {
399 if (activeEvc.evcIndex() == evcId) {
400 if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
401 UniSide.CUSTOMER) {
402 activeCeVlanMap = activeEvc.evcPerUni().evcPerUnic().ceVlanMap().string();
403 } else if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
404 UniSide.NETWORK) {
405 activeCeVlanMap = activeEvc.evcPerUni().evcPerUnin().ceVlanMap().string();
406 }
407 }
408 }
409 }
410
411 ceVlanMapMap.put(evcKey, CeVlanMapUtils.removeFromCeVlanMap(activeCeVlanMap, vlanId.id()));
412 if (!flowIdMap.containsKey(evcKey)) {
413 flowIdMap.put(evcKey, new ArrayList<>());
414 }
415 flowIdMap.get(evcKey).add(vlanId.id());
416 rulesRemoved.add(ruleToRemove);
417
418 } else {
419 log.info("Unexpected Flow Rule type removal: " + ruleToRemove);
420 }
421 }
422
423 //If there are IPv4 Flow Rules created commit them now through the
424 //MseaSaFiltering service
Sean Condon06613e92017-06-09 15:14:01 +0100425 if (saRangeList.size() > 0 && acvtiveFiltRanges.size() == 0) {
Sean Condonfae8e662016-12-15 10:25:13 +0000426 try {
Sean Condon06613e92017-06-09 15:14:01 +0100427 SourceIpaddressFiltering saFilter =
428 new DefaultSourceIpaddressFiltering();
429 MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
430 mseaSaFiltering.sourceIpaddressFiltering(saFilter);
431
432 mseaSaFilteringService.deleteMseaSaFilteringRange(
433 mseaSaFiltering, session, DatastoreId.RUNNING);
434 } catch (NetconfException e) {
435 log.warn("Remove FlowRule on MseaSaFilteringService could not delete all SARules - "
436 + "they may already have been deleted: " + e.getMessage());
437 }
438 } else if (saRangeList.size() > 0) {
439 try {
440 mseaSaFilteringService.deleteMseaSaFilteringRange(
441 buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000442 } catch (NetconfException e) {
443 log.warn("Remove FlowRule on MseaSaFilteringService could not delete SARule - "
444 + "it may already have been deleted: " + e.getMessage());
445 }
446 }
447
448 if (ceVlanMapMap.size() > 0) {
449 try {
450 mseaUniEvcServiceSvc.removeEvcUniFlowEntries(ceVlanMapMap, flowIdMap,
Sean Condon06613e92017-06-09 15:14:01 +0100451 session, DatastoreId.RUNNING, portAssignment);
Sean Condonfae8e662016-12-15 10:25:13 +0000452 } catch (NetconfException e) {
453 log.warn("Remove FlowRule on MseaUniEvcService could not delete EVC - "
454 + "it may already have been deleted: " + e.getMessage());
455 }
456 }
457
458 sessionMutex.release();
459 return rulesRemoved;
460 }
461
462 /**
463 * An internal method for extracting one EVC from a list and returning its ceVlanMap.
464 *
465 * @param evcList - the list of known EVCs
466 * @param evcIndex - the index of the EVC we're looking for
467 * @param side - the side of the UNI
468 * @return - the CEVlanMap we're looking for
469 */
470 private String getCeVlanMapForIdxFromEvcList(List<Evc> evcList, long evcIndex, UniSide side) {
471 if (evcList != null && evcList.size() > 0) {
472 for (Evc evc:evcList) {
473 if (evc.evcIndex() == evcIndex && evc.evcPerUni() != null) {
474 if (side == UniSide.CUSTOMER &&
475 evc.evcPerUni().evcPerUnic() != null &&
476 evc.evcPerUni().evcPerUnic().ceVlanMap() != null) {
477 return evc.evcPerUni().evcPerUnic().ceVlanMap().string();
478 } else if (side == UniSide.NETWORK &&
479 evc.evcPerUni().evcPerUnin() != null &&
480 evc.evcPerUni().evcPerUnin().ceVlanMap() != null) {
481 return evc.evcPerUni().evcPerUnin().ceVlanMap().string();
482 }
483 }
484 }
485 }
486
487 return ""; //The EVC required was not in the list
488 }
489
490 /**
491 * An internal method to convert from a FlowRule to SARange.
492 *
493 * @param frList A collection of flow rules
494 * @param saRangeList A list of SARanges
495 * @param fr A flow rule
496 */
497 private void parseFrForSaRange(Collection<FlowRule> frList, List<SourceAddressRange> saRangeList, FlowRule fr) {
498 String ipAddrStr = fr.selector().getCriterion(Type.IPV4_SRC).toString().substring(9);
499 log.debug("Applying IP address to " + ipAddrStr
500 + " (on Port 0) to IP SA Filtering on EA1000 through NETCONF");
501
Sean Condon06613e92017-06-09 15:14:01 +0100502 SourceAddressRange sar =
503 new DefaultSourceAddressRange();
Sean Condonfae8e662016-12-15 10:25:13 +0000504
Sean Condon06613e92017-06-09 15:14:01 +0100505 sar.rangeId((short) fr.tableId());
506 sar.name("Flow:" + fr.id().toString());
507 sar.ipv4AddressPrefix(ipAddrStr);
Sean Condonfae8e662016-12-15 10:25:13 +0000508
509 frList.add(fr);
510 saRangeList.add(sar);
511 }
512
513 private void parseFrForEvcs(Collection<FlowRule> frList, Map<Integer, Evc> evcMap,
514 List<Evc> activeEvcs, UniSideInterfaceAssignmentEnum portAssignment, FlowRule fr) {
515 //There could be many Flow Rules for one EVC depending on the ceVlanMap
516 //Cannot build up the EVC until we know the details - the key is the tableID and port
517 Ea1000Port port = Ea1000Port.fromNum(
518 ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong());
519 Integer evcKey = (fr.tableId() << 2) + port.portNum();
520 VlanId sourceVid = ((VlanIdCriterion) fr.selector().getCriterion(Type.VLAN_VID)).vlanId();
Sean Condon06613e92017-06-09 15:14:01 +0100521 FlowMapping fm = new DefaultFlowMapping();
522 fm.ceVlanId(VlanIdType.of(sourceVid.id()));
523 fm.flowId(BigInteger.valueOf(fr.id().value()));
524
Sean Condonfae8e662016-12-15 10:25:13 +0000525 if (evcMap.containsKey(evcKey)) { //Is there an entry already for this EVC and port?
526 //Replace ceVlanMap
Sean Condon06613e92017-06-09 15:14:01 +0100527 if (port.nOrC(portAssignment) == UniSide.CUSTOMER) {
528 evcMap.get(evcKey).evcPerUni().evcPerUnic().addToFlowMapping(fm);
529 ServiceListType newCeVlanMap = new ServiceListType(
530 CeVlanMapUtils.addtoCeVlanMap(
531 evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap().toString(),
532 sourceVid.toShort()));
533 evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
534 } else {
535 evcMap.get(evcKey).evcPerUni().evcPerUnin().addToFlowMapping(fm);
536 ServiceListType newCeVlanMap = new ServiceListType(
537 CeVlanMapUtils.addtoCeVlanMap(
538 evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap().toString(),
539 sourceVid.toShort()));
540 evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
541 }
Sean Condonfae8e662016-12-15 10:25:13 +0000542 } else if (evcMap.containsKey((evcKey ^ 1))) { //Is there an entry for this EVC but the opposite port?
543 TagManipulation tm = getTagManipulation(fr);
544 if (port.nOrC(portAssignment) == UniSide.NETWORK) {
Sean Condon06613e92017-06-09 15:14:01 +0100545 ServiceListType newCeVlanMap = new ServiceListType(
546 CeVlanMapUtils.addtoCeVlanMap(
547 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap().toString(),
548 sourceVid.toShort()));
549 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
550 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().tagManipulation(tm);
551 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().addToFlowMapping(fm);
552 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000553 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100554 ServiceListType newCeVlanMap = new ServiceListType(
555 CeVlanMapUtils.addtoCeVlanMap(
556 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap().toString(),
557 sourceVid.toShort()));
558 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
559 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().tagManipulation(tm);
560 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().addToFlowMapping(fm);
561 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000562 }
563 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100564 Evc evc = new DefaultEvc();
565 EvcPerUnin epun = new CustomEvcPerUnin();
566 EvcPerUnic epuc = new CustomEvcPerUnic();
Sean Condonfae8e662016-12-15 10:25:13 +0000567 TagManipulation tm = getTagManipulation(fr);
568
569 UniSide side = port.nOrC(portAssignment);
570 String oldCeVlanMap = getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(), side);
571 String newCeVlanMap =
572 CeVlanMapUtils.addtoCeVlanMap(oldCeVlanMap, sourceVid.id());
573 String oppositeCeVlanMap =
574 getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(),
575 port.opposite().nOrC(portAssignment));
576 oppositeCeVlanMap = oppositeCeVlanMap.isEmpty() ? "0" : oppositeCeVlanMap;
577 if (side == UniSide.NETWORK) {
Sean Condon06613e92017-06-09 15:14:01 +0100578 epun.ceVlanMap(new ServiceListType(newCeVlanMap));
579 epun.tagManipulation(tm);
580 epun.addToFlowMapping(fm);
581 epun.ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000582
Sean Condon06613e92017-06-09 15:14:01 +0100583 epuc.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
584 epuc.ingressBwpGroupIndex(new Long(0));
Sean Condonfae8e662016-12-15 10:25:13 +0000585 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100586 epuc.ceVlanMap(new ServiceListType(newCeVlanMap));
587 epuc.tagManipulation(tm);
588 epuc.addToFlowMapping(fm);
589 epuc.ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000590
Sean Condon06613e92017-06-09 15:14:01 +0100591 epun.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
592 epun.ingressBwpGroupIndex(new Long(0));
Sean Condonfae8e662016-12-15 10:25:13 +0000593 }
594
Sean Condon06613e92017-06-09 15:14:01 +0100595 evc.evcIndex(fr.tableId());
596 evc.name(new Identifier45("EVC-" + String.valueOf(fr.tableId())));
597
598 DefaultEvcPerUni epu = new DefaultEvcPerUni();
599 epu.evcPerUnin(epun);
600 epu.evcPerUnic(epuc);
601 evc.evcPerUni(epu);
602
603 evcMap.put(evcKey, evc);
Sean Condonfae8e662016-12-15 10:25:13 +0000604 }
605
606 frList.add(fr);
607 }
608
609
610 private MseaSaFilteringOpParam buildSaFilteringObject(List<SourceAddressRange> saRangeList) {
Sean Condon06613e92017-06-09 15:14:01 +0100611 InterfaceEth0 saIf = new DefaultInterfaceEth0();
Sean Condonfae8e662016-12-15 10:25:13 +0000612 for (SourceAddressRange sa:saRangeList) {
Sean Condon06613e92017-06-09 15:14:01 +0100613 saIf.addToSourceAddressRange(sa);
Sean Condonfae8e662016-12-15 10:25:13 +0000614 }
Sean Condon06613e92017-06-09 15:14:01 +0100615 saIf.filterAdminState(FilterAdminStateEnum.BLACKLIST);
Sean Condonfae8e662016-12-15 10:25:13 +0000616
Sean Condon06613e92017-06-09 15:14:01 +0100617 SourceIpaddressFiltering saFilter =
618 new DefaultSourceIpaddressFiltering();
619 saFilter.interfaceEth0(saIf);
Sean Condonfae8e662016-12-15 10:25:13 +0000620
Sean Condon06613e92017-06-09 15:14:01 +0100621 MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
622 mseaSaFiltering.sourceIpaddressFiltering(saFilter);
Sean Condonfae8e662016-12-15 10:25:13 +0000623
624 return mseaSaFiltering;
625 }
626
627 private Collection<FlowEntry> convertSaFilteringToFlowRules(
628 MseaSaFiltering saFilteringCurrent, ApplicationId appId) {
629 Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
630
631 List<SourceAddressRange> saRangelist =
632 saFilteringCurrent.sourceIpaddressFiltering().interfaceEth0().sourceAddressRange();
633 Criterion matchInPort = Criteria.matchInPort(PortNumber.portNumber(0));
634 TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
635
Sean Condon06613e92017-06-09 15:14:01 +0100636 if (saRangelist != null) {
637 for (SourceAddressRange sa : saRangelist) {
638 Criterion matchIpSrc = Criteria.matchIPSrc(IpPrefix.valueOf(sa.ipv4AddressPrefix()));
Sean Condonfae8e662016-12-15 10:25:13 +0000639
Sean Condon06613e92017-06-09 15:14:01 +0100640 TrafficSelector selector = tsBuilder.add(matchIpSrc).add(matchInPort).build();
Sean Condonfae8e662016-12-15 10:25:13 +0000641
Sean Condon06613e92017-06-09 15:14:01 +0100642 TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
643 TrafficTreatment treatment = trBuilder.drop().build();
Sean Condonfae8e662016-12-15 10:25:13 +0000644
Sean Condon06613e92017-06-09 15:14:01 +0100645 FlowRule.Builder feBuilder = new DefaultFlowRule.Builder();
646 if (sa.name() != null && sa.name().startsWith("Flow:")) {
647 String[] nameParts = sa.name().split(":");
648 Long cookie = Long.valueOf(nameParts[1], 16);
649 feBuilder = feBuilder.withCookie(cookie);
650 } else {
651 feBuilder = feBuilder.fromApp(appId);
652 }
653
654 FlowRule fr = feBuilder
655 .forDevice(handler().data().deviceId())
656 .withSelector(selector)
657 .withTreatment(treatment)
658 .forTable(sa.rangeId())
659 .makePermanent()
660 .withPriority(PRIORITY_DEFAULT)
661 .build();
662
663 flowEntryCollection.add(
664 new DefaultFlowEntry(fr, FlowEntryState.ADDED, 0, 0, 0));
Sean Condonfae8e662016-12-15 10:25:13 +0000665 }
Sean Condonfae8e662016-12-15 10:25:13 +0000666 }
Sean Condonfae8e662016-12-15 10:25:13 +0000667 return flowEntryCollection;
668 }
669
670
671 private Collection<FlowEntry> convertEvcUniToFlowRules(
672 MseaUniEvcService uniEvcCurrent, UniSideInterfaceAssignmentEnum portAssignment) {
673 Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
674
675 if (uniEvcCurrent == null || uniEvcCurrent.mefServices() == null ||
676 uniEvcCurrent.mefServices().uni() == null || uniEvcCurrent.mefServices().uni().evc() == null) {
677 log.info("No EVC's found when getting flow rules");
678 return flowEntryCollection;
679 }
680
681 for (Evc evc:uniEvcCurrent.mefServices().uni().evc()) {
682 FlowRule.Builder frBuilder = new DefaultFlowRule.Builder();
683 TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
684
685 TrafficTreatment uniNTreatment = treatmentForUniSde(evc.evcPerUni(), true);
686 //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
687 Short[] vlanIdsUniN =
688 CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), true));
689 for (Short vlanId:vlanIdsUniN) {
690 if (vlanId == 0) {
691 continue;
692 }
693 Criterion uniNportCriterion = criterionPortForUniSide(portAssignment, true);
694 TrafficSelector tsUniN = tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniNportCriterion).build();
695 long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnin().flowMapping(), vlanId);
696
697 FlowRule frUniN = frBuilder
698 .forDevice(handler().data().deviceId())
699 .withSelector(tsUniN)
700 .withTreatment(uniNTreatment)
701 .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
702 .makePermanent()
703 .withPriority(PRIORITY_DEFAULT)
704 .withCookie(flowId)
705 .build();
706 flowEntryCollection.add(new DefaultFlowEntry(frUniN, FlowEntryState.ADDED, 0, 0, 0));
707 }
708
709 TrafficTreatment uniCTreatment = treatmentForUniSde(evc.evcPerUni(), false);
710 //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
711 Short[] vlanIdsUniC =
712 CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), false));
713 if (vlanIdsUniC != null && vlanIdsUniC.length > 0) {
714 for (Short vlanId:vlanIdsUniC) {
715 if (vlanId == 0) {
716 continue;
717 }
718 Criterion uniCportCriterion = criterionPortForUniSide(portAssignment, false);
719 TrafficSelector tsUniC =
720 tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniCportCriterion).build();
721 long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnic().flowMapping(), vlanId);
722
723 FlowRule frUniC = frBuilder
724 .forDevice(handler().data().deviceId())
725 .withSelector(tsUniC)
726 .withTreatment(uniCTreatment)
727 .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
728 .makePermanent()
729 .withPriority(PRIORITY_DEFAULT)
730 .withCookie(flowId)
731 .build();
732 flowEntryCollection.add(new DefaultFlowEntry(frUniC, FlowEntryState.ADDED, 0, 0, 0));
733 }
734 }
735 }
736
737 return flowEntryCollection;
738 }
739
740 private long getFlowIdForVlan(List<FlowMapping> fmList, Short vlanId) {
741 if (fmList == null || vlanId == null) {
742 log.warn("Flow Mapping list is null when reading EVCs");
743 return -1L;
744 }
745 for (FlowMapping fm:fmList) {
746 if (fm.ceVlanId().uint16() == vlanId.intValue()) {
747 return fm.flowId().longValue();
748 }
749 }
750 return 0L;
751 }
752
753 private String ceVlanMapForUniSide(
754 EvcPerUni evcPerUni, boolean portN) {
755 if (portN) {
756 return evcPerUni.evcPerUnin().ceVlanMap().string();
757 } else {
758 return evcPerUni.evcPerUnic().ceVlanMap().string();
759 }
760 }
761
762 private Criterion criterionPortForUniSide(
763 UniSideInterfaceAssignmentEnum portAssignment, boolean portN) {
764 boolean cOnOptics = (portAssignment == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS);
765 int portNum = ((cOnOptics && portN) || (!cOnOptics && !portN)) ? 1 : 0;
766 return Criteria.matchInPort(PortNumber.portNumber(portNum));
767 }
768
769 private TrafficTreatment treatmentForUniSde(
770 EvcPerUni evcPerUni, boolean portN) {
771 TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
772
773 TagManipulation tm = null;
774 short meterId = 0;
775 if (portN) {
776 tm = evcPerUni.evcPerUnin().tagManipulation();
777 meterId = (short) evcPerUni.evcPerUnin().ingressBwpGroupIndex();
778 } else {
779 tm = evcPerUni.evcPerUnic().tagManipulation();
780 meterId = (short) evcPerUni.evcPerUnic().ingressBwpGroupIndex();
781 }
782
783 if (meterId > 0L) {
784 trBuilder = trBuilder.meter(MeterId.meterId((long) meterId));
785// trBuilder = trBuilder.meter(MeterId.meterId(meterId)).transition(0);
786 }
787
788 if (tm == null) {
789 return trBuilder.build(); //no tag manipulation found
790 }
791
792 if (tm.getClass().equals(DefaultTagPush.class)) {
793 VlanId pushVlanNum = VlanId.vlanId((short) ((TagPush) tm).tagPush().outerTagVlan().uint16());
794 PushTagTypeEnum pushTagType = ((TagPush) tm).tagPush().pushTagType();
795 //Note - the order of elements below MUST match the order of the Treatment in the stored FlowRule
796 // to be an exactMatch. See DefaultFlowRule.exactMatch()
797 trBuilder = trBuilder
798 .pushVlan(pushTagType.equals(PushTagTypeEnum.PUSHCTAG) ?
799 EtherType.VLAN.ethType() : EtherType.QINQ.ethType())
800 .setVlanId(pushVlanNum).transition(Integer.valueOf(0));
801
802 } else if (tm.getClass().equals(DefaultTagPop.class)) {
803 trBuilder = trBuilder.popVlan();
804
805 } else if (tm.getClass().equals(DefaultTagOverwrite.class)) {
806 TagOverwrite to = (TagOverwrite) tm;
807 VlanId ovrVlanNum = VlanId
808 .vlanId((short) (
809 //There are 2 classes TagOverwrite - the other one is already imported
810 to
811 .tagOverwrite()
812 .outerTagVlan()
813 .uint16()));
814 trBuilder = trBuilder.setVlanId(ovrVlanNum);
815
816 }
817
818 return trBuilder.build();
819 }
820
821 private static TagManipulation getTagManipulation(FlowRule fr) {
822 boolean isPop = false;
823 boolean isPush = false;
824 VlanId vlanId = null;
825 EthType ethType = EtherType.VLAN.ethType(); //Default
826 for (Instruction inst:fr.treatment().allInstructions()) {
827 if (inst.type() == Instruction.Type.L2MODIFICATION) {
828 L2ModificationInstruction l2Mod = (L2ModificationInstruction) inst;
829 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
830 isPop = true;
831 } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
832 isPush = true;
833 ethType = ((ModVlanHeaderInstruction) l2Mod).ethernetType();
834 } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
835 vlanId = ((ModVlanIdInstruction) l2Mod).vlanId();
836 }
837 }
838 }
839
840 if (isPop) {
841 //The should be no vlanId in this case
Sean Condon06613e92017-06-09 15:14:01 +0100842 TagPop pop = new DefaultTagPop();
843 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
844 .evcperuniextensionattributes.tagmanipulation
845 .tagpop.TagPop popInner =
846 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
847 .mseaunievcservice.evcperuniextensionattributes
848 .tagmanipulation.tagpop.DefaultTagPop();
849 pop.tagPop(popInner);
850 return pop;
Sean Condonfae8e662016-12-15 10:25:13 +0000851
852 } else if (isPush && vlanId != null) {
Sean Condon06613e92017-06-09 15:14:01 +0100853 TagPush push = new DefaultTagPush();
854 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
855 .evcperuniextensionattributes.tagmanipulation
856 .tagpush.TagPush pushInner =
857 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
858 .mseaunievcservice.evcperuniextensionattributes
859 .tagmanipulation.tagpush.DefaultTagPush();
860 pushInner.outerTagVlan(new VlanIdType(vlanId.id()));
861 pushInner.pushTagType(ethType.equals(EtherType.VLAN.ethType()) ?
862 PushTagTypeEnum.PUSHCTAG : PushTagTypeEnum.PUSHSTAG);
863 push.tagPush(pushInner);
864 return push;
Sean Condonfae8e662016-12-15 10:25:13 +0000865
866 } else if (vlanId != null) { //This is overwrite, as it has vlanId, but not push or pop
Sean Condon06613e92017-06-09 15:14:01 +0100867 TagOverwrite ovr = new DefaultTagOverwrite();
868 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
869 .evcperuniextensionattributes.tagmanipulation
870 .tagoverwrite.TagOverwrite ovrInner =
871 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
872 .mseaunievcservice.evcperuniextensionattributes
873 .tagmanipulation.tagoverwrite.DefaultTagOverwrite();
874 ovrInner.outerTagVlan(new VlanIdType(vlanId.id()));
875 ovr.tagOverwrite(ovrInner);
876 return ovr;
Sean Condonfae8e662016-12-15 10:25:13 +0000877 }
878
879 return null;
880 }
881
882 private static long getMeterId(TrafficTreatment treatment) {
883 return (treatment.metered() != null && treatment.metered().meterId() != null)
884 ? treatment.metered().meterId().id() : 0L;
885 }
886
887 /**
888 * An enumerated type that characterises the 2 port layout of the EA1000 device.
889 * The device is in an SFP package and has only 2 ports, the HOST port which
890 * plugs in to the chassis (Port 1) and the Optics Port on the rear (Port 0).
891 */
892 public enum Ea1000Port {
893 HOST(1),
894 OPTICS(0);
895
896 private int num = 0;
897 private Ea1000Port(int num) {
898 this.num = num;
899 }
900
901 /**
902 * The numerical assignment of this port.
903 * @return The port number
904 */
905 public int portNum() {
906 return num;
907 }
908
909 /**
910 * Return the enumerated value from a port number.
911 * @param num The port number
912 * @return An enumerated value
913 */
914 public static Ea1000Port fromNum(long num) {
915 for (Ea1000Port a:Ea1000Port.values()) {
916 if (a.num == num) {
917 return a;
918 }
919 }
920 return HOST;
921 }
922
923 /**
924 * Get the port that the UNI-N is present on.
925 * @param side The assignment of UNI-side to port
926 * @return An enumerated value
927 */
928 public static Ea1000Port uniNNum(UniSideInterfaceAssignmentEnum side) {
929 if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
930 return OPTICS;
931 } else {
932 return HOST;
933 }
934 }
935
936 /**
937 * Get the port that the UNI-C is present on.
938 * @param side The assignment of UNI-side to port
939 * @return An enumerated value
940 */
941 public static Ea1000Port uniCNum(UniSideInterfaceAssignmentEnum side) {
942 if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
943 return HOST;
944 } else {
945 return OPTICS;
946 }
947 }
948
949 /**
950 * Get the port opposite the current port.
951 * @return An enumerated value for the opposite side
952 */
953 public Ea1000Port opposite() {
954 if (this.equals(HOST)) {
955 return OPTICS;
956 } else {
957 return HOST;
958 }
959 }
960
961 /**
962 * Evaluate which side of the UNI on the EA1000 device this port refers to.
963 * @param side The assignment of UNI-side to port
964 * @return An enumerated value representing the UniSide
965 */
966 public UniSide nOrC(UniSideInterfaceAssignmentEnum side) {
967 if ((this == HOST && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST) ||
968 (this == OPTICS && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS)) {
969 return UniSide.CUSTOMER;
970 } else {
971 return UniSide.NETWORK;
972 }
973 }
974 }
975}