1 package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping;
3 import static com.google.common.base.Preconditions.checkNotNull;
7 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
8 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
9 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
10 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
11 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
12 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.DataStoreHelper;
13 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.IidFactory;
14 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
15 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.NeutronUtils;
16 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.Utils;
17 import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils.ForwardingCtx;
18 import org.opendaylight.neutron.spi.INeutronPortCRUD;
19 import org.opendaylight.neutron.spi.INeutronRouterAware;
20 import org.opendaylight.neutron.spi.INeutronRouterCRUD;
21 import org.opendaylight.neutron.spi.INeutronSubnetCRUD;
22 import org.opendaylight.neutron.spi.NeutronCRUDInterfaces;
23 import org.opendaylight.neutron.spi.NeutronPort;
24 import org.opendaylight.neutron.spi.NeutronRouter;
25 import org.opendaylight.neutron.spi.NeutronRouter_Interface;
26 import org.opendaylight.neutron.spi.NeutronSecurityRule;
27 import org.opendaylight.neutron.spi.NeutronSubnet;
28 import org.opendaylight.neutron.spi.Neutron_IPs;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Description;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.EndpointGroupId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L2FloodDomainId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.L3ContextId;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.Name;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubnetId;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.EndpointService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.mapper.rev150223.mappings.network.mappings.NetworkMapping;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomainBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3ContextBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubnetBuilder;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 import com.google.common.base.Optional;
51 import com.google.common.collect.ImmutableList;
53 public class NeutronRouterAware implements INeutronRouterAware {
55 private static final Logger LOG = LoggerFactory.getLogger(NeutronRouterAware.class);
56 private final DataBroker dataProvider;
57 private final EndpointService epService;
59 public NeutronRouterAware(DataBroker dataProvider, EndpointService epService) {
60 this.dataProvider = checkNotNull(dataProvider);
61 this.epService = checkNotNull(epService);
65 public int canCreateRouter(NeutronRouter router) {
66 LOG.trace("canCreateRouter - {}", router);
67 INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
68 if (routerInterface == null) {
69 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
70 return StatusCode.INTERNAL_SERVER_ERROR;
73 List<NeutronRouter> allRouters = routerInterface.getAllRouters();
74 if (allRouters != null && !allRouters.isEmpty()) {
75 LOG.warn("Illegal state - Neutron mapper does not support multiple routers yet.");
76 return StatusCode.FORBIDDEN;
82 public void neutronRouterCreated(NeutronRouter router) {
83 LOG.trace("neutronRouterCreated - {}", router);
84 // TODO Li msunal external gateway
88 public int canUpdateRouter(NeutronRouter delta, NeutronRouter original) {
89 LOG.trace("canUpdateRouter - delta: {} original: {}", delta, original);
90 // TODO Li msunal external gateway
95 public void neutronRouterUpdated(NeutronRouter router) {
96 LOG.trace("neutronRouterUpdated - {}", router);
97 // TODO Li msunal external gateway
101 public int canDeleteRouter(NeutronRouter router) {
102 LOG.trace("canDeleteRouter - {}", router);
103 // nothing to consider
104 return StatusCode.OK;
108 public void neutronRouterDeleted(NeutronRouter router) {
109 LOG.trace("neutronRouterDeleted - {}", router);
110 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
111 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
112 Optional<EndpointGroup> potentialEpg = DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
113 IidFactory.endpointGroupIid(tenantId, MappingUtils.EPG_ROUTER_ID), rwTx);
114 if (!potentialEpg.isPresent()) {
115 LOG.warn("Illegal state - Endpoint group {} does not exist.", MappingUtils.EPG_ROUTER_ID.getValue());
119 DataStoreHelper.submitToDs(rwTx);
123 public int canAttachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
124 LOG.trace("canAttachInterface - router: {} interface: {}", router, routerInterface);
125 try (ReadOnlyTransaction rTx = dataProvider.newReadOnlyTransaction()) {
126 L3ContextId l3ContextId = new L3ContextId(router.getID());
127 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
128 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
129 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
130 IidFactory.subnetIid(tenantId, subnetId), rTx);
131 if (!potentialSubnet.isPresent()) {
132 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
133 return StatusCode.NOT_FOUND;
135 Subnet subnet = potentialSubnet.get();
136 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
137 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rTx);
138 if (fwCtx.getL3Context() != null && fwCtx.getL3Context().equals(l3ContextId)) {
140 LOG.warn("Illegal state - Neutron mapper does not support multiple router interfaces in the same subnet yet.");
141 return StatusCode.FORBIDDEN;
143 return StatusCode.OK;
148 public void neutronRouterInterfaceAttached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
149 LOG.trace("neutronRouterInterfaceAttached - router: {} interface: {}", router, routerInterface);
150 INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
151 if (portInterface == null) {
152 LOG.warn("Illegal state - No provider for {}", INeutronPortCRUD.class.getName());
156 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
157 if (subnetInterface == null) {
158 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
162 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
163 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
164 L3ContextId l3ContextId = new L3ContextId(router.getID());
165 InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
166 Optional<L3Context> potentialL3Context = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
168 // add L3 context if missing
169 if (!potentialL3Context.isPresent()) {
170 Name l3ContextName = null;
171 if (router.getName() != null) {
172 l3ContextName = new Name(router.getName());
174 L3Context l3Context = new L3ContextBuilder().setId(l3ContextId)
175 .setName(l3ContextName)
176 .setDescription(new Description(MappingUtils.NEUTRON_ROUTER__ + router.getID()))
178 rwTx.put(LogicalDatastoreType.CONFIGURATION, l3ContextIid, l3Context);
181 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
182 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
183 IidFactory.subnetIid(tenantId, subnetId), rwTx);
184 if (!potentialSubnet.isPresent()) {
185 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
190 // Based on Neutron Northbound - Port representing router interface contains exactly on
192 NeutronPort routerPort = portInterface.getPort(routerInterface.getPortUUID());
193 Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(
194 Utils.createIpAddress(routerPort.getFixedIPs().get(0).getIpAddress())).build();
195 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
196 if (subnet.getParent() == null) {
197 LOG.warn("Illegal state - subnet {} does not have a parent.", subnetId.getValue());
202 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
203 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
204 if (fwCtx.getL2BridgeDomain() == null) {
205 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
210 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(l3ContextId)
212 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
215 // create security rules for router
216 List<NeutronSecurityRule> routerSecRules = createRouterSecRules(routerPort, null, rwTx);
217 if (routerSecRules == null) {
221 for (NeutronSecurityRule routerSecRule : routerSecRules) {
222 boolean isRouterSecRuleAdded = NeutronSecurityRuleAware.addNeutronSecurityRule(routerSecRule, rwTx);
223 if (!isRouterSecRuleAdded) {
229 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
230 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
231 for (NeutronPort port : portsInNeutronSubnet) {
232 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);
239 DataStoreHelper.submitToDs(rwTx);
242 public static List<NeutronSecurityRule> createRouterSecRules(NeutronPort port, EndpointGroupId consumerEpgId,
243 ReadTransaction rTx) {
244 TenantId tenantId = new TenantId(Utils.normalizeUuid(port.getTenantID()));
245 Neutron_IPs firstIp = getFirstIp(port.getFixedIPs());
246 if (firstIp == null) {
247 LOG.warn("Illegal state - Router port does not have an IP address.");
250 SubnetId routerSubnetId = new SubnetId(firstIp.getSubnetUUID());
251 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
252 IidFactory.subnetIid(tenantId, routerSubnetId), rTx);
253 if (!potentialSubnet.isPresent()) {
254 LOG.warn("Illegal state - Subnet {} where is router port does not exist.", routerSubnetId.getValue());
257 IpPrefix ipSubnet = potentialSubnet.get().getIpPrefix();
258 NeutronSecurityRule routerRuleEgress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
260 NeutronSecurityRule routerRuleIngress = createRouterSecRule(port.getID(), tenantId, ipSubnet, consumerEpgId,
262 return ImmutableList.of(routerRuleEgress, routerRuleIngress);
265 private static Neutron_IPs getFirstIp(List<Neutron_IPs> fixedIPs) {
266 if (fixedIPs == null || fixedIPs.isEmpty()) {
269 Neutron_IPs neutron_Ip = fixedIPs.get(0);
270 if (fixedIPs.size() > 1) {
271 LOG.warn("Neutron mapper does not support multiple IPs on the same port. Only first IP is selected {}",
277 private static NeutronSecurityRule createRouterSecRule(String ruleUuid, TenantId tenantId, IpPrefix ipSubnet,
278 EndpointGroupId consumerEpgId, boolean isEgress) {
279 NeutronSecurityRule dhcpSecRule = new NeutronSecurityRule();
280 dhcpSecRule.setSecurityRuleGroupID(MappingUtils.EPG_ROUTER_ID.getValue());
281 dhcpSecRule.setSecurityRuleTenantID(tenantId.getValue());
282 dhcpSecRule.setSecurityRuleRemoteIpPrefix(Utils.getStringIpPrefix(ipSubnet));
284 dhcpSecRule.setSecurityRuleUUID(NeutronUtils.EGRESS + "__" + ruleUuid);
285 dhcpSecRule.setSecurityRuleDirection(NeutronUtils.EGRESS);
287 dhcpSecRule.setSecurityRuleUUID(NeutronUtils.INGRESS + "__" + ruleUuid);
288 dhcpSecRule.setSecurityRuleDirection(NeutronUtils.INGRESS);
290 if (ipSubnet.getIpv4Prefix() != null) {
291 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv4);
293 dhcpSecRule.setSecurityRuleEthertype(NeutronUtils.IPv6);
299 public int canDetachInterface(NeutronRouter router, NeutronRouter_Interface routerInterface) {
300 LOG.trace("canDetachInterface - router: {} interface: {}", router, routerInterface);
301 // nothing to consider
302 return StatusCode.OK;
306 public void neutronRouterInterfaceDetached(NeutronRouter router, NeutronRouter_Interface routerInterface) {
307 LOG.trace("neutronRouterInterfaceDetached - router: {} interface: {}", router, routerInterface);
308 INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
309 if (subnetInterface == null) {
310 LOG.warn("Illegal state - No provider for {}", INeutronSubnetCRUD.class.getName());
314 ReadWriteTransaction rwTx = dataProvider.newReadWriteTransaction();
315 TenantId tenantId = new TenantId(Utils.normalizeUuid(router.getTenantID()));
316 L3ContextId l3ContextId = new L3ContextId(router.getID());
317 SubnetId subnetId = new SubnetId(routerInterface.getSubnetUUID());
318 InstanceIdentifier<L3Context> l3ContextIid = IidFactory.l3ContextIid(tenantId, l3ContextId);
319 DataStoreHelper.removeIfExists(LogicalDatastoreType.CONFIGURATION,
320 IidFactory.l3ContextIid(tenantId, l3ContextId), rwTx);
322 Optional<Subnet> potentialSubnet = DataStoreHelper.readFromDs(LogicalDatastoreType.CONFIGURATION,
323 IidFactory.subnetIid(tenantId, subnetId), rwTx);
324 if (!potentialSubnet.isPresent()) {
325 LOG.warn("Illegal state - subnet {} does not exist.", subnetId.getValue());
330 Subnet subnet = new SubnetBuilder(potentialSubnet.get()).setVirtualRouterIp(null).build();
331 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.subnetIid(tenantId, subnetId), subnet);
333 L2FloodDomainId l2FdId = new L2FloodDomainId(subnet.getParent().getValue());
334 ForwardingCtx fwCtx = MappingUtils.createForwardingContext(tenantId, l2FdId, rwTx);
335 if (fwCtx.getL2BridgeDomain() == null) {
336 LOG.warn("Illegal state - l2-flood-domain {} does not have a parent.", l2FdId.getValue());
341 Optional<NetworkMapping> potentialNetworkMapping = DataStoreHelper.readFromDs(LogicalDatastoreType.OPERATIONAL,
342 IidFactory.networkMappingIid(l2FdId), rwTx);
343 if (!potentialNetworkMapping.isPresent()) {
344 LOG.warn("Illegal state - network-mapping {} does not exist.", l2FdId.getValue());
349 L2BridgeDomain l2BridgeDomain = new L2BridgeDomainBuilder(fwCtx.getL2BridgeDomain()).setParent(
350 potentialNetworkMapping.get().getL3ContextId()).build();
351 rwTx.put(LogicalDatastoreType.CONFIGURATION, IidFactory.l2BridgeDomainIid(tenantId, l2BridgeDomain.getId()),
354 NeutronSubnet neutronSubnet = subnetInterface.getSubnet(subnetId.getValue());
355 List<NeutronPort> portsInNeutronSubnet = neutronSubnet.getPortsInSubnet();
356 for (NeutronPort port : portsInNeutronSubnet) {
357 boolean isPortAdded = NeutronPortAware.addNeutronPort(port, rwTx, epService);