1 # Copyright (C) 2017 Nippon Telegraph and Telephone Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 from __future__ import absolute_import
20 from sqlalchemy import Column
21 from sqlalchemy import Integer
22 from sqlalchemy import String
24 from ryu.lib import netdevice
25 from ryu.lib import ip
26 from ryu.lib.packet import zebra
31 LOG = logging.getLogger(__name__)
33 # Default value for ethernet interface
36 | netdevice.IFF_BROADCAST
37 | netdevice.IFF_RUNNING
38 | netdevice.IFF_MULTICAST)
39 DEFAULT_ETH_MTU = 1500
42 class Interface(base.Base):
44 Interface table for Zebra protocol service.
46 The default value for each fields suppose "Loopback" interface.
48 ``ifindex``: Number of index.
50 ``ifname``: Name of this interface.
52 ``status``: A combination of flags
53 "ryu.lib.packet.zebra.ZEBRA_INTERFACE_*".
54 The default value shows "active" and "link-detect".
56 ``flags``: A combination of flags "ryu.lib.netdevice.IFF_*".
57 The default value show "up", "loopback" and "running".
59 ``metric``: Metric of this interface.
61 ``ifmtu``: IPv4 MTU of this interface.
63 ``ifmtu6``: IPv6 MTU of this interface.
65 ``bandwidth``: Bandwidth of this interface.
67 ``ll_type``: Link Layer Type.
68 One of "ryu.lib.packet.zebra.ZEBRA_LLT_*" types.
70 ``hw_addr``: Hardware address of this interface (mostly, MAC address).
72 ``inet``: List of IPv4 addresses separated by a comma.
73 (e.g., "192.168.1.100/24,192.168.2.100/24)".
75 ``inet6``: List of IPv6 addresses separated by a comma.
77 __tablename__ = 'interface'
79 ifindex = Column(Integer, primary_key=True)
80 ifname = Column(String, default="lo")
84 zebra.ZEBRA_INTERFACE_ACTIVE
85 | zebra.ZEBRA_INTERFACE_LINKDETECTION))
90 | netdevice.IFF_LOOPBACK
91 | netdevice.IFF_RUNNING))
92 metric = Column(Integer, default=1)
93 ifmtu = Column(Integer, default=0x10000)
94 ifmtu6 = Column(Integer, default=0x10000)
95 bandwidth = Column(Integer, default=0)
96 ll_type = Column(Integer, default=zebra.ZEBRA_LLT_ETHER)
97 hw_addr = Column(String, default='00:00:00:00:00:00')
98 # Note: Only the PostgreSQL backend has support sqlalchemy.ARRAY,
99 # we use the comma separated string as array instead.
100 inet = Column(String, default='')
101 inet6 = Column(String, default='')
105 def ip_link_show(session, **kwargs):
107 Returns a first interface record matching the given filtering rules.
109 The arguments for "kwargs" is the same with Interface class.
111 :param session: Session instance connecting to database.
112 :param kwargs: Filtering rules to query.
113 :return: An instance of Interface record.
115 return session.query(Interface).filter_by(**kwargs).first()
119 def ip_link_show_all(session, **kwargs):
121 Returns all interface records matching the given filtering rules.
123 The arguments for "kwargs" is the same with Interface class.
125 :param session: Session instance connecting to database.
126 :param kwargs: Filtering rules to query.
127 :return: A list of Interface records.
129 return session.query(Interface).filter_by(**kwargs).all()
133 def ip_link_add(session, name, type_='loopback', lladdr='00:00:00:00:00:00'):
135 Adds an interface record into Zebra protocol service database.
137 The arguments are similar to "ip link add" command of iproute2.
139 :param session: Session instance connecting to database.
140 :param name: Name of interface.
141 :param type_: Type of interface. 'loopback' or 'ethernet'.
142 :param lladdr: Link layer address. Mostly MAC address.
143 :return: Instance of added record or already existing record.
145 intf = ip_link_show(session, ifname=name)
147 LOG.debug('Interface "%s" already exists: %s', intf.ifname, intf)
150 if type_ == 'ethernet':
153 flags=DEFAULT_ETH_FLAGS,
154 ifmtu=DEFAULT_ETH_MTU,
155 ifmtu6=DEFAULT_ETH_MTU,
157 else: # type_ == 'loopback':
169 def ip_link_delete(session, name):
171 Deletes an interface record from Zebra protocol service database.
173 The arguments are similar to "ip link delete" command of iproute2.
175 :param session: Session instance connecting to database.
176 :param name: Name of interface.
177 :return: Name of interface which was deleted. None if failed.
179 intf = ip_link_show(session, ifname=name)
181 LOG.debug('Interface "%s" does not exist', name)
189 # Currently, functions corresponding to "ip link show" and "ip address show"
190 # have the same implementation.
191 ip_address_show = ip_link_show
192 ip_address_show_all = ip_link_show_all
196 def ip_address_add(session, ifname, ifaddr):
198 Adds an IP address to interface record identified with the given "ifname".
200 The arguments are similar to "ip address add" command of iproute2.
202 :param session: Session instance connecting to database.
203 :param ifname: Name of interface.
204 :param ifaddr: IPv4 or IPv6 address.
205 :return: Instance of record or "None" if failed.
207 def _append_inet_addr(intf_inet, addr):
208 addr_list = intf_inet.split(',')
209 if addr in addr_list:
211 'Interface "%s" has already "ifaddr": %s',
215 addr_list.append(addr)
216 return ','.join(addr_list)
218 intf = ip_link_show(session, ifname=ifname)
220 LOG.debug('Interface "%s" does not exist', ifname)
223 if ip.valid_ipv4(ifaddr):
224 intf.inet = _append_inet_addr(intf.inet, ifaddr)
225 elif ip.valid_ipv6(ifaddr):
226 intf.inet6 = _append_inet_addr(intf.inet6, ifaddr)
228 LOG.debug('Invalid IP address for "ifaddr": %s', ifaddr)
235 def ip_address_delete(session, ifname, ifaddr):
237 Deletes an IP address from interface record identified with the given
240 The arguments are similar to "ip address delete" command of iproute2.
242 :param session: Session instance connecting to database.
243 :param ifname: Name of interface.
244 :param ifaddr: IPv4 or IPv6 address.
245 :return: Instance of record or "None" if failed.
247 def _remove_inet_addr(intf_inet, addr):
248 addr_list = intf_inet.split(',')
249 if addr not in addr_list:
251 'Interface "%s" does not have "ifaddr": %s',
255 addr_list.remove(addr)
256 return ','.join(addr_list)
258 intf = ip_link_show(session, ifname=ifname)
260 LOG.debug('Interface "%s" does not exist', ifname)
263 if ip.valid_ipv4(ifaddr):
264 intf.inet = _remove_inet_addr(intf.inet, ifaddr)
265 elif ip.valid_ipv6(ifaddr):
266 intf.inet6 = _remove_inet_addr(intf.inet6, ifaddr)
268 LOG.debug('Invalid IP address for "ifaddr": %s', ifaddr)