1/* 2 * Copyright (c) 2013 The Linux Foundation. All rights reserved. 3 * Permission to use, copy, modify, and/or distribute this software for 4 * any purpose with or without fee is hereby granted, provided that the 5 * above copyright notice and this permission notice appear in all copies. 6 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 7 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 9 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 10 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 11 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 12 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 13 */ 14 15#include <netlink/genl/genl.h> 16#include <netlink/genl/ctrl.h> 17#include <errno.h> 18#include <stdio.h> 19#include <arpa/inet.h> 20 21#include <fast-classifier.h> 22 23static struct nl_sock *sock; 24static struct nl_sock *sock_event; 25static int family; 26static int grp_id; 27 28static struct nla_policy fast_classifier_genl_policy[FAST_CLASSIFIER_A_MAX + 1] = { 29 [FAST_CLASSIFIER_A_TUPLE] = { .type = NLA_UNSPEC }, 30}; 31 32void dump_fc_tuple(struct fast_classifier_tuple *fc_msg) { 33 char src_str[INET_ADDRSTRLEN]; 34 char dst_str[INET_ADDRSTRLEN]; 35 36 printf("TUPLE: %d, %s, %s, %d, %d" 37 " SMAC=%02x:%02x:%02x:%02x:%02x:%02x", 38 " DMAC=%02x:%02x:%02x:%02x:%02x:%02x\n", 39 fc_msg->proto, 40 inet_ntop(AF_INET, &(fc_msg->src_saddr), src_str, INET_ADDRSTRLEN), 41 inet_ntop(AF_INET, &(fc_msg->dst_saddr), dst_str, INET_ADDRSTRLEN), 42 fc_msg->sport, fc_msg->dport, 43 fc_msg->smac[0], fc_msg->smac[1], fc_msg->smac[2], 44 fc_msg->smac[3], fc_msg->smac[4], fc_msg->smac[5], 45 fc_msg->dmac[0], fc_msg->dmac[1], fc_msg->dmac[2], 46 fc_msg->dmac[3], fc_msg->dmac[4], fc_msg->dmac[5]); 47} 48 49static int parse_cb(struct nl_msg *msg, void *arg) { 50 struct nlmsghdr *nlh = nlmsg_hdr(msg); 51 struct genlmsghdr *gnlh = nlmsg_data(nlh); 52 struct nlattr *attrs[FAST_CLASSIFIER_A_MAX]; 53 54 genlmsg_parse(nlh, 0, attrs, FAST_CLASSIFIER_A_MAX, fast_classifier_genl_policy); 55 56 switch (gnlh->cmd) { 57 case FAST_CLASSIFIER_C_OFFLOADED: 58 printf("Got a offloaded message\n"); 59 dump_fc_tuple(nla_data(attrs[FAST_CLASSIFIER_A_TUPLE])); 60 return NL_OK; 61 case FAST_CLASSIFIER_C_DONE: 62 printf("Got a done message\n"); 63 dump_fc_tuple(nla_data(attrs[FAST_CLASSIFIER_A_TUPLE])); 64 return NL_OK; 65 } 66 67 return NL_SKIP; 68} 69 70int fast_classifier_init() { 71 int err; 72 73 sock = nl_socket_alloc(); 74 if (sock == NULL) { 75 printf("Unable to allocation socket.\n"); 76 return -1; 77 } 78 genl_connect(sock); 79 80 sock_event = nl_socket_alloc(); 81 if (sock_event == NULL) { 82 nl_close(sock); 83 nl_socket_free(sock); 84 printf("Unable to allocation socket.\n"); 85 return -1; 86 } 87 genl_connect(sock_event); 88 89 family = genl_ctrl_resolve(sock, FAST_CLASSIFIER_GENL_NAME); 90 if (family < 0) { 91 nl_close(sock_event); 92 nl_close(sock); 93 nl_socket_free(sock); 94 nl_socket_free(sock_event); 95 printf("Unable to resolve family\n"); 96 return -1; 97 } 98 99 grp_id = genl_ctrl_resolve_grp(sock, FAST_CLASSIFIER_GENL_NAME, 100 FAST_CLASSIFIER_GENL_MCGRP); 101 if (grp_id < 0) { 102 printf("Unable to resolve mcast group\n"); 103 return -1; 104 } 105 106 err = nl_socket_add_membership(sock_event, grp_id); 107 if (err < 0) { 108 printf("Unable to add membership\n"); 109 return -1; 110 } 111 112 nl_socket_disable_seq_check(sock_event); 113 nl_socket_modify_cb(sock_event, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, NULL); 114 115 return 0; 116} 117 118void fast_classifier_close() { 119 nl_close(sock_event); 120 nl_close(sock); 121 nl_socket_free(sock_event); 122 nl_socket_free(sock); 123} 124 125void fast_classifier_ipv4_offload(unsigned char proto, unsigned long src_saddr, 126 unsigned long dst_saddr, unsigned short sport, 127 unsigned short dport) { 128 struct nl_msg *msg; 129 int ret; 130#ifdef DEBUG 131 char src_str[INET_ADDRSTRLEN]; 132 char dst_str[INET_ADDRSTRLEN]; 133#endif 134 struct fast_classifier_tuple fc_msg; 135 136#ifdef DEBUG 137 printf("DEBUG: would offload: %d, %s, %s, %d, %d\n", proto, 138 inet_ntop(AF_INET, &src_saddr, src_str, INET_ADDRSTRLEN), 139 inet_ntop(AF_INET, &dst_saddr, dst_str, INET_ADDRSTRLEN), 140 sport, dport); 141#endif 142 143 fc_msg.proto = proto; 144 fc_msg.src_saddr = src_saddr; 145 fc_msg.dst_saddr = dst_saddr; 146 fc_msg.sport = sport; 147 fc_msg.dport = dport; 148 fc_msg.smac[0] = 'a'; 149 fc_msg.smac[1] = 'b'; 150 fc_msg.smac[2] = 'c'; 151 fc_msg.smac[3] = 'd'; 152 fc_msg.smac[4] = 'e'; 153 fc_msg.smac[5] = 'f'; 154 fc_msg.dmac[0] = 'f'; 155 fc_msg.dmac[1] = 'e'; 156 fc_msg.dmac[2] = 'd'; 157 fc_msg.dmac[3] = 'c'; 158 fc_msg.dmac[4] = 'b'; 159 fc_msg.dmac[5] = 'a'; 160 161 if (fast_classifier_init() < 0) { 162 printf("Unable to init generic netlink\n"); 163 exit(1); 164 } 165 166 msg = nlmsg_alloc(); 167 if (msg == NULL) { 168 nl_socket_free(sock); 169 printf("Unable to allocate message\n"); 170 return; 171 } 172 173 genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 174 FAST_CLASSIFIER_GENL_HDRSIZE, NLM_F_REQUEST, 175 FAST_CLASSIFIER_C_OFFLOAD, FAST_CLASSIFIER_GENL_VERSION); 176 nla_put(msg, 1, sizeof(fc_msg), &fc_msg); 177 178 ret = nl_send_auto_complete(sock, msg); 179 180 nlmsg_free(msg); 181 if (ret < 0) { 182 printf("nlmsg_free failed"); 183 nl_close(sock); 184 nl_socket_free(sock); 185 return; 186 } 187 188 ret = nl_wait_for_ack(sock); 189 if (ret < 0) { 190 printf("wait for ack failed"); 191 nl_close(sock); 192 nl_socket_free(sock); 193 return; 194 } 195} 196 197void fast_classifier_listen_for_messages(void) { 198 printf("waiting for netlink events\n"); 199 200 while (1) { 201 nl_recvmsgs_default(sock_event); 202 } 203} 204int main(int argc, char *argv[]) 205{ 206 if (fast_classifier_init() < 0) { 207 printf("Unable to init generic netlink\n"); 208 exit(1); 209 } 210 211 fast_classifier_ipv4_offload('a', 0, 0, 0, 0); 212 213 /* this never returns */ 214 fast_classifier_listen_for_messages(); 215 216 fast_classifier_close(); 217 218 return 0; 219} 220