1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 2 /* 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 as 5 * published by the Free Software Foundation; 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 * 16 * Author: Blake Hurd <naimorai@gmail.com> 17 */ 18 19 /** 20 * \defgroup openflow OpenFlow Switch Device 21 * This section documents the API of the ns-3 OpenFlow module. For a generic functional description, please refer to the ns-3 manual. 22 */ 23 24 #ifndef OPENFLOW_SWITCH_NET_DEVICE_H 25 #define OPENFLOW_SWITCH_NET_DEVICE_H 26 27 #include "ns3/simulator.h" 28 #include "ns3/log.h" 29 #include "ns3/mac48-address.h" 30 31 #include "ns3/ethernet-header.h" 32 #include "ns3/arp-header.h" 33 #include "ns3/tcp-header.h" 34 #include "ns3/udp-header.h" 35 36 #include "ns3/ipv4-l3-protocol.h" 37 #include "ns3/arp-l3-protocol.h" 38 39 #include "ns3/bridge-channel.h" 40 #include "ns3/node.h" 41 #include "ns3/enum.h" 42 #include "ns3/string.h" 43 #include "ns3/integer.h" 44 #include "ns3/uinteger.h" 45 46 #include <map> 47 #include <set> 48 49 #include "openflow-interface.h" 50 51 namespace ns3 { 52 53 /** 54 * \ingroup openflow 55 * \brief A net device that switches multiple LAN segments via an OpenFlow-compatible flow table 56 * 57 * The OpenFlowSwitchNetDevice object aggregates multiple netdevices as ports 58 * and acts like a switch. It implements OpenFlow-compatibility, 59 * according to the OpenFlow Switch Specification v0.8.9 60 * <www.openflowswitch.org/documents/openflow-spec-v0.8.9.pdf>. 61 * It implements a flow table that all received packets are run through. 62 * It implements a connection to a controller via a subclass of the Controller class, 63 * which can send messages to manipulate the flow table, thereby manipulating 64 * how the OpenFlow switch behaves. 65 * 66 * There are two controllers available in the original package. DropController 67 * builds a flow for each received packet to drop all packets it matches (this 68 * demonstrates the flow table's basic implementation), and the LearningController 69 * implements a "learning switch" algorithm (see 802.1D), where incoming unicast 70 * frames from one port may occasionally be forwarded throughout all other ports, 71 * but usually they are forwarded only to a single correct output port. 72 * 73 * \attention The Spanning Tree Protocol part of 802.1D is not 74 * implemented. Therefore, you have to be careful not to create 75 * bridging loops, or else the network will collapse. 76 * 77 * \attention Each NetDevice used must only be assigned a Mac Address, adding it 78 * to an Ipv4 or Ipv6 layer will cause an error. It also must support a SendFrom 79 * call. 80 */ 81 82 /** 83 * \ingroup openflow 84 * \brief A net device that switches multiple LAN segments via an OpenFlow-compatible flow table 85 */ 86 class OpenFlowSwitchNetDevice : public NetDevice 87 { 88 public: 89 /** 90 * Register this type. 91 * \return The TypeId. 92 */ 93 static TypeId GetTypeId (void); 94 95 /** 96 * \name Descriptive Data 97 * \brief OpenFlowSwitchNetDevice Description Data 98 * 99 * These four data describe the OpenFlowSwitchNetDevice as if it were 100 * a real OpenFlow switch. 101 * 102 * There is a type of stats request that OpenFlow switches are supposed 103 * to handle that returns the description of the OpenFlow switch. Currently 104 * manufactured by "The ns-3 team", software description is "Simulated 105 * OpenFlow Switch", and the other two are "N/A". 106 * @{ 107 */ 108 /** \returns The descriptive string. */ 109 static const char * GetManufacturerDescription (); 110 static const char * GetHardwareDescription (); 111 static const char * GetSoftwareDescription (); 112 static const char * GetSerialNumber (); 113 /**@}*/ 114 115 OpenFlowSwitchNetDevice (); 116 virtual ~OpenFlowSwitchNetDevice (); 117 118 /** 119 * \brief Set up the Switch's controller connection. 120 * 121 * \param c Pointer to a Controller. 122 */ 123 void SetController (Ptr<ofi::Controller> c); 124 125 /** 126 * \brief Add a 'port' to a switch device 127 * 128 * This method adds a new switch port to a OpenFlowSwitchNetDevice, so that 129 * the new switch port NetDevice becomes part of the switch and L2 130 * frames start being forwarded to/from this NetDevice. 131 * 132 * \note The netdevice that is being added as switch port must 133 * _not_ have an IP address. In order to add IP connectivity to a 134 * bridging node you must enable IP on the OpenFlowSwitchNetDevice itself, 135 * never on its port netdevices. 136 * 137 * \param switchPort The port to add. 138 * \return 0 if everything's ok, otherwise an error number. 139 * \sa #EXFULL 140 */ 141 int AddSwitchPort (Ptr<NetDevice> switchPort); 142 143 /** 144 * \brief Add a virtual port to a switch device 145 * 146 * The Ericsson OFSID has the concept of virtual ports and virtual 147 * port tables. These are implemented in the OpenFlowSwitchNetDevice, but 148 * don't have an understood use [perhaps it may have to do with 149 * MPLS integration]. 150 * 151 * \sa #EINVAL 152 * 153 * \param ovpm The data for adding a virtual port. 154 * \return 0 if everything's ok, otherwise an error number. 155 */ 156 int AddVPort (const ofp_vport_mod *ovpm); 157 158 /** 159 * \brief Stats callback is ready for a dump. 160 * 161 * Controllers have a callback system for status requests which calls this function. 162 * 163 * \param cb_ The callback data. 164 * \return 0 if everything's ok, otherwise an error number. 165 */ 166 int StatsDump (ofi::StatsDumpCallback *cb_); 167 168 /** 169 * \brief Stats callback is done. 170 * 171 * Controllers have a callback system for status requests which calls this function. 172 * 173 * \param cb_ The callback data. 174 */ 175 void StatsDone (ofi::StatsDumpCallback *cb_); 176 177 /** 178 * \brief Called from the OpenFlow Interface to output the Packet on either a Port or the Controller 179 * 180 * \param packet_uid Packet UID; used to fetch the packet and its metadata. 181 * \param in_port The index of the port the Packet was initially received on. 182 * \param max_len The maximum number of bytes the caller wants to be sent; a value of 0 indicates the entire packet should be sent. Used when outputting to controller. 183 * \param out_port The port we want to output on. 184 * \param ignore_no_fwd If true, Ports that are set to not forward are forced to forward. 185 */ 186 void DoOutput (uint32_t packet_uid, int in_port, size_t max_len, int out_port, bool ignore_no_fwd); 187 188 /** 189 * \brief The registered controller calls this method when sending a message to the switch. 190 * 191 * \param msg The message received from the controller. 192 * \param length Length of the message. 193 * \return 0 if everything's ok, otherwise an error number. 194 */ 195 int ForwardControlInput (const void *msg, size_t length); 196 197 /** 198 * \return The flow table chain. 199 */ 200 sw_chain* GetChain (); 201 202 /** 203 * \return Number of switch ports attached to this switch. 204 */ 205 uint32_t GetNSwitchPorts (void) const; 206 207 /** 208 * \param p The Port to get the index of. 209 * \return The index of the provided Port. 210 */ 211 int GetSwitchPortIndex (ofi::Port p); 212 213 /** 214 * \param n index of the Port. 215 * \return The Port. 216 */ 217 ofi::Port GetSwitchPort (uint32_t n) const; 218 219 /** 220 * \return The virtual port table. 221 */ 222 vport_table_t GetVPortTable (); 223 224 // From NetDevice 225 virtual void SetIfIndex (const uint32_t index); 226 virtual uint32_t GetIfIndex (void) const; 227 virtual Ptr<Channel> GetChannel (void) const; 228 virtual void SetAddress (Address address); 229 virtual Address GetAddress (void) const; 230 virtual bool SetMtu (const uint16_t mtu); 231 virtual uint16_t GetMtu (void) const; 232 virtual bool IsLinkUp (void) const; 233 virtual void AddLinkChangeCallback (Callback<void> callback); 234 virtual bool IsBroadcast (void) const; 235 virtual Address GetBroadcast (void) const; 236 virtual bool IsMulticast (void) const; 237 virtual Address GetMulticast (Ipv4Address multicastGroup) const; 238 virtual bool IsPointToPoint (void) const; 239 virtual bool IsBridge (void) const; 240 virtual bool Send (Ptr<Packet> packet, const Address& dest, uint16_t protocolNumber); 241 virtual bool SendFrom (Ptr<Packet> packet, const Address& source, const Address& dest, uint16_t protocolNumber); 242 virtual Ptr<Node> GetNode (void) const; 243 virtual void SetNode (Ptr<Node> node); 244 virtual bool NeedsArp (void) const; 245 virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); 246 virtual void SetPromiscReceiveCallback (NetDevice::PromiscReceiveCallback cb); 247 virtual bool SupportsSendFrom () const; 248 virtual Address GetMulticast (Ipv6Address addr) const; 249 250 protected: 251 virtual void DoDispose (void); 252 253 /** 254 * Called when a packet is received on one of the switch's ports. 255 * 256 * \param netdev The port the packet was received on. 257 * \param packet The Packet itself. 258 * \param protocol The protocol defining the Packet. 259 * \param src The source address of the Packet. 260 * \param dst The destination address of the Packet. 261 * \param PacketType Type of the packet. 262 */ 263 void ReceiveFromDevice (Ptr<NetDevice> netdev, Ptr<const Packet> packet, uint16_t protocol, const Address& src, const Address& dst, PacketType packetType); 264 265 /** 266 * Takes a packet and generates an OpenFlow buffer from it, loading the packet data as well as its headers. 267 * 268 * \param packet The packet. 269 * \param src The source address. 270 * \param dst The destination address. 271 * \param mtu The Maximum Transmission Unit. 272 * \param protocol The protocol defining the packet. 273 * \return The OpenFlow Buffer created from the packet. 274 */ 275 ofpbuf * BufferFromPacket (Ptr<const Packet> packet, Address src, Address dst, int mtu, uint16_t protocol); 276 277 private: 278 /** 279 * Add a flow. 280 * 281 * \sa #ENOMEM, #ENOBUFS, #ESRCH 282 * 283 * \param ofm The flow data to add. 284 * \return 0 if everything's ok, otherwise an error number. 285 */ 286 int AddFlow (const ofp_flow_mod *ofm); 287 288 /** 289 * Modify a flow. 290 * 291 * \param ofm The flow data to modify. 292 * \return 0 if everything's ok, otherwise an error number. 293 */ 294 int ModFlow (const ofp_flow_mod *ofm); 295 296 /** 297 * Send packets out all the ports except the originating one 298 * 299 * \param packet_uid Packet UID; used to fetch the packet and its metadata. 300 * \param in_port The index of the port the Packet was initially received on. This port doesn't forward when flooding. 301 * \param flood If true, don't send out on the ports with flooding disabled. 302 * \return 0 if everything's ok, otherwise an error number. 303 */ 304 int OutputAll (uint32_t packet_uid, int in_port, bool flood); 305 306 /** 307 * Sends a copy of the Packet over the provided output port 308 * 309 * \param packet_uid Packet UID; used to fetch the packet and its metadata. 310 */ 311 void OutputPacket (uint32_t packet_uid, int out_port); 312 313 /** 314 * Seeks to send out a Packet over the provided output port. This is called generically 315 * when we may or may not know the specific port we're outputting on. There are many 316 * pre-set types of port options besides a Port that's hooked to our OpenFlowSwitchNetDevice. 317 * For example, it could be outputting as a flood, or seeking to output to the controller. 318 * 319 * \param packet_uid Packet UID; used to fetch the packet and its metadata. 320 * \param in_port The index of the port the Packet was initially received on. 321 * \param out_port The port we want to output on. 322 * \param ignore_no_fwd If true, Ports that are set to not forward are forced to forward. 323 */ 324 void OutputPort (uint32_t packet_uid, int in_port, int out_port, bool ignore_no_fwd); 325 326 /** 327 * Sends a copy of the Packet to the controller. If the packet can be saved 328 * in an OpenFlow buffer, then only the first 'max_len' bytes of the packet 329 * are sent; otherwise, all of the packet is sent. 330 * 331 * \param packet_uid Packet UID; used to fetch the packet and its metadata. 332 * \param in_port The index of the port the Packet was initially received on. 333 * \param max_len The maximum number of bytes that the caller wants to be sent; a value of 0 indicates the entire packet should be sent. 334 * \param reason Why the packet is being sent. 335 */ 336 void OutputControl (uint32_t packet_uid, int in_port, size_t max_len, int reason); 337 338 /** 339 * If an error message happened during the controller's request, send it to the controller. 340 * 341 * \param type The type of error. 342 * \param code The error code. 343 * \param data The faulty data that lead to the error. 344 * \param len The length of the faulty data. 345 */ 346 void SendErrorMsg (uint16_t type, uint16_t code, const void *data, size_t len); 347 348 /** 349 * Send a reply about this OpenFlow switch's features to the controller. 350 * 351 * List of capabilities and actions to support are found in the specification 352 * <www.openflowswitch.org/documents/openflow-spec-v0.8.9.pdf>. 353 * 354 * Supported capabilities and actions are defined in the openflow interface. 355 * To recap, flow status, flow table status, port status, virtual port table 356 * status can all be requested. It can also transmit over multiple physical 357 * interfaces. 358 * 359 * It supports every action: outputting over a port, and all of the flow table 360 * manipulation actions: setting the 802.1q VLAN ID, the 802.1q priority, 361 * stripping the 802.1 header, setting the Ethernet source address and destination, 362 * setting the IP source address and destination, setting the TCP/UDP source address 363 * and destination, and setting the MPLS label and EXP bits. 364 * 365 * \attention Capabilities STP (Spanning Tree Protocol) and IP packet 366 * reassembly are not currently supported. 367 * 368 */ 369 void SendFeaturesReply (); 370 371 /** 372 * Send a reply to the controller that a specific flow has expired. 373 * 374 * \param flow The flow that expired. 375 * \param reason The reason for sending this expiration notification. 376 */ 377 void SendFlowExpired (sw_flow *flow, enum ofp_flow_expired_reason reason); 378 379 /** 380 * Send a reply about a Port's status to the controller. 381 * 382 * \param p The port to get status from. 383 * \param status The reason for sending this reply. 384 */ 385 void SendPortStatus (ofi::Port p, uint8_t status); 386 387 /** 388 * Send a reply about this OpenFlow switch's virtual port table features to the controller. 389 */ 390 void SendVPortTableFeatures (); 391 392 /** 393 * Send a message to the controller. This method is the key 394 * to communicating with the controller, it does the actual 395 * sending. The other Send methods call this one when they 396 * are ready to send a message. 397 * 398 * \param buffer Buffer of the message to send out. 399 * \return 0 if successful, otherwise an error number. 400 */ 401 int SendOpenflowBuffer (ofpbuf *buffer); 402 403 /** 404 * Run the packet through the flow table. Looks up in the flow table for a match. 405 * If it doesn't match, it forwards the packet to the registered controller, if the flag is set. 406 * 407 * \param packet_uid Packet UID; used to fetch the packet and its metadata. 408 * \param port The port this packet was received over. 409 * \param send_to_controller If set, sends to the controller if the packet isn't matched. 410 */ 411 void RunThroughFlowTable (uint32_t packet_uid, int port, bool send_to_controller = true); 412 413 /** 414 * Run the packet through the vport table. As with AddVPort, 415 * this doesn't have an understood use yet. 416 * 417 * \param packet_uid Packet UID; used to fetch the packet and its metadata. 418 * \param port The port this packet was received over. 419 * \param vport The virtual port this packet identifies itself by. 420 * \return 0 if everything's ok, otherwise an error number. 421 */ 422 int RunThroughVPortTable (uint32_t packet_uid, int port, uint32_t vport); 423 424 /** 425 * Called by RunThroughFlowTable on a scheduled delay 426 * to account for the flow table lookup overhead. 427 * 428 * \param key Matching key to look up in the flow table. 429 * \param buffer Buffer of the packet received. 430 * \param packet_uid Packet UID; used to fetch the packet and its metadata. 431 * \param port The port the packet was received over. 432 * \param send_to_controller 433 */ 434 void FlowTableLookup (sw_flow_key key, ofpbuf* buffer, uint32_t packet_uid, int port, bool send_to_controller); 435 436 /** 437 * Update the port status field of the switch port. 438 * A non-zero return value indicates some field has changed. 439 * 440 * \param p A reference to a Port; used to change its config and flag fields. 441 * \return true if the status of the Port is changed, false if unchanged (was already the right status). 442 */ 443 int UpdatePortStatus (ofi::Port& p); 444 445 /** 446 * Fill out a description of the switch port. 447 * 448 * \param p The port to get the description from. 449 * \param desc A pointer to the description message; used to fill the description message with the data from the port. 450 */ 451 void FillPortDesc (ofi::Port p, ofp_phy_port *desc); 452 453 /** 454 * Generates an OpenFlow reply message based on the type. 455 * 456 * \param openflow_len Length of the reply to make. 457 * \param type Type of reply message to make. 458 * \param bufferp Message buffer; used to make the reply. 459 * \return The OpenFlow reply message. 460 */ 461 void* MakeOpenflowReply (size_t openflow_len, uint8_t type, ofpbuf **bufferp); 462 463 /** 464 * \name Receive Methods 465 * 466 * Actions to do when a specific OpenFlow message/packet is received 467 * 468 * @{ 469 */ 470 /** 471 * \param msg The OpenFlow message received. 472 * \return 0 if everything's ok, otherwise an error number. 473 */ 474 int ReceiveFeaturesRequest (const void *msg); 475 int ReceiveGetConfigRequest (const void *msg); 476 int ReceiveSetConfig (const void *msg); 477 int ReceivePacketOut (const void *msg); 478 int ReceiveFlow (const void *msg); 479 int ReceivePortMod (const void *msg); 480 int ReceiveStatsRequest (const void *oh); 481 int ReceiveEchoRequest (const void *oh); 482 int ReceiveEchoReply (const void *oh); 483 int ReceiveVPortMod (const void *msg); 484 int ReceiveVPortTableFeaturesRequest (const void *msg); 485 /**@}*/ 486 487 /// Callbacks 488 NetDevice::ReceiveCallback m_rxCallback; 489 NetDevice::PromiscReceiveCallback m_promiscRxCallback; 490 491 Mac48Address m_address; ///< Address of this device. 492 Ptr<Node> m_node; ///< Node this device is installed on. 493 Ptr<BridgeChannel> m_channel; ///< Collection of port channels into the Switch Channel. 494 uint32_t m_ifIndex; ///< Interface Index 495 uint16_t m_mtu; ///< Maximum Transmission Unit 496 497 typedef std::map<uint32_t,ofi::SwitchPacketMetadata> PacketData_t; 498 PacketData_t m_packetData; ///< Packet data 499 500 typedef std::vector<ofi::Port> Ports_t; 501 Ports_t m_ports; ///< Switch's ports 502 503 Ptr<ofi::Controller> m_controller; ///< Connection to controller. 504 505 uint64_t m_id; ///< Unique identifier for this switch, needed for OpenFlow 506 Time m_lookupDelay; ///< Flow Table Lookup Delay [overhead]. 507 508 Time m_lastExecute; ///< Last time the periodic execution occurred. 509 uint16_t m_flags; ///< Flags; configurable by the controller. 510 uint16_t m_missSendLen; ///< Flow Table Miss Send Length; configurable by the controller. 511 512 sw_chain *m_chain; ///< Flow Table; forwarding rules. 513 vport_table_t m_vportTable; ///< Virtual Port Table 514 }; 515 516 } // namespace ns3 517 518 #endif /* OPENFLOW_SWITCH_NET_DEVICE_H */ 519