VOL-1282 BBSim - Add reboot-related features

Change-Id: I9a1ce85eae18e42361956942aaf8d8fae0cc0802
diff --git a/Dockerfile b/Dockerfile
index 3d95450..d1aebf1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,10 +1,10 @@
-# Copyright 2018 the original author or authors.
+# Copyright 2018-present Open Networking Foundation
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
 #
-#      http://www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,49 +14,48 @@
 
 # bbsim dockerfile
 
-ARG TAG=latest
-ARG REGISTRY=
-ARG REPOSITORY=
+# builder parent
+FROM golang:1.10-stretch as builder
 
-#builder parent
-FROM ubuntu:16.04
+# install prereqs
+ENV PROTOC_VERSION 3.6.1
+ENV PROTOC_SHA256SUM 6003de742ea3fcf703cfec1cd4a3380fd143081a2eb0e559065563496af27807
 
-MAINTAINER Voltha Community <info@opennetworking.org>
+RUN apt-get update \
+ && apt-get install -y unzip libpcap-dev \
+ && curl -L -o /tmp/protoc-${PROTOC_VERSION}-linux-x86_64.zip https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip \
+ && echo "$PROTOC_SHA256SUM  /tmp/protoc-${PROTOC_VERSION}-linux-x86_64.zip" | sha256sum -c - \
+ && unzip /tmp/protoc-${PROTOC_VERSION}-linux-x86_64.zip -d /tmp/protoc3 \
+ && mv /tmp/protoc3/bin/* /usr/local/bin/ \
+ && mv /tmp/protoc3/include/* /usr/local/include/ \
+ && go get -v github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway \
+ && go get -v github.com/golang/protobuf/protoc-gen-go
 
-# Install required packages
-RUN apt-get update && apt-get install -y wget git make libpcap-dev gcc unzip
-ARG version="1.9.3."
-RUN wget https://storage.googleapis.com/golang/go${version}linux-amd64.tar.gz -P /tmp \
-    && tar -C /usr/local -xzf /tmp/go${version}linux-amd64.tar.gz \
-    && rm /tmp/go${version}linux-amd64.tar.gz
+# copy and build
+WORKDIR /go/src/gerrit.opencord.org/voltha-bbsim
+COPY . /go/src/gerrit.opencord.org/voltha-bbsim
 
-# Set PATH
-ENV GOPATH $HOME/go
-ENV PATH /usr/local/go/bin:/go/bin:$PATH
+RUN make bbsim
 
-# Copy source code
-RUN mkdir -p $GOPATH/src/gerrit.opencord.org/voltha-bbsim
-COPY . $GOPATH/src/gerrit.opencord.org/voltha-bbsim
+# runtime parent
+FROM golang:1.10-stretch
 
-# Install golang protobuf and pcap support
-RUN wget https://github.com/google/protobuf/releases/download/v3.6.0/protoc-3.6.0-linux-x86_64.zip -P /tmp/ \
-&& unzip /tmp/protoc-3.6.0-linux-x86_64.zip -d /tmp/ \
-&& mv /tmp/bin/* /usr/local/bin/ \
-&& mv /tmp/include/* /usr/local/include/ \
-&& go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway \
-&& go get -u github.com/golang/protobuf/protoc-gen-go \
-&& go get -u github.com/google/gopacket/pcap \
-&& go get -u golang.org/x/net/context \
-&& go get -u google.golang.org/grpc
+# runtime prereqs
+# the symlink on libpcap is because both alpine and debian come with 1.8.x, but
+# debian symlinks it to 0.8 for historical reasons:
+# https://packages.debian.org/stretch/libpcap0.8-dev
+RUN apt-get update \
+ && apt-get install -y libpcap-dev wpasupplicant isc-dhcp-server network-manager\
+ && ln -s /usr/lib/libpcap.so.1.8.1 /usr/lib/libpcap.so.0.8
 
-# ... Install utilities & config
-RUN apt-get update && apt-get install -y wpasupplicant isc-dhcp-server
 COPY ./config/wpa_supplicant.conf /etc/wpa_supplicant/
 COPY ./config/isc-dhcp-server /etc/default/
 COPY ./config/dhcpd.conf /etc/dhcp/
 RUN mv /usr/sbin/dhcpd /usr/local/bin/ \
-&& mv /sbin/dhclient /usr/local/bin/
+&& mv /sbin/dhclient /usr/local/bin/ \
+&& touch /var/lib/dhcp/dhcpd.leases
 
-WORKDIR $GOPATH/src/gerrit.opencord.org/voltha-bbsim
-RUN make bbsim
+WORKDIR /app
+COPY --from=builder /go/src/gerrit.opencord.org/voltha-bbsim/bbsim /app/bbsim
 
+CMD [ '/app/bbsim' ]
diff --git a/Makefile b/Makefile
index 56bbcb2..2c3bf1e 100644
--- a/Makefile
+++ b/Makefile
@@ -21,22 +21,30 @@
 	go build -i -v -o $@
 
 dep: protos/openolt.pb.go
-	@go get -v -d ./...
+	go get -v -d ./...
 
 protos/openolt.pb.go: openolt.proto
 	@protoc -I . \
 	-I${GOPATH}/src \
 	-I${GOPATH}/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
 	--go_out=plugins=grpc:protos/ \
-	openolt.proto
+	$<
 
 test:
-	@go test -v ./...
-	@go test -v ./... -cover
+	go test -v ./...
+	go test -v ./... -cover
+
+fmt:
+	go fmt ./...
+
+vet:
+	go vet ./...
+
+lint:
+	gometalinter --vendor --exclude ../../golang.org --skip protos --sort path --sort line ./...
 
 clean:
-	@rm bbsim protos/openolt.pb.go
+	rm -f bbsim openolt/openolt.pb.go
 
 docker:
-	@docker build -t voltha/voltha-bbsim:${DOCKERTAG} .
-
+	docker build -t voltha/voltha-bbsim:${DOCKERTAG} .
diff --git a/bbsim.go b/bbsim.go
old mode 100755
new mode 100644
index 27373f8..1950668
--- a/bbsim.go
+++ b/bbsim.go
@@ -73,7 +73,7 @@
 	addressport := ip + ":" + strconv.Itoa(int(port))
 	endchan := make(chan int, 1)
 	listener, gserver, err := core.CreateGrpcServer(oltid, npon, nonus, addressport)
-	server := core.CreateServer(oltid, npon, nonus, aaawait, dhcpwait, dhcpservip, gserver, mode, endchan)
+	server := core.Create(oltid, npon, nonus, aaawait, dhcpwait, dhcpservip, gserver, mode, endchan)
 	if err != nil {
 		log.Println(err)
 	}
diff --git a/config/dhcpd.conf b/config/dhcpd.conf
index 9f36163..06d366b 100644
--- a/config/dhcpd.conf
+++ b/config/dhcpd.conf
@@ -35,20 +35,10 @@
 
 # This is a very basic subnet declaration.
 subnet 182.21.0.0 netmask 255.255.0.0 {
-  range 182.21.0.1 182.21.0.32;
+  range 182.21.0.1 182.21.0.128;
   option routers 182.21.0.254;
 }
 
-#subnet 182.22.0.0 netmask 255.255.0.0 {
-#  range 182.22.0.1 182.22.0.240;
-#  option routers 182.22.0.254;
-#}
-
-#subnet 172.20.0.0 netmask 255.255.0.0 {
-#  range 172.20.0.1 172.20.0.240;
-#  option routers 172.20.0.254;
-#}
-
 #subnet 10.254.239.0 netmask 255.255.255.224 {
 #  range 10.254.239.10 10.254.239.20;
 #  option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org;
diff --git a/core/core_server.go b/core/core_server.go
index 9e609c5..7067b3f 100644
--- a/core/core_server.go
+++ b/core/core_server.go
@@ -17,10 +17,10 @@
 package core
 
 import (
+	"errors"
 	"gerrit.opencord.org/voltha-bbsim/device"
 	"gerrit.opencord.org/voltha-bbsim/protos"
 	"gerrit.opencord.org/voltha-bbsim/setup"
-	"errors"
 	"github.com/google/gopacket"
 	"github.com/google/gopacket/layers"
 	"github.com/google/gopacket/pcap"
@@ -51,6 +51,9 @@
 	DhcpWait     int
 	DhcpServerIP string
 	gRPCserver   *grpc.Server
+	VethEnv      []string
+	TestFlag     bool
+	Processes    []string
 }
 
 type Packet struct {
@@ -58,7 +61,15 @@
 	Pkt  gopacket.Packet
 }
 
-func CreateServer(oltid uint32, npon uint32, nonus uint32, aaawait int, dhcpwait int, ip string, g *grpc.Server, mode Mode, e chan int) *Server {
+func (s *Server)Initialize(){
+	s.VethEnv = []string{}
+	s.Endchan = make(chan int)
+	s.TestFlag = false
+	s.Processes = []string{}
+	s.Ioinfos = []*Ioinfo{}
+}
+
+func Create(oltid uint32, npon uint32, nonus uint32, aaawait int, dhcpwait int, ip string, g *grpc.Server, mode Mode, e chan int) *Server {
 	s := new(Server)
 	s.Olt = device.CreateOlt(oltid, npon, 1)
 	nnni := s.Olt.NumNniIntf
@@ -70,6 +81,8 @@
 	s.gRPCserver = g
 	s.Mode = mode
 	s.Endchan = e
+	s.VethEnv = []string{}
+	s.TestFlag = false
 	for intfid := nnni; intfid < npon+nnni; intfid++ {
 		s.Onumap[intfid] = device.CreateOnus(oltid, intfid, nonus, nnni)
 	}
@@ -80,14 +93,21 @@
 	// Activate OLT
 	olt := s.Olt
 	oltid := olt.ID
-	vethenv := []string{}
 	wg := &sync.WaitGroup{}
 
+	// DEBUG
+	log.Printf("pointer@activateOLT %p", s)
+	log.Printf("Ioinfos:%v\n", s.Ioinfos)
+	log.Printf("OLT Status:%v\n", s.Olt.OperState)
+	log.Printf("ONUmap:%v\n", s.Onumap)
+	log.Printf("VethEnv:%v\n", s.VethEnv)
+	log.Printf("Processes:%v\n", s.Processes)
+
 	if err := sendOltInd(stream, olt); err != nil {
 		return err
 	}
 	olt.OperState = "up"
-	olt.InternalState = device.OLT_UP
+	*olt.InternalState = device.OLT_UP
 	log.Printf("OLT %s sent OltInd.\n", olt.Name)
 
 	// OLT sends Interface Indication to Adapter
@@ -99,7 +119,7 @@
 
 	// OLT sends Operation Indication to Adapter after activating each interface
 	//time.Sleep(IF_UP_TIME * time.Second)
-	olt.InternalState = device.PONIF_UP
+	*olt.InternalState = device.PONIF_UP
 	if err := sendOperInd(stream, olt); err != nil {
 		log.Printf("[ERROR] Fail to sendOperInd: %v\n", err)
 		return err
@@ -122,6 +142,7 @@
 			break
 		}
 	}
+
 	for intfid, _ := range s.Onumap {
 		sendOnuInd(stream, s.Onumap[intfid])
 		log.Printf("OLT id:%d sent ONUInd.\n", olt.ID)
@@ -133,35 +154,17 @@
 		<-s.Endchan
 		log.Println("core server thread receives close !")
 	} else if s.Mode == AAA || s.Mode == BOTH {
+		s.TestFlag = true
 		var err error
-		s.Ioinfos = []*Ioinfo{}
-		for intfid, _ := range s.Onumap {
-			for i := 0; i < len(s.Onumap[intfid]); i++ {
-				var handler *pcap.Handle
-				onuid := s.Onumap[intfid][i].OnuID
-				uniup, unidw := makeUniName(oltid, intfid, onuid)
-				if handler, vethenv, err = setupVethHandler(uniup, unidw, vethenv); err != nil {
-					return err
-				}
-				iinfo := Ioinfo{name: uniup, iotype: "uni", ioloc: "inside", intfid: intfid, onuid: onuid, handler: handler}
-				s.Ioinfos = append(s.Ioinfos, &iinfo)
-				oinfo := Ioinfo{name: unidw, iotype: "uni", ioloc: "outside", intfid: intfid, onuid: onuid, handler: nil}
-				s.Ioinfos = append(s.Ioinfos, &oinfo)
-			}
-		}
-		var handler *pcap.Handle
-		nniup, nnidw := makeNniName(oltid)
-		if handler, vethenv, err = setupVethHandler(nniup, nnidw, vethenv); err != nil {
+		s.Ioinfos, s.VethEnv, err = createIoinfos(oltid, s.VethEnv, s.Onumap)
+		log.Println("s.VethEnv", s.VethEnv)
+		if err != nil {
 			return err
 		}
-		iinfo := Ioinfo{name: nnidw, iotype: "nni", ioloc: "inside", intfid: 1, handler: handler}
-		s.Ioinfos = append(s.Ioinfos, &iinfo)
-		oinfo := Ioinfo{name: nnidw, iotype: "nni", ioloc: "outside", intfid: 1, handler: nil}
-		s.Ioinfos = append(s.Ioinfos, &oinfo)
 
 		errchan := make(chan error)
 		go func() {
-			<-errchan
+			<- errchan
 			close(s.Endchan)
 		}()
 
@@ -171,6 +174,7 @@
 				log.Println("runPacketInDaemon Done")
 				wg.Done()
 			}()
+
 			err := s.runPacketInDaemon(stream)
 			if err != nil {
 				errchan <- err
@@ -184,16 +188,8 @@
 				log.Println("exeAAATest Done")
 				wg.Done()
 			}()
-			infos, err := s.getUniIoinfos("outside")
-			if err != nil {
-				errchan <- err
-				return
-			}
-			univeths := []string{}
-			for _, info := range infos {
-				univeths = append(univeths, info.name)
-			}
-			err = s.exeAAATest(univeths)
+
+			err = s.exeAAATest()
 			if err != nil {
 				errchan <- err
 				return
@@ -204,19 +200,8 @@
 					defer func() {
 						log.Println("exeDHCPTest Done")
 					}()
-					info, err := s.identifyNniIoinfo("outside")
-					setup.ActivateDHCPServer(info.name, s.DhcpServerIP)
 
-					infos, err := s.getUniIoinfos("outside")
-					if err != nil {
-						errchan <- err
-						return
-					}
-					univeths := []string{}
-					for _, info := range infos {
-						univeths = append(univeths, info.name)
-					}
-					err = s.exeDHCPTest(univeths)
+					err := s.exeDHCPTest()
 					if err != nil {
 						errchan <- err
 						return
@@ -225,12 +210,45 @@
 			}
 		}()
 		wg.Wait()
-		tearDown(vethenv) // Grace teardown
+		cleanUpVeths(s.VethEnv) // Grace teardown
+		pnames := s.Processes
+		killProcesses(pnames)
 		log.Println("Grace shutdown down")
 	}
 	return nil
 }
 
+func createIoinfos(oltid uint32, vethenv []string, onumap map[uint32][]*device.Onu)([]*Ioinfo, []string, error){
+	ioinfos := []*Ioinfo{}
+	var err error
+	for intfid, _ := range onumap {
+		for i := 0; i < len(onumap[intfid]); i++ {
+			var handler *pcap.Handle
+			onuid := onumap[intfid][i].OnuID
+			uniup, unidw := makeUniName(oltid, intfid, onuid)
+			if handler, vethenv, err = setupVethHandler(uniup, unidw, vethenv); err != nil {
+				return ioinfos, vethenv, err
+			}
+			iinfo := Ioinfo{name: uniup, iotype: "uni", ioloc: "inside", intfid: intfid, onuid: onuid, handler: handler}
+			ioinfos = append(ioinfos, &iinfo)
+			oinfo := Ioinfo{name: unidw, iotype: "uni", ioloc: "outside", intfid: intfid, onuid: onuid, handler: nil}
+			ioinfos = append(ioinfos, &oinfo)
+		}
+	}
+
+	var handler *pcap.Handle
+	nniup, nnidw := makeNniName(oltid)
+	if handler, vethenv, err = setupVethHandler(nniup, nnidw, vethenv); err != nil {
+		return ioinfos, vethenv, err
+	}
+	//TODO: Intfid should be modified
+	iinfo := Ioinfo{name: nnidw, iotype: "nni", ioloc: "inside", intfid: 1, handler: handler}
+	ioinfos = append(ioinfos, &iinfo)
+	oinfo := Ioinfo{name: nniup, iotype: "nni", ioloc: "outside", intfid: 1, handler: nil}
+	ioinfos = append(ioinfos, &oinfo)
+	return ioinfos, vethenv, nil
+}
+
 func (s *Server) runPacketInDaemon(stream openolt.Openolt_EnableIndicationServer) error {
 	log.Println("runPacketInDaemon Start")
 	unichannel := make(chan Packet, 2048)
@@ -268,6 +286,7 @@
 				log.Println("[WARNING] This packet does not come from UNI !")
 				continue
 			}
+
 			intfid := unipkt.Info.intfid
 			onuid := unipkt.Info.onuid
 			gemid, _ := getGemPortID(intfid, onuid)
@@ -286,17 +305,20 @@
 			} else {
 				continue
 			}
+
 			log.Printf("sendPktInd intfid:%d (onuid: %d) gemid:%d\n", intfid, onuid, gemid)
 			data = &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{IntfType: "pon", IntfId: intfid, GemportId: gemid, Pkt: pkt.Data()}}
 			if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
 				log.Printf("[ERROR] Failed to send PktInd indication. %v\n", err)
 				return err
 			}
+
 		case nnipkt := <-nnichannel:
 			if nnipkt.Info == nil || nnipkt.Info.iotype != "nni" {
 				log.Println("[WARNING] This packet does not come from NNI !")
 				continue
 			}
+
 			log.Println("Received packet in grpc Server from NNI.")
 			intfid := nnipkt.Info.intfid
 			pkt := nnipkt.Pkt
@@ -306,6 +328,7 @@
 				log.Printf("[ERROR] Failed to send PktInd indication. %v\n", err)
 				return err
 			}
+
 		case <-s.Endchan:
 			if flag == false {
 				log.Println("PacketInDaemon thread receives close !")
@@ -313,6 +336,7 @@
 				log.Println("Closed unichannel !")
 				close(nnichannel)
 				log.Println("Closed nnichannel !")
+
 				flag = true
 				return nil
 			}
@@ -321,41 +345,77 @@
 	return nil
 }
 
-func (s *Server) exeAAATest(vethenv []string) error {
+func (s *Server) exeAAATest() error {
 	log.Println("exeAAATest Start")
-	for i := 0; i < s.AAAWait; i++ {
+	infos, err := s.getUniIoinfos("outside")
+	if err != nil {
+		return err
+	}
+
+	univeths := []string{}
+	for _, info := range infos {
+		univeths = append(univeths, info.name)
+	}
+
+	for  {
 		select {
 		case <-s.Endchan:
 			log.Println("exeAAATest thread receives close !")
 			return nil
-		default:
-			log.Println("exeAAATest is now sleeping....")
-			time.Sleep(time.Second)
+		case <- time.After(time.Second * time.Duration(s.AAAWait)):
+			log.Println("timeout")
+			err = setup.ActivateWPASups(univeths)
+			if err != nil {
+				return err
+			}
+			s.Processes = append(s.Processes, "wpa_supplicant")
+			log.Println("s.Processes:", s.Processes)
+			return nil
 		}
 	}
-	err := setup.ActivateWPASups(vethenv)
-	if err != nil {
-		return err
-	}
 	return nil
 }
 
-func (s *Server) exeDHCPTest(vethenv []string) error {
+func (s *Server) exeDHCPTest() error {
 	log.Println("exeDHCPTest Start")
-	for i := 0; i < s.DhcpWait; i++ {
+	info, err := s.identifyNniIoinfo("outside")
+
+	if err != nil {
+		return err
+	}
+
+	err = setup.ActivateDHCPServer(info.name, s.DhcpServerIP)
+	if err != nil {
+		return err
+	}
+	s.Processes = append(s.Processes, "dhcpd")
+
+	infos, err := s.getUniIoinfos("outside")
+	if err != nil {
+		return err
+	}
+
+	univeths := []string{}
+	for _, info := range infos {
+		univeths = append(univeths, info.name)
+	}
+
+	for  {
 		select {
 		case <-s.Endchan:
 			log.Println("exeDHCPTest thread receives close !")
 			return nil
-		default:
-			log.Println("exeDHCPTest is now sleeping....")
-			time.Sleep(time.Second)
+		case <- time.After(time.Second * time.Duration(s.DhcpWait)):
+			log.Println("timeout")
+			err = setup.ActivateDHCPClients(univeths)
+			if err != nil {
+				return err
+			}
+			s.Processes = append(s.Processes, "dhclient")
+			log.Println("s.Processes:", s.Processes)
+			return nil
 		}
 	}
-	err := setup.ActivateDHCPClients(vethenv)
-	if err != nil {
-		return err
-	}
 	return nil
 }
 
@@ -407,7 +467,7 @@
 func (s *Server) IsAllONUActive() bool {
 	for _, onus := range s.Onumap {
 		for _, onu := range onus {
-			if onu.InternalState != device.ONU_ACTIVATED {
+			if *onu.InternalState != device.ONU_ACTIVATED {
 				return false
 			}
 		}
@@ -415,10 +475,6 @@
 	return true
 }
 
-func getVID(onuid uint32) (uint16, error) {
-	return uint16(onuid), nil
-}
-
 func getGemPortID(intfid uint32, onuid uint32) (uint32, error) {
 	idx := uint32(0)
 	return 1024 + (((MAX_ONUS_PER_PON*intfid + onuid - 1) * 7) + idx), nil
@@ -463,11 +519,18 @@
 	return
 }
 
-func tearDown(vethenv []string) error {
-	log.Println("tearDown()")
-	setup.KillAllWPASups()
-	setup.KillAllDHCPClients()
-	setup.TearVethDown(vethenv)
+func cleanUpVeths(vethenv []string) error {
+	if len(vethenv) > 0 {
+		log.Println("cleanUp veths !")
+		setup.TearVethDown(vethenv)
+	}
+	return nil
+}
+
+func killProcesses(pnames []string) error {
+	for _, pname := range  pnames {
+		setup.KillProcess(pname)
+	}
 	return nil
 }
 
diff --git a/core/grpc_service.go b/core/grpc_service.go
index a5bc3e5..e647c9d 100644
--- a/core/grpc_service.go
+++ b/core/grpc_service.go
@@ -45,13 +45,17 @@
 
 func (s *Server) GetDeviceInfo(c context.Context, empty *openolt.Empty) (*openolt.DeviceInfo, error) {
 	log.Printf("OLT receives GetDeviceInfo()\n")
-	return new(openolt.DeviceInfo), nil
+	devinfo := new(openolt.DeviceInfo)
+	devinfo.Vendor = "CORD"
+	devinfo.OnuIdStart = 0
+	devinfo.OnuIdEnd = 3
+	devinfo.PonPorts = 4
+	return devinfo, nil
 }
 
 func (s *Server) ActivateOnu(c context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
 	log.Printf("OLT receives ActivateONU()\n")
 	result := device.ValidateONU(*onu, s.Onumap)
-
 	if result == true {
 		matched, error := s.getOnuBySN(onu.SerialNumber)
 		if error != nil {
@@ -59,7 +63,7 @@
 		}
 		onuid := onu.OnuId
 		matched.OnuID = onuid
-		matched.InternalState = device.ONU_ACTIVATED
+		*matched.InternalState = device.ONU_ACTIVATED
 		log.Printf("ONU IntfID: %d OnuID: %d activated succesufully.\n", onu.IntfId, onu.OnuId)
 	}
 	return new(openolt.Empty), nil
@@ -130,6 +134,24 @@
 
 func (s *Server) Reboot(c context.Context, empty *openolt.Empty) (*openolt.Empty, error) {
 	log.Printf("OLT %d receives Reboot ().\n", s.Olt.ID)
+	log.Printf("pointer@Reboot %p", s)
+	// Initialize OLT & Env
+	if s.TestFlag == true{
+		log.Println("Initialize by Reboot")
+		cleanUpVeths(s.VethEnv)
+		close(s.Endchan)
+		processes := s.Processes
+		log.Println("processes:", processes)
+		killProcesses(processes)
+		s.Initialize()
+	}
+	olt := s.Olt
+	olt.InitializeStatus()
+	for intfid, _ := range s.Onumap{
+		for _, onu := range s.Onumap[intfid] {
+			onu.InitializeStatus()
+		}
+	}
 	return new(openolt.Empty), nil
 }
 
diff --git a/core/openolt_service.go b/core/openolt_service.go
index 3f0c311..ffded4d 100644
--- a/core/openolt_service.go
+++ b/core/openolt_service.go
@@ -34,12 +34,14 @@
 func sendIntfInd(stream openolt.Openolt_EnableIndicationServer, olt *device.Olt) error {
 	for i := uint32(0); i < olt.NumPonIntf+olt.NumNniIntf; i++ {
 		intf := olt.Intfs[i]
-		data := &openolt.Indication_IntfInd{&openolt.IntfIndication{IntfId: intf.IntfID, OperState: intf.OperState}}
-		if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
-			log.Printf("Failed to send Intf [id: %d] indication : %v\n", i, err)
-			return err
+		if intf.Type == "pon"{	// There is no need to send IntfInd for NNI
+			data := &openolt.Indication_IntfInd{&openolt.IntfIndication{IntfId: intf.IntfID, OperState: intf.OperState}}
+			if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+				log.Printf("Failed to send Intf [id: %d] indication : %v\n", i, err)
+				return err
+			}
+			log.Printf("SendIntfInd olt:%d intf:%d (%s)\n", olt.ID, intf.IntfID, intf.Type)
 		}
-		log.Printf("SendIntfInd olt:%d intf:%d (%s)\n", olt.ID, intf.IntfID, intf.Type)
 	}
 	return nil
 }
diff --git a/device/device_olt.go b/device/device_olt.go
index a01dda1..b87bc53 100644
--- a/device/device_olt.go
+++ b/device/device_olt.go
@@ -26,7 +26,7 @@
 	SerialNumber       string
 	Manufacture        string
 	Name               string
-	InternalState      oltState
+	InternalState      *oltState
 	OperState          string
 	Intfs              []intf
 	HeartbeatSignature uint32
@@ -51,7 +51,8 @@
 	olt.NumPonIntf = npon
 	olt.NumNniIntf = nnni
 	olt.Name = "BBSIM OLT"
-	olt.InternalState = PRE_ENABLE
+	olt.InternalState = new(oltState)
+	*olt.InternalState = PRE_ENABLE
 	olt.OperState = "up"
 	olt.Intfs = make([]intf, olt.NumPonIntf+olt.NumNniIntf)
 	olt.HeartbeatSignature = oltid
@@ -67,3 +68,18 @@
 	}
 	return &olt
 }
+
+func (olt *Olt)InitializeStatus(){
+	*olt.InternalState = PRE_ENABLE
+	olt.OperState = "up"
+	for i := uint32(0); i < olt.NumNniIntf; i++ {
+		olt.Intfs[i].IntfID = i
+		olt.Intfs[i].OperState = "up"
+		olt.Intfs[i].Type = "nni"
+	}
+	for i := uint32(olt.NumNniIntf); i < olt.NumPonIntf+olt.NumNniIntf; i++ {
+		olt.Intfs[i].IntfID = i
+		olt.Intfs[i].OperState = "up"
+		olt.Intfs[i].Type = "pon"
+	}
+}
diff --git a/device/device_onu.go b/device/device_onu.go
index e7b7c0c..3448799 100644
--- a/device/device_onu.go
+++ b/device/device_onu.go
@@ -30,7 +30,7 @@
 )
 
 type Onu struct {
-	InternalState onuState
+	InternalState *onuState
 	IntfID        uint32
 	OperState     string
 	SerialNumber  *openolt.SerialNumber
@@ -46,7 +46,8 @@
 	onus := []*Onu{}
 	for i := 0; i < int(nonus); i++ {
 		onu := Onu{}
-		onu.InternalState = ONU_PRE_ACTIVATED
+		onu.InternalState = new(onuState)
+		*onu.InternalState = ONU_PRE_ACTIVATED
 		onu.IntfID = intfid
 		onu.OperState = "up"
 		onu.SerialNumber = new(openolt.SerialNumber)
@@ -57,6 +58,11 @@
 	return onus
 }
 
+func (onu *Onu) InitializeStatus(){
+	onu.OperState = "up"
+	*onu.InternalState = ONU_PRE_ACTIVATED
+}
+
 func ValidateONU(targetonu openolt.Onu, regonus map[uint32][]*Onu) bool {
 	for _, onus := range regonus {
 		for _, onu := range onus {
diff --git a/setup/setup_env.go b/setup/setup_env.go
index c391875..72cf9cc 100644
--- a/setup/setup_env.go
+++ b/setup/setup_env.go
@@ -46,21 +46,13 @@
 	return nil
 }
 
-func KillAllWPASups() error {
-	err := exec.Command("pkill", "wpa_supplicant").Run()
+func KillProcess (name string) error {
+	err := exec.Command("pkill", name).Run()
 	if err != nil {
-		log.Printf("[ERROR] Fail to pkill wpa_supplicant: %v\n", err)
+		log.Printf("[ERROR] Fail to pkill %s: %v\n", name, err)
 		return err
 	}
-	return nil
-}
-
-func KillAllDHCPClients() error {
-	err := exec.Command("pkill", "dhclient").Run()
-	if err != nil {
-		log.Printf("[ERROR] Fail to pkill dhclient: %v\n", err)
-		return err
-	}
+	log.Printf("Successfully killed %s\n", name)
 	return nil
 }
 
@@ -129,20 +121,24 @@
 	return
 }
 
-func ActivateDHCPServer(veth string, serverip string) {
-	cmd := "/sbin/ifconfig"
-	err := exec.Command(cmd, veth, serverip, "up").Run()
+func ActivateDHCPServer(veth string, serverip string) error {
+	err := exec.Command("ip", "addr", "add", serverip, "dev",veth).Run()
 	if err != nil {
-		log.Printf("[ERROR] Fail to up %s()\n", veth, err)
-		return
+		log.Printf("[ERROR] Fail to add ip to %s address: %s\n", veth, err)
+		return err
 	}
-	cmd = "/usr/local/bin/dhcpd"
+	err = exec.Command("ip", "link", "set", veth, "up").Run()
+	if err != nil {
+		log.Printf("[ERROR] Fail to set %s up: %s\n", veth, err)
+		return err
+	}
+	cmd := "/usr/local/bin/dhcpd"
 	conf := "/etc/dhcp/dhcpd.conf"
 	err = exec.Command(cmd, "-cf", conf, veth).Run()
 	if err != nil {
 		log.Printf("[ERROR] Fail to activateDHCP Server ()\n", err)
-		return
+		return err
 	}
 	log.Printf("Activate DHCP Server()\n")
-	return
+	return err
 }