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\n"); 26 fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n"); 27 fprintf(stderr, " with default: 802.1Q\n"); 28} 29 30static void usage(void) 31{ 32 explain(); 33 exit(-1); 34} 35 36static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p, 37 int tca_id, struct nlmsghdr *n) 38{ 39 int argc = *argc_p; 40 char **argv = *argv_p; 41 struct rtattr *tail; 42 int action = 0; 43 __u16 id; 44 int id_set = 0; 45 __u16 proto; 46 int proto_set = 0; 47 struct tc_vlan parm = { 0 }; 48 49 if (matches(*argv, "vlan") != 0) 50 return -1; 51 52 NEXT_ARG(); 53 54 while (argc > 0) { 55 if (matches(*argv, "pop") == 0) { 56 if (action) { 57 fprintf(stderr, "unexpected \"%s\" - action already specified\n", 58 *argv); 59 explain(); 60 return -1; 61 } 62 action = TCA_VLAN_ACT_POP; 63 } else if (matches(*argv, "push") == 0) { 64 if (action) { 65 fprintf(stderr, "unexpected \"%s\" - action already specified\n", 66 *argv); 67 explain(); 68 return -1; 69 } 70 action = TCA_VLAN_ACT_PUSH; 71 } else if (matches(*argv, "id") == 0) { 72 if (action != TCA_VLAN_ACT_PUSH) { 73 fprintf(stderr, "\"%s\" is only valid for push\n", 74 *argv); 75 explain(); 76 return -1; 77 } 78 NEXT_ARG(); 79 if (get_u16(&id, *argv, 0)) 80 invarg("id is invalid", *argv); 81 id_set = 1; 82 } else if (matches(*argv, "protocol") == 0) { 83 if (action != TCA_VLAN_ACT_PUSH) { 84 fprintf(stderr, "\"%s\" is only valid for push\n", 85 *argv); 86 explain(); 87 return -1; 88 } 89 NEXT_ARG(); 90 if (ll_proto_a2n(&proto, *argv)) 91 invarg("protocol is invalid", *argv); 92 proto_set = 1; 93 } else if (matches(*argv, "help") == 0) { 94 usage(); 95 } else { 96 break; 97 } 98 argc--; 99 argv++; 100 } 101 102 parm.action = TC_ACT_PIPE; 103 if (argc) { 104 if (matches(*argv, "reclassify") == 0) { 105 parm.action = TC_ACT_RECLASSIFY; 106 argc--; 107 argv++; 108 } else if (matches(*argv, "pipe") == 0) { 109 parm.action = TC_ACT_PIPE; 110 argc--; 111 argv++; 112 } else if (matches(*argv, "drop") == 0 || 113 matches(*argv, "shot") == 0) { 114 parm.action = TC_ACT_SHOT; 115 argc--; 116 argv++; 117 } else if (matches(*argv, "continue") == 0) { 118 parm.action = TC_ACT_UNSPEC; 119 argc--; 120 argv++; 121 } else if (matches(*argv, "pass") == 0) { 122 parm.action = TC_ACT_OK; 123 argc--; 124 argv++; 125 } 126 } 127 128 if (argc) { 129 if (matches(*argv, "index") == 0) { 130 NEXT_ARG(); 131 if (get_u32(&parm.index, *argv, 10)) { 132 fprintf(stderr, "vlan: Illegal \"index\"\n"); 133 return -1; 134 } 135 argc--; 136 argv++; 137 } 138 } 139 140 if (action == TCA_VLAN_ACT_PUSH && !id_set) { 141 fprintf(stderr, "id needs to be set for push\n"); 142 explain(); 143 return -1; 144 } 145 146 parm.v_action = action; 147 tail = NLMSG_TAIL(n); 148 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 149 addattr_l(n, MAX_MSG, TCA_VLAN_PARMS, &parm, sizeof(parm)); 150 if (id_set) 151 addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_ID, &id, 2); 152 if (proto_set) { 153 if (proto != htons(ETH_P_8021Q) && 154 proto != htons(ETH_P_8021AD)) { 155 fprintf(stderr, "protocol not supported\n"); 156 explain(); 157 return -1; 158 } 159 160 addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PROTOCOL, &proto, 2); 161 } 162 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; 163 164 *argc_p = argc; 165 *argv_p = argv; 166 return 0; 167} 168 169static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) 170{ 171 SPRINT_BUF(b1); 172 struct rtattr *tb[TCA_VLAN_MAX + 1]; 173 __u16 val; 174 struct tc_vlan *parm; 175 176 if (arg == NULL) 177 return -1; 178 179 parse_rtattr_nested(tb, TCA_VLAN_MAX, arg); 180 181 if (!tb[TCA_VLAN_PARMS]) { 182 fprintf(f, "[NULL vlan parameters]"); 183 return -1; 184 } 185 parm = RTA_DATA(tb[TCA_VLAN_PARMS]); 186 187 fprintf(f, " vlan"); 188 189 switch(parm->v_action) { 190 case TCA_VLAN_ACT_POP: 191 fprintf(f, " pop"); 192 break; 193 case TCA_VLAN_ACT_PUSH: 194 fprintf(f, " push"); 195 if (tb[TCA_VLAN_PUSH_VLAN_ID]) { 196 val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]); 197 fprintf(f, " id %u", val); 198 } 199 if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) { 200 fprintf(f, " protocol %s", 201 ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]), 202 b1, sizeof(b1))); 203 } 204 break; 205 } 206 fprintf(f, " %s", action_n2a(parm->action, b1, sizeof (b1))); 207 208 fprintf(f, "\n\t index %d ref %d bind %d", parm->index, parm->refcnt, 209 parm->bindcnt); 210 211 if (show_stats) { 212 if (tb[TCA_VLAN_TM]) { 213 struct tcf_t *tm = RTA_DATA(tb[TCA_VLAN_TM]); 214 print_tm(f, tm); 215 } 216 } 217 218 fprintf(f, "\n "); 219 220 return 0; 221} 222 223struct action_util vlan_action_util = { 224 .id = "vlan", 225 .parse_aopt = parse_vlan, 226 .print_aopt = print_vlan, 227}; 228