/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.mapper.portsecurity; import com.google.common.annotations.VisibleForTesting; import org.opendaylight.groupbasedpolicy.dto.IndexedTenant; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowTable; import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain; import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collections; import java.util.List; import java.util.Set; /** *
* L2 flow:
* Priority = 100
* Matches:
* - in_port, {@link NodeConnectorId}
* - dl_src {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress}
* Actions:
* - {@link GoToTable} SOURCE MAPPER table
*
* L3 flow:
* Priority = 120
* Matches:
* - ip, (ethertype)
* - in_port, {@link NodeConnectorId}
* - dl_src {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress}
* - nw_src (source ip address)
* Actions:
* - {@link GoToTable} SOURCE MAPPER table
*
* L3 Arp flow:
* Priority = 121
* Matches:
* - arp, (ethertype)
* - in_port, {@link NodeConnectorId}
* - dl_src {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress}
* - arp_spa (arp source transport address)
* Actions:
* - {@link GoToTable} SOURCE MAPPER table
*
* L3 Dhcp dora flow:
* Priority = 115
* Matches:
* - ip, (ethertype)
* - in_port, {@link NodeConnectorId}
* - dl_src {@link org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress}
* - nw_dst (destination ip address)
* Actions:
* - {@link GoToTable} SOURCE MAPPER table
*
* Higher-priority flows providing VLAN support for external networks. Created when node contains external ports *
* Allow from external:
* Priority = 200
* Matches:
* - in_port, {@link NodeConnectorId}
* Actions:
* - {@link GoToTable} INGRESS NAT table
*
* Flow that pops VLAN tag for inbound traffic:
* Priority = 210
* See {@link PortSecurityFlows#popVlanTagsOnExternalPortFlows(short, NodeConnectorId, List, int, OfWriter)}
*
* Highest priority flows used to direct traffic coming from tunnel (SFC). These flows are created always *
* Allow from tunnel:
* Priority = 300
* Matches:
* - in_port (has to be tunnel port), {@link NodeConnectorId}
* Actions:
* - {@link GoToTable} SOURCE MAPPER table
*
*/
public class PortSecurity extends FlowTable {
private static final Logger LOG =
LoggerFactory.getLogger(PortSecurity.class);
// Priorities
private static final Integer DROP = 1;
private static final Integer L2FLOW = 100;
private static final Integer DROP_ARP = 110;
private static final Integer DROP_IPV4 = 111;
private static final Integer DROP_IPV6 = 112;
private static final Integer DHCP_DORA = 115;
private static final Integer L3IP_FLOW = 120;
private static final Integer L3ARP_FLOW = 121;
private static final Integer ALLOW_EXTERNAL = 200;
private static final Integer POP_VLAN_TAG_EXTERNAL = 210;
private static final Integer ALLOW_FROM_TUNNEL = 300;
private final short tableId;
public PortSecurity(OfContext ctx, short tableId) {
super(ctx);
this.tableId = tableId;
}
@Override
public short getTableId() {
return tableId;
}
@Override
public void sync(Endpoint endpoint, OfWriter ofWriter) {
NodeId endpointNodeId = ctx.getEndpointManager().getEndpointNodeId(endpoint);
if (endpointNodeId == null) {
LOG.warn("Endpoint {} has no location specified, skipped", endpoint);
return;
}
PortSecurityFlows flows = new PortSecurityFlows(endpointNodeId, tableId);
// Do sync
syncFlows(flows, endpointNodeId, endpoint, ofWriter);
}
@VisibleForTesting
void syncFlows(PortSecurityFlows flows, NodeId nodeId, Endpoint endpoint, OfWriter ofWriter) {
// TODO all "dropFlow" and "allowFlowFromTunnelFlow" flows should be called only once
// Drop all
flows.dropFlow(DROP, null, ofWriter);
// Drop IP traffic that doesn't match a source IP rule
flows.dropFlow(DROP_ARP, FlowUtils.ARP, ofWriter);
flows.dropFlow(DROP_IPV4, FlowUtils.IPv4, ofWriter);
flows.dropFlow(DROP_IPV6, FlowUtils.IPv6, ofWriter);
// Allow traffic from tunnel ports
short sourceMapperId = ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER();
NodeConnectorId vxLanPort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
if (vxLanPort != null) {
flows.allowFromTunnelFlow(sourceMapperId, ALLOW_FROM_TUNNEL, vxLanPort, ofWriter);
}
NodeConnectorId vxLanGpePort = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlanGpe.class);
if (vxLanGpePort != null) {
flows.allowFromTunnelFlow(sourceMapperId, ALLOW_FROM_TUNNEL, vxLanGpePort, ofWriter);
}
// L3/L2 flows
TenantId tenantId = endpoint.getTenant();
// Internal endpoint
if (EndpointManager.isInternal(endpoint, getExternalImplicitGroupsForTenant(tenantId))) {
NodeConnectorId nodeConnectorId = ctx.getEndpointManager().getEndpointNodeConnectorId(endpoint);
MacAddress macAddress = endpoint.getMacAddress();
if (nodeConnectorId != null && macAddress != null) {
// Allow layer 3 traffic (ARP and IP) with the correct source IP, MAC, and source port
flows.l3Flow(sourceMapperId, endpoint, nodeConnectorId, macAddress, L3IP_FLOW, false, ofWriter);
flows.l3Flow(sourceMapperId, endpoint, nodeConnectorId, macAddress, L3ARP_FLOW, true, ofWriter);
flows.l3DhcpDoraFlow(sourceMapperId, nodeConnectorId, macAddress, DHCP_DORA, ofWriter);
// Allow layer 2 traffic with the correct source MAC and port (lower priority than drop IP rules)
flows.l2flow(sourceMapperId, nodeConnectorId, macAddress, L2FLOW, ofWriter);
}
// External endpoint
} else {
if (LOG.isTraceEnabled()) {
LOG.trace("External Endpoint is ignored in PortSecurity: {}", endpoint);
}
}
// External ports
short ingressNatId = ctx.getPolicyManager().getTABLEID_INGRESS_NAT();
for (NodeConnectorId connectorId : ctx.getSwitchManager().getExternalPorts(nodeId)) {
// TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
if (tenantId != null && ctx.getTenant(tenantId) != null) {
Tenant tenant = ctx.getTenant(tenantId).getTenant();
if (tenant != null && tenant.getForwardingContext() != null &&
tenant.getForwardingContext().getL2FloodDomain() != null) {
List