blob: 1d81091ea1a45ad8f8f051794d8b23ab52fe763c [file] [log] [blame]
Sreeju Sreedhare3fefd92019-04-02 15:57:15 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
17"""
18Dummy platform
19
20This platform uses Open vSwitch dummy interfaces.
21"""
22
23import logging
24import os
25import select
26import socket
27import struct
28import sys
29import time
30from threading import Thread
31from threading import Lock
32
33RCV_TIMEOUT = 10000
34RUN_DIR = os.environ.get("OVS_RUNDIR", "/var/run/openvswitch")
35
36class DataPlanePortOVSDummy:
37 """
38 Class defining a port monitoring object that uses Unix domain
39 sockets for ports, intended for connecting to Open vSwitch "dummy"
40 netdevs.
41 """
42
43 def __init__(self, interface_name, port_number, max_pkts=1024):
44 """
45 Set up a port monitor object
46 @param interface_name The name of the physical interface like eth1
47 @param port_number The port number associated with this port
48 @param max_pkts Maximum number of pkts to keep in queue
49 """
50 self.interface_name = interface_name
51 self.max_pkts = max_pkts
52 self.port_number = port_number
53 self.txq = []
54 self.rxbuf = ""
55 logname = "dp-" + interface_name
56 self.logger = logging.getLogger(logname)
57 try:
58 self.socket = DataPlanePortOVSDummy.interface_open(interface_name)
59 except:
60 self.logger.info("Could not open socket")
61 raise
62 self.logger.info("Opened port monitor (class %s)", type(self).__name__)
63
64 @staticmethod
65 def interface_open(interface_name):
66 """
67 Open a Unix domain socket interface.
68 @param interface_name port name as a string such as 'eth1'
69 @retval s socket
70 """
71 s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
72 s.settimeout(RCV_TIMEOUT)
73 s.setblocking(0)
74 s.connect("%s/%s" % (RUN_DIR, interface_name))
75 return s
76
77 def __del__(self):
78 if self.socket:
79 self.socket.close()
80
81 def fileno(self):
82 """
83 Return an integer file descriptor that can be passed to select(2).
84 """
85 return self.socket.fileno()
86
87 def recv(self):
88 while True:
89 rout, wout, eout = select.select([self.socket], [], [], 0)
90 if not rout:
91 return
92
93 if len(self.rxbuf) < 2:
94 n = 2 - len(self.rxbuf)
95 else:
96 frame_len = struct.unpack('>h', self.rxbuf[:2])[0]
97 n = (2 + frame_len) - len(self.rxbuf)
98
99 data = self.socket.recv(n)
100 self.rxbuf += data
101 if len(data) == n and len(self.rxbuf) > 2:
102 rcvtime = time.time()
103 packet = self.rxbuf[2:]
104 self.logger.debug("Pkt len " + str(len(packet)) +
105 " in at " + str(rcvtime) + " on port " +
106 str(self.port_number))
107 self.rxbuf = ""
108 return (packet, rcvtime)
109
110 def send(self, packet):
111 if len(self.txq) < self.max_pkts:
112 self.txq.append(struct.pack('>h', len(packet)) + packet)
113 retval = len(packet)
114 else:
115 retval = 0
116 self.__run_tx()
117 return retval
118
119 def __run_tx(self):
120 while self.txq:
121 rout, wout, eout = select.select([], [self.socket], [], 0)
122 if not wout:
123 return
124
125 retval = self.socket.send(self.txq[0])
126 if retval > 0:
127 self.txq[0] = self.txq[0][retval:]
128 if len(self.txq[0]) == 0:
129 self.txq = self.txq[1:]
130
131 def down(self):
132 pass
133
134 def up(self):
135 pass
136
137# Update this dictionary to suit your environment.
138dummy_port_map = {
139 1 : "p1",
140 2 : "p2",
141 3 : "p3",
142 4 : "p4"
143}
144
145def platform_config_update(config):
146 """
147 Update configuration for the dummy platform
148
149 @param config The configuration dictionary to use/update
150 """
151 global dummy_port_map
152 config["port_map"] = dummy_port_map.copy()
153 config["caps_table_idx"] = 0
154 config["dataplane"] = {"portclass": DataPlanePortOVSDummy}
155 config["allow_user"] = True