[SEBA-819][SEBA-820] Adding commands to restart EAPOL and DHCP

Change-Id: I283dcae58bc5dbf0ef405c4ce6b5f2e8b818b993
diff --git a/Makefile b/Makefile
index 130603c..20d2723 100644
--- a/Makefile
+++ b/Makefile
@@ -47,9 +47,12 @@
 docker-push: # @HELP Push a docker container to a registry
 	docker push ${DOCKER_REGISTRY}${DOCKER_REPOSITORY}bbsim:${DOCKER_TAG}
 
-docker-run: # @HELP Run the container locally (intended for development purposes: DOCKER_RUN_ARGS="-pon 2 -onu 2" make docker-run)
+docker-run: # @HELP Runs the container locally (available options: DOCKER_RUN_ARGS="-pon 2 -onu 2" make docker-run)
 	docker run -d -p 50070:50070 -p 50060:50060 --privileged --rm --name bbsim ${DOCKER_REGISTRY}${DOCKER_REPOSITORY}bbsim:${DOCKER_TAG} /app/bbsim ${DOCKER_RUN_ARGS}
 
+docker-run-dev: # @HELP Runs the container locally (intended for development purposes, not in detached mode)
+	docker run -p 50070:50070 -p 50060:50060 --privileged --rm --name bbsim ${DOCKER_REGISTRY}${DOCKER_REPOSITORY}bbsim:${DOCKER_TAG} /app/bbsim ${DOCKER_RUN_ARGS}
+
 .PHONY: docs
 docs: # @HELP Generate docs and opens them in the browser
 	pushd docs; make doc_venv; make html; popd
diff --git a/README.md b/README.md
index 8c9c657..a7ec3e2 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@
 Documentation
 =============
 
-More advanced documentation lives in [here](./docs/index.rst).
+More advanced documentation lives in [here](./docs/source/index.rst).
 
 You can generate and browse the documentation by executing:
 
diff --git a/api/bbsim/bbsim.proto b/api/bbsim/bbsim.proto
index 85581fc..29583c5 100644
--- a/api/bbsim/bbsim.proto
+++ b/api/bbsim/bbsim.proto
@@ -87,4 +87,6 @@
     rpc SetLogLevel(LogLevel) returns (LogLevel) {}
     rpc ShutdownONU (ONURequest) returns (Response) {}
     rpc PoweronONU (ONURequest) returns (Response) {}
+    rpc RestartEapol (ONURequest) returns (Response) {}
+    rpc RestartDhcp (ONURequest) returns (Response) {}
 }
\ No newline at end of file
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 5aabec3..184fcfa 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -10,6 +10,7 @@
    :maxdepth: 2
    :caption: Contents:
 
+   operations.rst
    onu-state-machine.rst
    development-dependencies.rst
    bbr.rst
diff --git a/docs/source/onu-state-machine.rst b/docs/source/onu-state-machine.rst
index 9df3ca6..f66dd22 100644
--- a/docs/source/onu-state-machine.rst
+++ b/docs/source/onu-state-machine.rst
@@ -3,46 +3,46 @@
 ONU State Machine
 =================
 
-In ``BBSim`` the device state is createdtained using a state machine
+In ``BBSim`` the device state is created using a state machine
 library: `fsm <https://github.com/looplab/fsm>`__.
 
 Here is a list of possible state transitions in BBSim:
 
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| Transition                     | Starting States                                                                        | End State                      | Notes                                                                                         |
-+================================+========================================================================================+================================+===============================================================================================+
-|                                |                                                                                        | created                        |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| discover                       | created                                                                                | discovered                     |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| enable                         | discovered, disabled                                                                   | enabled                        |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| receive_eapol_flow             | enabled, gem_port_added                                                                | eapol_flow_received            |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| add_gem_port                   | enabled, eapol_flow_received                                                           | gem_port_added                 | We need to wait for both the flow and the gem port to come before moving to ``auth_started``  |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| start_auth                     | eapol_flow_received, gem_port_added                                                    | auth_started                   |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| eap_start_sent                 | auth_started                                                                           | eap_start_sent                 |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| eap_response_identity_sent     | eap_start_sent                                                                         | eap_response_identity_sent     |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| eap_response_challenge_sent    | eap_response_identity_sent                                                             | eap_response_challenge_sent    |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| eap_response_success_received  | eap_response_challenge_sent                                                            | eap_response_success_received  |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| auth_failed                    | auth_started, eap_start_sent, eap_response_identity_sent, eap_response_challenge_sent  | auth_failed                    |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| start_dhcp                     | eap_response_success_received                                                          | dhcp_started                   |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| dhcp_discovery_sent            | dhcp_started                                                                           | dhcp_discovery_sent            |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| dhcp_request_sent              | dhcp_discovery_sent                                                                    | dhcp_request_sent              |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| dhcp_ack_received              | dhcp_request_sent                                                                      | dhcp_ack_received              |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
-| dhcp_failed                    | dhcp_started, dhcp_discovery_sent, dhcp_request_sent                                   | dhcp_failed                    |                                                                                               |
-+--------------------------------+----------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| Transition                     | Starting States                                                                                                   | End State                      | Notes                                                                                         |
++================================+===================================================================================================================+================================+===============================================================================================+
+|                                |                                                                                                                   | created                        |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| discover                       | created                                                                                                           | discovered                     |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| enable                         | discovered, disabled                                                                                              | enabled                        |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| receive_eapol_flow             | enabled, gem_port_added                                                                                           | eapol_flow_received            |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| add_gem_port                   | enabled, eapol_flow_received                                                                                      | gem_port_added                 | We need to wait for both the flow and the gem port to come before moving to ``auth_started``  |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| start_auth                     | eapol_flow_received, gem_port_added, eap_response_success_received, auth_failed, dhcp_ack_received, dhcp_failed   | auth_started                   |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| eap_start_sent                 | auth_started                                                                                                      | eap_start_sent                 |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| eap_response_identity_sent     | eap_start_sent                                                                                                    | eap_response_identity_sent     |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| eap_response_challenge_sent    | eap_response_identity_sent                                                                                        | eap_response_challenge_sent    |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| eap_response_success_received  | eap_response_challenge_sent                                                                                       | eap_response_success_received  |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| auth_failed                    | auth_started, eap_start_sent, eap_response_identity_sent, eap_response_challenge_sent                             | auth_failed                    |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| start_dhcp                     | eap_response_success_received, dhcp_ack_received, dhcp_failed                                                     | dhcp_started                   |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| dhcp_discovery_sent            | dhcp_started                                                                                                      | dhcp_discovery_sent            |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| dhcp_request_sent              | dhcp_discovery_sent                                                                                               | dhcp_request_sent              |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| dhcp_ack_received              | dhcp_request_sent                                                                                                 | dhcp_ack_received              |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
+| dhcp_failed                    | dhcp_started, dhcp_discovery_sent, dhcp_request_sent                                                              | dhcp_failed                    |                                                                                               |
++--------------------------------+-------------------------------------------------------------------------------------------------------------------+--------------------------------+-----------------------------------------------------------------------------------------------+
 
 In addition some transition can be forced via the API:
 
@@ -98,6 +98,11 @@
         eap_response_identity_sent -> auth_failed
         eap_response_challenge_sent -> auth_failed
 
+        eap_response_success_received -> auth_started
+        auth_failed -> auth_started
+        dhcp_ack_received -> auth_started
+        dhcp_failed -> auth_started
+
         eap_response_success_received -> dhcp_started
         dhcp_started -> dhcp_discovery_sent -> dhcp_request_sent -> dhcp_ack_received
         dhcp_started -> dhcp_failed
@@ -110,4 +115,7 @@
         dhcp_ack_received -> disabled
         dhcp_failed -> disabled
         disabled -> enabled
+
+        dhcp_ack_received -> dhcp_started
+        dhcp_failed -> dhcp_started
     }
\ No newline at end of file
diff --git a/docs/source/operations.rst b/docs/source/operations.rst
new file mode 100644
index 0000000..0879a84
--- /dev/null
+++ b/docs/source/operations.rst
@@ -0,0 +1,63 @@
+.. _Operations:
+
+BBSim Operations
+================
+
+If you are testing basic functionality using BBSim no operator intervention is required.
+
+When you ``enable`` the device in VOLTHA the simulator will:
+
+- activate all the configured ONUs
+- wait for the EAPOL flow for each ONU and trigger the authentication state machine as soon as it's received
+- wait for the DHCP flow for each ONU and trigger the DHCP state machine as soon as it's received
+
+Access bbsimctl
+---------------
+
+When running a test you can check the state of each ONU using :ref:`BBSimCtl`.
+
+The easiest way to use ``bbsimctl`` is to ``exec`` inside the ``bbsim`` container:
+
+.. code:: bash
+
+    kubectl exec -it -n voltha -f $(kubectl get pods -n voltha | grep bbsim | awk '{print $1}') bash
+
+Check the ONU Status
+--------------------
+
+.. code:: bash
+
+    $ bbsimctl onu list
+    PONPORTID    ID    PORTNO    SERIALNUMBER    HWADDRESS            STAG    CTAG    OPERSTATE    INTERNALSTATE
+    0            1     0         BBSM00000001    2e:60:70:13:00:01    900     900     up           dhcp_ack_received
+
+Advanced operations
+-------------------
+
+In certain cases you may want to execute operations on the BBSim ONUs.
+
+Here are the one currently supported, for more usage information use the following commands:
+
+.. code:: bash
+
+    $ bbsimctl onu --help
+    Usage:
+      bbsimctl [OPTIONS] onu <command>
+
+    Commands to query and manipulate ONU devices
+
+    Global Options:
+      -c, --config=FILE           Location of client config file [$BBSIMCTL_CONFIG]
+      -s, --server=SERVER:PORT    IP/Host and port of XOS
+      -d, --debug                 Enable debug mode
+
+    Help Options:
+      -h, --help                  Show this help message
+
+    Available commands:
+      auth_restart
+      dhcp_restart
+      get
+      list
+      poweron
+      shutdown
\ No newline at end of file
diff --git a/internal/bbsim/api/onus_handler.go b/internal/bbsim/api/onus_handler.go
index 7f42f89..8feee21 100644
--- a/internal/bbsim/api/onus_handler.go
+++ b/internal/bbsim/api/onus_handler.go
@@ -158,3 +158,71 @@
 
 	return res, nil
 }
+
+func (s BBSimServer) RestartEapol(ctx context.Context, req *bbsim.ONURequest) (*bbsim.Response, error) {
+	res := &bbsim.Response{}
+
+	logger.WithFields(log.Fields{
+		"OnuSn": req.SerialNumber,
+	}).Infof("Received request to restart authentication ONU")
+
+	olt := devices.GetOLT()
+
+	onu, err := olt.FindOnuBySn(req.SerialNumber)
+
+	if err != nil {
+		res.StatusCode = int32(codes.NotFound)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	if err := onu.InternalState.Event("start_auth"); err != nil {
+		logger.WithFields(log.Fields{
+			"OnuId":  onu.ID,
+			"IntfId": onu.PonPortID,
+			"OnuSn":  onu.Sn(),
+		}).Errorf("Cannot restart authenticaton for ONU: %s", err.Error())
+		res.StatusCode = int32(codes.FailedPrecondition)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	res.StatusCode = int32(codes.OK)
+	res.Message = fmt.Sprintf("Authentication restarted for ONU %s.", onu.Sn())
+
+	return res, nil
+}
+
+func (s BBSimServer) RestartDhcp(ctx context.Context, req *bbsim.ONURequest) (*bbsim.Response, error) {
+	res := &bbsim.Response{}
+
+	logger.WithFields(log.Fields{
+		"OnuSn": req.SerialNumber,
+	}).Infof("Received request to restart DHCP on ONU")
+
+	olt := devices.GetOLT()
+
+	onu, err := olt.FindOnuBySn(req.SerialNumber)
+
+	if err != nil {
+		res.StatusCode = int32(codes.NotFound)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	if err := onu.InternalState.Event("start_dhcp"); err != nil {
+		logger.WithFields(log.Fields{
+			"OnuId":  onu.ID,
+			"IntfId": onu.PonPortID,
+			"OnuSn":  onu.Sn(),
+		}).Errorf("Cannot restart DHCP for ONU: %s", err.Error())
+		res.StatusCode = int32(codes.FailedPrecondition)
+		res.Message = err.Error()
+		return res, err
+	}
+
+	res.StatusCode = int32(codes.OK)
+	res.Message = fmt.Sprintf("DHCP restarted for ONU %s.", onu.Sn())
+
+	return res, nil
+}
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index 69721df..a5aa208 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -106,14 +106,14 @@
 			// NOTE should disabled state be diffente for oper_disabled (emulating an error) and admin_disabled (received a disabled call via VOLTHA)?
 			{Name: "disable", Src: []string{"eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}, Dst: "disabled"},
 			// EAPOL
-			{Name: "start_auth", Src: []string{"eapol_flow_received", "gem_port_added"}, Dst: "auth_started"},
+			{Name: "start_auth", Src: []string{"eapol_flow_received", "gem_port_added", "eap_response_success_received", "auth_failed", "dhcp_ack_received", "dhcp_failed"}, Dst: "auth_started"},
 			{Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
 			{Name: "eap_response_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_response_identity_sent"},
 			{Name: "eap_response_challenge_sent", Src: []string{"eap_response_identity_sent"}, Dst: "eap_response_challenge_sent"},
 			{Name: "eap_response_success_received", Src: []string{"eap_response_challenge_sent"}, Dst: "eap_response_success_received"},
 			{Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_response_identity_sent", "eap_response_challenge_sent"}, Dst: "auth_failed"},
 			// DHCP
-			{Name: "start_dhcp", Src: []string{"eap_response_success_received"}, Dst: "dhcp_started"},
+			{Name: "start_dhcp", Src: []string{"eap_response_success_received", "dhcp_ack_received", "dhcp_failed"}, Dst: "dhcp_started"},
 			{Name: "dhcp_discovery_sent", Src: []string{"dhcp_started"}, Dst: "dhcp_discovery_sent"},
 			{Name: "dhcp_request_sent", Src: []string{"dhcp_discovery_sent"}, Dst: "dhcp_request_sent"},
 			{Name: "dhcp_ack_received", Src: []string{"dhcp_request_sent"}, Dst: "dhcp_ack_received"},
diff --git a/internal/bbsimctl/commands/onu.go b/internal/bbsimctl/commands/onu.go
index 716c7d3..620e052 100644
--- a/internal/bbsimctl/commands/onu.go
+++ b/internal/bbsimctl/commands/onu.go
@@ -55,11 +55,25 @@
 	} `positional-args:"yes" required:"yes"`
 }
 
+type ONUEapolRestart struct {
+	Args struct {
+		OnuSn OnuSnString
+	} `positional-args:"yes" required:"yes"`
+}
+
+type ONUDhcpRestart struct {
+	Args struct {
+		OnuSn OnuSnString
+	} `positional-args:"yes" required:"yes"`
+}
+
 type ONUOptions struct {
-	List     ONUList     `command:"list"`
-	Get      ONUGet      `command:"get"`
-	ShutDown ONUShutDown `command:"shutdown"`
-	PowerOn  ONUPowerOn  `command:"poweron"`
+	List         ONUList         `command:"list"`
+	Get          ONUGet          `command:"get"`
+	ShutDown     ONUShutDown     `command:"shutdown"`
+	PowerOn      ONUPowerOn      `command:"poweron"`
+	RestartEapol ONUEapolRestart `command:"auth_restart"`
+	RestartDchp  ONUDhcpRestart  `command:"dhcp_restart"`
 }
 
 func RegisterONUCommands(parser *flags.Parser) {
@@ -142,7 +156,7 @@
 	res, err := client.ShutdownONU(ctx, &req)
 
 	if err != nil {
-		log.Fatalf("Cannot not shutdown ONU %s: %v", options.Args.OnuSn, err)
+		log.Fatalf("Cannot shutdown ONU %s: %v", options.Args.OnuSn, err)
 		return err
 	}
 
@@ -163,7 +177,49 @@
 	res, err := client.PoweronONU(ctx, &req)
 
 	if err != nil {
-		log.Fatalf("Cannot not power on ONU %s: %v", options.Args.OnuSn, err)
+		log.Fatalf("Cannot power on ONU %s: %v", options.Args.OnuSn, err)
+		return err
+	}
+
+	fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
+
+	return nil
+}
+
+func (options *ONUEapolRestart) Execute(args []string) error {
+	client, conn := connect()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+	req := pb.ONURequest{
+		SerialNumber: string(options.Args.OnuSn),
+	}
+	res, err := client.RestartEapol(ctx, &req)
+
+	if err != nil {
+		log.Fatalf("Cannot restart EAPOL for ONU %s: %v", options.Args.OnuSn, err)
+		return err
+	}
+
+	fmt.Println(fmt.Sprintf("[Status: %d] %s", res.StatusCode, res.Message))
+
+	return nil
+}
+
+func (options *ONUDhcpRestart) Execute(args []string) error {
+	client, conn := connect()
+	defer conn.Close()
+
+	ctx, cancel := context.WithTimeout(context.Background(), config.GlobalConfig.Grpc.Timeout)
+	defer cancel()
+	req := pb.ONURequest{
+		SerialNumber: string(options.Args.OnuSn),
+	}
+	res, err := client.RestartDhcp(ctx, &req)
+
+	if err != nil {
+		log.Fatalf("Cannot restart DHCP for ONU %s: %v", options.Args.OnuSn, err)
 		return err
 	}