Skip to content

Commit

Permalink
feat(opi-plugin): intel e2000 vendor plugin for opi-evpn-bridge
Browse files Browse the repository at this point in the history
Signed-off-by: atulpatel261194 <[email protected]>
  • Loading branch information
atulpatel261194 committed Jul 5, 2024
1 parent a72bf8c commit 8b25364
Show file tree
Hide file tree
Showing 3 changed files with 4,498 additions and 0 deletions.
308 changes: 308 additions & 0 deletions ipu-plugin/pkg/intel-e2000/p4runtime/p4driverapi/p4ctl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries.
// Copyright (C) 2023 Nordix Foundation.

// Package p4driverapi handles p4 driver realted functionality
package p4driverapi

import (
"bytes"
"context"
"encoding/binary"

// "encoding/hex"
"fmt"
"net"

// "strings"
"log"
"time"

logr "github.com/sirupsen/logrus"
"google.golang.org/grpc"

p4_v1 "github.com/p4lang/p4runtime/go/p4/v1"

"github.com/antoninbas/p4runtime-go-client/pkg/client"
)

const (
defaultDeviceID = 1
lpmStr = "lpm"
ternaryStr = "ternary"
)

var (
// Ctx var of type context
Ctx context.Context

// P4RtC var of \p4 runtime client
P4RtC *client.Client
)

// TableEntry p4 table entry type
type TableEntry struct {
Tablename string
TableField
Action
}

// Action p4 table action type
type Action struct {
ActionName string
Params []interface{}
}

// TableField p4 table field type
type TableField struct {
FieldValue map[string][2]interface{}
Priority int32
}

// uint16toBytes convert uint16 to bytes
func uint16toBytes(val uint16) []byte {
return []byte{byte(val >> 8), byte(val)}
}

// boolToBytes convert bool to bytes
func boolToBytes(val bool) []byte {
if val {
return []byte{1}
}
return []byte{0}
}

// uint32toBytes convert uint32 to bytes
func uint32toBytes(num uint32) []byte {
bytes := make([]byte, 4)
binary.BigEndian.PutUint32(bytes, num)
return bytes
}

// Buildmfs builds the match fields
func Buildmfs(tablefield TableField) (map[string]client.MatchInterface, bool, error) {
var isTernary bool
isTernary = false
mfs := map[string]client.MatchInterface{}
for key, value := range tablefield.FieldValue {
switch v := value[0].(type) {
case net.HardwareAddr:
mfs[key] = &client.ExactMatch{Value: value[0].(net.HardwareAddr)}
case uint16:
// if value[1].(string) == lpmStr {
switch value[1].(string) {
case lpmStr:
mfs[key] = &client.LpmMatch{Value: uint16toBytes(value[0].(uint16)), PLen: 31}
// } else if value[1].(string) == ternaryStr {
case ternaryStr:
isTernary = true
mfs[key] = &client.TernaryMatch{Value: uint16toBytes(value[0].(uint16)), Mask: uint32toBytes(4294967295)}
// } else {
default:
mfs[key] = &client.ExactMatch{Value: uint16toBytes(value[0].(uint16))}
}
case *net.IPNet:
maskSize, _ := v.Mask.Size()
ip := v.IP.To4()
// if value[1].(string) == lpmStr {
switch value[1].(string) {
case lpmStr:
mfs[key] = &client.LpmMatch{Value: v.IP.To4(), PLen: int32(maskSize)}
// } else if value[1].(string) == ternaryStr {
case ternaryStr:
isTernary = true
mfs[key] = &client.TernaryMatch{Value: []byte(ip), Mask: uint32toBytes(4294967295)}
// } else {
default:
mfs[key] = &client.ExactMatch{Value: []byte(ip)}
}
case net.IP:

switch value[1].(string) {
case lpmStr:

mfs[key] = &client.LpmMatch{Value: value[0].(net.IP).To4(), PLen: 24}
// } else if value[1].(string) == ternaryStr {
case ternaryStr:
isTernary = true
mfs[key] = &client.TernaryMatch{Value: []byte(v), Mask: uint32toBytes(4294967295)}
// } else {
default:
mfs[key] = &client.ExactMatch{Value: []byte(v)}
}
case bool:
mfs[key] = &client.ExactMatch{Value: boolToBytes(value[0].(bool))}
case uint32:
switch value[1].(string) {
case lpmStr:

mfs[key] = &client.LpmMatch{Value: uint32toBytes(value[0].(uint32)), PLen: 31}
// } else if value[1].(string) == ternaryStr {
case ternaryStr:
isTernary = true
mfs[key] = &client.TernaryMatch{Value: uint32toBytes(value[0].(uint32)), Mask: uint32toBytes(4294967295)}
// } else {
default:
mfs[key] = &client.ExactMatch{Value: uint32toBytes(value[0].(uint32))}
}
default:
log.Println("intel-e2000: Unknown field ", v)
return mfs, false, fmt.Errorf("invalid inputtype %d for %s", v, key)
}
}
return mfs, isTernary, nil
}

// GetEntry get the entry
func GetEntry(table string) ([]*p4_v1.TableEntry, error) {
entry, err1 := P4RtC.ReadTableEntryWildcard(Ctx, table)
return entry, err1
}

// DelEntry deletes the entry
func DelEntry(entry TableEntry) error {
Options := &client.TableEntryOptions{
Priority: entry.TableField.Priority,
}
mfs, isTernary, err := Buildmfs(entry.TableField)
if err != nil {
log.Fatalf("intel-e2000: Error in Building mfs: %v", err)
return err
}
if isTernary {
entry := P4RtC.NewTableEntry(entry.Tablename, mfs, nil, Options)
return P4RtC.DeleteTableEntry(Ctx, entry)
}

entryP := P4RtC.NewTableEntry(entry.Tablename, mfs, nil, nil)
return P4RtC.DeleteTableEntry(Ctx, entryP)
}

/*// mustMarshal marshal the msg
func mustMarshal(msg proto.Message) []byte {
data, err := proto.Marshal(msg)
if err != nil {
panic(err) // You should handle errors appropriately in your code
}
return data
}*/

// AddEntry adds an entry
func AddEntry(entry TableEntry) error {
Options := &client.TableEntryOptions{
Priority: entry.TableField.Priority,
}
mfs, isTernary, err := Buildmfs(entry.TableField)
if err != nil {
log.Fatalf("intel-e2000: Error in Building mfs: %v", err)
return err
}
params := make([][]byte, len(entry.Action.Params))
for i := 0; i < len(entry.Action.Params); i++ {
switch v := entry.Action.Params[i].(type) {
case uint16:
buf := new(bytes.Buffer)
err1 := binary.Write(buf, binary.BigEndian, v)
if err1 != nil {
log.Println("intel-e2000: binary.Write failed:", err1)
return err1
}
params[i] = buf.Bytes()
case uint32:
buf := new(bytes.Buffer)
err1 := binary.Write(buf, binary.BigEndian, v)
if err1 != nil {
log.Println("inte-e2000: binary.Write failed:", err1)
return err1
}
params[i] = buf.Bytes()
case net.HardwareAddr:
params[i] = v
case net.IP:
params[i] = v
default:
log.Println("intel-e2000: Unknown actionparam", v)
return nil
}
}

actionSet := P4RtC.NewTableActionDirect(entry.Action.ActionName, params)

if isTernary {
entryP := P4RtC.NewTableEntry(entry.Tablename, mfs, actionSet, Options)
return P4RtC.InsertTableEntry(Ctx, entryP)
}
entryP := P4RtC.NewTableEntry(entry.Tablename, mfs, actionSet, nil)
return P4RtC.InsertTableEntry(Ctx, entryP)
}

/*
// encodeMac encodes the mac from string
func encodeMac(macAddrString string) []byte {
str := strings.Replace(macAddrString, ":", "", -1)
decoded, _ := hex.DecodeString(str)
return decoded
}
*/

// StopCh is used to when to stop the p4rtc when a terminate signal is generated
var StopCh = make(chan struct{})

// NewP4RuntimeClient get the p4 runtime client
func NewP4RuntimeClient(binPath string, p4infoPath string, conn *grpc.ClientConn) error {
Ctx = context.Background()
c := p4_v1.NewP4RuntimeClient(conn)
resp, err := c.Capabilities(Ctx, &p4_v1.CapabilitiesRequest{})
if err != nil {
logr.Fatalf("intel-e2000: Error in Capabilities RPC: %v", err)
return err
}
logr.Infof("intel-e2000: P4Runtime server version is %s", resp.P4RuntimeApiVersion)

electionID := &p4_v1.Uint128{High: 0, Low: 1}

P4RtC = client.NewClient(c, defaultDeviceID, electionID)
arbitrationCh := make(chan bool)

errs := make(chan error, 1)
go func() {
errs <- P4RtC.Run(StopCh, arbitrationCh, nil)
}()

waitCh := make(chan struct{})

go func() {
sent := false
for isPrimary := range arbitrationCh {
if isPrimary {
logr.Infof("We are the primary client!")
if !sent {
waitCh <- struct{}{}
sent = true
}
} else {
logr.Infof("We are not the primary client!")
}
}
}()

func() {
timeout := 5 * time.Second
Ctx2, cancel := context.WithTimeout(Ctx, timeout)
defer cancel()
select {
case <-Ctx2.Done():
logr.Fatalf("Could not become the primary client within %v", timeout)
case <-errs:
logr.Fatalf("Could not get the client within %v", timeout)
case <-waitCh:
}
}()
logr.Info("Setting forwarding pipe")
if _, err := P4RtC.SetFwdPipe(Ctx, binPath, p4infoPath, 0); err != nil {
logr.Fatalf("Error when setting forwarding pipe: %v", err)
return err
}
return nil
}
Loading

0 comments on commit 8b25364

Please sign in to comment.