Bug 3302: fix for GroupTable
[groupbasedpolicy.git] / renderers / ofoverlay / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / flow / PortSecurity.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
10
11 import java.util.Set;
12
13 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfContext;
14 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
15 import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoint.fields.L3Address;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.overlay.rev150105.TunnelTypeVxlan;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38  * Manage the table that enforces port security
39  *
40  */
41 public class PortSecurity extends FlowTable {
42     protected static final Logger LOG =
43             LoggerFactory.getLogger(PortSecurity.class);
44
45     public static short TABLE_ID;
46
47     public PortSecurity(OfContext ctx, short tableId) {
48         super(ctx);
49         this.TABLE_ID=tableId;
50     }
51
52     @Override
53     public short getTableId() {
54         return TABLE_ID;
55     }
56
57     @Override
58     public void sync(NodeId nodeId, PolicyInfo policyInfo, OfWriter ofWriter) {
59
60         // Allow traffic from tunnel ports
61         NodeConnectorId tunnelIf = ctx.getSwitchManager().getTunnelPort(nodeId, TunnelTypeVxlan.class);
62         if (tunnelIf != null)
63             ofWriter.writeFlow(nodeId, TABLE_ID, allowFromPort(tunnelIf));
64
65         // Allow traffic from tunnel ports
66         //TODO Bug 3546 - Difficult: External port is unrelated to Tenant, L3C, L2BD..
67
68         Set<NodeConnectorId> external =
69                 ctx.getSwitchManager().getExternalPorts(nodeId);
70         for (NodeConnectorId extIf : external) {
71             ofWriter.writeFlow(nodeId, TABLE_ID, allowFromExternalPort(extIf));
72         }
73
74         // Default drop all
75         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(1), null, TABLE_ID));
76
77         // Drop IP traffic that doesn't match a source IP rule
78         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(110), FlowUtils.ARP, TABLE_ID));
79         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(111), FlowUtils.IPv4, TABLE_ID));
80         ofWriter.writeFlow(nodeId, TABLE_ID, dropFlow(Integer.valueOf(112), FlowUtils.IPv6, TABLE_ID));
81
82         for (Endpoint ep : ctx.getEndpointManager().getEndpointsForNode(nodeId)) {
83             OfOverlayContext ofc = ep.getAugmentation(OfOverlayContext.class);
84
85             if (ofc != null && ofc.getNodeConnectorId() != null
86                     && (ofc.getLocationType() == null || LocationType.Internal.equals(ofc.getLocationType()))) {
87                 // Allow layer 3 traffic (ARP and IP) with the correct
88                 // source IP, MAC, and source port
89                 l3flow(ofWriter, nodeId, ep, ofc, 120, false);
90                 l3flow(ofWriter, nodeId, ep, ofc, 121, true);
91                 ofWriter.writeFlow(nodeId, TABLE_ID, l3DhcpDoraFlow(ep, ofc, 115));
92
93                 // Allow layer 2 traffic with the correct source MAC and
94                 // source port (note lower priority than drop IP rules)
95                 ofWriter.writeFlow(nodeId, TABLE_ID, l2flow(ep, ofc, 100));
96             }
97         }
98     }
99
100     private Flow allowFromPort(NodeConnectorId port) {
101         Match match = new MatchBuilder()
102                 .setInPort(port)
103                 .build();
104         FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allow", match);
105         FlowBuilder flowb = base()
106                 .setId(flowid)
107                 .setPriority(Integer.valueOf(200))
108                 .setMatch(match)
109                 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
110         return flowb.build();
111     }
112
113     private Flow allowFromExternalPort(NodeConnectorId port) {
114         Match match = new MatchBuilder()
115                 .setInPort(port)
116                 .build();
117         FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "allowExternal", match);
118         FlowBuilder flowb = base()
119                 .setId(flowid)
120                 .setPriority(Integer.valueOf(200))
121                 .setMatch(match)
122                 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_INGRESS_NAT()));
123         return flowb.build();
124     }
125
126     private Flow l2flow(Endpoint ep, OfOverlayContext ofc, Integer priority) {
127         Match match = new MatchBuilder()
128                 .setEthernetMatch(
129                         FlowUtils.ethernetMatch(ep.getMacAddress(), null, null))
130                 .setInPort(ofc.getNodeConnectorId())
131                 .build();
132         FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "L2", match);
133         FlowBuilder flowb = base()
134                 .setPriority(priority)
135                 .setId(flowid)
136                 .setMatch(match)
137                 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()));
138
139         return flowb.build();
140     }
141
142     private Flow l3DhcpDoraFlow(Endpoint ep, OfOverlayContext ofc, Integer priority) {
143
144         //TODO: Handle IPv6 DORA
145         Long etherType = FlowUtils.IPv4;
146         // DHCP DORA destination is broadcast
147         String ikey = "255.255.255.255/32";
148         Layer3Match m = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
149
150         Match match = new MatchBuilder()
151                 .setEthernetMatch(
152                         FlowUtils.ethernetMatch(ep.getMacAddress(),
153                         null,
154                         etherType))
155                 .setLayer3Match(m)
156                 .setInPort(ofc.getNodeConnectorId())
157                 .build();
158         FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "dhcp", match);
159         Flow flow = base()
160                 .setPriority(priority)
161                 .setId(flowid)
162                 .setMatch(match)
163                 .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()))
164                 .build();
165
166         return flow;
167     }
168
169     private void l3flow(OfWriter ofWriter, NodeId nodeId,
170                         Endpoint ep, OfOverlayContext ofc,
171                         Integer priority, boolean arp) {
172         if (ep.getL3Address() == null)
173             return;
174         for (L3Address l3 : ep.getL3Address()) {
175             if (l3.getIpAddress() == null)
176                 continue;
177             Layer3Match m = null;
178             Long etherType = null;
179             String ikey = null;
180             if (l3.getIpAddress().getIpv4Address() != null) {
181                 ikey = l3.getIpAddress().getIpv4Address().getValue() + "/32";
182                 if (arp) {
183                     m = new ArpMatchBuilder()
184                             .setArpSourceTransportAddress(new Ipv4Prefix(ikey))
185                             .build();
186                     etherType = FlowUtils.ARP;
187                 } else {
188                     m = new Ipv4MatchBuilder()
189                             .setIpv4Source(new Ipv4Prefix(ikey))
190                             .build();
191                     etherType = FlowUtils.IPv4;
192                 }
193             } else if (l3.getIpAddress().getIpv6Address() != null) {
194                 if (arp)
195                     continue;
196                 ikey = l3.getIpAddress().getIpv6Address().getValue() + "/128";
197                 m = new Ipv6MatchBuilder()
198                         .setIpv6Source(new Ipv6Prefix(ikey))
199                         .build();
200                 etherType = FlowUtils.IPv6;
201             } else {
202                 continue;
203             }
204             Match match = new MatchBuilder()
205                     .setEthernetMatch(
206                             FlowUtils.ethernetMatch(ep.getMacAddress(),
207                             null,
208                             etherType))
209                     .setLayer3Match(m)
210                     .setInPort(ofc.getNodeConnectorId())
211                     .build();
212             FlowId flowid = FlowIdUtils.newFlowId(TABLE_ID, "L3", match);
213             Flow flow = base()
214                     .setPriority(priority)
215                     .setId(flowid)
216                     .setMatch(match)
217                     .setInstructions(FlowUtils.gotoTableInstructions(ctx.getPolicyManager().getTABLEID_SOURCE_MAPPER()))
218                     .build();
219
220             ofWriter.writeFlow(nodeId, TABLE_ID,flow);
221         }
222     }
223 }