m_vlan.c revision 69f5aff63c770bd95607b33d5ee8ee183dc13a64
1/* 2 * m_vlan.c vlan manipulation module 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Jiri Pirko <jiri@resnulli.us> 10 */ 11 12#include <stdio.h> 13#include <stdlib.h> 14#include <unistd.h> 15#include <string.h> 16#include <linux/if_ether.h> 17#include "utils.h" 18#include "rt_names.h" 19#include "tc_util.h" 20#include <linux/tc_act/tc_vlan.h> 21 22static void explain(void) 23{ 24 fprintf(stderr, "Usage: vlan pop\n"); 25 fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [CONTROL]\n"); 26 fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n"); 27 fprintf(stderr, " with default: 802.1Q\n"); 28 fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass\n"); 29} 30 31static void usage(void) 32{ 33 explain(); 34 exit(-1); 35} 36 37static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, 38 int tca_id, struct nlmsghdr *n) 39{ 40 int argc = *argc_p; 41 char **argv = *argv_p; 42 struct rtattr *tail; 43 int action = 0; 44 __u16 id; 45 int id_set = 0; 46 __u16 proto; 47 int proto_set = 0; 48 struct tc_vlan parm = { 0 }; 49 50 if (matches(*argv, "vlan") != 0) 51 return -1; 52 53 NEXT_ARG(); 54 55 while (argc > 0) { 56 if (matches(*argv, "pop") == 0) { 57 if (action) { 58 fprintf(stderr, "unexpected \"%s\" - action already specified\n", 59 *argv); 60 explain(); 61 return -1; 62 } 63 action = TCA_VLAN_ACT_POP; 64 } else if (matches(*argv, "push") == 0) { 65 if (action) { 66 fprintf(stderr, "unexpected \"%s\" - action already specified\n", 67 *argv); 68 explain(); 69 return -1; 70 } 71 action = TCA_VLAN_ACT_PUSH; 72 } else if (matches(*argv, "id") == 0) { 73 if (action != TCA_VLAN_ACT_PUSH) { 74 fprintf(stderr, "\"%s\" is only valid for push\n", 75 *argv); 76 explain(); 77 return -1; 78 } 79 NEXT_ARG(); 80 if (get_u16(&id, *argv, 0)) 81 invarg("id is invalid", *argv); 82 id_set = 1; 83 } else if (matches(*argv, "protocol") == 0) { 84 if (action != TCA_VLAN_ACT_PUSH) { 85 fprintf(stderr, "\"%s\" is only valid for push\n", 86 *argv); 87 explain(); 88 return -1; 89 } 90 NEXT_ARG(); 91 if (ll_proto_a2n(&proto, *argv)) 92 invarg("protocol is invalid", *argv); 93 proto_set = 1; 94 } else if (matches(*argv, "help") == 0) { 95 usage(); 96 } else { 97 break; 98 } 99 argc--; 100 argv++; 101 } 102 103 parm.action = TC_ACT_PIPE; 104 if (argc && !action_a2n(*argv, &parm.action, false)) 105 NEXT_ARG_FWD(); 106 107 if (argc) { 108 if (matches(*argv, "index") == 0) { 109 NEXT_ARG(); 110 if (get_u32(&parm.index, *argv, 10)) { 111 fprintf(stderr, "vlan: Illegal \"index\"\n"); 112 return -1; 113 } 114 argc--; 115 argv++; 116 } 117 } 118 119 if (action == TCA_VLAN_ACT_PUSH && !id_set) { 120 fprintf(stderr, "id needs to be set for push\n"); 121 explain(); 122 return -1; 123 } 124 125 parm.v_action = action; 126 tail = NLMSG_TAIL(n); 127 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 128 addattr_l(n, MAX_MSG, TCA_VLAN_PARMS, &parm, sizeof(parm)); 129 if (id_set) 130 addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_ID, &id, 2); 131 if (proto_set) { 132 if (proto != htons(ETH_P_8021Q) && 133 proto != htons(ETH_P_8021AD)) { 134 fprintf(stderr, "protocol not supported\n"); 135 explain(); 136 return -1; 137 } 138 139 addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PROTOCOL, &proto, 2); 140 } 141 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; 142 143 *argc_p = argc; 144 *argv_p = argv; 145 return 0; 146} 147 148static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) 149{ 150 SPRINT_BUF(b1); 151 struct rtattr *tb[TCA_VLAN_MAX + 1]; 152 __u16 val; 153 struct tc_vlan *parm; 154 155 if (arg == NULL) 156 return -1; 157 158 parse_rtattr_nested(tb, TCA_VLAN_MAX, arg); 159 160 if (!tb[TCA_VLAN_PARMS]) { 161 fprintf(f, "[NULL vlan parameters]"); 162 return -1; 163 } 164 parm = RTA_DATA(tb[TCA_VLAN_PARMS]); 165 166 fprintf(f, " vlan"); 167 168 switch (parm->v_action) { 169 case TCA_VLAN_ACT_POP: 170 fprintf(f, " pop"); 171 break; 172 case TCA_VLAN_ACT_PUSH: 173 fprintf(f, " push"); 174 if (tb[TCA_VLAN_PUSH_VLAN_ID]) { 175 val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); 176 fprintf(f, " id %u", val); 177 } 178 if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) { 179 fprintf(f, " protocol %s", 180 ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]), 181 b1, sizeof(b1))); 182 } 183 break; 184 } 185 fprintf(f, " %s", action_n2a(parm->action, b1, sizeof(b1))); 186 187 fprintf(f, "\n\t index %d ref %d bind %d", parm->index, parm->refcnt, 188 parm->bindcnt); 189 190 if (show_stats) { 191 if (tb[TCA_VLAN_TM]) { 192 struct tcf_t *tm = RTA_DATA(tb[TCA_VLAN_TM]); 193 194 print_tm(f, tm); 195 } 196 } 197 198 fprintf(f, "\n "); 199 200 return 0; 201} 202 203struct action_util vlan_action_util = { 204 .id = "vlan", 205 .parse_aopt = parse_vlan, 206 .print_aopt = print_vlan, 207}; 208