Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added two apis for adding and removing given ebpf programs #76

Merged
merged 5 commits into from
Aug 17, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions apis/handlers/addprog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright Contributors to the L3AF Project.
// SPDX-License-Identifier: Apache-2.0

package handlers

import (
"context"
"encoding/json"
"fmt"

"io/ioutil"
"net/http"

"github.com/rs/zerolog/log"

"github.com/l3af-project/l3afd/kf"
"github.com/l3af-project/l3afd/models"
)

// AddEbpfPrograms add new eBPF programs on node
// @Summary Adding new eBPF Programs on node
// @Description Adding new eBPF Programs on node
// @Accept json
// @Produce json
// @Param cfgs body []models.L3afBPFPrograms true "BPF programs"
// @Success 200
// @Router /l3af/configs/v1/add [post]
func AddEbpfPrograms(ctx context.Context, kfcfg *kf.NFConfigs) http.HandlerFunc {

return func(w http.ResponseWriter, r *http.Request) {
mesg := ""
statusCode := http.StatusOK

w.Header().Add("Content-Type", "application/json")

defer func(mesg *string, statusCode *int) {
w.WriteHeader(*statusCode)
_, err := w.Write([]byte(*mesg))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we cannot write, should we continue to limp along? I don't quite understand what would happen here after it logs the message?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just return from function because defer functions will execute in the end of parent function

if err != nil {
log.Warn().Msgf("Failed to write response bytes: %v", err)
}
}(&mesg, &statusCode)

if r.Body == nil {
log.Warn().Msgf("Empty request body")
return
}
bodyBuffer, err := ioutil.ReadAll(r.Body)
if err != nil {
mesg = fmt.Sprintf("failed to read request body: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
return
}

var t []models.L3afBPFPrograms
if err := json.Unmarshal(bodyBuffer, &t); err != nil {
mesg = fmt.Sprintf("failed to unmarshal payload: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
return
}

if err := kfcfg.AddeBPFPrograms(t); err != nil {
mesg = fmt.Sprintf("failed to AddEbpfPrograms : %v", err)
log.Error().Msg(mesg)

statusCode = http.StatusInternalServerError
return
}
}
}
104 changes: 104 additions & 0 deletions apis/handlers/addprog_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package handlers

import (
"context"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"

"github.com/l3af-project/l3afd/config"
"github.com/l3af-project/l3afd/kf"
)

const dummypayload string = `[
{
"host_name" : "l3af-local-test",
"iface" : "fakeif0",
"bpf_programs" : {
"xdp_ingress" : [
],
"tc_egress": [
],
"tc_ingress": [
]
}
}
]
`

func Test_addprog(t *testing.T) {

tests := []struct {
name string
Body *strings.Reader
header map[string]string
status int
cfg *kf.NFConfigs
}{
{
name: "NilBody",
Body: nil,
status: http.StatusOK,
cfg: &kf.NFConfigs{
HostConfig: &config.Config{
L3afConfigStoreFileName: filepath.FromSlash("../../testdata/Test_l3af-config.json"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this path ok on Windows as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It passes windows tests

},
},
},
{
name: "FailedToUnmarshal",
Body: strings.NewReader("Something"),
status: http.StatusInternalServerError,
header: map[string]string{},
cfg: &kf.NFConfigs{
HostConfig: &config.Config{
L3afConfigStoreFileName: filepath.FromSlash("../../testdata/Test_l3af-config.json"),
},
},
},
{
name: "EmptyInput",
Body: strings.NewReader("[]"),
header: map[string]string{
"Content-Type": "application/json",
},
cfg: &kf.NFConfigs{
HostConfig: &config.Config{
L3afConfigStoreFileName: filepath.FromSlash("../../testdata/Test_l3af-config.json"),
},
},
status: http.StatusOK,
},
{
name: "UnknownHostName",
Body: strings.NewReader(dummypayload),
status: http.StatusInternalServerError,
header: map[string]string{},
cfg: &kf.NFConfigs{
HostName: "dummy",
HostConfig: &config.Config{
L3afConfigStoreFileName: filepath.FromSlash("../../testdata/Test_l3af-config.json"),
},
},
},
}
for _, tt := range tests {
var req *http.Request
if tt.Body == nil {
req, _ = http.NewRequest("POST", "/l3af/configs/v1/add", nil)
} else {
req, _ = http.NewRequest("POST", "/l3af/configs/v1/add", tt.Body)
}
for key, val := range tt.header {
req.Header.Set(key, val)
}
rr := httptest.NewRecorder()
handler := AddEbpfPrograms(context.Background(), tt.cfg)
handler.ServeHTTP(rr, req)
if rr.Code != tt.status {
t.Error("AddEbpfPrograms Failed")
}
}
}
72 changes: 72 additions & 0 deletions apis/handlers/deleteprog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright Contributors to the L3AF Project.
// SPDX-License-Identifier: Apache-2.0

package handlers

import (
"context"
"encoding/json"
"fmt"

"io/ioutil"
"net/http"

"github.com/rs/zerolog/log"

"github.com/l3af-project/l3afd/kf"
"github.com/l3af-project/l3afd/models"
)

// DeleteEbpfPrograms remove eBPF programs on node
// @Summary remove eBPF Programs on node
// @Description remove eBPF Programs on node
// @Accept json
// @Produce json
// @Param cfgs body []models.L3afBPFProgramNames true "BPF program names"
// @Success 200
// @Router /l3af/configs/v1/delete [post]
func DeleteEbpfPrograms(ctx context.Context, kfcfg *kf.NFConfigs) http.HandlerFunc {

return func(w http.ResponseWriter, r *http.Request) {
mesg := ""
statusCode := http.StatusOK

w.Header().Add("Content-Type", "application/json")

defer func(mesg *string, statusCode *int) {
w.WriteHeader(*statusCode)
_, err := w.Write([]byte(*mesg))
if err != nil {
log.Warn().Msgf("Failed to write response bytes: %v", err)
}
}(&mesg, &statusCode)

if r.Body == nil {
log.Warn().Msgf("Empty request body")
return
}
bodyBuffer, err := ioutil.ReadAll(r.Body)
if err != nil {
mesg = fmt.Sprintf("failed to read request body: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
return
}

var t []models.L3afBPFProgramNames
if err := json.Unmarshal(bodyBuffer, &t); err != nil {
mesg = fmt.Sprintf("failed to unmarshal payload: %v", err)
log.Error().Msg(mesg)
statusCode = http.StatusInternalServerError
return
}

if err := kfcfg.DeleteEbpfPrograms(t); err != nil {
mesg = fmt.Sprintf("failed to DeleteEbpfPrograms : %v", err)
log.Error().Msg(mesg)

statusCode = http.StatusInternalServerError
return
}
}
}
102 changes: 102 additions & 0 deletions apis/handlers/deleteprog_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package handlers

import (
"context"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"

"github.com/l3af-project/l3afd/config"
"github.com/l3af-project/l3afd/kf"
)

const payloadfordelete string = `[
{
"host_name": "l3af-local-test",
"iface": "fakeif0",
"bpf_programs": {
"xdp_ingress": [
"ratelimiting",
"connection-limit"
]
}
}
]
`

func Test_DeleteEbpfPrograms(t *testing.T) {

tests := []struct {
name string
Body *strings.Reader
header map[string]string
status int
cfg *kf.NFConfigs
}{
{
name: "NilBody",
Body: nil,
status: http.StatusOK,
cfg: &kf.NFConfigs{
HostConfig: &config.Config{
L3afConfigStoreFileName: filepath.FromSlash("../../testdata/Test_l3af-config.json"),
},
},
},
{
name: "FailedToUnmarshal",
Body: strings.NewReader("Something"),
status: http.StatusInternalServerError,
header: map[string]string{},
cfg: &kf.NFConfigs{
HostConfig: &config.Config{
L3afConfigStoreFileName: filepath.FromSlash("../../testdata/Test_l3af-config.json"),
},
},
},
{
name: "EmptyInput",
Body: strings.NewReader(`[]`),
header: map[string]string{
"Content-Type": "application/json",
},
cfg: &kf.NFConfigs{
HostConfig: &config.Config{
L3afConfigStoreFileName: filepath.FromSlash("../../testdata/Test_l3af-config.json"),
},
},
status: http.StatusOK,
},
{
name: "UnknownHostName",
Body: strings.NewReader(payloadfordelete),
status: http.StatusInternalServerError,
header: map[string]string{},
cfg: &kf.NFConfigs{
HostName: "dummy",
HostConfig: &config.Config{
L3afConfigStoreFileName: filepath.FromSlash("../../testdata/Test_l3af-config.json"),
},
},
},
}
for _, tt := range tests {
var req *http.Request
if tt.Body == nil {
req, _ = http.NewRequest("POST", "/l3af/configs/v1/delete", nil)
} else {
req, _ = http.NewRequest("POST", "/l3af/configs/v1/delete", tt.Body)
}
for key, val := range tt.header {
req.Header.Set(key, val)
}
rr := httptest.NewRecorder()
handler := DeleteEbpfPrograms(context.Background(), tt.cfg)
handler.ServeHTTP(rr, req)
if rr.Code != tt.status {
t.Error("DeleteEbpfPrograms Failed")
}
}
}
Loading