Hello!
這次ㄧ樣來追一下程式碼,當作課堂的筆記。這堂課是交通大學的軟體定義網路,蠻有趣的一堂課。
這次主要想追的程式碼是onos中fwd這個app裡的ReactiveForwarding.java這個檔案。有些偷懶的就直接把function的用途寫在上面,不一行行寫註解了。甚至有些作業用不到的function,就直接不寫了,因為這篇還沒打完作業就寫完了,有點懶得繼續下去XDD
Code
完整的code可以看這裡
/**
* Sample reactive forwarding application.
*/
@Component(immediate = true)
@Service(value = ReactiveForwarding.class)
public class ReactiveForwarding {
private static final int DEFAULT_TIMEOUT = 10;
private static final int DEFAULT_PRIORITY = 10;
private final Logger log = getLogger(getClass()); //用於提供網絡拓補信息
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected TopologyService topologyService;
//攔截封包,選擇要攔截哪些封包,或是做哪些動作
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService; //用於與終端主機交互
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowRuleService flowRuleService; //用於新增flow rule
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected FlowObjectiveService flowObjectiveService; //在使用onos的各種服務前,要先向CoreService註冊
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CoreService coreService; //追蹤整個系統各個組件的配置
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ComponentConfigService cfgService; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService; //封包進來的時候,進行處理的handler
private ReactivePacketProcessor processor = new ReactivePacketProcessor(); //metrics:記錄所有host的資訊
private EventuallyConsistentMap<MacAddress, ReactiveForwardMetrics> metrics; //ONOS下,每個app都要有自己的appId
private ApplicationId appId; //一些設定
@Property(name = "packetOutOnly", boolValue = false,
label = "Enable packet-out only forwarding; default is false")
private boolean packetOutOnly = false; @Property(name = "packetOutOfppTable", boolValue = false,
label = "Enable first packet forwarding using OFPP_TABLE port " +"instead of PacketOut with actual port; default is false")
private boolean packetOutOfppTable = false;
.
.
. //Entity capable of receiving network topology related events
private final TopologyListener topologyListener = new InternalTopologyListener();
private ExecutorService blackHoleExecutor; //@Activate - marks a method as the method to call during the component startup routine.
@Activate
public void activate(ComponentContext context) { //一個快速高效的反序列化框架
KryoNamespace.Builder metricSerializer = KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(ReactiveForwardMetrics.class)
.register(MultiValuedTimestamp.class); metrics = storageService.<MacAddress, ReactiveForwardMetrics>eventuallyConsistentMapBuilder()
.withName("metrics-fwd")
.withSerializer(metricSerializer)
.withTimestampProvider((key, metricsData) -> new MultiValuedTimestamp<>(new WallClockTimestamp(), System.nanoTime()))
.build(); //topology有改變的話,就可以call(?) blackHoleExecutor = newSingleThreadExecutor(groupedThreads("onos/app/fwd",
"black-hole-fixer",
log)); //追蹤整個系統各個組件的配置
cfgService.registerProperties(getClass()); //註冊appId
appId = coreService.registerApplication("org.onosproject.fwd"); //ReactivePacketProcessor(這裡的變數是processor).process裡定義了接收到封包要做什麼動作
packetService.addProcessor(processor, PacketProcessor.director(2));
//當拓墣改變的話,會呼叫
topologyService.addListener(topologyListener); //In this way the application components can continue to use the standard and well-understood OSGi configuration via ComponentContext.
readComponentConfiguration(context); //想要攔截哪些種類的封包
requestIntercepts(); log.info("Started", appId.id());
} /**
* Request packet in via packet service.
*
* 在擷取的時候,指定想要擷取哪些封包
*/
private void requestIntercepts() {
//Abstraction of a slice of network traffic.
//Builder of traffic selector entities.
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
selector.matchEthType(Ethernet.TYPE_IPV4);
//要求讓ipv4的封包都packet in進來
packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId);
selector.matchEthType(Ethernet.TYPE_IPV6); if (ipv6Forwarding) {
packetService.requestPackets(selector.build(),
PacketPriority.REACTIVE, appId);
} else {
packetService.cancelPackets(selector.build(), PacketPriority.REACTIVE, appId);
}
}
/**
* Cancel request for packet in via packet service.
* 反正就是做跟requestIntercepts相反的事情
*/
private void withdrawIntercepts() {
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
selector.matchEthType(Ethernet.TYPE_IPV4); packetService.cancelPackets(selector.build(),
PacketPriority.REACTIVE, appId); selector.matchEthType(Ethernet.TYPE_IPV6); packetService.cancelPackets(selector.build(),
PacketPriority.REACTIVE, appId);
} /**
* Extracts properties from the component configuration context.
*
* 把一些設定從context裡面抽取出來
* @param context the component context
*/
private void readComponentConfiguration(ComponentContext context
{
} /**
* Packet processor responsible for forwarding packets along their paths.
* 這個function來決定要怎麼轉送封包
*/
private class ReactivePacketProcessor implements PacketProcessor {
//修改父母類別的function
@Override
public void process(PacketContext context) {
}
} // 判斷是不是 control packet(LLDP, BDDP)
// Indicates whether this is a control packet, e.g. LLDP, BDDP
private boolean isControlPacket(Ethernet eth) {
short type = eth.getEtherType();
return type == Ethernet.TYPE_LLDP || type == Ethernet.TYPE_BSN;
} // 假如目前的點可以flood,那就flood
// Floods the specified packet if permissible.
private void flood(PacketContext context, ReactiveForwardMetrics macMetrics) {
if(topologyService.isBroadcastPoint(topologyService.currentTopology(),context.inPacket().receivedFrom())) { packetOut(context, PortNumber.FLOOD, macMetrics);
} else {
context.block();
}
} // Sends a packet out the specified port.
// 送出封包到指定的port
private void packetOut(PacketContext context, PortNumber portNumber, ReactiveForwardMetrics macMetrics) {
}
// Install a rule forwarding the packet to the specified port.
// 1.packetout, 2.flow_mod
// flow_mod之後要packetout,這樣才不會把封包給平白無故地丟掉
private void installRule(PacketContext context, PortNumber portNumber, ReactiveForwardMetrics macMetrics) {
}
Reference
[1]开发基于ONOS的SDN应用程序 http://sdnhub.cn/index.php/onos-application-tutorial/
[2]onos wiki https://wiki.onosproject.org/display/ONOS11/Application+tutorial
[3]Kryo https://baymaxhuang.github.io/2017/06/14/Kryo%E5%BA%8F%E5%88%97%E5%8C%96%E5%8F%8A%E5%85%B6%E5%9C%A8ONOS%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/
[4]storageService https://baymaxhuang.github.io/2017/02/15/ONOS-cluster%E5%88%86%E5%B8%83%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E5%92%8C%E4%B8%9C%E8%A5%BF%E5%90%91%E9%80%9A%E4%BF%A1/
[5]onos api http://api.onosproject.org/1.5.0/overview-summary.html
[6]ONOS源碼筆記 — 前提 https://www.twblogs.net/a/5b8a41992b71775d1ce63797
[7]newSingleThreadExecutor https://blog.csdn.net/guyuealian/article/details/51706310
[8]ONOS源码笔记 — 机制 https://blog.csdn.net/fanshuquan/article/details/51251223
[9]path http://api.onosproject.org/1.5.1/org/onosproject/net/Path.html
[10]reactive forwarding http://networkstatic.net/openflow-proactive-vs-reactive-flows/
[11]how to flow mod? https://groups.google.com/a/onosproject.org/forum/#!topic/onos-dev/5o-6kDYby6I
[12]learning-sdn https://github.com/OSE-Lab/Learning-SDN/tree/master/Controller/ONOS