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
21 from sqlalchemy import Column
22 from sqlalchemy import Boolean
23 from sqlalchemy import Integer
24 from sqlalchemy import String
26 from ryu.lib import ip
27 from ryu.lib.packet import safi as packet_safi
28 from ryu.lib.packet import zebra
31 from . import interface
34 LOG = logging.getLogger(__name__)
37 class Route(base.Base):
39 Route table (like routing table) for Zebra protocol service.
41 ``id``: (Primary Key) ID of this route.
43 ``family``: Address Family, not AFI (Address Family Identifiers).
44 Mostly, "socket.AF_INET" or "socket.AF_INET6".
46 ``safi``: Subsequent Address Family Identifiers.
48 ``destination``: Destination prefix of this route.
50 ``gateway``: Next hop address of this route.
51 The default is "" (empty string).
53 ``ifindex``: Index of interface to forward packets.
55 ``source``: Source IP address of this route, which should be an
56 address assigned to the local interface.
58 ``route_type``: Route Type of this route.
59 This type shows which daemon (or kernel) generated this route.
61 ``is_selected``: Whether this route is selected for "destination".
63 __tablename__ = 'route'
65 id = Column(Integer, primary_key=True)
66 family = Column(Integer, default=socket.AF_INET)
67 safi = Column(Integer, default=packet_safi.UNICAST)
68 destination = Column(String, default='0.0.0.0/0')
69 gateway = Column(String, default='')
70 ifindex = Column(Integer, default=0)
71 source = Column(String, default='')
72 route_type = Column(Integer, default=zebra.ZEBRA_ROUTE_KERNEL)
73 is_selected = Column(Boolean, default=False)
77 def ip_route_show(session, destination, device, **kwargs):
79 Returns a selected route record matching the given filtering rules.
81 The arguments are similar to "ip route showdump" command of iproute2.
83 :param session: Session instance connecting to database.
84 :param destination: Destination prefix.
85 :param device: Source device.
86 :param kwargs: Filtering rules to query.
87 :return: Instance of route record or "None" if failed.
89 intf = interface.ip_link_show(session, ifname=device)
91 LOG.debug('Interface "%s" does not exist', device)
94 return session.query(Route).filter_by(
95 destination=destination, ifindex=intf.ifindex, **kwargs).first()
99 def ip_route_show_all(session, **kwargs):
101 Returns a selected route record matching the given filtering rules.
103 The arguments are similar to "ip route showdump" command of iproute2.
105 If "is_selected=True", disables the existing selected route for the
108 :param session: Session instance connecting to database.
109 :param kwargs: Filtering rules to query.
110 :return: A list of route records.
112 return session.query(Route).filter_by(**kwargs).all()
116 def ip_route_add(session, destination, device=None, gateway='', source='',
117 ifindex=0, route_type=zebra.ZEBRA_ROUTE_KERNEL,
120 Adds a route record into Zebra protocol service database.
122 The arguments are similar to "ip route add" command of iproute2.
124 If "is_selected=True", disables the existing selected route for the
127 :param session: Session instance connecting to database.
128 :param destination: Destination prefix.
129 :param device: Source device.
130 :param gateway: Gateway IP address.
131 :param source: Source IP address.
132 :param ifindex: Index of source device.
133 :param route_type: Route type of daemon (or kernel).
134 :param is_selected: If select the given route as "in use" or not.
135 :return: Instance of record or "None" if failed.
138 intf = interface.ip_link_show(session, ifname=device)
140 LOG.debug('Interface "%s" does not exist', device)
142 ifindex = ifindex or intf.ifindex
144 route = ip_route_show(session, destination=destination, device=device)
147 'Route to "%s" already exists on "%s" device',
151 dest_addr, dest_prefix_num = destination.split('/')
152 dest_prefix_num = int(dest_prefix_num)
153 if ip.valid_ipv4(dest_addr) and 0 <= dest_prefix_num <= 32:
154 family = socket.AF_INET
155 elif ip.valid_ipv6(dest_addr) and 0 <= dest_prefix_num <= 128:
156 family = socket.AF_INET6
158 LOG.debug('Invalid IP address for "prefix": %s', destination)
160 safi = packet_safi.UNICAST
163 old_routes = ip_route_show_all(
164 session, destination=destination, is_selected=True)
165 for old_route in old_routes:
167 LOG.debug('Set existing route to unselected: %s', old_route)
168 old_route.is_selected = False
173 destination=destination,
177 route_type=route_type,
178 is_selected=is_selected)
180 session.add(new_route)
186 def ip_route_delete(session, destination, **kwargs):
188 Deletes route record(s) from Zebra protocol service database.
190 The arguments are similar to "ip route delete" command of iproute2.
192 :param session: Session instance connecting to database.
193 :param destination: Destination prefix.
194 :param kwargs: Filtering rules to query.
195 :return: Records which are deleted.
197 routes = ip_route_show_all(session, destination=destination, **kwargs)
199 session.delete(route)