Skip to content

Instantly share code, notes, and snippets.

@Nikscorp
Last active December 21, 2018 17:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nikscorp/20d24d6a368ea840aee0b26a7d398683 to your computer and use it in GitHub Desktop.
Save Nikscorp/20d24d6a368ea840aee0b26a7d398683 to your computer and use it in GitHub Desktop.

Из задания

Сервис Point-to-Point (P2P) отвечает за построение туннеля между двумя выделенными точками на сети. Туннель определяется уникальным vlan тегом. На вход приложение принимает файл вида: vlan, <switch, port>:<switch,port>. При получении первого пакета с указанных портов с таким тегом нужно построить маршрут между этими двумя точками вида: in_port, vlan -> output (и туда, и обратно).

=> Из packet_in нужно достать vlan

Исходный код

Согласно файлу Packet.cc

// CONCEPT: ethaddr a = pkt.load(eth_src);
//    eth_src (type) is implicitly convertible to oxm::mask<eth_src>
//      with all bits set to 1
//    oxm::field<> convertible to oxm::field<Type>
//      with runtime check of size
//    oxm::field<Type> convertible to Type::value_type
//      with runtime check of mask (should be exact match)
// CONCEPT: oxm::field<ethaddr> m = pkt.load(eth_src & "ff:ff:00:00:00:00");
//      oxm::mask<eth_src_meta> operator& (eth_src_meta, eth_src_meta::mask_type)
class VLANVid: public OXMTLV {
private:
    uint16_t value_;
    uint16_t mask_;
public:
    VLANVid();
    VLANVid(uint16_t value);
    VLANVid(uint16_t value, uint16_t mask);
    ~VLANVid() {
    }
    virtual bool equals(const OXMTLV & other);
    OXMTLV& operator=(const OXMTLV& field);
    virtual VLANVid* clone() const {
        return new VLANVid(*this);
    }
    size_t pack(uint8_t *buffer);
    of_error unpack(uint8_t *buffer);
    uint16_t value() const {
        return this->value_;
    }
    uint16_t mask() const {
        return this->mask_;
    }
    void value(uint16_t value) {
        this->value_ = value;
    }
    void mask(uint16_t mask) {
        this->mask_ = mask;
    }
};

Пытаемся распарсить vlan из PacketIn

LOG(INFO) << "PacketIn captured";
ethaddr eth_dst = pkt.load(oxm::eth_dst());
auto vlan = pkt.load(oxm::vlan_vid());
uint16_t vlan_value = vlan;

Ошибка линковки

[100%] Linking CXX executable ../runos
CMakeFiles/runos.dir/Homework.cc.o: In function `Homework::init(Loader*, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, json11::Json, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, json11::Json> > > const&)::{lambda(std::shared_ptr<runos::SwitchConnection>)#1}::operator()(std::shared_ptr<runos::SwitchConnection>) const::{lambda(runos::Packet&, std::shared_ptr<runos::Flow>, runos::Decision)#1}::operator()(runos::Packet, runos::Flow, std::shared_ptr<runos::Flow>) const [clone .isra.250]':
Homework.cc:(.text+0x10d4): undefined reference to `unsigned short runos::bit_cast<unsigned short, runos::bits<12ul> >(runos::bits<12ul>)'
collect2: error: ld returned 1 exit status
src/CMakeFiles/runos.dir/build.make:864: recipe for target 'runos' failed
make[2]: *** [runos] Error 1
CMakeFiles/Makefile2:190: recipe for target 'src/CMakeFiles/runos.dir/all' failed
make[1]: *** [src/CMakeFiles/runos.dir/all] Error 2
Makefile:94: recipe for target 'all' failed
make: *** [all] Error 2
ERROR: Service 'runos' failed to build: The command '/bin/sh -c cd runos && third_party/bootstrap.sh && mkdir -p build; cd build && CXX=g++ cmake -DCMAKE_BUILD_TYPE=Release .. && make prefix -j2 && make -j2' returned a non-zero code: 2

Исправляем

Добавляем необходимую функцию в bits.hh

template<>
    inline uint16_t bit_cast(const bits<12> from)
    { return from.to_ulong(); }

Запускаем

I1221 15:52:14.536087    10 Homework.cc:66] GOT PACKET IN
E1221 15:52:14.536741    10 Controller.cc:641] Unhandled exception: /root/runos/src/PacketParser.cc(327): Throw in function uint8_t* runos::PacketParser::access(runos::oxm::type) const
Dynamic exception type: boost::exception_detail::clone_impl<runos::out_of_range>
[tag_pi_handler*] = homework
[runos::tag_oxm_ns*] = 32768
[runos::tag_error_msg*] = Unsupported oxm field
[runos::tag_oxm_field*] = 6
[runos::maple::tag_trace*] = (T runos::oxm::eth_type{} == 1000100011001100 -> 0) (L runos::oxm::eth_src{} == 010010100111000110101011000010010110000111000011) (T runos::oxm::eth_type{} == 0000100000000000 -> 0) (T runos::oxm::eth_type{} == 0000100000000110 -> 0)

что это за runos::tag_oxm_field*] = 6?

верно!

/* OXM Flow match field types for OpenFlow basic class. */
enum class basic_match_fields : uint8_t {
    IN_PORT        = 0,  /* Switch input port. */
    IN_PHY_PORT    = 1,  /* Switch physical input port. */
    METADATA       = 2,  /* Metadata passed between tables. */
    ETH_DST        = 3,  /* Ethernet destination address. */
    ETH_SRC        = 4,  /* Ethernet source address. */
    ETH_TYPE       = 5,  /* Ethernet frame type. */
    VLAN_VID       = 6,  /* VLAN id. */
    VLAN_PCP       = 7,  /* VLAN priority. */
    IP_DSCP        = 8,  /* IP DSCP (6 bits in ToS field). */
    IP_ECN         = 9,  /* IP ECN (2 bits in ToS field). */
    IP_PROTO       = 10, /* IP protocol. */
    IPV4_SRC       = 11, /* IPv4 source address. */
    IPV4_DST       = 12, /* IPv4 destination address. */
    TCP_SRC        = 13, /* TCP source port. */
    TCP_DST        = 14, /* TCP destination port. */
    UDP_SRC        = 15, /* UDP source port. */
    UDP_DST        = 16, /* UDP destination port. */
    SCTP_SRC       = 17, /* SCTP source port. */
    SCTP_DST       = 18, /* SCTP destination port. */
    ICMPV4_TYPE    = 19, /* ICMP type. */
    ICMPV4_CODE    = 20, /* ICMP code. */
    ARP_OP         = 21, /* ARP opcode. */
    ARP_SPA        = 22, /* ARP source IPv4 address. */
    ARP_TPA        = 23, /* ARP target IPv4 address. */
    ARP_SHA        = 24, /* ARP source hardware address. */
    ARP_THA        = 25, /* ARP target hardware address. */
    IPV6_SRC       = 26, /* IPv6 source address. */
    IPV6_DST       = 27, /* IPv6 destination address. */
    IPV6_FLABEL    = 28, /* IPv6 Flow Label */
    ICMPV6_TYPE    = 29, /* ICMPv6 type. */
    ICMPV6_CODE    = 30, /* ICMPv6 code. */
    IPV6_ND_TARGET = 31, /* Target address for ND. */
    IPV6_ND_SLL    = 32, /* Source link-layer for ND. */
    IPV6_ND_TLL    = 33, /* Target link-layer for ND. */
    MPLS_LABEL     = 34, /* MPLS label. */
    MPLS_TC        = 35, /* MPLS TC. */
    MPLS_BOS       = 36, /* MPLS BoS bit. */
    PBB_ISID       = 37, /* PBB I-SID. */
    TUNNEL_ID      = 38, /* Logical Port Metadata. */
    IPV6_EXTHDR    = 39, /* IPv6 Extension Header pseudo-field */
};

???

ARCCN/runos#22

if (eth->type == 0x8100){
            if (sizeof(dot1q_hdr) <= data_len ){
                dot1q = reinterpret_cast<dot1q_hdr*>(data);
                bind({
                    { ofb::ETH_TYPE, &dot1q->type },
                    { ofb::ETH_SRC, &dot1q->src },
                    { ofb::ETH_DST, &dot1q->dst },
                    { ofb::VLAN_VID, &dot1q->tci } //fix this
                });
                type = dot1q->type;
                len = dot1q->header_length();
            }
}

PS аналогичное поведение наблюдается в версиях 0.6 (предложена для выполнения в задании) и 0.7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment