github.com/fafucoder/cilium@v1.6.11/proxylib/proxylib.go (about)

     1  // Copyright 2018 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  /*
    18  #include "proxylib/types.h"
    19  */
    20  import "C"
    21  
    22  import (
    23  	"github.com/cilium/cilium/proxylib/accesslog"
    24  	_ "github.com/cilium/cilium/proxylib/cassandra"
    25  	_ "github.com/cilium/cilium/proxylib/memcached"
    26  	"github.com/cilium/cilium/proxylib/npds"
    27  	. "github.com/cilium/cilium/proxylib/proxylib"
    28  	_ "github.com/cilium/cilium/proxylib/r2d2"
    29  	_ "github.com/cilium/cilium/proxylib/testparsers"
    30  
    31  	"github.com/cilium/cilium/pkg/lock"
    32  	log "github.com/sirupsen/logrus"
    33  )
    34  
    35  var (
    36  	// mutex protects connections
    37  	mutex lock.RWMutex
    38  	// Key uint64 is a connection ID allocated by Envoy, practically a monotonically increasing number
    39  	connections map[uint64]*Connection = make(map[uint64]*Connection)
    40  )
    41  
    42  func init() {
    43  	log.Debug("proxylib: Initializing library")
    44  }
    45  
    46  // Copy value string from C-memory to Go-memory.
    47  // Go strings are immutable, but byte slices are not. Converting to a byte slice will thus
    48  // copy the memory.
    49  func strcpy(str string) string {
    50  	return string(([]byte(str))[0:])
    51  }
    52  
    53  // OnNewConnection is used to register a new connection of protocol 'proto'.
    54  // Note that the 'origBuf' and replyBuf' type '*[]byte' corresponds to 'InjectBuf' type, but due to
    55  // cgo export restrictions we can't use the go type in the prototype.
    56  //export OnNewConnection
    57  func OnNewConnection(instanceId uint64, proto string, connectionId uint64, ingress bool, srcId, dstId uint32, srcAddr, dstAddr, policyName string, origBuf, replyBuf *[]byte) C.FilterResult {
    58  	instance := FindInstance(instanceId)
    59  	if instance == nil {
    60  		return C.FILTER_INVALID_INSTANCE
    61  	}
    62  
    63  	err, conn := NewConnection(instance, strcpy(proto), connectionId, ingress, srcId, dstId, strcpy(srcAddr), strcpy(dstAddr), strcpy(policyName), origBuf, replyBuf)
    64  	if err == nil {
    65  		mutex.Lock()
    66  		connections[connectionId] = conn
    67  		mutex.Unlock()
    68  		return C.FILTER_OK
    69  	}
    70  	if res, ok := err.(FilterResult); ok {
    71  		return C.FilterResult(res)
    72  	}
    73  	return C.FILTER_UNKNOWN_ERROR
    74  }
    75  
    76  // Each connection is assumed to be called from a single thread, so accessing connection metadata
    77  // does not need protection.
    78  //
    79  // OnData gets all the unparsed data the datapath has received so far. The data is provided to the parser
    80  // associated with the connection, and the parser is expected to find if the data frame contains enough data
    81  // to make a PASS/DROP decision for the whole data frame. Note that the whole data frame need not be received,
    82  // if the decision including the length of the data frame in bytes can be determined based on the beginning of
    83  // the data frame only (e.g., headers including the length of the data frame). The parser returns a decision
    84  // with the number of bytes on which the decision applies. If more data is available, then the parser will be
    85  // called again with the remaining data. Parser needs to return MORE if a decision can't be made with
    86  // the available data, including the minimum number of additional bytes that is needed before the parser is
    87  // called again.
    88  //
    89  // The parser can also inject at arbitrary points in the data stream. This is indecated by an INJECT operation
    90  // with the number of bytes to be injected. The actual bytes to be injected are provided via an Inject()
    91  // callback prior to returning the INJECT operation. The Inject() callback operates on a limited size buffer
    92  // provided by the datapath, and multiple INJECT operations may be needed to inject large amounts of data.
    93  // Since we get the data on one direction at a time, any frames to be injected in the reverse direction
    94  // are placed in the reverse direction buffer, from where the datapath injects the data before calling
    95  // us again for the reverse direction input.
    96  //
    97  //export OnData
    98  func OnData(connectionId uint64, reply, endStream bool, data *[][]byte, filterOps *[][2]int64) C.FilterResult {
    99  	// Find the connection
   100  	mutex.RLock()
   101  	connection, ok := connections[connectionId]
   102  	mutex.RUnlock()
   103  	if !ok {
   104  		return C.FILTER_UNKNOWN_CONNECTION
   105  	}
   106  
   107  	return C.FilterResult(connection.OnData(reply, endStream, data, filterOps))
   108  }
   109  
   110  // Make this more general connection event callback
   111  //export Close
   112  func Close(connectionId uint64) {
   113  	mutex.Lock()
   114  	delete(connections, connectionId)
   115  	mutex.Unlock()
   116  }
   117  
   118  // OpenModule is called before any other APIs.
   119  // Called concurrently by different filter instances.
   120  // Returns a library instance ID that must be passed to all other API calls.
   121  // Calls with the same parameters will return the same instance.
   122  // Zero return value indicates an error.
   123  //export OpenModule
   124  func OpenModule(params [][2]string, debug bool) uint64 {
   125  	var accessLogPath, xdsPath, nodeID string
   126  	for i := range params {
   127  		key := params[i][0]
   128  		value := strcpy(params[i][1])
   129  
   130  		switch key {
   131  		case "access-log-path":
   132  			accessLogPath = value
   133  		case "xds-path":
   134  			xdsPath = value
   135  		case "node-id":
   136  			nodeID = value
   137  		default:
   138  			return 0
   139  		}
   140  	}
   141  
   142  	if debug {
   143  		mutex.Lock()
   144  		log.SetLevel(log.DebugLevel)
   145  		mutex.Unlock()
   146  	}
   147  	// Copy strings from C-memory to Go-memory so that the string remains valid
   148  	// also after this function returns
   149  	return OpenInstance(nodeID, xdsPath, npds.NewClient, accessLogPath, accesslog.NewClient)
   150  }
   151  
   152  //export CloseModule
   153  func CloseModule(id uint64) {
   154  	CloseInstance(id)
   155  }
   156  
   157  // Must have empty main
   158  func main() {}