OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
freebsd/pkt0_interface.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <assert.h>
9 #include <sys/ioctl.h>
10 #include <sys/socket.h>
11 
12 #include <net/if.h>
13 #include <sys/sockio.h>
14 #include <ifaddrs.h>
15 #include <net/ethernet.h>
16 
17 #include "base/logging.h"
18 #include "cmn/agent_cmn.h"
19 #include "sandesh/sandesh_trace.h"
20 #include "pkt/pkt_types.h"
21 #include "pkt/pkt_init.h"
22 #include "../pkt0_interface.h"
23 
24 #define TAP_TRACE(obj, ...) \
25 do { \
26  Tap##obj::TraceMsg(PacketTraceBuf, __FILE__, __LINE__, __VA_ARGS__); \
27 } while (false) \
28 
29 
31 static bool InterfaceExists(std::string if_name) {
32  struct ifaddrs *ifaddrs, *ifa;
33 
34  if (getifaddrs(&ifaddrs) < 0)
35  return false;
36 
37  for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
38  if (ifa->ifa_addr && strcmp(ifa->ifa_name, if_name.c_str()) == 0) {
39  freeifaddrs(ifaddrs);
40  return true;
41  }
42  }
43 
44  freeifaddrs(ifaddrs);
45  return false;
46 }
47 
49  unsigned int flags;
51 
52  // Create a socket for the TAP device
53  int socket_fd = socket(AF_LOCAL, SOCK_DGRAM, 0);
54  if (socket_fd < 0) {
55  LOG(ERROR, "Error creating socket for a TAP device, errno: " <<
56  errno << ": " << strerror(errno));
57  assert(0);
58  }
59 
60  // XXX: If interface of the name name_ exists, delete it first. It is
61  // necessary on FreeBSD as we have to create a new one to obtain path
62  // to the device file (/dev/tapX) used for receiving/sending the actual
63  // data. Should find a way to attach to the existing interface instead.
64  struct ifreq ifr;
65  if (InterfaceExists(name_)) {
66  memset(&ifr, 0, sizeof(ifr));
67  strncpy(ifr.ifr_name, name_.c_str(), IF_NAMESIZE);
68  if (ioctl(socket_fd, SIOCIFDESTROY, &ifr) < 0) {
69  LOG(ERROR, "Error destroying the existing " << name_ <<
70  " device, errno: " << errno << ": " << strerror(errno));
71  assert(0);
72  }
73  }
74 
75  // Create a device with 'tap' name as required by the FreeBSD. Later it
76  // can be renamed to pkt0 for example.
77  memset(&ifr, 0, sizeof(ifr));
78  strncpy(ifr.ifr_name, "tap", IF_NAMESIZE);
79  if (ioctl(socket_fd, SIOCIFCREATE2, &ifr) < 0) {
80  LOG(ERROR, "Error creating the TAP device, errno: " << errno <<
81  ": " << strerror(errno));
82  assert(0);
83  }
84 
85  // Set interface name and save the /dev/tapX path for later use
86  std::string dev_name = std::string("/dev/") +
87  std::string(ifr.ifr_name);
88  ifr.ifr_data = (caddr_t) name_.c_str();
89  if (ioctl(socket_fd, SIOCSIFNAME, &ifr) < 0) {
90  LOG(ERROR, "Can not change interface name to " << name_ <<
91  "with error: " << errno << ": " << strerror(errno));
92  assert(0);
93  }
94 
95  // Save mac address
96  memset(&ifr, 0, sizeof(ifr));
97  strncpy(ifr.ifr_name, name_.c_str(), IF_NAMESIZE);
98  if (ioctl(socket_fd, SIOCGIFADDR, &ifr)< 0) {
99  LOG(ERROR, "Can not get mac address of the TAP device, errno: "
100  << errno << ": " << strerror(errno));
101  assert(0);
102  }
103  memcpy(mac_address_, ifr.ifr_addr.sa_data, ETHER_ADDR_LEN);
104  close(socket_fd);
105 
106  // Set the interface up
107  socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
108  if (socket_fd < 0) {
109  LOG(ERROR, "Can not open socket for " << name_ << ", errno: " <<
110  errno << ": " << strerror(errno));
111  assert(0);
112  }
113  memset(&ifr, 0, sizeof(ifr));
114  strncpy(ifr.ifr_name, name_.c_str(), IF_NAMESIZE);
115  if (ioctl(socket_fd, SIOCGIFFLAGS, &ifr) < 0) {
116  LOG(ERROR, "Can not get socket flags, errno: " << errno << ": " <<
117  strerror(errno));
118  assert(0);
119  }
120 
121  flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
122  flags |= (IFF_UP|IFF_PPROMISC);
123  ifr.ifr_flags = flags & 0xffff;
124  ifr.ifr_flagshigh = flags >> 16;
125 
126  if (ioctl(socket_fd, SIOCSIFFLAGS, &ifr) < 0) {
127  LOG(ERROR, "Can not set socket flags, errno: " << errno << ": " <<
128  strerror(errno));
129  assert(0);
130  }
131  close(socket_fd);
132 
133  // Open a device file for the tap interface
134  tap_fd_ = open(dev_name.c_str(), O_RDWR);
135  if (tap_fd_ < 0) {
136  LOG(ERROR, "Can not open the device " << dev_name << " errno: "
137  << errno << ": " << strerror(errno));
138  assert(0);
139  }
140 
141  // We dont want the fd to be inherited by child process such as
142  // virsh etc... So, close tap fd on fork.
143  if (fcntl(tap_fd_, F_SETFD, FD_CLOEXEC) < 0) {
144  LOG(ERROR, "Packet Tap Error <" << errno << ": " <<
145  strerror(errno) << "> setting fcntl on " << name_ );
146  assert(0);
147  }
148 
149  boost::system::error_code ec;
150  input_.assign(tap_fd_, ec);
151  assert(!ec);
152 
154  AsyncRead();
155 }
156 
157 void Pkt0Interface::SendImpl(uint8_t *buff, uint16_t buff_len, const PacketBufferPtr &pkt,
158  buffer_list& buff_list) {
159  input_.async_write_some(buff_list,
160  boost::bind(&Pkt0Interface::WriteHandler, this,
161  boost::asio::placeholders::error,
162  boost::asio::placeholders::bytes_transferred, buff));
163 }
boost::shared_ptr< PacketBuffer > PacketBufferPtr
Definition: packet_buffer.h:18
void WriteHandler(const boost::system::error_code &error, std::size_t length, uint8_t *buff)
unsigned char mac_address_[ETHER_ADDR_LEN]
static bool InterfaceExists(std::string if_name)
PktHandler * pkt_handler() const
Agent * agent() const
Definition: pkt_handler.h:317
virtual void InitControlInterface()
std::string name_
boost::asio::posix::stream_descriptor input_
std::vector< boost::asio::const_buffer > buffer_list
void SendImpl(uint8_t *buff, uint16_t buff_len, const PacketBufferPtr &pkt, buffer_list &buff_list)
#define LOG(_Level, _Msg)
Definition: logging.h:33
void set_pkt_interface_name(const std::string &name)
Definition: agent.h:947
virtual void InitControlInterface()