1# Copyright (C) 2013 Nippon Telegraph and Telephone Corporation. 2# Copyright (C) 2013 Isaku Yamahata <yamahata at private email ne jp> 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 13# implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import contextlib 18import socket 19import struct 20 21from ryu.controller import handler 22from ryu.ofproto import ether 23from ryu.ofproto import inet 24from ryu.lib import addrconv 25from ryu.lib import hub 26from ryu.lib.packet import arp 27from ryu.lib.packet import vrrp 28from ryu.services.protocols.vrrp import monitor 29from ryu.services.protocols.vrrp import event as vrrp_event 30from ryu.services.protocols.vrrp import utils 31 32 33# Those are not defined in socket module 34SS_MAXSIZE = 128 35MCAST_JOIN_GROUP = 42 36MCAST_LEAVE_GROUP = 45 37PACKET_ADD_MEMBERSHIP = 1 38PACKET_DROP_MEMBERSHIP = 2 39PACKET_MR_MULTICAST = 0 40SOL_PACKET = 263 41 42 43def if_nametoindex(ifname): 44 filename = '/sys/class/net/' + ifname + '/ifindex' 45 with contextlib.closing(open(filename)) as f: 46 for line in f: 47 return int(line) 48 49 50@monitor.VRRPInterfaceMonitor.register(vrrp_event.VRRPInterfaceNetworkDevice) 51class VRRPInterfaceMonitorNetworkDevice(monitor.VRRPInterfaceMonitor): 52 """ 53 This module uses raw socket so that privilege(CAP_NET_ADMIN capability) 54 is required. 55 """ 56 57 def __init__(self, *args, **kwargs): 58 super(VRRPInterfaceMonitorNetworkDevice, self).__init__(*args, 59 **kwargs) 60 self.__is_active = True 61 config = self.config 62 if config.is_ipv6: 63 family = socket.AF_INET6 64 ether_type = ether.ETH_TYPE_IPV6 65 mac_address = vrrp.vrrp_ipv6_src_mac_address(config.vrid) 66 else: 67 family = socket.AF_INET 68 ether_type = ether.ETH_TYPE_IP 69 mac_address = vrrp.vrrp_ipv4_src_mac_address(config.vrid) 70 # socket module doesn't define IPPROTO_VRRP 71 self.ip_socket = socket.socket(family, socket.SOCK_RAW, 72 inet.IPPROTO_VRRP) 73 74 self.packet_socket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, 75 socket.htons(ether_type)) 76 self.packet_socket.bind((self.interface.device_name, ether_type, 77 socket.PACKET_MULTICAST, 78 arp.ARP_HW_TYPE_ETHERNET, 79 addrconv.mac.text_to_bin(mac_address))) 80 81 self.ifindex = if_nametoindex(self.interface.device_name) 82 83 def start(self): 84 # discard received packets before joining multicast membership 85 packet_socket = self.packet_socket 86 packet_socket.setblocking(0) 87 with hub.Timeout(0.1, False): 88 while True: 89 try: 90 packet_socket.recv(1500) 91 except socket.error: 92 break 93 packet_socket.setblocking(1) 94 95 self._join_multicast_membership(True) 96 self._join_vrrp_group(True) 97 super(VRRPInterfaceMonitorNetworkDevice, self).start() 98 self.threads.append(hub.spawn(self._recv_loop)) 99 100 def stop(self): 101 self.__is_active = False 102 super(VRRPInterfaceMonitorNetworkDevice, self).stop() 103 104 # we assume that the structures in the following two functions for 105 # multicast are aligned in the same way on all the archtectures. 106 def _join_multicast_membership(self, join_leave): 107 config = self.config 108 if config.is_ipv6: 109 mac_address = vrrp.vrrp_ipv6_src_mac_address(config.vrid) 110 else: 111 mac_address = vrrp.vrrp_ipv4_src_mac_address(config.vrid) 112 if join_leave: 113 add_drop = PACKET_ADD_MEMBERSHIP 114 else: 115 add_drop = PACKET_DROP_MEMBERSHIP 116 # struct packet_mreq { 117 # int mr_ifindex; 118 # unsigned short mr_type; 119 # unsigned short mr_alen; 120 # unsigned char mr_mr_address[8]; 121 # }; 122 packet_mreq = struct.pack('IHH8s', self.ifindex, 123 PACKET_MR_MULTICAST, 6, 124 addrconv.mac.text_to_bin(mac_address)) 125 self.packet_socket.setsockopt(SOL_PACKET, add_drop, packet_mreq) 126 127 def _join_vrrp_group(self, join_leave): 128 if join_leave: 129 join_leave = MCAST_JOIN_GROUP 130 else: 131 join_leave = MCAST_LEAVE_GROUP 132 133 # struct group_req { 134 # __u32 gr_interface; /* interface index */ 135 # struct __kernel_sockaddr_storage gr_group; /* group address */ 136 # }; 137 group_req = struct.pack('I', self.ifindex) 138 # padding to gr_group. This is environment dependent 139 group_req += b'\x00' * (struct.calcsize('P') - struct.calcsize('I')) 140 if self.config.is_ipv6: 141 # struct sockaddr_in6 { 142 # sa_family_t sin6_family; /* AF_INET6 */ 143 # in_port_t sin6_port; /* port number */ 144 # uint32_t sin6_flowinfo; /* IPv6 flow information */ 145 # struct in6_addr sin6_addr; /* IPv6 address */ 146 # uint32_t sin6_scope_id; /* Scope ID (new in 2.4) */ 147 # }; 148 # struct in6_addr { 149 # unsigned char s6_addr[16]; /* IPv6 address */ 150 # }; 151 family = socket.IPPROTO_IPV6 152 sockaddr = struct.pack('H', socket.AF_INET6) 153 sockaddr += struct.pack('!H', 0) 154 sockaddr += struct.pack('!I', 0) 155 sockaddr += addrconv.ipv6.text_to_bin(vrrp.VRRP_IPV6_DST_ADDRESS) 156 sockaddr += struct.pack('I', 0) 157 else: 158 # #define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ 159 # struct sockaddr_in { 160 # __kernel_sa_family_t sin_family; /* Address family */ 161 # __be16 sin_port; /* Port number */ 162 # struct in_addr sin_addr; /* Internet address */ 163 # /* Pad to size of `struct sockaddr'. */ 164 # unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - 165 # sizeof(unsigned short int) - sizeof(struct in_addr)]; 166 # }; 167 # struct in_addr { 168 # __be32 s_addr; 169 # }; 170 family = socket.IPPROTO_IP 171 sockaddr = struct.pack('H', socket.AF_INET) 172 sockaddr += struct.pack('!H', 0) 173 sockaddr += addrconv.ipv4.text_to_bin(vrrp.VRRP_IPV4_DST_ADDRESS) 174 175 sockaddr += b'\x00' * (SS_MAXSIZE - len(sockaddr)) 176 group_req += sockaddr 177 178 self.ip_socket.setsockopt(family, join_leave, group_req) 179 return 180 181 def _recv_loop(self): 182 packet_socket = self.packet_socket 183 packet_socket.settimeout(1.3) # to check activeness periodically 184 try: 185 while self.__is_active: 186 try: 187 buf = packet_socket.recv(128) 188 except socket.timeout: 189 self.logger.debug('timeout') 190 continue 191 except: 192 self.logger.error('recv failed') 193 continue 194 if len(buf) == 0: 195 self.__is_active = False 196 break 197 198 self.logger.debug('recv buf') 199 self._send_vrrp_packet_received(buf) 200 finally: 201 self._join_vrrp_group(False) 202 self._join_multicast_membership(False) 203 204 @handler.set_ev_handler(vrrp_event.EventVRRPTransmitRequest) 205 def vrrp_transmit_request_handler(self, ev): 206 self.logger.debug('send') 207 try: 208 self.packet_socket.sendto(ev.data, 209 (self.interface.device_name, 0)) 210 except: 211 self.logger.error('send failed') 212 213 def _initialize(self): 214 # nothing 215 pass 216 217 def _shutdown(self): 218 self.__is_active = False 219