[SEBA-817][SEBA-821]
Adding c/s tags and hw address in the onu struct
DHCP State machine completed
Cleaned up logs
Change-Id: Iadb1d3967befe1c402e302a552b67faa2701f5c5
diff --git a/Makefile b/Makefile
index 04f7f15..b2595bd 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,7 @@
DOCKER_TAG ?= ${VERSION}
DOCKER_REPOSITORY ?= voltha/
DOCKER_REGISTRY ?= ""
+DOCKER_RUN_ARGS ?= ""
# Public targets
@@ -43,6 +44,9 @@
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 -p 50070:50070 -p 50060:50060 --privileged --rm --name bbsim ${DOCKER_REGISTRY}${DOCKER_REPOSITORY}bbsim:${DOCKER_TAG} /app/bbsim ${DOCKER_RUN_ARGS}
+
help: # @HELP Print the command options
@echo
@echo "\033[0;31m BroadBand Simulator (BBSim) \033[0m"
diff --git a/README.md b/README.md
index 63e37cd..6a5dcbb 100644
--- a/README.md
+++ b/README.md
@@ -27,15 +27,16 @@
When you install the `BBSim` helm chart you'll notice that the last line of the output
prints the service name and port:
-```
+```bash
+...
NOTES:
BBSim deployed with release name: bbsim
OLT ID: 0
# of NNI Ports: 1
-# of PON Ports: 1
-# of ONU Ports: 1
-Total ONUs: (total: 1)
+# of PON Ports: 2
+# of ONU Ports: 2
+Total ONUs: (total: 4)
OLT is listening on: "voltha.svc.bbsim-olt-id-0:50060"
```
@@ -44,7 +45,7 @@
Connect to the voltha CLI and execute this commands:
-```
+```bash
preprovision_olt -t openolt -H voltha.svc.bbsim-olt-id-0:50060
enable
```
@@ -53,95 +54,94 @@
_This assumes `voltctl` is installed an configured_
-```
-voltctl device create -t openolt -H $(kubectl get -n voltha service/bbsim -o go-template='{{.spec.clusterIP}}'):50060
+```bash
+voltctl device create -t openolt -H bbsim-olt-id-0:50060
voltctl device enable $(voltctl device list --filter Type~openolt -q)
```
## Control API
BBSim comes with a gRPC interface to control the internal state.
-We plan to provide a `bbsimctl` at certain point, meanwhile you can use `grpcurl`:
-
-```
-$ export BBSIM_IP="$(kubectl get svc -n voltha bbsim-olt-id-0 -o go-template='{{.spec.clusterIP}}')"
-$ grpcurl -plaintext $BBSIM_IP:50070 bbsim.BBSim/Version
-{
- "version": "0.0.1-alpha",
- "buildTime": "”2019.08.09.084157”",
- "commitHash": "9ef7241b07a83c326ef152320428f204f7eff43d"
-}
-
-
-$ grpcurl -plaintext $BBSIM_IP:50070 bbsim.BBSim/GetOlt
-{
- "ID": 22,
- "OperState": "up",
- "NNIPorts": [
- {
- "OperState": "down"
- }
- ],
- "PONPorts": [
- {
- "OperState": "down"
- }
- ]
-}
-
-$ grpcurl -plaintext 127.0.0.1:50070 bbsim.BBSim/GetONUs
-{
- "items": [
- {
- "ID": 1,
- "SerialNumber": "vendor_id:\"BBSM\" vendor_specific:\"\\000\\000\\000\\001\" ",
- "OperState": "up",
- "InternalState": "auth_started"
- },
- {
- "ID": 2,
- "SerialNumber": "vendor_id:\"BBSM\" vendor_specific:\"\\000\\000\\000\\002\" ",
- "OperState": "up",
- "InternalState": "auth_started"
- },
- {
- "ID": 1,
- "SerialNumber": "vendor_id:\"BBSM\" vendor_specific:\"\\000\\000\\001\\001\" ",
- "OperState": "up",
- "InternalState": "auth_started",
- "PonPortID": 1
- },
- {
- "ID": 2,
- "SerialNumber": "vendor_id:\"BBSM\" vendor_specific:\"\\000\\000\\001\\002\" ",
- "OperState": "up",
- "InternalState": "auth_started",
- "PonPortID": 1
- }
- ]
-}
-```
-
-## Development
-
-To use a patched version of the `omci-sim` library:
+This interface can be queried using `bbsimctl` (the tool can be build with `make build`):
```bash
-make dep
-cd vendor/github.com/opencord/
-rm -rf omci-sim/
-git clone https://gerrit.opencord.org/omci-sim
-cd omci-sim
+$ ./bbsimctl --help
+Usage:
+ bbsimctl [OPTIONS] <config | olt | onus>
+
+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:
+ config generate bbsimctl configuration
+ olt OLT Commands
+ onus List ONU Devices
```
-Once done, go to `gerrit.opencord.org` and locate the patch you want to get. Click on the download URL and copy the `Checkout` command.
+`bbsimctl` can be configured via a config file such as:
-It should look something like:
-
-```
-git fetch ssh://teone@gerrit.opencord.org:29418/omci-sim refs/changes/67/15067/1 && git checkout FETCH_HEAD
+``` bash
+$ cat ~/.bbsim/config
+apiVersion: v1
+server: 127.0.0.1:50070
+grpc:
+ timeout: 10s
```
-Then just execute that command in the `omci-sim` folder inside the vendored dependencies.
+Some example commands:
+
+```bash
+$ ./bbsimctl olt get
+ID SERIALNUMBER OPERSTATE INTERNALSTATE
+0 BBSIM_OLT_0 up enabled
+
+
+$ ./bbsimctl olt pons
+PON Ports for : BBSIM_OLT_0
+
+ID OPERSTATE
+0 up
+1 up
+2 up
+3 up
+
+
+$ ./bbsimctl onus
+PONPORTID ID SERIALNUMBER STAG CTAG OPERSTATE INTERNALSTATE
+0 1 BBSM00000001 900 900 up eap_response_identity_sent
+0 2 BBSM00000002 900 901 up eap_start_sent
+0 3 BBSM00000003 900 902 up auth_failed
+0 4 BBSM00000004 900 903 up auth_failed
+1 1 BBSM00000101 900 904 up eap_response_success_received
+1 2 BBSM00000102 900 905 up eap_response_success_received
+1 3 BBSM00000103 900 906 up eap_response_challenge_sent
+1 4 BBSM00000104 900 907 up auth_failed
+2 1 BBSM00000201 900 908 up auth_failed
+2 2 BBSM00000202 900 909 up eap_start_sent
+2 3 BBSM00000203 900 910 up eap_response_identity_sent
+2 4 BBSM00000204 900 911 up eap_start_sent
+3 1 BBSM00000301 900 912 up eap_response_identity_sent
+3 2 BBSM00000302 900 913 up auth_failed
+3 3 BBSM00000303 900 914 up auth_failed
+3 4 BBSM00000304 900 915 up auth_failed
+```
+
+## Documentation
+
+More advanced documentation lives in the [here](./docs/README.md)
+
+## Know Issues
+
+In some runs, EAPOL fails with:
+```
+time="2019-09-20T21:24:31Z" level=error msg="Can't send EapStart Message: ONU {intfid:1, onuid:2} - Not DONE (GemportID is not set)" IntfId=1 OnuId=2 OnuSn=BBSM00000102 module=EAPOL
+time="2019-09-20T21:24:31Z" level=error msg="ONU failed to authenticate!" IntfId=1 OnuId=2 OnuSn=BBSM00000102 module=ONU
+```
+Investigate why this happens (we believe the source to be in the OMCI library)
> This project structure is based on [golang-standards/project-layout](https://github.com/golang-standards/project-layout).
diff --git a/api/bbsim/bbsim.proto b/api/bbsim/bbsim.proto
index 1a0134b..81a25f1 100644
--- a/api/bbsim/bbsim.proto
+++ b/api/bbsim/bbsim.proto
@@ -40,6 +40,9 @@
string OperState = 3;
string InternalState = 4;
int32 PonPortID = 5;
+ int32 STag = 6;
+ int32 CTag = 7;
+ string HwAddress = 8;
}
message ONUs {
diff --git a/build/package/Dockerfile b/build/package/Dockerfile
index 93a48d2..2b1484e 100644
--- a/build/package/Dockerfile
+++ b/build/package/Dockerfile
@@ -63,7 +63,7 @@
# 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 isc-dhcp-server network-manager\
+ && apt-get install -y libpcap-dev isc-dhcp-server network-manager tcpdump\
&& ln -s /usr/lib/libpcap.so.1.8.1 /usr/lib/libpcap.so.0.8
COPY ./configs/isc-dhcp-server /etc/default/
@@ -75,4 +75,4 @@
WORKDIR /app
COPY --from=builder /go/src/github.com/opencord/bbsim/cmd/bbsim /app/bbsim
RUN chmod a+x /app/bbsim
-ENTRYPOINT [ '/app/bbsim' ]
+CMD [ '/app/bbsim' ]
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index fe4d5d3..710182d 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1 +1,4 @@
-Coming soon
\ No newline at end of file
+# BBSim Documentation
+
+- [ONU State Machine](./onu-state-machine.md)
+- [Using development dependencies](./development-dependencies.md)
\ No newline at end of file
diff --git a/docs/development-dependencies.md b/docs/development-dependencies.md
new file mode 100644
index 0000000..fa1a474
--- /dev/null
+++ b/docs/development-dependencies.md
@@ -0,0 +1,21 @@
+# Development dependencies
+
+To use a patched version of the `omci-sim` library:
+
+```bash
+make dep
+cd vendor/github.com/opencord/
+rm -rf omci-sim/
+git clone https://gerrit.opencord.org/omci-sim
+cd omci-sim
+```
+
+Once done, go to `gerrit.opencord.org` and locate the patch you want to get. Click on the download URL and copy the `Checkout` command.
+
+It should look something like:
+
+```
+git fetch ssh://teone@gerrit.opencord.org:29418/omci-sim refs/changes/67/15067/1 && git checkout FETCH_HEAD
+```
+
+Then just execute that command in the `omci-sim` folder inside the vendored dependencies.
\ No newline at end of file
diff --git a/docs/onu-state-machine.md b/docs/onu-state-machine.md
new file mode 100644
index 0000000..af33db1
--- /dev/null
+++ b/docs/onu-state-machine.md
@@ -0,0 +1,27 @@
+# ONU State Machine
+
+In `BBSim` the device state is createdtained 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 | 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 |
+
\ No newline at end of file
diff --git a/examples/onos-dhcp.json b/examples/onos-dhcp.json
new file mode 100644
index 0000000..4e71440
--- /dev/null
+++ b/examples/onos-dhcp.json
@@ -0,0 +1,7 @@
+{
+ "org.opencord.dhcpl2relay": {
+ "dhcpl2relay": {
+ "useOltUplinkForServerPktInOut": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/sadis-minimal.json b/examples/sadis-minimal.json
index a37c3fe..259d3c4 100644
--- a/examples/sadis-minimal.json
+++ b/examples/sadis-minimal.json
@@ -11,8 +11,8 @@
"entries": [
{
"id": "BBSM00000001",
- "cTag": 101,
- "sTag": 99,
+ "cTag": 900,
+ "sTag": 900,
"nasPortId": "BBSM00000001",
"technologyProfileId": 64,
"upstreamBandwidthProfile": "High-Speed-Internet",
@@ -20,8 +20,8 @@
},
{
"id": "BBSM00000002",
- "cTag": 102,
- "sTag": 99,
+ "cTag": 901,
+ "sTag": 900,
"nasPortId": "BBSM00000002",
"technologyProfileId": 64,
"upstreamBandwidthProfile": "High-Speed-Internet",
@@ -29,8 +29,8 @@
},
{
"id": "BBSM00000101",
- "cTag": 111,
- "sTag": 99,
+ "cTag": 902,
+ "sTag": 900,
"nasPortId": "BBSM00000101",
"technologyProfileId": 64,
"upstreamBandwidthProfile": "High-Speed-Internet",
@@ -38,8 +38,8 @@
},
{
"id": "BBSM00000102",
- "cTag": 112,
- "sTag": 99,
+ "cTag": 903,
+ "sTag": 900,
"nasPortId": "BBSM00000102",
"technologyProfileId": 64,
"upstreamBandwidthProfile": "High-Speed-Internet",
diff --git a/internal/bbsim/bbsim.go b/internal/bbsim/bbsim.go
index 943c021..7c47e91 100644
--- a/internal/bbsim/bbsim.go
+++ b/internal/bbsim/bbsim.go
@@ -31,11 +31,13 @@
func getOpts() *CliOptions {
- olt_id := flag.Int("olt_id", 0, "Number of OLT devices to be emulated (default is 1)")
- nni := flag.Int("nni", 1, "Number of NNI ports per OLT device to be emulated (default is 1)")
- pon := flag.Int("pon", 1, "Number of PON ports per OLT device to be emulated (default is 1)")
- onu := flag.Int("onu", 1, "Number of ONU devices per PON port to be emulated (default is 1)")
- profileCpu := flag.String("cpuprofile", "", "write cpu profile to file")
+ olt_id := flag.Int("olt_id", 0, "Number of OLT devices to be emulated (default is 1)")
+ nni := flag.Int("nni", 1, "Number of NNI ports per OLT device to be emulated (default is 1)")
+ pon := flag.Int("pon", 1, "Number of PON ports per OLT device to be emulated (default is 1)")
+ onu := flag.Int("onu", 1, "Number of ONU devices per PON port to be emulated (default is 1)")
+ s_tag := flag.Int("s_tag", 900, "S-Tag value (default is 900)")
+ c_tag_init := flag.Int("c_tag", 900, "C-Tag starting value (default is 900), each ONU will get a sequentail one (targeting 1024 ONUs per BBSim instance the range is bug enough)")
+ profileCpu := flag.String("cpuprofile", "", "write cpu profile to file")
flag.Parse()
@@ -45,14 +47,16 @@
o.NumNniPerOlt = int(*nni)
o.NumPonPerOlt = int(*pon)
o.NumOnuPerPon = int(*onu)
+ o.STag = int(*s_tag)
+ o.CTagInit = int(*c_tag_init)
o.profileCpu = profileCpu
return o
}
-func startApiServer(channel chan bool, group *sync.WaitGroup) {
+func startApiServer(channel chan bool, group *sync.WaitGroup) {
// TODO make configurable
- address := "0.0.0.0:50070"
+ address := "0.0.0.0:50070"
log.Debugf("APIServer Listening on: %v", address)
lis, err := net.Listen("tcp", address)
if err != nil {
@@ -69,7 +73,7 @@
go grpcServer.Serve(lis)
for {
- _, ok := <- channel
+ _, ok := <-channel
if !ok {
// if the olt channel is closed, stop the gRPC server
log.Warnf("Stopping API gRPC server")
@@ -105,7 +109,7 @@
}
log.WithFields(log.Fields{
- "OltID": options.OltID,
+ "OltID": options.OltID,
"NumNniPerOlt": options.NumNniPerOlt,
"NumPonPerOlt": options.NumPonPerOlt,
"NumOnuPerPon": options.NumOnuPerPon,
@@ -118,8 +122,7 @@
wg := sync.WaitGroup{}
wg.Add(2)
-
- go devices.CreateOLT(options.OltID, options.NumNniPerOlt, options.NumPonPerOlt, options.NumOnuPerPon, &oltDoneChannel, &apiDoneChannel, &wg)
+ go devices.CreateOLT(options.OltID, options.NumNniPerOlt, options.NumPonPerOlt, options.NumOnuPerPon, options.STag, options.CTagInit, &oltDoneChannel, &apiDoneChannel, &wg)
log.Debugf("Created OLT with id: %d", options.OltID)
go startApiServer(apiDoneChannel, &wg)
log.Debugf("Started APIService")
@@ -133,4 +136,4 @@
pprof.StopCPUProfile()
}
}()
-}
\ No newline at end of file
+}
diff --git a/internal/bbsim/devices/helpers.go b/internal/bbsim/devices/helpers.go
index 920b1d4..5a56825 100644
--- a/internal/bbsim/devices/helpers.go
+++ b/internal/bbsim/devices/helpers.go
@@ -16,7 +16,11 @@
package devices
-import "github.com/looplab/fsm"
+import (
+ "github.com/looplab/fsm"
+ "github.com/opencord/voltha-protos/go/openolt"
+ "strconv"
+)
var newFSM = fsm.NewFSM
@@ -34,3 +38,11 @@
},
)
}
+
+func onuSnToString(sn *openolt.SerialNumber) string {
+ s := string(sn.VendorId)
+ for _, i := range sn.VendorSpecific {
+ s = s + strconv.FormatInt(int64(i/16), 16) + strconv.FormatInt(int64(i%16), 16)
+ }
+ return s
+}
diff --git a/internal/bbsim/devices/nni.go b/internal/bbsim/devices/nni.go
new file mode 100644
index 0000000..814c825
--- /dev/null
+++ b/internal/bbsim/devices/nni.go
@@ -0,0 +1,191 @@
+/*
+ * 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
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package devices
+
+import (
+ "bytes"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/pcap"
+ "github.com/looplab/fsm"
+ "github.com/opencord/bbsim/internal/bbsim/packetHandlers"
+ "github.com/opencord/bbsim/internal/bbsim/types"
+ log "github.com/sirupsen/logrus"
+ "os/exec"
+)
+
+var (
+ nniLogger = log.WithFields(log.Fields{"module": "NNI"})
+ nniVeth = "nni"
+ upstreamVeth = "upstream"
+ dhcpServerIp = "182.21.0.128"
+)
+
+func CreateNNI(olt *OltDevice) (NniPort, error) {
+ nniPort := NniPort{
+ ID: uint32(0),
+ OperState: getOperStateFSM(func(e *fsm.Event) {
+ oltLogger.Debugf("Changing NNI OperState from %s to %s", e.Src, e.Dst)
+ }),
+ Type: "nni",
+ }
+ createNNIPair(olt)
+ return nniPort, nil
+}
+
+// sendNniPacket will send a packet out of the NNI interface.
+// We will send upstream only DHCP packets and drop anything else
+func sendNniPacket(packet gopacket.Packet) error {
+ if isDhcp := packetHandlers.IsDhcpPacket(packet); !isDhcp {
+ nniLogger.WithFields(log.Fields{
+ "packet": packet,
+ }).Trace("Dropping NNI packet as it's not DHCP")
+ }
+
+ packet, err := packetHandlers.PopDoubleTag(packet)
+ if err != nil {
+ nniLogger.WithFields(log.Fields{
+ "packet": packet,
+ }).Errorf("Can't remove double tags from packet: %v", err)
+ return err
+ }
+
+ handle, err := getVethHandler(nniVeth)
+ if err != nil {
+ return err
+ }
+
+ err = handle.WritePacketData(packet.Data())
+ if err != nil {
+ nniLogger.WithFields(log.Fields{
+ "packet": packet,
+ }).Errorf("Failed to send packet out of the NNI: %s", err)
+ return err
+ }
+
+ nniLogger.Infof("Sent packet out of NNI")
+ return nil
+}
+
+// createNNIBridge will create a veth bridge to fake the connection between the NNI port
+// and something upstream, in this case a DHCP server.
+// It is also responsible to start the DHCP server itself
+func createNNIPair(olt *OltDevice) error {
+
+ if err := exec.Command("ip", "link", "add", nniVeth, "type", "veth", "peer", "name", upstreamVeth).Run(); err != nil {
+ nniLogger.Errorf("Couldn't create veth pair between %s and %s", nniVeth, upstreamVeth)
+ return err
+ }
+
+ if err := setVethUp(nniVeth); err != nil {
+ return err
+ }
+
+ if err := setVethUp(upstreamVeth); err != nil {
+ return err
+ }
+
+ if err := startDHCPServer(); err != nil {
+ return err
+ }
+
+ ch, err := listenOnVeth(nniVeth)
+ if err != nil {
+ return err
+ }
+ olt.nniPktInChannel = ch
+ return nil
+}
+
+// setVethUp is responsible to activate a virtual interface
+func setVethUp(vethName string) error {
+ if err := exec.Command("ip", "link", "set", vethName, "up").Run(); err != nil {
+ nniLogger.Errorf("Couldn't change interface %s state to up: %v", vethName, err)
+ return err
+ }
+ return nil
+}
+
+func startDHCPServer() error {
+ if err := exec.Command("ip", "addr", "add", dhcpServerIp, "dev", upstreamVeth).Run(); err != nil {
+ nniLogger.Errorf("Couldn't assing ip %s to interface %s: %v", dhcpServerIp, upstreamVeth, err)
+ return err
+ }
+
+ if err := setVethUp(upstreamVeth); err != nil {
+ return err
+ }
+
+ dhcp := "/usr/local/bin/dhcpd"
+ conf := "/etc/dhcp/dhcpd.conf" // copied in the container from configs/dhcpd.conf
+ logfile := "/tmp/dhcplog"
+ var stderr bytes.Buffer
+ cmd := exec.Command(dhcp, "-cf", conf, upstreamVeth, "-tf", logfile)
+ cmd.Stderr = &stderr
+ err := cmd.Run()
+ if err != nil {
+ nniLogger.Errorf("Fail to start DHCP Server: %s, %s", err, stderr.String())
+ return err
+ }
+ nniLogger.Info("Successfully activated DHCP Server")
+ return nil
+}
+
+func getVethHandler(vethName string) (*pcap.Handle, error) {
+ var (
+ device = vethName
+ snapshotLen int32 = 1518
+ promiscuous = false
+ timeout = pcap.BlockForever
+ )
+ handle, err := pcap.OpenLive(device, snapshotLen, promiscuous, timeout)
+ if err != nil {
+ nniLogger.Errorf("Can't retrieve handler for interface %s", vethName)
+ return nil, err
+ }
+ return handle, nil
+}
+
+func listenOnVeth(vethName string) (chan *types.PacketMsg, error) {
+
+ handle, err := getVethHandler(vethName)
+ if err != nil {
+ return nil, err
+ }
+
+ channel := make(chan *types.PacketMsg, 32)
+
+ go func() {
+ packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
+ for packet := range packetSource.Packets() {
+
+ if !packetHandlers.IsIncomingPacket(packet) {
+ nniLogger.Tracef("Ignoring packet as it's going out")
+ continue
+ }
+
+ nniLogger.WithFields(log.Fields{
+ "packet": packet.Dump(),
+ }).Tracef("Received packet on NNI Port")
+ pkt := types.PacketMsg{
+ Pkt: packet,
+ }
+ channel <- &pkt
+ }
+ }()
+
+ return channel, nil
+}
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 6ce09a1..c75f2d1 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -20,10 +20,10 @@
"context"
"errors"
"fmt"
- bbsim "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/looplab/fsm"
+ bbsim "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/voltha-protos/go/openolt"
"github.com/opencord/voltha-protos/go/tech_profile"
log "github.com/sirupsen/logrus"
@@ -43,32 +43,33 @@
var olt = OltDevice{}
-func GetOLT() OltDevice {
+func GetOLT() OltDevice {
return olt
}
-func CreateOLT(seq int, nni int, pon int, onuPerPon int, oltDoneChannel *chan bool, apiDoneChannel *chan bool, group *sync.WaitGroup) OltDevice {
+func CreateOLT(seq int, nni int, pon int, onuPerPon int, sTag int, cTagInit int, oltDoneChannel *chan bool, apiDoneChannel *chan bool, group *sync.WaitGroup) OltDevice {
oltLogger.WithFields(log.Fields{
- "ID": seq,
- "NumNni":nni,
- "NumPon":pon,
- "NumOnuPerPon":onuPerPon,
+ "ID": seq,
+ "NumNni": nni,
+ "NumPon": pon,
+ "NumOnuPerPon": onuPerPon,
}).Debug("CreateOLT")
olt = OltDevice{
- ID: seq,
+ ID: seq,
SerialNumber: fmt.Sprintf("BBSIM_OLT_%d", seq),
OperState: getOperStateFSM(func(e *fsm.Event) {
oltLogger.Debugf("Changing OLT OperState from %s to %s", e.Src, e.Dst)
}),
- NumNni:nni,
- NumPon:pon,
- NumOnuPerPon:onuPerPon,
- Pons: []PonPort{},
- Nnis: []NniPort{},
- channel: make(chan Message),
- oltDoneChannel: oltDoneChannel,
- apiDoneChannel: apiDoneChannel,
+ NumNni: nni,
+ NumPon: pon,
+ NumOnuPerPon: onuPerPon,
+ Pons: []PonPort{},
+ Nnis: []NniPort{},
+ channel: make(chan Message),
+ oltDoneChannel: oltDoneChannel,
+ apiDoneChannel: apiDoneChannel,
+ nniPktInChannel: make(chan *bbsim.PacketMsg, 1024), // packets coming in from the NNI and going to VOLTHA
}
// OLT State machine
@@ -87,22 +88,21 @@
)
// create NNI Port
- nniPort := NniPort{
- ID: uint32(0),
- OperState: getOperStateFSM(func(e *fsm.Event) {
- oltLogger.Debugf("Changing NNI OperState from %s to %s", e.Src, e.Dst)
- }),
- Type: "nni",
+ nniPort, err := CreateNNI(&olt)
+
+ if err != nil {
+ oltLogger.Fatalf("Couldn't create NNI Port: %v", err)
}
+
olt.Nnis = append(olt.Nnis, nniPort)
// create PON ports
- //onuId := 1
+ availableCTag := cTagInit
for i := 0; i < pon; i++ {
p := PonPort{
NumOnu: olt.NumOnuPerPon,
- ID: uint32(i),
- Type: "pon",
+ ID: uint32(i),
+ Type: "pon",
}
p.OperState = getOperStateFSM(func(e *fsm.Event) {
oltLogger.WithFields(log.Fields{
@@ -113,9 +113,9 @@
// create ONU devices
for j := 0; j < onuPerPon; j++ {
//o := CreateONU(olt, p, uint32(onuId))
- o := CreateONU(olt, p, uint32(j + 1))
+ o := CreateONU(olt, p, uint32(j+1), sTag, availableCTag)
p.Onus = append(p.Onus, o)
- //onuId = onuId + 1
+ availableCTag = availableCTag + 1
}
olt.Pons = append(olt.Pons, p)
@@ -129,7 +129,7 @@
func newOltServer(o OltDevice) error {
// TODO make configurable
- address := "0.0.0.0:50060"
+ address := "0.0.0.0:50060"
lis, err := net.Listen("tcp", address)
if err != nil {
oltLogger.Fatalf("OLT failed to listen: %v", err)
@@ -144,7 +144,7 @@
oltLogger.Debugf("OLT Listening on: %v", address)
for {
- _, ok := <- *o.oltDoneChannel
+ _, ok := <-*o.oltDoneChannel
if !ok {
// if the olt channel is closed, stop the gRPC server
log.Warnf("Stopping OLT gRPC server")
@@ -161,15 +161,16 @@
// Device Methods
-func (o OltDevice) Enable (stream openolt.Openolt_EnableIndicationServer) error {
+func (o OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
oltLogger.Debug("Enable OLT called")
wg := sync.WaitGroup{}
- wg.Add(1)
+ wg.Add(2)
// create a channel for all the OLT events
go o.processOltMessages(stream)
+ go o.processNniPacketIns(stream)
// enable the OLT
olt_msg := Message{
@@ -207,9 +208,9 @@
go onu.processOnuMessages(stream)
go onu.processOmciMessages(stream)
msg := Message{
- Type: OnuDiscIndication,
+ Type: OnuDiscIndication,
Data: OnuDiscIndicationMessage{
- Onu: onu,
+ Onu: onu,
OperState: UP,
},
}
@@ -257,8 +258,8 @@
nni.OperState.Event("enable")
// NOTE Operstate may need to be an integer
operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
- Type: nni.Type,
- IntfId: nni.ID,
+ Type: nni.Type,
+ IntfId: nni.ID,
OperState: nni.OperState.Current(),
}}
@@ -267,8 +268,8 @@
}
oltLogger.WithFields(log.Fields{
- "Type": nni.Type,
- "IntfId": nni.ID,
+ "Type": nni.Type,
+ "IntfId": nni.ID,
"OperState": nni.OperState.Current(),
}).Debug("Sent Indication_IntfOperInd for NNI")
}
@@ -277,7 +278,7 @@
pon, _ := o.getPonById(msg.PonPortID)
pon.OperState.Event("enable")
discoverData := &openolt.Indication_IntfInd{IntfInd: &openolt.IntfIndication{
- IntfId: pon.ID,
+ IntfId: pon.ID,
OperState: pon.OperState.Current(),
}}
@@ -286,13 +287,13 @@
}
oltLogger.WithFields(log.Fields{
- "IntfId": pon.ID,
+ "IntfId": pon.ID,
"OperState": pon.OperState.Current(),
}).Debug("Sent Indication_IntfInd")
operData := &openolt.Indication_IntfOperInd{IntfOperInd: &openolt.IntfOperIndication{
- Type: pon.Type,
- IntfId: pon.ID,
+ Type: pon.Type,
+ IntfId: pon.ID,
OperState: pon.OperState.Current(),
}}
@@ -301,8 +302,8 @@
}
oltLogger.WithFields(log.Fields{
- "Type": pon.Type,
- "IntfId": pon.ID,
+ "Type": pon.Type,
+ "IntfId": pon.ID,
"OperState": pon.OperState.Current(),
}).Debug("Sent Indication_IntfOperInd for PON")
}
@@ -311,9 +312,8 @@
oltLogger.Debug("Started OLT Indication Channel")
for message := range o.channel {
-
oltLogger.WithFields(log.Fields{
- "oltId": o.ID,
+ "oltId": o.ID,
"messageType": message.Type,
}).Trace("Received message")
@@ -341,11 +341,32 @@
}
}
+func (o OltDevice) processNniPacketIns(stream openolt.Openolt_EnableIndicationServer) {
+ oltLogger.WithFields(log.Fields{
+ "nniChannel": o.nniPktInChannel,
+ }).Debug("Started NNI Channel")
+ nniId := o.Nnis[0].ID // FIXME we are assuming we have only one NNI
+ for message := range o.nniPktInChannel {
+ oltLogger.Debug("Received packets on NNI Channel")
+ data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
+ IntfType: "nni",
+ IntfId: nniId,
+ Pkt: message.Pkt.Data()}}
+ if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+ oltLogger.WithFields(log.Fields{
+ "IntfType": data.PktInd.IntfType,
+ "IntfId": nniId,
+ "Pkt": message.Pkt.Data(),
+ }).Errorf("Fail to send PktInd indication: %v", err)
+ }
+ }
+}
+
// GRPC Endpoints
-func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
+func (o OltDevice) ActivateOnu(context context.Context, onu *openolt.Onu) (*openolt.Empty, error) {
oltLogger.WithFields(log.Fields{
- "onuSerialNumber": onu.SerialNumber,
+ "OnuSn": onuSnToString(onu.SerialNumber),
}).Info("Received ActivateOnu call from VOLTHA")
pon, _ := o.getPonById(onu.IntfId)
@@ -353,28 +374,28 @@
// NOTE we need to immediately activate the ONU or the OMCI state machine won't start
msg := Message{
- Type: OnuIndication,
- Data: OnuIndicationMessage{
+ Type: OnuIndication,
+ Data: OnuIndicationMessage{
OnuSN: onu.SerialNumber,
PonPortID: onu.IntfId,
OperState: UP,
},
}
_onu.channel <- msg
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
+func (o OltDevice) DeactivateOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
oltLogger.Error("DeactivateOnu not implemented")
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) DeleteOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
+func (o OltDevice) DeleteOnu(context.Context, *openolt.Onu) (*openolt.Empty, error) {
oltLogger.Error("DeleteOnu not implemented")
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
+func (o OltDevice) DisableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
// NOTE when we disable the OLT should we disable NNI, PONs and ONUs altogether?
olt_msg := Message{
Type: OltIndication,
@@ -383,37 +404,37 @@
},
}
o.channel <- olt_msg
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
+func (o OltDevice) DisablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
oltLogger.Error("DisablePonIf not implemented")
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
+func (o OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
o.Enable(stream)
return nil
}
-func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
+func (o OltDevice) EnablePonIf(context.Context, *openolt.Interface) (*openolt.Empty, error) {
oltLogger.Error("EnablePonIf not implemented")
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
+func (o OltDevice) FlowAdd(ctx context.Context, flow *openolt.Flow) (*openolt.Empty, error) {
oltLogger.WithFields(log.Fields{
- "IntfId": flow.AccessIntfId,
- "OnuId": flow.OnuId,
- "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
+ "IntfId": flow.AccessIntfId,
+ "OnuId": flow.OnuId,
+ "EthType": fmt.Sprintf("%x", flow.Classifier.EthType),
"InnerVlan": flow.Classifier.IVid,
"OuterVlan": flow.Classifier.OVid,
- "FlowType": flow.FlowType,
- "FlowId": flow.FlowId,
- "UniID": flow.UniId,
- "PortNo": flow.PortNo,
- }).Infof("OLT receives Flow")
+ "FlowType": flow.FlowType,
+ "FlowId": flow.FlowId,
+ "UniID": flow.UniId,
+ "PortNo": flow.PortNo,
+ }).Tracef("OLT receives Flow")
// TODO optionally store flows somewhere
if flow.AccessIntfId == -1 {
@@ -425,34 +446,34 @@
onu, _ := pon.getOnuById(uint32(flow.OnuId))
msg := Message{
- Type: FlowUpdate,
- Data: OnuFlowUpdateMessage{
- PonPortID: pon.ID,
- OnuID: onu.ID,
- Flow: flow,
+ Type: FlowUpdate,
+ Data: OnuFlowUpdateMessage{
+ PonPortID: pon.ID,
+ OnuID: onu.ID,
+ Flow: flow,
},
}
onu.channel <- msg
}
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
- oltLogger.Info("received FlowRemove")
+func (o OltDevice) FlowRemove(context.Context, *openolt.Flow) (*openolt.Empty, error) {
+ oltLogger.Tracef("received FlowRemove")
// TODO store flows somewhere
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
+func (o OltDevice) HeartbeatCheck(context.Context, *openolt.Empty) (*openolt.Heartbeat, error) {
oltLogger.Error("HeartbeatCheck not implemented")
- return new(openolt.Heartbeat) , nil
+ return new(openolt.Heartbeat), nil
}
-func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
+func (o OltDevice) GetDeviceInfo(context.Context, *openolt.Empty) (*openolt.DeviceInfo, error) {
oltLogger.WithFields(log.Fields{
- "oltId": o.ID,
+ "oltId": o.ID,
"PonPorts": o.NumPon,
}).Info("OLT receives GetDeviceInfo call from VOLTHA")
devinfo := new(openolt.DeviceInfo)
@@ -475,67 +496,76 @@
return devinfo, nil
}
-func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
+func (o OltDevice) OmciMsgOut(ctx context.Context, omci_msg *openolt.OmciMsg) (*openolt.Empty, error) {
pon, _ := o.getPonById(omci_msg.IntfId)
onu, _ := pon.getOnuById(omci_msg.OnuId)
msg := Message{
- Type: OMCI,
- Data: OmciMessage{
- OnuSN: onu.SerialNumber,
- OnuID: onu.ID,
- omciMsg: omci_msg,
+ Type: OMCI,
+ Data: OmciMessage{
+ OnuSN: onu.SerialNumber,
+ OnuID: onu.ID,
+ omciMsg: omci_msg,
},
}
onu.channel <- msg
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
+func (o OltDevice) OnuPacketOut(ctx context.Context, onuPkt *openolt.OnuPacket) (*openolt.Empty, error) {
pon, _ := o.getPonById(onuPkt.IntfId)
onu, _ := pon.getOnuById(onuPkt.OnuId)
rawpkt := gopacket.NewPacket(onuPkt.Pkt, layers.LayerTypeEthernet, gopacket.Default)
- // NOTE is this the best way to the to the ethertype?
etherType := rawpkt.Layer(layers.LayerTypeEthernet).(*layers.Ethernet).EthernetType
if etherType == layers.EthernetTypeEAPOL {
eapolPkt := bbsim.ByteMsg{IntfId: onuPkt.IntfId, OnuId: onuPkt.OnuId, Bytes: rawpkt.Data()}
onu.eapolPktOutCh <- &eapolPkt
+ } else if layerDHCP := rawpkt.Layer(layers.LayerTypeDHCPv4); layerDHCP != nil {
+ // TODO use IsDhcpPacket
+ // TODO we need to untag the packets
+ // NOTE here we receive packets going from the DHCP Server to the ONU
+ // for now we expect them to be double-tagged, but ideally the should be single tagged
+ dhcpPkt := bbsim.ByteMsg{IntfId: onuPkt.IntfId, OnuId: onuPkt.OnuId, Bytes: rawpkt.Data()}
+ onu.dhcpPktOutCh <- &dhcpPkt
}
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
-func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
+func (o OltDevice) Reboot(context.Context, *openolt.Empty) (*openolt.Empty, error) {
oltLogger.Info("Shutting Down")
close(*o.oltDoneChannel)
close(*o.apiDoneChannel)
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
func (o OltDevice) ReenableOlt(context.Context, *openolt.Empty) (*openolt.Empty, error) {
oltLogger.Error("ReenableOlt not implemented")
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
func (o OltDevice) UplinkPacketOut(context context.Context, packet *openolt.UplinkPacket) (*openolt.Empty, error) {
- oltLogger.Warn("UplinkPacketOut not implemented")
- return new(openolt.Empty) , nil
+ pkt := gopacket.NewPacket(packet.Pkt, layers.LayerTypeEthernet, gopacket.Default)
+
+ sendNniPacket(pkt)
+ // NOTE should we return an error if sendNniPakcet fails?
+ return new(openolt.Empty), nil
}
-func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
+func (o OltDevice) CollectStatistics(context.Context, *openolt.Empty) (*openolt.Empty, error) {
oltLogger.Error("CollectStatistics not implemented")
- return new(openolt.Empty) , nil
+ return new(openolt.Empty), nil
}
func (o OltDevice) GetOnuInfo(context context.Context, packet *openolt.Onu) (*openolt.OnuIndication, error) {
oltLogger.Error("GetOnuInfo not implemented")
- return new(openolt.OnuIndication) , nil
+ return new(openolt.OnuIndication), nil
}
func (o OltDevice) GetPonIf(context context.Context, packet *openolt.Interface) (*openolt.IntfIndication, error) {
oltLogger.Error("GetPonIf not implemented")
- return new(openolt.IntfIndication) , nil
+ return new(openolt.IntfIndication), nil
}
func (s OltDevice) CreateTrafficQueues(context.Context, *tech_profile.TrafficQueues) (*openolt.Empty, error) {
@@ -556,4 +586,4 @@
func (s OltDevice) RemoveTrafficSchedulers(context.Context, *tech_profile.TrafficSchedulers) (*openolt.Empty, error) {
oltLogger.Info("received RemoveTrafficSchedulers")
return new(openolt.Empty), nil
-}
\ No newline at end of file
+}
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index fac7ce1..77e912c 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -18,129 +18,130 @@
import (
"fmt"
- "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
"github.com/google/gopacket/layers"
"github.com/looplab/fsm"
+ "github.com/opencord/bbsim/internal/bbsim/responders/dhcp"
+ "github.com/opencord/bbsim/internal/bbsim/responders/eapol"
+ bbsim "github.com/opencord/bbsim/internal/bbsim/types"
omci "github.com/opencord/omci-sim"
"github.com/opencord/voltha-protos/go/openolt"
log "github.com/sirupsen/logrus"
- bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+ "net"
)
var onuLogger = log.WithFields(log.Fields{
"module": "ONU",
})
-func CreateONU(olt OltDevice, pon PonPort, id uint32) Onu {
- o := Onu{
- ID: id,
- PonPortID: pon.ID,
- PonPort: pon,
- // NOTE can we combine everything in a single channel?
- channel: make(chan Message),
- eapolPktOutCh: make(chan *bbsim.ByteMsg, 1024),
- }
- o.SerialNumber = o.NewSN(olt.ID, pon.ID, o.ID)
+func CreateONU(olt OltDevice, pon PonPort, id uint32, sTag int, cTag int) Onu {
- // NOTE this state machine is used to track the operational
- // state as requested by VOLTHA
- o.OperState = getOperStateFSM(func(e *fsm.Event) {
- onuLogger.WithFields(log.Fields{
- "ID": o.ID,
- }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
- })
+ o := Onu{
+ ID: id,
+ PonPortID: pon.ID,
+ PonPort: pon,
+ STag: sTag,
+ CTag: cTag,
+ HwAddress: net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(pon.ID), byte(id)},
+ // NOTE can we combine everything in a single channel?
+ channel: make(chan Message, 2048),
+ eapolPktOutCh: make(chan *bbsim.ByteMsg, 1024),
+ dhcpPktOutCh: make(chan *bbsim.ByteMsg, 1024),
+ }
+ o.SerialNumber = o.NewSN(olt.ID, pon.ID, o.ID)
- // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
- o.InternalState = fsm.NewFSM(
- "created",
- fsm.Events{
- {Name: "discover", Src: []string{"created"}, Dst: "discovered"},
- {Name: "enable", Src: []string{"discovered"}, Dst: "enabled"},
- {Name: "receive_eapol_flow", Src: []string{"enabled", "gem_port_added"}, Dst: "eapol_flow_received"},
- {Name: "add_gem_port", Src: []string{"enabled", "eapol_flow_received"}, Dst: "gem_port_added"},
- {Name: "start_auth", Src: []string{"eapol_flow_received", "gem_port_added"}, Dst: "auth_started"},
- {Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
- {Name: "eap_resonse_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_resonse_identity_sent"},
- {Name: "eap_resonse_challenge_sent", Src: []string{"eap_resonse_identity_sent"}, Dst: "eap_resonse_challenge_sent"},
- {Name: "eap_resonse_success_received", Src: []string{"eap_resonse_challenge_sent"}, Dst: "eap_resonse_success_received"},
- {Name: "auth_failed", Src: []string{"auth_started", "eap_start_sent", "eap_resonse_identity_sent", "eap_resonse_challenge_sent"}, Dst: "auth_failed"},
+ // NOTE this state machine is used to track the operational
+ // state as requested by VOLTHA
+ o.OperState = getOperStateFSM(func(e *fsm.Event) {
+ onuLogger.WithFields(log.Fields{
+ "ID": o.ID,
+ }).Debugf("Changing ONU OperState from %s to %s", e.Src, e.Dst)
+ })
+
+ // NOTE this state machine is used to activate the OMCI, EAPOL and DHCP clients
+ o.InternalState = fsm.NewFSM(
+ "created",
+ fsm.Events{
+ // DEVICE Activation
+ {Name: "discover", Src: []string{"created"}, Dst: "discovered"},
+ {Name: "enable", Src: []string{"discovered"}, Dst: "enabled"},
+ {Name: "receive_eapol_flow", Src: []string{"enabled", "gem_port_added"}, Dst: "eapol_flow_received"},
+ {Name: "add_gem_port", Src: []string{"enabled", "eapol_flow_received"}, Dst: "gem_port_added"},
+ // EAPOL
+ {Name: "start_auth", Src: []string{"eapol_flow_received", "gem_port_added"}, 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: "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"},
+ {Name: "dhcp_failed", Src: []string{"dhcp_started", "dhcp_discovery_sent", "dhcp_request_sent"}, Dst: "dhcp_failed"},
+ },
+ fsm.Callbacks{
+ "enter_state": func(e *fsm.Event) {
+ o.logStateChange(e.Src, e.Dst)
},
- fsm.Callbacks{
- "enter_state": func(e *fsm.Event) {
- o.logStateChange(e.Src, e.Dst)
- },
- "enter_eapol_flow_received": func(e *fsm.Event) {
- o.logStateChange(e.Src, e.Dst)
- if e.Src == "enter_gem_port_added" {
- if err := o.InternalState.Event("start_auth"); err != nil {
- log.Infof("Transitioning to StartAuth")
- onuLogger.WithFields(log.Fields{
- "OnuId": o.ID,
- "IntfId": o.PonPortID,
- "OnuSn": o.SerialNumber,
- }).Errorf("Error while transitioning ONU State")
- }
- }
- },
- "enter_gem_port_added": func(e *fsm.Event) {
- o.logStateChange(e.Src, e.Dst)
- if e.Src == "eapol_flow_received" {
- log.Infof("Transitioning to StartAuth")
- if err := o.InternalState.Event("start_auth"); err != nil {
- onuLogger.WithFields(log.Fields{
- "OnuId": o.ID,
- "IntfId": o.PonPortID,
- "OnuSn": o.SerialNumber,
- }).Errorf("Error while transitioning ONU State")
- }
- }
- },
- "enter_auth_started": func(e *fsm.Event) {
- o.logStateChange(e.Src, e.Dst)
- msg := Message{
- Type: StartEAPOL,
- Data: EapStartMessage{
- PonPortID: o.PonPortID,
- OnuID: o.ID,
- },
- }
- go func(msg Message){
- // you can only send a value on an unbuffered channel without blocking
- o.channel <- msg
- }(msg)
-
- },
- "enter_eap_resonse_success_received": func(e *fsm.Event) {
- o.logStateChange(e.Src, e.Dst)
- onuLogger.WithFields(log.Fields{
- "OnuId": o.ID,
- "IntfId": o.PonPortID,
- "OnuSn": o.SerialNumber,
- }).Warnf("TODO start DHCP request")
- },
+ "enter_auth_started": func(e *fsm.Event) {
+ o.logStateChange(e.Src, e.Dst)
+ msg := Message{
+ Type: StartEAPOL,
+ Data: PacketMessage{
+ PonPortID: o.PonPortID,
+ OnuID: o.ID,
+ },
+ }
+ o.channel <- msg
},
- )
- return o
+ "enter_auth_failed": func(e *fsm.Event) {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("ONU failed to authenticate!")
+ },
+ "enter_dhcp_started": func(e *fsm.Event) {
+ msg := Message{
+ Type: StartDHCP,
+ Data: PacketMessage{
+ PonPortID: o.PonPortID,
+ OnuID: o.ID,
+ },
+ }
+ o.channel <- msg
+ },
+ "enter_dhcp_failed": func(e *fsm.Event) {
+ onuLogger.WithFields(log.Fields{
+ "OnuId": o.ID,
+ "IntfId": o.PonPortID,
+ "OnuSn": o.Sn(),
+ }).Errorf("ONU failed to DHCP!")
+ },
+ },
+ )
+ return o
}
func (o Onu) logStateChange(src string, dst string) {
onuLogger.WithFields(log.Fields{
- "OnuId": o.ID,
+ "OnuId": o.ID,
"IntfId": o.PonPortID,
- "OnuSn": o.SerialNumber,
+ "OnuSn": o.Sn(),
}).Debugf("Changing ONU InternalState from %s to %s", src, dst)
}
-func (o Onu) processOnuMessages(stream openolt.Openolt_EnableIndicationServer) {
+func (o Onu) processOnuMessages(stream openolt.Openolt_EnableIndicationServer) {
onuLogger.WithFields(log.Fields{
"onuID": o.ID,
- "onuSN": o.SerialNumber,
+ "onuSN": o.Sn(),
}).Debug("Started ONU Indication Channel")
for message := range o.channel {
onuLogger.WithFields(log.Fields{
- "onuID": o.ID,
- "onuSN": o.SerialNumber,
+ "onuID": o.ID,
+ "onuSN": o.SerialNumber,
"messageType": message.Type,
}).Tracef("Received message on ONU Channel")
@@ -161,7 +162,29 @@
log.Infof("Receive StartEAPOL message on ONU channel")
go func() {
// TODO kill this thread
- eapol.CreateWPASupplicant(o.ID, o.PonPortID, o.SerialNumber, o.InternalState, stream, o.eapolPktOutCh)
+ eapol.CreateWPASupplicant(
+ o.ID,
+ o.PonPortID,
+ o.Sn(),
+ o.InternalState,
+ stream,
+ o.eapolPktOutCh,
+ )
+ }()
+ case StartDHCP:
+ log.Infof("Receive StartDHCP message on ONU channel")
+ go func() {
+ // TODO kill this thread
+ dhcp.CreateDHCPClient(
+ o.ID,
+ o.PonPortID,
+ o.Sn(),
+ o.HwAddress,
+ o.CTag,
+ o.InternalState,
+ stream,
+ o.dhcpPktOutCh,
+ )
}()
default:
onuLogger.Warnf("Received unknown message data %v for type %v in OLT channel", message.Data, message.Type)
@@ -169,19 +192,19 @@
}
}
-func (o Onu) processOmciMessages(stream openolt.Openolt_EnableIndicationServer) {
+func (o Onu) processOmciMessages(stream openolt.Openolt_EnableIndicationServer) {
ch := omci.GetChannel()
onuLogger.WithFields(log.Fields{
"onuID": o.ID,
- "onuSN": o.SerialNumber,
+ "onuSN": o.Sn(),
}).Debug("Started OMCI Indication Channel")
for message := range ch {
switch message.Type {
case omci.GemPortAdded:
log.WithFields(log.Fields{
- "OnuId": message.Data.OnuId,
+ "OnuId": message.Data.OnuId,
"IntfId": message.Data.IntfId,
}).Infof("GemPort Added")
@@ -191,7 +214,7 @@
if err := o.InternalState.Event("add_gem_port"); err != nil {
log.Errorf("Can't go to gem_port_added: %v", err)
}
- } else if o.InternalState.Is("eapol_flow_received"){
+ } else if o.InternalState.Is("eapol_flow_received") {
if err := o.InternalState.Event("start_auth"); err != nil {
log.Errorf("Can't go to auth_started: %v", err)
}
@@ -213,7 +236,7 @@
func (o Onu) sendOnuDiscIndication(msg OnuDiscIndicationMessage, stream openolt.Openolt_EnableIndicationServer) {
discoverData := &openolt.Indication_OnuDiscInd{OnuDiscInd: &openolt.OnuDiscIndication{
- IntfId: msg.Onu.PonPortID,
+ IntfId: msg.Onu.PonPortID,
SerialNumber: msg.Onu.SerialNumber,
}}
if err := stream.Send(&openolt.Indication{Data: discoverData}); err != nil {
@@ -222,8 +245,8 @@
o.InternalState.Event("discover")
onuLogger.WithFields(log.Fields{
"IntfId": msg.Onu.PonPortID,
- "SerialNumber": msg.Onu.SerialNumber,
- "OnuId": o.ID,
+ "OnuSn": msg.Onu.Sn(),
+ "OnuId": o.ID,
}).Debug("Sent Indication_OnuDiscInd")
}
@@ -235,10 +258,10 @@
o.OperState.Event("enable")
indData := &openolt.Indication_OnuInd{OnuInd: &openolt.OnuIndication{
- IntfId: o.PonPortID,
- OnuId: o.ID,
- OperState: o.OperState.Current(),
- AdminState: o.OperState.Current(),
+ IntfId: o.PonPortID,
+ OnuId: o.ID,
+ OperState: o.OperState.Current(),
+ AdminState: o.OperState.Current(),
SerialNumber: o.SerialNumber,
}}
if err := stream.Send(&openolt.Indication{Data: indData}); err != nil {
@@ -246,20 +269,20 @@
}
o.InternalState.Event("enable")
onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
- "OnuId": o.ID,
- "OperState": msg.OperState.String(),
+ "IntfId": o.PonPortID,
+ "OnuId": o.ID,
+ "OperState": msg.OperState.String(),
"AdminState": msg.OperState.String(),
- "SerialNumber": o.SerialNumber,
+ "OnuSn": o.Sn(),
}).Debug("Sent Indication_OnuInd")
}
func (o Onu) handleOmciMessage(msg OmciMessage, stream openolt.Openolt_EnableIndicationServer) {
onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
+ "IntfId": o.PonPortID,
"SerialNumber": o.SerialNumber,
- "omciPacket": msg.omciMsg.Pkt,
+ "omciPacket": msg.omciMsg.Pkt,
}).Tracef("Received OMCI message")
var omciInd openolt.OmciIndication
@@ -277,36 +300,48 @@
onuLogger.Errorf("send omci indication failed: %v", err)
}
onuLogger.WithFields(log.Fields{
- "IntfId": o.PonPortID,
+ "IntfId": o.PonPortID,
"SerialNumber": o.SerialNumber,
- "omciPacket": omciInd.Pkt,
+ "omciPacket": omciInd.Pkt,
}).Tracef("Sent OMCI message")
}
func (o Onu) handleFlowUpdate(msg OnuFlowUpdateMessage, stream openolt.Openolt_EnableIndicationServer) {
onuLogger.WithFields(log.Fields{
- "IntfId": msg.Flow.AccessIntfId,
- "OnuId": msg.Flow.OnuId,
- "EthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
+ "DstPort": msg.Flow.Classifier.DstPort,
+ "EthType": fmt.Sprintf("%x", msg.Flow.Classifier.EthType),
+ "FlowId": msg.Flow.FlowId,
+ "FlowType": msg.Flow.FlowType,
"InnerVlan": msg.Flow.Classifier.IVid,
+ "IntfId": msg.Flow.AccessIntfId,
+ "IpProto": msg.Flow.Classifier.IpProto,
+ "OnuId": msg.Flow.OnuId,
+ "OnuSn": o.Sn(),
"OuterVlan": msg.Flow.Classifier.OVid,
- "FlowType": msg.Flow.FlowType,
- "FlowId": msg.Flow.FlowId,
- "UniID": msg.Flow.UniId,
- "PortNo": msg.Flow.PortNo,
- }).Infof("ONU receives Flow")
+ "PortNo": msg.Flow.PortNo,
+ "SrcPort": msg.Flow.Classifier.SrcPort,
+ "UniID": msg.Flow.UniId,
+ }).Debug("ONU receives Flow")
+
if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeEAPOL) && msg.Flow.Classifier.OVid == 4091 {
// NOTE if we receive the EAPOL flows but we don't have GemPorts
// go an intermediate state, otherwise start auth
if o.InternalState.Is("enabled") {
if err := o.InternalState.Event("receive_eapol_flow"); err != nil {
- log.Errorf("Can't go to eapol_flow_received: %v", err)
+ log.Warnf("Can't go to eapol_flow_received: %v", err)
}
- } else if o.InternalState.Is("gem_port_added"){
+ } else if o.InternalState.Is("gem_port_added") {
if err := o.InternalState.Event("start_auth"); err != nil {
- log.Errorf("Can't go to auth_started: %v", err)
+ log.Warnf("Can't go to auth_started: %v", err)
}
}
+ } else if msg.Flow.Classifier.EthType == uint32(layers.EthernetTypeIPv4) &&
+ msg.Flow.Classifier.SrcPort == uint32(68) &&
+ msg.Flow.Classifier.DstPort == uint32(67) {
+ // NOTE we are receiving mulitple DHCP flows but we shouldn't call the transition multiple times
+ if err := o.InternalState.Event("start_dhcp"); err != nil {
+ log.Warnf("Can't go to dhcp_started: %v", err)
+ }
}
}
@@ -321,4 +356,4 @@
}
onuLogger.Tracef("Omci decoded: %x.", p)
return p
-}
\ No newline at end of file
+}
diff --git a/internal/bbsim/devices/types.go b/internal/bbsim/devices/types.go
index 65aa09e..e012858 100644
--- a/internal/bbsim/devices/types.go
+++ b/internal/bbsim/devices/types.go
@@ -20,9 +20,10 @@
"bytes"
"errors"
"fmt"
- "github.com/opencord/voltha-protos/go/openolt"
"github.com/looplab/fsm"
bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+ "github.com/opencord/voltha-protos/go/openolt"
+ "net"
)
// TODO get rid of this file
@@ -32,19 +33,25 @@
// Devices
type Onu struct {
- ID uint32
- PonPortID uint32
- PonPort PonPort
+ ID uint32
+ PonPortID uint32
+ PonPort PonPort
+ STag int
+ CTag int
+ HwAddress net.HardwareAddr
InternalState *fsm.FSM
- OperState *fsm.FSM
+ OperState *fsm.FSM
SerialNumber *openolt.SerialNumber
- channel chan Message
- eapolPktOutCh chan *bbsim.ByteMsg
+ channel chan Message // this channel is to track state changes and OMCI messages
+ eapolPktOutCh chan *bbsim.ByteMsg // this channel is for EAPOL Packet Outs (coming from the controller)
+ dhcpPktOutCh chan *bbsim.ByteMsg // this channel is for DHCP Packet Outs (coming from the controller)
}
-
+func (o Onu) Sn() string {
+ return onuSnToString(o.SerialNumber)
+}
type NniPort struct {
// BBSIM Internals
@@ -52,18 +59,18 @@
// PON Attributes
OperState *fsm.FSM
- Type string
+ Type string
}
type PonPort struct {
// BBSIM Internals
- ID uint32
+ ID uint32
NumOnu int
- Onus []Onu
+ Onus []Onu
// PON Attributes
OperState *fsm.FSM
- Type string
+ Type string
// NOTE do we need a state machine for the PON Ports?
}
@@ -88,15 +95,16 @@
type OltDevice struct {
// BBSIM Internals
- ID int
- SerialNumber string
- NumNni int
- NumPon int
- NumOnuPerPon int
- InternalState *fsm.FSM
- channel chan Message
- oltDoneChannel *chan bool
- apiDoneChannel *chan bool
+ ID int
+ SerialNumber string
+ NumNni int
+ NumPon int
+ NumOnuPerPon int
+ InternalState *fsm.FSM
+ channel chan Message
+ oltDoneChannel *chan bool
+ apiDoneChannel *chan bool
+ nniPktInChannel chan *bbsim.PacketMsg
Pons []PonPort
Nnis []NniPort
@@ -116,8 +124,10 @@
OnuDiscIndication MessageType = 3
OnuIndication MessageType = 4
OMCI MessageType = 5
- FlowUpdate MessageType = 6
- StartEAPOL MessageType = 7
+ FlowUpdate MessageType = 6
+ StartEAPOL MessageType = 7
+ DoneEAPOL MessageType = 8
+ StartDHCP MessageType = 9
)
func (m MessageType) String() string {
@@ -130,13 +140,15 @@
"OMCI",
"FlowUpdate",
"StartEAPOL",
+ "DoneEAPOL",
+ "StartDHCP",
}
return names[m]
}
type Message struct {
- Type MessageType
- Data interface{}
+ Type MessageType
+ Data interface{}
}
type OltIndicationMessage struct {
@@ -166,9 +178,9 @@
}
type OmciMessage struct {
- OnuSN *openolt.SerialNumber
- OnuID uint32
- omciMsg *openolt.OmciMsg
+ OnuSN *openolt.SerialNumber
+ OnuID uint32
+ omciMsg *openolt.OmciMsg
}
type OnuFlowUpdateMessage struct {
@@ -177,17 +189,16 @@
Flow *openolt.Flow
}
-type EapStartMessage struct {
+type PacketMessage struct {
PonPortID uint32
OnuID uint32
}
-
type OperState int
const (
- UP OperState = iota
- DOWN // The device has been discovered, but not yet activated
+ UP OperState = iota
+ DOWN // The device has been discovered, but not yet activated
)
func (m OperState) String() string {
@@ -196,4 +207,4 @@
"down",
}
return names[m]
-}
\ No newline at end of file
+}
diff --git a/internal/bbsim/grpc_api_server.go b/internal/bbsim/grpc_api_server.go
index 304d3fa..20b6164 100644
--- a/internal/bbsim/grpc_api_server.go
+++ b/internal/bbsim/grpc_api_server.go
@@ -89,10 +89,13 @@
for _, o := range pon.Onus {
onu := bbsim.ONU{
ID: int32(o.ID),
- SerialNumber: o.SerialNumber.String(),
+ SerialNumber: o.Sn(),
OperState: o.OperState.Current(),
InternalState: o.InternalState.Current(),
PonPortID: int32(o.PonPortID),
+ STag: int32(o.STag),
+ CTag: int32(o.CTag),
+ HwAddress: o.HwAddress.String(),
}
onus.Items = append(onus.Items, &onu)
}
diff --git a/internal/bbsim/packetHandlers/filters.go b/internal/bbsim/packetHandlers/filters.go
new file mode 100644
index 0000000..3233c8c
--- /dev/null
+++ b/internal/bbsim/packetHandlers/filters.go
@@ -0,0 +1,43 @@
+/*
+ * 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
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package packetHandlers
+
+import (
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "net"
+)
+
+func IsDhcpPacket(pkt gopacket.Packet) bool {
+ if layerDHCP := pkt.Layer(layers.LayerTypeDHCPv4); layerDHCP != nil {
+ return true
+ }
+ return false
+}
+
+func IsIncomingPacket(packet gopacket.Packet) bool {
+ if ipLayer := packet.Layer(layers.LayerTypeIPv4); ipLayer != nil {
+
+ ip, _ := ipLayer.(*layers.IPv4)
+
+ // FIXME find a better way to filter outgoing packets
+ if ip.SrcIP.Equal(net.ParseIP("182.21.0.128")) {
+ return true
+ }
+ }
+ return false
+}
diff --git a/internal/bbsim/packetHandlers/packet_tags.go b/internal/bbsim/packetHandlers/packet_tags.go
new file mode 100644
index 0000000..3e31e3c
--- /dev/null
+++ b/internal/bbsim/packetHandlers/packet_tags.go
@@ -0,0 +1,123 @@
+/*
+ * 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
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package packetHandlers
+
+import (
+ "errors"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+)
+
+func PushSingleTag(tag int, pkt gopacket.Packet) (gopacket.Packet, error) {
+ // TODO can this method be semplified?
+ if eth := getEthernetLayer(pkt); eth != nil {
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: eth.SrcMAC,
+ DstMAC: eth.DstMAC,
+ EthernetType: 0x8100,
+ }
+
+ dot1qLayer := &layers.Dot1Q{
+ Type: eth.EthernetType,
+ VLANIdentifier: uint16(tag),
+ }
+
+ buffer := gopacket.NewSerializeBuffer()
+ gopacket.SerializeLayers(
+ buffer,
+ gopacket.SerializeOptions{
+ FixLengths: false,
+ },
+ ethernetLayer,
+ dot1qLayer,
+ gopacket.Payload(eth.Payload),
+ )
+ ret := gopacket.NewPacket(
+ buffer.Bytes(),
+ layers.LayerTypeEthernet,
+ gopacket.Default,
+ )
+
+ return ret, nil
+ }
+ return nil, errors.New("Couldn't extract LayerTypeEthernet from packet")
+}
+
+func PopSingleTag(pkt gopacket.Packet) (gopacket.Packet, error) {
+ layer, err := getDot1QLayer(pkt)
+ if err != nil {
+ return nil, err
+ }
+
+ if eth := getEthernetLayer(pkt); eth != nil {
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: eth.SrcMAC,
+ DstMAC: eth.DstMAC,
+ EthernetType: layer.Type,
+ }
+ buffer := gopacket.NewSerializeBuffer()
+ gopacket.SerializeLayers(buffer, gopacket.SerializeOptions{},
+ ethernetLayer,
+ gopacket.Payload(layer.Payload),
+ )
+ retpkt := gopacket.NewPacket(
+ buffer.Bytes(),
+ layers.LayerTypeEthernet,
+ gopacket.Default,
+ )
+
+ return retpkt, nil
+ }
+ return nil, errors.New("no-ethernet-layer")
+}
+
+func PopDoubleTag(pkt gopacket.Packet) (gopacket.Packet, error) {
+ packet, err := PopSingleTag(pkt)
+ if err != nil {
+ return nil, err
+ }
+ packet, err = PopSingleTag(packet)
+ if err != nil {
+ return nil, err
+ }
+ return packet, nil
+}
+
+func getEthernetLayer(pkt gopacket.Packet) *layers.Ethernet {
+ eth := &layers.Ethernet{}
+ if ethLayer := pkt.Layer(layers.LayerTypeEthernet); ethLayer != nil {
+ eth, _ = ethLayer.(*layers.Ethernet)
+ }
+ return eth
+}
+
+func getDot1QLayer(pkt gopacket.Packet) (*layers.Dot1Q, error) {
+ dot1q := &layers.Dot1Q{}
+ if dot1qLayer := pkt.Layer(layers.LayerTypeDot1Q); dot1qLayer != nil {
+ dot1q = dot1qLayer.(*layers.Dot1Q)
+ return dot1q, nil
+ }
+ return nil, errors.New("no-dot1q-layer-in-packet")
+}
+
+func getVlanTag(pkt gopacket.Packet) (uint16, error) {
+ dot1q, err := getDot1QLayer(pkt)
+ if err != nil {
+ return 0, err
+ }
+ return dot1q.VLANIdentifier, nil
+}
diff --git a/internal/bbsim/packetHandlers/packet_tags_test.go b/internal/bbsim/packetHandlers/packet_tags_test.go
new file mode 100644
index 0000000..91c944e
--- /dev/null
+++ b/internal/bbsim/packetHandlers/packet_tags_test.go
@@ -0,0 +1,152 @@
+/*
+ * 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
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package packetHandlers
+
+import (
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "gotest.tools/assert"
+ "net"
+ "os"
+ "testing"
+)
+
+func setUp() {
+ fmt.Println("Test Setup")
+}
+
+func tearDown() {
+ fmt.Println("Test Teardown")
+}
+
+func TestMain(m *testing.M) {
+ setUp()
+ code := m.Run()
+ tearDown()
+ os.Exit(code)
+}
+
+// GO111MODULE=on go test -v -mod vendor ./internal/bbsim/... -run TestPushSingleTag
+func TestPushSingleTag(t *testing.T) {
+ rawBytes := []byte{10, 20, 30}
+ srcMac := net.HardwareAddr{0xff, 0xff, 0xff, 0xff, byte(1), byte(1)}
+ dstMac := net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: srcMac,
+ DstMAC: dstMac,
+ EthernetType: 0x8100,
+ }
+
+ buffer := gopacket.NewSerializeBuffer()
+ gopacket.SerializeLayers(
+ buffer,
+ gopacket.SerializeOptions{
+ FixLengths: false,
+ },
+ ethernetLayer,
+ gopacket.Payload(rawBytes),
+ )
+
+ untaggedPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, gopacket.Default)
+ taggedPkt, err := PushSingleTag(111, untaggedPkt)
+ if err != nil {
+ t.Fail()
+ t.Logf("Error in PushSingleTag: %v", err)
+ }
+
+ vlan, _ := getVlanTag(taggedPkt)
+ assert.Equal(t, vlan, uint16(111))
+}
+
+func TestPopSingleTag(t *testing.T) {
+ rawBytes := []byte{10, 20, 30}
+ srcMac := net.HardwareAddr{0xff, 0xff, 0xff, 0xff, byte(1), byte(1)}
+ dstMac := net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: srcMac,
+ DstMAC: dstMac,
+ EthernetType: 0x8100,
+ }
+
+ dot1qLayer := &layers.Dot1Q{
+ Type: 0x8100,
+ VLANIdentifier: uint16(111),
+ }
+
+ buffer := gopacket.NewSerializeBuffer()
+ gopacket.SerializeLayers(
+ buffer,
+ gopacket.SerializeOptions{
+ FixLengths: false,
+ },
+ ethernetLayer,
+ dot1qLayer,
+ gopacket.Payload(rawBytes),
+ )
+
+ untaggedPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, gopacket.Default)
+ taggedPkt, err := PopSingleTag(untaggedPkt)
+ if err != nil {
+ t.Fail()
+ t.Logf("Error in PushSingleTag: %v", err)
+ }
+
+ vlan, err := getVlanTag(taggedPkt)
+ assert.Equal(t, vlan, uint16(2580)) // FIXME where dows 2056 comes from??
+}
+
+func TestPopDoubleTag(t *testing.T) {
+ rawBytes := []byte{10, 20, 30}
+ srcMac := net.HardwareAddr{0xff, 0xff, 0xff, 0xff, byte(1), byte(1)}
+ dstMac := net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
+
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: srcMac,
+ DstMAC: dstMac,
+ EthernetType: 0x8100,
+ }
+
+ dot1qLayer := &layers.Dot1Q{
+ Type: 0x8100,
+ VLANIdentifier: uint16(111),
+ }
+
+ buffer := gopacket.NewSerializeBuffer()
+ gopacket.SerializeLayers(
+ buffer,
+ gopacket.SerializeOptions{
+ FixLengths: false,
+ },
+ ethernetLayer,
+ dot1qLayer,
+ gopacket.Payload(rawBytes),
+ )
+
+ untaggedPkt := gopacket.NewPacket(buffer.Bytes(), layers.LayerTypeEthernet, gopacket.Default)
+ taggedPkt, err := PopDoubleTag(untaggedPkt)
+ if err != nil {
+ t.Fail()
+ t.Logf("Error in PushSingleTag: %v", err)
+ }
+
+ vlan, err := getVlanTag(taggedPkt)
+ assert.Equal(t, vlan, uint16(0))
+ assert.Equal(t, err.Error(), "no-dot1q-layer-in-packet")
+}
diff --git a/internal/bbsim/responders/dhcp/dhcp.go b/internal/bbsim/responders/dhcp/dhcp.go
new file mode 100644
index 0000000..d2a3db7
--- /dev/null
+++ b/internal/bbsim/responders/dhcp/dhcp.go
@@ -0,0 +1,387 @@
+/*
+ * 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
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dhcp
+
+import (
+ "errors"
+ "fmt"
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+ "github.com/looplab/fsm"
+ bbsim "github.com/opencord/bbsim/internal/bbsim/types"
+ omci "github.com/opencord/omci-sim"
+ "github.com/opencord/voltha-protos/go/openolt"
+ log "github.com/sirupsen/logrus"
+ "net"
+ "reflect"
+)
+
+var dhcpLogger = log.WithFields(log.Fields{
+ "module": "DHCP",
+})
+
+var defaultParamsRequestList = []layers.DHCPOpt{
+ layers.DHCPOptSubnetMask,
+ layers.DHCPOptBroadcastAddr,
+ layers.DHCPOptTimeOffset,
+ layers.DHCPOptRouter,
+ layers.DHCPOptDomainName,
+ layers.DHCPOptDNS,
+ layers.DHCPOptDomainSearch,
+ layers.DHCPOptHostname,
+ layers.DHCPOptNetBIOSTCPNS,
+ layers.DHCPOptNetBIOSTCPScope,
+ layers.DHCPOptInterfaceMTU,
+ layers.DHCPOptClasslessStaticRoute,
+ layers.DHCPOptNTPServers,
+}
+
+func createDefaultDHCPReq(intfId uint32, onuId uint32) layers.DHCPv4 {
+ return layers.DHCPv4{
+ Operation: layers.DHCPOpRequest,
+ HardwareType: layers.LinkTypeEthernet,
+ HardwareLen: 6,
+ HardwareOpts: 0,
+ Xid: onuId,
+ ClientHWAddr: net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, byte(intfId), byte(onuId)},
+ }
+}
+
+func createDefaultOpts() []layers.DHCPOption {
+ hostname := []byte("bbsim.onf.org")
+ opts := []layers.DHCPOption{}
+ opts = append(opts, layers.DHCPOption{
+ Type: layers.DHCPOptHostname,
+ Data: hostname,
+ Length: uint8(len(hostname)),
+ })
+
+ bytes := []byte{}
+ for _, option := range defaultParamsRequestList {
+ bytes = append(bytes, byte(option))
+ }
+
+ opts = append(opts, layers.DHCPOption{
+ Type: layers.DHCPOptParamsRequest,
+ Data: bytes,
+ Length: uint8(len(bytes)),
+ })
+ return opts
+}
+
+func createDHCPDisc(intfId uint32, onuId uint32) *layers.DHCPv4 {
+ dhcpLayer := createDefaultDHCPReq(intfId, onuId)
+ defaultOpts := createDefaultOpts()
+ dhcpLayer.Options = append([]layers.DHCPOption{layers.DHCPOption{
+ Type: layers.DHCPOptMessageType,
+ Data: []byte{byte(layers.DHCPMsgTypeDiscover)},
+ Length: 1,
+ }}, defaultOpts...)
+
+ return &dhcpLayer
+}
+
+func createDHCPReq(intfId uint32, onuId uint32) *layers.DHCPv4 {
+ dhcpLayer := createDefaultDHCPReq(intfId, onuId)
+ defaultOpts := createDefaultOpts()
+
+ dhcpLayer.Options = append(defaultOpts, layers.DHCPOption{
+ Type: layers.DHCPOptMessageType,
+ Data: []byte{byte(layers.DHCPMsgTypeRequest)},
+ Length: 1,
+ })
+
+ data := []byte{182, 21, 0, 128}
+ dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
+ Type: layers.DHCPOptServerID,
+ Data: data,
+ Length: uint8(len(data)),
+ })
+
+ data = []byte{0xcd, 0x28, 0xcb, 0xcc, 0x00, 0x01, 0x00, 0x01,
+ 0x23, 0xed, 0x11, 0xec, 0x4e, 0xfc, 0xcd, 0x28, 0xcb, 0xcc}
+ dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
+ Type: layers.DHCPOptClientID,
+ Data: data,
+ Length: uint8(len(data)),
+ })
+
+ data = []byte{182, 21, 0, byte(onuId)}
+ dhcpLayer.Options = append(dhcpLayer.Options, layers.DHCPOption{
+ Type: layers.DHCPOptRequestIP,
+ Data: data,
+ Length: uint8(len(data)),
+ })
+ return &dhcpLayer
+}
+
+func serializeDHCPPacket(intfId uint32, onuId uint32, srcMac net.HardwareAddr, dhcp *layers.DHCPv4) ([]byte, error) {
+ buffer := gopacket.NewSerializeBuffer()
+ options := gopacket.SerializeOptions{
+ ComputeChecksums: true,
+ FixLengths: true,
+ }
+
+ ethernetLayer := &layers.Ethernet{
+ SrcMAC: srcMac,
+ DstMAC: net.HardwareAddr{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ EthernetType: layers.EthernetTypeIPv4,
+ }
+
+ ipLayer := &layers.IPv4{
+ Version: 4,
+ TOS: 0x10,
+ TTL: 128,
+ SrcIP: []byte{0, 0, 0, 0},
+ DstIP: []byte{255, 255, 255, 255},
+ Protocol: layers.IPProtocolUDP,
+ }
+
+ udpLayer := &layers.UDP{
+ SrcPort: 68,
+ DstPort: 67,
+ }
+
+ udpLayer.SetNetworkLayerForChecksum(ipLayer)
+ if err := gopacket.SerializeLayers(buffer, options, ethernetLayer, ipLayer, udpLayer, dhcp); err != nil {
+ return nil, err
+ }
+
+ bytes := buffer.Bytes()
+ return bytes, nil
+}
+
+func getDhcpLayer(pkt gopacket.Packet) (*layers.DHCPv4, error) {
+ layerDHCP := pkt.Layer(layers.LayerTypeDHCPv4)
+ dhcp, _ := layerDHCP.(*layers.DHCPv4)
+ if dhcp == nil {
+ return nil, errors.New("Failed-to-extract-DHCP-layer")
+ }
+ return dhcp, nil
+}
+
+func getDhcpMessageType(dhcp *layers.DHCPv4) (layers.DHCPMsgType, error) {
+ for _, option := range dhcp.Options {
+ if option.Type == layers.DHCPOptMessageType {
+ if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeOffer)}) {
+ return layers.DHCPMsgTypeOffer, nil
+ } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeAck)}) {
+ return layers.DHCPMsgTypeAck, nil
+ } else if reflect.DeepEqual(option.Data, []byte{byte(layers.DHCPMsgTypeRelease)}) {
+ return layers.DHCPMsgTypeRelease, nil
+ } else {
+ msg := fmt.Sprintf("This type %x is not supported", option.Data)
+ return 0, errors.New(msg)
+ }
+ }
+ }
+ return 0, errors.New("Failed to extract MsgType from dhcp")
+}
+
+func sendDHCPPktIn(msg bbsim.ByteMsg, stream openolt.Openolt_EnableIndicationServer) error {
+ // FIXME unify sendDHCPPktIn and sendEapolPktIn methods
+ gemid, err := omci.GetGemPortId(msg.IntfId, msg.OnuId)
+ if err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": msg.OnuId,
+ "IntfId": msg.IntfId,
+ }).Errorf("Can't retrieve GemPortId: %s", err)
+ return err
+ }
+ data := &openolt.Indication_PktInd{PktInd: &openolt.PacketIndication{
+ IntfType: "pon", IntfId: msg.IntfId, GemportId: uint32(gemid), Pkt: msg.Bytes,
+ }}
+
+ if err := stream.Send(&openolt.Indication{Data: data}); err != nil {
+ dhcpLogger.Errorf("Fail to send DHCP PktInd indication. %v", err)
+ return err
+ }
+ return nil
+}
+
+func sendDHCPDiscovery(ponPortId uint32, onuId uint32, serialNumber string, onuHwAddress net.HardwareAddr, cTag int, stream openolt.Openolt_EnableIndicationServer) error {
+ dhcp := createDHCPDisc(ponPortId, onuId)
+ pkt, err := serializeDHCPPacket(ponPortId, onuId, onuHwAddress, dhcp)
+ if err != nil {
+ dhcpLogger.Errorf("Cannot serializeDHCPPacket: %s", err)
+ return err
+ }
+ // NOTE I don't think we need to tag the packet
+ //taggedPkt, err := packetHandlers.PushSingleTag(cTag, pkt)
+
+ msg := bbsim.ByteMsg{
+ IntfId: ponPortId,
+ OnuId: onuId,
+ Bytes: pkt,
+ }
+
+ if err := sendDHCPPktIn(msg, stream); err != nil {
+ return err
+ }
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("DHCPDiscovery Sent")
+ return nil
+}
+
+func sendDHCPRequest(ponPortId uint32, onuId uint32, serialNumber string, onuHwAddress net.HardwareAddr, cTag int, stream openolt.Openolt_EnableIndicationServer) error {
+ dhcp := createDHCPReq(ponPortId, onuId)
+ pkt, err := serializeDHCPPacket(ponPortId, onuId, onuHwAddress, dhcp)
+
+ if err != nil {
+ dhcpLogger.Errorf("Cannot serializeDHCPPacket: %s", err)
+ return err
+ }
+ // NOTE I don't think we need to tag the packet
+ //taggedPkt, err := packetHandlers.PushSingleTag(cTag, pkt)
+
+ msg := bbsim.ByteMsg{
+ IntfId: ponPortId,
+ OnuId: onuId,
+ Bytes: pkt,
+ }
+
+ if err := sendDHCPPktIn(msg, stream); err != nil {
+ return err
+ }
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("DHCPDiscovery Sent")
+ return nil
+}
+
+func CreateDHCPClient(onuId uint32, ponPortId uint32, serialNumber string, onuHwAddress net.HardwareAddr, cTag int, onuStateMachine *fsm.FSM, stream openolt.Openolt_EnableIndicationServer, pktOutCh chan *bbsim.ByteMsg) {
+ // NOTE pckOutCh is channel to listen on for packets received by VOLTHA
+ // the OLT device will publish messages on that channel
+
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("DHCP State Machine starting")
+
+ defer dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("DHCP State machine completed")
+
+ // Send DHCP Discovery packet
+ if err := sendDHCPDiscovery(ponPortId, onuId, serialNumber, onuHwAddress, cTag, stream); err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Can't send DHCP Discovery: %s", err)
+ if err := onuStateMachine.Event("dhcp_failed"); err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Error while transitioning ONU State %v", err)
+ }
+ return
+ }
+
+ if err := onuStateMachine.Event("dhcp_discovery_sent"); err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Error while transitioning ONU State %v", err)
+ }
+
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("Listening on dhcpPktOutCh")
+
+ for msg := range pktOutCh {
+ dhcpLogger.Tracef("Received DHCP message %v", msg)
+
+ pkt := gopacket.NewPacket(msg.Bytes, layers.LayerTypeEthernet, gopacket.Default)
+ dhcpLayer, err := getDhcpLayer(pkt)
+ if err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Can't get DHCP Layer from Packet: %v", err)
+ continue
+ }
+ dhcpMessageType, err := getDhcpMessageType(dhcpLayer)
+ if err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Can't get DHCP Message Type from DHCP Layer: %v", err)
+ continue
+ }
+
+ if dhcpLayer.Operation == layers.DHCPOpReply {
+ if dhcpMessageType == layers.DHCPMsgTypeOffer {
+ if err := sendDHCPRequest(ponPortId, onuId, serialNumber, onuHwAddress, cTag, stream); err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Can't send DHCP Request: %s", err)
+ if err := onuStateMachine.Event("dhcp_failed"); err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Error while transitioning ONU State %v", err)
+ }
+ return
+ }
+ if err := onuStateMachine.Event("dhcp_request_sent"); err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Error while transitioning ONU State %v", err)
+ }
+
+ } else if dhcpMessageType == layers.DHCPMsgTypeAck {
+ // NOTE once the ack is received we don't need to do anything but change the state
+ if err := onuStateMachine.Event("dhcp_ack_received"); err != nil {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Error while transitioning ONU State %v", err)
+ }
+ return
+ }
+ // NOTE do we need to care about DHCPMsgTypeRelease??
+ } else {
+ dhcpLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Warnf("Unsupported DHCP Operation: %s", dhcpLayer.Operation.String())
+ continue
+ }
+ }
+}
diff --git a/internal/bbsim/responders/eapol/eapol.go b/internal/bbsim/responders/eapol/eapol.go
index d32999a..602a78e 100644
--- a/internal/bbsim/responders/eapol/eapol.go
+++ b/internal/bbsim/responders/eapol/eapol.go
@@ -19,15 +19,14 @@
import (
"crypto/md5"
"errors"
- bbsim "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
"github.com/looplab/fsm"
+ bbsim "github.com/opencord/bbsim/internal/bbsim/types"
omci "github.com/opencord/omci-sim"
"github.com/opencord/voltha-protos/go/openolt"
log "github.com/sirupsen/logrus"
"net"
- "sync"
)
var eapolLogger = log.WithFields(log.Fields{
@@ -36,25 +35,28 @@
var eapolVersion uint8 = 1
-func CreateWPASupplicant(onuId uint32, ponPortId uint32, serialNumber *openolt.SerialNumber, onuStateMachine *fsm.FSM, stream openolt.Openolt_EnableIndicationServer, pktOutCh chan *bbsim.ByteMsg) {
+func CreateWPASupplicant(onuId uint32, ponPortId uint32, serialNumber string, onuStateMachine *fsm.FSM, stream openolt.Openolt_EnableIndicationServer, pktOutCh chan *bbsim.ByteMsg) {
// NOTE pckOutCh is channel to listen on for packets received by VOLTHA
// the OLT device will publish messages on that channel
eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
+ "OnuId": onuId,
"IntfId": ponPortId,
- "OnuSn": serialNumber,
+ "OnuSn": serialNumber,
}).Infof("EAPOL State Machine starting")
- var wg sync.WaitGroup
- wg.Add(1)
+ defer eapolLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("EAPOL State machine completed")
if err := sendEapStart(onuId, ponPortId, serialNumber, stream); err != nil {
eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
+ "OnuId": onuId,
"IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Errorf("Can't retrieve GemPortId: %s", err)
+ "OnuSn": serialNumber,
+ }).Errorf("Can't send EapStart Message: %s", err)
if err := onuStateMachine.Event("auth_failed"); err != nil {
eapolLogger.WithFields(log.Fields{
"OnuId": onuId,
@@ -72,104 +74,92 @@
}).Errorf("Error while transitioning ONU State %v", err)
}
- // NOTE do we really need a thread here?
- go func() {
- eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
- "IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Infof("Listening on eapolPktOutCh")
- for msg := range pktOutCh {
- recvpkt := gopacket.NewPacket(msg.Bytes, layers.LayerTypeEthernet, gopacket.Default)
- eap, err := extractEAP(recvpkt)
- if err != nil {
- eapolLogger.Errorf("%s", err)
- }
+ eapolLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("Listening on eapolPktOutCh")
- if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
- reseap := createEAPIdentityResponse(eap.Id)
- pkt := createEAPOLPkt(reseap, onuId, ponPortId)
-
- msg := bbsim.ByteMsg{
- IntfId: ponPortId,
- OnuId: onuId,
- Bytes: pkt,
- }
-
- sendEapolPktIn(msg, stream)
- eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
- "IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Infof("Sent EAPIdentityResponse packet")
- if err := onuStateMachine.Event("eap_resonse_identity_sent"); err != nil {
- eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
- "IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Errorf("Error while transitioning ONU State %v", err)
- }
-
- } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
- senddata := getMD5Data(eap)
- senddata = append([]byte{0x10}, senddata...)
- sendeap := createEAPChallengeResponse(eap.Id, senddata)
- pkt := createEAPOLPkt(sendeap, onuId, ponPortId)
-
- msg := bbsim.ByteMsg{
- IntfId: ponPortId,
- OnuId: onuId,
- Bytes: pkt,
- }
-
- sendEapolPktIn(msg, stream)
- eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
- "IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Infof("Sent EAPChallengeResponse packet")
- if err := onuStateMachine.Event("eap_resonse_challenge_sent"); err != nil {
- eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
- "IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Errorf("Error while transitioning ONU State %v", err)
- }
- } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
- eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
- "IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Infof("Received EAPSuccess packet")
- if err := onuStateMachine.Event("eap_resonse_success_received"); err != nil {
- eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
- "IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Errorf("Error while transitioning ONU State %v", err)
- }
- wg.Done()
- }
-
+ for msg := range pktOutCh {
+ recvpkt := gopacket.NewPacket(msg.Bytes, layers.LayerTypeEthernet, gopacket.Default)
+ eap, err := extractEAP(recvpkt)
+ if err != nil {
+ eapolLogger.Errorf("%s", err)
}
+ if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
+ reseap := createEAPIdentityResponse(eap.Id)
+ pkt := createEAPOLPkt(reseap, onuId, ponPortId)
- }()
+ msg := bbsim.ByteMsg{
+ IntfId: ponPortId,
+ OnuId: onuId,
+ Bytes: pkt,
+ }
- defer eapolLogger.WithFields(log.Fields{
- "OnuId": onuId,
- "IntfId": ponPortId,
- "OnuSn": serialNumber,
- }).Infof("EAPOL State machine completed")
+ sendEapolPktIn(msg, stream)
+ eapolLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("Sent EAPIdentityResponse packet")
+ if err := onuStateMachine.Event("eap_response_identity_sent"); err != nil {
+ eapolLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Error while transitioning ONU State %v", err)
+ }
- wg.Wait()
+ } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
+ senddata := getMD5Data(eap)
+ senddata = append([]byte{0x10}, senddata...)
+ sendeap := createEAPChallengeResponse(eap.Id, senddata)
+ pkt := createEAPOLPkt(sendeap, onuId, ponPortId)
+
+ msg := bbsim.ByteMsg{
+ IntfId: ponPortId,
+ OnuId: onuId,
+ Bytes: pkt,
+ }
+
+ sendEapolPktIn(msg, stream)
+ eapolLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("Sent EAPChallengeResponse packet")
+ if err := onuStateMachine.Event("eap_response_challenge_sent"); err != nil {
+ eapolLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Error while transitioning ONU State %v", err)
+ }
+ } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
+ eapolLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Infof("Received EAPSuccess packet")
+ if err := onuStateMachine.Event("eap_response_success_received"); err != nil {
+ eapolLogger.WithFields(log.Fields{
+ "OnuId": onuId,
+ "IntfId": ponPortId,
+ "OnuSn": serialNumber,
+ }).Errorf("Error while transitioning ONU State %v", err)
+ }
+ return
+ }
+ }
}
func sendEapolPktIn(msg bbsim.ByteMsg, stream openolt.Openolt_EnableIndicationServer) {
+ // FIXME unify sendDHCPPktIn and sendEapolPktIn methods
gemid, err := omci.GetGemPortId(msg.IntfId, msg.OnuId)
if err != nil {
eapolLogger.WithFields(log.Fields{
- "OnuId": msg.OnuId,
+ "OnuId": msg.OnuId,
"IntfId": msg.IntfId,
}).Errorf("Can't retrieve GemPortId: %s", err)
return
@@ -198,9 +188,9 @@
func createEAPChallengeResponse(eapId uint8, payload []byte) *layers.EAP {
eap := layers.EAP{
- Code: layers.EAPCodeResponse,
- Id: eapId,
- Length: 22,
+ Code: layers.EAPCodeResponse,
+ Id: eapId,
+ Length: 22,
Type: layers.EAPTypeOTP,
TypeData: payload,
}
@@ -226,7 +216,6 @@
EthernetType: layers.EthernetTypeEAPOL,
}
-
gopacket.SerializeLayers(buffer, options,
ethernetLayer,
&layers.EAPOL{Version: eapolVersion, Type: 0, Length: eap.Length},
@@ -246,7 +235,7 @@
return eap, nil
}
-var sendEapStart = func(onuId uint32, ponPortId uint32, serialNumber *openolt.SerialNumber, stream openolt.Openolt_EnableIndicationServer) error {
+var sendEapStart = func(onuId uint32, ponPortId uint32, serialNumber string, stream openolt.Openolt_EnableIndicationServer) error {
// send the packet (hacked together)
gemid, err := omci.GetGemPortId(ponPortId, onuId)
@@ -254,6 +243,7 @@
return err
}
+ // TODO use createEAPOLPkt
buffer := gopacket.NewSerializeBuffer()
options := gopacket.SerializeOptions{}
@@ -269,13 +259,14 @@
)
msg := buffer.Bytes()
+ // TODO end createEAPOLPkt
data := &openolt.Indication_PktInd{
PktInd: &openolt.PacketIndication{
- IntfType: "pon",
- IntfId: ponPortId,
+ IntfType: "pon",
+ IntfId: ponPortId,
GemportId: uint32(gemid),
- Pkt: msg,
+ Pkt: msg,
},
}
// end of hacked (move in an EAPOL state machine)
@@ -284,4 +275,4 @@
return err
}
return nil
-}
\ No newline at end of file
+}
diff --git a/internal/bbsim/responders/eapol/eapol_test.go b/internal/bbsim/responders/eapol/eapol_test.go
index 2d8a06c..9e37dae 100644
--- a/internal/bbsim/responders/eapol/eapol_test.go
+++ b/internal/bbsim/responders/eapol/eapol_test.go
@@ -17,8 +17,8 @@
package eapol
import (
- bbsim "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/looplab/fsm"
+ bbsim "github.com/opencord/bbsim/internal/bbsim/types"
"github.com/opencord/voltha-protos/go/openolt"
"google.golang.org/grpc"
"gotest.tools/assert"
@@ -29,7 +29,7 @@
)
var (
- originalSendEapStart func(onuId uint32, ponPortId uint32, serialNumber *openolt.SerialNumber, stream openolt.Openolt_EnableIndicationServer) error
+ originalSendEapStart func(onuId uint32, ponPortId uint32, serialNumber string, stream openolt.Openolt_EnableIndicationServer) error
)
type fakeStream struct {
@@ -42,12 +42,11 @@
return nil
}
-func setUp() {
+func setUp() {
originalSendEapStart = sendEapStart
}
-
-func tearDown() {
+func tearDown() {
sendEapStart = originalSendEapStart
}
@@ -63,12 +62,12 @@
// mocks
mockSendEapStartCalled := 0
mockSendEapStartArgs := struct {
- onuId uint32
- ponPortId uint32
+ onuId uint32
+ ponPortId uint32
serialNumber *openolt.SerialNumber
- stream openolt.Openolt_EnableIndicationServer
+ stream openolt.Openolt_EnableIndicationServer
}{}
- mockSendEapStart := func(onuId uint32, ponPortId uint32, serialNumber *openolt.SerialNumber, stream openolt.Openolt_EnableIndicationServer) error {
+ mockSendEapStart := func(onuId uint32, ponPortId uint32, serialNumber string, stream openolt.Openolt_EnableIndicationServer) error {
mockSendEapStartCalled++
mockSendEapStartArgs.onuId = onuId
mockSendEapStartArgs.ponPortId = ponPortId
@@ -79,20 +78,17 @@
// params for the function under test
var onuId uint32 = 1
var ponPortId uint32 = 0
- var serialNumber = new(openolt.SerialNumber)
-
- serialNumber.VendorId = []byte("BBSM")
- serialNumber.VendorSpecific = []byte{0, byte(0 % 256), byte(ponPortId), byte(onuId)}
+ var serialNumber string = "BBSM00000001"
eapolStateMachine := fsm.NewFSM(
- "auth_started",
- fsm.Events{
- {Name: "eap_start_sent", Src: []string{"auth_started"}, Dst: "eap_start_sent"},
- {Name: "eap_resonse_identity_sent", Src: []string{"eap_start_sent"}, Dst: "eap_resonse_identity_sent"},
- {Name: "eap_resonse_challenge_sent", Src: []string{"eap_resonse_identity_sent"}, Dst: "eap_resonse_challenge_sent"},
- {Name: "eap_resonse_success_received", Src: []string{"eap_resonse_challenge_sent"}, Dst: "eap_resonse_success_received"},
- },
- fsm.Callbacks{},
+ "auth_started",
+ fsm.Events{
+ {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"},
+ },
+ fsm.Callbacks{},
)
pktOutCh := make(chan *bbsim.ByteMsg, 1024)
@@ -103,7 +99,7 @@
wg.Add(1)
go CreateWPASupplicant(onuId, ponPortId, serialNumber, eapolStateMachine, stream, pktOutCh)
- go func(){
+ go func() {
time.Sleep(1 * time.Second)
close(pktOutCh)
wg.Done()
@@ -114,4 +110,4 @@
assert.Equal(t, mockSendEapStartCalled, 1)
assert.Equal(t, mockSendEapStartArgs.onuId, onuId)
assert.Equal(t, mockSendEapStartArgs.ponPortId, ponPortId)
-}
\ No newline at end of file
+}
diff --git a/internal/bbsim/types.go b/internal/bbsim/types.go
index 0da944a..76c23cd 100644
--- a/internal/bbsim/types.go
+++ b/internal/bbsim/types.go
@@ -19,10 +19,11 @@
// General
type CliOptions struct {
- OltID int
- NumNniPerOlt int
- NumPonPerOlt int
- NumOnuPerPon int
- profileCpu *string
+ OltID int
+ NumNniPerOlt int
+ NumPonPerOlt int
+ NumOnuPerPon int
+ STag int
+ CTagInit int
+ profileCpu *string
}
-
diff --git a/internal/bbsim/types/types.go b/internal/bbsim/types/types.go
index 1a1788c..731ca58 100644
--- a/internal/bbsim/types/types.go
+++ b/internal/bbsim/types/types.go
@@ -16,8 +16,14 @@
package types
+import "github.com/google/gopacket"
+
type ByteMsg struct {
IntfId uint32
OnuId uint32
- Bytes []byte
-}
\ No newline at end of file
+ Bytes []byte
+}
+
+type PacketMsg struct {
+ Pkt gopacket.Packet
+}
diff --git a/internal/bbsimctl/commands/onu.go b/internal/bbsimctl/commands/onu.go
index 7d6da8e..6422f0a 100644
--- a/internal/bbsimctl/commands/onu.go
+++ b/internal/bbsimctl/commands/onu.go
@@ -29,7 +29,7 @@
)
const (
- DEFAULT_ONU_DEVICE_HEADER_FORMAT = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .SerialNumber }}\t{{ .OperState }}\t{{ .InternalState }}"
+ DEFAULT_ONU_DEVICE_HEADER_FORMAT = "table{{ .PonPortID }}\t{{ .ID }}\t{{ .SerialNumber }}\t{{ .STag }}\t{{ .CTag }}\t{{ .OperState }}\t{{ .InternalState }}"
)
type ONUOptions struct{}