Saurav Das

Getting router interface config into the corsa dataplane pipeline

Change-Id: I67d5bf7a20190b07a7bf55c7b60f771877ca8dbb
......@@ -46,5 +46,11 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-app-config</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
......
......@@ -20,6 +20,7 @@ import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -29,6 +30,7 @@ import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.DeviceId;
......@@ -41,6 +43,7 @@ import org.onosproject.net.flow.FlowRuleOperationsContext;
import org.onosproject.net.flow.FlowRuleService;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.FlowRule.Type;
import org.onosproject.net.group.DefaultGroupBucket;
import org.onosproject.net.group.DefaultGroupDescription;
import org.onosproject.net.group.Group;
......@@ -51,19 +54,24 @@ import org.onosproject.net.group.GroupEvent;
import org.onosproject.net.group.GroupKey;
import org.onosproject.net.group.GroupListener;
import org.onosproject.net.group.GroupService;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.packet.PacketService;
import org.onosproject.routing.FibEntry;
import org.onosproject.routing.FibListener;
import org.onosproject.routing.FibUpdate;
import org.onosproject.routing.RoutingService;
import org.onosproject.routing.config.BgpSpeaker;
import org.onosproject.routing.config.Interface;
import org.onosproject.routing.config.RoutingConfigurationService;
import org.onosproject.config.NetworkConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* BgpRouter component.
......@@ -95,6 +103,14 @@ public class BgpRouter {
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
//
// NOTE: Unused reference - needed to guarantee that the
// NetworkConfigReader component is activated and the network configuration
// is read.
//
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected NetworkConfigService networkConfigService;
private ApplicationId appId;
// Reference count for how many times a next hop is used by a route
......@@ -109,7 +125,12 @@ public class BgpRouter {
// Stores FIB updates that are waiting for groups to be set up
private final Multimap<GroupKey, FibEntry> pendingUpdates = HashMultimap.create();
private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001"); // TODO config
// Device id of data-plane switch - should be learned from config
private DeviceId deviceId;
// Device id of control-plane switch (OVS) connected to BGP Speaker - should be
// learned from config
private DeviceId ctrlDeviceId;
private final GroupListener groupListener = new InternalGroupListener();
......@@ -120,10 +141,11 @@ public class BgpRouter {
@Activate
protected void activate() {
appId = coreService.registerApplication(BGP_ROUTER_APP);
getDeviceConfiguration(configService.getBgpSpeakers());
groupService.addListener(groupListener);
provisionStaticTables.provision(true);
provisionStaticTables.provision(true, configService.getInterfaces());
connectivityManager = new TunnellingConnectivityManager(appId,
configService,
......@@ -140,13 +162,31 @@ public class BgpRouter {
protected void deactivate() {
routingService.stop();
connectivityManager.stop();
provisionStaticTables.provision(false);
provisionStaticTables.provision(false, configService.getInterfaces());
groupService.removeListener(groupListener);
log.info("BgpRouter stopped");
}
private void getDeviceConfiguration(Map<String, BgpSpeaker> bgps) {
if (bgps == null || bgps.values().isEmpty()) {
log.error("BGP speakers configuration is missing");
return;
}
for (BgpSpeaker s : bgps.values()) {
ctrlDeviceId = s.connectPoint().deviceId();
if (s.interfaceAddresses() == null || s.interfaceAddresses().isEmpty()) {
log.error("BGP Router must have interfaces configured");
return;
}
deviceId = s.interfaceAddresses().get(0).connectPoint().deviceId();
break;
}
log.info("Router dpid: {}", deviceId);
log.info("Control Plane OVS dpid: {}", ctrlDeviceId);
}
private void updateFibEntry(Collection<FibUpdate> updates) {
for (FibUpdate update : updates) {
FibEntry entry = update.entry();
......@@ -279,9 +319,13 @@ public class BgpRouter {
private static final int CONTROLLER_PRIORITY = 255;
private static final int DROP_PRIORITY = 0;
private static final int HIGHEST_PRIORITY = 0xffff;
private Set<InterfaceIpAddress> intfIps = new HashSet<InterfaceIpAddress>();
private Set<MacAddress> intfMacs = new HashSet<MacAddress>();
private Set<VlanId> intfVlans = new HashSet<VlanId>();
public void provision(boolean install) {
public void provision(boolean install, Set<Interface> intfs) {
getIntefaceConfig(intfs);
processTableZero(install);
processTableOne(install);
processTableTwo(install);
......@@ -292,10 +336,20 @@ public class BgpRouter {
}
private void getIntefaceConfig(Set<Interface> intfs) {
log.info("Processing {} router interfaces", intfs.size());
for (Interface intf : intfs) {
intfIps.addAll(intf.ipAddresses());
intfMacs.add(intf.mac());
intfVlans.add(intf.vlan());
}
}
private void processTableZero(boolean install) {
TrafficSelector.Builder selector;
TrafficTreatment.Builder treatment;
// Bcast rule
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
......@@ -311,6 +365,23 @@ public class BgpRouter {
ops = install ? ops.add(rule) : ops.remove(rule);
// Interface MACs
for (MacAddress mac : intfMacs) {
log.debug("adding rule for MAC: {}", mac);
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
selector.matchEthDst(mac);
treatment.transition(FlowRule.Type.VLAN_MPLS);
rule = new DefaultFlowRule(deviceId, selector.build(),
treatment.build(),
CONTROLLER_PRIORITY, appId, 0,
true, FlowRule.Type.FIRST);
ops = install ? ops.add(rule) : ops.remove(rule);
}
//Drop rule
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
......@@ -404,13 +475,31 @@ public class BgpRouter {
}
private void processTableTwo(boolean install) {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment
.builder();
TrafficSelector.Builder selector;
TrafficTreatment.Builder treatment;
FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
FlowRule rule;
//Interface Vlans
for (VlanId vid : intfVlans) {
log.debug("adding rule for VLAN: {}", vid);
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
selector.matchVlanId(vid);
treatment.popVlan();
treatment.transition(Type.ETHER);
rule = new DefaultFlowRule(deviceId, selector.build(),
treatment.build(), CONTROLLER_PRIORITY, appId,
0, true, FlowRule.Type.VLAN);
ops = install ? ops.add(rule) : ops.remove(rule);
}
//Drop rule
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
treatment.drop();
......@@ -517,13 +606,33 @@ public class BgpRouter {
}
private void processTableSix(boolean install) {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment
.builder();
TrafficSelector.Builder selector;
TrafficTreatment.Builder treatment;
FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
FlowRule rule;
//Interface IPs
for (InterfaceIpAddress ipAddr : intfIps) {
log.debug("adding rule for IPs: {}", ipAddr.ipAddress());
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
selector.matchEthType(Ethernet.TYPE_IPV4);
selector.matchIPDst(IpPrefix.valueOf(ipAddr.ipAddress(), 32));
treatment.transition(Type.ACL);
rule = new DefaultFlowRule(deviceId, selector.build(),
treatment.build(), HIGHEST_PRIORITY, appId,
0, true, FlowRule.Type.IP);
ops = install ? ops.add(rule) : ops.remove(rule);
}
//Drop rule
selector = DefaultTrafficSelector.builder();
treatment = DefaultTrafficTreatment.builder();
treatment.drop();
......
......@@ -64,12 +64,11 @@ public class NetworkConfigReader implements NetworkConfigService {
@Activate
protected void activate() {
log.info("Started network config reader");
AddressConfiguration config = readNetworkConfig();
if (config != null) {
applyNetworkConfig(config);
}
log.info("Started network config reader");
}
@Deactivate
......
......@@ -255,6 +255,11 @@ public final class DefaultTrafficTreatment implements TrafficTreatment {
}
@Override
public Builder popVlan() {
return add(Instructions.popVlan());
}
@Override
public TrafficTreatment build() {
//If we are dropping should we just return an empty list?
......
......@@ -205,6 +205,13 @@ public interface TrafficTreatment {
public Builder transition(FlowRule.Type type);
/**
* Pops outermost VLAN tag.
*
* @return a treatment builder.
*/
public Builder popVlan();
/**
* Builds an immutable traffic treatment descriptor.
*
* @return traffic treatment
......
......@@ -255,6 +255,19 @@ public final class Instructions {
return new PushHeaderInstructions(L2SubType.MPLS_POP, etherType);
}
/**
* Creates a vlan header instruction.
* @return a L2 modification.
*/
public static Instruction popVlan() {
return new PopVlanInstruction(L2SubType.VLAN_POP);
}
/**
* Sends the packet to the table described in 'type'.
* @param type
* @return
*/
public static Instruction transition(FlowRule.Type type) {
checkNotNull(type, "Table type cannot be null");
return new TableTypeTransition(type);
......
......@@ -70,8 +70,12 @@ public abstract class L2ModificationInstruction implements Instruction {
/**
* MPLS TTL modification.
*/
DEC_MPLS_TTL
DEC_MPLS_TTL,
/**
* VLAN Pop modification.
*/
VLAN_POP
}
// TODO: Create factory class 'Instructions' that will have various factory
......@@ -269,6 +273,44 @@ public abstract class L2ModificationInstruction implements Instruction {
}
}
/**
* Represents a VLAN POP modification instruction.
*/
public static final class PopVlanInstruction extends L2ModificationInstruction {
private final L2SubType subtype;
PopVlanInstruction(L2SubType subType) {
this.subtype = subType;
}
@Override
public L2SubType subtype() {
return subtype;
}
@Override
public String toString() {
return toStringHelper(subtype().toString())
.toString();
}
@Override
public int hashCode() {
return Objects.hash(type(), subtype);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof PushHeaderInstructions) {
PushHeaderInstructions that = (PushHeaderInstructions) obj;
return Objects.equals(subtype, that.subtype);
}
return false;
}
}
/**
* Represents a MPLS label modification.
......
......@@ -89,6 +89,7 @@ public class OFCorsaSwitchDriver extends AbstractOpenFlowSwitch {
@Override
public void transformAndSendMsg(OFMessage msg, TableType type) {
log.trace("Trying to send {} of TableType {}", msg, type);
if (msg.getType() == OFType.FLOW_MOD) {
OFFlowMod flowMod = (OFFlowMod) msg;
OFFlowMod.Builder builder = flowMod.createBuilder();
......
......@@ -265,10 +265,12 @@ public class FlowEntryBuilder {
OFActionGroup group = (OFActionGroup) act;
builder.group(new DefaultGroupId(group.getGroup().getGroupNumber()));
break;
case POP_VLAN:
builder.popVlan();
break;
case SET_TP_DST:
case SET_TP_SRC:
case POP_PBB:
case POP_VLAN:
case PUSH_PBB:
case PUSH_VLAN:
case SET_MPLS_LABEL:
......
......@@ -327,6 +327,8 @@ public class FlowModBuilderVer13 extends FlowModBuilder {
break;
case DEC_MPLS_TTL:
return factory().actions().decMplsTtl();
case VLAN_POP:
return factory().actions().popVlan();
default:
log.warn("Unimplemented action type {}.", l2m.subtype());
break;
......