Fix NPE triggered after disabling SG on a port
[netvirt.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / netvirt / openstack / netvirt / providers / openflow13 / services / VlanResponderService.java
1 /*
2  * Copyright (c) 2016 NEC Corporation and others. All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services;
9
10 import java.util.ArrayList;
11 import java.util.concurrent.ConcurrentHashMap;
12 import java.util.HashSet;
13 import java.util.Iterator;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Set;
17
18 import org.apache.commons.lang3.tuple.ImmutablePair;
19 import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
20 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
21 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
22 import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
23 import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
24 import org.opendaylight.netvirt.openstack.netvirt.api.VlanResponderProvider;
25 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
26 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
27 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
28 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
29 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
30 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
31 import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
32 import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
33 import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
34 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
57 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
58 import org.osgi.framework.BundleContext;
59 import org.osgi.framework.ServiceReference;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 public class VlanResponderService extends AbstractServiceInstance implements VlanResponderProvider, ConfigInterface {
64     private static final Logger LOG = LoggerFactory.getLogger(VlanResponderService.class);
65     private static final int PRIORITY_2 = 2;
66     private static final int PRIORITY_4 = 4;
67     private static final int PRIORITY_5 = 5;
68
69     private volatile ConfigurationService configurationService;
70     private volatile NodeCacheManager nodeCacheManager;
71     private volatile TenantNetworkManager tenantNetworkManager;
72     private volatile Southbound southbound;
73     private volatile INeutronNetworkCRUD neutronNetworkCache;
74     private volatile Map<String, ArrayList<ImmutablePair<String, Long>>> segmentationOfPortMap =
75             new ConcurrentHashMap<String, ArrayList<ImmutablePair<String, Long>>>();
76
77     public VlanResponderService() {
78         super(Service.OUTBOUND_NAT);
79     }
80
81     public VlanResponderService(Service service) {
82         super(service);
83     }
84
85     /**
86      * Creates provider network flows for internal bridge.
87      *
88      * @param dpIdInt dp Id
89      * @param segmentationId segmentation id
90      * @param patchIntPort patch port of internal bridge
91      * @param ofPort of port value
92      * @param macAddress mac address
93      * @param vlanProviderCache Initial VLAN cache with processing cache
94      * @param write - flag to indicate the operation
95      */
96     @Override
97     public void programProviderNetworkRulesInternal(Long dpIdInt, String segmentationId, Long ofPort, Long patchIntPort,
98             String macAddress, Map<String, Set<String>> vlanProviderCache, boolean write) {
99
100         programProviderBroadAndMultiCastOfRouter(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, write);
101         programProviderUnicastFlowOfRouters(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, write);
102         programProviderUnicastFlowOfExternal(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, write);
103         programProviderBroadAndMultiCastOfExternal(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, write);
104         programProviderUnicastFlowFromExternal(dpIdInt, segmentationId, ofPort, patchIntPort, macAddress, vlanProviderCache, write);
105     }
106
107     /**
108      * Creates provider network flows for external bridge.
109      *
110      * @param dpIdExt dp id
111      * @param segmentationId segmentation id
112      * @param patchExtPort patch port of external bridge
113      * @param macAddress mac address
114      * @param vlanProviderCache Initial VLAN cache with processing cache
115      * @param write - flag indicate the operation
116      */
117     @Override
118     public void programProviderNetworkRulesExternal(Long dpIdExt,  String segmentationId, Long patchExtPort,
119             String macAddress, Map<String, Set<String>> vlanProviderCache, boolean write) {
120
121         programProviderNetworkForExternal(dpIdExt, segmentationId, patchExtPort, macAddress, vlanProviderCache, write);
122         programProviderNetworkDrop(dpIdExt, patchExtPort, vlanProviderCache, write);
123     }
124
125
126     /**
127      * Write or remove the flows for forward the BC/MC packets of router to patch port and
128      * the router ports connected to same external network.
129      * Sample flow: table=100, priority=5,in_port=2,dl_src=fa:16:3e:ff:9c:57,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00
130      * actions=output:3,push_vlan:0x8100,set_field:4196->vlan_vid,output:1
131      */
132     private void programProviderBroadAndMultiCastOfRouter(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
133                                              String macAddress, boolean write) {
134         try {
135             String nodeName = OPENFLOW + dpidLong;
136             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
137             FlowBuilder flowBuilder = new FlowBuilder();
138             // Create the OF Match using MatchBuilder
139             MatchBuilder matchBuilder = new MatchBuilder();
140             //Match In Port
141             MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
142             matchBuilder = MatchUtils.createEthSrcDestMatch(matchBuilder, new MacAddress(macAddress),
143                     new MacAddress("01:00:00:00:00:00"), new MacAddress("01:00:00:00:00:00"));
144             flowBuilder.setMatch(matchBuilder.build());
145             // Add Flow Attributes
146             String flowName = "ProviderNetwork_BC_Router_" + dpidLong + "_" + ofPort;
147             final FlowId flowId = new FlowId(flowName);
148             flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
149                     .setPriority(PRIORITY_5).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
150             ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
151             if (macAddrOfPortPairList == null) {
152                 macAddrOfPortPairList = new ArrayList<ImmutablePair<String, Long>>();
153                 segmentationOfPortMap.put(segmentationId, macAddrOfPortPairList);
154             }
155             if (write) {
156                 ImmutablePair<String, Long> ofPortMacAddressPair = new ImmutablePair<>(macAddress, ofPort);
157                 if (macAddrOfPortPairList.contains(ofPortMacAddressPair)) {
158                     return;
159                 }
160                 List<Instruction> outputInstructions = new ArrayList<Instruction>();
161                 int instructionIndex = 0;
162                 for (ImmutablePair<String, Long> macAddressOfPortPair : macAddrOfPortPairList) {
163                     InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong, macAddressOfPortPair.getRight(),
164                             outputInstructions);
165                     instructionIndex++;
166                 }
167                 // Set the Output Port/Iface
168                 Instruction outputPortInstruction = InstructionUtils.createVlanOutputPortInstructions(new InstructionBuilder(),
169                         dpidLong, patchPort, outputInstructions, new VlanId(Integer.valueOf(segmentationId)))
170                         .setOrder(0).setKey(new InstructionKey(0)).build();
171                 // Add InstructionsBuilder to FlowBuilder
172                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
173                 writeFlow(flowBuilder, nodeBuilder);
174                 macAddrOfPortPairList.add(ofPortMacAddressPair);
175             } else {
176                 removeFlow(flowBuilder, nodeBuilder);
177                 Iterator<ImmutablePair<String, Long>> iterator = macAddrOfPortPairList.iterator();
178                 while (iterator.hasNext()) {
179                     ImmutablePair<String, Long> macAddressOfPortPair = iterator.next();
180                     if (macAddress.equals(macAddressOfPortPair.getLeft())) {
181                         iterator.remove();
182                         break;
183                     }
184                 }
185             }
186             programExistingProviderBroadAndMultiCastOfRouter(dpidLong, segmentationId, ofPort, patchPort, macAddress, write);
187         } catch (Exception e) {
188             LOG.error("Error while writing/removing broadcast flows. dpidLong = {}, patchPort={}, write = {}."
189                     + " Caused due to, {}", dpidLong, patchPort, write, e.getMessage());
190         }
191     }
192
193     /**
194      * Write or remove the existing flows of forward the BC/MC packets of router to patch port and
195      * the router ports connected to same external network.
196      * Sample flow: table=100, priority=5,in_port=2,dl_src=fa:16:3e:ff:9c:57,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00
197      * actions=output:3,push_vlan:0x8100,set_field:4196->vlan_vid,output:1
198      */
199     private void programExistingProviderBroadAndMultiCastOfRouter(Long dpidLong, String segmentationId, Long currentOfPort, Long patchPort,
200             String macAddress, boolean write) {
201
202         String nodeName = OPENFLOW + dpidLong;
203         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
204         FlowBuilder flowBuilder = new FlowBuilder();
205
206         MatchBuilder matchBuilder = new MatchBuilder();
207         ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
208         for (ImmutablePair<String, Long> macAddrOfPortPair : macAddrOfPortPairList) {
209             Long ofPort = macAddrOfPortPair.getRight();
210             if (ofPort.equals(currentOfPort)) {
211                 continue;
212             }
213             //Match In Port
214             MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
215             matchBuilder = MatchUtils.createEthSrcDestMatch(matchBuilder, new MacAddress(macAddrOfPortPair.getLeft()),
216                     new MacAddress("01:00:00:00:00:00"), new MacAddress("01:00:00:00:00:00"));
217             flowBuilder.setMatch(matchBuilder.build());
218             // Add Flow Attributes
219             String flowName = "ProviderNetwork_BC_Router_" + dpidLong + "_" + ofPort;
220             final FlowId flowId = new FlowId(flowName);
221             flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
222             .setPriority(PRIORITY_5).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
223
224             if (write) {
225                 List<Instruction> outputInstructions = new ArrayList<Instruction>();
226                 int instructionIndex = 0;
227                 for (ImmutablePair<String, Long> macAddressOfPortPair : macAddrOfPortPairList) {
228                     if (ofPort.equals(macAddressOfPortPair.getRight())) {
229                         continue;
230                     }
231                     InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong, macAddressOfPortPair.getRight(),
232                             outputInstructions);
233                     instructionIndex++;
234                 }
235
236                 Instruction outputPortInstruction = InstructionUtils.createVlanOutputPortInstructions(new InstructionBuilder(),
237                         dpidLong, patchPort, outputInstructions, new VlanId(Integer.valueOf(segmentationId)))
238                         .setOrder(0).setKey(new InstructionKey(0)).build();
239                 // Add InstructionsBuilder to FlowBuilder
240                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
241                 writeFlow(flowBuilder, nodeBuilder);
242             } else {
243                 List<Instruction> outputInstructions = new ArrayList<Instruction>();
244                 int instructionIndex = 0;
245                 for (ImmutablePair<String, Long> ofPortMacAddrPair : macAddrOfPortPairList) {
246                     Long cachedOfPort = ofPortMacAddrPair.getRight();
247                     if (cachedOfPort.equals(ofPort) || cachedOfPort.equals(currentOfPort)) {
248                         continue;
249                     }
250                     InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong, cachedOfPort, outputInstructions);
251                     instructionIndex++;
252                 }
253                 Instruction outputPortInstruction = InstructionUtils.createVlanOutputPortInstructions(new InstructionBuilder(),
254                         dpidLong, patchPort, outputInstructions, new VlanId(Integer.valueOf(segmentationId)))
255                         .setOrder(0).setKey(new InstructionKey(0)).build();
256                 // Add InstructionsBuilder to FlowBuilder
257                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
258                 writeFlow(flowBuilder, nodeBuilder);
259             }
260         }
261     }
262
263     /**
264      * Write or remove the flows for forward the packets from one router to another routers (Unicast flow)
265      * Sample flow: table=100, priority=4,in_port=2,dl_dst=fa:16:3e:4b:cc:0a actions=output:8
266      */
267     private void programProviderUnicastFlowOfRouters(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
268             String macAddress, boolean write) {
269         try {
270             String nodeName = OPENFLOW + dpidLong;
271             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
272             FlowBuilder flowBuilder = new FlowBuilder();
273             ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
274             if (write) {
275                 for (ImmutablePair<String, Long> macAddressOfPortPair : macAddrOfPortPairList) {
276                     for (ImmutablePair<String, Long> subMacAddressOfPortPair : macAddrOfPortPairList) {
277                         if (macAddressOfPortPair.getLeft().equals(subMacAddressOfPortPair.getLeft())
278                                 || ((!macAddressOfPortPair.getLeft().equals(macAddress) &&
279                                         !subMacAddressOfPortPair.getLeft().equals(macAddress)))) {
280                             continue;
281                         }
282                         // Create the OF Match using MatchBuilder
283                         MatchBuilder currentMatchBuilder = new MatchBuilder();
284                         //Match In Port
285                         MatchUtils.createInPortMatch(currentMatchBuilder, dpidLong, macAddressOfPortPair.getRight());
286                         currentMatchBuilder = MatchUtils.createDestEthMatch(currentMatchBuilder,
287                                 new MacAddress(subMacAddressOfPortPair.getLeft()), null);
288                         flowBuilder.setMatch(currentMatchBuilder.build());
289                         // Add Flow Attributes
290                         String currentFlowName = "ProviderNetwork_unicast_router_" + dpidLong + "_" +
291                             macAddressOfPortPair.getLeft() + "_" + subMacAddressOfPortPair.getLeft();
292
293                         final FlowId flowId = new FlowId(currentFlowName);
294                         flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
295                                 .setPriority(PRIORITY_4).setFlowName(currentFlowName).setHardTimeout(0).setIdleTimeout(0);
296
297                         Instruction outputPortInstruction = InstructionUtils.createOutputPortInstructions(new InstructionBuilder(),
298                                 dpidLong, subMacAddressOfPortPair.getRight()).setOrder(0).setKey(new InstructionKey(0)).build();
299                         // Add InstructionsBuilder to FlowBuilder
300                         InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
301                         writeFlow(flowBuilder, nodeBuilder);
302                     }
303                 }
304             } else {
305                 for (ImmutablePair<String, Long> macAddressOfPortPair : macAddrOfPortPairList) {
306                     if (macAddressOfPortPair.getLeft().equals(macAddress)) {
307                         continue;
308                     }
309                      // Create the OF Match using MatchBuilder
310                      MatchBuilder matchBuilder = new MatchBuilder();
311                      //Match In Port
312                      MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
313                      matchBuilder = MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(macAddressOfPortPair.getLeft()), null);
314                      flowBuilder.setMatch(matchBuilder.build());
315                      // Add Flow Attributes
316                      String flowName = "ProviderNetwork_unicast_router_" + dpidLong + "_" + macAddress + "_" + macAddressOfPortPair.getLeft();
317                      FlowId flowId = new FlowId(flowName);
318                      flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
319                               .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
320
321                     removeFlow(flowBuilder, nodeBuilder);
322
323                     MatchUtils.createInPortMatch(matchBuilder, dpidLong, macAddressOfPortPair.getRight());
324                     matchBuilder = MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(macAddress), null);
325                     flowBuilder.setMatch(matchBuilder.build());
326                     // Add Flow Attributes
327                     flowName = "ProviderNetwork_unicast_router_" + dpidLong + "_" + macAddressOfPortPair.getLeft() + "_" + macAddress;
328                     flowId = new FlowId(flowName);
329                     flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
330                              .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
331
332                     removeFlow(flowBuilder, nodeBuilder);
333                 }
334             }
335         } catch (Exception e) {
336             LOG.error("Error while writing/removing unicast flow of routers. dpidLong = {}, patchPort={}, write = {}."
337                     + " Caused due to, {}", dpidLong, patchPort, write, e.getMessage());
338         }
339     }
340
341     /**
342      * Write or remove the flows for forwarding the BC/MC packets to all other router ports connected to same external network.
343      * Sample flow: table=100, priority=4,in_port=1,dl_vlan=100,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=pop_vlan,output:2,output:8
344      */
345     private void programProviderBroadAndMultiCastOfExternal(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
346                                              String macAddress, boolean write) {
347         try {
348             String nodeName = OPENFLOW + dpidLong;
349             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
350             FlowBuilder flowBuilder = new FlowBuilder();
351             // Create the OF Match using MatchBuilder
352             MatchBuilder matchBuilder = new MatchBuilder();
353          // Match Vlan ID
354             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
355             //Match In Port
356             MatchUtils.createInPortMatch(matchBuilder, dpidLong, patchPort);
357             matchBuilder = MatchUtils.createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"),
358                     new MacAddress("01:00:00:00:00:00"));
359             flowBuilder.setMatch(matchBuilder.build());
360             // Add Flow Attributes
361             String flowName = "ProviderNetwork_BC_External_" + segmentationId + "_" + patchPort;
362             final FlowId flowId = new FlowId(flowName);
363             flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
364                     .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
365             if (write) {
366                 ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
367                 List<Instruction> outputInstructions = new ArrayList<Instruction>();
368                 int instructionIndex = 1;
369                 for (ImmutablePair<String, Long> ofPortMacAddrPair : macAddrOfPortPairList) {
370                     InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong,
371                             ofPortMacAddrPair.getRight(), outputInstructions);
372                     instructionIndex++;
373                 }
374                 Instruction outputPortInstruction =
375                         InstructionUtils.createPopOutputPortInstructions(new InstructionBuilder(), dpidLong, null, outputInstructions)
376                         .setOrder(0)
377                         .setKey(new InstructionKey(0))
378                         .build();
379                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
380                 writeFlow(flowBuilder, nodeBuilder);
381             } else {
382                 ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
383                 if (macAddrOfPortPairList == null || macAddrOfPortPairList.isEmpty()) {
384                     removeFlow(flowBuilder, nodeBuilder);
385                 } else {
386                     List<Instruction> outputInstructions = new ArrayList<Instruction>();
387                     int instructionIndex = 1;
388                     for (ImmutablePair<String, Long> ofPortMacAddrPair : macAddrOfPortPairList) {
389                         InstructionUtils.createOutputPortInstruction(instructionIndex, dpidLong, ofPortMacAddrPair.getRight(),
390                                 outputInstructions);
391                         instructionIndex++;
392                     }
393                     Instruction outputPortInstruction = InstructionUtils.createPopOutputPortInstructions(new InstructionBuilder(),
394                             dpidLong, null, outputInstructions).setOrder(0).setKey(new InstructionKey(0)).build();
395                     // Add InstructionsBuilder to FlowBuilder
396                     InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
397                     writeFlow(flowBuilder, nodeBuilder);
398                 }
399             }
400         } catch (Exception e) {
401             LOG.error("Error while writing/removing BC/MC flow of external interface. dpidLong = {}, patchPort={}, write = {}."
402                     +" Caused due to, {}", dpidLong, patchPort, write, e.getMessage());
403         }
404     }
405
406
407     /**
408      * Write or remove the flows for forwarding unicast packets from router to external Gateway.
409      * Sample flow: table=100, priority=2,in_port=2,dl_src=fa:16:3e:ff:9c:57 actions=push_vlan:0x8100,set_field:4196- >vlan_vid,output:1
410      */
411     private void programProviderUnicastFlowOfExternal(Long dpidLong, String segmentationId, Long ofPort, Long patchPort,
412             String macAddress, boolean write) {
413         try {
414             String nodeName = OPENFLOW + dpidLong;
415             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
416             FlowBuilder flowBuilder = new FlowBuilder();
417             // Create the OF Match using MatchBuilder
418             MatchBuilder matchBuilder = new MatchBuilder();
419             //Match In Port
420             MatchUtils.createInPortMatch(matchBuilder, dpidLong, ofPort);
421             MatchUtils.createEthSrcMatch(matchBuilder, new MacAddress(macAddress));
422             flowBuilder.setMatch(matchBuilder.build());
423             // Add Flow Attributes
424             String flowName = "ProviderNetwork_unicast_external_" + dpidLong + "_" + ofPort;
425             final FlowId flowId = new FlowId(flowName);
426             flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
427                     .setPriority(PRIORITY_2).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
428             if (write) {
429                 // Set the Output Port/Iface
430                 Instruction outputPortInstruction = InstructionUtils.createPushVlanInstruction(new InstructionBuilder(),
431                         dpidLong, patchPort, new VlanId(Integer.valueOf(segmentationId)), new ArrayList<>())
432                         .setOrder(0).setKey(new InstructionKey(0)).build();
433                 // Add InstructionsBuilder to FlowBuilder
434                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
435                 writeFlow(flowBuilder, nodeBuilder);
436             } else {
437                 removeFlow(flowBuilder, nodeBuilder);
438             }
439         } catch (Exception e) {
440             LOG.error("Error while writing/removing unicast flow of external gateway. dpidLong = {}, write = {}."
441                     +" Caused due to, {}", dpidLong, write, e.getMessage());
442         }
443     }
444
445     /**
446      * Write or remove the flows for forwarding unicast packets from external Gateway to router.
447      * Sample flow: table=100, priority=4,in_port=1,dl_vlan=100,dl_dst=fa:16:3e:ff:9c:57 actions=pop_vlan,output:2
448      */
449     private void programProviderUnicastFlowFromExternal(Long dpidLong, String segmentationId,
450                                               Long ofPort, Long patchPort, String macAddress,
451                                               Map<String, Set<String>> vlanProviderCache, boolean write) {
452         try {
453             String nodeName = OPENFLOW + dpidLong;
454             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
455             FlowBuilder flowBuilder = new FlowBuilder();
456             ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(segmentationId);
457             // Create the OF Match using MatchBuilder
458             MatchBuilder matchBuilder = new MatchBuilder();
459             // Match Vlan ID
460             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
461             //Match In Port
462             MatchUtils.createInPortMatch(matchBuilder, dpidLong, patchPort);
463             matchBuilder = MatchUtils.createDestEthMatch(matchBuilder, new MacAddress(macAddress), null);
464             flowBuilder.setMatch(matchBuilder.build());
465             // Add Flow Attributes
466             String flowName = "ProviderNetwork_unicast_ext_int" + segmentationId + "_" + ofPort;
467             final FlowId flowId = new FlowId(flowName);
468             flowBuilder.setId(flowId).setBarrier(true).setTableId(getTable()).setKey(new FlowKey(flowId))
469                     .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
470             if (write) {
471                 // Set the Output Port/Iface
472                 Instruction outputPortInstruction = InstructionUtils.createPopOutputPortInstructions(new InstructionBuilder(),
473                         dpidLong, ofPort, null).setOrder(0).setKey(new InstructionKey(0)).build();
474                 // Add InstructionsBuilder to FlowBuilder
475                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, outputPortInstruction);
476                 writeFlow(flowBuilder, nodeBuilder);
477             } else {
478                  removeFlow(flowBuilder, nodeBuilder);
479                }
480         } catch (Exception e) {
481             LOG.error("Error while writing/removing unicast flow of external gateway to router. dpidLong = {}, patchPort={}, write = {}."
482                     + "Caused due to, {}", dpidLong, patchPort, write, e.getMessage());
483         }
484     }
485
486     /**
487      * Write or remove the flows for external bridge.
488      * Sample flow: cookie=0x0, duration=4831.827s, table=0, n_packets=1202, n_bytes=56476, priority=4,in_port=3,
489      * dl_src=fa:16:3e:74:a9:2e actions=push_vlan:0x8100,set_field:4196 vlan_vid,NORMAL
490      */
491     private void programProviderNetworkForExternal(Long dpidLong, String segmentationId,
492                                                Long patchExtPort, String macAddress,
493                                                Map<String, Set<String>> vlanProviderCache, boolean write) {
494         try {
495             String nodeName = OPENFLOW + dpidLong;
496             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
497             FlowBuilder flowBuilder = new FlowBuilder();
498             // Create the OF Match using MatchBuilder
499             MatchBuilder matchBuilder = new MatchBuilder();
500             //Match Vlan ID
501             MatchUtils.createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId)), true);
502             //Match In Port
503             MatchUtils.createInPortMatch(matchBuilder, dpidLong, patchExtPort);
504             flowBuilder.setMatch(matchBuilder.build());
505             // Add Flow Attributes
506             String flowName = "ProviderNetwork_pushVLAN_" + dpidLong + "_" + segmentationId;
507             final FlowId flowId = new FlowId(flowName);
508             flowBuilder.setId(flowId).setBarrier(true).setTableId((short) 0).setKey(new FlowKey(flowId))
509                     .setPriority(PRIORITY_4).setFlowName(flowName).setHardTimeout(0).setIdleTimeout(0);
510             if (write) {
511                 LOG.debug("In programProviderNetworkPushVlan macAddress:" + macAddress
512                         + "segmentationId:" + segmentationId);
513                 Set<String> lstMacAddress = new HashSet<String>();
514                 if (vlanProviderCache != null && !vlanProviderCache.isEmpty() && vlanProviderCache.containsKey(segmentationId)) {
515                     lstMacAddress = vlanProviderCache.get(segmentationId);
516                 } else {
517                     lstMacAddress = new HashSet<String>();
518                     vlanProviderCache.put(segmentationId, lstMacAddress);
519                 }
520                 lstMacAddress.add(macAddress);
521                 Instruction normalInstruction = InstructionUtils.createNormalInstructions(
522                         FlowUtils.getNodeName(dpidLong), new InstructionBuilder()).
523                         setOrder(0).setKey(new InstructionKey(0)).build();
524                 // Add InstructionsBuilder to FlowBuilder
525                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, normalInstruction);
526                 writeFlow(flowBuilder, nodeBuilder);
527             } else {
528                 Set<String> lstMacAddress = new HashSet<String>();
529                 if (vlanProviderCache != null && !vlanProviderCache.isEmpty() && vlanProviderCache.containsKey(segmentationId)) {
530                     lstMacAddress = vlanProviderCache.get(segmentationId);
531                     lstMacAddress.remove(macAddress);
532                 }
533                 if (lstMacAddress == null || lstMacAddress.isEmpty()) {
534                     vlanProviderCache.remove(segmentationId);
535                 }
536                 boolean isSegmentationIdExist = vlanProviderCache.containsKey(segmentationId);
537                 if (!isSegmentationIdExist)  {
538                     removeFlow(flowBuilder, nodeBuilder);
539                 }
540                 //removeFlow(flowBuilder, nodeBuilder);
541             }
542         } catch (Exception e) {
543             LOG.error("Error while writing/removing push vlan instruction flow. dpidLong = {}, patchPort={}, write = {}."
544                     + "Caused due to, {}", dpidLong, patchExtPort, write, e.getMessage());
545         }
546     }
547
548     /**
549      * Write or remove the flows for drop instructions based on flag value actions.
550      * Sample flow: table=0, n_packets=0, n_bytes=0, priority=2,in_port=3 actions=drop
551      */
552     private void programProviderNetworkDrop(Long dpidLong, Long patchExtPort,
553                                            Map<String, Set<String>> vlanProviderCache, boolean write) {
554         try {
555             String nodeName = OPENFLOW + dpidLong;
556             NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(nodeName);
557             FlowBuilder flowBuilder = new FlowBuilder();
558             // Create the OF Match using MatchBuilder
559             MatchBuilder matchBuilder = new MatchBuilder();
560             //Match In Port
561             MatchUtils.createInPortMatch(matchBuilder, dpidLong, patchExtPort);
562             flowBuilder.setMatch(matchBuilder.build());
563             // Add Flow Attributes
564             String flowName = "ProviderNetwork_drop_" + dpidLong + "_" + patchExtPort;
565             final FlowId flowId = new FlowId(flowName);
566             flowBuilder.setId(flowId).setBarrier(true).setTableId((short) 0)
567                     .setKey(new FlowKey(flowId)).setPriority(PRIORITY_2).setFlowName(flowName)
568                     .setHardTimeout(0).setIdleTimeout(0);
569             if (write) {
570                 // Call the InstructionBuilder Methods Containing Actions
571                 Instruction dropInstruction = InstructionUtils.createDropInstructions(new InstructionBuilder())
572                         .setOrder(0)
573                         .setKey(new InstructionKey(0))
574                         .build();
575                 // Add InstructionsBuilder to FlowBuilder
576                 InstructionUtils.setFlowBuilderInstruction(flowBuilder, dropInstruction);
577                 writeFlow(flowBuilder, nodeBuilder);
578             } else {
579                 if (vlanProviderCache.isEmpty()) {
580                     removeFlow(flowBuilder, nodeBuilder);
581                 }
582             }
583         } catch (Exception e) {
584             LOG.error("Error while writing/removing drop instruction flow. dpidLong = {}, patchPort={}, write = {}."
585                     + "Caused due to, {}", dpidLong, patchExtPort, write, e.getMessage());
586         }
587     }
588
589     private void populateSegmentationCache() {
590         try {
591             Map<String, String> networkUUIDSegIdMap = new ConcurrentHashMap<String, String>();
592             for (Node node : nodeCacheManager.getBridgeNodes()) {
593                 Node srcBridgeNode = southbound.getBridgeNode(node, configurationService.getIntegrationBridgeName());
594                 if (srcBridgeNode != null) {
595                     List<OvsdbTerminationPointAugmentation> terminationPointOfBridgeList =
596                             southbound.getTerminationPointsOfBridge(srcBridgeNode);
597                     for (OvsdbTerminationPointAugmentation intf : terminationPointOfBridgeList) {
598                         NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
599                         if (neutronPort != null && neutronPort.getDeviceOwner().equalsIgnoreCase(Constants.OWNER_ROUTER_GATEWAY)) {
600                             final String macAddress = neutronPort.getMacAddress();
601                             final String networkUUID = neutronPort.getNetworkUUID();
602                             String providerSegmentationId = networkUUIDSegIdMap.get(networkUUID);
603                             if (providerSegmentationId == null) {
604                                 NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
605                                 providerSegmentationId = neutronNetwork != null ?
606                                         neutronNetwork.getProviderSegmentationID() : null;
607                             }
608                             if (providerSegmentationId == null || providerSegmentationId.isEmpty()
609                                     || macAddress == null || macAddress.isEmpty()) {
610                                 continue;
611                             }
612                             networkUUIDSegIdMap.put(networkUUID, providerSegmentationId);
613                             ArrayList<ImmutablePair<String, Long>> macAddrOfPortPairList = segmentationOfPortMap.get(providerSegmentationId);
614                             if (macAddrOfPortPairList == null)
615                             {
616                                 macAddrOfPortPairList = new ArrayList<ImmutablePair<String, Long>>();
617                                 segmentationOfPortMap.put(providerSegmentationId, macAddrOfPortPairList);
618                             }
619                             ImmutablePair<String, Long> macAddrOfPortPair = new ImmutablePair<String, Long>(macAddress, intf.getOfport());
620                             macAddrOfPortPairList.add(macAddrOfPortPair);
621                         }
622                     }
623                 }
624             }
625         }
626         catch (Exception e) {
627             LOG.error("Error while populating segmentation mac-ofport cache, due to {} ", e.getMessage());
628         }
629     }
630
631     @Override
632     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
633         super.setDependencies(bundleContext.getServiceReference(VlanResponderProvider.class.getName()), this);
634         configurationService =
635                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
636         southbound =
637                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
638         nodeCacheManager =
639                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
640         tenantNetworkManager =
641                 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
642     }
643
644     @Override
645     public void setDependencies(Object impl) {
646         if (impl instanceof INeutronNetworkCRUD) {
647             neutronNetworkCache = (INeutronNetworkCRUD)impl;
648         }
649         populateSegmentationCache();
650     }
651
652 }