今天會有簡易的SFC(Service Function Chain)範例,也會簡單的介紹SFC是什麼。
SFC(Service Function Chain),指的是一個數據流需要通過多個網絡服務設備,而這多個網路服務設備可以做一些像是防火牆、IDS/IPS等等防護措施。
關於pom的部分我就不多介紹了,後面會放github,只單純紀錄function的部分。
主要部分為activie()以及deactivate()部分,我將SFC部分做一個class,所以這邊只有做創建以及刪除部分。另外要注意的便是getAppId部分,這裡的ID為Pom內的onos.app.name值。
@Activate
protected void activate() {
log.info("Started============================");
appId = coreService.getAppId("test123"); //equal to the name shown in pom.xml file
// app id
mSFCWorking = new SFCWorking(flowRuleService, appId, hostService,
deviceService, topologyService, groupService, meterService, meterStore,packetService);
// add packet processor
packetService.addProcessor(mSFCWorking, PacketProcessor.director(3));
packetService.requestPackets(DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4).build(), PacketPriority.REACTIVE, appId, Optional.empty());
}
/**
* Deactivates the processor by removing it.
*/
@Deactivate
protected void deactivate() {
log.info("Stopped");
for (GroupDescription description : descriptionArrayList) {
log.info("remove {} ", description);
groupService.removeGroup(description.deviceId(), description.appCookie(), appId);
}
flowRuleService.removeFlowRulesById(AppComponent.appId);
packetService.removeProcessor(mSFCWorking);
}
CoreService: 控制器的核心系統溝通的功能。
FlowRuleService: 將Flow規則部署到環境中,也可以獲得當前的規則訊息。
PacketService:能獲取Data Plane的封包與直接發送封包到目標port。
packetService:對封包通道做設定。
在這次的範例中,我將ip寫為固定的,也只有一條chain,測試方式也只有使用ping去做測試,因此看到這發現不是需要的可以跳過了。
這裡主要部分為
initMacTable:將一般switch上紀錄mac表實作出來,macTables變數會將switch上的來源的mac與來源port記錄起來。
actLikeSwitch:將封包送到目標port,並且建立新的Flow規則。
runSFC:設定SFC規則,這裡的規則優先權會大於剛剛建立的,因此會跑這邊的規則。
#process會再有封包時就會開始執行
@Override
public void process(PacketContext packetContext) {
log.info("------------------------------------------------------");
initMacTable(packetContext.inPacket().receivedFrom());
//registerMeter這部分可以限制傳輸速度,不過由於只是測試SFC,因此註解。
// registerMeter(packetContext);
actLikeSwitchforSFC(packetContext);
runSFC(packetContext);
// processSFC(packetContext);
}
actLikeSwitchforSFC部分,我會建立一個簡單的轉發規則,其規則的優先度為10,如果都沒有run這個規則,5秒後便會消失,這單純透過mac以及目的地port去做轉發。
private void actLikeSwitchforSFC(PacketContext packetContext) {
Ethernet ethernet = packetContext.inPacket().parsed();
log.info("actLikeSwitchforSFC----------------" + ethernet.getEtherType());
short type = ethernet.getEtherType();
if (type != Ethernet.TYPE_IPV4 && type != Ethernet.TYPE_ARP) {
return;
}
ConnectPoint connectPoint = packetContext.inPacket().receivedFrom();
Map<MacAddress, PortNumber> macTable = macTables.get(connectPoint.deviceId());
MacAddress srcMac = ethernet.getSourceMAC();
MacAddress dstMac = ethernet.getDestinationMAC();
macTable.put(srcMac, connectPoint.port());
PortNumber outPort = macTable.get(dstMac);
if (outPort != null) {
if (type == Ethernet.TYPE_IPV4) {
IPv4 iPv4 = (IPv4) ethernet.getPayload();
TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
.matchEthSrc(srcMac)
.matchEthDst(dstMac)
.build();
createFlowRule(trafficSelector,
createTrafficTreatment(null, outPort),
connectPoint.deviceId());
} else {
packetContext.treatmentBuilder().setOutput(outPort);
packetContext.send();
}
} else {
actLikeHub(packetContext);
}
}
private int Temporary = 5;
private void createFlowRule(TrafficSelector trafficSelector, TrafficTreatment trafficTreatment, DeviceId deviceId) {
FlowRule flowRule = DefaultFlowRule.builder()
.fromApp(appId)
.withSelector(trafficSelector)
.withTreatment(trafficTreatment)
.forDevice(deviceId)
.withPriority(10)
.makeTemporary(Temporary)
.build();
flowRuleService.applyFlowRules(flowRule);
}
runSFC部分,我會重新建立一個SFC的規則,其優先度為50,由於高於剛剛所建立的規則,因此若有通,則會跑這個規則。
private void runSFC(PacketContext packetContext) {
if (packetContext.inPacket().parsed().getEtherType() != Ethernet.TYPE_IPV4) return;
ArrayList<String> ipArrayListforReturnRoute = new ArrayList<>(ipArrayList);
Collections.reverse(ipArrayListforReturnRoute);
addTag(flowRuleService, packetContext, ipArrayList, false);
}
private void addTag(FlowRuleService flowRuleService, PacketContext packetContext, ArrayList<String> ipArrayListforAddTag, boolean isReverse) {
new Thread(() -> {
Ethernet ethernet = packetContext.inPacket().parsed();
IPv4 iPv4 = (IPv4) ethernet.getPayload();
int sfId = 0;
log.info("ipArrayListforAddTag:"+ipArrayListforAddTag);
for (int position = 0; position < ipArrayListforAddTag.size() - 1; position++) {
String currentIp = ipArrayListforAddTag.get(position);
String nextIp = ipArrayListforAddTag.get(position + 1);
MplsLabel mplsLabel;
MacAddress ethDst;
IpPrefix iPDst;
if (isReverse) {
mplsLabel = MplsLabel.mplsLabel(1048575 - sfId);
ethDst = ethernet.getSourceMAC();
IpAddress dstIpAddress = IpAddress.valueOf(iPv4.getDestinationAddress());
iPDst = dstIpAddress.toIpPrefix();
} else {
mplsLabel = MplsLabel.mplsLabel(sfId);
ethDst = ethernet.getDestinationMAC();
IpAddress dstIpAddress = IpAddress.valueOf(iPv4.getDestinationAddress());
iPDst = dstIpAddress.toIpPrefix();
}
//currentIpAddress
IpAddress ipAddress = IpAddress.valueOf(currentIp);
TrafficTreatment trafficTreatment = DefaultTrafficTreatment.builder()
.pushMpls()
.setMpls(mplsLabel)
.transition(1)
.build();
FlowRule flowRule = DefaultFlowRule.builder()
.withSelector(DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchEthDst(ethDst)
.matchEthSrc(sfcList.get(ipAddress))
.matchIPDst(iPDst)
.build())
.withTreatment(trafficTreatment)
.forDevice(packetContext.inPacket().receivedFrom().deviceId())
.fromApp(AppComponent.appId)
.makeTemporary(Temporary)
.withPriority(50)
.forTable(0)
.build();
log.info("-----addTagaddTagaddTag------" + flowRule.toString());
flowRuleService.applyFlowRules(flowRule);
processSfcFlowRule(packetContext, IpAddress.valueOf(currentIp), IpAddress.valueOf(nextIp), mplsLabel, isReverse, sfId);
sfId++;
}
}).start();
}
將app放入onos中之後執行mininet指令。
注意要將openFlow打開
sudo mn --controller=remote,ip=<control ip> --mac --topo=single,3 --switch ovsk,protocols=OpenFlow13
將中介部分(也就是h2)開放傳封包到其他機器上的功能。
h2 cat /proc/sys/net/ipv4/ip_forward
0 #表示沒開,反之1表示有
h2 echo 1 > /proc/sys/net/ipv4/ip_forward
在mininet內輸入(如果沒ping通請確認程式或是看ONOS log看看有沒有找到h1~h3三個裝置的mac,如果沒有,有機會要刪除onos server再重開,這我有遇到過。)
h1 ping h3
到onos看規則是否有成立(會先看到優先度為10的,之後會生成50的,過一段時間50的如果有留著代表有成功,此處只有h1->h2->h3,h3->h1),所以會注意到,來源為01目的地為03的10優先度規則會消失。
到這裡表示簡單的SFC功能完成了,此處只有簡單的ping去做驗證,通過查看SDN內的規則來做確認。
git部分
ps:git clone的時候記得把target部分刪除,這是build才會出來的。