BFD packet sender.

def _send(self):
        """
        BFD packet sender.
        """
        # If the switch was not connected to controller, exit.
        if self.datapath is None:
            return

        # BFD Flags Setup
        flags = 0

        if self._pending_final:
            flags |= bfd.BFD_FLAG_FINAL
            self._pending_final = False
            self._is_polling = False

        if self._is_polling:
            flags |= bfd.BFD_FLAG_POLL

        # Authentication Section
        auth_cls = None
        if self._auth_type:
            auth_key_id = list(self._auth_keys.keys())[
                random.randint(0, len(list(self._auth_keys.keys())) - 1)]
            auth_key = self._auth_keys[auth_key_id]

            if self._auth_type == bfd.BFD_AUTH_SIMPLE_PASS:
                auth_cls = bfd.SimplePassword(auth_key_id=auth_key_id,
                                              password=auth_key)

            if self._auth_type in [bfd.BFD_AUTH_KEYED_MD5,
                                   bfd.BFD_AUTH_METICULOUS_KEYED_MD5,
                                   bfd.BFD_AUTH_KEYED_SHA1,
                                   bfd.BFD_AUTH_METICULOUS_KEYED_SHA1]:
                if self._auth_type in [bfd.BFD_AUTH_KEYED_MD5,
                                       bfd.BFD_AUTH_KEYED_SHA1]:
                    if random.randint(0, 1):
                        self._xmit_auth_seq = \
                            (self._xmit_auth_seq + 1) & UINT32_MAX
                else:
                    self._xmit_auth_seq = \
                        (self._xmit_auth_seq + 1) & UINT32_MAX

                auth_cls = bfd.bfd._auth_parsers[self._auth_type](
                    auth_key_id=auth_key_id,
                    seq=self._xmit_auth_seq,
                    auth_key=auth_key)

        if auth_cls is not None:
            flags |= bfd.BFD_FLAG_AUTH_PRESENT

        if self._demand_mode and \
                self._session_state == bfd.BFD_STATE_UP and \
                self._remote_session_state == bfd.BFD_STATE_UP:
            flags |= bfd.BFD_FLAG_DEMAND

        diag = self._local_diag
        state = self._session_state
        detect_mult = self._detect_mult
        my_discr = self._local_discr
        your_discr = self._remote_discr
        desired_min_tx_interval = self._desired_min_tx_interval
        required_min_rx_interval = self._required_min_rx_interval
        required_min_echo_rx_interval = self._cfg_required_min_echo_rx_interval

        # Prepare for Ethernet/IP/UDP header fields
        src_mac = self.src_mac
        dst_mac = self.dst_mac
        src_ip = self.src_ip
        dst_ip = self.dst_ip
        self.ipv4_id = (self.ipv4_id + 1) & UINT16_MAX
        ipv4_id = self.ipv4_id
        src_port = self.src_port
        dst_port = self.dst_port

        # Construct BFD Control packet
        data = BFDPacket.bfd_packet(
            src_mac=src_mac, dst_mac=dst_mac,
            src_ip=src_ip, dst_ip=dst_ip, ipv4_id=ipv4_id,
            src_port=src_port, dst_port=dst_port,
            diag=diag, state=state, flags=flags, detect_mult=detect_mult,
            my_discr=my_discr, your_discr=your_discr,
            desired_min_tx_interval=desired_min_tx_interval,
            required_min_rx_interval=required_min_rx_interval,
            required_min_echo_rx_interval=required_min_echo_rx_interval,
            auth_cls=auth_cls)

        # Prepare for a datapath
        datapath = self.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        actions = [parser.OFPActionOutput(self.ofport)]

        out = parser.OFPPacketOut(datapath=datapath,
                                  buffer_id=ofproto.OFP_NO_BUFFER,
                                  in_port=ofproto.OFPP_CONTROLLER,
                                  actions=actions,
                                  data=data)

        datapath.send_msg(out)
        LOG.debug("[BFD][%s][SEND] BFD Control sent.", hex(self._local_discr))