2 * Copyright (c) 2016, 2017 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.netvirt.sfc.translator.portchain;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.List;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.netvirt.sfc.translator.DelegatingDataTreeListener;
22 import org.opendaylight.netvirt.sfc.translator.NeutronMdsalHelper;
23 import org.opendaylight.netvirt.sfc.translator.SfcMdsalHelper;
24 import org.opendaylight.netvirt.sfc.translator.flowclassifier.FlowClassifierTranslator;
25 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.RenderedServicePathService;
26 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sf.rev140701.service.functions.ServiceFunction;
27 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfc.rev140701.service.function.chain.grouping.ServiceFunctionChain;
28 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sff.rev140701.service.function.forwarders.ServiceFunctionForwarder;
29 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.sfp.rev140701.service.function.paths.ServiceFunctionPath;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.flow.classifier.rev160511.sfc.flow.classifiers.attributes.sfc.flow.classifiers.SfcFlowClassifier;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.PortChains;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.chains.PortChain;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pair.groups.PortPairGroup;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.sfc.rev160511.sfc.attributes.port.pairs.PortPair;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * OpenDaylight Neutron Port Chain yang models data change listener.
45 public class NeutronPortChainListener extends DelegatingDataTreeListener<PortChain> {
46 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChainListener.class);
48 private static final InstanceIdentifier<PortChain> PORT_CHAIN_IID =
49 InstanceIdentifier.create(Neutron.class).child(PortChains.class).child(PortChain.class);
50 private final SfcMdsalHelper sfcMdsalHelper;
51 private final NeutronMdsalHelper neutronMdsalHelper;
52 private final RenderedServicePathService rspService;
54 public NeutronPortChainListener(DataBroker db, RenderedServicePathService rspService) {
55 super(db,new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, PORT_CHAIN_IID));
56 this.sfcMdsalHelper = new SfcMdsalHelper(db);
57 this.neutronMdsalHelper = new NeutronMdsalHelper(db);
58 this.rspService = rspService;
62 * Method removes PortChain which is identified by InstanceIdentifier.
64 * @param deletedPortChain - PortChain for removing
67 public void remove(PortChain deletedPortChain) {
68 sfcMdsalHelper.deleteServiceFunctionPath(PortChainTranslator.getSFPKey(deletedPortChain));
69 sfcMdsalHelper.deleteServiceFunctionChain(PortChainTranslator.getSFCKey(deletedPortChain));
73 * Method updates the original PortChain to the update PortChain.
74 * Both are identified by same InstanceIdentifier.
76 * @param origPortChain - original PortChain
77 * @param updatePortChain - changed PortChain (contain updates)
80 public void update(PortChain origPortChain, PortChain updatePortChain) {
81 List<Uuid> oldFcList = origPortChain.getFlowClassifiers();
82 oldFcList = oldFcList != null ? new ArrayList<>(oldFcList) : new ArrayList<>();
83 List<Uuid> newFcList = updatePortChain.getFlowClassifiers();
84 if (oldFcList != null && newFcList != null) {
85 oldFcList.removeAll(newFcList);
86 if (!oldFcList.isEmpty()) {
87 LOG.debug("Removing old list {}", oldFcList);
88 processFlowClassifiers(origPortChain, oldFcList, null, false);
91 processPortChain(updatePortChain);
95 * Method adds the PortChain which is identified by InstanceIdentifier
98 * @param newPortChain - new PortChain
101 public void add(final PortChain newPortChain) {
102 processPortChain(newPortChain);
105 private void processPortChain(PortChain newPortChain) {
107 //List of Port Pair Group attached to the Port Chain
108 List<PortPairGroup> portPairGroupList = new ArrayList<>();
109 //Port Pair Group and associated Port Pair
110 Map<Uuid, List<PortPair>> groupPortPairsList = new HashMap<>();
112 List<ServiceFunction> portChainServiceFunctionList = new ArrayList<>();
114 //Read chain related port pair group from neutron data store
115 List<Uuid> newPortPairGroups = newPortChain.getPortPairGroups();
116 if (newPortPairGroups != null) {
117 for (Uuid ppgUuid : newPortPairGroups) {
118 PortPairGroup ppg = neutronMdsalHelper.getNeutronPortPairGroup(ppgUuid);
120 List<PortPair> portPairList = new ArrayList<>();
121 portPairGroupList.add(ppg);
122 @org.eclipse.jdt.annotation.Nullable List<Uuid> ppgPortPairs = ppg.getPortPairs();
123 if (ppgPortPairs != null) {
124 for (Uuid ppUuid : ppgPortPairs) {
125 PortPair pp = neutronMdsalHelper.getNeutronPortPair(ppUuid);
127 LOG.error("Port pair {} does not exist in the neutron data store", ppUuid);
130 portPairList.add(pp);
133 groupPortPairsList.put(ppgUuid, portPairList);
138 //For each port pair group
139 for (PortPairGroup ppg : portPairGroupList) {
141 List<PortPair> portPairList = groupPortPairsList.get(ppg.getUuid());
143 //Generate all the SF and write it to SFC data store
144 for (PortPair portPair : portPairList) {
145 //Build the service function for the given port pair.
146 ServiceFunction serviceFunction = PortPairTranslator.buildServiceFunction(portPair, ppg);
147 portChainServiceFunctionList.add(serviceFunction);
149 //Write the Service Function to SFC data store.
150 LOG.info("Add Service Function {} for Port Pair {}", serviceFunction, portPair);
151 sfcMdsalHelper.addServiceFunction(serviceFunction);
154 //Build the SFF Builder from port pair group
155 ServiceFunctionForwarder serviceFunctionForwarder = PortPairGroupTranslator
156 .buildServiceFunctionForwarder(ppg, portPairList);
157 // Send SFF create request
158 LOG.info("Update Service Function Forwarder with {} for Port Pair Group {}", serviceFunctionForwarder, ppg);
159 sfcMdsalHelper.updateServiceFunctionForwarder(serviceFunctionForwarder);
162 //Build Service Function Chain Builder
163 ServiceFunctionChain sfc =
164 PortChainTranslator.buildServiceFunctionChain(newPortChain, portChainServiceFunctionList);
166 //Write SFC to data store
168 LOG.warn("Service Function Chain building failed for Port Chain {}", newPortChain);
172 LOG.info("Add service function chain {}", sfc);
173 sfcMdsalHelper.addServiceFunctionChain(sfc);
175 // Build Service Function Path Builder
176 ServiceFunctionPath sfp = PortChainTranslator.buildServiceFunctionPath(sfc);
178 // Write SFP to data store
179 LOG.info("Add service function path {}", sfp);
180 sfcMdsalHelper.addServiceFunctionPath(sfp);
182 // The RSP will automatically be created from the SFP added above.
184 // Add ACLs from flow classifiers
185 List<Uuid> newFlowClassifiers = newPortChain.getFlowClassifiers();
186 processFlowClassifiers(newPortChain, newFlowClassifiers != null ? newFlowClassifiers : Collections.emptyList(),
187 sfp.getName().getValue(), true);
190 private void processFlowClassifiers(PortChain pc, @NonNull List<Uuid> flowClassifiers, @Nullable String sfpName,
192 for (Uuid uuid : flowClassifiers) {
193 SfcFlowClassifier fc = neutronMdsalHelper.getNeutronFlowClassifier(uuid);
195 Acl acl = FlowClassifierTranslator.buildAcl(fc, sfpName);
198 sfcMdsalHelper.addAclFlowClassifier(acl);
200 sfcMdsalHelper.removeAclFlowClassifier(acl);
203 LOG.warn("Acl building failed for flow classifier {}. Traffic might not be redirected to RSP", fc);
207 LOG.error("Neutron Flow Classifier {} attached to Port Chain {} is not present in the neutron data "
208 + "store", uuid, pc);