]>
Commit | Line | Data |
---|---|---|
1 | #!/usr/bin/env python | |
2 | # | |
3 | # Copyright 2014 Cumulus Networks, Inc. All rights reserved. | |
4 | # | |
5 | # Author: Roopa Prabhu, roopa@cumulusnetworks.com | |
6 | # | |
7 | # | |
8 | ||
9 | from os import getpid | |
10 | from socket import AF_UNSPEC | |
11 | from socket import AF_BRIDGE | |
12 | from iff import IFF_UP | |
13 | from rtnetlink import * | |
14 | import os | |
15 | import ifupdownmain | |
16 | ||
17 | class rtnetlinkApi(RtNetlink): | |
18 | ||
19 | bind_done = False | |
20 | ||
21 | def __init__(self, pid): | |
22 | RtNetlink.__init__(self, pid) | |
23 | self.logger = logging.getLogger('ifupdown.' + | |
24 | self.__class__.__name__) | |
25 | self.bind(0, None) | |
26 | self.bind_done = True | |
27 | self.ifindexmap = {} | |
28 | ||
29 | def do_bind(self): | |
30 | if self.bind_done: | |
31 | return True | |
32 | self.bind(0, None) | |
33 | self.bind_done = True | |
34 | ||
35 | def get_ifindex(self, ifname): | |
36 | ifindex = self.ifindexmap.get(ifname) | |
37 | if not ifindex: | |
38 | with open('/sys/class/net/%s/ifindex' %ifname, 'r') as f: | |
39 | ifindex = int(f.read()) | |
40 | self.ifindexmap[ifname] = ifindex | |
41 | return ifindex | |
42 | ||
43 | def create_vlan(self, link, ifname, vlanid): | |
44 | self.logger.info('rtnetlink: creating vlan interface %s' %ifname) | |
45 | if ifupdownmain.ifupdownFlags.DRYRUN: | |
46 | return | |
47 | try: | |
48 | ifindex = self.get_ifindex(link) | |
49 | except Exception, e: | |
50 | raise Exception('cannot determine ifindex for link %s (%s)' | |
51 | %(link, str(e))) | |
52 | ||
53 | ifm = Ifinfomsg(AF_UNSPEC) | |
54 | rtas = {IFLA_IFNAME: ifname, | |
55 | IFLA_LINK : ifindex, | |
56 | IFLA_LINKINFO : { | |
57 | IFLA_INFO_KIND : 'vlan', | |
58 | IFLA_INFO_DATA : { | |
59 | IFLA_VLAN_ID : vlanid, | |
60 | } | |
61 | } | |
62 | } | |
63 | token = self.request(RTM_NEWLINK, | |
64 | NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas) | |
65 | self.process_wait([token]) | |
66 | ||
67 | def create_macvlan(self, ifname, link, mode='private'): | |
68 | self.logger.info('rtnetlink: creating macvlan interface %s' %ifname) | |
69 | if ifupdownmain.ifupdownFlags.DRYRUN: | |
70 | return | |
71 | try: | |
72 | ifindex = self.get_ifindex(link) | |
73 | except Exception, e: | |
74 | raise Exception('cannot determine ifindex for link %s (%s)' | |
75 | %(link, str(e))) | |
76 | ||
77 | ifm = Ifinfomsg(AF_UNSPEC) | |
78 | rtas = {IFLA_IFNAME: ifname, | |
79 | IFLA_LINK : ifindex, | |
80 | IFLA_LINKINFO : { | |
81 | IFLA_INFO_KIND : 'macvlan', | |
82 | IFLA_INFO_DATA : { | |
83 | IFLA_MACVLAN_MODE : MACVLAN_MODE_PRIVATE, | |
84 | } | |
85 | } | |
86 | } | |
87 | token = self.request(RTM_NEWLINK, NLM_F_CREATE | NLM_F_REQUEST | | |
88 | NLM_F_ACK, ifm, rtas) | |
89 | self.process_wait([token]) | |
90 | ||
91 | def link_set(self, ifname, state): | |
92 | flags = 0 | |
93 | self.logger.info('rtnetlink: setting link %s %s' %(ifname, state)) | |
94 | if ifupdownmain.ifupdownFlags.DRYRUN: | |
95 | return | |
96 | ||
97 | if state == "up": | |
98 | flags |= IFF_UP | |
99 | else: | |
100 | flags &= ~IFF_UP | |
101 | ||
102 | ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags) | |
103 | rtas = {IFLA_IFNAME: ifname} | |
104 | ||
105 | token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas) | |
106 | self.process_wait([token]) | |
107 | ||
108 | def link_set_hwaddress(self, ifname, hwaddress): | |
109 | flags = 0 | |
110 | self.logger.info('rtnetlink: setting link hwaddress %s %s' %(ifname, hwaddress)) | |
111 | if ifupdownmain.ifupdownFlags.DRYRUN: | |
112 | return | |
113 | ||
114 | flags &= ~IFF_UP | |
115 | ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP) | |
116 | rtas = {IFLA_IFNAME: ifname, | |
117 | IFLA_ADDRESS : str(bytearray([int(a,16) for a in hwaddress.split(':')]))} | |
118 | ||
119 | self.logger.info(rtas) | |
120 | ||
121 | token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas) | |
122 | self.process_wait([token]) | |
123 | ||
124 | def addr_add(self, ifname, address, broadcast=None, peer=None, scope=None, | |
125 | preferred_lifetime=None): | |
126 | self.logger.info('rtnetlink: setting address') | |
127 | if ifupdownmain.ifupdownFlags.DRYRUN: | |
128 | return | |
129 | ||
130 | try: | |
131 | ifindex = self.get_ifindex(link) | |
132 | except Exception, e: | |
133 | raise Exception('cannot determine ifindex for link %s (%s)' | |
134 | %(link, str(e))) | |
135 | ifa_scope = RT_SCOPE_ | |
136 | if scope: | |
137 | if scope == "universe": | |
138 | ifa_scope = RT_SCOPE_UNIVERSE | |
139 | elif scope == "site": | |
140 | ifa_scope = RT_SCOPE_SITE | |
141 | elif scope == "link": | |
142 | ifa_scope = RT_SCOPE_LINK | |
143 | elif scope == "host": | |
144 | ifa_scope = RT_SCOPE_HOST | |
145 | elif scope == "nowhere": | |
146 | ifa_scope = RT_SCOPE_NOWHERE | |
147 | rtas = {IFLA_ADDRESS: ifname} | |
148 | ||
149 | ifa = Ifaddrmsg(AF_UNSPEC, ifa_scope=ifa_scope, ifa_index=ifindex) | |
150 | ||
151 | token = self.request(RTM_NEWADDR, NLM_F_REQUEST | NLM_F_ACK, ifa, rtas) | |
152 | self.process_wait([token]) | |
153 | ||
154 | def link_set_many(self, ifname, ifattrs): | |
155 | _ifattr_to_rta_map = {'dev' : IFLA_NAME, | |
156 | 'address' : IFLA_ADDRESS, | |
157 | 'broadcast' : IFLA_BROADCAST, | |
158 | 'mtu' : IFLA_MTU, | |
159 | 'master' : IFLA_MASTER} | |
160 | flags = 0 | |
161 | ifi_change = IFF_UP | |
162 | rtas = {} | |
163 | self.logger.info('rtnetlink: setting link %s %s' %(ifname, state)) | |
164 | if ifupdownmain.ifupdownFlags.DRYRUN: | |
165 | return | |
166 | if not ifattrs: | |
167 | return | |
168 | state = ifattrs.get('state') | |
169 | if state == 'up': | |
170 | flags |= IFF_UP | |
171 | elif state == 'down': | |
172 | flags &= ~IFF_UP | |
173 | else: | |
174 | ifi_change = 0 | |
175 | ||
176 | if ifi_change: | |
177 | ifm = Ifinfomsg(AF_UNSPEC, ifi_change=IFF_UP, ifi_flags=flags) | |
178 | else: | |
179 | ifm = Ifinfomsg(AF_UNSPEC) | |
180 | ||
181 | for attr, attrval in ifattrs.items(): | |
182 | rta_attr = _ifattr_to_rta_map.get(attr) | |
183 | if rta_attr: | |
184 | if attr == 'hwaddress': | |
185 | rtas[rta_attr] = str(bytearray([int(a,16) for a in attrval.split(':')])) | |
186 | else: | |
187 | rtas[rta_attr] = attrval | |
188 | ||
189 | token = self.request(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_ACK, ifm, rtas) | |
190 | self.process_wait([token]) | |
191 | ||
192 | def bridge_vlan(self, add=True, vid=None, dev=None, pvid=False, | |
193 | untagged=False, master=True): | |
194 | flags = 0 | |
195 | vflags = 0 | |
196 | if not vid or not dev: | |
197 | return | |
198 | self.logger.info('rtnetlink: bridge vlan add vid %s %s %s dev %s %s' | |
199 | %(vid, 'untagged' if untagged else '', | |
200 | 'pvid' if pvid else '', dev, | |
201 | 'self' if self else '')) | |
202 | if ifupdownmain.ifupdownFlags.DRYRUN: | |
203 | return | |
204 | try: | |
205 | ifindex = self.get_ifindex(dev) | |
206 | except Exception, e: | |
207 | raise Exception('cannot determine ifindex for dev %s (%s)' | |
208 | %(dev, str(e))) | |
209 | if not master: | |
210 | flags = BRIDGE_FLAGS_SELF | |
211 | ||
212 | if pvid: | |
213 | vflags = BRIDGE_VLAN_INFO_PVID | |
214 | vflags |= BRIDGE_VLAN_INFO_UNTAGGED | |
215 | elif untagged: | |
216 | vflags |= BRIDGE_VLAN_INFO_UNTAGGED | |
217 | ||
218 | ifm = Ifinfomsg(AF_BRIDGE, ifi_index=ifindex) | |
219 | rtas = {IFLA_AF_SPEC: { | |
220 | IFLA_BRIDGE_FLAGS: flags, | |
221 | IFLA_BRIDGE_VLAN_INFO : BridgeVlanInfo(vflags, int(vid), int(vid)) | |
222 | } | |
223 | } | |
224 | if add: | |
225 | token = self.request(RTM_SETLINK, | |
226 | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas) | |
227 | else: | |
228 | token = self.request(RTM_DELLINK, | |
229 | NLM_F_REQUEST | NLM_F_ACK, ifm, rtas) | |
230 | self.process_wait([token]) | |
231 | ||
232 | def bridge_vlan_many(self, add=True, vids=[], dev=None, pvid=False, | |
233 | untagged=False, master=True): | |
234 | for v in vids: | |
235 | self.bridge_vlan_add(add, v, dev, ispvid, isuntagged, master) | |
236 | ||
237 | rtnl_api = rtnetlinkApi(os.getpid()) |