blob: 1e0dfd92a04eb2105943f3a23a88a63fc71bbb9b [file] [log] [blame]
Sean Condonfae8e662016-12-15 10:25:13 +00001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Sean Condonfae8e662016-12-15 10:25:13 +00003 *
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
Sean Condon3a1efef2018-02-24 13:16:03 +0000127 public static final int RADIX_16 = 16;
Sean Condonfae8e662016-12-15 10:25:13 +0000128 protected final Logger log = getLogger(getClass());
129 public static final String MICROSEMI_DRIVERS = "com.microsemi.drivers";
130 public static final int PRIORITY_DEFAULT = 50000;
131 //To protect the NETCONF session from concurrent access across flow addition and removal
132 static Semaphore sessionMutex = new Semaphore(1);
133
134 /**
135 * Get the flow entries that are present on the EA1000.
136 * Since the EA1000 does not have any 'real' flow entries these are retrieved from 2 configuration
137 * areas on the EA1000 NETCONF model - from SA filtering YANG model and from EVC UNI YANG model.<br>
138 * The flow entries must match exactly the FlowRule entries in the ONOS store. If they are not an
139 * exact match the device will be requested to remove those flows and the FlowRule will stay in a
140 * PENDING_ADD state.
141 * @return A collection of Flow Entries
142 */
143 @Override
144 public Collection<FlowEntry> getFlowEntries() {
Sean Condon3a1efef2018-02-24 13:16:03 +0000145 Collection<FlowEntry> flowEntryCollection = new HashSet<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000146
147 UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
148 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
Sean Condon06613e92017-06-09 15:14:01 +0100149 NetconfDevice ncDevice = controller.getDevicesMap().get(handler().data().deviceId());
150 if (ncDevice == null) {
151 log.error("Internal ONOS Error. Device has been marked as reachable, " +
152 "but deviceID {} is not in Devices Map. Continuing with empty description",
153 handler().data().deviceId());
154 return flowEntryCollection;
155 }
156 NetconfSession session = ncDevice.getSession();
Sean Condonfae8e662016-12-15 10:25:13 +0000157 CoreService coreService = checkNotNull(handler().get(CoreService.class));
158 ApplicationId appId = coreService.getAppId(MICROSEMI_DRIVERS);
159 MseaSaFilteringNetconfService mseaSaFilteringService =
Sean Condon3a1efef2018-02-24 13:16:03 +0000160 checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
Sean Condonfae8e662016-12-15 10:25:13 +0000161 MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
Sean Condon3a1efef2018-02-24 13:16:03 +0000162 checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
Sean Condonfae8e662016-12-15 10:25:13 +0000163 log.debug("getFlowEntries() called on EA1000FlowRuleProgrammable");
164
165 //First get the MseaSaFiltering rules
Sean Condon06613e92017-06-09 15:14:01 +0100166 SourceIpaddressFiltering sip =
167 new DefaultSourceIpaddressFiltering();
Sean Condonfae8e662016-12-15 10:25:13 +0000168
Sean Condon06613e92017-06-09 15:14:01 +0100169 MseaSaFilteringOpParam op =
170 new MseaSaFilteringOpParam();
171 op.sourceIpaddressFiltering(sip);
172
Sean Condonfae8e662016-12-15 10:25:13 +0000173 try {
174 MseaSaFiltering saFilteringCurrent =
Sean Condon06613e92017-06-09 15:14:01 +0100175 mseaSaFilteringService.getMseaSaFiltering(op, session);
176 if (saFilteringCurrent != null &&
177 saFilteringCurrent.sourceIpaddressFiltering() != null) {
Sean Condonfae8e662016-12-15 10:25:13 +0000178 flowEntryCollection.addAll(
179 convertSaFilteringToFlowRules(saFilteringCurrent, appId));
180 }
181 } catch (NetconfException e) {
Sean Condon06613e92017-06-09 15:14:01 +0100182 if (e.getCause() instanceof TimeoutException) {
183 log.warn("Timeout exception getting SA Filt Flow Entries from {}",
184 handler().data().deviceId());
185 return flowEntryCollection;
186 } else {
187 log.error("Unexpected error on SA Filt getFlowEntries on {}",
188 handler().data().deviceId(), e);
Sean Condon7347de92017-07-21 12:17:25 +0100189 return flowEntryCollection;
Sean Condon06613e92017-06-09 15:14:01 +0100190 }
Sean Condonfae8e662016-12-15 10:25:13 +0000191 }
192
193
194 //Then get the EVCs - there will be a flow entry per EVC
Sean Condon06613e92017-06-09 15:14:01 +0100195 MefServices mefServices = new DefaultMefServices();
196 mefServices.uni(new DefaultUni());
Sean Condonfae8e662016-12-15 10:25:13 +0000197
Sean Condon06613e92017-06-09 15:14:01 +0100198 MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
199 mseaUniEvcServiceFilter.mefServices(mefServices);
Sean Condonfae8e662016-12-15 10:25:13 +0000200 try {
201 MseaUniEvcService uniEvcCurrent =
202 mseaUniEvcServiceSvc.getConfigMseaUniEvcService(mseaUniEvcServiceFilter,
Sean Condon06613e92017-06-09 15:14:01 +0100203 session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000204
205 flowEntryCollection.addAll(
206 convertEvcUniToFlowRules(uniEvcCurrent, portAssignment));
207
208 } catch (NetconfException e) {
Sean Condon06613e92017-06-09 15:14:01 +0100209 if (e.getCause() instanceof TimeoutException) {
210 log.warn("Timeout exception getting EVC Flow Entries from {}",
211 handler().data().deviceId());
212 return flowEntryCollection;
213 } else {
214 log.error("Unexpected error on EVC getFlowEntries on {}",
215 handler().data().deviceId(), e);
216 }
Sean Condonfae8e662016-12-15 10:25:13 +0000217 }
218
Sean Condonfae8e662016-12-15 10:25:13 +0000219 return flowEntryCollection;
220 }
221
222 /**
223 * Apply the flow entries to the EA1000.
224 * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
225 * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.<br>
226 * Only a subset of the possible OpenFlow rules are supported. Any rule that's not handled
227 * will not be in the returned set.
228 *
229 * @param rules A collection of Flow Rules to be applied to the EA1000
230 * @return A collection of the Flow Rules that have been added.
231 */
232 @Override
233 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
Sean Condon3a1efef2018-02-24 13:16:03 +0000234 Collection<FlowRule> frAdded = new HashSet<>();
235 if (rules == null || rules.isEmpty()) {
Sean Condonfae8e662016-12-15 10:25:13 +0000236 return rules;
237 }
238 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
239 NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
240 MseaSaFilteringNetconfService mseaSaFilteringService =
Sean Condon3a1efef2018-02-24 13:16:03 +0000241 checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
Sean Condonfae8e662016-12-15 10:25:13 +0000242 MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
Sean Condon3a1efef2018-02-24 13:16:03 +0000243 checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
Sean Condonfae8e662016-12-15 10:25:13 +0000244 log.debug("applyFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rules.size());
Sean Condon3a1efef2018-02-24 13:16:03 +0000245 // TODO: Change this so it's dynamically driven
Sean Condonfae8e662016-12-15 10:25:13 +0000246 UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
247
Sean Condon3a1efef2018-02-24 13:16:03 +0000248 List<SourceAddressRange> saRangeList = new ArrayList<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000249 Map<Integer, Evc> evcMap = new HashMap<>();
250
251 //Retrieve the list of actual EVCs and the CeVlanMaps from device
252 List<Evc> activeEvcs = new ArrayList<>();
253 try {
254 sessionMutex.acquire();
255 MseaUniEvcService evcResponse =
Sean Condon06613e92017-06-09 15:14:01 +0100256 mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000257 //There could be zero or more EVCs
258 if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
259 activeEvcs.addAll(evcResponse.mefServices().uni().evc());
260 }
261 } catch (NetconfException | InterruptedException e1) {
262 log.warn("Unexpected error on applyFlowRules", e1);
263 }
264
265 for (FlowRule fr : rules) {
266
267 // IP SA Filtering can only apply to Port 0 optics
268 if (fr.selector().getCriterion(Type.IPV4_SRC) != null &&
269 fr.selector().getCriterion(Type.IN_PORT) != null &&
270 ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
271 parseFrForSaRange(frAdded, saRangeList, fr);
272
273 // EVCs will be defined by Flow Rules relating to VIDs
274 } else if (fr.selector().getCriterion(Type.VLAN_VID) != null &&
275 fr.selector().getCriterion(Type.IN_PORT) != null) {
276 //There could be many Flow Rules for one EVC depending on the ceVlanMap
277 //Cannot build up the EVC until we know the details - the key is the tableID and port
278 parseFrForEvcs(frAdded, evcMap, activeEvcs, portAssignment, fr);
279 } else {
280 log.info("Unexpected Flow Rule type applied: " + fr);
281 }
282 }
283
284 //If there are IPv4 Flow Rules created commit them now through the
285 //MseaSaFiltering service
Sean Condon3a1efef2018-02-24 13:16:03 +0000286 if (!saRangeList.isEmpty()) {
Sean Condonfae8e662016-12-15 10:25:13 +0000287 try {
288 mseaSaFilteringService.setMseaSaFiltering(
Sean Condon06613e92017-06-09 15:14:01 +0100289 buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000290 } catch (NetconfException e) {
Sean Condon3a1efef2018-02-24 13:16:03 +0000291 log.error("Error applying Flow Rules to SA Filtering - " +
292 "will try again: " + e.getMessage(), e);
Sean Condonfae8e662016-12-15 10:25:13 +0000293 sessionMutex.release();
294 return frAdded;
295 }
296 }
297 //If there are EVC flow rules then populate the MseaUniEvc part of EA1000
298 if (evcMap.size() > 0) {
299 List<Evc> evcList = evcMap.entrySet().stream()
300 .map(x -> x.getValue())
301 .collect(Collectors.toList());
Sean Condon06613e92017-06-09 15:14:01 +0100302 Uni uni = new DefaultUni();
Sean Condonfae8e662016-12-15 10:25:13 +0000303 URI deviceName = handler().data().deviceId().uri();
Sean Condon06613e92017-06-09 15:14:01 +0100304 uni.name(new Identifier45("Uni-on-"
305 + deviceName.getSchemeSpecificPart()));
306 uni.evc(evcList);
Sean Condonfae8e662016-12-15 10:25:13 +0000307
Sean Condon3a1efef2018-02-24 13:16:03 +0000308 List<BwpGroup> bwpGroupList = new ArrayList<>();
Sean Condon06613e92017-06-09 15:14:01 +0100309 BwpGroup bwpGrp = new DefaultBwpGroup();
310 bwpGrp.groupIndex((short) 0);
311 bwpGroupList.add(bwpGrp);
312 Profiles profiles = new DefaultProfiles();
313 profiles.bwpGroup(bwpGroupList);
Sean Condonfae8e662016-12-15 10:25:13 +0000314
Sean Condon06613e92017-06-09 15:14:01 +0100315 MefServices mefServices = new DefaultMefServices();
316 mefServices.uni(uni);
317 mefServices.profiles(profiles);
Sean Condonfae8e662016-12-15 10:25:13 +0000318
Sean Condon06613e92017-06-09 15:14:01 +0100319 MseaUniEvcServiceOpParam mseaUniEvcServiceFilter = new MseaUniEvcServiceOpParam();
320 mseaUniEvcServiceFilter.mefServices(mefServices);
Sean Condonfae8e662016-12-15 10:25:13 +0000321 try {
Sean Condon06613e92017-06-09 15:14:01 +0100322 mseaUniEvcServiceSvc.setMseaUniEvcService(mseaUniEvcServiceFilter, session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000323 } catch (NetconfException e) {
Sean Condon3a1efef2018-02-24 13:16:03 +0000324 log.error("Error applying Flow Rules to EVC - will try again: " + e.getMessage(), e);
Sean Condonfae8e662016-12-15 10:25:13 +0000325 sessionMutex.release();
326 return frAdded;
327 }
328 }
329 sessionMutex.release();
330 return frAdded;
331 }
332
333 /**
334 * Remove flow rules from the EA1000.
335 * Since the EA1000 does not have any 'real' flow entries these are converted 2 configuration
336 * areas on the EA1000 NETCONF model - to SA filtering YANG model and to EVC UNI YANG model.
337 *
338 * @param rulesToRemove A collection of Flow Rules to be removed to the EA1000
339 * @return A collection of the Flow Rules that have been removed.
340 */
341 @Override
342 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rulesToRemove) {
343 NetconfController controller = checkNotNull(handler().get(NetconfController.class));
344 NetconfSession session = controller.getDevicesMap().get(handler().data().deviceId()).getSession();
345 MseaSaFilteringNetconfService mseaSaFilteringService =
Sean Condon3a1efef2018-02-24 13:16:03 +0000346 checkNotNull(handler().get(MseaSaFilteringNetconfService.class));
Sean Condonfae8e662016-12-15 10:25:13 +0000347 MseaUniEvcServiceNetconfService mseaUniEvcServiceSvc =
Sean Condon3a1efef2018-02-24 13:16:03 +0000348 checkNotNull(handler().get(MseaUniEvcServiceNetconfService.class));
Sean Condonfae8e662016-12-15 10:25:13 +0000349 UniSideInterfaceAssignmentEnum portAssignment = UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST;
350 log.debug("removeFlowRules() called on EA1000FlowRuleProgrammable with {} rules.", rulesToRemove.size());
351
Sean Condon3a1efef2018-02-24 13:16:03 +0000352 if (rulesToRemove.isEmpty()) {
Sean Condonfae8e662016-12-15 10:25:13 +0000353 return rulesToRemove;
354 }
355
356 //Retrieve the list of actual EVCs and the CeVlanMaps from device
357 List<Evc> activeEvcs = new ArrayList<>();
Sean Condon06613e92017-06-09 15:14:01 +0100358 List<Short> acvtiveFiltRanges = new ArrayList<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000359 try {
360 sessionMutex.acquire();
361 MseaUniEvcService evcResponse =
Sean Condon06613e92017-06-09 15:14:01 +0100362 mseaUniEvcServiceSvc.getmseaUniEvcCeVlanMaps(session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000363 //There could be zero or more EVCs
364 if (evcResponse != null && evcResponse.mefServices() != null && evcResponse.mefServices().uni() != null) {
365 activeEvcs.addAll(evcResponse.mefServices().uni().evc());
366 }
Sean Condon06613e92017-06-09 15:14:01 +0100367 mseaSaFilteringService.getConfigMseaSaFilterIds(session).forEach(
368 r -> acvtiveFiltRanges.add(r.rangeId()));
369
Sean Condonfae8e662016-12-15 10:25:13 +0000370 } catch (NetconfException | InterruptedException e1) {
371 log.warn("Error on removeFlowRules.", e1);
372 }
373
Sean Condon3a1efef2018-02-24 13:16:03 +0000374 List<SourceAddressRange> saRangeList = new ArrayList<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000375 Map<Integer, String> ceVlanMapMap = new HashMap<>();
376 Map<Integer, List<Short>> flowIdMap = new HashMap<>();
377
Sean Condon3a1efef2018-02-24 13:16:03 +0000378 Collection<FlowRule> rulesRemoved = new HashSet<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000379 for (FlowRule ruleToRemove : rulesToRemove) {
380 // IP SA Filtering can only apply to Port 0 optics
381 if (ruleToRemove.selector().getCriterion(Type.IPV4_SRC) != null &&
382 ruleToRemove.selector().getCriterion(Type.IN_PORT) != null &&
383 ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port().toLong() == 0) {
Sean Condon06613e92017-06-09 15:14:01 +0100384 SourceAddressRange sar = new DefaultSourceAddressRange();
385 sar.rangeId((short) ruleToRemove.tableId());
386 acvtiveFiltRanges.remove(Short.valueOf((short) ruleToRemove.tableId()));
Sean Condonfae8e662016-12-15 10:25:13 +0000387 rulesRemoved.add(ruleToRemove);
388 saRangeList.add(sar);
389
390 } else if (ruleToRemove.selector().getCriterion(Type.VLAN_VID) != null &&
391 ruleToRemove.selector().getCriterion(Type.IN_PORT) != null) {
392 PortNumber portNumber = ((PortCriterion) ruleToRemove.selector().getCriterion(Type.IN_PORT)).port();
393 VlanId vlanId = ((VlanIdCriterion) ruleToRemove.selector().getCriterion(Type.VLAN_VID)).vlanId();
394 int evcId = ruleToRemove.tableId();
395 int evcKey = (evcId << 2) + (int) portNumber.toLong();
396 String activeCeVlanMap = "";
397 //If this is one of many VLANs belonging to an EVC then we should only remove this VLAN
398 // from the ceVlanMap and not the whole EVC
399 if (!ceVlanMapMap.containsKey(evcKey)) {
400 for (Evc activeEvc:activeEvcs) {
401 if (activeEvc.evcIndex() == evcId) {
402 if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
403 UniSide.CUSTOMER) {
404 activeCeVlanMap = activeEvc.evcPerUni().evcPerUnic().ceVlanMap().string();
405 } else if (Ea1000Port.fromNum(portNumber.toLong()).nOrC(portAssignment) ==
406 UniSide.NETWORK) {
407 activeCeVlanMap = activeEvc.evcPerUni().evcPerUnin().ceVlanMap().string();
408 }
409 }
410 }
411 }
412
413 ceVlanMapMap.put(evcKey, CeVlanMapUtils.removeFromCeVlanMap(activeCeVlanMap, vlanId.id()));
414 if (!flowIdMap.containsKey(evcKey)) {
415 flowIdMap.put(evcKey, new ArrayList<>());
416 }
417 flowIdMap.get(evcKey).add(vlanId.id());
418 rulesRemoved.add(ruleToRemove);
419
420 } else {
Sean Condon3a1efef2018-02-24 13:16:03 +0000421 log.warn("Unexpected Flow Rule type removal: " + ruleToRemove);
Sean Condonfae8e662016-12-15 10:25:13 +0000422 }
423 }
424
425 //If there are IPv4 Flow Rules created commit them now through the
426 //MseaSaFiltering service
Sean Condon3a1efef2018-02-24 13:16:03 +0000427 if (!saRangeList.isEmpty() && acvtiveFiltRanges.isEmpty()) {
Sean Condonfae8e662016-12-15 10:25:13 +0000428 try {
Sean Condon06613e92017-06-09 15:14:01 +0100429 SourceIpaddressFiltering saFilter =
430 new DefaultSourceIpaddressFiltering();
431 MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
432 mseaSaFiltering.sourceIpaddressFiltering(saFilter);
433
434 mseaSaFilteringService.deleteMseaSaFilteringRange(
435 mseaSaFiltering, session, DatastoreId.RUNNING);
436 } catch (NetconfException e) {
Sean Condon3a1efef2018-02-24 13:16:03 +0000437 log.debug("Remove FlowRule on MseaSaFilteringService could not delete all SARules - "
438 + "they may already have been deleted: " + e.getMessage(), e);
Sean Condon06613e92017-06-09 15:14:01 +0100439 }
Sean Condon3a1efef2018-02-24 13:16:03 +0000440 } else if (!saRangeList.isEmpty()) {
Sean Condon06613e92017-06-09 15:14:01 +0100441 try {
442 mseaSaFilteringService.deleteMseaSaFilteringRange(
443 buildSaFilteringObject(saRangeList), session, DatastoreId.RUNNING);
Sean Condonfae8e662016-12-15 10:25:13 +0000444 } catch (NetconfException e) {
445 log.warn("Remove FlowRule on MseaSaFilteringService could not delete SARule - "
Sean Condon3a1efef2018-02-24 13:16:03 +0000446 + "it may already have been deleted: " + e.getMessage(), e);
Sean Condonfae8e662016-12-15 10:25:13 +0000447 }
448 }
449
Sean Condon3a1efef2018-02-24 13:16:03 +0000450 if (!ceVlanMapMap.isEmpty()) {
Sean Condonfae8e662016-12-15 10:25:13 +0000451 try {
452 mseaUniEvcServiceSvc.removeEvcUniFlowEntries(ceVlanMapMap, flowIdMap,
Sean Condon06613e92017-06-09 15:14:01 +0100453 session, DatastoreId.RUNNING, portAssignment);
Sean Condonfae8e662016-12-15 10:25:13 +0000454 } catch (NetconfException e) {
Sean Condon3a1efef2018-02-24 13:16:03 +0000455 log.debug("Remove FlowRule on MseaUniEvcService could not delete EVC - "
456 + "it may already have been deleted: " + e.getMessage(), e);
Sean Condonfae8e662016-12-15 10:25:13 +0000457 }
458 }
459
460 sessionMutex.release();
461 return rulesRemoved;
462 }
463
464 /**
465 * An internal method for extracting one EVC from a list and returning its ceVlanMap.
466 *
467 * @param evcList - the list of known EVCs
468 * @param evcIndex - the index of the EVC we're looking for
469 * @param side - the side of the UNI
470 * @return - the CEVlanMap we're looking for
471 */
472 private String getCeVlanMapForIdxFromEvcList(List<Evc> evcList, long evcIndex, UniSide side) {
Sean Condon3a1efef2018-02-24 13:16:03 +0000473 if (evcList != null && !evcList.isEmpty()) {
Sean Condonfae8e662016-12-15 10:25:13 +0000474 for (Evc evc:evcList) {
475 if (evc.evcIndex() == evcIndex && evc.evcPerUni() != null) {
476 if (side == UniSide.CUSTOMER &&
477 evc.evcPerUni().evcPerUnic() != null &&
478 evc.evcPerUni().evcPerUnic().ceVlanMap() != null) {
479 return evc.evcPerUni().evcPerUnic().ceVlanMap().string();
480 } else if (side == UniSide.NETWORK &&
481 evc.evcPerUni().evcPerUnin() != null &&
482 evc.evcPerUni().evcPerUnin().ceVlanMap() != null) {
483 return evc.evcPerUni().evcPerUnin().ceVlanMap().string();
484 }
485 }
486 }
487 }
488
489 return ""; //The EVC required was not in the list
490 }
491
492 /**
493 * An internal method to convert from a FlowRule to SARange.
494 *
495 * @param frList A collection of flow rules
496 * @param saRangeList A list of SARanges
497 * @param fr A flow rule
498 */
499 private void parseFrForSaRange(Collection<FlowRule> frList, List<SourceAddressRange> saRangeList, FlowRule fr) {
500 String ipAddrStr = fr.selector().getCriterion(Type.IPV4_SRC).toString().substring(9);
501 log.debug("Applying IP address to " + ipAddrStr
502 + " (on Port 0) to IP SA Filtering on EA1000 through NETCONF");
503
Sean Condon06613e92017-06-09 15:14:01 +0100504 SourceAddressRange sar =
505 new DefaultSourceAddressRange();
Sean Condonfae8e662016-12-15 10:25:13 +0000506
Sean Condon06613e92017-06-09 15:14:01 +0100507 sar.rangeId((short) fr.tableId());
508 sar.name("Flow:" + fr.id().toString());
509 sar.ipv4AddressPrefix(ipAddrStr);
Sean Condonfae8e662016-12-15 10:25:13 +0000510
511 frList.add(fr);
512 saRangeList.add(sar);
513 }
514
515 private void parseFrForEvcs(Collection<FlowRule> frList, Map<Integer, Evc> evcMap,
516 List<Evc> activeEvcs, UniSideInterfaceAssignmentEnum portAssignment, FlowRule fr) {
517 //There could be many Flow Rules for one EVC depending on the ceVlanMap
518 //Cannot build up the EVC until we know the details - the key is the tableID and port
519 Ea1000Port port = Ea1000Port.fromNum(
520 ((PortCriterion) fr.selector().getCriterion(Type.IN_PORT)).port().toLong());
521 Integer evcKey = (fr.tableId() << 2) + port.portNum();
522 VlanId sourceVid = ((VlanIdCriterion) fr.selector().getCriterion(Type.VLAN_VID)).vlanId();
Sean Condon06613e92017-06-09 15:14:01 +0100523 FlowMapping fm = new DefaultFlowMapping();
524 fm.ceVlanId(VlanIdType.of(sourceVid.id()));
525 fm.flowId(BigInteger.valueOf(fr.id().value()));
526
Sean Condonfae8e662016-12-15 10:25:13 +0000527 if (evcMap.containsKey(evcKey)) { //Is there an entry already for this EVC and port?
528 //Replace ceVlanMap
Sean Condon06613e92017-06-09 15:14:01 +0100529 if (port.nOrC(portAssignment) == UniSide.CUSTOMER) {
530 evcMap.get(evcKey).evcPerUni().evcPerUnic().addToFlowMapping(fm);
531 ServiceListType newCeVlanMap = new ServiceListType(
532 CeVlanMapUtils.addtoCeVlanMap(
533 evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap().toString(),
534 sourceVid.toShort()));
535 evcMap.get(evcKey).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
536 } else {
537 evcMap.get(evcKey).evcPerUni().evcPerUnin().addToFlowMapping(fm);
538 ServiceListType newCeVlanMap = new ServiceListType(
539 CeVlanMapUtils.addtoCeVlanMap(
540 evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap().toString(),
541 sourceVid.toShort()));
542 evcMap.get(evcKey).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
543 }
Sean Condonfae8e662016-12-15 10:25:13 +0000544 } else if (evcMap.containsKey((evcKey ^ 1))) { //Is there an entry for this EVC but the opposite port?
545 TagManipulation tm = getTagManipulation(fr);
546 if (port.nOrC(portAssignment) == UniSide.NETWORK) {
Sean Condon06613e92017-06-09 15:14:01 +0100547 ServiceListType newCeVlanMap = new ServiceListType(
548 CeVlanMapUtils.addtoCeVlanMap(
549 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap().toString(),
550 sourceVid.toShort()));
551 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ceVlanMap(newCeVlanMap);
552 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().tagManipulation(tm);
553 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().addToFlowMapping(fm);
554 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnin().ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000555 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100556 ServiceListType newCeVlanMap = new ServiceListType(
557 CeVlanMapUtils.addtoCeVlanMap(
558 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap().toString(),
559 sourceVid.toShort()));
560 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ceVlanMap(newCeVlanMap);
561 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().tagManipulation(tm);
562 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().addToFlowMapping(fm);
563 evcMap.get(evcKey ^ 1).evcPerUni().evcPerUnic().ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000564 }
565 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100566 Evc evc = new DefaultEvc();
567 EvcPerUnin epun = new CustomEvcPerUnin();
568 EvcPerUnic epuc = new CustomEvcPerUnic();
Sean Condonfae8e662016-12-15 10:25:13 +0000569 TagManipulation tm = getTagManipulation(fr);
570
571 UniSide side = port.nOrC(portAssignment);
572 String oldCeVlanMap = getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(), side);
573 String newCeVlanMap =
574 CeVlanMapUtils.addtoCeVlanMap(oldCeVlanMap, sourceVid.id());
575 String oppositeCeVlanMap =
576 getCeVlanMapForIdxFromEvcList(activeEvcs, fr.tableId(),
577 port.opposite().nOrC(portAssignment));
578 oppositeCeVlanMap = oppositeCeVlanMap.isEmpty() ? "0" : oppositeCeVlanMap;
579 if (side == UniSide.NETWORK) {
Sean Condon06613e92017-06-09 15:14:01 +0100580 epun.ceVlanMap(new ServiceListType(newCeVlanMap));
581 epun.tagManipulation(tm);
582 epun.addToFlowMapping(fm);
583 epun.ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000584
Sean Condon06613e92017-06-09 15:14:01 +0100585 epuc.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
Sean Condon3a1efef2018-02-24 13:16:03 +0000586 epuc.ingressBwpGroupIndex(0);
Sean Condonfae8e662016-12-15 10:25:13 +0000587 } else {
Sean Condon06613e92017-06-09 15:14:01 +0100588 epuc.ceVlanMap(new ServiceListType(newCeVlanMap));
589 epuc.tagManipulation(tm);
590 epuc.addToFlowMapping(fm);
591 epuc.ingressBwpGroupIndex(getMeterId(fr.treatment()));
Sean Condonfae8e662016-12-15 10:25:13 +0000592
Sean Condon06613e92017-06-09 15:14:01 +0100593 epun.ceVlanMap(new ServiceListType(oppositeCeVlanMap));
Sean Condon3a1efef2018-02-24 13:16:03 +0000594 epun.ingressBwpGroupIndex(0);
Sean Condonfae8e662016-12-15 10:25:13 +0000595 }
596
Sean Condon06613e92017-06-09 15:14:01 +0100597 evc.evcIndex(fr.tableId());
Sean Condon3a1efef2018-02-24 13:16:03 +0000598 evc.name(new Identifier45("EVC-" + fr.tableId()));
Sean Condon06613e92017-06-09 15:14:01 +0100599
600 DefaultEvcPerUni epu = new DefaultEvcPerUni();
601 epu.evcPerUnin(epun);
602 epu.evcPerUnic(epuc);
603 evc.evcPerUni(epu);
604
605 evcMap.put(evcKey, evc);
Sean Condonfae8e662016-12-15 10:25:13 +0000606 }
607
608 frList.add(fr);
609 }
610
611
612 private MseaSaFilteringOpParam buildSaFilteringObject(List<SourceAddressRange> saRangeList) {
Sean Condon06613e92017-06-09 15:14:01 +0100613 InterfaceEth0 saIf = new DefaultInterfaceEth0();
Sean Condonfae8e662016-12-15 10:25:13 +0000614 for (SourceAddressRange sa:saRangeList) {
Sean Condon06613e92017-06-09 15:14:01 +0100615 saIf.addToSourceAddressRange(sa);
Sean Condonfae8e662016-12-15 10:25:13 +0000616 }
Sean Condon06613e92017-06-09 15:14:01 +0100617 saIf.filterAdminState(FilterAdminStateEnum.BLACKLIST);
Sean Condonfae8e662016-12-15 10:25:13 +0000618
Sean Condon06613e92017-06-09 15:14:01 +0100619 SourceIpaddressFiltering saFilter =
620 new DefaultSourceIpaddressFiltering();
621 saFilter.interfaceEth0(saIf);
Sean Condonfae8e662016-12-15 10:25:13 +0000622
Sean Condon06613e92017-06-09 15:14:01 +0100623 MseaSaFilteringOpParam mseaSaFiltering = new MseaSaFilteringOpParam();
624 mseaSaFiltering.sourceIpaddressFiltering(saFilter);
Sean Condonfae8e662016-12-15 10:25:13 +0000625
626 return mseaSaFiltering;
627 }
628
629 private Collection<FlowEntry> convertSaFilteringToFlowRules(
630 MseaSaFiltering saFilteringCurrent, ApplicationId appId) {
Sean Condon3a1efef2018-02-24 13:16:03 +0000631 Collection<FlowEntry> flowEntryCollection = new HashSet<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000632
633 List<SourceAddressRange> saRangelist =
634 saFilteringCurrent.sourceIpaddressFiltering().interfaceEth0().sourceAddressRange();
635 Criterion matchInPort = Criteria.matchInPort(PortNumber.portNumber(0));
636 TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
637
Sean Condon06613e92017-06-09 15:14:01 +0100638 if (saRangelist != null) {
639 for (SourceAddressRange sa : saRangelist) {
640 Criterion matchIpSrc = Criteria.matchIPSrc(IpPrefix.valueOf(sa.ipv4AddressPrefix()));
Sean Condonfae8e662016-12-15 10:25:13 +0000641
Sean Condon06613e92017-06-09 15:14:01 +0100642 TrafficSelector selector = tsBuilder.add(matchIpSrc).add(matchInPort).build();
Sean Condonfae8e662016-12-15 10:25:13 +0000643
Sean Condon06613e92017-06-09 15:14:01 +0100644 TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
645 TrafficTreatment treatment = trBuilder.drop().build();
Sean Condonfae8e662016-12-15 10:25:13 +0000646
Sean Condon06613e92017-06-09 15:14:01 +0100647 FlowRule.Builder feBuilder = new DefaultFlowRule.Builder();
648 if (sa.name() != null && sa.name().startsWith("Flow:")) {
649 String[] nameParts = sa.name().split(":");
Sean Condon3a1efef2018-02-24 13:16:03 +0000650 Long cookie = Long.valueOf(nameParts[1], RADIX_16);
Sean Condon06613e92017-06-09 15:14:01 +0100651 feBuilder = feBuilder.withCookie(cookie);
652 } else {
653 feBuilder = feBuilder.fromApp(appId);
654 }
655
656 FlowRule fr = feBuilder
657 .forDevice(handler().data().deviceId())
658 .withSelector(selector)
659 .withTreatment(treatment)
660 .forTable(sa.rangeId())
661 .makePermanent()
662 .withPriority(PRIORITY_DEFAULT)
663 .build();
664
665 flowEntryCollection.add(
666 new DefaultFlowEntry(fr, FlowEntryState.ADDED, 0, 0, 0));
Sean Condonfae8e662016-12-15 10:25:13 +0000667 }
Sean Condonfae8e662016-12-15 10:25:13 +0000668 }
Sean Condonfae8e662016-12-15 10:25:13 +0000669 return flowEntryCollection;
670 }
671
672
673 private Collection<FlowEntry> convertEvcUniToFlowRules(
674 MseaUniEvcService uniEvcCurrent, UniSideInterfaceAssignmentEnum portAssignment) {
Sean Condon3a1efef2018-02-24 13:16:03 +0000675 Collection<FlowEntry> flowEntryCollection = new HashSet<>();
Sean Condonfae8e662016-12-15 10:25:13 +0000676
677 if (uniEvcCurrent == null || uniEvcCurrent.mefServices() == null ||
678 uniEvcCurrent.mefServices().uni() == null || uniEvcCurrent.mefServices().uni().evc() == null) {
679 log.info("No EVC's found when getting flow rules");
680 return flowEntryCollection;
681 }
682
683 for (Evc evc:uniEvcCurrent.mefServices().uni().evc()) {
684 FlowRule.Builder frBuilder = new DefaultFlowRule.Builder();
685 TrafficSelector.Builder tsBuilder = DefaultTrafficSelector.builder();
686
687 TrafficTreatment uniNTreatment = treatmentForUniSde(evc.evcPerUni(), true);
688 //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
689 Short[] vlanIdsUniN =
690 CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), true));
691 for (Short vlanId:vlanIdsUniN) {
692 if (vlanId == 0) {
693 continue;
694 }
695 Criterion uniNportCriterion = criterionPortForUniSide(portAssignment, true);
696 TrafficSelector tsUniN = tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniNportCriterion).build();
697 long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnin().flowMapping(), vlanId);
698
699 FlowRule frUniN = frBuilder
700 .forDevice(handler().data().deviceId())
701 .withSelector(tsUniN)
702 .withTreatment(uniNTreatment)
Sean Condon3a1efef2018-02-24 13:16:03 +0000703 .forTable(Math.toIntExact(evc.evcIndex())) //narrowing to int
Sean Condonfae8e662016-12-15 10:25:13 +0000704 .makePermanent()
705 .withPriority(PRIORITY_DEFAULT)
706 .withCookie(flowId)
707 .build();
708 flowEntryCollection.add(new DefaultFlowEntry(frUniN, FlowEntryState.ADDED, 0, 0, 0));
709 }
710
711 TrafficTreatment uniCTreatment = treatmentForUniSde(evc.evcPerUni(), false);
712 //Depending on the ceVlanMap there may be multiple VLans and hence multiple flow entries
713 Short[] vlanIdsUniC =
714 CeVlanMapUtils.getVlanSet(ceVlanMapForUniSide(evc.evcPerUni(), false));
715 if (vlanIdsUniC != null && vlanIdsUniC.length > 0) {
716 for (Short vlanId:vlanIdsUniC) {
717 if (vlanId == 0) {
718 continue;
719 }
720 Criterion uniCportCriterion = criterionPortForUniSide(portAssignment, false);
721 TrafficSelector tsUniC =
722 tsBuilder.matchVlanId(VlanId.vlanId(vlanId)).add(uniCportCriterion).build();
723 long flowId = getFlowIdForVlan(evc.evcPerUni().evcPerUnic().flowMapping(), vlanId);
724
725 FlowRule frUniC = frBuilder
726 .forDevice(handler().data().deviceId())
727 .withSelector(tsUniC)
728 .withTreatment(uniCTreatment)
Sean Condon3a1efef2018-02-24 13:16:03 +0000729 .forTable(Math.toIntExact(evc.evcIndex())) //narrowing to int
Sean Condonfae8e662016-12-15 10:25:13 +0000730 .makePermanent()
731 .withPriority(PRIORITY_DEFAULT)
732 .withCookie(flowId)
733 .build();
734 flowEntryCollection.add(new DefaultFlowEntry(frUniC, FlowEntryState.ADDED, 0, 0, 0));
735 }
736 }
737 }
738
739 return flowEntryCollection;
740 }
741
742 private long getFlowIdForVlan(List<FlowMapping> fmList, Short vlanId) {
743 if (fmList == null || vlanId == null) {
744 log.warn("Flow Mapping list is null when reading EVCs");
745 return -1L;
746 }
747 for (FlowMapping fm:fmList) {
748 if (fm.ceVlanId().uint16() == vlanId.intValue()) {
749 return fm.flowId().longValue();
750 }
751 }
752 return 0L;
753 }
754
755 private String ceVlanMapForUniSide(
756 EvcPerUni evcPerUni, boolean portN) {
757 if (portN) {
758 return evcPerUni.evcPerUnin().ceVlanMap().string();
759 } else {
760 return evcPerUni.evcPerUnic().ceVlanMap().string();
761 }
762 }
763
764 private Criterion criterionPortForUniSide(
765 UniSideInterfaceAssignmentEnum portAssignment, boolean portN) {
766 boolean cOnOptics = (portAssignment == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS);
Sean Condon3a1efef2018-02-24 13:16:03 +0000767 //If both are true or both are false then return 1
768 int portNum = (cOnOptics == portN) ? 1 : 0;
Sean Condonfae8e662016-12-15 10:25:13 +0000769 return Criteria.matchInPort(PortNumber.portNumber(portNum));
770 }
771
772 private TrafficTreatment treatmentForUniSde(
773 EvcPerUni evcPerUni, boolean portN) {
774 TrafficTreatment.Builder trBuilder = DefaultTrafficTreatment.builder();
775
Sean Condon3a1efef2018-02-24 13:16:03 +0000776 TagManipulation tm;
777 short meterId;
Sean Condonfae8e662016-12-15 10:25:13 +0000778 if (portN) {
779 tm = evcPerUni.evcPerUnin().tagManipulation();
780 meterId = (short) evcPerUni.evcPerUnin().ingressBwpGroupIndex();
781 } else {
782 tm = evcPerUni.evcPerUnic().tagManipulation();
783 meterId = (short) evcPerUni.evcPerUnic().ingressBwpGroupIndex();
784 }
785
786 if (meterId > 0L) {
787 trBuilder = trBuilder.meter(MeterId.meterId((long) meterId));
Sean Condonfae8e662016-12-15 10:25:13 +0000788 }
789
790 if (tm == null) {
791 return trBuilder.build(); //no tag manipulation found
792 }
793
794 if (tm.getClass().equals(DefaultTagPush.class)) {
795 VlanId pushVlanNum = VlanId.vlanId((short) ((TagPush) tm).tagPush().outerTagVlan().uint16());
796 PushTagTypeEnum pushTagType = ((TagPush) tm).tagPush().pushTagType();
797 //Note - the order of elements below MUST match the order of the Treatment in the stored FlowRule
798 // to be an exactMatch. See DefaultFlowRule.exactMatch()
799 trBuilder = trBuilder
800 .pushVlan(pushTagType.equals(PushTagTypeEnum.PUSHCTAG) ?
801 EtherType.VLAN.ethType() : EtherType.QINQ.ethType())
802 .setVlanId(pushVlanNum).transition(Integer.valueOf(0));
803
804 } else if (tm.getClass().equals(DefaultTagPop.class)) {
805 trBuilder = trBuilder.popVlan();
806
807 } else if (tm.getClass().equals(DefaultTagOverwrite.class)) {
808 TagOverwrite to = (TagOverwrite) tm;
809 VlanId ovrVlanNum = VlanId
810 .vlanId((short) (
811 //There are 2 classes TagOverwrite - the other one is already imported
812 to
813 .tagOverwrite()
814 .outerTagVlan()
815 .uint16()));
816 trBuilder = trBuilder.setVlanId(ovrVlanNum);
817
818 }
819
820 return trBuilder.build();
821 }
822
823 private static TagManipulation getTagManipulation(FlowRule fr) {
824 boolean isPop = false;
825 boolean isPush = false;
826 VlanId vlanId = null;
827 EthType ethType = EtherType.VLAN.ethType(); //Default
828 for (Instruction inst:fr.treatment().allInstructions()) {
829 if (inst.type() == Instruction.Type.L2MODIFICATION) {
830 L2ModificationInstruction l2Mod = (L2ModificationInstruction) inst;
831 if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
832 isPop = true;
833 } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
834 isPush = true;
835 ethType = ((ModVlanHeaderInstruction) l2Mod).ethernetType();
836 } else if (l2Mod.subtype() == L2ModificationInstruction.L2SubType.VLAN_ID) {
837 vlanId = ((ModVlanIdInstruction) l2Mod).vlanId();
838 }
839 }
840 }
841
842 if (isPop) {
843 //The should be no vlanId in this case
Sean Condon06613e92017-06-09 15:14:01 +0100844 TagPop pop = new DefaultTagPop();
845 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
846 .evcperuniextensionattributes.tagmanipulation
847 .tagpop.TagPop popInner =
848 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
849 .mseaunievcservice.evcperuniextensionattributes
850 .tagmanipulation.tagpop.DefaultTagPop();
851 pop.tagPop(popInner);
852 return pop;
Sean Condonfae8e662016-12-15 10:25:13 +0000853
854 } else if (isPush && vlanId != null) {
Sean Condon06613e92017-06-09 15:14:01 +0100855 TagPush push = new DefaultTagPush();
856 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
857 .evcperuniextensionattributes.tagmanipulation
858 .tagpush.TagPush pushInner =
859 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
860 .mseaunievcservice.evcperuniextensionattributes
861 .tagmanipulation.tagpush.DefaultTagPush();
862 pushInner.outerTagVlan(new VlanIdType(vlanId.id()));
863 pushInner.pushTagType(ethType.equals(EtherType.VLAN.ethType()) ?
864 PushTagTypeEnum.PUSHCTAG : PushTagTypeEnum.PUSHSTAG);
865 push.tagPush(pushInner);
866 return push;
Sean Condonfae8e662016-12-15 10:25:13 +0000867
868 } else if (vlanId != null) { //This is overwrite, as it has vlanId, but not push or pop
Sean Condon06613e92017-06-09 15:14:01 +0100869 TagOverwrite ovr = new DefaultTagOverwrite();
870 org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317.mseaunievcservice
871 .evcperuniextensionattributes.tagmanipulation
872 .tagoverwrite.TagOverwrite ovrInner =
873 new org.onosproject.yang.gen.v1.mseaunievcservice.rev20160317
874 .mseaunievcservice.evcperuniextensionattributes
875 .tagmanipulation.tagoverwrite.DefaultTagOverwrite();
876 ovrInner.outerTagVlan(new VlanIdType(vlanId.id()));
877 ovr.tagOverwrite(ovrInner);
878 return ovr;
Sean Condonfae8e662016-12-15 10:25:13 +0000879 }
880
881 return null;
882 }
883
884 private static long getMeterId(TrafficTreatment treatment) {
885 return (treatment.metered() != null && treatment.metered().meterId() != null)
886 ? treatment.metered().meterId().id() : 0L;
887 }
888
889 /**
890 * An enumerated type that characterises the 2 port layout of the EA1000 device.
891 * The device is in an SFP package and has only 2 ports, the HOST port which
892 * plugs in to the chassis (Port 1) and the Optics Port on the rear (Port 0).
893 */
894 public enum Ea1000Port {
895 HOST(1),
896 OPTICS(0);
897
898 private int num = 0;
899 private Ea1000Port(int num) {
900 this.num = num;
901 }
902
903 /**
904 * The numerical assignment of this port.
905 * @return The port number
906 */
907 public int portNum() {
908 return num;
909 }
910
911 /**
912 * Return the enumerated value from a port number.
913 * @param num The port number
914 * @return An enumerated value
915 */
916 public static Ea1000Port fromNum(long num) {
917 for (Ea1000Port a:Ea1000Port.values()) {
918 if (a.num == num) {
919 return a;
920 }
921 }
922 return HOST;
923 }
924
925 /**
926 * Get the port that the UNI-N is present on.
927 * @param side The assignment of UNI-side to port
928 * @return An enumerated value
929 */
930 public static Ea1000Port uniNNum(UniSideInterfaceAssignmentEnum side) {
931 if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
932 return OPTICS;
933 } else {
934 return HOST;
935 }
936 }
937
938 /**
939 * Get the port that the UNI-C is present on.
940 * @param side The assignment of UNI-side to port
941 * @return An enumerated value
942 */
943 public static Ea1000Port uniCNum(UniSideInterfaceAssignmentEnum side) {
944 if (side.equals(UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST)) {
945 return HOST;
946 } else {
947 return OPTICS;
948 }
949 }
950
951 /**
952 * Get the port opposite the current port.
953 * @return An enumerated value for the opposite side
954 */
955 public Ea1000Port opposite() {
956 if (this.equals(HOST)) {
957 return OPTICS;
958 } else {
959 return HOST;
960 }
961 }
962
963 /**
964 * Evaluate which side of the UNI on the EA1000 device this port refers to.
965 * @param side The assignment of UNI-side to port
966 * @return An enumerated value representing the UniSide
967 */
968 public UniSide nOrC(UniSideInterfaceAssignmentEnum side) {
969 if ((this == HOST && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_HOST) ||
970 (this == OPTICS && side == UniSideInterfaceAssignmentEnum.UNI_C_ON_OPTICS)) {
971 return UniSide.CUSTOMER;
972 } else {
973 return UniSide.NETWORK;
974 }
975 }
976 }
977}