NVR 또는 IP Camera 에서 현재 네트워크 상태를 진단(diagnostic)할 수 있는 기능에 대한 분석 및 정리한 내용을 담고 있다.

목적

현재 및 과거의 네트워크 품질 및 상태를 확인할 수 있다.

메뉴 설명

DVR 에 연결되어 있는 네트워크 토폴로지를 그래픽으로 출력하고, 현재 NVR 에 설정된 네트워크 정보(IP, MAC, DDNS, SERVICE PORT)를 보여준다.
오른쪽 상단의 선택 메뉴를 통해, 각각 'POE POWER CONSUMPTION, RTT(ROUND TRIP TIME)/LOSS RATE, INBOUND TRAFFIC' 를 지정할 수 있다.

POE POWER CONSUMPTION NVR 에 연결된 각각의 카메라의 소비 전류을 표시하고, 현재 NVR 에 걸리는 전류의 총합과 최대 허용 전류의 양을 표시한다
ROUND TRIP TIME/LOSS RATE 각각의 연결된 카메라로 부터의 RTT 값과 PACKET LOSS 값을 표시한다(ping 이용)
INBOUND TRAFFIC 카메라로부터 전송되어 들어오는 데이터 트래픽의 양을 표시한다. 이때 각각의 카메라에 전송 트래픽의 양을 표시하고, 이들 카메라의 합한 수치를 표시한다. 이 수치가 일정량을 넘어가면 'CHECK Status' 메시지를 띄운다(ifconfig 의 RX bytes 이용)

NVR 에 연결된 각 카메라와의 네트워크 상태정보를 표시한다. 연결된 포트명, 연결된 디바이스 이름, RTT, PACKET LOSS, TRAFFIC, STATUS, NOTE 항목을 표시한다.

연결된 포트명 NVR 에 연결된 포트를 표시한다
연결된 디바이스 이름 장치의 이름을 표시한다
STATUS OK/CHECK/FAIL 로 표시한다
NOTE 상태가 FAIL 인 경우, 이유와 해결방법을 표시한다

나머지 항목은 NETWORK MAP 탭과 동일하다.

연결된 카메라들의 소비 전류 정보(평균, 최소, 최대, 현재, 상태)를 표시한다.

RMON(The Remote Network MONitoring)은 SNMP은 확장형태로, 네트워크 곳곳에 설치되어 있는 장비로부터 오가는 트래픽을 분석하고 감시할 수 있다. RMON MIB(Management Information Base)는 RFC 1757에 정의되어 있으며, SNMP management station과 RMON monitoring agent의 상호작용에 관해 기술되어 있다. Protocol Analyzers와 RMON probe들은 모니터 되는 LAN의 패킷 데이터를 수집함으로써 RMON 에이전트의 향상된 모니터링 기능을 제공한다. Probe는 SNMP를 통해 수집된 데이터를 NMS 장비에 보낸다. 또한, NMS 장비는 NetScout Managers, Optivity LAN, HP Openview 같은 응용 프로그램을 이용하여 수집된 데이터를 가공 처리하여, 완성된 리포트 형태로 보여준다.

RMON은 중앙 사이트로부터 T-1/E-1과 T-2/E-3 회선들이 서로 연결되어 있는 분산 근거리통신망 그룹을 감시, 분석 및 고장 처치하는데 사용될 수 있는 표준 정보를 네트웍 관리자에게 제공한다. 명확히 말하면 RMON은, 어떠한 네트웍 감시 시스템이라도 제공할 수 있을 정보를 명백히 보여준다. 이것은 SNMP의 확장판으로서 RFC 1757에 정의된 MIB의 일부로 정의되어 있다. 최신판은 때로 “RMON 2”라고도 불리는 RMON Version 2이다.

RMON은 프로브라고 불리는 하드웨어 감시 장치나, 소프트웨어 또는 그 조합에 의해 지원된다. 예를 들면, 시스코의 LAN 스위치 계열에는 각 스위치가 MIB 내를 통과하는 트래픽 정보를 잡고, 기록할 수 있는 소프트웨어가 포함된다. 소프트웨어 에이전트는 네트웍 관리자에게 GUI 형태로 보여주기 위해 정보를 모을 수 있다. 많은 공급회사들이 RMON을 지원하는 다양한 종류의 제품을 제공한다.

RMON은 보내진 패킷의 수, 바이트 수, 없어진 패킷의 수, 호스트별 통계, 주고받은 주소지별 통계, 다양한 종류의 이벤트 발생 내역 등 9가지 종류의 정보를 수집한다. 네트웍 관리자는 네트웍 상에서 각 사용자들이 부과하는 대역폭이나 트래픽 량이 얼마나 되는지, 어떤 웹사이트들이 액세스되고 있는지 등을 알아낼 수 있다. 절박한 문제점들을 알리기 위하여 경고신호가 보내질 수 있다.

RMON 을 통해 얻을 수 있는 많은 항목들을 출력한다.

지금까지 다뤘던 항목들을 그래프로 나타낸다. 'PACKET LOSS RATE, INBOUND TRAFFIC, POE POWER CONSUMPTION' 을 선택할 수 있고, 이에 대한 필터링으로서 카메라별(or 모두), 측정 기간별, 시간 날짜별로 지정할 수 있다.
그래프는 gnuplot 라는 프로그램을 사용하는데, 이를 위해서는 그래프를 그릴 수 있는 데이터값을 가지고 있어야 한다(파일 형태?). 이후에 이를 JPEG 나 PNG 형식으로 만들 수도 있다. GRAPH 항목을 선택했을 때만, 동작하도록 한다. 오버헤드 정도에 따라.

ping 과 netstat 를 실행하여 결과를 표시한다. 이후 이 로그를 파일로 저장할 수 있다.

필요한 것들

앞서 설명한 Network Diagnostic 메뉴를 위해 필요한 것들을 정리해보자.

  1. ping - RTT, Packet LOSS 측정
  2. netstat - netstat 명령 실행
  3. ifconfig - INBOUND TRAFFIC 측정
  4. cron - 주기적으로 일정 시간마다 실행
  5. 그 외(전류체크, RMON)

위의 명령어들은 멀티 쓰레드로 실행되며, 또한 주기적으로 실행된다. 실행되어 얻어진 데이터는 파일 또는 DB 또는 배열 구조체 의 형태로 저장되며, 차후 이를 이용해 그래프를 그린다.–
위의 명령어들은 cron 을 통해 주기적(1분마다)으로 실행된다. 실행된 결과는 파일로 저장되며, 이를 이용하여 차후 이를 이용해 그래프를 그린다.

  1. NVR 에 카메라가 연결되고, 통신이 가능한 상태가 되면, 카메라의 IP 를 특정 파일(/usr/local/sbin/ipaddr)에 저장한다. 파일 내용은 아래와 같다.
192.168.0.1
127.0.0.1

  1. 이 파일을 읽은 후, 해당 IP 에 ping 을 실행하여, RTT, INBOUND TRAFFIC 를 측정하고 이를 파일에 저장한다(/tmp/ping_IP주소).
  2. 해당 네트워크 인터페이스(eth0)에 일정시간동안 데이터 입력량을 측정하고, 이를 앞서 측정한 ping 결과 데이터와 함께 최종 파일에 저장한다(/tmp/IP주소). 1분 주기로 실행될 때마다 파일에 한줄 쓰여진다. 한줄당 약 22 byte 이다. 계산을 해보면, 카메라 한 대당 '22 * 60 * 24 * 30 = 950400(약 1MB)' 이다.

busybox 에 내장된 ping 코드를 수정하여, 아래와 같이 실행할 때, 결과가 나오도록 수정하였다.

#ping -q -c 4 192.168.0.1
0%    0.87    0.91    0.97

순서대로, Packet Loss, RTT(MIN), RTT(AVG), RTT(MAX) 값이다.

다음은 수정 방법이다. networking/ping.c 파일을 수정한다.

static void print_stats_and_exit(int junk UNUSED_PARAM)
{
    signal(SIGINT, SIG_IGN);
 
//  printf("\n--- %s ping statistics ---\n", hostname);
//  printf("%lu packets transmitted, ", ntransmitted);
//  printf("%lu packets received, ", nreceived);
    if (nrepeats)
        printf("%lu duplicates, ", nrepeats);
    if (ntransmitted)
        ntransmitted = (ntransmitted - nreceived) * 100 / ntransmitted;
//  printf("%lu%% packet loss\n", ntransmitted);
    printf("%lu\t", ntransmitted);                                 // 추가
    if (tmin != UINT_MAX) {
        unsigned tavg = tsum / (nreceived + nrepeats);
 
//        printf("%u.%03u\t%u.%03u\t%u.%03u ms\n",
//            tmin / 1000, tmin % 1000,
//            tavg / 1000, tavg % 1000,
//            tmax / 1000, tmax % 1000);
 
        printf("%u.%02u\t%u.%02u\t%u.%02u\n",
            tmin / 1000, (tmin % 1000) / 10, 
            tavg / 1000, (tavg % 1000) / 10, 
            tmax / 1000, (tmax % 1000) / 10);
    }   
    else
        printf("0\t0\t0\n");                  // 추가
 
    /* if condition is true, exit with 1 -- 'failure' */
    exit(nreceived == 0 || (deadline && nreceived < pingcount));
}
...
static void ping(len_and_sockaddr *lsa)
{
//  printf("PING %s (%s)", hostname, dotted);                    // 주석
    if (source_lsa) {
        printf(" from %s",
            xmalloc_sockaddr2dotted_noport(&source_lsa->u.sa));
    }   
//  printf(": %d data bytes\n", datalen);                 // 주석
 
    G.sizeof_rcv_packet = datalen + MAXIPLEN + MAXICMPLEN;
    G.rcv_packet = xzalloc(G.sizeof_rcv_packet);
#if ENABLE_PING6
    if (lsa->u.sa.sa_family == AF_INET6) {
        /* +4 reserves a place for timestamp, which may end up sitting
         * _after_ packet. Saves one if() - see sendping4/6() */
        G.snd_packet = xzalloc(datalen + sizeof(struct icmp6_hdr) + 4); 
        ping6(lsa);
    } else
#endif

참고로 여기서는 busybox-1.21.1.tar 를 사용했다. 압축을 풀고, 빌드 준비를 한다. busybox 의 수많은 유틸리티 중에 ping 만 필요하기 때문에 빌드 설정 시, ping 만 선택하도록 한다.
먼저 모든 옵션을 끈다. 아래와 같이 실행하면 모든 옵션을 끌 수 있다. 그리고 나서 ping 을 선택

#make allnoconfig

그리고 나서 'Networking Utilties → ping' 을 선택한다.
추가로 빌드 옵션을 추가해주어야 하는데, 일반적으로 busybox 를 빌드 후 설치하면, 추가한 모든 명령어는 busybox 라는 바이너리 실행파일에 포함되고, 파일시스템 상에서는 이를 심볼릭 링크를 걸어 사용하도록 설정되어 있다. 여기서는 하나의 실행파일(ping)만 필요로 하므로, 'Busybox Settings → Installation Options (“make install behavior”) → What kind of applet links to install' 를 'as hard-links' 를 선택한다.

#make
#make install

빌드 후, _install 디렉토리 아래에 ping 바이너리 파일을 볼 수 있다.

이 스크립트는 앞서 만든 ping 을 사용하여 packet loss, rtt 값을 측정하고, 이를 파일에 저장하는 역할을 한다.
/usr/local/sbin/ipaddr 파일을 읽어들여서, 해당 IP 로 4초간 ping 을 실행하고 결과를 '/tmp/ping_${line}' 파일에 저장한다.
실행해야할 IP 가 많아지더라도, 백그라운드(&) 실행을 하기 때문에 거의 동시에 4초 안에 수행이 완료된다. 만일 응답이 없는 IP 일 경우, 약 13초 안에 완료된다.

#!/bin/sh
 
INPUT=/srv/network/ipaddr
 
count=`wc -l < $INPUT`
 
num=0
 
while read line;
do
    if [ $num -ne $count ]; then
        /srv/network/ping -q -c4 $(echo "${line}") > /tmp/ping_${line} &
    else
        echo $line
    fi  
    num=$((num+1))
done < $INPUT

이 스크립트는 해당 인자 인터페이스로 주고 받은 데이터의 속도를 측정한다.
ifconfig 명령어는 /proc/net/dev 파일을 파싱하여 보여주는데, 아래는 이를 이용하여 일정시간(30초) 동안 특정 인터페이스로 주고 받은 데이터의 값을 보여준다.

추가로 데이터 저장시 '년/월/일/시간/분' 을 저장하도록 추가하였다.

#!/bin/sh
if [ "$1" != "" ]; then
# ethnet device
ETH="$1:"
CHECK=/proc/net/dev
CAT=/bin/cat
 
GREP="/bin/grep ${ETH}"
SED="sed -e s/${ETH}//"
UPTIME=/usr/bin/uptime
 
# parcket user check
set `${CAT} ${CHECK} | ${GREP} | ${SED}`
 
# Transmit packet
in1=$1
out1=$9
 
echo $in1
echo $out1
 
sleep 30            # 30 초
 
set `${CAT} ${CHECK} | ${GREP} | ${SED}`
 
in0=$1
out0=$9
 
echo $in0
echo $out0
 
in=`expr \( $in0 - $in1 \) / \( 10 \* 1024 \)`
out=`expr \( $out0 - $out1 \) / \( 10 \* 1024 \)`
 
#let " in = ($in0 - $in1)"
#let " out = ($out0 - $out1)"
 
echo $in
echo $out
 
echo "rx (in) $in kbyte/s"
echo "tx(out) $out kbyte/s"
 
#echo -e "`cat /tmp/net_info`\t$in" >> /tmp/final_result
 
INPUT=/srv/network/ipaddr
 
count=`wc -l < $INPUT`
 
num=0
 
while read line;
do
    if [ $num -ne $count ]; then
 
        if [ -f /tmp/ping_${line} ]; then
                echo -e "`date +"%y-%m-%d %H:%M"`\t`cat /tmp/ping_${line}`\t$in" >> /tmp/${line}            # 년-월-일 시간:분 포맷으로 저장
        fi
    else
        echo $line
    fi  
    num=$((num+1))
done < $INPUT
 
rm -f /tmp/ping_${line}
 
else
echo "USAGE: $0 [ethernet device no]"
echo "ex) ./$0 eth0"
fi
 
exit 0

저장공간의 부족 때문에, 모든 시간의 데이터를 저장할 수 없다. 따라서 최장 4 주 간의 데이터를 기록하기 위해서 다음과 같은 규칙을 만들었다.

  1. 하루 동안의 데이터들의 평균을 저장하는 데이터 파일을 만든다. 이 파일은 4주, 즉 28일 동안의 데이터가 저장된다.
  2. 일주일(7일)까지는 매 1분마다 저장되는 데이터를 가지고 있으며, 7일이 지나는 시점부터는 앞서 가장 오래된 1일 분량의 데이터는 삭제된다.
  3. 하루 동안의 파일을 저장하는 파일 또한 마찬가지다. 28일이 지나는 시점부터 앞서 가장 오래된 1일 분량의 데이터는 삭제된다.

이 스크립트 파일은 하루마다 실행되며, 하루 동안 저장된 데이터들의 평균을 계산하여 저장한다.

#!/bin/sh
base_date=`date +"%y-%m-%d" -d "1day ago"`                      # 기준 시간
echo $base_date
 
INPUT=/srv/network/ipaddr
count=`wc -l < $INPUT`
num=0
 
while read line;
do
    if [ $num -ne $count ]; then
                start_line_num=`grep -n "$base_date" /tmp/$(echo "${line}") | awk -F: '{print $1}' | head -n 1`  # 해당 시간의 첫번째 줄 번호
                end_line_num=`grep -c "$base_date" /tmp/$(echo "${line}")`                                              # 해당 시간의 마지막 줄 번호
                total_area=`expr $start_line_num + $end_line_num`                                                               # 해당 시간 데이터의 영역
 
                echo start = $start_line_num, end = $end_line_num, total = $total_area
 
#               sed -n ''$start_line_num','$total_area' p' /tmp/${line} > /tmp/${line}_tmp                      # 기준에 맞는 데이터 추출 후 파일 생성
 
                echo "$base_date\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $3; cnt += 1} END {print s/cnt}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $4; cnt += 1} END {printf("%.2f", s/cnt)}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $5; cnt += 1} END {printf ("%.2f", s/cnt)}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $6; cnt += 1} END {printf("%.2f", s/cnt)}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $7; cnt += 1} END {printf("%.2f", s/cnt)}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $8; cnt += 1} END {printf("%.2f", s/cnt)}')" >> /tmp/${line}_daily          # 기준시간 동안의 평균값을 구하고 특정파일에 저장
 
        #SAVE_DAY_NUM=`awk '{print $2}' /tmp/${line}_daily | awk -F: '{print $1}' | sort -u | wc -l`
 
 
 
        SAVE_DAY_NUM=`awk '{print $1}' /tmp/${line}_daily | sort -u | wc -l`                            # 저장된 날짜 수
 
        echo save-day-num = $SAVE_DAY_NUM
 
        if [ $SAVE_DAY_NUM -gt 28 ]; then               # 저장된 날짜가 28 일 이상이면 TRUE     - 날짜 데이터를 삭제한다
#               FILTER_DAY=`echo $(awk '{print $1}' /tmp/${line}_daily | head -n 1) $(awk '{print $2}' /tmp/${line}_daily | awk -F: '{print $1}' | head -n 1)`
                FILTER_DAY=`echo $(awk '{print $1}' /tmp/${line}_daily | head -n 1)`            # 삭제될 날짜 - 가장 오랜된 날짜 - 첫 줄
 
                echo filter-day = $FILTER_DAY
 
                sed '/'"$FILTER_DAY"'/d' /tmp/${line}_daily > /tmp/del_${line}_daily
                rm -rf /tmp/${line}_daily
                mv /tmp/del_${line}_daily /tmp/${line}_daily
        else
                echo 1
        fi
 
#       SAVE_HOUR_NUM=`awk '{print $2}' /tmp/${line} | awk -F: '{print $1}' | sort -u | wc -l`
        SAVE_TOTAL_DAY_NUM=`awk '{print $1}' /tmp/${line} | sort -u | wc -l`
 
        echo save-hour-num = $SAVE_TOTAL_DAY_NUM                # 저장된 날짜 수
 
        if [ $SAVE_TOTAL_DAY_NUM -gt 7 ]; then                  # 7일 이상일 때 TRUE
                FILTER=`echo $(awk '{print $1}' /tmp/${line} | head -n 1)`
#               FILTER=`echo $(awk '{print $1}' /tmp/${line} | head -n 1) $(awk '{print $2}' /tmp/${line} | awk -F: '{print $1}' | head -n 1)`
                sed '/'"$FILTER"'/d' /tmp/${line} > /tmp/del_${line}            
                rm -rf /tmp/${line}
                mv /tmp/del_${line} /tmp/${line}
        else
                echo 1
        fi
 
        rm -rf /tmp/${line}_tmp
    else
        echo $line
    fi  
    num=$((num+1))
done < $INPUT
 
#rm -rf /tmp/${line}_tmp
#rm -rf /tmp/192.168.0.1_tmp
echo aaa
#!/bin/sh
#base_date=`date +"%y-%m-%d" -d "1day ago"`                      # 기준 시간
#echo $base_date
 
AA=`date +%s`
BB=`expr $AA - \( 1 \* 60 \* 60 \* 24 \)`
 
base_date=`date +"%y-%m-%d" -D '%s' -d "$BB"`
 
INPUT=/srv/network/ipaddr
count=`wc -l < $INPUT`
num=0
 
while read line;
do
    if [ $num -ne $count ]; then
                start_line_num=`grep -n "$base_date" /tmp/$(echo "${line}") | awk -F: '{print $1}' | head -n 1`  # 해당 시간의 첫번째 줄 번호
                end_line_num=`grep -c "$base_date" /tmp/$(echo "${line}")`                                              # 해당 시간의 마지막 줄 번호
                total_area=`expr $start_line_num + $end_line_num`                                                               # 해당 시간 데이터의 영역
 
                echo start = $start_line_num, end = $end_line_num, total = $total_area
 
                echo -e "$base_date\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $3; cnt += 1} END {print s/cnt}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $4; cnt += 1} END {printf("%.2f", s/cnt)}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $5; cnt += 1} END {printf ("%.2f", s/cnt)}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $6; cnt += 1} END {printf("%.2f", s/cnt)}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $7; cnt += 1} END {printf("%.2f", s/cnt)}')\t$(sed -n ''$start_line_num','$total_area' p' /tmp/${line} | awk '{s += $8; cnt += 1} END {printf("%.2f", s/cnt)}')" >> /tmp/${line}_daily          # 기준시간 동안의 평균값을 구하고 특정파일에 저장
 
        SAVE_DAY_NUM=`awk '{print $1}' /tmp/${line}_daily | sort -u | wc -l`                            # 저장된 날짜 수
 
        echo save-day-num = $SAVE_DAY_NUM
 
        if [ $SAVE_DAY_NUM -gt 28 ]; then               # 저장된 날짜가 28 일 이상이면 TRUE     - 날짜 데이터를 삭제한다
                FILTER_DAY=`echo $(awk '{print $1}' /tmp/${line}_daily | head -n 1)`            # 삭제될 날짜 - 가장 오랜된 날짜 - 첫 줄
 
                echo filter-day = $FILTER_DAY
 
                sed '/'"$FILTER_DAY"'/d' /tmp/${line}_daily > /tmp/del_${line}_daily
                rm -rf /tmp/${line}_daily
                mv /tmp/del_${line}_daily /tmp/${line}_daily
        else
                echo 1
        fi
 
        SAVE_TOTAL_DAY_NUM=`awk '{print $1}' /tmp/${line} | sort -u | wc -l`
 
        echo save-hour-num = $SAVE_TOTAL_DAY_NUM                # 저장된 날짜 수
 
        if [ $SAVE_TOTAL_DAY_NUM -gt 7 ]; then                  # 7일 이상일 때 TRUE
                FILTER=`echo $(awk '{print $1}' /tmp/${line} | head -n 1)`
                sed '/'"$FILTER"'/d' /tmp/${line} > /tmp/del_${line}
                rm -rf /tmp/${line}
                mv /tmp/del_${line} /tmp/${line}
        else
                echo 1
        fi
 
        rm -rf /tmp/${line}_tmp
    else
        echo $line
    fi
    num=$((num+1))
done < $INPUT

Network Diagnostic API 를 위해 만들어진 스크립트 파일이다. 인자값으로 '기준 날짜/시간, 기간' 이다.

#!/bin/sh
test=`date -d "$1" +%s`
 
echo $test
 
case "$2" in
        1)
        echo "input min"
#       dur=`expr 1 \* 60 \* 10`
        dur=600
        ;;
 
        2)
        echo "input hour"
#       dur=`expr 1 \* 60 \* 60`
        dur=3600
        ;;
 
        3)
        echo "input day"
#       dur=`expr 1 \* 60 \* 60 \* 24`
        dur=86400
        ;;
 
        4)
        echo "input week"
#       dur=`expr 1 \* 60 \* 60 \* 24 \* 7`
        dur=604800
        ;;
 
        5)
        echo "input month"
#       dur=`expr 1 \* 60 \* 60 \* 24 \* 28`
        dur=2419200
        ;;
esac
 
process=`expr $test + $dur`
 
#result=`date +"%y-%m-%d" -D '%s' -d "$test"`
result=`date +"%y-%m-%d" -D '%s' -d "$process"`
 
echo $result
#!/bin/sh
test=`date -d "$1" +%s`
 
#echo $test
 
case "$2" in
        1)
        echo "input min"
#       dur=`expr 1 \* 60 \* 10`
        dur=600
        process=`expr $test + $dur`
        result=`date +"%y-%m-%d %H:%M" -D '%s' -d "$process"`
        ;;
 
        2)
        echo "input hour"
#       dur=`expr 1 \* 60 \* 60`
        dur=3600
        process=`expr $test + $dur`
        result=`date +"%y-%m-%d %H:%M" -D '%s' -d "$process"`
        ;;
 
        3)
        echo "input day"
#       dur=`expr 1 \* 60 \* 60 \* 24`
        dur=86400
        process=`expr $test + $dur`
        result=`date +"%y-%m-%d %H:%M" -D '%s' -d "$process"`
        ;;
 
        4)
        echo "input week"
#       dur=`expr 1 \* 60 \* 60 \* 24 \* 7`
        dur=604800
        process=`expr $test + $dur`
        result=`date +"%y-%m-%d" -D '%s' -d "$process"`
        ;;
 
        5)
        echo "input month"
#       dur=`expr 1 \* 60 \* 60 \* 24 \* 28`
        dur=2419200
        process=`expr $test + $dur`
        result=`date +"%y-%m-%d" -D '%s' -d "$process"`
        ;;
esac
 
#process=`expr $test + $dur`
 
#result=`date +"%y-%m-%d" -D '%s' -d "$test"`
#result=`date +"%y-%m-%d" -D '%s' -d "$process"`
 
basic=`date +"%y-%m-%d %H:%M" -D '%s' -d "$test"`
 
echo "base time : $basic"
echo "end time : $result"
 
 
start_line=`grep -n "$basic" /tmp/127.0.0.1 | awk -F: '{print $1}' | head -n 1`
end_line=`grep -n "$result" /tmp/127.0.0.1 | awk -F: '{print $1}' | head -n 1`
 
echo $start_line $end_line
 
#echo -e "$(sed -n ''$start_line','$end_line' p' /tmp/127.0.0.1)"
 
type=$3
 
fat=`sed -n ''$start_line','$end_line' p' /tmp/127.0.0.1 | awk '{print \$'"${type}"'}'`
 
echo "$fat"

앞서 만든 스크립트 파일들을 주기적으로 실행하기 위해 cron 을 이용한다. busybox 에서 'Miscellaneous Utilities → crond, crontab' 을 선택한다(make allnoconfig 이용). 빌드 후 설치 디렉토리에 가면 crond, crontab 파일을 볼 수 있다.
crond 는 실제 동작하는 데몬 파일이고, crontab 파일은 스케줄 등록 및 출력을 할 수 있는 설정 용도로 사용한다. cron 동작을 위해서는 사전에 필요한 디렉토리 경로를 만들어야 한다.

#mkdir -p /var/spool/cron/crontabs
#crontab -e

매 1분마다 주기적으로 실행해야 하므로 아래와 같이 입력한다.

*/1 * * * * /srv/network/auto
*/1 * * * * /srv/network/data_eth eth0

저장 후 실제 crond 데몬을 실행한다. 이 방법은 직접 입력하는 방법이고, 파일에 바로 입력하여 작성하는 방법도 있다. /var/spool/cron/crontabs 아래에 root 라는 이름의 파일(퍼미션은 600)을 만들고, 위의 내용을 저장하면 된다.
추가로 파일 퍼미션과 소유권을 수정해주어야 한다. 부팅 시, 자동 실행되는 스크립트 파일에 다음을 추가한다.

chown root.root /var/spool/cron/crontabs/root
/srv/network/crond -l 0

로그를 남기려면 아래와 같이 입력한다.

#crond -l 0 -L /data/cron.log

앞서 등록한 두 스크립트(auto, data_eth)는 동시에 실행되는 것 같지만, data_eth 스크립트의 경우, 30 초 정도 delay 이후에 동작하므로, 2개의 스크립트가 충돌이 발생하지는 않는다. 순서적으로 보면, auto 가 먼저 실행되고, 이후 data_eth0 가 실행된다.

생각해봐야 할 것들

  1. 주기를 얼마나 할 것인가?
  2. IPX 와 카메라는 eth0 인터페이스로 통신을 하기 때문에 각각의 연결된 카메라 별 데이터 전송량을 측정할 수 없다. phy 단위별로 측정이 가능하기 때문이다. 따라서 각 카메라 측에서는 측정이 가능한데, 그것도 타사 카메라의 경우에는 이마저도 불가능하다.

FAQ

실제 접속이 안된 IP 로 ping 을 보내면, PACKET LOSS 이외에 다른 정보는 아무것도 받아오지 않는다. PACKET LOSS 는 100% 이다. 이런 경우 RTT 값은 강제로 각각 0 으로 출력하도록 하였다.

다음은 검색하려는 날짜가 몇 번째 줄에 있는지를 반환해주는 스크립트다.

#grep -n '13-10-04 19:12' 127.0.0.1 | awk -F: '{print $1}'

다음은 몇번째 줄부터 몇번째 줄까지 출력해주는 스크립트다.

#sed -n '20,26p' 192.168.0.1

다음은 출력된 데이터들의 평균을 계산해주는 스크립트다.

#sed -n '20,26p' 192.168.0.1 | awk '{s += $4; cnt += 1} END {print s, s/cnt}'

앞서 생성한 로그 데이터로 부터 필요한 데이터만을 뽑아 그래프를 그린다. gnuplot 라는 프로그램을 사용하는데, 아래 파일을 사용하여 그릴 것이다.

#set terminal png size 1200,800             # 그래프를 png 파일로 생성할 때 사이즈를 지정
set xdata time                            # x축은 시간으로 지정
set timefmt "%y-%m-%d %H:%M"                 # 시간 포맷은 년-월-일 시간:분 으로 지정
#set output "load.png"                                           # 생성될 파일 이름은 load.png 로 지정
# time range must be in same format as data file
set xrange ["13-10-10 09:50":"13-10-10 14:59"]             # x축의 범위 지정
#set xrange ["13-10-10 09:50":"13-10-10 09:59"]
set yrange [0:5]                                               # y축의 범위 지정
 
set grid                      # 격자 보이게끔 지정
set xlabel "Date Time"                      # x축의 이름을 Date Time 으로 지정
set ylabel "Response Time(ms)"          # y축의 이름을 Response Time(ms) 로 지정
set title "ROUND-TRIP TIME"              # 그래프의 제목 지정
set key left box                            # 요소 설명 상자의 위치를 왼쪽으로 지정
#plot "load.dat.4" using 1:2 index 0 title "ahost" with linespoint
plot "load.dat.4" using 1:3 index 0 title "192.168.0.1" with linespoint,"load.dat.5" using 1:3 index 0 title "127.0.0.1" with linespoint     # 두개의 파일로부터 데이터를 읽어들여 그래프를 그린다. 1:3 은 첫번째와 세번째 column 을 의미한다
pause -1       # 별다른 입력을 없을 때까지 그래프를 출력한다 

위의 스크립트에서 각 그래프마다 수정되어야 할 부분이 있다. x/y 축의 주기, 이름 등

#sed -e '/xrange/d' xxx.conf | sed -e '4 i\set xrange ["13-10-10 18:50":"13-10-10 14:59"]' > /tmp/uuu           // 해당

파싱된 파일이 aaa 라고 할 때, 각각 최대값과 최소값을 구할 수 있다.

#echo $(sort -k 4 aaa | tail -n 1 | awk '{print $4}') $(sort -r -k 4 aaa | tail -n 1 | awk '{print $4}')
#awk '{print $1}' b | sort -u | wc -l

'A' 라는 파일이 있다고 하자.

1
2
3
4
5
6
7
8
9
10
11
12.3
10000

이제 다음과 같이 명령어를 실행한다.

#awk '{s += $1; cnt += 1} END {printf("%.2f\n", s/cnt) }' A
775.25

위의 명령은 소수점 아래 2자리까지 출력한 것이다. 만일 '%.1f' 로 명령하면, '775.3' 으로 반올림한 값이 출력된다.

한정된 공간에 데이터 로그를 저장해야 하기 때문에 포맷과 용량은 중요하다.

저장 파일 포맷은 다음과 같다.

년-월-일    시:분      Packet_Loss       RTT(MIN)      RTT(AVG)     RTT(MAX)      Data_Traffic      POE

포트가 최대 16 개인 경우, 파일 사이즈를 계산해보면, 1줄 당 42 byte 이다. 일 주일 동안의 로그를 저장한다면, 예상되는 파일 사이즈는 아래와 같다.

'42(byte) X 60(min) X 24(hour) X 7(day) X 16(port) = 6773760(약 6.45 MB)'

위 수치는 16 포트 IPX 에서 일주일간에 저장한 파일 사이즈를 구한 것이다.

일반적인 방법은 아래와 같이 명령어를 실행하는 방법이다.

#crontab -e

하지만, 직접 타이핑으로 추가해야 하기 때문에 번거롭다. task 를 추가하고, 저장하면, 자동으로 어딘가에 저장이 되고, 이후 부터 task 가 적용된다.
어딘가에 저장되는 파일은 '/var/spool/cron/crontabs/root' 이다. 결국 이 파일을 수정하면 되는 것이다. 이때 유의할 것은 수정 후, 기존의 crond 프로세스를 죽이고(killall crond), 다시 실행해야 반영이 된다는 것이다.

#killall crond
#crond -l 0

일반 PC 에 설치된 gnu date 에서 가능한 명령어가 busybox 상의 date 에서는 해당 명령어 지원이 안된다. 대표적인 것이 날짜를 계산해주는 것인데, 아래와 같은 방법으로 사용이 가능하다.
아래 예제는 현재 시간보다 하루 전의 날짜를 출력한다.

#date +"%y-%m-%d" -D '%s' -d "$(( `busybox date +%s`-1*60*60*24 ))"

이를 스크립트로 나타내면 아래와 같다.

#!/bin/sh
AA=`date +%s`
BB=`expr $AA - \( 1 \* 60 \* 60 \* 24 \)`
 
TODAY3=`date +"%y-%m-%d" -D '%s' -d "$BB"`
 
echo $AA
echo $BB
echo $TODAY3
  • computer/itx/network_diagnostic.txt
  • Last modified: 3 years ago
  • by likewind