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;
13 import java.util.ArrayList;
14 import java.util.HashSet;
17 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
18 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
19 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
20 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.ExternalImplicitGroup;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.Segmentation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L2FloodDomain;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlanGpe;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
53 * Manage the table that enforces port security
56 public class PortSecurity extends FlowTable {
57 protected static final Logger LOG =
58 LoggerFactory.getLogger(PortSecurity.class);
60 public static short TABLE_ID;
62 public PortSecurity(OfContext ctx, short tableId) {
68 public short getTableId() {
73 public void sync(NodeId nodeId, OfWriter ofWriter) {
75 // Allow traffic from tunnel ports
76 NodeConnectorId vxLanTunnel = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
77 NodeConnectorId vxLanGpeTunnel = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlanGpe.class);
78 if (vxLanTunnel != null)
79 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromPort(vxLanTunnel));
80 if (vxLanGpeTunnel != null)
81 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromPort(vxLanGpeTunnel));
84 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(1, null, TABLE_ID));
86 // Drop IP traffic that doesn't match a source IP rule
87 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(110, FlowUtils.ARP, TABLE_ID));
88 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(111, FlowUtils.IPv4, TABLE_ID));
89 ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(112, FlowUtils.IPv6, TABLE_ID));
91 Set<TenantId> tenantIds = new HashSet<>();
92 for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
93 OfOverlayContext ofc = ep.getAugmentation(OfOverlayContext.class);
94 if (ofc == null || ofc.getNodeConnectorId() == null) {
95 LOG.info("Endpoint {} does not contain node-connector-id. OFOverlay ignores the endpoint.",
100 tenantIds.add(ep.getTenant());
101 Set<ExternalImplicitGroup> eigs = getExternalImplicitGroupsForTenant(ep.getTenant());
102 if (EndpointManager.isInternal(ep, eigs)) {
103 // Allow layer 3 traffic (ARP and IP) with the correct
104 // source IP, MAC, and source port
105 l3flow(ofWriter, nodeId, ep, ofc, 120, false);
106 l3flow(ofWriter, nodeId, ep, ofc, 121, true);
107 ofWriter.writeFlow(nodeId, TABLE_ID, l3DhcpDoraFlow(ep, ofc, 115));
109 // Allow layer 2 traffic with the correct source MAC and
110 // source port (note lower priority than drop IP rules)
111 ofWriter.writeFlow(nodeId, TABLE_ID, l2flow(ep, ofc, 100));
112 } else { // EP is external
113 if (LOG.isTraceEnabled()) {
114 LOG.trace("External Endpoint is ignored in PortSecurity: {}", ep);
119 for (TenantId tenantId : tenantIds) {
120 for (NodeConnectorId nc : ctx.getSwitchManager().getExternalPorts(nodeId)) {
121 // TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
122 for (Flow flow : popVlanTagsOnExternalPort(nc, tenantId, 210)) {
123 // tagged frames have to be untagged when entering policy domain
124 ofWriter.writeFlow(nodeId, TABLE_ID, flow);
126 // allowing untagged frames entering policy domain
127 ofWriter.writeFlow(nodeId, TABLE_ID, allowFromExternalPort(nc, 200));
132 private Set<ExternalImplicitGroup> getExternalImplicitGroupsForTenant(TenantId tenantId) {
133 IndexedTenant tenant = ctx.getTenant(tenantId);
134 if (tenant == null) {
135 return Collections.emptySet();
137 return tenant.getExternalImplicitGroups();
140 private Flow allowFromPort(NodeConnectorId port) {
141 Match match = new MatchBuilder()
144 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allow", match);
145 FlowBuilder flowb = base()
149 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
150 return flowb.build();
153 private Flow l2flow(Endpoint ep, OfOverlayContext ofc, Integer priority) {
154 Match match = new MatchBuilder()
156 FlowUtils.ethernetMatch(ep.getMacAddress(), null, null))
157 .setInPort(ofc.getNodeConnectorId())
159 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "L2", match);
160 FlowBuilder flowb = base()
161 .setPriority(priority)
164 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
166 return flowb.build();
169 private Flow l3DhcpDoraFlow(Endpoint ep, OfOverlayContext ofc, Integer priority) {
171 //TODO: Handle IPv6 DORA
172 Long etherType = FlowUtils.IPv4;
173 // DHCP DORA destination is broadcast
174 String ikey = "255.255.255.255/32";
175 Layer3Match m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
177 Match match = new MatchBuilder()
179 FlowUtils.ethernetMatch(ep.getMacAddress(),
183 .setInPort(ofc.getNodeConnectorId())
185 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "dhcp", match);
187 .setPriority(priority)
190 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()))
194 private void l3flow(OfWriter ofWriter, NodeId nodeId,
195 Endpoint ep, OfOverlayContext ofc,
196 Integer priority, boolean arp) {
197 if (ep.getL3Address() == null)
199 for (L3Address l3 : ep.getL3Address()) {
200 if (l3.getIpAddress() == null)
205 if (l3.getIpAddress().getIpv4Address() != null) {
206 ikey = l3.getIpAddress().getIpv4Address().getValue() + "/32";
208 m = new ArpMatchBuilder()
209 .setArpSourceTransportAddress(new Ipv4Prefix(ikey))
211 etherType = FlowUtils.ARP;
213 m = new Ipv4MatchBuilder()
214 .setIpv4Source(new Ipv4Prefix(ikey))
216 etherType = FlowUtils.IPv4;
218 } else if (l3.getIpAddress().getIpv6Address() != null) {
221 ikey = l3.getIpAddress().getIpv6Address().getValue() + "/128";
222 m = new Ipv6MatchBuilder()
223 .setIpv6Source(new Ipv6Prefix(ikey))
225 etherType = FlowUtils.IPv6;
229 Match match = new MatchBuilder()
231 FlowUtils.ethernetMatch(ep.getMacAddress(),
235 .setInPort(ofc.getNodeConnectorId())
237 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "L3", match);
239 .setPriority(priority)
242 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()))
245 ofWriter.writeFlow(nodeId, TABLE_ID,flow);
249 private Flow allowFromExternalPort(NodeConnectorId nc, Integer priority) {
250 Match match = new MatchBuilder().setInPort(nc).build();
251 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allowExternal", match);
252 FlowBuilder flowb = base().setId(flowid)
253 .setPriority(priority)
255 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_INGRESS_NAT()));
256 return flowb.build();
260 * Pops VLAN tag for inbound traffic.
262 * @param nc should be external for now
263 * @param tenantId of {@link Tenant} from which {@link L2FloodDomain}s are read from which VLAN IDs are resolved.
264 * @param priority of flows in the table
265 * @return {@link Flow}s which match on ingress port, and VLAN ID to pop.
266 * {@link GoToTable} Instructions are set to INGRESS NAT table.
268 private List<Flow> popVlanTagsOnExternalPort(NodeConnectorId nc, TenantId tenantId, Integer priority) {
269 List<Flow> flows = new ArrayList<>();
270 if(ctx.getTenant(tenantId) != null) {
271 for (L2FloodDomain l2Fd : ctx.getTenant(tenantId).getTenant().getForwardingContext().getL2FloodDomain()) {
272 Segmentation segmentation = l2Fd.getAugmentation(Segmentation.class);
273 if (segmentation != null) {
274 Integer vlanId = segmentation.getSegmentationId();
275 flows.add(buildPopVlanFlow(nc, vlanId, priority));
282 private Flow buildPopVlanFlow(NodeConnectorId nc, Integer vlanId, int priority) {
283 Match match = new MatchBuilder()
284 .setVlanMatch(FlowUtils.vlanMatch(vlanId, true))
287 List<Instruction> instructions = new ArrayList<>();
288 instructions.add(FlowUtils.popVlanInstruction(0));
289 instructions.add(new InstructionBuilder().setOrder(1)
290 // TODO for now matches on external flows are passed to ingress nat table
291 .setInstruction(FlowUtils.gotoTableIns(ctx.getPolicyManager().getTABLEID_INGRESS_NAT()))
293 FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allowExternalPopVlan", match);
294 return base().setPriority(priority)
297 .setInstructions(new InstructionsBuilder().setInstruction(instructions).build())