Neutron-mapper uses only DTOs from neutron.yang
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / OrdinalFactory.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.groupbasedpolicy.renderer.ofoverlay.flow;
9
10 import java.util.List;
11 import java.util.Set;
12 import java.util.TreeSet;
13 import java.util.concurrent.ConcurrentHashMap;
14 import java.util.concurrent.ConcurrentMap;
15 import java.util.concurrent.atomic.AtomicInteger;
16
17 import com.google.common.annotations.VisibleForTesting;
18
19 import org.opendaylight.groupbasedpolicy.dto.ConditionGroup;
20 import org.opendaylight.groupbasedpolicy.dto.EgKey;
21 import org.opendaylight.groupbasedpolicy.dto.EpKey;
22 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
23 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.EndpointGroup;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 public class OrdinalFactory {
42
43     private final static Logger LOG = LoggerFactory.getLogger(OrdinalFactory.class);
44
45     /**
46      * Counter used to allocate ordinal values for forwarding contexts and VNIDs
47      */
48     private final static AtomicInteger policyOrdinal = new AtomicInteger(1);
49
50     private final static ConcurrentMap<String, Integer> ordinals = new ConcurrentHashMap<>();
51
52     // XXX - need to garbage collect
53     private final static ConcurrentMap<ConditionGroup, Integer> cgOrdinals = new ConcurrentHashMap<>();
54
55     /**
56      * Creates an ordinal for the OfOverlay pipeline comparison, based on @TenantId and a
57      * uniqueID (UUID) associated with any other attribute.
58      *
59      * @param tenantId the tenant id
60      * @param id a unique id
61      * @return the ordinal
62      */
63     public static int getContextOrdinal(final TenantId tenantId, final UniqueId id) {
64         if (tenantId == null || id == null)
65             return 0;
66         return getContextOrdinalFromString(tenantId.getValue() + "|" + id.getValue());
67     }
68
69     /**
70      * Get a unique ordinal for the given condition group, suitable for use in
71      * the data plane. This is unique only for this node, and not globally.
72      *
73      * @param cg
74      *        the {@link ConditionGroup}
75      * @return the unique ID
76      */
77     public static int getCondGroupOrdinal(final ConditionGroup cg) {
78         if (cg == null)
79             return 0;
80         Integer ord = cgOrdinals.get(cg);
81         if (ord == null) {
82             ord = policyOrdinal.getAndIncrement();
83             Integer old = cgOrdinals.putIfAbsent(cg, ord);
84             if (old != null)
85                 ord = old;
86         }
87         return ord.intValue();
88     }
89
90     /**
91      * Get a 32-bit context ordinal suitable for use in the OF data plane for
92      * the given policy item.
93      *
94      * @param destNode
95      *        destination node ID
96      * @return the 32-bit ordinal value
97      * @throws Exception throws all exception
98      */
99
100     public static int getContextOrdinal(NodeId destNode) throws Exception {
101         return getContextOrdinalFromString(destNode.getValue());
102     }
103
104     public static int getContextOrdinal(Endpoint ep, NetworkDomainId networkContainment) {
105
106         Set<String> epgs = new TreeSet<>();
107
108         // Get EPGs and add to ordered Set
109         if (ep.getEndpointGroup() != null) {
110             epgs.add(ep.getEndpointGroup().getValue());
111         }
112         if (ep.getEndpointGroups() != null) {
113             for (EndpointGroupId epgId : ep.getEndpointGroups()) {
114                 epgs.add(epgId.getValue());
115             }
116         }
117
118         StringBuilder key = new StringBuilder(ep.getTenant().getValue());
119
120         for (String epg : epgs) {
121             key.append('|');
122             key.append(epg);
123         }
124
125         key.append("|").append(networkContainment);
126
127         return getContextOrdinalFromString(key.toString());
128
129     }
130
131     public static int getContextOrdinal(Endpoint ep) {
132
133         Set<String> epgs = new TreeSet<>();
134
135         // Get EPGs and add to ordered Set
136         if (ep.getEndpointGroup() != null) {
137             epgs.add(ep.getEndpointGroup().getValue());
138         }
139         if (ep.getEndpointGroups() != null) {
140             for (EndpointGroupId epgId : ep.getEndpointGroups()) {
141                 epgs.add(epgId.getValue());
142             }
143         }
144
145         StringBuilder key = new StringBuilder(ep.getTenant().getValue());
146
147         for (String epg : epgs) {
148             key.append('|');
149             key.append(epg);
150         }
151
152         return getContextOrdinalFromString(key.toString());
153
154     }
155
156     /**
157      * Get a 32-bit context ordinal suitable for use in the OF data plane for
158      * the given policy item.
159      *
160      * @param id
161      *        the unique ID for the element
162      * @return the 32-bit ordinal value
163      */
164     private static int getContextOrdinalFromString(final String id) {
165
166         Integer ord = ordinals.get(id);
167         if (ord == null) {
168             ord = policyOrdinal.getAndIncrement();
169             Integer old = ordinals.putIfAbsent(id, ord);
170             if (old != null)
171                 ord = old;
172         }
173         return ord.intValue();
174     }
175
176     public static final EndpointFwdCtxOrdinals getEndpointFwdCtxOrdinals(OfContext ctx,
177             Endpoint ep) {
178         IndexedTenant tenant = ctx.getTenant(ep.getTenant());
179         if (tenant == null) {
180             LOG.debug("Tenant {} is null", ep.getTenant());
181             return null;
182         }
183         return new EndpointFwdCtxOrdinals(ep, ctx);
184     }
185
186     // TODO alagalah Li: Move to either OrdinalFactory or EndpointManager
187     public static class EndpointFwdCtxOrdinals {
188
189         private NetworkDomainId networkContainment;
190         private EpKey ep;
191         private int epgId = 0, bdId = 0, fdId = 0, l3Id = 0, cgId = 0, tunnelId = 0;
192
193         private EndpointFwdCtxOrdinals(Endpoint ep, OfContext ctx) {
194             this.ep = new EpKey(ep.getL2Context(), ep.getMacAddress());
195
196             IndexedTenant tenant = ctx.getTenant(ep.getTenant());
197
198             // Set network containment either from ep, or from primary EPG
199             if (ep.getNetworkContainment() != null) {
200                 this.networkContainment = ep.getNetworkContainment();
201             } else {
202                 EndpointGroup epg = tenant.getEndpointGroup(ep.getEndpointGroup());
203                 if (epg.getNetworkDomain() != null) {
204                     this.networkContainment = epg.getNetworkDomain();
205                 } else {
206                     LOG.info("endPoint ordinals for {} not processed in SourceMapper. Must be able to resolve "
207                             + "network containment either directly, or from primary EPG", ep.getKey());
208                     return;
209                 }
210             }
211
212             // TODO: alagalah: I have a draft to address structure of mEPG
213             // conditions, but
214             // out of scope until broader bugs with conditions are fixed.
215             List<ConditionName> conds = ctx.getEndpointManager().getConditionsForEndpoint(ep);
216             ConditionGroup cg = ctx.getCurrentPolicy().getEgCondGroup(new EgKey(ep.getTenant(), ep.getEndpointGroup()), conds);
217             this.cgId = getCondGroupOrdinal(cg);
218
219             // Based on network containment, determine components of
220             // forwarding context
221             Subnet s = ctx.getTenant(ep.getTenant()).resolveSubnet(new SubnetId(networkContainment));
222             L2FloodDomainId l2fdId = new L2FloodDomainId(s.getParent().getValue());
223             L2BridgeDomain bd = tenant.resolveL2BridgeDomain(l2fdId);
224             L2FloodDomain fd = tenant.resolveL2FloodDomain(l2fdId);
225             L3Context l3c = tenant.resolveL3Context(l2fdId);
226
227
228             // Set ordinal id's for use in flows for each forwarding context
229             // component
230
231             this.epgId = getContextOrdinal(ep);
232
233             // TODO: alagalah Li/Be: This idea can be extended to include conditions.
234             this.tunnelId = getContextOrdinal(ep, networkContainment);
235             if (bd != null)
236                 this.bdId = getContextOrdinal(ep.getTenant(), bd.getId());
237             if (fd != null)
238                 this.fdId = getContextOrdinal(ep.getTenant(), fd.getId());
239             if (l3c != null)
240                 this.l3Id = getContextOrdinal(ep.getTenant(), l3c.getId());
241
242         }
243
244         public int getTunnelId() {
245             return tunnelId;
246         }
247
248         public int getEpgId() {
249             return this.epgId;
250         }
251
252         public NetworkDomainId getNetworkContainment() {
253             return this.networkContainment;
254         }
255
256         public EpKey getEp() {
257             return this.ep;
258         }
259
260         public int getBdId() {
261             return this.bdId;
262         }
263
264         public int getFdId() {
265             return this.fdId;
266         }
267
268         public int getL3Id() {
269             return this.l3Id;
270         }
271
272         public int getCgId() {
273             return this.cgId;
274         }
275     }
276
277     @VisibleForTesting
278     // Used only for unit testing
279     public static void resetPolicyOrdinalValue() {
280         policyOrdinal.set(1);
281     }
282 }