OSDN Git Service

add routing informations for tunneling remote_ip to OVSAgent
[ti2/ti2.git] / linkpair / collect / agent / ovs_agent.py
1 # vim: tabstop=4 shiftwidth=4 softtabstop=4
2 # -*- coding: utf-8 -*-
3 #
4
5 __version__ = '1.1'
6
7 import re
8 from linkpair.device import Device
9 from linkpair.port import Port
10 from linkpair.collect.agent.base_agent import BaseAgent
11
12
13 class OVSAgent(BaseAgent):
14     '''
15     Open vSwitch Collector Agent
16     '''
17
18     def run(self):
19         self.get_configuration()
20
21     def get_bridge_metadata(self, br):
22         br_meta = {}
23         br_meta["dpid"] = ""
24         br_meta["controller"] = ""
25         br_meta["manager"] = ""
26
27         res_mgr = self._runner.exec_cmd("ovs-vsctl get-manager")
28         for mgr in res_mgr:
29             br_meta["manager"] = self._u.str_join(
30                 br_meta["manager"], mgr.strip(), ", ")
31
32         res_ctl = self._runner.exec_cmd("ovs-vsctl get-controller " + br)
33         for ctl in res_ctl:
34             br_meta["controller"] = self._u.str_join(
35                 br_meta["controller"], ctl.strip(), ", ")
36
37         res_ofsw = self._runner.exec_cmd("ovs-ofctl show " + br)
38         for ofsw_spec in res_ofsw:
39             ofsw_spec = ofsw_spec.strip()
40             if self._u.d_push(re.search(r': dpid:(.*)', ofsw_spec)) is not None:
41                 br_meta["dpid"] = self._u.d_pop().group(1).strip()
42             elif self._u.d_push(re.search(r'n_tables:(.*), n_buffers:(.*)', ofsw_spec)) is not None:
43                 match = self._u.d_pop()
44                 br_meta["tables"] = match.group(1).strip()
45                 br_meta["buffers"] = match.group(2).strip()
46             elif self._u.d_push(re.search(r'capabilities:(.*)', ofsw_spec)) is not None:
47                 br_meta["capabilities"] = self._u.d_pop().group(1).strip()
48             elif self._u.d_push(re.search(r'actions:(.*)', ofsw_spec)) is not None:
49                 br_meta["actions"] = self._u.d_pop().group(1).strip()
50
51         return br_meta
52
53     def get_port_metadata(self, port_name, br_name=""):
54         port_meta = {}
55         exist_port = self._cu.get_port(port_name)
56         if exist_port != self._cu.PORT_NOT_FOUND:
57             port_meta = exist_port.metadata
58
59         res_ovsport = self._runner.exec_cmd("ovs-vsctl show")
60         for i in range(0, len(res_ovsport)):
61             port_start = res_ovsport[i].strip()
62             if self._u.d_push(re.search(r'Port "?%s"?' % port_name, port_start)) is not None:
63                 for j in range(i + 1, len(res_ovsport)):
64                     port_spec = res_ovsport[j].strip()
65                     if self._u.d_push(re.search(r'tag: (.*)', port_spec)) is not None:
66                         port_meta["tag"] = self._u.d_pop().group(1).strip()
67                     elif self._u.d_push(re.search(r'type: (.*)', port_spec)) is not None:
68                         port_meta["type"] = self._u.d_pop().group(1).strip()
69                     elif self._u.d_push(re.search(r'options: {(.*)}', port_spec)) is not None:
70                         port_options = self._u.d_pop().group(
71                             1).strip().split(",")
72                         for port_option in port_options:
73                             (opt_name, opt_value) = port_option.split("=")
74                             opt_name = opt_name.strip()
75                             opt_value = opt_value.replace("\""," ")
76                             opt_value = opt_value.strip()
77                             port_meta[opt_name] = opt_value
78                             if opt_name == "remote_ip":
79                                 res_iproute = self._runner.exec_cmd("ip route get " + opt_value)
80                                 for i in range(0, len(res_iproute)):
81                                     remote_route = res_iproute[i].strip()
82                                     if self._u.d_push(re.search(r'via (\S+) dev (\S+)  src (\S+)', remote_route)) is not None:
83                                         match = self._u.d_pop()
84                                         port_meta["remote_routing_if_ipaddr"] = match.group(1).strip()
85                                         port_meta["remote_routing_if_dev"] = match.group(2).strip()
86                                         port_meta["remote_routing_src_ipaddr"] = match.group(3).strip()
87                                     elif self._u.d_push(re.search(r'cache  mtu (\d+) advmss (\d+) hoplimit (\d+)', remote_route)) is not None:
88                                         match = self._u.d_pop()
89                                         port_meta["remote_peer_mtu"] = match.group(1).strip()
90                                         port_meta["remote_peer_mss"] = match.group(2).strip()
91                                         port_meta["remote_peer_hoplimit"] = match.group(3).strip()
92
93                     elif self._u.d_push(re.search(r'Port "*', port_spec)) is not None:
94                         break
95         
96         if br_name != "":
97             res_ofctl = self._runner.exec_cmd("ovs-ofctl show " + br_name)
98             for i in range(0, len(res_ofctl)):
99                 port_start = res_ofctl[i].strip()
100                 if self._u.d_push(re.search(r'(\d+)\(%s\): addr:(.*)' % port_name, port_start)) is not None:
101                     match = self._u.d_pop()
102                     port_meta["port_no"] = match.group(1).strip()
103                     port_meta["mac_addr"] = match.group(2).strip()
104                     break
105                     
106             res_ofctl = self._runner.exec_cmd("ovs-ofctl dump-ports " + br_name)
107             if "port_no" in port_meta:
108                 found_port = False
109                 for i in range(0, len(res_ofctl)):
110                     port_start = res_ofctl[i].strip()
111                     if self._u.d_push(
112                         re.search(r'port\s*%s:\s*rx pkts=(\d+), bytes=(\d+), drop=(\d+), errs=(\d+), frame=(\d+), over=(\d+), crc=(\d+)'
113                             % port_meta["port_no"], port_start)) is not None:
114                         match = self._u.d_pop()
115                         port_meta["rx_pkts"] = match.group(1).strip()
116                         port_meta["rx_bytes"] = match.group(2).strip()
117                         port_meta["rx_drop"] = match.group(3).strip()
118                         port_meta["rx_errs"] = match.group(4).strip()
119                         port_meta["rx_frame"] = match.group(5).strip()
120                         port_meta["rx_over"] = match.group(6).strip()
121                         port_meta["rx_crc"] = match.group(7).strip()
122                         found_port = True
123                     elif self._u.d_push(
124                         re.search(r'\s*tx pkts=(\d+), bytes=(\d+), drop=(\d+), errs=(\d+), coll=(\d+)',
125                             port_start)) is not None and found_port:
126                         match = self._u.d_pop()
127                         port_meta["tx_pkts"] = match.group(1).strip()
128                         port_meta["tx_bytes"] = match.group(2).strip()
129                         port_meta["tx_drop"] = match.group(3).strip()
130                         port_meta["tx_errs"] = match.group(4).strip()
131                         port_meta["tx_coll"] = match.group(5).strip()
132                         break
133         
134         return port_meta
135
136     def get_configuration(self):
137         patch_peers = {}
138         veth_peers = {}
139
140         result = self._runner.exec_cmd("ovs-vsctl list-br")
141         for br_src in result:
142             br_src = br_src.rstrip()
143             br_src_meta = self.get_bridge_metadata(br_src)
144             port_names = self._runner.exec_cmd(
145                 "ovs-vsctl list-ports " + br_src)
146             for port_name in port_names:
147                 port_name = port_name.rstrip()
148                 port_meta = self.get_port_metadata(port_name, br_src)
149
150                 self._port_to_br[port_name] = br_src
151                 # patch port
152                 if self._cu.get_port_type(port_meta) == "patch":
153                     patch_src = port_name
154                     patch_dst = self._cu.get_port_peer(port_meta)
155                     patch_peers[patch_src + ":" + patch_dst] = self.PEER_FOUND
156
157                     if patch_dst + ":" + patch_src in patch_peers:
158                         continue
159
160                     patch_src_meta = port_meta
161                     result3 = self._runner.exec_cmd(
162                         "ovs-vsctl port-to-br " + patch_dst)
163                     if result3 is not None and len(result3) > 0:
164                         br_dst = result3[0].rstrip()
165                         br_dst_meta = self.get_bridge_metadata(br_dst)
166                         patch_dst_meta = self.get_port_metadata(patch_dst, br_dst)
167                         self._cu.add_linkpair(
168                             Device(br_src, Device.BR_TYPE, br_src_meta),
169                             Device(br_dst, Device.BR_TYPE, br_dst_meta),
170                             Port(patch_src, Port.DEFAULT_TYPE, patch_src_meta),
171                             Port(patch_dst, Port.DEFAULT_TYPE, patch_dst_meta),
172                             self._formatter.PATCH_FORMAT)
173                     else:
174                         patch_dst_meta = self.get_port_metadata(patch_dst, br_dst)
175                         self._cu.add_linkpair(
176                             Device(br_src, Device.BR_TYPE, br_src_meta),
177                             Device("NOT CONNECTED", Device.NOT_CONNECTED_TYPE),
178                             Port(patch_src, Port.DEFAULT_TYPE, patch_src_meta),
179                             Port(patch_dst, Port.DEFAULT_TYPE, patch_dst_meta),
180                             self._formatter.PATCH_FORMAT)
181
182                 # veth port
183                 elif self._cu.get_port_veth_peer(port_name) != self._cu.PORT_PEER_UNSPECIFIED:
184                     peer_src = port_name
185                     peer_dst = self._cu.get_port_veth_peer(port_name)
186                     veth_peers[peer_src + ":" + peer_dst] = self.PEER_FOUND
187
188                     if peer_dst + ":" + peer_src in veth_peers:
189                         continue
190
191                     peer_src_meta = port_meta
192                     result3 = self._runner.exec_cmd(
193                         "ovs-vsctl port-to-br " + peer_dst)
194                     if result3 is not None and len(result3) > 0:
195                         br_dst = result3[0].rstrip()
196                         br_dst_meta = self.get_bridge_metadata(br_dst)
197                         peer_dst_meta = self.get_port_metadata(peer_dst, br_dst)
198                         self._cu.add_linkpair(
199                             Device(br_src, Device.BR_TYPE, br_src_meta),
200                             Device(br_dst, Device.BR_TYPE, br_dst_meta),
201                             Port(peer_src, Port.DEFAULT_TYPE, peer_src_meta),
202                             Port(peer_dst, Port.DEFAULT_TYPE, peer_dst_meta),
203                             self._formatter.VETH_FORMAT)
204                     else:
205                         peer_dst_meta = self.get_port_metadata(peer_dst, br_dst)
206                         self._cu.add_linkpair(
207                             Device(br_src, Device.BR_TYPE, br_src_meta),
208                             Device("NOT CONNECTED", Device.NOT_CONNECTED_TYPE),
209                             Port(peer_src, Port.DEFAULT_TYPE, peer_src_meta),
210                             Port(peer_dst, Port.DEFAULT_TYPE, peer_dst_meta),
211                             self._formatter.VETH_FORMAT)
212
213                 # none patch/veth port
214                 else:
215                     # NOT Internal Bridge Port.
216                     if self._cu.get_port_type(port_meta) != "internal":
217
218                         # physical interface
219                         if self._u.d_push(re.match(r'^eth\d+$', port_name)) \
220                             or self._u.d_push(re.match(r'^em\d+$', port_name)) \
221                                 or self._u.d_push(re.match(r'^igb\d+$', port_name)) \
222                                 or self._u.d_push(re.match(r'^bond\d+$', port_name)):
223                             self._cu.add_linkpair(
224                                 Device(br_src, Device.BR_TYPE, br_src_meta),
225                                 Device("Physical NW", Device.PHYNET_TYPE),
226                                 Port(port_name, Port.DEFAULT_TYPE, port_meta),
227                                 Port(""))
228
229                         # tunnel port
230                         elif self._u.d_push(re.match(r'(vxlan\d+)', port_name)) \
231                             or self._cu.get_port_type(port_meta) == "gre" \
232                                 or self._cu.get_port_type(port_meta) == "stt":
233                             self._cu.add_linkpair(
234                                 Device(br_src, Device.BR_TYPE, br_src_meta),
235                                 Device("OS Routing", Device.OS_ROUTE_TYPE),
236                                 Port(port_name, Port.DEFAULT_TYPE, port_meta),
237                                 Port(""),
238                                 self._formatter.OS_ROUTING_FORMAT)
239
240                         # Other OVSPort
241                         else:
242                             #### VLAN interface
243                             if self._cu.get_port_vlan_master_if(port_name) != self._cu.PORT_VLAN_UNSPECIFIED:
244                                 master_if = self._cu.get_port_vlan_master_if(port_name)
245                                 if master_if in self._port_to_br:
246                                     br_dst = self._port_to_br[master_if]
247                                     br_dst_obj = self._cu.get_device(br_dst)
248                                     port_src = port_name
249                                     port_src_meta = port_meta
250                                     port_dst = master_if
251                                     #port_dst_obj = self._cu.get_port(master_if)
252                                     port_dst_meta = self.get_port_metadata(port_dst, br_dst)
253                                     self._cu.add_linkpair(
254                                         Device(br_src, Device.BR_TYPE, br_src_meta),
255                                         br_dst_obj,
256                                         Port(port_src, Port.DEFAULT_TYPE, port_src_meta),
257                                         #port_dst_obj,
258                                         Port(port_dst, Port.DEFAULT_TYPE, port_dst_meta),
259                                         self._formatter.VLAN_DIST_FORMAT)
260
261                                 elif self._u.d_push(re.match(r'^eth\d+$', master_if)) \
262                                     or self._u.d_push(re.match(r'^em\d+$', master_if)) \
263                                         or self._u.d_push(re.match(r'^igb\d+$', master_if)) \
264                                         or self._u.d_push(re.match(r'^bond\d+$', master_if)):
265                                     self._cu.add_linkpair(
266                                         Device(br_src, Device.BR_TYPE, br_src_meta),
267                                         Device("Physical NW", Device.PHYNET_TYPE),
268                                         Port(port_name, Port.DEFAULT_TYPE, port_meta),
269                                         Port(""))
270                             else:
271                                 self._cu.add_linkpair(
272                                     Device(br_src, Device.BR_TYPE, br_src_meta),
273                                     Device("NOT CONNECTED", Device.NOT_CONNECTED_TYPE),
274                                     Port(port_name, Port.DEFAULT_TYPE, port_meta),
275                                     Port(""))
276
277                     # internal
278                     elif self._cu.get_port_type(port_meta) == "internal":
279                         if port_name in self._iface_to_nss:
280                             self._cu.add_linkpair(
281                                 Device(br_src, Device.BR_TYPE, br_src_meta),
282                                 Device(self._iface_to_nss[
283                                        port], Device.NAMESPACE_TYPE),
284                                 Port(port_name, Port.DEFAULT_TYPE, port_meta),
285                                 Port(""),
286                                 self._formatter.NAMESPACE_FORMAT)
287                         else:
288                             self._cu.add_linkpair(
289                                 Device(br_src, Device.BR_TYPE, br_src_meta),
290                                 Device("INTERNAL", Device.OS_ROUTE_TYPE),
291                                 Port(port_name, Port.DEFAULT_TYPE, port_meta),
292                                 Port(""))
293                     # else:
294                     #        ## Other OVSPort
295                     #        self._port_to_br[port_name] = br_src
296                     else:
297                         continue