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.mapper.destination;
11 import com.google.common.base.Preconditions;
12 import org.opendaylight.groupbasedpolicy.dto.IndexedTenant;
13 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.OfWriter;
14 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.endpoint.EndpointManager;
15 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowIdUtils;
16 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils;
17 import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.OrdinalFactory;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
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.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
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.FlowBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.go.to.table._case.GoToTable;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.TenantId;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.UniqueId;
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;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.EndpointL3Prefix;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.unregister.endpoint.input.L3Prefix;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.L3Context;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.forwarding.context.Subnet;
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.ethernet.match.fields.EthernetDestinationBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
58 import java.math.BigInteger;
59 import java.util.ArrayList;
60 import java.util.List;
63 import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
65 class DestinationMapperFlows {
67 private static final Logger LOG = LoggerFactory.getLogger(DestinationMapperFlows.class);
68 private final DestinationMapperUtils utils;
69 private final NodeId nodeId;
70 private final short tableId;
72 public DestinationMapperFlows(DestinationMapperUtils utils, NodeId nodeId, short tableId) {
73 this.utils = Preconditions.checkNotNull(utils);
74 this.nodeId = Preconditions.checkNotNull(nodeId);
75 this.tableId = tableId;
79 * Default flow which drops all incoming traffic
81 * @param priority of flow in the table
82 * @param etherType can be set as specific protocol to match
83 * @param ofWriter flow writer
85 void dropFlow(int priority, Long etherType, OfWriter ofWriter) {
87 FlowBuilder flowBuilder = FlowUtils.base(tableId)
88 .setPriority(priority)
89 .setInstructions(FlowUtils.dropInstructions());
90 if (etherType != null) {
91 MatchBuilder matchBuilder = new MatchBuilder()
92 .setEthernetMatch(FlowUtils.ethernetMatch(null, null, etherType));
93 Match match = matchBuilder.build();
94 flowId = FlowIdUtils.newFlowId(tableId, "drop", match);
95 flowBuilder.setMatch(match);
97 flowId = FlowIdUtils.newFlowId("dropAll");
99 flowBuilder.setId(flowId);
100 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
104 * Create external L2 flow for every external port found on node
106 * @param goToTable {@link GoToTable} instruction value
107 * @param priority of the flow
108 * @param peerEndpoint original endpoint (input parameter to {@link DestinationMapper#sync(Endpoint, OfWriter)}
109 * @param externalPorts list of external {@link NodeConnectorId}-s get from node
110 * @param ofWriter flow writer
112 void createExternalL2Flow(short goToTable, int priority, Endpoint peerEndpoint, Set<NodeConnectorId> externalPorts,
114 OrdinalFactory.EndpointFwdCtxOrdinals peerOrdinals = utils.getEndpointOrdinals(peerEndpoint);
115 if (peerOrdinals != null) {
116 MatchBuilder matchBuilder = new MatchBuilder()
117 .setEthernetMatch(ethernetMatch(null, peerEndpoint.getMacAddress(), null));
118 addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg4.class, (long) peerOrdinals.getBdId()));
119 Match match = matchBuilder.build();
122 for (NodeConnectorId externalPort : externalPorts) {
124 port = getOfPortNum(externalPort);
125 writeExternalL2Flow(goToTable, priority, peerOrdinals, port, match, ofWriter);
126 } catch (NumberFormatException e) {
127 LOG.warn("Invalid NodeConnectorId. External port: {}", externalPort);
134 * Create external L3 flow for every external port found on node
136 * @param goToTable {@link GoToTable} instruction value
137 * @param priority of the flow
138 * @param peerEndpoint to original endpoint (input parameter to {@link DestinationMapper#sync(Endpoint, OfWriter)}
139 * @param l2GatewayEp L2 endpoint of subnet gateway
140 * @param destL3Address endpoint L3 address
141 * @param externalPorts list of external {@link NodeConnectorId}-s get from node
142 * @param ofWriter flow writer
144 void createExternalL3RoutedFlow(short goToTable, int priority, Endpoint peerEndpoint, Endpoint l2GatewayEp,
145 L3Address destL3Address, Set<NodeConnectorId> externalPorts, OfWriter ofWriter) {
146 OrdinalFactory.EndpointFwdCtxOrdinals peerOrdinals = utils.getEndpointOrdinals(peerEndpoint);
147 if (peerOrdinals != null) {
148 Layer3Match layer3Match;
151 if (destL3Address.getIpAddress() != null && destL3Address.getIpAddress().getIpv4Address() != null) {
152 ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
154 layer3Match = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
155 } else if (destL3Address.getIpAddress() != null && destL3Address.getIpAddress().getIpv6Address() != null) {
156 ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
158 layer3Match = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
160 LOG.error("Endpoint has Ip Address that is not recognised as either IPv4 or IPv6.", destL3Address);
163 MacAddress matcherMac = peerEndpoint.getMacAddress();
164 MatchBuilder matchBuilder = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
165 .setLayer3Match(layer3Match);
166 addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg6.class, (long) peerOrdinals.getL3Id()));
167 Match match = matchBuilder.build();
170 for (NodeConnectorId externalPort : externalPorts) {
172 port = getOfPortNum(externalPort);
173 writeExternalL3RoutedFlow(goToTable, priority, port, l2GatewayEp, match, peerOrdinals, ofWriter);
174 } catch (NumberFormatException e) {
175 LOG.warn("Invalid NodeConnectorId. External port: {}", externalPort);
182 * Create local L2 flow
184 * @param goToTable {@link GoToTable} instruction value
185 * @param priority of the flow
186 * @param endpoint original endpoint (input parameter to {@link DestinationMapper#sync(Endpoint, OfWriter)}
187 * @param ofWriter flow writer
189 void createLocalL2Flow(short goToTable, int priority, Endpoint endpoint, OfWriter ofWriter) {
190 OfOverlayContext context = endpoint.getAugmentation(OfOverlayContext.class);
191 OrdinalFactory.EndpointFwdCtxOrdinals ordinals = utils.getEndpointOrdinals(endpoint);
195 setNextHop = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(getOfPortNum(context.getNodeConnectorId())));
196 } catch (NumberFormatException ex) {
197 LOG.warn("Could not parse port number {}", context.getNodeConnectorId(), ex);
200 List<Action> applyActions = new ArrayList<>();
201 applyActions.add(nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(ordinals.getEpgId())));
202 applyActions.add(nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(ordinals.getCgId())));
203 applyActions.add(setNextHop);
206 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
207 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
209 Instruction gotoTable = new InstructionBuilder().setOrder(order)
210 .setInstruction(gotoTableIns(goToTable))
213 ArrayList<Instruction> instructions = new ArrayList<>();
214 instructions.add(applyActionsIns);
215 instructions.add(gotoTable);
217 MatchBuilder matchBuilder = new MatchBuilder()
218 .setEthernetMatch(ethernetMatch(null, endpoint.getMacAddress(), null));
219 addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg4.class, (long) ordinals.getBdId()));
220 Match match = matchBuilder.build();
221 FlowId flowId = FlowIdUtils.newFlowId(tableId, "localL2", match);
222 FlowBuilder flowBuilder = base(tableId).setId(flowId)
223 .setPriority(priority)
225 .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
226 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
230 * Create local L3 routed flow
232 * @param goToTable {@link GoToTable} instruction value
233 * @param priority of the flow
234 * @param endpoint original endpoint (input parameter to {@link DestinationMapper#sync(Endpoint, OfWriter)}
235 * @param l3Address endpoint L3 address
236 * @param localSubnet subnet from local node
237 * @param destSubnet destination endpoint's subnet
238 * @param ofWriter flow writer
240 void createLocalL3RoutedFlow(short goToTable, int priority, Endpoint endpoint, L3Address l3Address,
241 Subnet localSubnet, Subnet destSubnet, OfWriter ofWriter) {
242 NodeConnectorId connectorId = endpoint.getAugmentation(OfOverlayContext.class).getNodeConnectorId();
243 L3Context l3Context = utils.getL3ContextForSubnet(utils.getIndexedTenant(endpoint.getTenant()), localSubnet);
244 if (l3Context == null) {
247 MacAddress matcherMac = utils.routerPortMac(l3Context, localSubnet.getVirtualRouterIp(), endpoint.getTenant());
248 MacAddress epDestMac = endpoint.getMacAddress();
249 if (matcherMac == null || epDestMac == null) {
252 MacAddress destSubnetGatewayMac = utils.routerPortMac(l3Context, destSubnet.getVirtualRouterIp(),
253 endpoint.getTenant());
254 OrdinalFactory.EndpointFwdCtxOrdinals ordinals = utils.getEndpointOrdinals(endpoint);
255 if (localSubnet.getId().getValue().equals(destSubnet.getId().getValue())) {
256 matcherMac = epDestMac;
258 Action setNextHopAction;
260 setNextHopAction = nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(getOfPortNum(connectorId)));
261 } catch (NumberFormatException ex) {
262 LOG.warn("Could not parse port number {}", connectorId, ex);
265 List<Action> l3ApplyActions = new ArrayList<>();
266 l3ApplyActions.add(setDlDstAction(epDestMac));
267 l3ApplyActions.add(decNwTtlAction());
268 if (!(matcherMac.getValue().equals(epDestMac.getValue()))) {
269 l3ApplyActions.add(setDlSrcAction(destSubnetGatewayMac));
271 List<Action> applyActions = new ArrayList<>();
272 applyActions.add(nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(ordinals.getEpgId())));
273 applyActions.add(nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(ordinals.getCgId())));
274 applyActions.add(setNextHopAction);
275 applyActions.addAll(l3ApplyActions);
278 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
279 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
281 Instruction gotoTable = new InstructionBuilder().setOrder(order)
282 .setInstruction(gotoTableIns(goToTable))
284 ArrayList<Instruction> l3instructions = new ArrayList<>();
285 l3instructions.add(applyActionsIns);
286 l3instructions.add(gotoTable);
290 if (l3Address.getIpAddress() != null && l3Address.getIpAddress().getIpv4Address() != null) {
291 ikey = l3Address.getIpAddress().getIpv4Address().getValue() + "/32";
293 l3Match = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
294 } else if (l3Address.getIpAddress() != null && l3Address.getIpAddress().getIpv6Address() != null) {
295 ikey = l3Address.getIpAddress().getIpv6Address().getValue() + "/128";
297 l3Match = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
299 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", l3Address.toString());
302 MatchBuilder matchBuilder = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
303 .setLayer3Match(l3Match);
304 addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg6.class, (long) ordinals.getL3Id()));
305 Match match = matchBuilder.build();
306 FlowId flowid = FlowIdUtils.newFlowId(tableId, "localL3", match);
307 FlowBuilder flowBuilder = base(tableId).setId(flowid)
308 .setPriority(priority)
310 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
311 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
315 * Create remote L2 flow
317 * @param goToTable {@link GoToTable} instruction value
318 * @param priority of the flow
319 * @param endpoint original peer
320 * @param peerEndpoint peer endpoint to original endpoint
321 * @param tunDst tunnel destination Ip address
322 * @param connectorId tunnel port
323 * @param ofWriter flow writer
325 void createRemoteL2Flow(short goToTable, int priority, Endpoint endpoint, Endpoint peerEndpoint, IpAddress tunDst,
326 NodeConnectorId connectorId, OfWriter ofWriter) {
327 OrdinalFactory.EndpointFwdCtxOrdinals endpointOrdinals = utils.getEndpointOrdinals(endpoint);
330 port = getOfPortNum(connectorId);
331 } catch (NumberFormatException ex) {
332 LOG.warn("Could not parse port number {}", connectorId);
335 Action tunnelDestinationAction = null;
336 if (tunDst.getIpv4Address() != null) {
337 tunnelDestinationAction = nxLoadTunIPv4Action(tunDst.getIpv4Address().getValue(), false);
338 } else if (tunDst.getIpv6Address() != null) {
339 LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(),
343 List<Action> applyActions = new ArrayList<>();
344 applyActions.add(nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(endpointOrdinals.getEpgId())));
345 applyActions.add(nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(endpointOrdinals.getCgId())));
346 applyActions.add(nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(port)));
347 applyActions.add(tunnelDestinationAction);
350 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
351 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
353 Instruction gotoTable = new InstructionBuilder().setOrder(order)
354 .setInstruction(gotoTableIns(goToTable))
357 ArrayList<Instruction> instructions = new ArrayList<>();
358 instructions.add(applyActionsIns);
359 instructions.add(gotoTable);
361 MatchBuilder matchBuilder = new MatchBuilder()
362 .setEthernetMatch(ethernetMatch(null, peerEndpoint.getMacAddress(), null));
363 addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg4.class, (long) endpointOrdinals.getBdId()));
364 Match match = matchBuilder.build();
365 FlowId flowid = FlowIdUtils.newFlowId(tableId, "remoteL2", match);
366 FlowBuilder flowBuilder = base(tableId).setId(flowid)
367 .setPriority(priority)
369 .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
371 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
375 * Create remote L3 routed flow
377 * @param goToTable {@link GoToTable} instruction value
378 * @param priority of the flow
379 * @param endpoint peer
380 * @param destL3Address destination L3 address
381 * @param destSubnet subnet from destination node
382 * @param tunDst tunnel destination Ip address
383 * @param connectorId tunnel port
384 * @param localSubnet subnet from local node
385 * @param ofWriter flow writer
387 void createRemoteL3RoutedFlow(short goToTable, int priority, Endpoint endpoint, L3Address destL3Address,
388 Subnet destSubnet, IpAddress tunDst, NodeConnectorId connectorId, Subnet localSubnet,
390 L3Context context = utils.getL3ContextForSubnet(utils.getIndexedTenant(endpoint.getTenant()), destSubnet);
391 if (context == null) {
394 OrdinalFactory.EndpointFwdCtxOrdinals ordinals = utils.getEndpointOrdinals(endpoint);
395 MacAddress matcherMac = utils.routerPortMac(context, localSubnet.getVirtualRouterIp(), endpoint.getTenant());
396 MacAddress epDestMac = endpoint.getMacAddress();
397 if (matcherMac == null || epDestMac == null) {
400 MacAddress destSubnetGatewayMac = utils.routerPortMac(context, destSubnet.getVirtualRouterIp(),
401 endpoint.getTenant());
404 List<Action> l3ApplyActions = new ArrayList<>();
405 if (localSubnet.getId().getValue().equals(destSubnet.getId().getValue())) {
406 // This is our final destination, so match on actual EP mac.
407 matcherMac = epDestMac;
409 if (!(matcherMac.getValue().equals(epDestMac.getValue()))) {
410 Action setDlSrc = setDlSrcAction(destSubnetGatewayMac);
411 l3ApplyActions.add(setDlSrc);
413 l3ApplyActions.add(setDlDstAction(epDestMac));
414 l3ApplyActions.add(decNwTtlAction());
418 Action tunnelDestinationAction;
419 if (tunDst != null && tunDst.getIpv4Address() != null) {
420 tunnelDestinationAction = nxLoadTunIPv4Action(tunDst.getIpv4Address().getValue(), false);
421 } else if (tunDst != null && tunDst.getIpv6Address() != null) {
422 LOG.error("IPv6 tunnel destination {} for {} not supported", tunDst.getIpv6Address().getValue(), nodeId);
425 LOG.error("Tunnel IP for {} invalid", nodeId);
430 port = getOfPortNum(connectorId);
431 } catch (NumberFormatException ex) {
432 LOG.warn("Could not parse port number {}", connectorId, ex);
435 List<Action> applyActions = new ArrayList<>();
436 applyActions.add(nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(ordinals.getEpgId())));
437 applyActions.add(nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(ordinals.getCgId())));
438 applyActions.add(nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(port)));
439 applyActions.add(tunnelDestinationAction);
440 applyActions.addAll(l3ApplyActions);
443 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
444 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
446 Instruction gotoTable = new InstructionBuilder().setOrder(order)
447 .setInstruction(gotoTableIns(goToTable))
450 ArrayList<Instruction> l3instructions = new ArrayList<>();
451 l3instructions.add(applyActionsIns);
452 l3instructions.add(gotoTable);
454 Layer3Match layer3Match;
457 if (destL3Address.getIpAddress().getIpv4Address() != null) {
458 ikey = destL3Address.getIpAddress().getIpv4Address().getValue() + "/32";
460 layer3Match = new Ipv4MatchBuilder().setIpv4Destination(new Ipv4Prefix(ikey)).build();
462 ikey = destL3Address.getIpAddress().getIpv6Address().getValue() + "/128";
464 layer3Match = new Ipv6MatchBuilder().setIpv6Destination(new Ipv6Prefix(ikey)).build();
466 MatchBuilder matchBuilder = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMac, etherType))
467 .setLayer3Match(layer3Match);
468 addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg6.class, (long) ordinals.getL3Id()));
469 Match match = matchBuilder.build();
470 FlowId flowid = FlowIdUtils.newFlowId(tableId, "remoteL3", match);
471 FlowBuilder flowBuilder = base(tableId).setId(flowid)
472 .setPriority(priority)
474 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
475 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
479 * Creates arp flow using virtual router IP in {@link Subnet}
481 * @param priority of the flow
482 * @param indexedTenant of the {@link Endpoint}
483 * @param subnet entries get from peer's tenants
484 * @param ofWriter flow writer
485 * @throws Exception could be thrown during {@link OrdinalFactory#getContextOrdinal(TenantId, UniqueId)}. Handled
486 * in {@link DestinationMapper#syncArpFlow(DestinationMapperFlows, TenantId, OfWriter)}
488 void createRouterArpFlow(int priority, IndexedTenant indexedTenant, Subnet subnet, OfWriter ofWriter)
490 Tenant tenant = indexedTenant.getTenant();
491 if (tenant != null) {
492 L3Context l3Context = utils.getL3ContextForSubnet(indexedTenant, subnet);
493 if (l3Context != null) {
494 int contextOrdinal = OrdinalFactory.getContextOrdinal(tenant.getId(), l3Context.getId());
495 MacAddress routerMac = utils.routerPortMac(l3Context, subnet.getVirtualRouterIp(),
496 indexedTenant.getTenant().getId());
497 if (routerMac != null) {
498 if (subnet.getVirtualRouterIp().getIpv4Address() == null
499 && subnet.getVirtualRouterIp().getIpv6Address() != null) {
500 LOG.warn("IPv6 virtual router {} for subnet {} not supported", subnet.getVirtualRouterIp(), subnet.getId()
504 String ipv4Value = subnet.getVirtualRouterIp().getIpv4Address().getValue();
505 BigInteger intRouterMac = new BigInteger(1, bytesFromHexString(routerMac.getValue()));
506 MatchBuilder matchBuilder = new MatchBuilder()
507 .setEthernetMatch(ethernetMatch(null, null, ARP))
508 .setLayer3Match(new ArpMatchBuilder()
510 .setArpTargetTransportAddress(new Ipv4Prefix(ipv4Value + "/32"))
512 addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg6.class, (long) contextOrdinal));
513 Match match = matchBuilder.build();
514 FlowId flowId = FlowIdUtils.newFlowId(tableId, "routerarp", match);
515 FlowBuilder flowBuilder = base(tableId).setPriority(priority)
518 .setInstructions(instructions(applyActionIns(nxMoveEthSrcToEthDstAction(),
519 setDlSrcAction(routerMac), nxLoadArpOpAction(BigInteger.valueOf(2L)),
520 nxMoveArpShaToArpThaAction(), nxLoadArpShaAction(intRouterMac),
521 nxMoveArpSpaToArpTpaAction(), nxLoadArpSpaAction(ipv4Value),
522 outputAction(new NodeConnectorId(nodeId.getValue() + ":INPORT")))));
523 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
526 LOG.error("No L3 Context found associated with subnet {}.", subnet.getId());
532 * Broadcast flow for destination mapper
534 * @param priority of the flow
535 * @param ordinals of the endpoint (input parameter in {@link DestinationMapper#sync(Endpoint, OfWriter)})
536 * @param mac address of the multicast router {@link DestinationMapper#MULTICAST_MAC}
537 * @param ofWriter flow writer
539 void createBroadcastFlow(int priority, OrdinalFactory.EndpointFwdCtxOrdinals ordinals, MacAddress mac,
541 MatchBuilder matchBuilder = new MatchBuilder()
542 .setEthernetMatch(new EthernetMatchBuilder()
543 .setEthernetDestination(new EthernetDestinationBuilder().setAddress(mac).setMask(mac).build())
545 addNxRegMatch(matchBuilder, FlowUtils.RegMatch.of(NxmNxReg5.class, (long) ordinals.getFdId()));
546 Match match = matchBuilder.build();
547 FlowId flowId = FlowIdUtils.newFlowId(tableId, "broadcast", match);
548 FlowBuilder flowBuilder = base(tableId)
549 .setPriority(priority)
552 .setInstructions(instructions(applyActionIns(nxLoadTunIdAction(BigInteger
553 .valueOf(ordinals.getFdId()), false), groupAction((long) ordinals.getFdId()))));
554 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
558 * L3 prefix flow is created with endpoint {@link NodeConnectorId} if internal. If endpoint is external and
559 * external ports are present, one flow per external port is created
561 * @param goToTable policy enforcer table Id
562 * @param priority of the flow
563 * @param gatewayEp L2 endpoint, should contain {@link MacAddress} and {@link OrdinalFactory.EndpointFwdCtxOrdinals}
564 * @param l3Prefix endpoint L3 prefix value
565 * @param tenant value get from {@link L3Prefix}
566 * @param localSubnet value where this node is present
567 * @param externalPorts list of all external ports
568 * @param ofWriter flow writer
570 void createL3PrefixFlow(short goToTable, int priority, Endpoint gatewayEp, EndpointL3Prefix l3Prefix, IndexedTenant tenant,
571 Subnet localSubnet, Set<NodeConnectorId> externalPorts, OfWriter ofWriter) {
572 L3Context l3Context = utils.getL3ContextForSubnet(tenant, localSubnet);
573 if (l3Context != null && localSubnet.getVirtualRouterIp() != null) {
574 MacAddress matcherMacAddress = utils.routerPortMac(l3Context, localSubnet.getVirtualRouterIp(),
575 tenant.getTenant().getId());
576 OfOverlayContext context = gatewayEp.getAugmentation(OfOverlayContext.class);
577 if (EndpointManager.isInternal(gatewayEp, tenant.getExternalImplicitGroups())) {
578 Preconditions.checkNotNull(context.getNodeConnectorId());
580 Long port = getOfPortNum(context.getNodeConnectorId());
581 if(matcherMacAddress != null) {
582 writeL3PrefixFlow(priority, goToTable, gatewayEp, l3Prefix, port, matcherMacAddress, ofWriter);
584 } catch (NumberFormatException e) {
585 LOG.warn("Could not parse port number {}", context.getNodeConnectorId());
588 for (NodeConnectorId externalPort : externalPorts) {
590 Long port = getOfPortNum(externalPort);
591 if(matcherMacAddress != null) {
592 writeL3PrefixFlow(priority, goToTable, gatewayEp, l3Prefix, port, matcherMacAddress, ofWriter);
594 } catch (NumberFormatException e) {
595 LOG.warn("Could not parse port number {}", externalPort);
602 private void writeExternalL2Flow(short goToTable, int priority, OrdinalFactory.EndpointFwdCtxOrdinals ordinals,
603 Long port, Match match, OfWriter ofWriter) {
604 List<Action> applyActions = new ArrayList<>();
605 applyActions.add(nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(ordinals.getEpgId())));
606 applyActions.add(nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(ordinals.getCgId())));
607 applyActions.add(nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(port)));
610 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
611 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
613 Instruction gotoTable = new InstructionBuilder().setOrder(order)
614 .setInstruction(gotoTableIns(goToTable))
617 ArrayList<Instruction> instructions = new ArrayList<>();
618 instructions.add(applyActionsIns);
619 instructions.add(gotoTable);
621 FlowId flowId = FlowIdUtils.newFlowId(tableId, "externalL2", match);
622 FlowBuilder flowBuilder = base(tableId).setId(flowId)
623 .setPriority(priority)
625 .setInstructions(new InstructionsBuilder().setInstruction(instructions).build());
626 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
629 private void writeExternalL3RoutedFlow(short goToTable, int priority, long port, Endpoint l2GatewayEp, Match match,
630 OrdinalFactory.EndpointFwdCtxOrdinals peerOrdinals, OfWriter ofWriter) {
631 MacAddress destSubnetGatewayMac = l2GatewayEp.getMacAddress();
633 List<Action> l3ApplyActions = new ArrayList<>();
634 l3ApplyActions.add(setDlSrcAction(destSubnetGatewayMac));
635 l3ApplyActions.add(setDlDstAction(l2GatewayEp.getMacAddress()));
637 List<Action> applyActions = new ArrayList<>();
638 applyActions.add(nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(peerOrdinals.getEpgId())));
639 applyActions.add(nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(peerOrdinals.getCgId())));
640 applyActions.add(nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(port)));
641 applyActions.addAll(l3ApplyActions);
644 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
645 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
647 Instruction gotoTable = new InstructionBuilder().setOrder(order)
648 .setInstruction(gotoTableIns(goToTable))
650 ArrayList<Instruction> l3instructions = new ArrayList<>();
651 l3instructions.add(applyActionsIns);
652 l3instructions.add(gotoTable);
654 FlowId flowid = FlowIdUtils.newFlowId(tableId, "externalL3", match);
655 FlowBuilder flowBuilder = base(tableId).setId(flowid)
656 .setPriority(priority)
658 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
659 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());
662 private void writeL3PrefixFlow(int priority, short goToTable, Endpoint endpoint, EndpointL3Prefix l3Prefix,
663 Long port, MacAddress matcherMacAddress, OfWriter ofWriter) {
664 MacAddress macAddress = endpoint.getMacAddress();
665 OrdinalFactory.EndpointFwdCtxOrdinals ordinals = utils.getEndpointOrdinals(endpoint);
666 Action setEpgAction = nxLoadRegAction(NxmNxReg2.class, BigInteger.valueOf(ordinals.getEpgId()));
667 Action setCgAction = nxLoadRegAction(NxmNxReg3.class, BigInteger.valueOf(ordinals.getCgId()));
669 List<Action> l3ApplyActions = new ArrayList<>();
670 l3ApplyActions.add(setDlDstAction(macAddress));
671 l3ApplyActions.add(decNwTtlAction());
672 List<Action> applyActions = new ArrayList<>();
673 applyActions.add(setEpgAction);
674 applyActions.add(setCgAction);
675 applyActions.add(nxLoadRegAction(NxmNxReg7.class, BigInteger.valueOf(port)));
676 applyActions.addAll(l3ApplyActions);
679 ArrayList<Instruction> l3instructions = new ArrayList<>();
680 Instruction applyActionsIns = new InstructionBuilder().setOrder(order++)
681 .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
683 Instruction gotoTable = new InstructionBuilder().setOrder(order)
684 .setInstruction(gotoTableIns(goToTable))
686 l3instructions.add(applyActionsIns);
687 l3instructions.add(gotoTable);
689 if(l3Prefix.getIpPrefix() != null) {
691 Integer prefixLength;
692 if (l3Prefix.getIpPrefix().getIpv4Prefix() != null) {
694 prefixLength = Integer.valueOf(l3Prefix.getIpPrefix().getIpv4Prefix().getValue().split("/")[1]);
695 } else if (l3Prefix.getIpPrefix().getIpv6Prefix() != null) {
697 prefixLength = Integer.valueOf(l3Prefix.getIpPrefix().getIpv6Prefix().getValue().split("/")[1]);
699 LOG.error("Endpoint has IPAddress that is not recognised as either IPv4 or IPv6.", l3Prefix);
702 MatchBuilder matchBuilder = new MatchBuilder().setEthernetMatch(ethernetMatch(null, matcherMacAddress, etherType));
703 addNxRegMatch(matchBuilder, RegMatch.of(NxmNxReg6.class, (long) ordinals.getL3Id()));
704 Match match = matchBuilder.build();
706 FlowId flowid = FlowIdUtils.newFlowId(tableId, "L3prefix", match);
707 FlowBuilder flowBuilder = base(tableId).setId(flowid)
708 .setPriority(priority + prefixLength)
710 .setInstructions(new InstructionsBuilder().setInstruction(l3instructions).build());
711 ofWriter.writeFlow(nodeId, tableId, flowBuilder.build());