2 * Copyright (c) 2014 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
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
11 import java.util.Collections;
12 import java.util.List;
15 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
16 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
17 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
18 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * Manage the table that enforces port security
45 public class PortSecurity extends FlowTable {
46 protected static final Logger LOG =
47 LoggerFactory.getLogger(PortSecurity.class);
49 public static short TABLE_ID;
51 public PortSecurity(OfContext ctx, short tableId) {
53 this.TABLE_ID=tableId;
57 public short getTableId() {
62 public void sync(NodeId nodeId, OfWriter ofWriter) {
64 // Allow traffic from tunnel ports
65 NodeConnectorId tunnelIf = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
67 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromPort(tunnelIf));
69 // Allow traffic from tunnel ports
70 //TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
72 Set<NodeConnectorId> external =
73 ctx.getSwitchManager().getExternalPorts(nodeId);
74 for (NodeConnectorId extIf : external) {
75 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromExternalPort(extIf));
79 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
81 // Drop IP traffic that doesn't match a source IP rule
82 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(110), FlowUtils.ARP, TABLE_ID));
83 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(111), FlowUtils.IPv4, TABLE_ID));
84 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(112), FlowUtils.IPv6, TABLE_ID));
86 for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
87 OfOverlayContext ofc = ep.getAugmentation(OfOverlayContext.class);
88 if (ofc == null || ofc.getNodeConnectorId() == null) {
89 LOG.info("Endpoint {} does not contain node-connector-id. OFOverlay ignores the endpoint.",
94 Set<ExternalImplicitGroup> eigs = getExternalImplicitGroupsForTenant(ep.getTenant());
95 if (EndpointManager.isInternal(ep, eigs)) {
96 // Allow layer 3 traffic (ARP and IP) with the correct
97 // source IP, MAC, and source port
98 l3flow(ofWriter, nodeId, ep, ofc, 120, false);
99 l3flow(ofWriter, nodeId, ep, ofc, 121, true);
100 ofWriter.writeFlow(nodeId, TABLE_ID, l3DhcpDoraFlow(ep, ofc, 115));
102 // Allow layer 2 traffic with the correct source MAC and
103 // source port (note lower priority than drop IP rules)
104 ofWriter.writeFlow(nodeId, TABLE_ID, l2flow(ep, ofc, 100));
105 } else { // EP is external
106 if (LOG.isTraceEnabled()) {
107 LOG.trace("External Endpoint is ignored in PortSecurity: {}", ep);
113 private Set<ExternalImplicitGroup> getExternalImplicitGroupsForTenant(TenantId tenantId) {
114 IndexedTenant tenant = ctx.getTenant(tenantId);
115 if (tenant == null) {
116 return Collections.emptySet();
118 return tenant.getExternalImplicitGroups();
121 private Flow allowFromPort(NodeConnectorId port) {
122 Match match = new MatchBuilder()
125 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allow", match);
126 FlowBuilder flowb = base()
128 .setPriority(Integer.valueOf(200))
130 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
131 return flowb.build();
134 private Flow allowFromExternalPort(NodeConnectorId port) {
135 Match match = new MatchBuilder()
138 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allowExternal", match);
139 FlowBuilder flowb = base()
141 .setPriority(Integer.valueOf(200))
143 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_INGRESS_NAT()));
144 return flowb.build();
147 private Flow l2flow(Endpoint ep, OfOverlayContext ofc, Integer priority) {
148 Match match = new MatchBuilder()
150 FlowUtils.ethernetMatch(ep.getMacAddress(), null, null))
151 .setInPort(ofc.getNodeConnectorId())
153 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "L2", match);
154 FlowBuilder flowb = base()
155 .setPriority(priority)
158 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
160 return flowb.build();
163 private Flow l3DhcpDoraFlow(Endpoint ep, OfOverlayContext ofc, Integer priority) {
165 //TODO: Handle IPv6 DORA
166 Long etherType = FlowUtils.IPv4;
167 // DHCP DORA destination is broadcast
168 String ikey = "255.255.255.255/32";
169 Layer3Match m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
171 Match match = new MatchBuilder()
173 FlowUtils.ethernetMatch(ep.getMacAddress(),
177 .setInPort(ofc.getNodeConnectorId())
179 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "dhcp", match);
181 .setPriority(priority)
184 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()))
190 private void l3flow(OfWriter ofWriter, NodeId nodeId,
191 Endpoint ep, OfOverlayContext ofc,
192 Integer priority, boolean arp) {
193 if (ep.getL3Address() == null)
195 for (L3Address l3 : ep.getL3Address()) {
196 if (l3.getIpAddress() == null)
198 Layer3Match m = null;
199 Long etherType = null;
201 if (l3.getIpAddress().getIpv4Address() != null) {
202 ikey = l3.getIpAddress().getIpv4Address().getValue() + "/32";
204 m = new ArpMatchBuilder()
205 .setArpSourceTransportAddress(new Ipv4Prefix(ikey))
207 etherType = FlowUtils.ARP;
209 m = new Ipv4MatchBuilder()
210 .setIpv4Source(new Ipv4Prefix(ikey))
212 etherType = FlowUtils.IPv4;
214 } else if (l3.getIpAddress().getIpv6Address() != null) {
217 ikey = l3.getIpAddress().getIpv6Address().getValue() + "/128";
218 m = new Ipv6MatchBuilder()
219 .setIpv6Source(new Ipv6Prefix(ikey))
221 etherType = FlowUtils.IPv6;
225 Match match = new MatchBuilder()
227 FlowUtils.ethernetMatch(ep.getMacAddress(),
231 .setInPort(ofc.getNodeConnectorId())
233 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "L3", match);
235 .setPriority(priority)
238 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()))
241 ofWriter.writeFlow(nodeId, TABLE_ID,flow);