<commit_before>///
/// @file  S2LoadBalancer.cpp
/// @brief The S2LoadBalancer evenly distributes the work load between
///        the threads in the computation of the special leaves.
///
/// Simply parallelizing the computation of the special leaves in the
/// Lagarias-Miller-Odlyzko and Deleglise-Rivat algorithms by
/// subdividing the sieve interval by the number of threads into
/// equally sized subintervals does not scale because the distribution
/// of the special leaves is highly skewed and most special leaves are
/// in the first few segments whereas later on there are very few
/// special leaves.
///
/// Based on the above observations it is clear that we need some kind
/// of load balancing in order to scale our parallel algorithm for
/// computing special leaves. Below are the ideas I used to develop a
/// load balancing algorithm that achieves a high load balance by
/// dynamically increasing or decreasing the interval size based on
/// the relative standard deviation of the thread run-times.
///
/// 1) Start with a tiny segment size of x^(1/3) / (log x * log log x)
///    and one segment per thread. Our algorithm uses equally sized
///    intervals, for each thread the interval_size is
///    segment_size * segments_per_thread and the threads process
///    adjacent intervals i.e.
///    [base + interval_size * thread_id, base + interval_size * (thread_id + 1)].
///
/// 2) If the relative standard deviation of the thread run-times is
///    large then we know the special leaves are distributed unevenly,
///    else if the relative standard deviation is low the special
///    leaves are more evenly distributed.
///
/// 3) If the special leaves are distributed unevenly then we can
///    increase the load balance by decreasing the interval_size.
///    Contrary if the special leaves are more evenly distributed
///    we can increase the interval_size in order to improve the
///    algorithm's efficiency.
///
/// 4) We can't use a static threshold for as to when the relative
///    standard deviation is low or large as this threshold varies for
///    different PC architectures. So instead we compare the current
///    relative standard deviation to the previous one in order to
///    decide whether to increase or decrease the interval_size.
///
/// Copyright (C) 2016 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <S2LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>

using namespace std;
using namespace primecount;

namespace {

double get_average(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double sum = 0;

  for (size_t i = 0; i < n; i++)
    sum += timings[i];

  return sum / n;
}

double relative_standard_deviation(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double average = get_average(timings);
  double sum = 0;

  if (average == 0)
    return 0;

  for (size_t i = 0; i < n; i++)
  {
    double mean = timings[i] - average;
    sum += mean * mean;
  }

  double std_dev = sqrt(sum / max(1.0, n - 1.0));
  double rsd = 100 * std_dev / average;

  return rsd;
}

} // namespace

namespace primecount {

S2LoadBalancer::S2LoadBalancer(maxint_t x,
                               int64_t y,
                               int64_t z,
                               int64_t threads) :
  x_((double) x),
  y_((double) y),
  z_((double) z),
  rsd_(40),
  avg_seconds_(0),
  count_(0),
  sqrtz_(isqrt(z))
{
  init(x, y, threads);
}

S2LoadBalancer::S2LoadBalancer(maxint_t x,
                               int64_t y,
                               int64_t z,
                               int64_t threads,
                               double rsd) :
  x_((double) x),
  y_((double) y),
  z_((double) z),
  rsd_(rsd),
  avg_seconds_(0),
  count_(0),
  sqrtz_(isqrt(z))
{
  init(x, y, threads);
}

void S2LoadBalancer::init(maxint_t x,
                          int64_t y,
                          int64_t threads)
{
  // determined by benchmarking
  double log_threads = max(1.0, log((double) threads));
  decrease_dividend_ = max(0.5, log_threads / 3);

  min_seconds_ = 0.02 * log_threads;
  double divisor = log(log(x_)) * log(x_);
  update_min_size(divisor);

  double alpha = get_alpha(x, y);
  smallest_hard_leaf_ = (int64_t) (x / (y * sqrt(alpha) * iroot<6>(x)));
}

double S2LoadBalancer::get_rsd() const
{
  return rsd_;
}

int64_t S2LoadBalancer::get_min_segment_size() const
{
  return min_size_;
}

bool S2LoadBalancer::increase_size(double seconds,
                                   double decrease) const
{
  return seconds < avg_seconds_ &&
        !decrease_size(seconds, decrease);
}

bool S2LoadBalancer::decrease_size(double seconds,
                                   double decrease) const
{
  return seconds > min_seconds_ &&
         rsd_ > decrease;
}

double S2LoadBalancer::get_decrease_threshold(double seconds) const
{
  double log_seconds = max(min_seconds_, log(seconds));
  double dont_decrease = min(decrease_dividend_ / (seconds * log_seconds), rsd_);
  return rsd_ + dont_decrease;
}

void S2LoadBalancer::update_avg_seconds(double seconds)
{
  seconds = max(seconds, min_seconds_);
  double dividend = avg_seconds_ * count_ + seconds;
  avg_seconds_ = dividend / ++count_;
}

void S2LoadBalancer::update_min_size(double divisor)
{
  int64_t size = (int64_t) (sqrtz_ / max(1.0, divisor));
  int64_t min_size = 1 << 9;
  min_size_ = max(size, min_size);
  min_size_ = next_power_of_2(min_size_);
}

/// Balance the load in the computation of the special leaves
/// by dynamically adjusting the segment_size and segments_per_thread.
/// @param timings  Timings of the threads.
///
void S2LoadBalancer::update(int64_t low,
                            int64_t threads,
                            int64_t* segment_size,
                            int64_t* segments_per_thread,
                            aligned_vector<double>& timings)
{
  double seconds = get_average(timings);
  update_avg_seconds(seconds);
  double decrease_threshold = get_decrease_threshold(seconds);
  rsd_ = max(0.1, relative_standard_deviation(timings));

  // 1 segment per thread
  if (*segment_size < sqrtz_)
  {
    if (increase_size(seconds, decrease_threshold))
      *segment_size <<= 1;
    else if (decrease_size(seconds, decrease_threshold))
      if (*segment_size > min_size_)
        *segment_size >>= 1;
  }
  // many segments per thread
  else if (low > smallest_hard_leaf_)
    update(segments_per_thread, decrease_threshold, seconds);

  int64_t thread_distance = *segment_size * *segments_per_thread;
  int64_t high = low + thread_distance * threads;

  // near smallest_hard_leaf_ the hard special leaves
  // are distributed unevenly so use min_size_
  if (low <= smallest_hard_leaf_ &&
      high > smallest_hard_leaf_)
  {
    *segment_size = min_size_;
    thread_distance = *segment_size * *segments_per_thread;
    high = low + thread_distance * threads;
  }

  // slightly increase min_size_
  if (high >= smallest_hard_leaf_)
  {
    update_min_size(log(y_));
    *segment_size = max(min_size_, *segment_size);
  }
}

/// Increase the number of segments per thread if the previous
/// thread run-times are close, otherwise decrease the
/// number of segments per thread.
///
void S2LoadBalancer::update(int64_t* segments_per_thread,
                            double decrease_threshold,
                            double seconds)
{
  double factor = decrease_threshold / rsd_;
  factor = in_between(0.5, factor, 2);
  double n = *segments_per_thread * factor;
  n = max(1.0, n);

  if ((n < *segments_per_thread && seconds > min_seconds_) ||
      (n > *segments_per_thread && seconds < avg_seconds_))
  {
    *segments_per_thread = (int64_t) n;
  }
}

} // namespace
<commit_msg>Refactor<commit_after>///
/// @file  S2LoadBalancer.cpp
/// @brief The S2LoadBalancer evenly distributes the work load between
///        the threads in the computation of the special leaves.
///
/// Simply parallelizing the computation of the special leaves in the
/// Lagarias-Miller-Odlyzko and Deleglise-Rivat algorithms by
/// subdividing the sieve interval by the number of threads into
/// equally sized subintervals does not scale because the distribution
/// of the special leaves is highly skewed and most special leaves are
/// in the first few segments whereas later on there are very few
/// special leaves.
///
/// Based on the above observations it is clear that we need some kind
/// of load balancing in order to scale our parallel algorithm for
/// computing special leaves. Below are the ideas I used to develop a
/// load balancing algorithm that achieves a high load balance by
/// dynamically increasing or decreasing the interval size based on
/// the relative standard deviation of the thread run-times.
///
/// 1) Start with a tiny segment size of x^(1/3) / (log x * log log x)
///    and one segment per thread. Our algorithm uses equally sized
///    intervals, for each thread the interval_size is
///    segment_size * segments_per_thread and the threads process
///    adjacent intervals i.e.
///    [base + interval_size * thread_id, base + interval_size * (thread_id + 1)].
///
/// 2) If the relative standard deviation of the thread run-times is
///    large then we know the special leaves are distributed unevenly,
///    else if the relative standard deviation is low the special
///    leaves are more evenly distributed.
///
/// 3) If the special leaves are distributed unevenly then we can
///    increase the load balance by decreasing the interval_size.
///    Contrary if the special leaves are more evenly distributed
///    we can increase the interval_size in order to improve the
///    algorithm's efficiency.
///
/// 4) We can't use a static threshold for as to when the relative
///    standard deviation is low or large as this threshold varies for
///    different PC architectures. So instead we compare the current
///    relative standard deviation to the previous one in order to
///    decide whether to increase or decrease the interval_size.
///
/// Copyright (C) 2016 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <S2LoadBalancer.hpp>
#include <primecount-internal.hpp>
#include <aligned_vector.hpp>
#include <pmath.hpp>
#include <int128.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>

using namespace std;
using namespace primecount;

namespace {

double get_average(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double sum = 0;

  for (size_t i = 0; i < n; i++)
    sum += timings[i];

  return sum / n;
}

/// Relative standard deviation
double rel_std_dev(aligned_vector<double>& timings)
{
  size_t n = timings.size();
  double avg = get_average(timings);
  double sum = 0;

  if (avg == 0)
    return 0;

  for (size_t i = 0; i < n; i++)
  {
    double mean = timings[i] - avg;
    sum += mean * mean;
  }

  double std_dev = sqrt(sum / max(1.0, n - 1.0));
  double rsd = 100 * std_dev / avg;

  return rsd;
}

} // namespace

namespace primecount {

S2LoadBalancer::S2LoadBalancer(maxint_t x,
                               int64_t y,
                               int64_t z,
                               int64_t threads) :
  x_((double) x),
  y_((double) y),
  z_((double) z),
  rsd_(40),
  avg_seconds_(0),
  count_(0),
  sqrtz_(isqrt(z))
{
  init(x, y, threads);
}

S2LoadBalancer::S2LoadBalancer(maxint_t x,
                               int64_t y,
                               int64_t z,
                               int64_t threads,
                               double rsd) :
  x_((double) x),
  y_((double) y),
  z_((double) z),
  rsd_(rsd),
  avg_seconds_(0),
  count_(0),
  sqrtz_(isqrt(z))
{
  init(x, y, threads);
}

void S2LoadBalancer::init(maxint_t x,
                          int64_t y,
                          int64_t threads)
{
  // determined by benchmarking
  double log_threads = max(1.0, log((double) threads));
  decrease_dividend_ = max(0.5, log_threads / 3);

  min_seconds_ = 0.02 * log_threads;
  double divisor = log(log(x_)) * log(x_);
  update_min_size(divisor);

  double alpha = get_alpha(x, y);
  smallest_hard_leaf_ = (int64_t) (x / (y * sqrt(alpha) * iroot<6>(x)));
}

double S2LoadBalancer::get_rsd() const
{
  return rsd_;
}

int64_t S2LoadBalancer::get_min_segment_size() const
{
  return min_size_;
}

bool S2LoadBalancer::increase_size(double seconds,
                                   double decrease) const
{
  return seconds < avg_seconds_ &&
        !decrease_size(seconds, decrease);
}

bool S2LoadBalancer::decrease_size(double seconds,
                                   double decrease) const
{
  return seconds > min_seconds_ &&
         rsd_ > decrease;
}

double S2LoadBalancer::get_decrease_threshold(double seconds) const
{
  double log_seconds = max(min_seconds_, log(seconds));
  double dont_decrease = min(decrease_dividend_ / (seconds * log_seconds), rsd_);
  return rsd_ + dont_decrease;
}

void S2LoadBalancer::update_avg_seconds(double seconds)
{
  seconds = max(seconds, min_seconds_);
  double dividend = avg_seconds_ * count_ + seconds;
  avg_seconds_ = dividend / ++count_;
}

void S2LoadBalancer::update_min_size(double divisor)
{
  int64_t size = (int64_t) (sqrtz_ / max(1.0, divisor));
  int64_t min_size = 1 << 9;
  min_size_ = max(size, min_size);
  min_size_ = next_power_of_2(min_size_);
}

/// Balance the load in the computation of the special leaves
/// by dynamically adjusting the segment_size and segments_per_thread.
/// @param timings  Timings of the threads.
///
void S2LoadBalancer::update(int64_t low,
                            int64_t threads,
                            int64_t* segment_size,
                            int64_t* segments_per_thread,
                            aligned_vector<double>& timings)
{
  double seconds = get_average(timings);
  update_avg_seconds(seconds);
  double decrease_threshold = get_decrease_threshold(seconds);
  rsd_ = max(0.1, rel_std_dev(timings));

  // 1 segment per thread
  if (*segment_size < sqrtz_)
  {
    if (increase_size(seconds, decrease_threshold))
      *segment_size <<= 1;
    else if (decrease_size(seconds, decrease_threshold))
      if (*segment_size > min_size_)
        *segment_size >>= 1;
  }
  // many segments per thread
  else if (low > smallest_hard_leaf_)
    update(segments_per_thread, decrease_threshold, seconds);

  int64_t thread_distance = *segment_size * *segments_per_thread;
  int64_t high = low + thread_distance * threads;

  // near smallest_hard_leaf_ the hard special leaves
  // are distributed unevenly so use min_size_
  if (low <= smallest_hard_leaf_ &&
      high > smallest_hard_leaf_)
  {
    *segment_size = min_size_;
    thread_distance = *segment_size * *segments_per_thread;
    high = low + thread_distance * threads;
  }

  // slightly increase min_size_
  if (high >= smallest_hard_leaf_)
  {
    update_min_size(log(y_));
    *segment_size = max(min_size_, *segment_size);
  }
}

/// Increase the number of segments per thread if the previous
/// thread run-times are close, otherwise decrease the
/// number of segments per thread.
///
void S2LoadBalancer::update(int64_t* segments_per_thread,
                            double decrease_threshold,
                            double seconds)
{
  double factor = decrease_threshold / rsd_;
  factor = in_between(0.5, factor, 2);
  double n = *segments_per_thread * factor;
  n = max(1.0, n);

  if ((n < *segments_per_thread && seconds > min_seconds_) ||
      (n > *segments_per_thread && seconds < avg_seconds_))
  {
    *segments_per_thread = (int64_t) n;
  }
}

} // namespace
<|endoftext|>


<commit_before>/*
 * This file is part of SpeakEasy.
 * Copyright (C) 2011-2012  Lambert Clara <lambert.clara@yahoo.fr>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file    SE_CLogManager.cpp
 * @brief   Logging class
 *
 * @author  Lambert Clara <lambert.clara@yahoo.fr>
 * @date    Created : 2011-08-21
 */

#include "SE_CLogManager.h"

#include "SE_ConsoleColors.h"

#include <cassert>

// define the static member
SE_CLogManager *SE_CLogManager::ms_pInstance = nullptr;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
SE_CLogManager::SE_CLogManager(std::ostream &inOutStream):
    m_outputStream(inOutStream),
    m_currentLogLevel(kNone)
{
    (void)_pad;

    // because this class is meant to be used as singleton,
    // m_pInstance MUST be nullptr here
    assert(!ms_pInstance);

    // set the static instance to this
    ms_pInstance = this;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
SE_CLogManager::~SE_CLogManager()
{
    ms_pInstance = nullptr;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool SE_CLogManager::startUp(const ELogLevel inLogLevel)
{
    m_currentLogLevel = inLogLevel;
    seLogInfo("SE_CLogManager successfully started with logLevel set to ",
              static_cast<U32>(inLogLevel));
    m_initSuccess = true;
    return m_initSuccess;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool SE_CLogManager::shutDown()
{
    seLogInfo("SE_CLogManager successfully shut downed");
    return true;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void SE_CLogManager::logLevelToSStream(const ELogLevel inLevel,
                                       std::ostringstream &ioStringStream)
{
    ioStringStream << COL_BEGIN;
    switch(inLevel)
    {
        case kNone:        ioStringStream << WHITE  << "    kNone     "; break;
        case kDebug:       ioStringStream << BLUE   << "    kDebug    "; break;
        case kInformation: ioStringStream << GREEN  << " kInformation "; break;
        case kWarning:     ioStringStream << YELLOW << "   kWarning   "; break;
        case kError:       ioStringStream << RED    << "    kError    "; break;
        default:           ioStringStream << WHITE  << "   Unknown !  "; break;
    }
    ioStringStream << COL_END;
}

<commit_msg>Prevent clang to emit a warning.<commit_after>/*
 * This file is part of SpeakEasy.
 * Copyright (C) 2011-2012  Lambert Clara <lambert.clara@yahoo.fr>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * @file    SE_CLogManager.cpp
 * @brief   Logging class
 *
 * @author  Lambert Clara <lambert.clara@yahoo.fr>
 * @date    Created : 2011-08-21
 */

#include "SE_CLogManager.h"

#include "SE_ConsoleColors.h"

#include <cassert>

// define the static member
SE_CLogManager *SE_CLogManager::ms_pInstance = nullptr;

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
SE_CLogManager::SE_CLogManager(std::ostream &inOutStream):
    m_outputStream(inOutStream),
    m_currentLogLevel(kNone)
{
    (void)_pad;

    // because this class is meant to be used as singleton,
    // m_pInstance MUST be nullptr here
    assert(!ms_pInstance);

    // set the static instance to this
    ms_pInstance = this;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
SE_CLogManager::~SE_CLogManager()
{
    ms_pInstance = nullptr;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool SE_CLogManager::startUp(const ELogLevel inLogLevel)
{
    m_currentLogLevel = inLogLevel;
    seLogInfo("SE_CLogManager successfully started with logLevel set to ",
              static_cast<U32>(inLogLevel));
    m_initSuccess = true;
    return m_initSuccess;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
bool SE_CLogManager::shutDown()
{
    seLogInfo("SE_CLogManager successfully shut downed");
    return true;
}

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void SE_CLogManager::logLevelToSStream(const ELogLevel inLevel,
                                       std::ostringstream &ioStringStream)
{
    ioStringStream << COL_BEGIN;
    switch(inLevel)
    {
        case kNone:        ioStringStream << WHITE  << "    kNone     "; break;
        case kDebug:       ioStringStream << BLUE   << "    kDebug    "; break;
        case kInformation: ioStringStream << GREEN  << " kInformation "; break;
        case kWarning:     ioStringStream << YELLOW << "   kWarning   "; break;
        case kError:       ioStringStream << RED    << "    kError    "; break;
#ifndef __clang__
        // prevent clang to emit a warning when all enum values are covered
        // but a default case is also present
        default:           ioStringStream << WHITE  << "   Unknown !  "; break;
#endif // ifndef __clang__
    }
    ioStringStream << COL_END;
}

<|endoftext|>


<commit_before>#include "VirtualMachine.h"

VirtualMachine::VirtualMachine()
{
    //ctor
    stackSize = 0;
}

VirtualMachine::~VirtualMachine()
{
    //dtor
}

void VirtualMachine::interpret(unsigned char bytecode[], int byteSize)
{
    for(int a = 0; a < byteSize; a++)
    {
        int currentInstruction = bytecode[a];
        switch(currentInstruction)
        {
        case Instruction::CONSOLE_OUT:
        {
            Type variable = pop();
            switch(variable.type)
            {
            case DataType::INT:
                std::cout << variable.intData;
                break;
            case DataType::CHAR:
                std::cout << variable.charData;
                break;
            case DataType::BOOL:
                std::cout << variable.boolData;
                break;
            case DataType::STRING:
                std::cout << *variable.stringData;
                break;
            default:
                throwError(std::string("Failed to CONSOLE_OUT, Unknown data type '" + std::to_string(variable.type) + "'"));
            }
        }
        break;
        case Instruction::CREATE_INT:
            push_integer(bytecode[++a]);
            break;
        case Instruction::CREATE_CHAR:
            push_char(bytecode[++a]);
            break;
        case Instruction::CREATE_BOOL:
            push_bool(bytecode[++a]);
            break;
        case Instruction::CREATE_STRING:
        {
            unsigned int stringSize = bytecode[++a]; //String length stored in next byte
            std::string *wholeString = new std::string; //Allocate memory on heap for the string
            wholeString->resize(stringSize);
            for(unsigned int cChar = 0; cChar < stringSize; cChar++) //Read in the string from the bytecode into the allocated memory
                (*wholeString)[cChar] = bytecode[++a];

            push_string(wholeString); //Push the resulting char*
            break;
        }
        case Instruction::GOTO:
            a = static_cast<int>(bytecode[a+1])-1;
            break;
        case Instruction::CONSOLE_IN:
        {
            Type &variable = stack[bytecode[++a]];
            switch(variable.type)
            {
            case DataType::INT:
                std::cin >> variable.intData;
                break;
            case DataType::CHAR:
                std::cin >> variable.charData;
                break;
            case DataType::BOOL:
                std::cin >> variable.boolData;
                break;
            case DataType::STRING:
                std::getline(std::cin, *variable.stringData);
                break;
            default:
                throwError(std::string("Failed to CONSOLE_IN, Unknown data type '" + std::to_string(variable.type) + "'"));
            }
            break;
        }
        case Instruction::MATH_ADD:
            {
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to add from bytecode
                int result = 0;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and add to 'result'
                    result += pop().intData;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::MATH_SUBTRACT:
            {
                //TEMPORARY
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to subtract from bytecode
                std::vector<int> values;
                int result = 0;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and subtract from 'result'
                    values.emplace_back(pop().intData);
                result = values.back();
                values.pop_back();
                for(auto iter = values.rbegin(); iter != values.rend(); iter++)
                    result -= *iter;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::MATH_MULTIPLY:
            {
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to multiply from bytecode
                int result = 1;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and multiply by result
                    result *= pop().intData;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::MATH_DIVIDE:
            {
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to divide from bytecode
                int result = 1;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and divide
                    result /= pop().intData;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::MATH_MOD:
            {
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to add mod bytecode
                int result = 1;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and add to 'result'
                    result %= pop().intData;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::CLONE_TOP:
            {
                push_type(stack[bytecode[++a]]); //Clone a variable from a position in the stack to the top of the stack
                break;
            }

        default:
            throwError("Unknown instruction '" + std::to_string(currentInstruction) + "'");
        }
    }
}

void VirtualMachine::push_integer(int value)
{
    pushStackCheck();

    stack[stackSize++] = Type(value);
}

void VirtualMachine::push_char(unsigned char value)
{
    pushStackCheck();

    stack[stackSize++] = Type(value);
}

void VirtualMachine::push_bool(bool value)
{
    pushStackCheck();

    stack[stackSize++] = Type(value);
}

void VirtualMachine::push_string(std::string* value)
{
    pushStackCheck();

    stack[stackSize++] = Type(value);
}

void VirtualMachine::push_type(Type value)
{
    pushStackCheck();

    stack[stackSize++] = value;
}

Type VirtualMachine::pop()
{
    popStackCheck();

    return stack[--stackSize];
}

void VirtualMachine::popStackCheck()
{
    if(stackSize == 0)
    {
        throwError("\nCouldn't pop from stack, stack empty!");
    }
}

void VirtualMachine::pushStackCheck()
{
    if(stackSize == maxStackSize)
    {
        throwError("\nCouldn't push to stack, stack full!");
    }
}

void VirtualMachine::throwError(const std::string& reason)
{
    throw std::string(reason);
}
<commit_msg>Fixed some more math<commit_after>#include "VirtualMachine.h"

VirtualMachine::VirtualMachine()
{
    //ctor
    stackSize = 0;
}

VirtualMachine::~VirtualMachine()
{
    //dtor
}

void VirtualMachine::interpret(unsigned char bytecode[], int byteSize)
{
    for(int a = 0; a < byteSize; a++)
    {
        int currentInstruction = bytecode[a];
        switch(currentInstruction)
        {
        case Instruction::CONSOLE_OUT:
        {
            Type variable = pop();
            switch(variable.type)
            {
            case DataType::INT:
                std::cout << variable.intData;
                break;
            case DataType::CHAR:
                std::cout << variable.charData;
                break;
            case DataType::BOOL:
                std::cout << variable.boolData;
                break;
            case DataType::STRING:
                std::cout << *variable.stringData;
                break;
            default:
                throwError(std::string("Failed to CONSOLE_OUT, Unknown data type '" + std::to_string(variable.type) + "'"));
            }
        }
        break;
        case Instruction::CREATE_INT:
            push_integer(bytecode[++a]);
            break;
        case Instruction::CREATE_CHAR:
            push_char(bytecode[++a]);
            break;
        case Instruction::CREATE_BOOL:
            push_bool(bytecode[++a]);
            break;
        case Instruction::CREATE_STRING:
        {
            unsigned int stringSize = bytecode[++a]; //String length stored in next byte
            std::string *wholeString = new std::string; //Allocate memory on heap for the string
            wholeString->resize(stringSize);
            for(unsigned int cChar = 0; cChar < stringSize; cChar++) //Read in the string from the bytecode into the allocated memory
                (*wholeString)[cChar] = bytecode[++a];

            push_string(wholeString); //Push the resulting char*
            break;
        }
        case Instruction::GOTO:
            a = static_cast<int>(bytecode[a+1])-1;
            break;
        case Instruction::CONSOLE_IN:
        {
            Type &variable = stack[bytecode[++a]];
            switch(variable.type)
            {
            case DataType::INT:
                std::cin >> variable.intData;
                break;
            case DataType::CHAR:
                std::cin >> variable.charData;
                break;
            case DataType::BOOL:
                std::cin >> variable.boolData;
                break;
            case DataType::STRING:
                std::getline(std::cin, *variable.stringData);
                break;
            default:
                throwError(std::string("Failed to CONSOLE_IN, Unknown data type '" + std::to_string(variable.type) + "'"));
            }
            break;
        }
        case Instruction::MATH_ADD:
            {
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to add from bytecode
                int result = 0;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and add to 'result'
                    result += pop().intData;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::MATH_SUBTRACT:
            {
                //TEMPORARY
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to subtract from bytecode
                std::vector<int> values;
                int result = 0;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and subtract from 'result'
                    values.emplace_back(pop().intData);
                result = values.back();
                values.pop_back();
                for(auto iter = values.rbegin(); iter != values.rend(); iter++)
                    result -= *iter;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::MATH_MULTIPLY:
            {
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to subtract from bytecode
                std::vector<int> values;
                int result = 0;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and subtract from 'result'
                    values.emplace_back(pop().intData);
                result = values.back();
                values.pop_back();
                for(auto iter = values.rbegin(); iter != values.rend(); iter++)
                    result *= *iter;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::MATH_DIVIDE:
            {
                //TEMPORARY
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to subtract from bytecode
                std::vector<int> values;
                int result = 0;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and subtract from 'result'
                    values.emplace_back(pop().intData);
                result = values.back();
                values.pop_back();
                for(auto iter = values.rbegin(); iter != values.rend(); iter++)
                    result /= *iter;
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::MATH_MOD:
            {
                //TEMPORARY
                unsigned int numberCount = bytecode[++a]; //Get number of bytes to subtract from bytecode
                std::vector<int> values;
                int result = 0;
                for(unsigned int a = 0; a < numberCount; a++) //For the number of arguments specified, pop them all off the stack and subtract from 'result'
                    values.emplace_back(pop().intData);
                result = values.back();
                values.pop_back();
                for(auto iter = values.rbegin(); iter != values.rend(); iter++)
                {
                    result %= *iter;
                }
                push_integer(result); //Push the result to the stack
                break;
            }
        case Instruction::CLONE_TOP:
            {
                push_type(stack[bytecode[++a]]); //Clone a variable from a position in the stack to the top of the stack
                break;
            }

        default:
            throwError("Unknown instruction '" + std::to_string(currentInstruction) + "'");
        }
    }
}

void VirtualMachine::push_integer(int value)
{
    pushStackCheck();

    stack[stackSize++] = Type(value);
}

void VirtualMachine::push_char(unsigned char value)
{
    pushStackCheck();

    stack[stackSize++] = Type(value);
}

void VirtualMachine::push_bool(bool value)
{
    pushStackCheck();

    stack[stackSize++] = Type(value);
}

void VirtualMachine::push_string(std::string* value)
{
    pushStackCheck();

    stack[stackSize++] = Type(value);
}

void VirtualMachine::push_type(Type value)
{
    pushStackCheck();

    stack[stackSize++] = value;
}

Type VirtualMachine::pop()
{
    popStackCheck();

    return stack[--stackSize];
}

void VirtualMachine::popStackCheck()
{
    if(stackSize == 0)
    {
        throwError("\nCouldn't pop from stack, stack empty!");
    }
}

void VirtualMachine::pushStackCheck()
{
    if(stackSize == maxStackSize)
    {
        throwError("\nCouldn't push to stack, stack full!");
    }
}

void VirtualMachine::throwError(const std::string& reason)
{
    throw std::string(reason);
}
<|endoftext|>


<commit_before>#include "ofdpa_bridge.hpp"

#include "roflibs/netlink/clogging.hpp"

#include <cassert>
#include <map>
#include <cstring>

#include <rofl/common/openflow/cofport.h>

namespace basebox {

ofdpa_bridge::ofdpa_bridge(rofl::rofl_ofdpa_fm_driver &fm_driver)
    : ingress_vlan_filtered(true), egress_vlan_filtered(false),
      fm_driver(fm_driver) {}

ofdpa_bridge::~ofdpa_bridge() {}

void ofdpa_bridge::set_bridge_interface(const rofcore::crtlink &rtl) {
  if (AF_BRIDGE != rtl.get_family() || 0 != rtl.get_master()) {
    rofcore::logging::error << __PRETTY_FUNCTION__
                            << " not a bridge master: " << rtl << std::endl;
    return;
  }

  this->bridge = rtl;
  fm_driver.enable_policy_arp(1, 1);
}

static int find_next_bit(int i, uint32_t x) {
  int j;

  if (i >= 32)
    return -1;

  /* find first bit */
  if (i < 0)
    return __builtin_ffs(x);

  /* mask off prior finds to get next */
  j = __builtin_ffs(x >> i);
  return j ? j + i : 0;
}

void ofdpa_bridge::add_interface(const rofcore::crtlink &rtl) {

  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot attach interface without bridge: " << rtl
                   << std::endl;
    return;
  }
  if (AF_BRIDGE != rtl.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a bridge interface " << std::endl;
    return;
  }
  if (bridge.get_ifindex() != rtl.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a slave of this bridge interface " << std::endl;
    return;
  }

  if (not ingress_vlan_filtered) {
    // ingress
    fm_driver.enable_port_vid_allow_all(rtl.get_devname());
  }

  if (not egress_vlan_filtered) {
    // egress
    uint32_t group = fm_driver.enable_port_unfiltered_egress(rtl.get_devname());
    l2_domain[0].push_back(group);
  }

  if (not ingress_vlan_filtered && not egress_vlan_filtered) {
    return;
  }

  const struct rtnl_link_bridge_vlan *br_vlan = rtl.get_br_vlan();

  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = br_vlan->vlan_bitmap[k];

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, a);
      if (j > 0) {
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;
        }

        if (egress_vlan_filtered) {
          uint32_t group = fm_driver.enable_port_vid_egress(
              rtl.get_devname(), vid, egress_untagged);
          assert(group && "invalid group identifier");
          if (rofl::openflow::OFPG_MAX == group) {
            logging::error << __PRETTY_FUNCTION__
                           << " failed to set vid on egress " << std::endl;
            i = j;
            continue;
          }
          l2_domain[vid].push_back(group);
        }

        if (ingress_vlan_filtered) {
          if (br_vlan->pvid == vid) {
            fm_driver.enable_port_pvid_ingress(rtl.get_devname(), vid);
          } else {
            fm_driver.enable_port_vid_ingress(rtl.get_devname(), vid);
          }
        }

        // // todo check if vid is okay as an id as well
        // group = fm_driver.enable_group_l2_multicast(vid, vid,
        //                                             l2_domain[vid],
        //                                             1 !=
        //                                             l2_domain[vid].size());
        //
        // if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
        //   fm_driver.enable_policy_arp(vid, group);
        // }

        i = j;
      } else {
        done = 1;
      }
    }
  }
}

void ofdpa_bridge::update_vlans(const std::string &devname,
                                const rtnl_link_bridge_vlan *old_br_vlan,
                                const rtnl_link_bridge_vlan *new_br_vlan) {
  using rofcore::logging;
  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = old_br_vlan->vlan_bitmap[k];
    uint32_t b = new_br_vlan->vlan_bitmap[k];

    uint32_t c = old_br_vlan->untagged_bitmap[k];
    uint32_t d = new_br_vlan->untagged_bitmap[k];

    uint32_t vlan_diff = a ^ b;
    uint32_t untagged_diff = c ^ d;

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, vlan_diff);
      if (j > 0) {
        // vlan added or removed
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (new_br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;

          // clear untagged_diff bit
          untagged_diff &= ~((uint32_t)1 << (j - 1));
        }

        if (new_br_vlan->vlan_bitmap[k] & 1 << (j - 1)) {
          // vlan added

          if (egress_vlan_filtered) {
            try {
              uint32_t group = fm_driver.enable_port_vid_egress(
                  devname, vid, egress_untagged);
              assert(group && "invalid group identifier");
              if (rofl::openflow::OFPG_MAX == group) {
                logging::error << __PRETTY_FUNCTION__
                               << " failed to set vid on egress " << std::endl;
                i = j;
                continue;
              }
              l2_domain[vid].push_back(group);
            } catch (std::exception &e) {
              logging::error << __PRETTY_FUNCTION__
                             << " caught error1:" << e.what() << std::endl;
            }
          }

          if (ingress_vlan_filtered) {
            try {
              if (new_br_vlan->pvid == vid) {
                // todo check for existing pvid?
                fm_driver.enable_port_pvid_ingress(devname, vid);
              } else {
                fm_driver.enable_port_vid_ingress(devname, vid);
              }
            } catch (std::exception &e) {
              logging::error << __PRETTY_FUNCTION__
                             << " caught error2:" << e.what() << std::endl;
            }
          }

          // todo check if vid is okay as an id as well
          // group = fm_driver.enable_group_l2_multicast(vid, vid,
          //                                             l2_domain[vid],
          //                                             1 !=
          //                                             l2_domain[vid].size());
          // // enable arp flooding as well
          // #if DISABLED_TO_TEST
          // if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
          //   fm_driver.enable_policy_arp(vid, group);
          // }
          // #endif

        } else {
          // vlan removed

          if (ingress_vlan_filtered) {
            try {
              if (old_br_vlan->pvid == vid) {
                fm_driver.disable_port_pvid_ingress(devname, vid);
              } else {
                fm_driver.disable_port_vid_ingress(devname, vid);
              }
            } catch (std::exception &e) {
              logging::error << __PRETTY_FUNCTION__
                             << " caught error3:" << e.what() << std::endl;
            }
          }

          if (egress_vlan_filtered) {
            try {
              uint32_t group = fm_driver.disable_port_vid_egress(
                  devname, vid, egress_untagged);
              assert(group && "invalid group identifier");
              if (rofl::openflow::OFPG_MAX == group) {
                logging::error << __PRETTY_FUNCTION__
                               << " failed to remove vid on egress " << std::endl;
                i = j;
                continue;
              }
              l2_domain[vid].remove(group);
            } catch (std::exception &e) {
              logging::error << __PRETTY_FUNCTION__
                             << " caught error4:" << e.what() << std::endl;
            }
          }
        }

        i = j;
      } else {
        done = 1;
      }
    }

#if 0 // not yet implemented the update
		done = 0;
		i = -1;
		while (!done) {
			// vlan is existing, but swapping egress tagged/untagged
			int j = find_next_bit(i, untagged_diff);
			if (j > 0) {
				// egress untagged changed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				// XXX implement update
				fm_driver.update_port_vid_egress(devname, vid, egress_untagged);

				i = j;
			} else {
				done = 1;
			}
		}
#endif
  }
}

void ofdpa_bridge::update_interface(const rofcore::crtlink &oldlink,
                                    const rofcore::crtlink &newlink) {
  using rofcore::crtlink;
  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot update interface without bridge" << std::endl;
    return;
  }
  if (AF_BRIDGE != newlink.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a bridge interface" << std::endl;
    return;
  }
  // if (AF_BRIDGE != oldlink.get_family()) {
  //   logging::error << __PRETTY_FUNCTION__ << oldlink << " is
  //                     not a bridge interface" << std::endl;
  //   return;
  // }
  if (bridge.get_ifindex() != newlink.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a slave of this bridge interface" << std::endl;
    return;
  }
  if (bridge.get_ifindex() != oldlink.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a slave of this bridge interface" << std::endl;
    return;
  }

  if (newlink.get_devname().compare(oldlink.get_devname())) {
    logging::info << __PRETTY_FUNCTION__
                  << " interface rename currently ignored " << std::endl;
    // FIXME this has to be handled differently
    return;
  }

  // handle VLANs
  if (not ingress_vlan_filtered && not egress_vlan_filtered) {
    return;
  }

  if (not crtlink::are_br_vlan_equal(newlink.get_br_vlan(),
                                     oldlink.get_br_vlan())) {
    // vlan updated
    update_vlans(oldlink.get_devname(), oldlink.get_br_vlan(),
                 newlink.get_br_vlan());
  }
}

void ofdpa_bridge::delete_interface(const rofcore::crtlink &rtl) {
  using rofcore::crtlink;
  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot attach interface without bridge: " << rtl
                   << std::endl;
    return;
  }
  if (AF_BRIDGE != rtl.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a bridge interface " << std::endl;
    return;
  }
  if (bridge.get_ifindex() != rtl.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a slave of this bridge interface " << std::endl;
    return;
  }

  if (not ingress_vlan_filtered) {
    // ingress
    fm_driver.disable_port_vid_allow_all(rtl.get_devname());
  }

  if (not egress_vlan_filtered) {
    // egress
    uint32_t group =
        fm_driver.disable_port_unfiltered_egress(rtl.get_devname());
    l2_domain[0].remove(group);
  }

  if (not ingress_vlan_filtered && not egress_vlan_filtered) {
    return;
  }

  const struct rtnl_link_bridge_vlan *br_vlan = rtl.get_br_vlan();
  struct rtnl_link_bridge_vlan br_vlan_empty;
  memset(&br_vlan_empty, 0, sizeof(struct rtnl_link_bridge_vlan));

  if (not crtlink::are_br_vlan_equal(br_vlan, &br_vlan_empty)) {
    // vlan updated
    update_vlans(rtl.get_devname(), br_vlan, &br_vlan_empty);
  }
}

void ofdpa_bridge::add_mac_to_fdb(const uint32_t of_port_no,
                                  const uint16_t vlan,
                                  const rofl::cmacaddr &mac, bool permanent) {
  fm_driver.add_bridging_unicast_vlan(mac, vlan, of_port_no, permanent,
                                      egress_vlan_filtered);
}

void ofdpa_bridge::remove_mac_from_fdb(const uint32_t of_port_no, uint16_t vid,
                                       const rofl::cmacaddr &mac) {
  fm_driver.remove_bridging_unicast_vlan(mac, vid, of_port_no);
}

} /* namespace basebox */
<commit_msg>indentation/cleanup<commit_after>#include "ofdpa_bridge.hpp"

#include "roflibs/netlink/clogging.hpp"

#include <cassert>
#include <map>
#include <cstring>

#include <rofl/common/openflow/cofport.h>

namespace basebox {

ofdpa_bridge::ofdpa_bridge(rofl::rofl_ofdpa_fm_driver &fm_driver)
    : ingress_vlan_filtered(true), egress_vlan_filtered(false),
      fm_driver(fm_driver) {}

ofdpa_bridge::~ofdpa_bridge() {}

void ofdpa_bridge::set_bridge_interface(const rofcore::crtlink &rtl) {
  if (AF_BRIDGE != rtl.get_family() || 0 != rtl.get_master()) {
    rofcore::logging::error << __PRETTY_FUNCTION__
                            << " not a bridge master: " << rtl << std::endl;
    return;
  }

  this->bridge = rtl;
  fm_driver.enable_policy_arp(1, 1);
}

static int find_next_bit(int i, uint32_t x) {
  int j;

  if (i >= 32)
    return -1;

  /* find first bit */
  if (i < 0)
    return __builtin_ffs(x);

  /* mask off prior finds to get next */
  j = __builtin_ffs(x >> i);
  return j ? j + i : 0;
}

void ofdpa_bridge::add_interface(const rofcore::crtlink &rtl) {

  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot attach interface without bridge: " << rtl
                   << std::endl;
    return;
  }
  if (AF_BRIDGE != rtl.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a bridge interface " << std::endl;
    return;
  }
  if (bridge.get_ifindex() != rtl.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a slave of this bridge interface " << std::endl;
    return;
  }

  if (not ingress_vlan_filtered) {
    // ingress
    fm_driver.enable_port_vid_allow_all(rtl.get_devname());
  }

  if (not egress_vlan_filtered) {
    // egress
    uint32_t group = fm_driver.enable_port_unfiltered_egress(rtl.get_devname());
    l2_domain[0].push_back(group);
  }

  if (not ingress_vlan_filtered && not egress_vlan_filtered) {
    return;
  }

  const struct rtnl_link_bridge_vlan *br_vlan = rtl.get_br_vlan();

  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = br_vlan->vlan_bitmap[k];

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, a);
      if (j > 0) {
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;
        }

        if (egress_vlan_filtered) {
          uint32_t group = fm_driver.enable_port_vid_egress(
              rtl.get_devname(), vid, egress_untagged);
          assert(group && "invalid group identifier");
          if (rofl::openflow::OFPG_MAX == group) {
            logging::error << __PRETTY_FUNCTION__
                           << " failed to set vid on egress " << std::endl;
            i = j;
            continue;
          }
          l2_domain[vid].push_back(group);
        }

        if (ingress_vlan_filtered) {
          if (br_vlan->pvid == vid) {
            fm_driver.enable_port_pvid_ingress(rtl.get_devname(), vid);
          } else {
            fm_driver.enable_port_vid_ingress(rtl.get_devname(), vid);
          }
        }

        // // todo check if vid is okay as an id as well
        // group = fm_driver.enable_group_l2_multicast(vid, vid,
        //                                             l2_domain[vid],
        //                                             1 !=
        //                                             l2_domain[vid].size());
        //
        // if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
        //   fm_driver.enable_policy_arp(vid, group);
        // }

        i = j;
      } else {
        done = 1;
      }
    }
  }
}

void ofdpa_bridge::update_vlans(const std::string &devname,
                                const rtnl_link_bridge_vlan *old_br_vlan,
                                const rtnl_link_bridge_vlan *new_br_vlan) {
  using rofcore::logging;
  for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
    int base_bit;
    uint32_t a = old_br_vlan->vlan_bitmap[k];
    uint32_t b = new_br_vlan->vlan_bitmap[k];

    uint32_t c = old_br_vlan->untagged_bitmap[k];
    uint32_t d = new_br_vlan->untagged_bitmap[k];

    uint32_t vlan_diff = a ^ b;
    uint32_t untagged_diff = c ^ d;

    base_bit = k * 32;
    int i = -1;
    int done = 0;
    while (!done) {
      int j = find_next_bit(i, vlan_diff);
      if (j > 0) {
        // vlan added or removed
        int vid = j - 1 + base_bit;
        bool egress_untagged = false;

        // check if egress is untagged
        if (new_br_vlan->untagged_bitmap[k] & 1 << (j - 1)) {
          egress_untagged = true;

          // clear untagged_diff bit
          untagged_diff &= ~((uint32_t)1 << (j - 1));
        }

        if (new_br_vlan->vlan_bitmap[k] & 1 << (j - 1)) {
          // vlan added

          if (egress_vlan_filtered) {
            try {
              uint32_t group = fm_driver.enable_port_vid_egress(
                  devname, vid, egress_untagged);
              assert(group && "invalid group identifier");
              if (rofl::openflow::OFPG_MAX == group) {
                logging::error << __PRETTY_FUNCTION__
                               << " failed to set vid on egress" << std::endl;
                i = j;
                continue;
              }
              l2_domain[vid].push_back(group);
            } catch (std::exception &e) {
              logging::error << __PRETTY_FUNCTION__
                             << " caught error1:" << e.what() << std::endl;
            }
          }

          if (ingress_vlan_filtered) {
            try {
              if (new_br_vlan->pvid == vid) {
                // todo check for existing pvid?
                fm_driver.enable_port_pvid_ingress(devname, vid);
              } else {
                fm_driver.enable_port_vid_ingress(devname, vid);
              }
            } catch (std::exception &e) {
              logging::error << __PRETTY_FUNCTION__
                             << " caught error2:" << e.what() << std::endl;
            }
          }

          // todo check if vid is okay as an id as well
          // group = fm_driver.enable_group_l2_multicast(vid, vid,
          //                                             l2_domain[vid],
          //                                             1 !=
          //                                             l2_domain[vid].size());
          // // enable arp flooding as well
          // #if DISABLED_TO_TEST
          // if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
          //   fm_driver.enable_policy_arp(vid, group);
          // }
          // #endif

        } else {
          // vlan removed

          if (ingress_vlan_filtered) {
            try {
              if (old_br_vlan->pvid == vid) {
                fm_driver.disable_port_pvid_ingress(devname, vid);
              } else {
                fm_driver.disable_port_vid_ingress(devname, vid);
              }
            } catch (std::exception &e) {
              logging::error << __PRETTY_FUNCTION__
                             << " caught error3:" << e.what() << std::endl;
            }
          }

          if (egress_vlan_filtered) {
            try {
              // XXX delete all FM pointing to this group first
              uint32_t group = fm_driver.disable_port_vid_egress(
                  devname, vid, egress_untagged);
              assert(group && "invalid group identifier");
              if (rofl::openflow::OFPG_MAX == group) {
                logging::error << __PRETTY_FUNCTION__
                               << " failed to remove vid on egress"
                               << std::endl;
                i = j;
                continue;
              }
              l2_domain[vid].remove(group);
            } catch (std::exception &e) {
              logging::error << __PRETTY_FUNCTION__
                             << " caught error4:" << e.what() << std::endl;
            }
          }
        }

        i = j;
      } else {
        done = 1;
      }
    }

#if 0 // not yet implemented the update
		done = 0;
		i = -1;
		while (!done) {
			// vlan is existing, but swapping egress tagged/untagged
			int j = find_next_bit(i, untagged_diff);
			if (j > 0) {
				// egress untagged changed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				// XXX implement update
				fm_driver.update_port_vid_egress(devname, vid, egress_untagged);

				i = j;
			} else {
				done = 1;
			}
		}
#endif
  }
}

void ofdpa_bridge::update_interface(const rofcore::crtlink &oldlink,
                                    const rofcore::crtlink &newlink) {
  using rofcore::crtlink;
  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot update interface without bridge" << std::endl;
    return;
  }
  if (AF_BRIDGE != newlink.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a bridge interface" << std::endl;
    return;
  }
  // if (AF_BRIDGE != oldlink.get_family()) {
  //   logging::error << __PRETTY_FUNCTION__ << oldlink << " is
  //                     not a bridge interface" << std::endl;
  //   return;
  // }
  if (bridge.get_ifindex() != newlink.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a slave of this bridge interface" << std::endl;
    return;
  }
  if (bridge.get_ifindex() != oldlink.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << newlink
                   << " is not a slave of this bridge interface" << std::endl;
    return;
  }

  if (newlink.get_devname().compare(oldlink.get_devname())) {
    logging::info << __PRETTY_FUNCTION__
                  << " interface rename currently ignored " << std::endl;
    // FIXME this has to be handled differently
    return;
  }

  // handle VLANs
  if (not ingress_vlan_filtered && not egress_vlan_filtered) {
    return;
  }

  if (not crtlink::are_br_vlan_equal(newlink.get_br_vlan(),
                                     oldlink.get_br_vlan())) {
    // vlan updated
    update_vlans(oldlink.get_devname(), oldlink.get_br_vlan(),
                 newlink.get_br_vlan());
  }
}

void ofdpa_bridge::delete_interface(const rofcore::crtlink &rtl) {
  using rofcore::crtlink;
  using rofcore::logging;

  // sanity checks
  if (0 == bridge.get_ifindex()) {
    logging::error << __PRETTY_FUNCTION__
                   << " cannot attach interface without bridge: " << rtl
                   << std::endl;
    return;
  }
  if (AF_BRIDGE != rtl.get_family()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a bridge interface " << std::endl;
    return;
  }
  if (bridge.get_ifindex() != rtl.get_master()) {
    logging::error << __PRETTY_FUNCTION__ << rtl
                   << " is not a slave of this bridge interface " << std::endl;
    return;
  }

  if (not ingress_vlan_filtered) {
    // ingress
    fm_driver.disable_port_vid_allow_all(rtl.get_devname());
  }

  if (not egress_vlan_filtered) {
    // egress
    uint32_t group =
        fm_driver.disable_port_unfiltered_egress(rtl.get_devname());
    l2_domain[0].remove(group);
  }

  if (not ingress_vlan_filtered && not egress_vlan_filtered) {
    return;
  }

  const struct rtnl_link_bridge_vlan *br_vlan = rtl.get_br_vlan();
  struct rtnl_link_bridge_vlan br_vlan_empty;
  memset(&br_vlan_empty, 0, sizeof(struct rtnl_link_bridge_vlan));

  if (not crtlink::are_br_vlan_equal(br_vlan, &br_vlan_empty)) {
    // vlan updated
    update_vlans(rtl.get_devname(), br_vlan, &br_vlan_empty);
  }
}

void ofdpa_bridge::add_mac_to_fdb(const uint32_t of_port_no,
                                  const uint16_t vlan,
                                  const rofl::cmacaddr &mac, bool permanent) {
  fm_driver.add_bridging_unicast_vlan(mac, vlan, of_port_no, permanent,
                                      egress_vlan_filtered);
}

void ofdpa_bridge::remove_mac_from_fdb(const uint32_t of_port_no, uint16_t vid,
                                       const rofl::cmacaddr &mac) {
  fm_driver.remove_bridging_unicast_vlan(mac, vid, of_port_no);
}

} /* namespace basebox */
<|endoftext|>


<commit_before>#include "ofdpa_bridge.hpp"

#include "roflibs/netlink/clogging.hpp"

#include <cassert>
#include <map>

#include <rofl/common/openflow/cofport.h>

namespace basebox {

ofdpa_bridge::ofdpa_bridge(rofl::rofl_ofdpa_fm_driver &fm_driver) :
		fm_driver(fm_driver)
{
}

ofdpa_bridge::~ofdpa_bridge()
{
}

void
ofdpa_bridge::set_bridge_interface(const rofcore::crtlink& rtl)
{
	if (AF_BRIDGE != rtl.get_family() || 0 != rtl.get_master()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << " not a bridge master: " << rtl << std::endl;
		return;
	}

	this->bridge = rtl;
}

static int find_next_bit(int i, uint32_t x)
{
	int j;

	if (i >= 32)
		return -1;

	/* find first bit */
	if (i < 0)
		return __builtin_ffs(x);

	/* mask off prior finds to get next */
	j = __builtin_ffs(x >> i);
	return j ? j + i : 0;
}

void
ofdpa_bridge::add_interface(const rofcore::crtlink& rtl)
{
	// sanity checks
	if (0 == bridge.get_ifindex()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << " cannot attach interface without bridge: " << rtl << std::endl;
		return;
	}
	if (AF_BRIDGE != rtl.get_family()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << rtl << " is not a bridge interface " << std::endl;
		return;
	}
	if (bridge.get_ifindex() != rtl.get_master()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << rtl << " is not a slave of this bridge interface " << std::endl;
		return;
	}

	const struct rtnl_link_bridge_vlan* br_vlan = rtl.get_br_vlan();

	for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
		int base_bit;
		uint32_t a = br_vlan->vlan_bitmap[k];

		base_bit = k * 32;
		int i = -1;
		int done = 0;
		while (!done) {
			int j = find_next_bit(i, a);
			if (j > 0) {
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				uint32_t group = fm_driver.enable_port_vid_egress(rtl.get_devname(), vid, egress_untagged);
				assert(group && "invalid group identifier");
				if (rofl::openflow::OFPG_MAX == group) {
					rofcore::logging::error << __PRETTY_FUNCTION__ << " failed to set vid on egress " << std::endl;
					i = j;
					continue;
				}
				l2_domain[vid].push_back(group);

				if (br_vlan->pvid == vid) {
					fm_driver.enable_port_pvid_ingress(rtl.get_devname(), vid);
				} else {
					fm_driver.enable_port_vid_ingress(rtl.get_devname(), vid);
				}

				// todo check if vid is okay as an id as well
				group = fm_driver.enable_group_l2_multicast(vid, vid, l2_domain[vid], 1 != l2_domain[vid].size());
				// enable arp flooding as well

				if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
					fm_driver.enable_policy_arp(vid, group);
				}

				i = j;
			} else {
				done = 1;
			}
		}
	}
}

void
ofdpa_bridge::update_vlans(const std::string &devname,
			const rtnl_link_bridge_vlan *old_br_vlan,
			const rtnl_link_bridge_vlan *new_br_vlan)
{
	for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
		int base_bit;
		uint32_t a = old_br_vlan->vlan_bitmap[k];
		uint32_t b = new_br_vlan->vlan_bitmap[k];

		uint32_t c = old_br_vlan->untagged_bitmap[k];
		uint32_t d = new_br_vlan->untagged_bitmap[k];

		uint32_t vlan_diff = a ^ b;
		uint32_t untagged_diff = c ^ d;

		base_bit = k * 32;
		int i = -1;
		int done = 0;
		while (!done) {
			int j = find_next_bit(i, vlan_diff);
			if (j > 0) {
				// vlan added or removed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;

					// clear untagged_diff bit
					untagged_diff &= ~((uint32_t)1 << (j-1));
				}

				if (new_br_vlan->vlan_bitmap[k] & 1 << (j-1)) {
					// vlan added

					uint32_t group = fm_driver.enable_port_vid_egress(devname, vid, egress_untagged);
					assert(group && "invalid group identifier");
					if (rofl::openflow::OFPG_MAX == group) {
						rofcore::logging::error << __PRETTY_FUNCTION__ << " failed to set vid on egress " << std::endl;
						i = j;
						continue;
					}
					l2_domain[vid].push_back(group);

					if (new_br_vlan->pvid == vid) {
						// todo check for existing pvid?
						fm_driver.enable_port_pvid_ingress(devname, vid);
					} else {
						fm_driver.enable_port_vid_ingress(devname, vid);
					}

					// todo check if vid is okay as an id as well
					group = fm_driver.enable_group_l2_multicast(vid, vid, l2_domain[vid], 1 != l2_domain[vid].size());
					// enable arp flooding as well
#if DISABLED_TO_TEST
					if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
						fm_driver.enable_policy_arp(vid, group);
					}
#endif
				} else {
					// vlan removed
				}

				i = j;
			} else {
				done = 1;
			}
		}

#if 0 // not yet implemented the update
		done = 0;
		i = -1;
		while (!done) {
			// vlan is existing, but swapping egress tagged/untagged
			int j = find_next_bit(i, untagged_diff);
			if (j > 0) {
				// egress untagged changed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				// xxx implement update
				fm_driver.update_port_vid_egress(devname, vid, egress_untagged);

				i = j;
			} else {
				done = 1;
			}
		}
#endif
	}
}

void
ofdpa_bridge::update_interface(const rofcore::crtlink& oldlink, const rofcore::crtlink& newlink)
{
	using rofcore::crtlink;

	// sanity checks
	if (0 == bridge.get_ifindex()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << " cannot update interface without bridge" << std::endl;
		return;
	}
	if (AF_BRIDGE != newlink.get_family()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << newlink << " is not a bridge interface" << std::endl;
		return;
	}
//	if (AF_BRIDGE != oldlink.get_family()) {
//		rofcore::logging::error << __PRETTY_FUNCTION__ << oldlink << " is not a bridge interface" << std::endl;
//		return;
//	}
	if (bridge.get_ifindex() != newlink.get_master()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << newlink << " is not a slave of this bridge interface" << std::endl;
		return;
	}
	if (bridge.get_ifindex() != oldlink.get_master()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << newlink << " is not a slave of this bridge interface" << std::endl;
		return;
	}

	if (newlink.get_devname().compare(oldlink.get_devname())) {
		rofcore::logging::info << __PRETTY_FUNCTION__ << " interface rename currently ignored " << std::endl;
		// FIXME this has to be handled differently
		return;
	}

	if (not crtlink::are_br_vlan_equal(newlink.get_br_vlan(), oldlink.get_br_vlan())) {
		// vlan updated
		update_vlans(oldlink.get_devname(), oldlink.get_br_vlan(), newlink.get_br_vlan());
	}

}

void
ofdpa_bridge::delete_interface(const rofcore::crtlink& rtl)
{
	// fixme update L2 Multicast Group
}

void
ofdpa_bridge::add_mac_to_fdb(const uint32_t of_port_no, const uint16_t vlan, const rofl::cmacaddr &mac, bool permanent)
{
	fm_driver.add_bridging_unicast_vlan(mac, vlan, of_port_no, permanent);
}

void ofdpa_bridge::remove_mac_from_fdb(const uint32_t of_port_no, uint16_t vid,
		const rofl::cmacaddr& mac)
{
	fm_driver.remove_bridging_unicast_vlan(mac, vid, of_port_no);
}

} /* namespace basebox */
<commit_msg>added comments<commit_after>#include "ofdpa_bridge.hpp"

#include "roflibs/netlink/clogging.hpp"

#include <cassert>
#include <map>

#include <rofl/common/openflow/cofport.h>

namespace basebox {

ofdpa_bridge::ofdpa_bridge(rofl::rofl_ofdpa_fm_driver &fm_driver) :
		fm_driver(fm_driver)
{
}

ofdpa_bridge::~ofdpa_bridge()
{
}

void
ofdpa_bridge::set_bridge_interface(const rofcore::crtlink& rtl)
{
	if (AF_BRIDGE != rtl.get_family() || 0 != rtl.get_master()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << " not a bridge master: " << rtl << std::endl;
		return;
	}

	this->bridge = rtl;
}

static int find_next_bit(int i, uint32_t x)
{
	int j;

	if (i >= 32)
		return -1;

	/* find first bit */
	if (i < 0)
		return __builtin_ffs(x);

	/* mask off prior finds to get next */
	j = __builtin_ffs(x >> i);
	return j ? j + i : 0;
}

void
ofdpa_bridge::add_interface(const rofcore::crtlink& rtl)
{
	// sanity checks
	if (0 == bridge.get_ifindex()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << " cannot attach interface without bridge: " << rtl << std::endl;
		return;
	}
	if (AF_BRIDGE != rtl.get_family()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << rtl << " is not a bridge interface " << std::endl;
		return;
	}
	if (bridge.get_ifindex() != rtl.get_master()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << rtl << " is not a slave of this bridge interface " << std::endl;
		return;
	}

	const struct rtnl_link_bridge_vlan* br_vlan = rtl.get_br_vlan();

	for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
		int base_bit;
		uint32_t a = br_vlan->vlan_bitmap[k];

		base_bit = k * 32;
		int i = -1;
		int done = 0;
		while (!done) {
			int j = find_next_bit(i, a);
			if (j > 0) {
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				uint32_t group = fm_driver.enable_port_vid_egress(rtl.get_devname(), vid, egress_untagged);
				assert(group && "invalid group identifier");
				if (rofl::openflow::OFPG_MAX == group) {
					rofcore::logging::error << __PRETTY_FUNCTION__ << " failed to set vid on egress " << std::endl;
					i = j;
					continue;
				}
				l2_domain[vid].push_back(group);

				if (br_vlan->pvid == vid) {
					fm_driver.enable_port_pvid_ingress(rtl.get_devname(), vid);
				} else {
					fm_driver.enable_port_vid_ingress(rtl.get_devname(), vid);
				}

				// todo check if vid is okay as an id as well
				group = fm_driver.enable_group_l2_multicast(vid, vid, l2_domain[vid], 1 != l2_domain[vid].size());

				if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
					fm_driver.enable_policy_arp(vid, group);
				}

				i = j;
			} else {
				done = 1;
			}
		}
	}
}

void
ofdpa_bridge::update_vlans(const std::string &devname,
			const rtnl_link_bridge_vlan *old_br_vlan,
			const rtnl_link_bridge_vlan *new_br_vlan)
{
	for (int k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
		int base_bit;
		uint32_t a = old_br_vlan->vlan_bitmap[k];
		uint32_t b = new_br_vlan->vlan_bitmap[k];

		uint32_t c = old_br_vlan->untagged_bitmap[k];
		uint32_t d = new_br_vlan->untagged_bitmap[k];

		uint32_t vlan_diff = a ^ b;
		uint32_t untagged_diff = c ^ d;

		base_bit = k * 32;
		int i = -1;
		int done = 0;
		while (!done) {
			int j = find_next_bit(i, vlan_diff);
			if (j > 0) {
				// vlan added or removed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;

					// clear untagged_diff bit
					untagged_diff &= ~((uint32_t)1 << (j-1));
				}

				if (new_br_vlan->vlan_bitmap[k] & 1 << (j-1)) {
					// vlan added

					uint32_t group = fm_driver.enable_port_vid_egress(devname, vid, egress_untagged);
					assert(group && "invalid group identifier");
					if (rofl::openflow::OFPG_MAX == group) {
						rofcore::logging::error << __PRETTY_FUNCTION__ << " failed to set vid on egress " << std::endl;
						i = j;
						continue;
					}
					l2_domain[vid].push_back(group);

					if (new_br_vlan->pvid == vid) {
						// todo check for existing pvid?
						fm_driver.enable_port_pvid_ingress(devname, vid);
					} else {
						fm_driver.enable_port_vid_ingress(devname, vid);
					}

					// todo check if vid is okay as an id as well
					group = fm_driver.enable_group_l2_multicast(vid, vid, l2_domain[vid], 1 != l2_domain[vid].size());
					// enable arp flooding as well
#if DISABLED_TO_TEST
					if (1 == l2_domain[vid].size()) { // todo maybe unnecessary
						fm_driver.enable_policy_arp(vid, group);
					}
#endif
				} else {
					// vlan removed
				}

				i = j;
			} else {
				done = 1;
			}
		}

#if 0 // not yet implemented the update
		done = 0;
		i = -1;
		while (!done) {
			// vlan is existing, but swapping egress tagged/untagged
			int j = find_next_bit(i, untagged_diff);
			if (j > 0) {
				// egress untagged changed
				int vid = j - 1 + base_bit;
				bool egress_untagged = false;

				// check if egress is untagged
				if (new_br_vlan->untagged_bitmap[k] & 1 << (j-1)) {
					egress_untagged = true;
				}

				// xxx implement update
				fm_driver.update_port_vid_egress(devname, vid, egress_untagged);

				i = j;
			} else {
				done = 1;
			}
		}
#endif
	}
}

void
ofdpa_bridge::update_interface(const rofcore::crtlink& oldlink, const rofcore::crtlink& newlink)
{
	using rofcore::crtlink;

	// sanity checks
	if (0 == bridge.get_ifindex()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << " cannot update interface without bridge" << std::endl;
		return;
	}
	if (AF_BRIDGE != newlink.get_family()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << newlink << " is not a bridge interface" << std::endl;
		return;
	}
//	if (AF_BRIDGE != oldlink.get_family()) {
//		rofcore::logging::error << __PRETTY_FUNCTION__ << oldlink << " is not a bridge interface" << std::endl;
//		return;
//	}
	if (bridge.get_ifindex() != newlink.get_master()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << newlink << " is not a slave of this bridge interface" << std::endl;
		return;
	}
	if (bridge.get_ifindex() != oldlink.get_master()) {
		rofcore::logging::error << __PRETTY_FUNCTION__ << newlink << " is not a slave of this bridge interface" << std::endl;
		return;
	}

	if (newlink.get_devname().compare(oldlink.get_devname())) {
		rofcore::logging::info << __PRETTY_FUNCTION__ << " interface rename currently ignored " << std::endl;
		// FIXME this has to be handled differently
		return;
	}

	if (not crtlink::are_br_vlan_equal(newlink.get_br_vlan(), oldlink.get_br_vlan())) {
		// vlan updated
		update_vlans(oldlink.get_devname(), oldlink.get_br_vlan(), newlink.get_br_vlan());
	}

}

void
ofdpa_bridge::delete_interface(const rofcore::crtlink& rtl)
{
	// XXX update L2 Multicast Group

  // get group id

  // remove id from l2_domain

  // update enable_group_l2_multicast
}

void
ofdpa_bridge::add_mac_to_fdb(const uint32_t of_port_no, const uint16_t vlan, const rofl::cmacaddr &mac, bool permanent)
{
	fm_driver.add_bridging_unicast_vlan(mac, vlan, of_port_no, permanent);
}

void ofdpa_bridge::remove_mac_from_fdb(const uint32_t of_port_no, uint16_t vid,
		const rofl::cmacaddr& mac)
{
	fm_driver.remove_bridging_unicast_vlan(mac, vid, of_port_no);
}

} /* namespace basebox */
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "rpc/connectivity/multiplexer.hpp"

#include "errors.hpp"
#include <boost/bind.hpp>
#include <boost/function.hpp>

#include "rpc/connectivity/connectivity.hpp"

#define MAX_OUTSTANDING_WRITES_PER_MULTIPLEXER_CLIENT_THREAD 16

message_multiplexer_t::run_t::run_t(message_multiplexer_t *p) : parent(p) {
    guarantee(parent->run == NULL);
    parent->run = this;
#ifndef NDEBUG
    for (int i = 0; i < max_tag; i++) {
        if (parent->clients[i]) {
            rassert(parent->clients[i]->run);
        }
    }
#endif  // NDEBUG
}

message_multiplexer_t::run_t::~run_t() {
    guarantee(parent->run == this);
    parent->run = NULL;
}

void message_multiplexer_t::run_t::on_message(peer_id_t source, string_read_stream_t *stream) {
    tag_t tag;
    archive_result_t res = deserialize(stream, &tag);
    if (res) { throw fake_archive_exc_t(); }
    client_t *client = parent->clients[tag];
    guarantee(client != NULL, "Got a message for an unfamiliar tag. Apparently "
        "we aren't compatible with the cluster on the other end.");
    client->run->message_handler->on_message(source, stream);
}

message_multiplexer_t::client_t::run_t::run_t(client_t *c, message_handler_t *m) :
    parent(c), message_handler(m)
{
    guarantee(parent->parent->run == NULL);
    guarantee(parent->run == NULL);
    parent->run = this;
}

message_multiplexer_t::client_t::run_t::~run_t() {
    guarantee(parent->parent->run == NULL);
    guarantee(parent->run == this);
    parent->run = NULL;
}

message_multiplexer_t::client_t::client_t(message_multiplexer_t *p, tag_t t) :
    parent(p),
    tag(t),
    run(NULL),
    outstanding_writes_semaphores(MAX_OUTSTANDING_WRITES_PER_MULTIPLEXER_CLIENT_THREAD)
{
    guarantee(parent->run == NULL);
    guarantee(parent->clients[tag] == NULL);
    parent->clients[tag] = this;
}

message_multiplexer_t::client_t::~client_t() {
    guarantee(parent->run == NULL);
    guarantee(parent->clients[tag] == this);
    parent->clients[tag] = NULL;
}

connectivity_service_t *message_multiplexer_t::client_t::get_connectivity_service() {
    return parent->message_service->get_connectivity_service();
}

class tagged_message_writer_t : public send_message_write_callback_t {
public:
    tagged_message_writer_t(message_multiplexer_t::tag_t _tag, send_message_write_callback_t *_subwriter) :
        tag(_tag), subwriter(_subwriter) { }
    virtual ~tagged_message_writer_t() { }

    void write(write_stream_t *os) {
        write_message_t msg;
        msg << tag;
        int res = send_write_message(os, &msg);
        if (res) { throw fake_archive_exc_t(); }
        subwriter->write(os);
    }

private:
    message_multiplexer_t::tag_t tag;
    send_message_write_callback_t *subwriter;
};

void message_multiplexer_t::client_t::send_message(peer_id_t dest, send_message_write_callback_t *callback) {
    tagged_message_writer_t writer(tag, callback);
    {
        semaphore_acq_t outstanding_write_acq (outstanding_writes_semaphores.get());
        parent->message_service->send_message(dest, &writer);
        // Release outstanding_writes_semaphore
    }
}

void message_multiplexer_t::client_t::kill_connection(peer_id_t peer) {
    parent->message_service->kill_connection(peer);
}

message_multiplexer_t::message_multiplexer_t(message_service_t *super_ms) :
    message_service(super_ms), run(NULL)
{
    for (int i = 0; i < max_tag; i++) {
        clients[i] = NULL;
    }
}

message_multiplexer_t::~message_multiplexer_t() {
    guarantee(run == NULL);
    for (int i = 0; i < max_tag; i++) {
        guarantee(clients[i] == NULL);
    }
}
<commit_msg>Ok, actually in release it seems better with a smaller limit. Revert "Increased multiplexer client outstanding write limit. Seems faster that way."<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "rpc/connectivity/multiplexer.hpp"

#include "errors.hpp"
#include <boost/bind.hpp>
#include <boost/function.hpp>

#include "rpc/connectivity/connectivity.hpp"

#define MAX_OUTSTANDING_WRITES_PER_MULTIPLEXER_CLIENT_THREAD 4

message_multiplexer_t::run_t::run_t(message_multiplexer_t *p) : parent(p) {
    guarantee(parent->run == NULL);
    parent->run = this;
#ifndef NDEBUG
    for (int i = 0; i < max_tag; i++) {
        if (parent->clients[i]) {
            rassert(parent->clients[i]->run);
        }
    }
#endif  // NDEBUG
}

message_multiplexer_t::run_t::~run_t() {
    guarantee(parent->run == this);
    parent->run = NULL;
}

void message_multiplexer_t::run_t::on_message(peer_id_t source, string_read_stream_t *stream) {
    tag_t tag;
    archive_result_t res = deserialize(stream, &tag);
    if (res) { throw fake_archive_exc_t(); }
    client_t *client = parent->clients[tag];
    guarantee(client != NULL, "Got a message for an unfamiliar tag. Apparently "
        "we aren't compatible with the cluster on the other end.");
    client->run->message_handler->on_message(source, stream);
}

message_multiplexer_t::client_t::run_t::run_t(client_t *c, message_handler_t *m) :
    parent(c), message_handler(m)
{
    guarantee(parent->parent->run == NULL);
    guarantee(parent->run == NULL);
    parent->run = this;
}

message_multiplexer_t::client_t::run_t::~run_t() {
    guarantee(parent->parent->run == NULL);
    guarantee(parent->run == this);
    parent->run = NULL;
}

message_multiplexer_t::client_t::client_t(message_multiplexer_t *p, tag_t t) :
    parent(p),
    tag(t),
    run(NULL),
    outstanding_writes_semaphores(MAX_OUTSTANDING_WRITES_PER_MULTIPLEXER_CLIENT_THREAD)
{
    guarantee(parent->run == NULL);
    guarantee(parent->clients[tag] == NULL);
    parent->clients[tag] = this;
}

message_multiplexer_t::client_t::~client_t() {
    guarantee(parent->run == NULL);
    guarantee(parent->clients[tag] == this);
    parent->clients[tag] = NULL;
}

connectivity_service_t *message_multiplexer_t::client_t::get_connectivity_service() {
    return parent->message_service->get_connectivity_service();
}

class tagged_message_writer_t : public send_message_write_callback_t {
public:
    tagged_message_writer_t(message_multiplexer_t::tag_t _tag, send_message_write_callback_t *_subwriter) :
        tag(_tag), subwriter(_subwriter) { }
    virtual ~tagged_message_writer_t() { }

    void write(write_stream_t *os) {
        write_message_t msg;
        msg << tag;
        int res = send_write_message(os, &msg);
        if (res) { throw fake_archive_exc_t(); }
        subwriter->write(os);
    }

private:
    message_multiplexer_t::tag_t tag;
    send_message_write_callback_t *subwriter;
};

void message_multiplexer_t::client_t::send_message(peer_id_t dest, send_message_write_callback_t *callback) {
    tagged_message_writer_t writer(tag, callback);
    {
        semaphore_acq_t outstanding_write_acq (outstanding_writes_semaphores.get());
        parent->message_service->send_message(dest, &writer);
        // Release outstanding_writes_semaphore
    }
}

void message_multiplexer_t::client_t::kill_connection(peer_id_t peer) {
    parent->message_service->kill_connection(peer);
}

message_multiplexer_t::message_multiplexer_t(message_service_t *super_ms) :
    message_service(super_ms), run(NULL)
{
    for (int i = 0; i < max_tag; i++) {
        clients[i] = NULL;
    }
}

message_multiplexer_t::~message_multiplexer_t() {
    guarantee(run == NULL);
    for (int i = 0; i < max_tag; i++) {
        guarantee(clients[i] == NULL);
    }
}
<|endoftext|>