blob: 4df22ecc184490a30c8b2458e3006b0cd8627d31 [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);
188 }
Sean Condonfae8e662016-12-15 10:25:13 +0000189 }
190
191
192 //Then get the EVCs - there will be a flow entry per EVC
Sean Condon06613e92017-06-09 15:14:01 +0100193 MefServices mefServices = new DefaultMefServices();
194 mefServices.uni(new DefaultUni());
Sean Condonfae8e662016-12-15 10:25:13 +0000195
Sean Condon06613e92017-06-09 15:14:01 +0100196 MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
197 mseaUniEvcServiceFilter.mefServices(mefServices);
Sean Condonfae8e662016-12-15 10:25:13 +0000198 try {
199 MseaUniEvcService uniEvcCurrent =
200 mseaUniEvcServiceSvc.getConfigMseaUniEvcService(mseaUniEvcServiceFilter,
Sean Condon06613e92017-06-09 15:14:01 +0100201 session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000202
203 flowEntryCollection.addAll(
204 convertEvcUniToFlowRules(uniEvcCurrent, portAssignment));
205
206 } catch (NetconfException e) {
Sean Condon06613e92017-06-09 15:14:01 +0100207 if (e.getCause() instanceof TimeoutException) {
208 log.warn("Timeout exception getting EVC Flow Entries from {}",
209 handler().data().deviceId());
210 return flowEntryCollection;
211 } else {
212 log.error("Unexpected error on EVC getFlowEntries on {}",
213 handler().data().deviceId(), e);
214 }
Sean Condonfae8e662016-12-15 10:25:13 +0000215 }
216
Sean Condonfae8e662016-12-15 10:25:13 +0000217 return flowEntryCollection;
218 }
219
220 /**
221 * Apply the flow entries to the EA1000.
222 * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
223 * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.<br>
224 * Only a subset of the possible OpenFlow rules are supported. Any rule that's not handled
225 * will not be in the returned set.
226 *
227 * @param rules A collection of Flow Rules to be applied to the EA1000
228 * @return A collection of the Flow Rules that have been added.
229 */
230 @Override
231 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
232 Collection<FlowRule> frAdded = new HashSet<FlowRule>();
233 if (rules == null || rules.size() == 0) {
234 return rules;
235 }
236 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
237 NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
238 MseaSaFilteringNetconfService mseaSaFilteringService =
239 (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
240 MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
241 (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
242 log.debug("applyFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rules.size());
243 // FIXME: Change this so it's dynamically driven
244 UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
245
246 List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
247 Map<Integer, Evc> evcMap = new HashMap<>();
248
249 //Retrieve the list of actual EVCs and the CeVlanMaps from device
250 List<Evc> activeEvcs = new ArrayList<>();
251 try {
252 sessionMutex.acquire();
253 MseaUniEvcService evcResponse =
Sean Condon06613e92017-06-09 15:14:01 +0100254 mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000255 //There could be zero or more EVCs
256 if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
257 activeEvcs.addAll(evcResponse.mefServices().uni().evc());
258 }
259 } catch (NetconfException | InterruptedException e1) {
260 log.warn("Unexpected error on applyFlowRules", e1);
261 }
262
263 for (FlowRule fr : rules) {
264
265 // IP SA Filtering can only apply to Port 0 optics
266 if (fr.selector().getCriterion(Type.IPV4_SRC) != null &&
267 fr.selector().getCriterion(Type.IN_PORT) != null &&
268 ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
269 parseFrForSaRange(frAdded, saRangeList, fr);
270
271 // EVCs will be defined by Flow Rules relating to VIDs
272 } else if (fr.selector().getCriterion(Type.VLAN_VID) != null &&
273 fr.selector().getCriterion(Type.IN_PORT) != null) {
274 //There could be many Flow Rules for one EVC depending on the ceVlanMap
275 //Cannot build up the EVC until we know the details - the key is the tableID and port
276 parseFrForEvcs(frAdded, evcMap, activeEvcs, portAssignment, fr);
277 } else {
278 log.info("Unexpected Flow Rule type applied: " + fr);
279 }
280 }
281
282 //If there are IPv4 Flow Rules created commit them now through the
283 //MseaSaFiltering service
284 if (saRangeList.size() > 0) {
285 try {
286 mseaSaFilteringService.setMseaSaFiltering(
Sean Condon06613e92017-06-09 15:14:01 +0100287 buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000288 } catch (NetconfException e) {
289 log.error("Error applying Flow Rules to SA Filtering - will try again: " + e.getMessage());
290 sessionMutex.release();
291 return frAdded;
292 }
293 }
294 //If there are EVC flow rules then populate the MseaUniEvc part of EA1000
295 if (evcMap.size() > 0) {
296 List<Evc> evcList = evcMap.entrySet().stream()
297 .map(x -> x.getValue())
298 .collect(Collectors.toList());
Sean Condon06613e92017-06-09 15:14:01 +0100299 Uni uni = new DefaultUni();
Sean Condonfae8e662016-12-15 10:25:13 +0000300 URI deviceName = handler().data().deviceId().uri();
Sean Condon06613e92017-06-09 15:14:01 +0100301 uni.name(new Identifier45("Uni-on-"
302 + deviceName.getSchemeSpecificPart()));
303 uni.evc(evcList);
Sean Condonfae8e662016-12-15 10:25:13 +0000304
305 List<BwpGroup> bwpGroupList = new ArrayList<BwpGroup>();
Sean Condon06613e92017-06-09 15:14:01 +0100306 BwpGroup bwpGrp = new DefaultBwpGroup();
307 bwpGrp.groupIndex((short) 0);
308 bwpGroupList.add(bwpGrp);
309 Profiles profiles = new DefaultProfiles();
310 profiles.bwpGroup(bwpGroupList);
Sean Condonfae8e662016-12-15 10:25:13 +0000311
Sean Condon06613e92017-06-09 15:14:01 +0100312 MefServices mefServices = new DefaultMefServices();
313 mefServices.uni(uni);
314 mefServices.profiles(profiles);
Sean Condonfae8e662016-12-15 10:25:13 +0000315
Sean Condon06613e92017-06-09 15:14:01 +0100316 MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
317 mseaUniEvcServiceFilter.mefServices(mefServices);
Sean Condonfae8e662016-12-15 10:25:13 +0000318 try {
Sean Condon06613e92017-06-09 15:14:01 +0100319 mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter, session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000320 } catch (NetconfException e) {
321 log.error("Error applying Flow Rules to EVC - will try again: " + e.getMessage());
322 sessionMutex.release();
323 return frAdded;
324 }
325 }
326 sessionMutex.release();
327 return frAdded;
328 }
329
330 /**
331 * Remove flow rules from the EA1000.
332 * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
333 * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.
334 *
335 * @param rulesToRemove A collection of Flow Rules to be removed to the EA1000
336 * @return A collection of the Flow Rules that have been removed.
337 */
338 @Override
339 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rulesToRemove) {
340 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
341 NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
342 MseaSaFilteringNetconfService mseaSaFilteringService =
343 (MseaSaFilteringNetconfService) checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
344 MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
345 (MseaUniEvcServiceNetconfService) checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
346 UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
347 log.debug("removeFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rulesToRemove.size());
348
349 if (rulesToRemove.size() == 0) {
350 return rulesToRemove;
351 }
352
353 //Retrieve the list of actual EVCs and the CeVlanMaps from device
354 List<Evc> activeEvcs = new ArrayList<>();
Sean Condon06613e92017-06-09 15:14:01 +0100355 List<Short> acvtiveFiltRanges = new ArrayList<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000356 try {
357 sessionMutex.acquire();
358 MseaUniEvcService evcResponse =
Sean Condon06613e92017-06-09 15:14:01 +0100359 mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000360 //There could be zero or more EVCs
361 if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
362 activeEvcs.addAll(evcResponse.mefServices().uni().evc());
363 }
Sean Condon06613e92017-06-09 15:14:01 +0100364 mseaSaFilteringService.getConfigMseaSaFilterIds(session).forEach(
365 r -> acvtiveFiltRanges.add(r.rangeId()));
366
Sean Condonfae8e662016-12-15 10:25:13 +0000367 } catch (NetconfException | InterruptedException e1) {
368 log.warn("Error on removeFlowRules.", e1);
369 }
370
371 List<SourceAddressRange> saRangeList = new ArrayList<SourceAddressRange>();
372 Map<Integer, String> ceVlanMapMap = new HashMap<>();
373 Map<Integer, List<Short>> flowIdMap = new HashMap<>();
374
375 Collection<FlowRule> rulesRemoved = new HashSet<FlowRule>();
376 for (FlowRule ruleToRemove : rulesToRemove) {
377 // IP SA Filtering can only apply to Port 0 optics
378 if (ruleToRemove.selector().getCriterion(Type.IPV4_SRC) != null &&
379 ruleToRemove.selector().getCriterion(Type.IN_PORT) != null &&
380 ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
Sean Condon06613e92017-06-09 15:14:01 +0100381 SourceAddressRange sar = new DefaultSourceAddressRange();
382 sar.rangeId((short) ruleToRemove.tableId());
383 acvtiveFiltRanges.remove(Short.valueOf((short) ruleToRemove.tableId()));
Sean Condonfae8e662016-12-15 10:25:13 +0000384 rulesRemoved.add(ruleToRemove);
385 saRangeList.add(sar);
386
387 } else if (ruleToRemove.selector().getCriterion(Type.VLAN_VID) != null &&
388 ruleToRemove.selector().getCriterion(Type.IN_PORT) != null) {
389 PortNumber portNumber = ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port();
390 VlanId vlanId = ((VlanIdCriterion) ruleToRemove.selector().getCriterion(Type.VLAN_VID)).vlanId();
391 int evcId = ruleToRemove.tableId();
392 int evcKey = (evcId << 2) + (int) portNumber.toLong();
393 String activeCeVlanMap = "";
394 //If this is one of many VLANs belonging to an EVC then we should only remove this VLAN
395 // from the ceVlanMap and not the whole EVC
396 if (!ceVlanMapMap.containsKey(evcKey)) {
397 for (Evc activeEvc:activeEvcs) {
398 if (activeEvc.evcIndex() == evcId) {
399 if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
400 UniSide.CUSTOMER) {
401 activeCeVlanMap = activeEvc.evcPerUni().evcPerUnic().ceVlanMap().string();
402 } else if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
403 UniSide.NETWORK) {
404 activeCeVlanMap = activeEvc.evcPerUni().evcPerUnin().ceVlanMap().string();
405 }
406 }
407 }
408 }
409
410 ceVlanMapMap.put(evcKey, CeVlanMapUtils.removeFromCeVlanMap(activeCeVlanMap, vlanId.id()));
411 if (!flowIdMap.containsKey(evcKey)) {
412 flowIdMap.put(evcKey, new ArrayList<>());
413 }
414 flowIdMap.get(evcKey).add(vlanId.id());
415 rulesRemoved.add(ruleToRemove);
416
417 } else {
418 log.info("Unexpected Flow Rule type removal: " + ruleToRemove);
419 }
420 }
421
422 //If there are IPv4 Flow Rules created commit them now through the
423 //MseaSaFiltering service
Sean Condon06613e92017-06-09 15:14:01 +0100424 if (saRangeList.size() > 0 && acvtiveFiltRanges.size() == 0) {
Sean Condonfae8e662016-12-15 10:25:13 +0000425 try {
Sean Condon06613e92017-06-09 15:14:01 +0100426 SourceIpaddressFiltering saFilter =
427 new DefaultSourceIpaddressFiltering();
428 MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
429 mseaSaFiltering.sourceIpaddressFiltering(saFilter);
430
431 mseaSaFilteringService.deleteMseaSaFilteringRange(
432 mseaSaFiltering, session, DatastoreId.RUNNING);
433 } catch (NetconfException e) {
434 log.warn("Remove FlowRule on MseaSaFilteringService could not delete all SARules - "
435 + "they may already have been deleted: " + e.getMessage());
436 }
437 } else if (saRangeList.size() > 0) {
438 try {
439 mseaSaFilteringService.deleteMseaSaFilteringRange(
440 buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000441 } catch (NetconfException e) {
442 log.warn("Remove FlowRule on MseaSaFilteringService could not delete SARule - "
443 + "it may already have been deleted: " + e.getMessage());
444 }
445 }
446
447 if (ceVlanMapMap.size() > 0) {
448 try {
449 mseaUniEvcServiceSvc.removeEvcUniFlowEntries(ceVlanMapMap, flowIdMap,
Sean Condon06613e92017-06-09 15:14:01 +0100450 session, DatastoreId.RUNNING, portAssignment);
Sean Condonfae8e662016-12-15 10:25:13 +0000451 } catch (NetconfException e) {
452 log.warn("Remove FlowRule on MseaUniEvcService could not delete EVC - "
453 + "it may already have been deleted: " + e.getMessage());
454 }
455 }
456
457 sessionMutex.release();
458 return rulesRemoved;
459 }
460
461 /**
462 * An internal method for extracting one EVC from a list and returning its ceVlanMap.
463 *
464 * @param evcList - the list of known EVCs
465 * @param evcIndex - the index of the EVC we're looking for
466 * @param side - the side of the UNI
467 * @return - the CEVlanMap we're looking for
468 */
469 private String getCeVlanMapForIdxFromEvcList(List<Evc> evcList, long evcIndex, UniSide side) {
470 if (evcList != null && evcList.size() > 0) {
471 for (Evc evc:evcList) {
472 if (evc.evcIndex() == evcIndex && evc.evcPerUni() != null) {
473 if (side == UniSide.CUSTOMER &&
474 evc.evcPerUni().evcPerUnic() != null &&
475 evc.evcPerUni().evcPerUnic().ceVlanMap() != null) {
476 return evc.evcPerUni().evcPerUnic().ceVlanMap().string();
477 } else if (side == UniSide.NETWORK &&
478 evc.evcPerUni().evcPerUnin() != null &&
479 evc.evcPerUni().evcPerUnin().ceVlanMap() != null) {
480 return evc.evcPerUni().evcPerUnin().ceVlanMap().string();
481 }
482 }
483 }
484 }
485
486 return ""; //The EVC required was not in the list
487 }
488
489 /**
490 * An internal method to convert from a FlowRule to SARange.
491 *
492 * @param frList A collection of flow rules
493 * @param saRangeList A list of SARanges
494 * @param fr A flow rule
495 */
496 private void parseFrForSaRange(Collection<FlowRule> frList, List<SourceAddressRange> saRangeList, FlowRule fr) {
497 String ipAddrStr = fr.selector().getCriterion(Type.IPV4_SRC).toString().substring(9);
498 log.debug("Applying IP address to " + ipAddrStr
499 + " (on Port 0) to IP SA Filtering on EA1000 through NETCONF");
500
Sean Condon06613e92017-06-09 15:14:01 +0100501 SourceAddressRange sar =
502 new DefaultSourceAddressRange();
Sean Condonfae8e662016-12-15 10:25:13 +0000503
Sean Condon06613e92017-06-09 15:14:01 +0100504 sar.rangeId((short) fr.tableId());
505 sar.name("Flow:" + fr.id().toString());
506 sar.ipv4AddressPrefix(ipAddrStr);
Sean Condonfae8e662016-12-15 10:25:13 +0000507
508 frList.add(fr);
509 saRangeList.add(sar);
510 }
511
512 private void parseFrForEvcs(Collection<FlowRule> frList, Map<Integer, Evc> evcMap,
513 List<Evc> activeEvcs, UniSideInterfaceAssignmentEnum portAssignment, FlowRule fr) {
514 //There could be many Flow Rules for one EVC depending on the ceVlanMap
515 //Cannot build up the EVC until we know the details - the key is the tableID and port
516 Ea1000Port port = Ea1000Port.fromNum(
517 ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong());
518 Integer evcKey = (fr.tableId() << 2) + port.portNum();
519 VlanId sourceVid = ((VlanIdCriterion) fr.selector().getCriterion(Type.VLAN_VID)).vlanId();
Sean Condon06613e92017-06-09 15:14:01 +0100520 FlowMapping fm = new DefaultFlowMapping();
521 fm.ceVlanId(VlanIdType.of(sourceVid.id()));
522 fm.flowId(BigInteger.valueOf(fr.id().value()));
523
Sean Condonfae8e662016-12-15 10:25:13 +0000524 if (evcMap.containsKey(evcKey)) { //Is there an entry already for this EVC and port?
525 //Replace ceVlanMap
Sean Condon06613e92017-06-09 15:14:01 +0100526 if (port.nOrC(portAssignment) == UniSide.CUSTOMER) {
527 evcMap.get(evcKey).evcPerUni().evcPerUnic().addToFlowMapping(fm);
528 ServiceListType newCeVlanMap = new ServiceListType(
529 CeVlanMapUtils.addtoCeVlanMap(
530 evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap().toString(),
531 sourceVid.toShort()));
532 evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
533 } else {
534 evcMap.get(evcKey).evcPerUni().evcPerUnin().addToFlowMapping(fm);
535 ServiceListType newCeVlanMap = new ServiceListType(
536 CeVlanMapUtils.addtoCeVlanMap(
537 evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap().toString(),
538 sourceVid.toShort()));
539 evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
540 }
Sean Condonfae8e662016-12-15 10:25:13 +0000541 } else if (evcMap.containsKey((evcKey ^ 1))) { //Is there an entry for this EVC but the opposite port?
542 TagManipulation tm = getTagManipulation(fr);
543 if (port.nOrC(portAssignment) == UniSide.NETWORK) {
Sean Condon06613e92017-06-09 15:14:01 +0100544 ServiceListType newCeVlanMap = new ServiceListType(
545 CeVlanMapUtils.addtoCeVlanMap(
546 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap().toString(),
547 sourceVid.toShort()));
548 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
549 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().tagManipulation(tm);
550 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().addToFlowMapping(fm);
551 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000552 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100553 ServiceListType newCeVlanMap = new ServiceListType(
554 CeVlanMapUtils.addtoCeVlanMap(
555 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap().toString(),
556 sourceVid.toShort()));
557 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
558 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().tagManipulation(tm);
559 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().addToFlowMapping(fm);
560 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000561 }
562 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100563 Evc evc = new DefaultEvc();
564 EvcPerUnin epun = new CustomEvcPerUnin();
565 EvcPerUnic epuc = new CustomEvcPerUnic();
Sean Condonfae8e662016-12-15 10:25:13 +0000566 TagManipulation tm = getTagManipulation(fr);
567
568 UniSide side = port.nOrC(portAssignment);
569 String oldCeVlanMap = getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(), side);
570 String newCeVlanMap =
571 CeVlanMapUtils.addtoCeVlanMap(oldCeVlanMap, sourceVid.id());
572 String oppositeCeVlanMap =
573 getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(),
574 port.opposite().nOrC(portAssignment));
575 oppositeCeVlanMap = oppositeCeVlanMap.isEmpty() ? "0" : oppositeCeVlanMap;
576 if (side == UniSide.NETWORK) {
Sean Condon06613e92017-06-09 15:14:01 +0100577 epun.ceVlanMap(new ServiceListType(newCeVlanMap));
578 epun.tagManipulation(tm);
579 epun.addToFlowMapping(fm);
580 epun.ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000581
Sean Condon06613e92017-06-09 15:14:01 +0100582 epuc.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
583 epuc.ingressBwpGroupIndex(new Long(0));
Sean Condonfae8e662016-12-15 10:25:13 +0000584 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100585 epuc.ceVlanMap(new ServiceListType(newCeVlanMap));
586 epuc.tagManipulation(tm);
587 epuc.addToFlowMapping(fm);
588 epuc.ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000589
Sean Condon06613e92017-06-09 15:14:01 +0100590 epun.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
591 epun.ingressBwpGroupIndex(new Long(0));
Sean Condonfae8e662016-12-15 10:25:13 +0000592 }
593
Sean Condon06613e92017-06-09 15:14:01 +0100594 evc.evcIndex(fr.tableId());
595 evc.name(new Identifier45("EVC-" + String.valueOf(fr.tableId())));
596
597 DefaultEvcPerUni epu = new DefaultEvcPerUni();
598 epu.evcPerUnin(epun);
599 epu.evcPerUnic(epuc);
600 evc.evcPerUni(epu);
601
602 evcMap.put(evcKey, evc);
Sean Condonfae8e662016-12-15 10:25:13 +0000603 }
604
605 frList.add(fr);
606 }
607
608
609 private MseaSaFilteringOpParam buildSaFilteringObject(List<SourceAddressRange> saRangeList) {
Sean Condon06613e92017-06-09 15:14:01 +0100610 InterfaceEth0 saIf = new DefaultInterfaceEth0();
Sean Condonfae8e662016-12-15 10:25:13 +0000611 for (SourceAddressRange sa:saRangeList) {
Sean Condon06613e92017-06-09 15:14:01 +0100612 saIf.addToSourceAddressRange(sa);
Sean Condonfae8e662016-12-15 10:25:13 +0000613 }
Sean Condon06613e92017-06-09 15:14:01 +0100614 saIf.filterAdminState(FilterAdminStateEnum.BLACKLIST);
Sean Condonfae8e662016-12-15 10:25:13 +0000615
Sean Condon06613e92017-06-09 15:14:01 +0100616 SourceIpaddressFiltering saFilter =
617 new DefaultSourceIpaddressFiltering();
618 saFilter.interfaceEth0(saIf);
Sean Condonfae8e662016-12-15 10:25:13 +0000619
Sean Condon06613e92017-06-09 15:14:01 +0100620 MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
621 mseaSaFiltering.sourceIpaddressFiltering(saFilter);
Sean Condonfae8e662016-12-15 10:25:13 +0000622
623 return mseaSaFiltering;
624 }
625
626 private Collection<FlowEntry> convertSaFilteringToFlowRules(
627 MseaSaFiltering saFilteringCurrent, ApplicationId appId) {
628 Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
629
630 List<SourceAddressRange> saRangelist =
631 saFilteringCurrent.sourceIpaddressFiltering().interfaceEth0().sourceAddressRange();
632 Criterion matchInPort = Criteria.matchInPort(PortNumber.portNumber(0));
633 TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
634
Sean Condon06613e92017-06-09 15:14:01 +0100635 if (saRangelist != null) {
636 for (SourceAddressRange sa : saRangelist) {
637 Criterion matchIpSrc = Criteria.matchIPSrc(IpPrefix.valueOf(sa.ipv4AddressPrefix()));
Sean Condonfae8e662016-12-15 10:25:13 +0000638
Sean Condon06613e92017-06-09 15:14:01 +0100639 TrafficSelector selector = tsBuilder.add(matchIpSrc).add(matchInPort).build();
Sean Condonfae8e662016-12-15 10:25:13 +0000640
Sean Condon06613e92017-06-09 15:14:01 +0100641 TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
642 TrafficTreatment treatment = trBuilder.drop().build();
Sean Condonfae8e662016-12-15 10:25:13 +0000643
Sean Condon06613e92017-06-09 15:14:01 +0100644 FlowRule.Builder feBuilder = new DefaultFlowRule.Builder();
645 if (sa.name() != null && sa.name().startsWith("Flow:")) {
646 String[] nameParts = sa.name().split(":");
647 Long cookie = Long.valueOf(nameParts[1], 16);
648 feBuilder = feBuilder.withCookie(cookie);
649 } else {
650 feBuilder = feBuilder.fromApp(appId);
651 }
652
653 FlowRule fr = feBuilder
654 .forDevice(handler().data().deviceId())
655 .withSelector(selector)
656 .withTreatment(treatment)
657 .forTable(sa.rangeId())
658 .makePermanent()
659 .withPriority(PRIORITY_DEFAULT)
660 .build();
661
662 flowEntryCollection.add(
663 new DefaultFlowEntry(fr, FlowEntryState.ADDED, 0, 0, 0));
Sean Condonfae8e662016-12-15 10:25:13 +0000664 }
Sean Condonfae8e662016-12-15 10:25:13 +0000665 }
Sean Condonfae8e662016-12-15 10:25:13 +0000666 return flowEntryCollection;
667 }
668
669
670 private Collection<FlowEntry> convertEvcUniToFlowRules(
671 MseaUniEvcService uniEvcCurrent, UniSideInterfaceAssignmentEnum portAssignment) {
672 Collection<FlowEntry> flowEntryCollection = new HashSet<FlowEntry>();
673
674 if (uniEvcCurrent == null || uniEvcCurrent.mefServices() == null ||
675 uniEvcCurrent.mefServices().uni() == null || uniEvcCurrent.mefServices().uni().evc() == null) {
676 log.info("No EVC's found when getting flow rules");
677 return flowEntryCollection;
678 }
679
680 for (Evc evc:uniEvcCurrent.mefServices().uni().evc()) {
681 FlowRule.Builder frBuilder = new DefaultFlowRule.Builder();
682 TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
683
684 TrafficTreatment uniNTreatment = treatmentForUniSde(evc.evcPerUni(), true);
685 //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
686 Short[] vlanIdsUniN =
687 CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), true));
688 for (Short vlanId:vlanIdsUniN) {
689 if (vlanId == 0) {
690 continue;
691 }
692 Criterion uniNportCriterion = criterionPortForUniSide(portAssignment, true);
693 TrafficSelector tsUniN = tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniNportCriterion).build();
694 long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnin().flowMapping(), vlanId);
695
696 FlowRule frUniN = frBuilder
697 .forDevice(handler().data().deviceId())
698 .withSelector(tsUniN)
699 .withTreatment(uniNTreatment)
700 .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
701 .makePermanent()
702 .withPriority(PRIORITY_DEFAULT)
703 .withCookie(flowId)
704 .build();
705 flowEntryCollection.add(new DefaultFlowEntry(frUniN, FlowEntryState.ADDED, 0, 0, 0));
706 }
707
708 TrafficTreatment uniCTreatment = treatmentForUniSde(evc.evcPerUni(), false);
709 //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
710 Short[] vlanIdsUniC =
711 CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), false));
712 if (vlanIdsUniC != null && vlanIdsUniC.length > 0) {
713 for (Short vlanId:vlanIdsUniC) {
714 if (vlanId == 0) {
715 continue;
716 }
717 Criterion uniCportCriterion = criterionPortForUniSide(portAssignment, false);
718 TrafficSelector tsUniC =
719 tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniCportCriterion).build();
720 long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnic().flowMapping(), vlanId);
721
722 FlowRule frUniC = frBuilder
723 .forDevice(handler().data().deviceId())
724 .withSelector(tsUniC)
725 .withTreatment(uniCTreatment)
726 .forTable(new Long(evc.evcIndex()).intValue()) //narrowing to int
727 .makePermanent()
728 .withPriority(PRIORITY_DEFAULT)
729 .withCookie(flowId)
730 .build();
731 flowEntryCollection.add(new DefaultFlowEntry(frUniC, FlowEntryState.ADDED, 0, 0, 0));
732 }
733 }
734 }
735
736 return flowEntryCollection;
737 }
738
739 private long getFlowIdForVlan(List<FlowMapping> fmList, Short vlanId) {
740 if (fmList == null || vlanId == null) {
741 log.warn("Flow Mapping list is null when reading EVCs");
742 return -1L;
743 }
744 for (FlowMapping fm:fmList) {
745 if (fm.ceVlanId().uint16() == vlanId.intValue()) {
746 return fm.flowId().longValue();
747 }
748 }
749 return 0L;
750 }
751
752 private String ceVlanMapForUniSide(
753 EvcPerUni evcPerUni, boolean portN) {
754 if (portN) {
755 return evcPerUni.evcPerUnin().ceVlanMap().string();
756 } else {
757 return evcPerUni.evcPerUnic().ceVlanMap().string();
758 }
759 }
760
761 private Criterion criterionPortForUniSide(
762 UniSideInterfaceAssignmentEnum portAssignment, boolean portN) {
763 boolean cOnOptics = (portAssignment == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS);
764 int portNum = ((cOnOptics && portN) || (!cOnOptics && !portN)) ? 1 : 0;
765 return Criteria.matchInPort(PortNumber.portNumber(portNum));
766 }
767
768 private TrafficTreatment treatmentForUniSde(
769 EvcPerUni evcPerUni, boolean portN) {
770 TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
771
772 TagManipulation tm = null;
773 short meterId = 0;
774 if (portN) {
775 tm = evcPerUni.evcPerUnin().tagManipulation();
776 meterId = (short) evcPerUni.evcPerUnin().ingressBwpGroupIndex();
777 } else {
778 tm = evcPerUni.evcPerUnic().tagManipulation();
779 meterId = (short) evcPerUni.evcPerUnic().ingressBwpGroupIndex();
780 }
781
782 if (meterId > 0L) {
783 trBuilder = trBuilder.meter(MeterId.meterId((long) meterId));
784// trBuilder = trBuilder.meter(MeterId.meterId(meterId)).transition(0);
785 }
786
787 if (tm == null) {
788 return trBuilder.build(); //no tag manipulation found
789 }
790
791 if (tm.getClass().equals(DefaultTagPush.class)) {
792 VlanId pushVlanNum = VlanId.vlanId((short) ((TagPush) tm).tagPush().outerTagVlan().uint16());
793 PushTagTypeEnum pushTagType = ((TagPush) tm).tagPush().pushTagType();
794 //Note - the order of elements below MUST match the order of the Treatment in the stored FlowRule
795 // to be an exactMatch. See DefaultFlowRule.exactMatch()
796 trBuilder = trBuilder
797 .pushVlan(pushTagType.equals(PushTagTypeEnum.PUSHCTAG) ?
798 EtherType.VLAN.ethType() : EtherType.QINQ.ethType())
799 .setVlanId(pushVlanNum).transition(Integer.valueOf(0));
800
801 } else if (tm.getClass().equals(DefaultTagPop.class)) {
802 trBuilder = trBuilder.popVlan();
803
804 } else if (tm.getClass().equals(DefaultTagOverwrite.class)) {
805 TagOverwrite to = (TagOverwrite) tm;
806 VlanId ovrVlanNum = VlanId
807 .vlanId((short) (
808 //There are 2 classes TagOverwrite - the other one is already imported
809 to
810 .tagOverwrite()
811 .outerTagVlan()
812 .uint16()));
813 trBuilder = trBuilder.setVlanId(ovrVlanNum);
814
815 }
816
817 return trBuilder.build();
818 }
819
820 private static TagManipulation getTagManipulation(FlowRule fr) {
821 boolean isPop = false;
822 boolean isPush = false;
823 VlanId vlanId = null;
824 EthType ethType = EtherType.VLAN.ethType(); //Default
825 for (Instruction inst:fr.treatment().allInstructions()) {
826 if (inst.type() == Instruction.Type.L2MODIFICATION) {
827 L2ModificationInstruction l2Mod = (L2ModificationInstruction) inst;
828 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
829 isPop = true;
830 } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
831 isPush = true;
832 ethType = ((ModVlanHeaderInstruction) l2Mod).ethernetType();
833 } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
834 vlanId = ((ModVlanIdInstruction) l2Mod).vlanId();
835 }
836 }
837 }
838
839 if (isPop) {
840 //The should be no vlanId in this case
Sean Condon06613e92017-06-09 15:14:01 +0100841 TagPop pop = new DefaultTagPop();
842 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
843 .evcperuniextensionattributes.tagmanipulation
844 .tagpop.TagPop popInner =
845 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
846 .mseaunievcservice.evcperuniextensionattributes
847 .tagmanipulation.tagpop.DefaultTagPop();
848 pop.tagPop(popInner);
849 return pop;
Sean Condonfae8e662016-12-15 10:25:13 +0000850
851 } else if (isPush && vlanId != null) {
Sean Condon06613e92017-06-09 15:14:01 +0100852 TagPush push = new DefaultTagPush();
853 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
854 .evcperuniextensionattributes.tagmanipulation
855 .tagpush.TagPush pushInner =
856 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
857 .mseaunievcservice.evcperuniextensionattributes
858 .tagmanipulation.tagpush.DefaultTagPush();
859 pushInner.outerTagVlan(new VlanIdType(vlanId.id()));
860 pushInner.pushTagType(ethType.equals(EtherType.VLAN.ethType()) ?
861 PushTagTypeEnum.PUSHCTAG : PushTagTypeEnum.PUSHSTAG);
862 push.tagPush(pushInner);
863 return push;
Sean Condonfae8e662016-12-15 10:25:13 +0000864
865 } else if (vlanId != null) { //This is overwrite, as it has vlanId, but not push or pop
Sean Condon06613e92017-06-09 15:14:01 +0100866 TagOverwrite ovr = new DefaultTagOverwrite();
867 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
868 .evcperuniextensionattributes.tagmanipulation
869 .tagoverwrite.TagOverwrite ovrInner =
870 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
871 .mseaunievcservice.evcperuniextensionattributes
872 .tagmanipulation.tagoverwrite.DefaultTagOverwrite();
873 ovrInner.outerTagVlan(new VlanIdType(vlanId.id()));
874 ovr.tagOverwrite(ovrInner);
875 return ovr;
Sean Condonfae8e662016-12-15 10:25:13 +0000876 }
877
878 return null;
879 }
880
881 private static long getMeterId(TrafficTreatment treatment) {
882 return (treatment.metered() != null && treatment.metered().meterId() != null)
883 ? treatment.metered().meterId().id() : 0L;
884 }
885
886 /**
887 * An enumerated type that characterises the 2 port layout of the EA1000 device.
888 * The device is in an SFP package and has only 2 ports, the HOST port which
889 * plugs in to the chassis (Port 1) and the Optics Port on the rear (Port 0).
890 */
891 public enum Ea1000Port {
892 HOST(1),
893 OPTICS(0);
894
895 private int num = 0;
896 private Ea1000Port(int num) {
897 this.num = num;
898 }
899
900 /**
901 * The numerical assignment of this port.
902 * @return The port number
903 */
904 public int portNum() {
905 return num;
906 }
907
908 /**
909 * Return the enumerated value from a port number.
910 * @param num The port number
911 * @return An enumerated value
912 */
913 public static Ea1000Port fromNum(long num) {
914 for (Ea1000Port a:Ea1000Port.values()) {
915 if (a.num == num) {
916 return a;
917 }
918 }
919 return HOST;
920 }
921
922 /**
923 * Get the port that the UNI-N is present on.
924 * @param side The assignment of UNI-side to port
925 * @return An enumerated value
926 */
927 public static Ea1000Port uniNNum(UniSideInterfaceAssignmentEnum side) {
928 if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
929 return OPTICS;
930 } else {
931 return HOST;
932 }
933 }
934
935 /**
936 * Get the port that the UNI-C is present on.
937 * @param side The assignment of UNI-side to port
938 * @return An enumerated value
939 */
940 public static Ea1000Port uniCNum(UniSideInterfaceAssignmentEnum side) {
941 if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
942 return HOST;
943 } else {
944 return OPTICS;
945 }
946 }
947
948 /**
949 * Get the port opposite the current port.
950 * @return An enumerated value for the opposite side
951 */
952 public Ea1000Port opposite() {
953 if (this.equals(HOST)) {
954 return OPTICS;
955 } else {
956 return HOST;
957 }
958 }
959
960 /**
961 * Evaluate which side of the UNI on the EA1000 device this port refers to.
962 * @param side The assignment of UNI-side to port
963 * @return An enumerated value representing the UniSide
964 */
965 public UniSide nOrC(UniSideInterfaceAssignmentEnum side) {
966 if ((this == HOST && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST) ||
967 (this == OPTICS && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS)) {
968 return UniSide.CUSTOMER;
969 } else {
970 return UniSide.NETWORK;
971 }
972 }
973 }
974}