2 * Copyright (c) 2015 Cisco 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
8 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
10 import static com.google.common.base.Preconditions.checkNotNull;
12 import java.util.ArrayList;
13 import java.util.List;
16 import javax.annotation.Nullable;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.groupbasedpolicy.domain_extension.l2_l3.util.L2L3IidFactory;
23 import org.opendaylight.groupbasedpolicy.neutron.gbp.util.NeutronGbpIidFactory;
24 import org.opendaylight.groupbasedpolicy.neutron.mapper.EndpointRegistrator;
25 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkClient;
26 import org.opendaylight.groupbasedpolicy.neutron.mapper.infrastructure.NetworkService;
27 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
28 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.PortUtils;
29 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.SubnetUtils;
30 import org.opendaylight.groupbasedpolicy.util.DataStoreHelper;
31 import org.opendaylight.groupbasedpolicy.util.IidFactory;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.RegisterEndpointInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInputBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.NetworkContainmentBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.common.endpoint.fields.network.containment.containment.NetworkDomainContainmentBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.endpoints.address.endpoints.AddressEndpointKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpoint;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.has.child.endpoints.ChildEndpointBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.ParentEndpointCaseBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpoint;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.parent.child.endpoints.parent.endpoint.choice.parent.endpoint._case.ParentEndpointBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointReg;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.register.endpoint.input.AddressEndpointRegBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.AddressEndpointUnreg;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.unregister.endpoint.input.AddressEndpointUnregBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContextId;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2BridgeDomainId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.NetworkDomainId;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3AddressBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L2Builder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Builder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.IpPrefixType;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.L3Context;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.l2_l3.rev160427.MacAddressType;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.ForwardingContext;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.ForwardingContextBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.forwarding.rev160427.forwarding.forwarding.by.tenant.NetworkDomain;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.base.endpoints.by.ports.BaseEndpointByPort;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.gbp.by.neutron.mappings.endpoints.by.ports.EndpointByPort;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.base.endpoints.PortByBaseEndpoint;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.base.endpoints.PortByBaseEndpointKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.mappings.neutron.by.gbp.mappings.ports.by.endpoints.PortByEndpoint;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomain;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2BridgeDomainBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
83 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
84 import org.slf4j.Logger;
85 import org.slf4j.LoggerFactory;
87 import com.google.common.base.Optional;
88 import com.google.common.collect.ImmutableList;
90 public class NeutronPortAware implements NeutronAware<Port> {
92 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortAware.class);
93 public static final InstanceIdentifier<Port> PORT_WILDCARD_IID =
94 InstanceIdentifier.builder(Neutron.class).child(Ports.class).child(Port.class).build();
95 private final DataBroker dataProvider;
96 private final EndpointRegistrator epRegistrator;
98 public NeutronPortAware(DataBroker dataProvider, EndpointRegistrator epRegistrator) {
99 this.dataProvider = checkNotNull(dataProvider);
100 this.epRegistrator = checkNotNull(epRegistrator);
104 public void onCreated(Port port, Neutron neutron) {
105 LOG.trace("created port - {}", port);
106 if (PortUtils.isRouterInterfacePort(port)) {
107 LOG.trace("Port is router interface port: {}", port.getUuid().getValue());
108 // router interface port can have only one IP
109 Optional<FixedIps> potentialPortIpWithSubnet = PortUtils.resolveFirstFixedIps(port);
110 if (!potentialPortIpWithSubnet.isPresent()) {
111 LOG.warn("Illegal state - router interface port does not contain fixed IPs {}",
115 FixedIps portIpWithSubnet = potentialPortIpWithSubnet.get();
116 ContextId routerL3Context = new ContextId(port.getDeviceId());
117 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
119 AddressEndpointKey addrEpKey = new AddressEndpointKey(port.getMacAddress().getValue(),
120 MacAddressType.class, new ContextId(port.getNetworkId().getValue()), MappingUtils.L2_BRDIGE_DOMAIN);
121 UniqueId portId = new UniqueId(port.getUuid().getValue());
122 addBaseEndpointMappings(addrEpKey, portId, rwTx);
124 // Add Qrouter port as Endpoint
125 if (port.getAugmentation(PortBindingExtension.class) != null &&
126 PortUtils.DEVICE_VIF_TYPE.equals(port.getAugmentation(PortBindingExtension.class).getVifType())) {
127 LOG.trace("Port is QRouter port: {}", port.getUuid().getValue());
128 Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
129 if (!firstFixedIps.isPresent()) {
130 LOG.warn("QRouter port does not have an IP address. {}", port);
134 FixedIps ipWithSubnet = firstFixedIps.get();
135 NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
136 List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
137 epgsFromSecGroups.add(NetworkService.EPG_ID);
139 // BUILD BASE ENDPOINT
140 AddressEndpointRegBuilder l2BaseEp = createBasicMacAddrEpInputBuilder(port, networkContainment,
142 AddressEndpointRegBuilder l3BaseEp = createBasicL3AddrEpInputBuilder(port, networkContainment,
143 epgsFromSecGroups, neutron);
144 setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
147 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder
149 createEndpointRegFromPort(
150 port, ipWithSubnet, networkContainment, epgsFromSecGroups, neutron);
151 registerBaseEndpointAndStoreMapping(
152 ImmutableList.of(l2BaseEp.build(), l3BaseEp.build()), port, rwTx);
153 registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
156 // change L3Context for all EPs with same subnet as router port
157 changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), neutron);
158 // set L3Context as parent for bridge domain which is parent of subnet
159 TenantId tenantId = new TenantId(port.getTenantId().getValue());
160 Optional<Subnet> potentialRouterPortSubnet = SubnetUtils.findSubnet(portIpWithSubnet.getSubnetId(), neutron.getSubnets());
161 if (!potentialRouterPortSubnet.isPresent()) {
162 LOG.warn("Illegal state - router interface port is in subnet which does not exist. {}",
166 Subnet routerPortSubnet = potentialRouterPortSubnet.get();
167 ContextId l2BdId = new ContextId(routerPortSubnet.getNetworkId().getValue());
168 ForwardingContext l2Bd = new ForwardingContextBuilder().setContextId(l2BdId)
169 .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
170 .setParent(MappingUtils.createParent(routerL3Context, MappingUtils.L3_CONTEXT))
172 rwTx.merge(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd, true);
173 // set virtual router IP for subnet
174 NetworkDomain subnetDomain = NeutronSubnetAware.createSubnet(
175 routerPortSubnet, portIpWithSubnet.getIpAddress());
176 rwTx.merge(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.subnetIid(tenantId, subnetDomain.getNetworkDomainId()), subnetDomain);
178 // does the same for tenant forwarding domains
179 processTenantForwarding(routerPortSubnet, routerL3Context, portIpWithSubnet, tenantId, rwTx);
181 DataStoreHelper.submitToDs(rwTx);
182 } else if (PortUtils.isDhcpPort(port)) {
183 // process as normal port but put it to DHCP group
184 LOG.trace("Port is DHCP port: {}", port.getUuid().getValue());
185 Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
186 if (!firstFixedIps.isPresent()) {
187 LOG.warn("DHCP port does not have an IP address. {}", port);
190 FixedIps ipWithSubnet = firstFixedIps.get();
191 NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
192 List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
193 epgsFromSecGroups.add(NetworkService.EPG_ID);
195 // BUILD BASE ENDPOINT
196 AddressEndpointRegBuilder l2BaseEp = createBasicMacAddrEpInputBuilder(port, networkContainment,
198 AddressEndpointRegBuilder l3BaseEp = createBasicL3AddrEpInputBuilder(port, networkContainment,
199 epgsFromSecGroups, neutron);
200 setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
203 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = createEndpointRegFromPort(
204 port, ipWithSubnet, networkContainment, epgsFromSecGroups, neutron);
206 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
207 registerBaseEndpointAndStoreMapping(
208 ImmutableList.of(l2BaseEp.build(), l3BaseEp.build()), port, rwTx);
209 registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
210 DataStoreHelper.submitToDs(rwTx);
211 } else if (PortUtils.isNormalPort(port)) {
212 LOG.trace("Port is normal port: {}", port.getUuid().getValue());
213 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = null;
214 AddressEndpointRegBuilder l2BaseEp;
215 AddressEndpointRegBuilder l3BaseEp = null;
216 Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
217 List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
218 epgsFromSecGroups.add(NetworkClient.EPG_ID);
219 if (firstFixedIps.isPresent()) {
220 // endpoint has only one network containment therefore only first IP is used
221 FixedIps ipWithSubnet = firstFixedIps.get();
222 NetworkDomainId containment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
223 epInBuilder = createEndpointRegFromPort(port, ipWithSubnet, containment, epgsFromSecGroups, neutron);
224 l2BaseEp = createBasicMacAddrEpInputBuilder(port,
225 containment, epgsFromSecGroups);
226 l3BaseEp = createBasicL3AddrEpInputBuilder(port, containment, epgsFromSecGroups, neutron);
227 setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
229 NetworkDomainId containment = new NetworkDomainId(port.getNetworkId().getValue());
230 epInBuilder = createEndpointRegFromPort(port, null, containment, epgsFromSecGroups, neutron);
231 l2BaseEp = createBasicMacAddrEpInputBuilder(port, containment, epgsFromSecGroups);
233 List<AddressEndpointReg> baseEpRegs = new ArrayList<>();
234 baseEpRegs.add(l2BaseEp.build());
235 if (l3BaseEp != null) {
236 baseEpRegs.add(l3BaseEp.build());
238 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
239 registerBaseEndpointAndStoreMapping(baseEpRegs, port, rwTx);
240 registerEndpointAndStoreMapping(epInBuilder.build(), port, rwTx);
241 DataStoreHelper.submitToDs(rwTx);
242 } else if (PortUtils.isRouterGatewayPort(port)) {
243 // do nothing because actual trigger is attaching of port to router
244 LOG.trace("Port is router gateway port: {}", port.getUuid().getValue());
245 } else if (PortUtils.isFloatingIpPort(port)) {
246 // do nothing because trigger is floating IP
247 LOG.trace("Port is floating ip: {}", port.getUuid().getValue());
249 LOG.warn("Unknown port: {}", port);
253 private void setParentChildRelationshipForEndpoints(AddressEndpointRegBuilder parentEp,
254 AddressEndpointRegBuilder childEp) {
255 childEp.setParentEndpointChoice(new ParentEndpointCaseBuilder().setParentEndpoint(
256 ImmutableList.<ParentEndpoint>of(createParentEndpoint(parentEp))).build());
257 parentEp.setChildEndpoint(ImmutableList.<ChildEndpoint>of(createChildEndpoint(childEp)));
261 private void processTenantForwarding(Subnet routerPortSubnet, ContextId routerL3Context, FixedIps portIpWithSubnet,
262 TenantId tenantId, ReadWriteTransaction rwTx) {
263 L2BridgeDomainId l2BdId = new L2BridgeDomainId(routerPortSubnet.getNetworkId().getValue());
264 L2BridgeDomain l2Bd = new L2BridgeDomainBuilder().setId(l2BdId).setParent(new L3ContextId(routerL3Context)).build();
265 rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd, true);
266 // set virtual router IP for subnet
267 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet subnet = NeutronSubnetAware.createTenantSubnet(
268 routerPortSubnet, portIpWithSubnet.getIpAddress());
269 rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnet.getId()), subnet);
273 * Registers endpoint from {@link Port} and method parameters.
274 * Always creates registration input for L2 endpoint.
275 * Creates registration input for L3 endpoint if fixedIps argument is not null.
278 private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder createEndpointRegFromPort(
279 Port port, FixedIps fixedIps, NetworkDomainId networkContainment, List<EndpointGroupId> endpointGroupIds, Neutron neutron) {
280 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = createBasicEndpointInputBuilder(
281 port).setNetworkContainment(networkContainment);
282 if (fixedIps != null) {
283 L3Address l3Address = resolveL3AddressFromPort(port, fixedIps, neutron);
284 epInBuilder.setL3Address(ImmutableList.of(l3Address));
286 epInBuilder.setEndpointGroups(endpointGroupIds);
290 private void changeL3ContextForEpsInSubnet(Uuid subnetUuid, Neutron neutron) {
291 Set<Port> portsInSameSubnet = PortUtils.findPortsBySubnet(subnetUuid, neutron.getPorts());
292 for (Port portInSameSubnet : portsInSameSubnet) {
293 if (PortUtils.isNormalPort(portInSameSubnet) || PortUtils.isDhcpPort(portInSameSubnet)
294 || PortUtils.isQrouterPort(portInSameSubnet)) {
295 // endpoints are created only from neutron normal port or DHCP port
296 Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(portInSameSubnet);
297 if (firstFixedIps.isPresent()) {
298 // endpoint has only one network containment therefore only first IP is used
299 FixedIps ipWithSubnet = firstFixedIps.get();
300 List<EndpointGroupId> endpointGroupIds = new ArrayList<>();
301 if (PortUtils.isDhcpPort(portInSameSubnet) || PortUtils.isQrouterPort(portInSameSubnet)) {
302 endpointGroupIds.add(NetworkService.EPG_ID);
303 } else if (PortUtils.isNormalPort(portInSameSubnet)) {
304 endpointGroupIds.add(NetworkClient.EPG_ID);
306 NetworkDomainId networkContainment = new NetworkDomainId(ipWithSubnet.getSubnetId().getValue());
307 AddressEndpointRegBuilder l2BaseEp = createBasicMacAddrEpInputBuilder(portInSameSubnet,
308 networkContainment, endpointGroupIds);
309 AddressEndpointRegBuilder l3BaseEp = createBasicL3AddrEpInputBuilder(portInSameSubnet,
310 networkContainment, endpointGroupIds, neutron);
311 setParentChildRelationshipForEndpoints(l3BaseEp, l2BaseEp);
312 AddressEndpointUnreg addrEpUnreg = new AddressEndpointUnregBuilder().setAddress(l3BaseEp.getAddress())
313 .setAddressType(l3BaseEp.getAddressType())
314 .setContextId(new ContextId(portInSameSubnet.getNetworkId().getValue()))
315 .setContextType(l3BaseEp.getContextType())
317 epRegistrator.unregisterEndpoint(addrEpUnreg);
318 RegisterEndpointInput regBaseEpInput = new RegisterEndpointInputBuilder()
319 .setAddressEndpointReg(ImmutableList.of(l2BaseEp.build(), l3BaseEp.build())).build();
320 epRegistrator.registerEndpoint(regBaseEpInput);
322 modifyL3ContextForEndpoints(portInSameSubnet, ipWithSubnet, l3BaseEp.getContextId());
328 private ChildEndpoint createChildEndpoint(AddressEndpointRegBuilder builder) {
329 return new ChildEndpointBuilder().setAddress(builder.getAddress())
330 .setAddressType(builder.getAddressType())
331 .setContextId(builder.getContextId())
332 .setContextType(builder.getContextType())
336 private ParentEndpoint createParentEndpoint(AddressEndpointRegBuilder builder) {
337 return new ParentEndpointBuilder().setAddress(builder.getAddress())
338 .setAddressType(builder.getAddressType())
339 .setContextId(builder.getContextId())
340 .setContextType(builder.getContextType())
345 private void modifyL3ContextForEndpoints(Port port, FixedIps resolvedPortFixedIp, ContextId newContextId) {
346 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder epInBuilder = createBasicEndpointInputBuilder(port);
347 epInBuilder.setNetworkContainment(new NetworkDomainId(resolvedPortFixedIp.getSubnetId().getValue()));
348 L3Address l3Address = new L3AddressBuilder().setL3Context(new L3ContextId(newContextId))
349 .setIpAddress(resolvedPortFixedIp.getIpAddress())
351 epInBuilder.setL3Address(ImmutableList.of(l3Address));
352 List<EndpointGroupId> epgsFromSecGroups = resolveEpgIdsFromSecGroups(port.getSecurityGroups());
353 epgsFromSecGroups.add(NetworkClient.EPG_ID);
354 epInBuilder.setEndpointGroups(epgsFromSecGroups);
355 epRegistrator.registerEndpoint(epInBuilder.build());
357 L3ContextId oldL3Context = new L3ContextId(port.getNetworkId().getValue());
358 L3 l3 = new L3Builder().setL3Context(oldL3Context).setIpAddress(resolvedPortFixedIp.getIpAddress()).build();
359 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput epUnreg = new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder().setL3(
360 ImmutableList.of(l3))
362 epRegistrator.unregisterEndpoint(epUnreg);
365 private AddressEndpointRegBuilder createBasicMacAddrEpInputBuilder(Port port,
366 NetworkDomainId networkContainment, @Nullable List<EndpointGroupId> endpointGroupsToAdd) {
367 AddressEndpointRegBuilder addrEpbuilder = new AddressEndpointRegBuilder().setAddressType(MacAddressType.class)
368 .setAddress(port.getMacAddress().getValue())
369 .setAddressType(MacAddressType.class)
370 .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
371 .setContextId(new ContextId(port.getNetworkId().getValue()))
372 .setTenant(new TenantId(port.getTenantId().getValue()))
373 .setTimestamp(System.currentTimeMillis());
374 List<EndpointGroupId> epgs = concatEndpointGroups(port.getSecurityGroups(), endpointGroupsToAdd);
375 addrEpbuilder.setEndpointGroup(epgs);
376 if (networkContainment != null) {
377 addrEpbuilder.setNetworkContainment(new NetworkContainmentBuilder().setContainment(
378 new NetworkDomainContainmentBuilder().setNetworkDomainId(networkContainment)
379 .setNetworkDomainType(MappingUtils.SUBNET)
382 return addrEpbuilder;
385 private AddressEndpointRegBuilder createBasicL3AddrEpInputBuilder(Port port, NetworkDomainId networkContainment,
386 @Nullable List<EndpointGroupId> endpointGroupsToAdd, Neutron neutron) {
387 Optional<FixedIps> firstFixedIps = PortUtils.resolveFirstFixedIps(port);
388 if (!firstFixedIps.isPresent()) {
389 throw new IllegalStateException("Failed to resolve FixedIps for port " + port.getKey()
390 + ". Cannot register L3 Address endpoint.");
392 ContextId resolveL3ContextForPort = resolveL3ContextForPort(port, port.getFixedIps().get(0), neutron);
394 AddressEndpointRegBuilder addrEpbuilder = new AddressEndpointRegBuilder().setAddressType(MacAddressType.class)
395 .setAddress(MappingUtils.ipAddressToStringIpPrefix(firstFixedIps.get().getIpAddress()))
396 .setAddressType(IpPrefixType.class)
397 .setContextType(MappingUtils.L3_CONTEXT)
398 .setContextId(resolveL3ContextForPort)
399 .setTenant(new TenantId(port.getTenantId().getValue()))
400 .setTimestamp(System.currentTimeMillis());
401 List<EndpointGroupId> epgs = concatEndpointGroups(port.getSecurityGroups(), endpointGroupsToAdd);
402 addrEpbuilder.setEndpointGroup(epgs);
403 if (networkContainment != null) {
404 addrEpbuilder.setNetworkContainment(new NetworkContainmentBuilder().setContainment(
405 new NetworkDomainContainmentBuilder().setNetworkDomainId(networkContainment)
406 .setNetworkDomainType(MappingUtils.SUBNET)
409 return addrEpbuilder;
412 private List<EndpointGroupId> concatEndpointGroups(List<Uuid> securityGroups,
413 @Nullable List<EndpointGroupId> endpointGroupsToAdd) {
414 List<EndpointGroupId> epgs = new ArrayList<>();
415 if (securityGroups != null) {
416 for (Uuid sgId : securityGroups) {
417 epgs.add(new EndpointGroupId(sgId.getValue()));
420 if (endpointGroupsToAdd != null) {
421 epgs.addAll(endpointGroupsToAdd);
427 private static org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder createBasicEndpointInputBuilder(
429 return new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInputBuilder().setL2Context(
430 new L2BridgeDomainId(port.getNetworkId().getValue()))
431 .setMacAddress(new MacAddress(port.getMacAddress().getValue()))
432 .setTenant(new TenantId(port.getTenantId().getValue()))
433 .setTimestamp(System.currentTimeMillis());
436 private static List<EndpointGroupId> resolveEpgIdsFromSecGroups(@Nullable List<Uuid> securityGroups) {
437 List<EndpointGroupId> epgIds = new ArrayList<>();
438 if ((securityGroups == null || securityGroups.isEmpty())) {
441 for (Uuid secGrp : securityGroups) {
442 epgIds.add(new EndpointGroupId(secGrp.getValue()));
448 private void registerEndpointAndStoreMapping(
449 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.RegisterEndpointInput regEpInput,
450 Port port, ReadWriteTransaction rwTx) {
451 boolean isRegisteredEndpoint = epRegistrator.registerEndpoint(regEpInput);
452 if (!isRegisteredEndpoint) {
453 LOG.error("Failed to register an endpoint: {}", regEpInput);
456 UniqueId portId = new UniqueId(port.getUuid().getValue());
457 EndpointKey epKey = new EndpointKey(new L2BridgeDomainId(port.getNetworkId().getValue()), new MacAddress(
458 port.getMacAddress().getValue()));
459 LOG.trace("Adding Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getUuid()
460 .getValue(), port.getDeviceOwner(), epKey);
461 EndpointByPort endpointByPort = MappingFactory.createEndpointByPort(epKey, portId);
462 rwTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.endpointByPortIid(portId), endpointByPort, true);
463 PortByEndpoint portByEndpoint = MappingFactory.createPortByEndpoint(portId, epKey);
464 rwTx.put(LogicalDatastoreType.OPERATIONAL,
465 NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), portByEndpoint,
470 private void unregisterEndpointAndRemoveMapping(
471 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput unregEpInput,
472 Port port, ReadWriteTransaction rwTx) {
473 boolean isUnregisteredEndpoint = epRegistrator.unregisterEndpoint(unregEpInput);
474 if (isUnregisteredEndpoint) {
475 UniqueId portId = new UniqueId(port.getUuid().getValue());
476 EndpointKey epKey = new EndpointKey(new L2BridgeDomainId(port.getNetworkId().getValue()), new MacAddress(
477 port.getMacAddress().getValue()));
478 LOG.trace("Removing Port-Endpoint mapping for port {} (device owner {}) and endpoint {}", port.getUuid()
479 .getValue(), port.getDeviceOwner(), epKey);
480 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
481 NeutronGbpIidFactory.endpointByPortIid(portId), rwTx);
482 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
483 NeutronGbpIidFactory.portByEndpointIid(epKey.getL2Context(), epKey.getMacAddress()), rwTx);
487 private void registerBaseEndpointAndStoreMapping(List<AddressEndpointReg> addrEpRegs, Port port,
488 WriteTransaction wTx) {
489 RegisterEndpointInput regBaseEpInput = new RegisterEndpointInputBuilder().setAddressEndpointReg(addrEpRegs)
492 boolean isRegisteredBaseEndpoint = epRegistrator.registerEndpoint(regBaseEpInput);
493 if (!isRegisteredBaseEndpoint) {
494 LOG.error("Failed to register an address endpoint: {}", addrEpRegs);
497 for (AddressEndpointReg addrEpReg : addrEpRegs) {
498 if (MappingUtils.L2_BRDIGE_DOMAIN.equals(addrEpReg.getContextType())) {
499 UniqueId portId = new UniqueId(port.getUuid().getValue());
500 LOG.trace("Adding Port-BaseEndpoint mapping for port {} (device owner {}) and endpoint {}",
502 AddressEndpointKey addrEpKey = new AddressEndpointKey(addrEpReg.getAddress(),
503 addrEpReg.getAddressType(), addrEpReg.getContextId(), addrEpReg.getContextType());
504 addBaseEndpointMappings(addrEpKey, portId, wTx);
509 private void addBaseEndpointMappings(AddressEndpointKey addrEpKey, UniqueId portId, WriteTransaction wTx) {
510 BaseEndpointByPort baseEndpointByPort = MappingFactory.createBaseEndpointByPort(addrEpKey, portId);
511 wTx.put(LogicalDatastoreType.OPERATIONAL, NeutronGbpIidFactory.baseEndpointByPortIid(portId),
512 baseEndpointByPort, true);
513 PortByBaseEndpoint portByBaseEndpoint = MappingFactory.createPortByBaseEndpoint(portId, addrEpKey);
514 wTx.put(LogicalDatastoreType.OPERATIONAL,
515 NeutronGbpIidFactory.portByBaseEndpointIid(new PortByBaseEndpointKey(
516 portByBaseEndpoint.getKey())), portByBaseEndpoint, true);
519 private void unregisterEndpointAndRemoveMapping(UnregisterEndpointInput baseEpUnreg, Port port,
520 ReadWriteTransaction rwTx) {
521 boolean isUnregisteredBaseEndpoint = epRegistrator.unregisterEndpoint(baseEpUnreg);
522 if (isUnregisteredBaseEndpoint) {
523 UniqueId portId = new UniqueId(port.getUuid().getValue());
524 PortByBaseEndpointKey portByBaseEndpointKey = new PortByBaseEndpointKey(port.getMacAddress().getValue(),
525 MacAddressType.class, new ContextId(port.getNetworkId().getValue()), MappingUtils.L2_BRDIGE_DOMAIN);
526 LOG.trace("Removing Port-BaseEndpoint mapping for port {} (device owner {}) and endpoint {}",
527 port.getUuid().getValue(), port.getDeviceOwner(), portByBaseEndpointKey);
528 removeBaseEndpointMappings(portByBaseEndpointKey, portId, rwTx);
532 private void removeBaseEndpointMappings(PortByBaseEndpointKey portByBaseEndpointKey, UniqueId portId, ReadWriteTransaction rwTx) {
533 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
534 NeutronGbpIidFactory.baseEndpointByPortIid(portId), rwTx);
535 DataStoreHelper.removeIfExists(LogicalDatastoreType.OPERATIONAL,
536 NeutronGbpIidFactory.portByBaseEndpointIid(portByBaseEndpointKey), rwTx);
540 public void onUpdated(Port oldPort, Port newPort, Neutron oldNeutron, Neutron newNeutron) {
541 LOG.trace("updated port - OLD: {}\nNEW: {}", oldPort, newPort);
542 onDeleted(oldPort, oldNeutron, newNeutron);
543 onCreated(newPort, newNeutron);
547 public void onDeleted(Port port, Neutron oldNeutron, Neutron newNeutron) {
548 LOG.trace("deleted port - {}", port);
549 if (PortUtils.isRouterInterfacePort(port)) {
550 LOG.trace("Port is router interface port: {}", port.getUuid().getValue());
551 // router interface port can have only one IP
552 Optional<FixedIps> potentialPortIpWithSubnet = PortUtils.resolveFirstFixedIps(port);
553 if (!potentialPortIpWithSubnet.isPresent()) {
554 LOG.warn("Illegal state - router interface port does not contain fixed IPs {}",
558 FixedIps portIpWithSubnet = potentialPortIpWithSubnet.get();
559 L3ContextId l3Context = new L3ContextId(port.getNetworkId().getValue());
560 // change L3Context for all EPs with same subnet as router port
561 changeL3ContextForEpsInSubnet(portIpWithSubnet.getSubnetId(), oldNeutron);
562 // set L3Context as parent for bridge domain which is parent of subnet
563 TenantId tenantId = new TenantId(port.getTenantId().getValue());
564 Optional<Subnet> potentialRouterPortSubnet = SubnetUtils.findSubnet(portIpWithSubnet.getSubnetId(),
565 oldNeutron.getSubnets());
566 if (!potentialRouterPortSubnet.isPresent()) {
567 LOG.warn("Illegal state - router interface port is in subnet which does not exist. {}", port);
570 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
571 Subnet routerPortSubnet = potentialRouterPortSubnet.get();
572 modifyForwardingOnDelete(routerPortSubnet, l3Context, tenantId, rwTx);
573 ContextId l2BdId = new ContextId(routerPortSubnet.getNetworkId().getValue());
574 ForwardingContext fwdCtx = new ForwardingContextBuilder().setContextId(l2BdId)
575 .setContextType(MappingUtils.L2_BRDIGE_DOMAIN)
576 .setParent(MappingUtils.createParent(l3Context, MappingUtils.L3_CONTEXT))
578 rwTx.merge(LogicalDatastoreType.CONFIGURATION,
579 L2L3IidFactory.l2BridgeDomainIid(tenantId, fwdCtx.getContextId()), fwdCtx);
580 NetworkDomain subnet = NeutronSubnetAware.createSubnet(routerPortSubnet, null);
581 rwTx.put(LogicalDatastoreType.CONFIGURATION, L2L3IidFactory.subnetIid(tenantId, subnet.getNetworkDomainId()),
583 UniqueId portId = new UniqueId(port.getUuid().getValue());
584 PortByBaseEndpointKey portByBaseEndpointKey = new PortByBaseEndpointKey(port.getMacAddress().getValue(),
585 MacAddressType.class, new ContextId(port.getNetworkId().getValue()), MappingUtils.L2_BRDIGE_DOMAIN);
586 removeBaseEndpointMappings(portByBaseEndpointKey, portId, rwTx);
587 DataStoreHelper.submitToDs(rwTx);
588 } else if (PortUtils.isDhcpPort(port)) {
589 LOG.trace("Port is DHCP port: {}", port.getUuid().getValue());
590 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
591 unregisterEndpointAndRemoveMapping(createUnregisterEndpointInput(port, oldNeutron), port, rwTx);
592 unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx);
593 DataStoreHelper.submitToDs(rwTx);
594 } else if (PortUtils.isNormalPort(port)) {
595 LOG.trace("Port is normal port: {}", port.getUuid().getValue());
596 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
597 unregisterEndpointAndRemoveMapping(createUnregisterEndpointInput(port, oldNeutron), port, rwTx);
598 unregisterEndpointAndRemoveMapping(createUnregisterBaseEndpointInput(port, oldNeutron), port, rwTx);
599 DataStoreHelper.submitToDs(rwTx);
600 } else if (PortUtils.isRouterGatewayPort(port)) {
601 // do nothing because actual trigger is detaching of port from router
602 LOG.trace("Port is router gateway port: {}", port.getUuid().getValue());
603 } else if (PortUtils.isFloatingIpPort(port)) {
604 // do nothing because trigger is floating IP
605 LOG.trace("Port is floating ip: {}", port.getUuid().getValue());
607 LOG.warn("Unknown port: {}", port);
612 private void modifyForwardingOnDelete(Subnet routerPortSubnet, L3ContextId l3contextId, TenantId tenantId, ReadWriteTransaction rwTx) {
613 L2BridgeDomainId l2BdId = new L2BridgeDomainId(routerPortSubnet.getNetworkId().getValue());
614 L2BridgeDomain l2Bd = new L2BridgeDomainBuilder().setId(l2BdId).setParent(l3contextId).build();
615 rwTx.merge(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BdId), l2Bd);
616 // remove virtual router IP for subnet
617 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet tenantSubnet = NeutronSubnetAware.createTenantSubnet(routerPortSubnet, null);
618 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, tenantSubnet.getId()), tenantSubnet);
621 private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.base_endpoint.rev160427.UnregisterEndpointInput createUnregisterBaseEndpointInput(
622 Port port, Neutron neutron) {
623 UnregisterEndpointInputBuilder inputBuilder = new UnregisterEndpointInputBuilder();
624 List<AddressEndpointUnreg> list = new ArrayList<>();
625 AddressEndpointUnregBuilder addrL2EpUnregBuilder = new AddressEndpointUnregBuilder();
626 addrL2EpUnregBuilder.setAddress(port.getMacAddress().getValue())
627 .setAddressType(MacAddressType.class)
628 .setContextId(new ContextId(port.getNetworkId().getValue()))
629 .setContextType(MappingUtils.L2_BRDIGE_DOMAIN);
630 list.add(addrL2EpUnregBuilder.build());
631 Optional<FixedIps> potentialFirstIp = PortUtils.resolveFirstFixedIps(port);
632 if (potentialFirstIp.isPresent()) {
633 ContextId l3ContextId = resolveL3ContextForPort(port, potentialFirstIp.get(), neutron);
634 AddressEndpointUnregBuilder addrL3EpUnregBuilder = new AddressEndpointUnregBuilder();
635 addrL3EpUnregBuilder.setAddress(MappingUtils.ipAddressToStringIpPrefix(potentialFirstIp.get().getIpAddress()))
636 .setAddressType(IpPrefixType.class)
637 .setContextId(l3ContextId)
638 .setContextType(L3Context.class);
639 list.add(addrL3EpUnregBuilder.build());
641 inputBuilder.setAddressEndpointUnreg(list);
642 return inputBuilder.build();
646 private org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInput createUnregisterEndpointInput(
647 Port port, Neutron neutron) {
648 org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder inputBuilder =
649 new org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.UnregisterEndpointInputBuilder();
650 L2 l2Ep = new L2Builder().setL2Context(new L2BridgeDomainId(port.getNetworkId().getValue()))
651 .setMacAddress(new MacAddress(port.getMacAddress().getValue()))
653 inputBuilder.setL2(ImmutableList.of(l2Ep));
654 // we've registered EP with only first IP so remove only EP with first IP
655 Optional<FixedIps> potentialFirstIp = PortUtils.resolveFirstFixedIps(port);
656 if (potentialFirstIp.isPresent()) {
657 FixedIps firstIp = potentialFirstIp.get();
658 L3Address l3Address = resolveL3AddressFromPort(port, firstIp, neutron);
659 L3 l3 = new L3Builder().setIpAddress(l3Address.getIpAddress())
660 .setL3Context(l3Address.getL3Context())
662 inputBuilder.setL3(ImmutableList.of(l3));
664 return inputBuilder.build();
668 private static L3Address resolveL3AddressFromPort(Port port, FixedIps portFixedIPs, Neutron neutron) {
669 Set<Port> routerIfacePorts = PortUtils.findRouterInterfacePorts(neutron.getPorts());
670 for (Port routerIfacePort : routerIfacePorts) {
671 Uuid routerIfacePortSubnet = routerIfacePort.getFixedIps().get(0).getSubnetId();
672 // if port is in the same subnet as router interface then we want to use L3Context of
674 if (portFixedIPs.getSubnetId().equals(routerIfacePortSubnet)) {
675 L3ContextId epL3ContextId = new L3ContextId(routerIfacePort.getDeviceId());
676 LOG.trace("Router interface port was found in the same subnet as port have {}", port);
677 return new L3AddressBuilder().setL3Context(epL3ContextId)
678 .setIpAddress(portFixedIPs.getIpAddress())
682 return new L3AddressBuilder().setL3Context(new L3ContextId(port.getNetworkId().getValue()))
683 .setIpAddress(portFixedIPs.getIpAddress())
687 private static ContextId resolveL3ContextForPort(Port port, FixedIps portFixedIPs, Neutron neutron) {
688 Set<Port> routerIfacePorts = PortUtils.findRouterInterfacePorts(neutron.getPorts());
689 for (Port routerIfacePort : routerIfacePorts) {
690 Uuid routerIfacePortSubnet = routerIfacePort.getFixedIps().get(0).getSubnetId();
691 // if port is in the same subnet as router interface then we want to use L3Context of
693 if (portFixedIPs.getSubnetId().equals(routerIfacePortSubnet)) {
694 LOG.trace("Router interface port was found in the same subnet as port have {}", port);
695 return new ContextId(routerIfacePort.getDeviceId());
698 return new ContextId(port.getNetworkId().getValue());