blob: 1d81091ea1a45ad8f8f051794d8b23ab52fe763c [file] [log] [blame]
Matteo Scandoloa229eca2017-08-08 13:05:28 -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
Rich Lane17215b32012-10-26 18:01:12 -070017"""
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
Ben Pfaff40661482013-02-01 13:37:59 -080036class DataPlanePortOVSDummy:
Rich Lane17215b32012-10-26 18:01:12 -070037 """
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
Ben Pfaff40661482013-02-01 13:37:59 -080043 def __init__(self, interface_name, port_number, max_pkts=1024):
Rich Lane17215b32012-10-26 18:01:12 -070044 """
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
Rich Lane17215b32012-10-26 18:01:12 -070048 @param max_pkts Maximum number of pkts to keep in queue
49 """
Rich Lane17215b32012-10-26 18:01:12 -070050 self.interface_name = interface_name
51 self.max_pkts = max_pkts
Rich Lane17215b32012-10-26 18:01:12 -070052 self.port_number = port_number
53 self.txq = []
Ben Pfaff40661482013-02-01 13:37:59 -080054 self.rxbuf = ""
Rich Lane17215b32012-10-26 18:01:12 -070055 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__)
Rich Lane17215b32012-10-26 18:01:12 -070063
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
Ben Pfaff40661482013-02-01 13:37:59 -080077 def __del__(self):
78 if self.socket:
Rich Lane17215b32012-10-26 18:01:12 -070079 self.socket.close()
Rich Lane17215b32012-10-26 18:01:12 -070080
Ben Pfaff40661482013-02-01 13:37:59 -080081 def fileno(self):
Rich Lane17215b32012-10-26 18:01:12 -070082 """
Ben Pfaff40661482013-02-01 13:37:59 -080083 Return an integer file descriptor that can be passed to select(2).
Rich Lane17215b32012-10-26 18:01:12 -070084 """
Ben Pfaff40661482013-02-01 13:37:59 -080085 return self.socket.fileno()
Rich Lane17215b32012-10-26 18:01:12 -070086
Ben Pfaff40661482013-02-01 13:37:59 -080087 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)
Rich Lane17215b32012-10-26 18:01:12 -0700109
110 def send(self, packet):
Rich Lane17215b32012-10-26 18:01:12 -0700111 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
Ben Pfaff40661482013-02-01 13:37:59 -0800116 self.__run_tx()
Rich Lane17215b32012-10-26 18:01:12 -0700117 return retval
118
Ben Pfaff40661482013-02-01 13:37:59 -0800119 def __run_tx(self):
120 while self.txq:
121 rout, wout, eout = select.select([], [self.socket], [], 0)
122 if not wout:
123 return
Rich Lane17215b32012-10-26 18:01:12 -0700124
Ben Pfaff40661482013-02-01 13:37:59 -0800125 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):
Rich Lane17215b32012-10-26 18:01:12 -0700132 pass
133
Ben Pfaff40661482013-02-01 13:37:59 -0800134 def up(self):
135 pass
Rich Lane17215b32012-10-26 18:01:12 -0700136
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