Adding multiple EPG capability to EPs and IntraEPG policy
[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 org.opendaylight.groupbasedpolicy.endpoint.EpKey;
18 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
19 import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
20 import org.opendaylight.groupbasedpolicy.resolver.EgKey;
21 import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
22 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ConditionName;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 public class OrdinalFactory {
38
39     private final static Logger LOG = LoggerFactory.getLogger(OrdinalFactory.class);
40
41     /**
42      * Counter used to allocate ordinal values for forwarding contexts and VNIDs
43      */
44     private final static AtomicInteger policyOrdinal = new AtomicInteger(1);
45
46     private final static ConcurrentMap<String, Integer> ordinals =
47             new ConcurrentHashMap<>();
48     // XXX - need to garbage collect
49     private final static ConcurrentMap<ConditionGroup, Integer> cgOrdinals =
50             new ConcurrentHashMap<>();
51
52     public static int getContextOrdinal(final TenantId tenantId,
53             final UniqueId id) throws Exception {
54         if (tenantId == null || id == null)
55             return 0;
56         return getContextOrdinalFromString(tenantId.getValue() + "|" + id.getValue());
57     }
58
59     /**
60      * Get a unique ordinal for the given condition group, suitable for use in
61      * the data plane. This is unique only for this node, and not globally.
62      *
63      * @param cg
64      *            the {@link ConditionGroup}
65      * @return the unique ID
66      */
67     public static int getCondGroupOrdinal(final ConditionGroup cg) {
68         if (cg == null)
69             return 0;
70         Integer ord = cgOrdinals.get(cg);
71         if (ord == null) {
72             ord = policyOrdinal.getAndIncrement();
73             Integer old = cgOrdinals.putIfAbsent(cg, ord);
74             if (old != null)
75                 ord = old;
76         }
77         return ord.intValue();
78     }
79
80     /**
81      * Get a 32-bit context ordinal suitable for use in the OF data plane for
82      * the given policy item.
83      *
84      * @param tenantId
85      *            the tenant ID of the element
86      * @param id
87      *            the unique ID for the element
88      * @return the 32-bit ordinal value
89      * @throws Exception
90      */
91
92     public static int getContextOrdinal(NodeId destNode) throws Exception {
93         return getContextOrdinalFromString(destNode.getValue());
94     }
95
96     public static int getContextOrdinal(Endpoint ep, NetworkDomainId networkContainment) throws Exception {
97         // TODO: Define private static final Comparator<EndpointGroupId>
98         // COMPARATOR = new Comparator<EndpointGroupId>() { ... }
99         // pass to constructor: new TreeSet<>(COMPARATOR);
100
101         Set<String> epgs = new TreeSet<>();
102
103         // Get EPGs and add to ordered Set
104         if (ep.getEndpointGroup() != null) {
105             epgs.add(ep.getEndpointGroup().getValue());
106         }
107         if (ep.getEndpointGroups() != null) {
108             for (EndpointGroupId epgId : ep.getEndpointGroups()) {
109                 epgs.add(epgId.getValue());
110             }
111         }
112
113         StringBuilder key = new StringBuilder(ep.getTenant().getValue());
114
115         for (String epg : epgs) {
116             key.append('|');
117             key.append(epg);
118         }
119
120         key.append("|")
121                 .append(networkContainment);
122
123         return getContextOrdinalFromString(key.toString());
124
125     }
126
127     /**
128      * Get a 32-bit context ordinal suitable for use in the OF data plane for
129      * the given policy item.
130      *
131      * @param id
132      *            the unique ID for the element
133      * @return the 32-bit ordinal value
134      */
135     private static int getContextOrdinalFromString(final String id) throws Exception {
136
137         Integer ord = ordinals.get(id);
138         if (ord == null) {
139             ord = policyOrdinal.getAndIncrement();
140             Integer old = ordinals.putIfAbsent(id, ord);
141             if (old != null)
142                 ord = old;
143         }
144         return ord.intValue();
145     }
146
147     public static final EndpointFwdCtxOrdinals getEndpointFwdCtxOrdinals(OfContext ctx, PolicyInfo policyInfo,
148             Endpoint ep) throws Exception {
149         return new EndpointFwdCtxOrdinals(ep, policyInfo, ctx);
150     }
151
152     // TODO alagalah Li: Move to either OrdinalFactory or EndpointManager
153     public static class EndpointFwdCtxOrdinals {
154
155         private NetworkDomainId networkContainment;
156         private EpKey ep;
157         private int epgId = 0, bdId = 0, fdId = 0, l3Id = 0, cgId = 0;
158
159         private EndpointFwdCtxOrdinals(Endpoint ep, PolicyInfo policyInfo, OfContext ctx) throws Exception {
160             this.ep = new EpKey(ep.getL2Context(), ep.getMacAddress());
161
162             IndexedTenant tenant = ctx.getPolicyResolver().getTenant(ep.getTenant());
163             // Set network containment either from ep, or from primary EPG
164             if (ep.getNetworkContainment() != null) {
165                 this.networkContainment = ep.getNetworkContainment();
166             } else {
167                 EndpointGroup epg = tenant.getEndpointGroup(ep.getEndpointGroup());
168                 if (epg.getNetworkDomain() != null) {
169                     this.networkContainment = epg.getNetworkDomain();
170                 } else {
171                     LOG.info(
172                             "endPoint ordinals for {} not processed in SourceMapper. Must be able to resolve network containment either directly, or from primary EPG",
173                             ep.getKey());
174                     return;
175                 }
176             }
177
178             // TODO: alagalah: I have a draft to address structure of mEPG
179             // conditions, but
180             // out of scope until broader bugs with conditions are fixed.
181             List<ConditionName> conds = ctx.getEndpointManager().getCondsForEndpoint(ep);
182             ConditionGroup cg =
183                     policyInfo.getEgCondGroup(new EgKey(ep.getTenant(), ep.getEndpointGroup()), conds);
184             this.cgId = getCondGroupOrdinal(cg);
185
186             // Based on network containment, determine components of
187             // forwarding context
188             L3Context l3c = tenant.resolveL3Context(networkContainment);
189             L2BridgeDomain bd = tenant.resolveL2BridgeDomain(networkContainment);
190             L2FloodDomain fd = tenant.resolveL2FloodDomain(networkContainment);
191
192             // Set ordinal id's for use in flows for each forwarding context
193             // component
194
195             this.epgId = getContextOrdinal(ep, networkContainment);
196             if (bd != null)
197                 this.bdId = getContextOrdinal(ep.getTenant(),
198                         bd.getId());
199             if (fd != null)
200                 this.fdId = getContextOrdinal(ep.getTenant(),
201                         fd.getId());
202             if (l3c != null)
203                 this.l3Id = getContextOrdinal(ep.getTenant(),
204                         l3c.getId());
205
206         }
207
208         public int getEpgId() {
209             return this.epgId;
210         }
211
212         public NetworkDomainId getNetworkContainment() {
213             return this.networkContainment;
214         }
215
216         public EpKey getEp() {
217             return this.ep;
218         }
219
220         public int getBdId() {
221             return this.bdId;
222         }
223
224         public int getFdId() {
225             return this.fdId;
226         }
227
228         public int getL3Id() {
229             return this.l3Id;
230         }
231
232         public int getCgId() {
233             return this.cgId;
234         }
235     }
236 }