2 * Copyright (c) 2018 Red Hat, 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
8 package org.opendaylight.netvirt.aclservice;
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.genius.mdsalutil.InstructionInfo;
18 import org.opendaylight.genius.mdsalutil.MDSALUtil;
19 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
22 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
23 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
24 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
25 import org.opendaylight.genius.utils.ServiceIndex;
26 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
27 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
28 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
29 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
30 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
31 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
32 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
33 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
34 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 * Provides the implementation for ingress (w.r.t VM) ACL service.
51 * Note: Table names used are w.r.t switch. Hence, switch ingress is VM egress
54 public class IngressAclServiceImpl extends AbstractAclServiceImpl {
56 private static final Logger LOG = LoggerFactory.getLogger(IngressAclServiceImpl.class);
59 * Initialize the member variables.
61 * @param dataBroker the data broker instance.
62 * @param mdsalManager the mdsal manager.
63 * @param aclDataUtil the acl data util.
64 * @param aclServiceUtils the acl service util.
65 * @param jobCoordinator the job coordinator
66 * @param aclInterfaceCache the acl interface cache
68 public IngressAclServiceImpl(DataBroker dataBroker, IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil,
69 AclServiceUtils aclServiceUtils, JobCoordinator jobCoordinator, AclInterfaceCache aclInterfaceCache) {
70 // Service mode is w.rt. switch
71 super(ServiceModeEgress.class, dataBroker, mdsalManager, aclDataUtil, aclServiceUtils, jobCoordinator,
78 * @param aclInterface the acl interface
81 public void bindService(AclInterface aclInterface) {
82 String interfaceName = aclInterface.getInterfaceId();
83 jobCoordinator.enqueueJob(interfaceName, () -> {
84 int instructionKey = 0;
85 List<Instruction> instructions = new ArrayList<>();
87 MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.EGRESS_ACL_DUMMY_TABLE, ++instructionKey));
88 int flowPriority = NwConstants.EGRESS_ACL_SERVICE_INDEX;
90 ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX);
91 BoundServices serviceInfo =
92 AclServiceUtils.getBoundServices(String.format("%s.%s.%s", "acl", "egressacl", interfaceName),
93 serviceIndex, flowPriority, AclConstants.COOKIE_ACL_BASE, instructions);
94 InstanceIdentifier<BoundServices> path = AclServiceUtils.buildServiceId(interfaceName,
95 ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX),
98 return Collections.singletonList(
99 txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.put(LogicalDatastoreType.CONFIGURATION,
100 path, serviceInfo, WriteTransaction.CREATE_MISSING_PARENTS)));
107 * @param aclInterface the acl interface
110 protected void unbindService(AclInterface aclInterface) {
111 String interfaceName = aclInterface.getInterfaceId();
112 InstanceIdentifier<BoundServices> path = AclServiceUtils.buildServiceId(interfaceName,
113 ServiceIndex.getIndex(NwConstants.EGRESS_ACL_SERVICE_NAME, NwConstants.EGRESS_ACL_SERVICE_INDEX),
116 LOG.debug("UnBinding ACL service for interface {}", interfaceName);
117 jobCoordinator.enqueueJob(interfaceName, () -> Collections.singletonList(txRunner
118 .callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.delete(LogicalDatastoreType.CONFIGURATION, path))));
122 protected void programAntiSpoofingRules(AclInterface port,
123 List<AllowedAddressPairs> allowedAddresses, Action action, int addOrRemove) {
124 LOG.info("{} programAntiSpoofingRules for port {}, AAPs={}, action={}, addOrRemove={}", this.directionString,
125 port.getInterfaceId(), allowedAddresses, action, addOrRemove);
127 BigInteger dpid = port.getDpId();
128 int lportTag = port.getLPortTag();
129 if (action == Action.ADD || action == Action.REMOVE) {
130 ingressAclDhcpAllowServerTraffic(dpid, lportTag, addOrRemove);
131 ingressAclDhcpv6AllowServerTraffic(dpid, lportTag, addOrRemove);
132 ingressAclIcmpv6AllowedTraffic(dpid, lportTag, addOrRemove);
134 programArpRule(dpid, lportTag, addOrRemove);
135 programIpv4BroadcastRule(port, addOrRemove);
140 protected void programGotoClassifierTableRules(BigInteger dpId, List<AllowedAddressPairs> aaps, int lportTag,
142 for (AllowedAddressPairs aap : aaps) {
143 IpPrefixOrAddress attachIp = aap.getIpAddress();
144 MacAddress mac = aap.getMacAddress();
146 List<MatchInfoBase> matches = new ArrayList<>();
147 matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
148 matches.add(new MatchEthernetDestination(mac));
149 matches.addAll(AclServiceUtils.buildIpMatches(attachIp, MatchCriteria.MATCH_DESTINATION));
151 List<InstructionInfo> gotoInstructions = new ArrayList<>();
152 gotoInstructions.add(new InstructionGotoTable(getAclConntrackClassifierTable()));
154 String flowName = "Ingress_Fixed_Goto_Classifier_" + dpId + "_" + lportTag + "_" + mac.getValue() + "_"
155 + String.valueOf(attachIp.getValue());
156 syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
157 AclConstants.COOKIE_ACL_BASE, matches, gotoInstructions, addOrRemove);
162 protected void programRemoteAclTableFlow(BigInteger dpId, Integer aclTag, AllowedAddressPairs aap,
164 List<MatchInfoBase> flowMatches = new ArrayList<>();
165 flowMatches.addAll(AclServiceUtils.buildIpAndSrcServiceMatch(aclTag, aap));
167 List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getGotoInstructionInfo(getAclCommitterTable());
168 String flowNameAdded = "Acl_Filter_Ingress_" + String.valueOf(aap.getIpAddress().getValue()) + "_" + aclTag;
170 syncFlow(dpId, getAclRemoteAclTable(), flowNameAdded, AclConstants.ACL_DEFAULT_PRIORITY, "ACL", 0, 0,
171 AclConstants.COOKIE_ACL_BASE, flowMatches, instructions, addOrRemove);
175 * Add rule to ensure only DHCP server traffic from the specified mac is
178 * @param dpId the dpid
179 * @param lportTag the lport tag
180 * @param addOrRemove is write or delete
182 protected void ingressAclDhcpAllowServerTraffic(BigInteger dpId, int lportTag, int addOrRemove) {
183 final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpMatches(AclConstants.DHCP_SERVER_PORT_IPV4,
184 AclConstants.DHCP_CLIENT_PORT_IPV4, lportTag, serviceMode);
185 List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
187 String flowName = "Ingress_DHCP_Server_v4" + dpId + "_" + lportTag + "_Permit_";
188 syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, "ACL", 0, 0,
189 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
193 * Add rule to ensure only DHCPv6 server traffic from the specified mac is
196 * @param dpId the dpid
197 * @param lportTag the lport tag
198 * @param addOrRemove is write or delete
200 protected void ingressAclDhcpv6AllowServerTraffic(BigInteger dpId, int lportTag, int addOrRemove) {
201 final List<MatchInfoBase> matches = AclServiceUtils.buildDhcpV6Matches(AclConstants.DHCP_SERVER_PORT_IPV6,
202 AclConstants.DHCP_CLIENT_PORT_IPV6, lportTag, serviceMode);
203 List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
205 String flowName = "Ingress_DHCP_Server_v6" + "_" + dpId + "_" + lportTag + "_Permit_";
206 syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_DHCP_SERVER_MATCH_PRIORITY, "ACL", 0, 0,
207 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
211 * Add rules to ensure that certain ICMPv6 like MLD_QUERY (130), NS (135), NA (136) are allowed into the VM.
213 * @param dpId the dpid
214 * @param lportTag the lport tag
215 * @param addOrRemove is write or delete
217 private void ingressAclIcmpv6AllowedTraffic(BigInteger dpId, int lportTag, int addOrRemove) {
218 List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
220 // Allow ICMPv6 Multicast Listener Query packets.
221 List<MatchInfoBase> matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_MLD_QUERY, 0,
222 lportTag, serviceMode);
224 final short tableId = getAclAntiSpoofingTable();
226 "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_MLD_QUERY + "_Permit_";
227 syncFlow(dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL", 0, 0,
228 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
230 // Allow ICMPv6 Neighbor Solicitation packets.
231 matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_NS, 0, lportTag, serviceMode);
233 flowName = "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_NS + "_Permit_";
234 syncFlow(dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL", 0, 0,
235 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
237 // Allow ICMPv6 Neighbor Advertisement packets.
238 matches = AclServiceUtils.buildIcmpV6Matches(AclConstants.ICMPV6_TYPE_NA, 0, lportTag, serviceMode);
240 flowName = "Ingress_ICMPv6" + "_" + dpId + "_" + lportTag + "_" + AclConstants.ICMPV6_TYPE_NA + "_Permit_";
241 syncFlow(dpId, tableId, flowName, AclConstants.PROTO_IPV6_ALLOWED_PRIORITY, "ACL", 0, 0,
242 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
246 * Adds the rule to allow arp packets.
248 * @param dpId the dpId
249 * @param lportTag the lport tag
250 * @param addOrRemove whether to add or remove the flow
252 protected void programArpRule(BigInteger dpId, int lportTag, int addOrRemove) {
253 List<MatchInfoBase> matches = new ArrayList<>();
254 matches.add(MatchEthernetType.ARP);
255 matches.add(AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode));
256 List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions();
257 LOG.debug(addOrRemove == NwConstants.DEL_FLOW ? "Deleting " : "Adding " + "ARP Rule on DPID {}, "
258 + "lportTag {}", dpId, lportTag);
259 String flowName = "Ingress_ARP_" + dpId + "_" + lportTag;
260 syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_ARP_TRAFFIC_MATCH_PRIORITY, "ACL", 0, 0,
261 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
266 * Programs broadcast rules.
268 * @param port the Acl Interface port
269 * @param addOrRemove whether to delete or add flow
272 protected void programBroadcastRules(AclInterface port, int addOrRemove) {
273 programIpv4BroadcastRule(port, addOrRemove);
277 * Programs IPv4 broadcast rules.
279 * @param port the Acl Interface port
280 * @param addOrRemove whether to delete or add flow
282 private void programIpv4BroadcastRule(AclInterface port, int addOrRemove) {
283 BigInteger dpId = port.getDpId();
284 int lportTag = port.getLPortTag();
285 MatchInfoBase lportMatchInfo = AclServiceUtils.buildLPortTagMatch(lportTag, serviceMode);
286 List<IpPrefixOrAddress> cidrs = port.getSubnetIpPrefixes();
288 List<String> broadcastAddresses = AclServiceUtils.getIpBroadcastAddresses(cidrs);
289 for (String broadcastAddress : broadcastAddresses) {
290 List<MatchInfoBase> matches =
291 AclServiceUtils.buildBroadcastIpV4Matches(broadcastAddress);
292 matches.add(lportMatchInfo);
293 List<InstructionInfo> instructions = new ArrayList<>();
294 instructions.add(new InstructionGotoTable(getAclConntrackClassifierTable()));
295 String flowName = "Ingress_v4_Broadcast_" + dpId + "_" + lportTag + "_" + broadcastAddress + "_Permit";
296 syncFlow(dpId, getAclAntiSpoofingTable(), flowName, AclConstants.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
297 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
300 LOG.warn("IP Broadcast CIDRs are missing for port {}", port.getInterfaceId());
305 protected boolean isValidDirection(Class<? extends DirectionBase> direction) {
306 return direction.equals(DirectionIngress.class);
310 protected short getAclAntiSpoofingTable() {
311 return NwConstants.EGRESS_ACL_ANTI_SPOOFING_TABLE;
315 protected short getAclConntrackClassifierTable() {
316 return NwConstants.EGRESS_ACL_CONNTRACK_CLASSIFIER_TABLE;
320 protected short getAclConntrackSenderTable() {
321 return NwConstants.EGRESS_ACL_CONNTRACK_SENDER_TABLE;
325 protected short getAclForExistingTrafficTable() {
326 return NwConstants.EGRESS_ACL_FOR_EXISTING_TRAFFIC_TABLE;
330 protected short getAclFilterCumDispatcherTable() {
331 return NwConstants.EGRESS_ACL_FILTER_CUM_DISPATCHER_TABLE;
335 protected short getAclRuleBasedFilterTable() {
336 return NwConstants.EGRESS_ACL_RULE_BASED_FILTER_TABLE;
340 protected short getAclRemoteAclTable() {
341 return NwConstants.EGRESS_REMOTE_ACL_TABLE;
345 protected short getAclCommitterTable() {
346 return NwConstants.EGRESS_ACL_COMMITTER_TABLE;