/* * Copyright (c) 2013 The Linux Foundation. All rights reserved. * Permission to use, copy, modify, and/or distribute this software for * any purpose with or without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all copies. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include static struct nl_sock *sock; static struct nl_sock *sock_event; static int family; static int grp_id; static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = { [FAST_CLASSIFIER_A_TUPLE] = { .type = NLA_UNSPEC }, }; void dump_fc_tuple(struct fast_classifier_tuple *fc_msg) { char src_str[INET_ADDRSTRLEN]; char dst_str[INET_ADDRSTRLEN]; printf("TUPLE: %d, %s, %s, %d, %d" " SMAC=%02x:%02x:%02x:%02x:%02x:%02x", " DMAC=%02x:%02x:%02x:%02x:%02x:%02x\n", fc_msg->proto, inet_ntop(AF_INET, &(fc_msg->src_saddr), src_str, INET_ADDRSTRLEN), inet_ntop(AF_INET, &(fc_msg->dst_saddr), dst_str, INET_ADDRSTRLEN), fc_msg->sport, fc_msg->dport, fc_msg->smac[0], fc_msg->smac[1], fc_msg->smac[2], fc_msg->smac[3], fc_msg->smac[4], fc_msg->smac[5], fc_msg->dmac[0], fc_msg->dmac[1], fc_msg->dmac[2], fc_msg->dmac[3], fc_msg->dmac[4], fc_msg->dmac[5]); } static int parse_cb(struct nl_msg *msg, void *arg) { struct nlmsghdr *nlh = nlmsg_hdr(msg); struct genlmsghdr *gnlh = nlmsg_data(nlh); struct nlattr *attrs[FAST_CLASSIFIER_A_MAX]; genlmsg_parse(nlh, 0, attrs, FAST_CLASSIFIER_A_MAX, fast_classifier_genl_policy); switch (gnlh->cmd) { case FAST_CLASSIFIER_C_OFFLOADED: printf("Got a offloaded message\n"); dump_fc_tuple(nla_data(attrs[FAST_CLASSIFIER_A_TUPLE])); return NL_OK; case FAST_CLASSIFIER_C_DONE: printf("Got a done message\n"); dump_fc_tuple(nla_data(attrs[FAST_CLASSIFIER_A_TUPLE])); return NL_OK; } return NL_SKIP; } int fast_classifier_init() { int err; sock = nl_socket_alloc(); if (sock == NULL) { printf("Unable to allocation socket.\n"); return -1; } genl_connect(sock); sock_event = nl_socket_alloc(); if (sock_event == NULL) { nl_close(sock); nl_socket_free(sock); printf("Unable to allocation socket.\n"); return -1; } genl_connect(sock_event); family = genl_ctrl_resolve(sock, FAST_CLASSIFIER_GENL_NAME); if (family < 0) { nl_close(sock_event); nl_close(sock); nl_socket_free(sock); nl_socket_free(sock_event); printf("Unable to resolve family\n"); return -1; } grp_id = genl_ctrl_resolve_grp(sock, FAST_CLASSIFIER_GENL_NAME, FAST_CLASSIFIER_GENL_MCGRP); if (grp_id < 0) { printf("Unable to resolve mcast group\n"); return -1; } err = nl_socket_add_membership(sock_event, grp_id); if (err < 0) { printf("Unable to add membership\n"); return -1; } nl_socket_disable_seq_check(sock_event); nl_socket_modify_cb(sock_event, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL); return 0; } void fast_classifier_close() { nl_close(sock_event); nl_close(sock); nl_socket_free(sock_event); nl_socket_free(sock); } void fast_classifier_ipv4_offload(unsigned char proto, unsigned long src_saddr, unsigned long dst_saddr, unsigned short sport, unsigned short dport) { struct nl_msg *msg; int ret; #ifdef DEBUG char src_str[INET_ADDRSTRLEN]; char dst_str[INET_ADDRSTRLEN]; #endif struct fast_classifier_tuple fc_msg; #ifdef DEBUG printf("DEBUG: would offload: %d, %s, %s, %d, %d\n", proto, inet_ntop(AF_INET, &src_saddr, src_str, INET_ADDRSTRLEN), inet_ntop(AF_INET, &dst_saddr, dst_str, INET_ADDRSTRLEN), sport, dport); #endif fc_msg.proto = proto; fc_msg.src_saddr = src_saddr; fc_msg.dst_saddr = dst_saddr; fc_msg.sport = sport; fc_msg.dport = dport; fc_msg.smac[0] = 'a'; fc_msg.smac[1] = 'b'; fc_msg.smac[2] = 'c'; fc_msg.smac[3] = 'd'; fc_msg.smac[4] = 'e'; fc_msg.smac[5] = 'f'; fc_msg.dmac[0] = 'f'; fc_msg.dmac[1] = 'e'; fc_msg.dmac[2] = 'd'; fc_msg.dmac[3] = 'c'; fc_msg.dmac[4] = 'b'; fc_msg.dmac[5] = 'a'; if (fast_classifier_init() < 0) { printf("Unable to init generic netlink\n"); exit(1); } msg = nlmsg_alloc(); if (msg == NULL) { nl_socket_free(sock); printf("Unable to allocate message\n"); return; } genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, FAST_CLASSIFIER_GENL_HDRSIZE, NLM_F_REQUEST, FAST_CLASSIFIER_C_OFFLOAD, FAST_CLASSIFIER_GENL_VERSION); nla_put(msg, 1, sizeof(fc_msg), &fc_msg); ret = nl_send_auto_complete(sock, msg); nlmsg_free(msg); if (ret < 0) { printf("nlmsg_free failed"); nl_close(sock); nl_socket_free(sock); return; } ret = nl_wait_for_ack(sock); if (ret < 0) { printf("wait for ack failed"); nl_close(sock); nl_socket_free(sock); return; } } void fast_classifier_listen_for_messages(void) { printf("waiting for netlink events\n"); while (1) { nl_recvmsgs_default(sock_event); } } int main(int argc, char *argv[]) { if (fast_classifier_init() < 0) { printf("Unable to init generic netlink\n"); exit(1); } fast_classifier_ipv4_offload('a', 0, 0, 0, 0); /* this never returns */ fast_classifier_listen_for_messages(); fast_classifier_close(); return 0; }