Hyunsun Moon
Committed by Gerrit Code Review

CORD-484 Support management network for a VM

Change-Id: I866ae3ae7d839cd29f1732605170f3dfbab402bb
......@@ -38,7 +38,8 @@ public final class CordService {
PRIVATE_DIRECT,
PRIVATE_INDIRECT,
PUBLIC_DIRECT,
PUBLIC_INDIRECT
PUBLIC_INDIRECT,
MANAGEMENT
}
private final CordServiceId id;
......@@ -165,7 +166,7 @@ public final class CordService {
* It assumes that network name contains network type.
*
* @param netName network name
* @return network type, or null if it doesn't match any type
* @return network type, or PRIVATE if it doesn't match any type
*/
private ServiceType getServiceType(String netName) {
checkNotNull(netName);
......@@ -179,10 +180,10 @@ public final class CordService {
return PUBLIC_DIRECT;
} else if (name.contains(PUBLIC_INDIRECT.toString())) {
return PUBLIC_INDIRECT;
} else if (name.contains(PRIVATE.toString())) {
return PRIVATE;
} else if (name.contains(MANAGEMENT.toString())) {
return MANAGEMENT;
} else {
return null;
return PRIVATE;
}
}
}
......
......@@ -403,7 +403,13 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
host.ipAddresses().stream().findFirst().get());
CordService service = getCordService(vNet);
if (service != null) {
if (service == null) {
return;
}
if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
ruleInstaller.populateManagementNetworkRules(host, service);
} else {
// TODO check if the service needs an update on its group buckets after done CORD-433
ruleInstaller.updateServiceGroup(service);
arpProxy.addServiceIp(service.serviceIp());
......@@ -440,7 +446,13 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
ruleInstaller.removeBasicConnectionRules(host);
CordService service = getCordService(vNet);
if (service != null) {
if (service == null) {
return;
}
if (service.serviceType().equals(CordService.ServiceType.MANAGEMENT)) {
ruleInstaller.removeManagementNetworkRules(host, service);
} else {
// TODO check if the service needs an update on its group buckets after done CORD-433
ruleInstaller.updateServiceGroup(service);
......
......@@ -103,10 +103,11 @@ public class CordVtnRuleInstaller {
private static final int TABLE_DST_IP = 4;
private static final int TABLE_TUNNEL_IN = 5;
private static final int MANAGEMENT_PRIORITY = 55000;
private static final int HIGH_PRIORITY = 50000;
private static final int DEFAULT_PRIORITY = 5000;
private static final int LOWER_PRIORITY = 4000;
private static final int LOW_PRIORITY = 4000;
private static final int LOWEST_PRIORITY = 0;
private static final int HIGHER_PRIORITY = 50000;
private static final int VXLAN_UDP_PORT = 4789;
......@@ -387,6 +388,126 @@ public class CordVtnRuleInstaller {
}
/**
* Populates flow rules for management network access.
*
* @param host host which has management network interface
* @param mService management network service
*/
public void populateManagementNetworkRules(Host host, CordService mService) {
checkNotNull(mService);
DeviceId deviceId = host.location().deviceId();
IpAddress hostIp = host.ipAddresses().stream().findFirst().get();
TrafficSelector selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_ARP)
.matchArpTpa(mService.serviceIp().getIp4Address())
.build();
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.LOCAL)
.build();
FlowRule flowRule = DefaultFlowRule.builder()
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(MANAGEMENT_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_FIRST)
.makePermanent()
.build();
processFlowRule(true, flowRule);
selector = DefaultTrafficSelector.builder()
.matchInPort(PortNumber.LOCAL)
.matchEthType(Ethernet.TYPE_ARP)
.matchArpTpa(hostIp.getIp4Address())
.build();
treatment = DefaultTrafficTreatment.builder()
.setOutput(host.location().port())
.build();
flowRule = DefaultFlowRule.builder()
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(MANAGEMENT_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_FIRST)
.makePermanent()
.build();
processFlowRule(true, flowRule);
selector = DefaultTrafficSelector.builder()
.matchInPort(PortNumber.LOCAL)
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(mService.serviceIpRange())
.build();
treatment = DefaultTrafficTreatment.builder()
.transition(TABLE_DST_IP)
.build();
flowRule = DefaultFlowRule.builder()
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(MANAGEMENT_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_FIRST)
.makePermanent()
.build();
processFlowRule(true, flowRule);
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(mService.serviceIp().toIpPrefix())
.build();
treatment = DefaultTrafficTreatment.builder()
.setOutput(PortNumber.LOCAL)
.build();
flowRule = DefaultFlowRule.builder()
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(MANAGEMENT_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_ACCESS_TYPE)
.makePermanent()
.build();
processFlowRule(true, flowRule);
}
/**
* Removes management network access rules.
*
* @param host host to be removed
* @param mService service for management network
*/
public void removeManagementNetworkRules(Host host, CordService mService) {
checkNotNull(mService);
for (FlowRule flowRule : flowRuleService.getFlowRulesById(appId)) {
if (flowRule.deviceId().equals(host.location().deviceId())) {
PortNumber port = getOutputFromTreatment(flowRule);
if (port != null && port.equals(host.location().port())) {
processFlowRule(false, flowRule);
}
}
// TODO remove the other rules if mgmt network is not in use
}
}
/**
* Populates default rules on the first table.
* The rules are for shuttling vxlan-encapped packets and supporting physical
* network connectivity.
......@@ -409,7 +530,7 @@ public class CordVtnRuleInstaller {
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(HIGHER_PRIORITY)
.withPriority(HIGH_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_FIRST)
.makePermanent()
......@@ -433,7 +554,7 @@ public class CordVtnRuleInstaller {
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(HIGHER_PRIORITY)
.withPriority(HIGH_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_FIRST)
.makePermanent()
......@@ -456,7 +577,7 @@ public class CordVtnRuleInstaller {
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(HIGHER_PRIORITY)
.withPriority(HIGH_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_FIRST)
.makePermanent()
......@@ -479,7 +600,7 @@ public class CordVtnRuleInstaller {
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(HIGHER_PRIORITY)
.withPriority(HIGH_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_FIRST)
.makePermanent()
......@@ -633,7 +754,7 @@ public class CordVtnRuleInstaller {
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(LOWER_PRIORITY)
.withPriority(LOW_PRIORITY)
.forDevice(deviceId)
.forTable(TABLE_IN_PORT)
.makePermanent()
......@@ -665,7 +786,7 @@ public class CordVtnRuleInstaller {
.fromApp(appId)
.withSelector(selector)
.withTreatment(treatment)
.withPriority(LOWER_PRIORITY)
.withPriority(LOW_PRIORITY)
.forDevice(device.id())
.forTable(TABLE_ACCESS_TYPE)
.makePermanent()
......@@ -1006,6 +1127,25 @@ public class CordVtnRuleInstaller {
}
/**
* Returns the output port number from a given flow rule.
*
* @param flowRule flow rule
* @return port number, or null if the rule does not have output instruction
*/
private PortNumber getOutputFromTreatment(FlowRule flowRule) {
Instruction instruction = flowRule.treatment().allInstructions().stream()
.filter(inst -> inst instanceof Instructions.OutputInstruction)
.findFirst()
.orElse(null);
if (instruction == null) {
return null;
}
return ((Instructions.OutputInstruction) instruction).port();
}
/**
* Creates a new group for a given service.
*
* @param deviceId device id to create a group
......