package org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow;
+import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.PolicyManager.Dirty;
+import org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.RegMatch;
import org.opendaylight.groupbasedpolicy.resolver.ConditionGroup;
import org.opendaylight.groupbasedpolicy.resolver.EgKey;
+import org.opendaylight.groupbasedpolicy.resolver.IndexedTenant;
import org.opendaylight.groupbasedpolicy.resolver.PolicyInfo;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.endpoint.rev140421.endpoints.Endpoint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.EndpointLocation.LocationType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.ofoverlay.rev140528.OfOverlayContext;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.EndpointGroup;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2BridgeDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L2FloodDomain;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.L3Context;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.Subnet;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetDestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Layer3Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv6MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg0;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg2;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg3;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg5;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg6;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflowjava.nx.match.rev140421.NxmNxReg7;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Sets;
+import static org.opendaylight.groupbasedpolicy.renderer.ofoverlay.flow.FlowUtils.*;
+
/**
* Manage the table that maps the destination address to the next hop
* for the path as well as applies any relevant routing transformations.
*/
public static final MacAddress ROUTER_MAC =
new MacAddress("88:f0:31:b5:12:b5");
+ public static final MacAddress MULTICAST_MAC =
+ new MacAddress("01:00:00:00:00:00");
public DestinationMapper(OfTable.OfTableCtx ctx) {
super(ctx);
dropFlow(t, tiid, flowMap, Integer.valueOf(1), null);
HashSet<EgKey> visitedEgs = new HashSet<>();
+ HashSet<Integer> visitedFds = new HashSet<>();
+
for (EgKey epg : ctx.epManager.getGroupsForNode(nodeId)) {
Set<EgKey> peers = Sets.union(Collections.singleton(epg),
policyInfo.getPeers(epg));
for (EgKey peer : peers) {
syncEPG(t, tiid, flowMap, nodeId,
- policyInfo, peer, visitedEgs);
+ policyInfo, peer,
+ visitedEgs, visitedFds);
}
}
}
Map<String, FlowCtx> flowMap,
NodeId nodeId, PolicyInfo policyInfo,
EgKey key,
- HashSet<EgKey> visitedEgs) throws Exception {
+ HashSet<EgKey> visitedEgs,
+ HashSet<Integer> visitedFds) throws Exception {
if (visitedEgs.contains(key)) return;
visitedEgs.add(key);
+ IndexedTenant tenant = ctx.policyResolver.getTenant(key.getTenantId());
+ EndpointGroup eg = tenant.getEndpointGroup(key.getEgId());
+ L2FloodDomain fd = tenant.resolveL2FloodDomain(eg.getNetworkDomain());
+ Subnet sn = tenant.resolveSubnet(eg.getNetworkDomain());
+ L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
+ int l3Id = 0;
+
+ if (l3c != null)
+ l3Id = ctx.policyManager.getContextOrdinal(key.getTenantId(),
+ l3c.getId());
+
Collection<Endpoint> egEps = ctx.epManager
.getEndpointsForGroup(key);
+
for (Endpoint e : egEps) {
if (e.getTenant() == null || e.getEndpointGroup() == null)
continue;
OfOverlayContext ofc = e.getAugmentation(OfOverlayContext.class);
if (ofc == null || ofc.getNodeId() == null) continue;
- syncEP(t, tiid, flowMap, nodeId, policyInfo, e, ofc, key);
+ syncEP(t, tiid, flowMap, nodeId, policyInfo, e, ofc, tenant, key);
+ }
+
+ if (fd == null) return;
+ Integer fdId = ctx.policyManager.getContextOrdinal(key.getTenantId(),
+ fd.getId());
+ if (visitedFds.contains(fdId)) return;
+ visitedFds.add(fdId);
+
+ FlowId flowId = new FlowId(new StringBuilder()
+ .append("broadcast|")
+ .append(fdId).toString());
+ if (visit(flowMap, flowId.getValue())) {
+ MatchBuilder mb = new MatchBuilder()
+ .setEthernetMatch(new EthernetMatchBuilder()
+ .setEthernetDestination(new EthernetDestinationBuilder()
+ .setAddress(MULTICAST_MAC)
+ .setMask(MULTICAST_MAC)
+ .build())
+ .build());
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg5.class,Long.valueOf(fdId)));
+
+ FlowBuilder flow = base()
+ .setPriority(Integer.valueOf(140))
+ .setId(flowId)
+ .setMatch(mb.build())
+ .setInstructions(instructions(applyActionIns(nxMoveRegTunIdAction(NxmNxReg0.class, false),
+ groupAction(Long.valueOf(fdId)))));
+ writeFlow(t, tiid, flow.build());
+ }
+
+ if (sn != null && sn.getVirtualRouterIp() != null) {
+ if (sn.getVirtualRouterIp().getIpv4Address() != null) {
+ String ikey = sn.getVirtualRouterIp().getIpv4Address().getValue();
+ flowId = new FlowId(new StringBuffer()
+ .append("routerarp|")
+ .append(sn.getId().getValue())
+ .append("|")
+ .append(ikey)
+ .append("|")
+ .append(l3Id)
+ .toString());
+ if (visit(flowMap, flowId.getValue())) {
+ MatchBuilder mb = new MatchBuilder()
+ .setEthernetMatch(ethernetMatch(null, null, ARP))
+ .setLayer3Match(new ArpMatchBuilder()
+ .setArpOp(Integer.valueOf(1))
+ .setArpTargetTransportAddress(new Ipv4Prefix(ikey))
+ .build());
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
+ Long.valueOf(l3Id)));
+ BigInteger routerMac =
+ new BigInteger(1, HexEncode
+ .bytesFromHexString(ROUTER_MAC
+ .getValue()));
+ /* XXX - TODO add output to inport action */
+ FlowBuilder flowb = base()
+ .setPriority(150)
+ .setId(flowId)
+ .setMatch(mb.build())
+ .setInstructions(instructions(applyActionIns(nxMoveEthSrcToEthDstAction(),
+ setDlSrcAction(ROUTER_MAC),
+ nxLoadArpOpAction(BigInteger.valueOf(2L)),
+ nxMoveArpShaToArpThaAction(),
+ nxLoadArpShaAction(routerMac),
+ nxMoveArpSpaToArpTpaAction(),
+ nxLoadArpSpaAction(ikey),
+ outputAction(new NodeConnectorId(nodeId.getValue() + ":INPORT")))));
+ writeFlow(t, tiid, flowb.build());
+ }
+ } else {
+ LOG.warn("IPv6 virtual router {} for subnet {} not supported",
+ sn.getVirtualRouterIp(), sn.getId().getValue());
+ }
}
}
Map<String, FlowCtx> flowMap,
NodeId nodeId, PolicyInfo policyInfo,
Endpoint e, OfOverlayContext ofc,
- EgKey key)
+ IndexedTenant tenant, EgKey key)
throws Exception {
-
ArrayList<Instruction> instructions = new ArrayList<>();
ArrayList<Instruction> l3instructions = new ArrayList<>();
+ List<Action> applyActions = new ArrayList<>();
+ List<Action> l3ApplyActions = new ArrayList<>();
+
int order = 0;
+ EndpointGroup eg = tenant.getEndpointGroup(e.getEndpointGroup());
+ L3Context l3c = tenant.resolveL3Context(eg.getNetworkDomain());
+ L2BridgeDomain bd = tenant.resolveL2BridgeDomain(eg.getNetworkDomain());
+
+ int egId = 0, bdId = 0, l3Id = 0, cgId = 0;
+
+ egId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+ e.getEndpointGroup());
+ if (bd != null)
+ bdId = ctx.policyManager.getContextOrdinal(e.getTenant(),
+ bd.getId());
+ if (l3c != null)
+ l3Id = ctx.policyManager.getContextOrdinal(e.getTenant(),
+ l3c.getId());
+ List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
+ ConditionGroup cg =
+ policyInfo.getEgCondGroup(new EgKey(e.getTenant(),
+ e.getEndpointGroup()),
+ conds);
+ cgId = ctx.policyManager.getCondGroupOrdinal(cg);
+ Action setdEPG = nxLoadRegAction(NxmNxReg2.class,
+ BigInteger.valueOf(egId));
+ Action setdCG = nxLoadRegAction(NxmNxReg3.class,
+ BigInteger.valueOf(cgId));
+ Action setNextHop;
String nextHop;
if (LocationType.External.equals(ofc.getLocationType())) {
// XXX - TODO - perform NAT and send to the external network
nextHop = "external";
LOG.warn("External endpoints not yet supported");
return;
- } else {
- Action setDlSrc = FlowUtils.setDlSrc(ROUTER_MAC);
- Action setDlDst = FlowUtils.setDlDst(e.getMacAddress());
- Action decTtl = FlowUtils.decNwTtl();
+ } else {
+ Action setDlSrc = setDlSrcAction(ROUTER_MAC);
+ Action decTtl = decNwTtlAction();
if (Objects.equals(ofc.getNodeId(), nodeId)) {
- // this is a local endpoint
+ // this is a local endpoint; send to the approppriate local
+ // port
nextHop = ofc.getNodeConnectorId().getValue();
- // XXX - TODO - instead of outputting, write next hop
- // to a register and output from the policy table
- Action output = FlowUtils.outputAction(ofc.getNodeConnectorId());
+ long portNum;
+ try {
+ portNum = getOfPortNum(ofc.getNodeConnectorId());
+ } catch (NumberFormatException ex) {
+ LOG.warn("Could not parse port number {}",
+ ofc.getNodeConnectorId(), ex);
+ return;
+ }
+
+ setNextHop = nxLoadRegAction(NxmNxReg7.class,
+ BigInteger.valueOf(portNum));
- instructions.add(new InstructionBuilder()
- .setOrder(order)
- .setInstruction(FlowUtils.writeActionIns(output))
- .build());
- l3instructions.add(new InstructionBuilder()
- .setOrder(order)
- .setInstruction(FlowUtils.writeActionIns(setDlSrc,
- setDlDst,
- decTtl,
- output))
- .build());
+ Action setDlDst = setDlDstAction(e.getMacAddress());
+ l3ApplyActions.add(setDlSrc);
+ l3ApplyActions.add(setDlDst);
+ l3ApplyActions.add(decTtl);
order +=1;
} else {
// this endpoint is on a different switch; send to the
if (tunDst == null) return;
if (tunPort == null) return;
+ Action tundstAction;
+
if (tunDst.getIpv4Address() != null) {
nextHop = tunDst.getIpv4Address().getValue();
-
- // XXX - TODO Add action: set tunnel dst to tunDst ipv4
+ tundstAction = nxLoadTunIPv4Action(nextHop, false);
} else if (tunDst.getIpv6Address() != null) {
- nextHop = tunDst.getIpv6Address().getValue();
-
- // XXX - TODO Add action: set tunnel dst to tunDst ipv6
+ // nextHop = tunDst.getIpv6Address().getValue();
+ LOG.error("IPv6 tunnel destination {} for {} not supported",
+ tunDst.getIpv6Address().getValue(),
+ ofc.getNodeId());
+ return;
} else {
// this shouldn't happen
LOG.error("Tunnel IP for {} invalid", ofc.getNodeId());
return;
}
- Action output = FlowUtils.outputAction(tunPort);
+
+ long portNum;
+ try {
+ portNum = getOfPortNum(tunPort);
+ } catch (NumberFormatException ex) {
+ LOG.warn("Could not parse port number {}",
+ ofc.getNodeConnectorId(), ex);
+ return;
+ }
- // XXX - TODO Add action: set tunnel_id from sEPG register
- instructions.add(new InstructionBuilder()
- .setOrder(order)
- .setInstruction(FlowUtils.writeActionIns(output))
- .build());
- l3instructions.add(new InstructionBuilder()
- .setOrder(order)
- .setInstruction(FlowUtils.writeActionIns(setDlSrc,
- decTtl,
- output))
- .build());
+ setNextHop = nxLoadRegAction(NxmNxReg7.class,
+ BigInteger.valueOf(portNum));
+ Action tunIdAction =
+ nxMoveRegTunIdAction(NxmNxReg0.class, false);
+ applyActions.add(tunIdAction);
+ applyActions.add(tundstAction);
+ l3ApplyActions.add(setDlSrc);
+ l3ApplyActions.add(decTtl);
order +=1;
}
}
+ applyActions.add(setdEPG);
+ applyActions.add(setdCG);
+ applyActions.add(setNextHop);
+ Instruction applyActionsIns = new InstructionBuilder()
+ .setOrder(order++)
+ .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
+ .build();
+ instructions.add(applyActionsIns);
+
+ applyActions.addAll(l3ApplyActions);
+ applyActionsIns = new InstructionBuilder()
+ .setOrder(order++)
+ .setInstruction(applyActionIns(applyActions.toArray(new Action[applyActions.size()])))
+ .build();
+ l3instructions.add(applyActionsIns);
- int egId = ctx.policyManager.getContextOrdinal(e.getTenant(),
- e.getEndpointGroup());
- List<ConditionName> conds = ctx.epManager.getCondsForEndpoint(e);
- ConditionGroup cg =
- policyInfo.getEgCondGroup(new EgKey(e.getTenant(),
- e.getEndpointGroup()),
- conds);
- int cgId = ctx.policyManager.getConfGroupOrdinal(cg);
-
- // XXX TODO - add action set dEPG and dCG into registers
Instruction gotoTable = new InstructionBuilder()
.setOrder(order++)
- .setInstruction(FlowUtils.gotoTableIns((short)(getTableId()+1)))
+ .setInstruction(gotoTableIns((short)(getTableId()+1)))
.build();
instructions.add(gotoTable);
l3instructions.add(gotoTable);
FlowId flowid = new FlowId(new StringBuilder()
- .append(e.getL2Context().getValue())
+ .append(bdId)
.append("|l2|")
.append(e.getMacAddress().getValue())
.append("|")
.append(nextHop)
.toString());
if (visit(flowMap, flowid.getValue())) {
- LOG.info("{} deg:{} dcg:{}", e.getMacAddress(), egId, cgId);
- // XXX TODO add match against bridge domain register
+ MatchBuilder mb = new MatchBuilder()
+ .setEthernetMatch(ethernetMatch(null,
+ e.getMacAddress(),
+ null));
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg4.class, Long.valueOf(bdId)));
FlowBuilder flowb = base()
.setId(flowid)
.setPriority(Integer.valueOf(50))
- .setMatch(new MatchBuilder()
- .setEthernetMatch(FlowUtils.ethernetMatch(null,
- e.getMacAddress(),
- null))
- .build())
+ .setMatch(mb.build())
.setInstructions(new InstructionsBuilder()
.setInstruction(instructions)
.build());
String ikey = null;
if (l3a.getIpAddress().getIpv4Address() != null) {
ikey = l3a.getIpAddress().getIpv4Address().getValue();
- etherType = FlowUtils.IPv4;
+ etherType = IPv4;
m = new Ipv4MatchBuilder()
.setIpv4Destination(new Ipv4Prefix(ikey))
.build();
} else if (l3a.getIpAddress().getIpv6Address() != null) {
ikey = l3a.getIpAddress().getIpv6Address().getValue();
- etherType = FlowUtils.IPv6;
+ etherType = IPv6;
m = new Ipv6MatchBuilder()
.setIpv6Destination(new Ipv6Prefix(ikey))
.build();
.append(nextHop)
.toString());
if (visit(flowMap, flowid.getValue())) {
- // XXX TODO add match against routing domain register
-
+ MatchBuilder mb = new MatchBuilder()
+ .setEthernetMatch(ethernetMatch(null,
+ ROUTER_MAC,
+ etherType))
+ .setLayer3Match(m);
+ addNxRegMatch(mb, RegMatch.of(NxmNxReg6.class,
+ Long.valueOf(l3Id)));
FlowBuilder flowb = base()
.setId(flowid)
.setPriority(Integer.valueOf(132))
- .setMatch(new MatchBuilder()
- .setEthernetMatch(FlowUtils.ethernetMatch(null,
- ROUTER_MAC,
- etherType))
- .setLayer3Match(m)
- .build())
+ .setMatch(mb.build())
.setInstructions(new InstructionsBuilder()
.setInstruction(l3instructions)
.build());