Skip to content

Commit 351887e

Browse files
feat(opi-plugin): intel e2000 vendor plugin for opi-evpn-bridge
Signed-off-by: atulpatel261194 <[email protected]>
1 parent a72bf8c commit 351887e

File tree

3 files changed

+4498
-0
lines changed

3 files changed

+4498
-0
lines changed
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright (c) 2022-2023 Intel Corporation, or its subsidiaries.
3+
// Copyright (C) 2023 Nordix Foundation.
4+
5+
// Package p4driverapi handles p4 driver realted functionality
6+
package p4driverapi
7+
8+
import (
9+
"bytes"
10+
"context"
11+
"encoding/binary"
12+
13+
// "encoding/hex"
14+
"fmt"
15+
"net"
16+
17+
// "strings"
18+
"log"
19+
"time"
20+
21+
logr "github.com/sirupsen/logrus"
22+
"google.golang.org/grpc"
23+
24+
p4_v1 "github.com/p4lang/p4runtime/go/p4/v1"
25+
26+
"github.com/antoninbas/p4runtime-go-client/pkg/client"
27+
)
28+
29+
const (
30+
defaultDeviceID = 1
31+
lpmStr = "lpm"
32+
ternaryStr = "ternary"
33+
)
34+
35+
var (
36+
// Ctx var of type context
37+
Ctx context.Context
38+
39+
// P4RtC var of \p4 runtime client
40+
P4RtC *client.Client
41+
)
42+
43+
// TableEntry p4 table entry type
44+
type TableEntry struct {
45+
Tablename string
46+
TableField
47+
Action
48+
}
49+
50+
// Action p4 table action type
51+
type Action struct {
52+
ActionName string
53+
Params []interface{}
54+
}
55+
56+
// TableField p4 table field type
57+
type TableField struct {
58+
FieldValue map[string][2]interface{}
59+
Priority int32
60+
}
61+
62+
// uint16toBytes convert uint16 to bytes
63+
func uint16toBytes(val uint16) []byte {
64+
return []byte{byte(val >> 8), byte(val)}
65+
}
66+
67+
// boolToBytes convert bool to bytes
68+
func boolToBytes(val bool) []byte {
69+
if val {
70+
return []byte{1}
71+
}
72+
return []byte{0}
73+
}
74+
75+
// uint32toBytes convert uint32 to bytes
76+
func uint32toBytes(num uint32) []byte {
77+
bytes := make([]byte, 4)
78+
binary.BigEndian.PutUint32(bytes, num)
79+
return bytes
80+
}
81+
82+
// Buildmfs builds the match fields
83+
func Buildmfs(tablefield TableField) (map[string]client.MatchInterface, bool, error) {
84+
var isTernary bool
85+
isTernary = false
86+
mfs := map[string]client.MatchInterface{}
87+
for key, value := range tablefield.FieldValue {
88+
switch v := value[0].(type) {
89+
case net.HardwareAddr:
90+
mfs[key] = &client.ExactMatch{Value: value[0].(net.HardwareAddr)}
91+
case uint16:
92+
// if value[1].(string) == lpmStr {
93+
switch value[1].(string) {
94+
case lpmStr:
95+
mfs[key] = &client.LpmMatch{Value: uint16toBytes(value[0].(uint16)), PLen: 31}
96+
// } else if value[1].(string) == ternaryStr {
97+
case ternaryStr:
98+
isTernary = true
99+
mfs[key] = &client.TernaryMatch{Value: uint16toBytes(value[0].(uint16)), Mask: uint32toBytes(4294967295)}
100+
// } else {
101+
default:
102+
mfs[key] = &client.ExactMatch{Value: uint16toBytes(value[0].(uint16))}
103+
}
104+
case *net.IPNet:
105+
maskSize, _ := v.Mask.Size()
106+
ip := v.IP.To4()
107+
// if value[1].(string) == lpmStr {
108+
switch value[1].(string) {
109+
case lpmStr:
110+
mfs[key] = &client.LpmMatch{Value: v.IP.To4(), PLen: int32(maskSize)}
111+
// } else if value[1].(string) == ternaryStr {
112+
case ternaryStr:
113+
isTernary = true
114+
mfs[key] = &client.TernaryMatch{Value: []byte(ip), Mask: uint32toBytes(4294967295)}
115+
// } else {
116+
default:
117+
mfs[key] = &client.ExactMatch{Value: []byte(ip)}
118+
}
119+
case net.IP:
120+
121+
switch value[1].(string) {
122+
case lpmStr:
123+
124+
mfs[key] = &client.LpmMatch{Value: value[0].(net.IP).To4(), PLen: 24}
125+
// } else if value[1].(string) == ternaryStr {
126+
case ternaryStr:
127+
isTernary = true
128+
mfs[key] = &client.TernaryMatch{Value: []byte(v), Mask: uint32toBytes(4294967295)}
129+
// } else {
130+
default:
131+
mfs[key] = &client.ExactMatch{Value: []byte(v)}
132+
}
133+
case bool:
134+
mfs[key] = &client.ExactMatch{Value: boolToBytes(value[0].(bool))}
135+
case uint32:
136+
switch value[1].(string) {
137+
case lpmStr:
138+
139+
mfs[key] = &client.LpmMatch{Value: uint32toBytes(value[0].(uint32)), PLen: 31}
140+
// } else if value[1].(string) == ternaryStr {
141+
case ternaryStr:
142+
isTernary = true
143+
mfs[key] = &client.TernaryMatch{Value: uint32toBytes(value[0].(uint32)), Mask: uint32toBytes(4294967295)}
144+
// } else {
145+
default:
146+
mfs[key] = &client.ExactMatch{Value: uint32toBytes(value[0].(uint32))}
147+
}
148+
default:
149+
log.Println("intel-e2000: Unknown field ", v)
150+
return mfs, false, fmt.Errorf("invalid inputtype %d for %s", v, key)
151+
}
152+
}
153+
return mfs, isTernary, nil
154+
}
155+
156+
// GetEntry get the entry
157+
func GetEntry(table string) ([]*p4_v1.TableEntry, error) {
158+
entry, err1 := P4RtC.ReadTableEntryWildcard(Ctx, table)
159+
return entry, err1
160+
}
161+
162+
// DelEntry deletes the entry
163+
func DelEntry(entry TableEntry) error {
164+
Options := &client.TableEntryOptions{
165+
Priority: entry.TableField.Priority,
166+
}
167+
mfs, isTernary, err := Buildmfs(entry.TableField)
168+
if err != nil {
169+
log.Fatalf("intel-e2000: Error in Building mfs: %v", err)
170+
return err
171+
}
172+
if isTernary {
173+
entry := P4RtC.NewTableEntry(entry.Tablename, mfs, nil, Options)
174+
return P4RtC.DeleteTableEntry(Ctx, entry)
175+
}
176+
177+
entryP := P4RtC.NewTableEntry(entry.Tablename, mfs, nil, nil)
178+
return P4RtC.DeleteTableEntry(Ctx, entryP)
179+
}
180+
181+
/*// mustMarshal marshal the msg
182+
func mustMarshal(msg proto.Message) []byte {
183+
data, err := proto.Marshal(msg)
184+
if err != nil {
185+
panic(err) // You should handle errors appropriately in your code
186+
}
187+
return data
188+
}*/
189+
190+
// AddEntry adds an entry
191+
func AddEntry(entry TableEntry) error {
192+
Options := &client.TableEntryOptions{
193+
Priority: entry.TableField.Priority,
194+
}
195+
mfs, isTernary, err := Buildmfs(entry.TableField)
196+
if err != nil {
197+
log.Fatalf("intel-e2000: Error in Building mfs: %v", err)
198+
return err
199+
}
200+
params := make([][]byte, len(entry.Action.Params))
201+
for i := 0; i < len(entry.Action.Params); i++ {
202+
switch v := entry.Action.Params[i].(type) {
203+
case uint16:
204+
buf := new(bytes.Buffer)
205+
err1 := binary.Write(buf, binary.BigEndian, v)
206+
if err1 != nil {
207+
log.Println("intel-e2000: binary.Write failed:", err1)
208+
return err1
209+
}
210+
params[i] = buf.Bytes()
211+
case uint32:
212+
buf := new(bytes.Buffer)
213+
err1 := binary.Write(buf, binary.BigEndian, v)
214+
if err1 != nil {
215+
log.Println("inte-e2000: binary.Write failed:", err1)
216+
return err1
217+
}
218+
params[i] = buf.Bytes()
219+
case net.HardwareAddr:
220+
params[i] = v
221+
case net.IP:
222+
params[i] = v
223+
default:
224+
log.Println("intel-e2000: Unknown actionparam", v)
225+
return nil
226+
}
227+
}
228+
229+
actionSet := P4RtC.NewTableActionDirect(entry.Action.ActionName, params)
230+
231+
if isTernary {
232+
entryP := P4RtC.NewTableEntry(entry.Tablename, mfs, actionSet, Options)
233+
return P4RtC.InsertTableEntry(Ctx, entryP)
234+
}
235+
entryP := P4RtC.NewTableEntry(entry.Tablename, mfs, actionSet, nil)
236+
return P4RtC.InsertTableEntry(Ctx, entryP)
237+
}
238+
239+
/*
240+
// encodeMac encodes the mac from string
241+
242+
func encodeMac(macAddrString string) []byte {
243+
str := strings.Replace(macAddrString, ":", "", -1)
244+
decoded, _ := hex.DecodeString(str)
245+
return decoded
246+
}
247+
*/
248+
249+
// StopCh is used to when to stop the p4rtc when a terminate signal is generated
250+
var StopCh = make(chan struct{})
251+
252+
// NewP4RuntimeClient get the p4 runtime client
253+
func NewP4RuntimeClient(binPath string, p4infoPath string, conn *grpc.ClientConn) error {
254+
Ctx = context.Background()
255+
c := p4_v1.NewP4RuntimeClient(conn)
256+
resp, err := c.Capabilities(Ctx, &p4_v1.CapabilitiesRequest{})
257+
if err != nil {
258+
logr.Fatalf("intel-e2000: Error in Capabilities RPC: %v", err)
259+
return err
260+
}
261+
logr.Infof("intel-e2000: P4Runtime server version is %s", resp.P4RuntimeApiVersion)
262+
263+
electionID := &p4_v1.Uint128{High: 0, Low: 1}
264+
265+
P4RtC = client.NewClient(c, defaultDeviceID, electionID)
266+
arbitrationCh := make(chan bool)
267+
268+
errs := make(chan error, 1)
269+
go func() {
270+
errs <- P4RtC.Run(StopCh, arbitrationCh, nil)
271+
}()
272+
273+
waitCh := make(chan struct{})
274+
275+
go func() {
276+
sent := false
277+
for isPrimary := range arbitrationCh {
278+
if isPrimary {
279+
logr.Infof("We are the primary client!")
280+
if !sent {
281+
waitCh <- struct{}{}
282+
sent = true
283+
}
284+
} else {
285+
logr.Infof("We are not the primary client!")
286+
}
287+
}
288+
}()
289+
290+
func() {
291+
timeout := 5 * time.Second
292+
Ctx2, cancel := context.WithTimeout(Ctx, timeout)
293+
defer cancel()
294+
select {
295+
case <-Ctx2.Done():
296+
logr.Fatalf("Could not become the primary client within %v", timeout)
297+
case <-errs:
298+
logr.Fatalf("Could not get the client within %v", timeout)
299+
case <-waitCh:
300+
}
301+
}()
302+
logr.Info("Setting forwarding pipe")
303+
if _, err := P4RtC.SetFwdPipe(Ctx, binPath, p4infoPath, 0); err != nil {
304+
logr.Fatalf("Error when setting forwarding pipe: %v", err)
305+
return err
306+
}
307+
return nil
308+
}

0 commit comments

Comments
 (0)