Result<basic::Classifier> decode<basic::Classifier>( const Netlink<struct rtnl_cls>& cls) { if (rtnl_tc_get_kind(TC_CAST(cls.get())) != string("basic")) { return None(); } return basic::Classifier(rtnl_cls_get_protocol(cls.get())); }
Result<ingress::Discipline> decode<ingress::Discipline>( const Netlink<struct rtnl_qdisc>& qdisc) { if (rtnl_tc_get_kind(TC_CAST(qdisc.get())) != string("ingress") || rtnl_tc_get_parent(TC_CAST(qdisc.get())) != INGRESS_ROOT.get() || rtnl_tc_get_handle(TC_CAST(qdisc.get())) != ingress::HANDLE.get()) { return None(); } return ingress::Discipline(); }
Try<Nothing> encode<basic::Classifier>( const Netlink<struct rtnl_cls>& cls, const basic::Classifier& classifier) { rtnl_cls_set_protocol(cls.get(), classifier.protocol()); int error = rtnl_tc_set_kind(TC_CAST(cls.get()), "basic"); if (error != 0) { return Error( "Failed to set the kind of the classifier: " + string(nl_geterror(error))); } return Nothing(); }
Try<Nothing> encode<ingress::Discipline>( const Netlink<struct rtnl_qdisc>& qdisc, const ingress::Discipline& discipline) { int error = rtnl_tc_set_kind(TC_CAST(qdisc.get()), "ingress"); if (error != 0) { return Error( "Failed to set the kind of the queueing discipline: " + string(nl_geterror(error))); } rtnl_tc_set_parent(TC_CAST(qdisc.get()), INGRESS_ROOT.get()); rtnl_tc_set_handle(TC_CAST(qdisc.get()), ingress::HANDLE.get()); return Nothing(); }
Result<htb::Config> decode<htb::Config>( const Netlink<struct rtnl_qdisc>& qdisc) { if (rtnl_tc_get_kind(TC_CAST(qdisc.get())) != htb::KIND) { return None(); } return htb::Config(); }
Try<Nothing> encode<icmp::Classifier>( const Netlink<struct rtnl_cls>& cls, const icmp::Classifier& classifier) { // ICMP packets are one type of IP packets. rtnl_cls_set_protocol(cls.get(), ETH_P_IP); int error = rtnl_tc_set_kind(TC_CAST(cls.get()), "u32"); if (error != 0) { return Error( "Failed to set the kind of the classifier: " + string(nl_geterror(error))); } // To avoid confusion, we only use u32 selectors which are used to // match arbitrary 32-bit content in a packet. // Format of an IP packet at offset 8. The IP protocol field is at // offset 9. ICMP has protocol = 1. // +--------+--------+--------+--------+ // | X | Proto. | X | X | // +--------+--------+--------+--------+ // Offset: 8 9 10 11 uint32_t protocol = 0x00010000; uint32_t mask = 0x00ff0000; // Ignore offset 8, 10, 11. // To match ICMP packets (protocol = 1). error = rtnl_u32_add_key( cls.get(), htonl(protocol), htonl(mask), 8, // Offset from which to start matching. 0); if (error != 0) { return Error( "Failed to add selector for IP protocol: " + string(nl_geterror(error))); } if (classifier.destinationIP.isSome()) { Try<struct in_addr> in = classifier.destinationIP.get().in(); if (in.isError()) { return Error("Destination IP is not an IPv4 address"); } // To match those IP packets that have the given destination IP. error = rtnl_u32_add_key( cls.get(), in.get().s_addr, htonl(0xffffffff), 16, // Offset from which to start matching. 0); if (error != 0) { return Error( "Failed to add selector for destination IP address: " + string(nl_geterror(error))); } } return Nothing(); }
Result<icmp::Classifier> decode<icmp::Classifier>( const Netlink<struct rtnl_cls>& cls) { if (rtnl_cls_get_protocol(cls.get()) != ETH_P_IP || rtnl_tc_get_kind(TC_CAST(cls.get())) != string("u32")) { return None(); } // Raw values. Option<uint32_t> protocol; Option<net::IP> destinationIP; // There are at most 0xff keys. for (uint8_t i = 0; i <= 0xff; i++) { uint32_t value; uint32_t mask; int offset; int offsetmask; // Decode a selector from the libnl filter 'cls'. int error = rtnl_u32_get_key( cls.get(), i, &value, &mask, &offset, &offsetmask); if (error != 0) { if (error == -NLE_INVAL) { // This is the case where cls does not have a u32 selector. In // that case, we just return None. return None(); } else if (error == -NLE_RANGE) { break; } else { return Error( "Failed to decode a u32 selector: " + string(nl_geterror(error))); } } // The function "rtnl_u32_get_key" sets value and mask in network // order. Convert them back to host order. value = ntohl(value); mask = ntohl(mask); // IP protocol field. if (offset == 8 && value == 0x00010000 && mask == 0x00ff0000) { protocol = value; } // Destination IP address. if (offset == 16 && mask == 0xffffffff) { destinationIP = net::IP(value); } } if (protocol.isSome()) { return icmp::Classifier(destinationIP); } return None(); }