티스토리 뷰

2019년 1년 동안, REST 기반의 SDN 오케스트레이션(orchestration)을 주제로 졸업 프로젝트를 2인 팀으로 진행했다. 처음 보는 오픈소스 프로젝트를 지지고 볶으면서 경험한 것을 학교와 내 머리와 컴퓨터에 썩혀 두기는 너무 아까웠기에, 정리해서 공유하려 한다.

배경

내가 SDN에 대해 이해한 간략한 배경은 다음과 같다.

레거시 네트워크는 control plane과 data plane이 결합된 구조이다. Control plane이 여기저기 분산되어 있으므로, 규모가 커지면 관리가 복잡해지고 그 비용도 증가한다.

SDN(Software Defined Networking)은 프로그래밍을 통해 중앙에서 네트워크 자원을 관리하는 것을 말한다. Control plane이 data plane과 분리되어 있어 중앙 집중된 제어가 가능하기 때문에, 더 유연한 환경을 구성할 수 있고 관리 비용도 줄일 수 있다. 이 구조에서 네트워크 제어는 SDN 컨트롤러가 담당한다. 더 나아가서 SDN으로 구성한 여러 네트워크를 통합적으로, 더 안정적으로 관리하기 위해서는 SDN orchestration이 필요하다.


목표

이 프로젝트의 최종 목표는 오픈소스 SDN 컨트롤러인 ONOS를 활용한 REST 기반의 orchestrator를 설계하고 구현하는 것이었다. 목표 달성을 위해 다음과 같은 요구사항이 주어졌다.

  • 다음 세 가지 네트워크 기본 기능 수행
    • Topology discovery: 토폴로지 정보 수집 및 유지
    • Fault monitoring: 토폴로지에 이상 발생 시 감지 및 조치
    • Path computation and provisioning: 데이터 전송을 위한 경로 계산 및 반영
  • 하나만의 대상이 아닌, 다수의 대상과 연결 가능
  • ONOS에서 제공하는 Service API 활용
  • Netty 프레임워크를 이용하여 ONOS 모듈 구현
  • 인터페이스를 REST API로 구현
  • JSON 포맷 사용

진행 과정

프로젝트 진행 과정은 대강 이런 순서였다. 내용이 길어질 수 있는 부분은 따로 작성할 것이다.

  1. SDN, orchestration 등 배경지식 학습
  2. ONOS 애플리케이션 제작 실습
  3. Netty 프레임워크를 활용한 REST 클라이언트 및 서버 제작 실습
  4. ONOS에서 제공하는 API를 통한 가상의 네트워크 요소 등록 방법 파악 및 이를 활용한 인터페이스 설계·구현
  5. ONOS에서 작동하는 REST 클라이언트 및 서버 애플리케이션 제작
  6. Topology discovery 구현
  7. Fault monitoring 구현
  8. Path computation and provisioning 구현
  9. 서버-클라이언트 통합
  10. 네트워크 디바이스의 implicit mapping을 위한 네트워크 기본 기능 추가 구현

프로젝트 진행 과정을 나타낸 digraph: (1,2),(1,3),(2,4),(2,5),(3,5),(4,6),(5,6),(6,7),(7,8),(8,9),(8,10)

SDN, orchestration 등 배경지식 학습

프로젝트에서 다룰 기술에 대한 아무 배경지식도 없이 프로젝트를 진행할 수는 없다. 프로젝트 초기에는 배경지식 학습을 위해 자료를 찾아 정리했다. SDN, SDN 컨트롤러, ONOS, Netty, OpenFlow, REST, JSON 등에 대해 찾아봤다.

ONOS 애플리케이션 제작 실습

Ubuntu 16.04에 프로젝트 진행을 위한 환경을 구성한 뒤, ONOS를 설치하여 실행해 보았다. 이후 Mininet으로 구성한 토폴로지에 따라 네트워크 자원이 추가·제거되는 이벤트가 발생하면 로그를 출력하는 ONOS 애플리케이션을 제작하는 실습을 진행했다. 이 과정에서 빌드나 구동이 제대로 되지 않는 등의 문제를 많이 겪고 해결했다. 나중에 똑같은 문제를 또 마주칠 수 있기 때문에, 관련 매뉴얼도 작성해 두었다.

정말 안타깝게도, 프로젝트를 제출하고 나서 이 과정에서 내가 겪은 문제를 완전히 피하는 방법을 알았다.

Netty 프레임워크를 활용한 REST 클라이언트 및 서버 제작 실습

먼저 ONOS에서 제공하는 REST API를 파악했다. 특히 device, link, host, flow rule과 관련된 요청이 어떻게 전달되는지를 확인했다.

ONOS 애플리케이션에 Netty 프레임워크를 활용하기 전에, 먼저 Netty 프레임워크에 익숙해지기 위해 Netty 프레임워크를 활용하여 REST 클라이언트 및 서버를 Java 애플리케이션으로 제작하는 실습을 진행했다. 이 부분은 다른 팀원이 진행하여 예제와 매뉴얼을 넘겨주었고, 나는 그걸 토대로 실습을 진행해 보았다.

ONOS에서 제공하는 API를 통한 가상의 네트워크 요소 등록 방법 파악 및 이를 활용한 인터페이스 설계·구현

이 부분은 내가 진행했는데, 개인적으로 정말 어려웠던 첫 번째 정체 구간이다. 당시 ONOS 서브시스템 구조에 대한 이해 수준이 얕았기 때문에 이 단계에서 정체가 심했다. ONOS에 기본으로 포함되는 일부 애플리케이션과 ONOS 코어 일부의 코드를 뜯어보고 나서야 ONOS 서브시스템 구조를 제대로 이해하고 활용할 수 있었다. ONOS가 오픈소스 프로젝트여서 해결할 수 있었던 것 같다. 문서만 보고 이해했으면 좋았겠지만, 그게 아니어서 코드를 직접 뜯어보고 예제도 살펴보는 것이 필요했다. 갈피를 잡고 나서는 이 부분 관련 매뉴얼을 작성해 두었고, 다시 정리해서 별도로 게시해 두었다.

ONOS에서 작동하는 REST 클라이언트 및 서버 애플리케이션 제작

앞서 진행한 ONOS 애플리케이션 제작 실습 및 Netty 프레임워크를 활용한 REST 클라이언트 및 서버 제작 실습의 결과물을 활용하여 ONOS에서 작동하는 REST 클라이언트 및 서버 애플리케이션을 제작했다. 왜인지는 모르겠지만, ONOS 1.x에서는 OSGi wiring error로 작동하지 않았고, ONOS 2.x에서는 정상적으로 작동했다.

Topology discovery 구현

초기에 실습을 통해 작성한 네트워크 자원 추가·제거 이벤트를 처리하는 ONOS 애플리케이션과, ONOS에서 작동하는 REST 서버 애플리케이션을 합쳐서, child-side 애플리케이션을 만들었다. 그리고 가상의 네트워크 요소를 등록하는 인터페이스를 구현한 것과, ONOS에서 작동하는 REST 클라이언트 애플리케이션을 합쳐서, parent-side 애플리케이션을 만들었다. Parent-side 애플리케이션 쪽에 child ONOS 3개의 IP를 하드코딩해서, 두 애플리케이션이 제대로 상호작용하는지 확인했다.

Fault monitoring 구현

앞서 구현한 parent-side 애플리케이션에, 가상의 네트워크 요소끼리 연결된 링크를 제거하는 인터페이스를 추가로 설계·구현했다. 그리고 parent-side 애플리케이션이 일정 주기마다 child-side 서버에 링크의 변경 사항을 요청하게 했다. 이렇게 polling 방식으로 fault monitoring 기능을 구현했다. 시간에 쫓겨 long polling 방식으로 구현하지 못한 게 아쉽다.

Path computation and provisioning 구현

여기가 두 번째 정체 구간이다. 여기서는 flow rule을 적용하게 하는 방법을 찾느라 조금 정체가 있었다. 이때는 ONOS 내장 REST API의 핸들러도 뜯어 봤는데, 그때 보기에는 좀 복잡해서 ONOS 내장 REST 서버에 POST /flows 요청을 날리는 것으로 일단 때웠다.

처음 provisioning 기능을 구현할 때는, parent-side에서 요청한 경로를 계산한 뒤에 child ONOS에 직접 flow rule을 내리도록 구현했다. 그러나 이 구현은 나중에 implicit mapping을 위한 provisioning을 구현할 때와 multi-level orchestration을 하려고 할 때 코드를 재사용할 수 없다는 문제가 있다.

따라서 implicit mapping을 위한 provisioning 기능을 구현하기 전에, child-side에 재귀적으로 provisioning 요청을 분할하여 전달하도록(divide and conquer) 수정했다. Ancestor부터 재귀적으로 provisioning 요청을 분할하여 descendant로 내려보내는데, 가상 디바이스가 아닌 OpenFlow 디바이스가 걸려서 더 이상 요청을 분할할 수 없다면, 그때 flow rule을 만들어 내려준다. Parent-side에서는 어느 네트워크 디바이스가 어느 child ONOS에 연결되어 있는지를 매핑 테이블에 기록하여 알고 있기 때문에, 금방 수정할 수 있었다.

서버-클라이언트 통합

세 가지 네트워크 기본 기능을 구현한 뒤에는 child-side 애플리케이션과 parent-side 애플리케이션을 합쳤다. Parent와 child 모두 같은 앱으로 orchestration을 하기 위해서다.

이 과정에서 코드를 많이 다듬었다. 가상의 네트워크 요소를 등록하는 인터페이스도 다듬었고, 특히 이벤트 핸들러 부분이나 REST 요청/응답 핸들러 부분을 많이 다듬었던 것 같다. REST API도 좀 더 RESTful하게 고치려고 노력했다. 비효율적으로 보이는 동작도 보일 때마다 다듬었다. 결국 여기가 세 번째 정체 구간이 되었다.

이 과정을 거친 뒤로는 parent-side에 child의 IP를 하드코딩한 것을 제거해야 했다. 그 대안으로, REST API를 통해 일부 설정이나 동작을 할 수 있도록 수정했다.

네트워크 디바이스의 implicit mapping을 위한 네트워크 기본 기능 추가 구현

Parent-side에서 child가 가진 네트워크 자원을 추상화하여 보여주기 위한, 네트워크 기본 기능을 추가로 구현했다. 추상화된 topology discovery와 fault monitoring은 서버와 클라이언트를 통합하기 직전에 추가했는데, 그때 실제 자원과 추상화된 자원의 매핑 테이블을 구현했다.

Path computation and provisioning을 구현하면서, 이전에 ONOS 내장 REST API 호출로 때운 flow rule 반영하는 부분을 결국 구현해 냈다. 나중에 ONOS 내장 REST 핸들러 코드를 뜯어봤을 때 JSON decoder가 있어서 그걸 활용했다.

댓글
공지사항